diff --git a/CoCoLoT_Tracker.py b/CoCoLoT_Tracker.py new file mode 100755 index 0000000..d3b6d0c --- /dev/null +++ b/CoCoLoT_Tracker.py @@ -0,0 +1,492 @@ + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from vot_path import base_path +import cv2 +import os +import torch +import numpy as np +import math +import tensorflow as tf +import sys +import time +import copy +sys.path.append(os.path.join(base_path, 'CoCoLoT/meta_updater')) +sys.path.append(os.path.join(base_path, 'CoCoLoT/utils/metric_net')) +from tcNet import tclstm +from tcopt import tcopts +from metric_model import ft_net +from torch.autograd import Variable +from me_sample_generator import * +import vot +os.environ["CUDA_VISIBLE_DEVICES"] = "0" + +# Dimp +import argparse +from pytracking.libs.tensorlist import TensorList +from pytracking.utils.plotting import show_tensor +from pytracking.features.preprocessing import numpy_to_torch +env_path = os.path.join(os.path.dirname(__file__)) +if env_path not in sys.path: + sys.path.append(env_path) +from pytracking.evaluation import Tracker as pyTracker + +from PIL import Image, ImageDraw, ImageFont +Image.MAX_IMAGE_PIXELS = 1000000000 +from tracking_utils import compute_iou, show_res, process_regions + + +sys.path.append(os.path.join(base_path, 'CoCoLoT/pyMDNet/modules')) +sys.path.append(os.path.join(base_path, 'CoCoLoT/pyMDNet/tracking')) +# pymdnet +from pyMDNet.modules.model import * +sys.path.insert(0, './pyMDNet') +from pyMDNet.modules.model import MDNet, BCELoss, set_optimizer +from pyMDNet.modules.sample_generator import SampleGenerator +from pyMDNet.modules.utils import overlap_ratio +from pyMDNet.tracking.data_prov import RegionExtractor +from pyMDNet.tracking.run_tracker import * +from bbreg import BBRegressor +from gen_config import gen_config +opts = yaml.safe_load(open(os.path.join(base_path, 'CoCoLoT/pyMDNet/tracking/options.yaml'), 'r')) + +from Stark.lib.test.vot20.stark_vot20lt import * + +import random + +SEED = 150 +torch.manual_seed(SEED) +np.random.seed(SEED) +torch.cuda.manual_seed_all(SEED) + + +class p_config(object): + Verification = "rtmdnet" + name = 'Dimp_MU' + model_dir = 'dimp_mu_votlt' + checkpoint = 220000 + start_frame = 200 + R_candidates = 20 + save_results = False + use_mask = True + save_training_data = False + visualization = True + + +class CoCoLoT_Tracker(object): + + def __init__(self, image, region, p=None, groundtruth=None): + self.p = p + self.i = 0 + self.t_id = 0 + if groundtruth is not None: + self.groundtruth = groundtruth + + tfconfig = tf.ConfigProto() + tfconfig.gpu_options.per_process_gpu_memory_fraction = 0.3 + self.sess = tf.Session(config=tfconfig) + init_gt1 = [region.x, region.y, region.width, region.height] + init_gt = [init_gt1[1], init_gt1[0], init_gt1[1]+init_gt1[3], init_gt1[0]+init_gt1[2]] # ymin xmin ymax xmax + + self.last_gt = init_gt # when initialized assumes ground-truth values + self.init_pymdnet(image, init_gt1) + self.local_init(image, init_gt1) + + + self.tc_init(self.p.model_dir) + self.metric_init(image, np.array(init_gt1)) + self.dis_record = [] + self.state_record = [] + self.rv_record = [] + self.all_map = [] + self.count = 0 + local_state1, self.score_map, update, self.score_max, dis, flag = self.local_track(image) + self.local_Tracker.pos = torch.FloatTensor( + [(self.last_gt[0] + self.last_gt[2] - 1) / 2, (self.last_gt[1] + self.last_gt[3] - 1) / 2]) + self.local_Tracker.target_sz = torch.FloatTensor( + [(self.last_gt[2] - self.last_gt[0]), (self.last_gt[3] - self.last_gt[1])]) # height, width + + init_stark = [int(init_gt1[0]), int(init_gt1[1]), int(init_gt1[2]), int(init_gt1[3])] + self.stark_init(image, init_stark) + + self.boxes = [init_gt1] + self.boxes_stark = [init_gt1] + self.boxes_dimp = [init_gt1] + self.confidences = [1.0] + self.md_scores_dimp = [1.0] + self.md_scores_stark = [1.0] + self.md_scores_sum = [5] + + self.last_good = copy.copy(self.last_gt) + self.last_good_idx = 0 + + self.img_shape = image.shape + + + def get_first_state(self): + return self.score_map, self.score_max + + def stark_init(self, image, init_box): + self.stark_tracker = stark_vot20_lt(tracker_name='stark_st', para_name='baseline') + self.stark_tracker.initialize(image, init_box) + + def init_pymdnet(self, image, init_bbox): + target_bbox = np.array(init_bbox) + self.last_result = target_bbox + self.pymodel = MDNet(os.path.join(base_path, 'CoCoLoT/pyMDNet/models/mdnet_imagenet_vid.pth')) + if opts['use_gpu']: + self.pymodel = self.pymodel.cuda() + self.pymodel.set_learnable_params(opts['ft_layers']) + + # Init criterion and optimizer + self.criterion = BCELoss() + init_optimizer = set_optimizer(self.pymodel, opts['lr_init'], opts['lr_mult']) + self.update_optimizer = set_optimizer(self.pymodel, opts['lr_update'], opts['lr_mult']) + + tic = time.time() + + # Draw pos/neg samples + pos_examples = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos'])( + target_bbox, opts['n_pos_init'], opts['overlap_pos_init']) + + neg_examples = np.concatenate([ + SampleGenerator('uniform', image.size, opts['trans_neg_init'], opts['scale_neg_init'])( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init']), + SampleGenerator('whole', image.size)( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init'])]) + neg_examples = np.random.permutation(neg_examples) + + # Extract pos/neg features + pos_feats = forward_samples(self.pymodel, image, pos_examples, opts) + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.feat_dim = pos_feats.size(-1) + + # Initial training + train(self.pymodel, self.criterion, init_optimizer, pos_feats, neg_feats, opts['maxiter_init'], opts=opts) + del init_optimizer, neg_feats + torch.cuda.empty_cache() + + # Train bbox regressor + bbreg_examples = SampleGenerator('uniform', image.size, opts['trans_bbreg'], opts['scale_bbreg'], + opts['aspect_bbreg'])( + target_bbox, opts['n_bbreg'], opts['overlap_bbreg']) + bbreg_feats = forward_samples(self.pymodel, image, bbreg_examples, opts) + self.bbreg = BBRegressor(image.size) + self.bbreg.train(bbreg_feats, bbreg_examples, target_bbox) + del bbreg_feats + torch.cuda.empty_cache() + # Init sample generators + self.sample_generator = SampleGenerator('gaussian', image.size, opts['trans'], opts['scale']) + self.pos_generator = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos']) + self.neg_generator = SampleGenerator('uniform', image.size, opts['trans_neg'], opts['scale_neg']) + + # Init pos/neg features for update + neg_examples = self.neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_init']) + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.pos_feats_all = [pos_feats] + self.neg_feats_all = [neg_feats] + + spf_total = time.time() - tic + + def pymdnet_eval(self, image, samples): + sample_scores = forward_samples(self.pymodel, image, samples, out_layer='fc6', opts=opts) + return sample_scores[:, 1][:].cpu().numpy() + + def collect_samples_pymdnet(self, image): + self.t_id += 1 + target_bbox = np.array([self.last_gt[1], self.last_gt[0], self.last_gt[3]-self.last_gt[1], self.last_gt[2]-self.last_gt[0]]) + pos_examples = self.pos_generator(target_bbox, opts['n_pos_update'], opts['overlap_pos_update']) + if len(pos_examples) > 0: + pos_feats = forward_samples(self.pymodel, image, pos_examples, opts) + self.pos_feats_all.append(pos_feats) + if len(self.pos_feats_all) > opts['n_frames_long']: + del self.pos_feats_all[0] + + neg_examples = self.neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_update']) + if len(neg_examples) > 0: + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.neg_feats_all.append(neg_feats) + if len(self.neg_feats_all) > opts['n_frames_short']: + del self.neg_feats_all[0] + + def pymdnet_short_term_update(self): + # Short term update + nframes = min(opts['n_frames_short'], len(self.pos_feats_all)) + pos_data = torch.cat(self.pos_feats_all[-nframes:], 0) + neg_data = torch.cat(self.neg_feats_all, 0) + train(self.pymodel, self.criterion, self.update_optimizer, pos_data, neg_data, opts['maxiter_update'], + opts=opts) + + def pymdnet_long_term_update(self): + if self.t_id % opts['long_interval'] == 0: + # Long term update + pos_data = torch.cat(self.pos_feats_all, 0) + neg_data = torch.cat(self.neg_feats_all, 0) + train(self.pymodel, self.criterion, self.update_optimizer, pos_data, neg_data, opts['maxiter_update'], + opts=opts) + + def metric_init(self, im, init_box): + self.metric_model = ft_net(class_num=1120) + path = os.path.join(base_path, 'CoCoLoT/ckpt/metric_model.pt') + self.metric_model.eval() + self.metric_model = self.metric_model.cuda() + self.metric_model.load_state_dict(torch.load(path)) + tmp = np.random.rand(1, 3, 107, 107) + tmp = (Variable(torch.Tensor(tmp))).type(torch.FloatTensor).cuda() + # get target feature + self.metric_model(tmp) + init_box = init_box.reshape((1, 4)) + anchor_region = me_extract_regions(im, init_box) + anchor_region = process_regions(anchor_region) + anchor_region = torch.Tensor(anchor_region) + anchor_region = (Variable(anchor_region)).type(torch.FloatTensor).cuda() + self.anchor_feature, _ = self.metric_model(anchor_region) + + def metric_eval(self, im, boxes, anchor_feature): + box_regions = me_extract_regions(np.array(im), boxes) + box_regions = process_regions(box_regions) + box_regions = torch.Tensor(box_regions) + box_regions = (Variable(box_regions)).type(torch.FloatTensor).cuda() + box_features, class_result = self.metric_model(box_regions) + + class_result = torch.softmax(class_result, dim=1) + ap_dist = torch.norm(anchor_feature - box_features, 2, dim=1).view(-1) + return ap_dist + + def tc_init(self, model_dir): + self.tc_model = tclstm() + self.X_input = tf.placeholder("float", [None, tcopts['time_steps'], tcopts['lstm_num_input']]) + self.maps = tf.placeholder("float", [None, 19, 19, 1]) + self.map_logits = self.tc_model.map_net(self.maps) + self.Inputs = tf.concat((self.X_input, self.map_logits), axis=2) + self.logits, _ = self.tc_model.net(self.Inputs) + + variables_to_restore = [var for var in tf.global_variables() if + (var.name.startswith('tclstm') or var.name.startswith('mapnet'))] + saver = tf.train.Saver(var_list=variables_to_restore) + if self.p.checkpoint is None: + checkpoint = tf.train.latest_checkpoint(os.path.join(base_path, 'CoCoLoT/meta_updater', model_dir)) + else: + checkpoint = os.path.join(base_path, 'CoCoLoT/meta_updater/' + self.p.model_dir + '/lstm_model.ckpt-' + str(self.p.checkpoint)) + saver.restore(self.sess, checkpoint) + + def local_init(self, image, init_bbox): + local_tracker = pyTracker('dimp', 'super_dimp') + params = local_tracker.get_parameters() + + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = local_tracker.name + params.param_name = local_tracker.parameter_name + + self.local_Tracker = local_tracker.tracker_class(params) + init_box = dict() + init_box['init_bbox'] = init_bbox + self.local_Tracker.initialize(image, init_box) + + def local_track(self, image): + state, score_map, test_x, scale_ind, sample_pos, sample_scales, flag, s = self.local_Tracker.track_updater(image) + score_map = cv2.resize(score_map, (19, 19)) + update_flag = flag not in ['not_found', 'uncertain'] + update = update_flag + max_score = max(score_map.flatten()) + self.all_map.append(score_map) + local_state = np.array(state).reshape((1, 4)) + ap_dis = self.metric_eval(image, local_state, self.anchor_feature) + self.dis_record.append(ap_dis.data.cpu().numpy()[0]) + h = image.shape[0] + w = image.shape[1] + self.state_record.append([local_state[0][0] / w, local_state[0][1] / h, + (local_state[0][0] + local_state[0][2]) / w, + (local_state[0][1] + local_state[0][3]) / h]) + self.rv_record.append(max_score) + #if len(self.state_record) >= tcopts['time_steps']: + if len(self.state_record) >= self.p.start_frame: + dis = np.array(self.dis_record[-tcopts["time_steps"]:]).reshape((tcopts["time_steps"], 1)) + rv = np.array(self.rv_record[-tcopts["time_steps"]:]).reshape((tcopts["time_steps"], 1)) + state_tc = np.array(self.state_record[-tcopts["time_steps"]:]) + map_input = np.array(self.all_map[-tcopts["time_steps"]:]) + map_input = np.reshape(map_input, [tcopts['time_steps'], 1, 19, 19]) + map_input = map_input.transpose((0, 2, 3, 1)) + X_input = np.concatenate((state_tc, rv, dis), axis=1) + logits = self.sess.run(self.logits, + feed_dict={self.X_input: np.expand_dims(X_input, axis=0), + self.maps: map_input}) + update = logits[0][0] < logits[0][1] + + hard_negative = (flag == 'hard_negative') + learning_rate = getattr(self.local_Tracker.params, 'hard_negative_learning_rate', None) if hard_negative else None + + if update: + # Get train sample + train_x = test_x[scale_ind:scale_ind+1, ...] + + # Create target_box and label for spatial sample + target_box = self.local_Tracker.get_iounet_box(self.local_Tracker.pos, self.local_Tracker.target_sz, + sample_pos[scale_ind, :], sample_scales[scale_ind]) + + # Update the classifier model + self.local_Tracker.update_classifier(train_x, target_box, learning_rate, s[scale_ind,...]) + self.last_gt = [state[1], state[0], state[1]+state[3], state[0]+state[2]] + return state, score_map, update, max_score, ap_dis.data.cpu().numpy()[0], flag + + def locate(self, image): + + # Convert image + im = numpy_to_torch(image) + self.local_Tracker.im = im # For debugging only + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.local_Tracker.pos.round() + sample_scales = self.local_Tracker.target_scale * self.local_Tracker.params.scale_factors + test_x = self.local_Tracker.extract_processed_sample(im, self.local_Tracker.pos, sample_scales, self.local_Tracker.img_sample_sz) + + # Compute scores + scores_raw = self.local_Tracker.apply_filter(test_x) + translation_vec, scale_ind, s, flag = self.local_Tracker.localize_target(scores_raw) + return translation_vec, scale_ind, s, flag, sample_pos, sample_scales, test_x + + def local_update(self, sample_pos, translation_vec, scale_ind, sample_scales, s, test_x, update_flag=None): + + # Check flags and set learning rate if hard negative + if update_flag is None: + update_flag = self.flag not in ['not_found', 'uncertain'] + hard_negative = (self.flag == 'hard_negative') + learning_rate = self.local_Tracker.params.hard_negative_learning_rate if hard_negative else None + + if update_flag: + # Get train sample + train_x = TensorList([x[scale_ind:scale_ind + 1, ...] for x in test_x]) + + # Create label for sample + train_y = self.local_Tracker.get_label_function(sample_pos, sample_scales[scale_ind]) + + # Update memory + self.local_Tracker.update_memory(train_x, train_y, learning_rate) + + # Train filter + if hard_negative: + self.local_Tracker.filter_optimizer.run(self.local_Tracker.params.hard_negative_CG_iter) + elif (self.local_Tracker.frame_num - 1) % self.local_Tracker.params.train_skipping == 0: + self.local_Tracker.filter_optimizer.run(self.local_Tracker.params.CG_iter) + + def local_track_stark(self, image): + update_ouput = [0, 0] + cur_ori_img = Image.fromarray(image).convert('RGB') + cur_image = np.asarray(cur_ori_img) + + target_bbox, local_score = self.stark_tracker.track(image) + + return target_bbox, local_score + + def dist_penalty(self, bbox): + dist_max = math.sqrt(sum(np.array([self.img_shape[0], self.img_shape[1]]) ** 2)) + #for i in range(len(list_search_pos)): + # dist1[i] = math.sqrt(sum((list_search_pos[i] - list_search_pos[0]) ** 2)) + last_good = [self.last_good[1], self.last_good[0], self.last_good[3] - self.last_good[1], self.last_good[2] - self.last_good[0]] + dist = math.sqrt(sum((np.array(bbox[:2]) - np.array(last_good[:2])) ** 2)) + #weight_penalty = 1.0 - self.params.get('redetection_score_penalty_alpha', 0.5) * (dist / dist_max) * math.exp(- self.params.get('redetection_score_penalty_beta', 0.5) * (self.cnt_empty - 1)) + #weight_penalty = 1.0 - 0.75 * (dist / dist_max) * math.exp(- 0.25 * (self.i - self.last_good_idx - 1)) + weight_penalty = 1.0 - 1.0 * (dist / dist_max) * math.exp(- 1.0 * (self.i - self.last_good_idx - 1)) + + return weight_penalty + + def tracking(self, image): + self.i += 1 + + local_state, self.score_map, update, local_score, dis, flag = self.local_track(image) + local_score = np.clip(local_score, 0, 1) + + stark_state, stark_score = self.local_track_stark(image) + + if self.md_scores_sum[-1] > 4: + max_dim = np.argmax([self.boxes[-1][2], self.boxes[-1][3]]) + max_dim_idx = 2 + max_dim + min_dim_idx = 2 + (1 - max_dim) + base_ar = self.boxes[-1][max_dim_idx] / self.boxes[-1][min_dim_idx] + ar = stark_state[max_dim_idx] / stark_state[min_dim_idx] + if base_ar > ar: + if (np.abs(ar - base_ar) > (0.4 * base_ar)): + stark_score = 0.0 + else: + if (np.abs(ar - base_ar) > (1.35 * base_ar)): + stark_score = 0.0 + + md_score_dimp = self.pymdnet_eval(image, np.array(local_state).reshape([-1, 4]))[0] + md_score_dimp = np.clip((local_score + np.arctan(0.2 * md_score_dimp) / math.pi + 0.5) / 2, 0, 1) + #dist_penalty_dimp = self.dist_penalty(local_state) + #md_score_dimp *= dist_penalty_dimp + md_score_stark = self.pymdnet_eval(image, np.array(stark_state).reshape([-1, 4]))[0] + md_score_stark = np.clip((stark_score + np.arctan(0.2 * md_score_stark) / math.pi + 0.5) / 2, 0, 1) + #dist_penalty_stark = self.dist_penalty(stark_state) + #md_score_stark *= dist_penalty_stark + + self.md_scores_dimp.append(md_score_dimp) + self.md_scores_stark.append(md_score_stark) + + if len(self.md_scores_dimp) > 5: + md_scores = [(np.array(self.md_scores_stark)[-5:] > 0.5).sum(), (np.array(self.md_scores_dimp)[-5:] > 0.5).sum()] + else: + md_scores = [md_score_stark, md_score_dimp] + md_scores_1 = [md_score_stark, md_score_dimp] + all_scores = [self.md_scores_stark, self.md_scores_dimp] + bboxes = [copy.copy(stark_state), copy.copy(local_state)] + md_score = max(md_scores) + md_idx = np.argmax(md_scores) + + + if md_score > 3: + + if md_idx == 0: + self.local_Tracker.pos = torch.FloatTensor([(stark_state[1] + stark_state[3] + stark_state[1] - 1) / 2, (stark_state[0] + stark_state[2] + stark_state[0] - 1) / 2]) + self.local_Tracker.target_sz = torch.FloatTensor([stark_state[3], stark_state[2]]) + + self.last_gt = np.array([stark_state[1], stark_state[0], stark_state[1] + stark_state[3], stark_state[0] + stark_state[2]]) + + confidence_score = md_score_stark + + else: + self.stark_tracker.tracker.state = [int(local_state[0]), int(local_state[1]), int(local_state[2]), int(local_state[3])] + + self.last_gt = np.array([local_state[1], local_state[0], local_state[1] + local_state[3], local_state[0] + local_state[2]]) + + confidence_score = md_score_dimp + + self.stark_tracker.tracker.params.search_factor = 2.5 + self.last_good = copy.copy(self.last_gt) + self.last_good_idx = copy.copy(self.i) + + else: + new_box = bboxes[md_idx] + + self.last_gt = np.array([new_box[1], new_box[0], new_box[1] + new_box[3], new_box[0] + new_box[2]]) + + confidence_score = (md_score_stark + md_score_dimp) / 2 + + self.stark_tracker.tracker.params.search_factor = 5.0 + + + if update or (md_scores[0] == 5 and md_scores[1] == 5): + self.collect_samples_pymdnet(image) + + self.pymdnet_long_term_update() + + width = self.last_gt[3] - self.last_gt[1] + height = self.last_gt[2] - self.last_gt[0] + + self.boxes.append(np.array([float(self.last_gt[1]), float(self.last_gt[0]), float(width), float(height)])) + self.boxes_stark.append(np.array(stark_state)) + self.boxes_dimp.append(np.array(local_state)) + self.confidences.append(int(self.score_max > 0)) + + self.md_scores_sum.append(md_score) + + return vot.Rectangle(float(self.last_gt[1]), float(self.last_gt[0]), float(width), + float(height)), confidence_score + diff --git a/README.md b/README.md new file mode 100755 index 0000000..bb6dc12 --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +### CoCoLoT: Combining Complementary Trackers in Long-Term Visual Tracking + +🏆 Winner of the [Visual Object Tracking VOT2021 Long-term Challenge](https://openaccess.thecvf.com/content/ICCV2021W/VOT/papers/Kristan_The_Ninth_Visual_Object_Tracking_VOT2021_Challenge_Results_ICCVW_2021_paper.pdf) (aka mlpLT) + +Matteo Dunnhofer, Kristian Simonato, Christian Micheloni + +Machine Learning and Perception Lab +Department of Mathematics, Computer Science and Physics +University of Udine +Udine, Italy + +##### Hardware and OS specifications +CPU Intel Xeon E5-2690 v4 @ 2.60GHz +GPU NVIDIA TITAN V +320 GB of RAM +OS: Ubuntu 20.04 + +#### VOT-LT test instructions +To run the VOT Challenge Long-term experiments please follow these instructions: + ++ Clone the repository ``git clone https://github.com/matteo-dunnhofer/CoCoLoT`` + ++ Download the pre-trained weights files ``STARKST_ep0050.pth.tar``, ``super_dimp.pth.tar`` from [here](https://drive.google.com/drive/folders/1W_ePPy5HoLgcGbUE5Gh_0HZ034szvSiQ?usp=sharing) and put them in the folder ``CoCoLoT/ckpt/`` + ++ Move to the submission source folder ``cd CoCoLoT`` + ++ Create the Anaconda environment ``conda env create -f environment.yml`` + ++ Activate the environment ``conda activate CoCoLoT`` + ++ Install ninja-build ``sudo apt-get install ninja-build`` + ++ Edit the variable ``base_path`` in the file ``vot_path.py`` by providing the full-path to the location where the submission folder is stored, +and do the same in the file ``trackers.ini`` by substituting the paths ``[full-path-to-CoCoLoT]`` in line 9 and 13 + ++ Run ``python compile_pytracking.py`` + ++ Run the analysis by ``vot evaluate CoCoLoT`` + ++ Run the evaluation by ``vot analysis CoCoLoT`` + +#### If you fail to run our tracker please write to ``matteo.dunnhofer@uniud.it`` + +#### An improved version of CoCoLoT exploiting Stark and KeepTrack is downloadable [here](http://data.votchallenge.net/vot2022/trackers/CoCoLoT-code-2022-04-28T08_08_35.527492.zip). + +#### References + +If you find this code useful please cite: + +``` +@INPROCEEDINGS{9956082, + author={Dunnhofer, Matteo and Micheloni, Christian}, + booktitle={2022 26th International Conference on Pattern Recognition (ICPR)}, + title={CoCoLoT: Combining Complementary Trackers in Long-Term Visual Tracking}, + year={2022}, + pages={5132-5139}, + doi={10.1109/ICPR56361.2022.9956082} +} + +@article{Dunnhofer2022imavis, + title = {Combining complementary trackers for enhanced long-term visual object tracking}, + journal = {Image and Vision Computing}, + volume = {122}, + year = {2022}, + doi = {https://doi.org/10.1016/j.imavis.2022.104448} +} +``` + +The code presented here is built up on the following repositories: + + [pytracking](https://github.com/visionml/pytracking) + + [Stark](https://github.com/researchmm/Stark) + + [LTMU](https://github.com/Daikenan/LTMU) diff --git a/Stark/MODEL_ZOO.md b/Stark/MODEL_ZOO.md new file mode 100755 index 0000000..be81ea3 --- /dev/null +++ b/Stark/MODEL_ZOO.md @@ -0,0 +1,123 @@ +# STARK Model Zoo + +Here we provide the performance of the STARK trackers on multiple tracking benchmarks and the corresponding raw results. +The model weights and the corresponding training logs are also given by the links. + +## Tracking +### Models & Logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModelLaSOT
AUC (%)
GOT-10k
AO (%)
TrackingNet
AUC (%)
VOT2020
EAO
VOT2020-LT
F-score (%)
ModelsLogsLogs(GOT10K)
STARK-S5065.867.280.30.462-modelloglog
STARK-ST5066.468.081.30.50570.2modelloglog
STARK-ST10167.168.882.00.49770.1modelloglog
+ +The downloaded checkpoints should be organized in the following structure + ``` + ${STARK_ROOT} + -- checkpoints + -- train + -- stark_s + -- baseline + STARKS_ep0500.pth.tar + -- baseline_got10k_only + STARKS_ep0500.pth.tar + -- stark_st2 + -- baseline + STARKST_ep0050.pth.tar + -- baseline_got10k_only + STARKST_ep0050.pth.tar + -- baseline_R101 + STARKST_ep0050.pth.tar + -- baseline_R101_got10k_only + STARKST_ep0050.pth.tar + ``` +### Raw Results +The raw results are in the format [top_left_x, top_left_y, width, height]. Raw results of GOT-10K and TrackingNet can be +directly submitted to the corresponding evaluation servers. The folder ```test/tracking_results/``` contains raw results +for the LaSOT dataset and results should be organized in the following structure + ``` + ${STARK_ROOT} + -- test + -- tracking_results + -- stark_s + -- baseline + airplane-1.txt + airplane-13.txt + ... + -- stark_st2 + -- baseline + airplane-1.txt + airplane-13.txt + ... + -- baseline_R101 + airplane-1.txt + airplane-13.txt + ... + ``` +The raw results of VOT2020 and VOT2020-LT should be organized in the following structure + ``` + ${STARK_ROOT} + -- external + -- vot20 + -- stark_s50 + -- results + -- stark_s50_ar + -- results + -- stark_st50 + -- results + -- stark_st50_ar + -- results + -- stark_st101 + -- results + -- stark_st101_ar + -- results + -- vot20_lt + -- stark_st50 + -- results + -- stark_st101 + -- results + ``` \ No newline at end of file diff --git a/Stark/README.md b/Stark/README.md new file mode 100755 index 0000000..db25e73 --- /dev/null +++ b/Stark/README.md @@ -0,0 +1,139 @@ +# STARK +[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/learning-spatio-temporal-transformer-for/visual-object-tracking-on-lasot)](https://paperswithcode.com/sota/visual-object-tracking-on-lasot?p=learning-spatio-temporal-transformer-for) +[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/learning-spatio-temporal-transformer-for/visual-object-tracking-on-got-10k)](https://paperswithcode.com/sota/visual-object-tracking-on-got-10k?p=learning-spatio-temporal-transformer-for) +[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/learning-spatio-temporal-transformer-for/visual-object-tracking-on-trackingnet)](https://paperswithcode.com/sota/visual-object-tracking-on-trackingnet?p=learning-spatio-temporal-transformer-for) + +The official implementation of the paper [**Learning Spatio-Temporal Transformer for Visual Tracking**](https://arxiv.org/abs/2103.17154) + +Hiring research interns for visual transformer projects: houwen.peng@microsoft.com + + +![STARK_Framework](tracking/Framework.png) +## Highlights +### End-to-End, Post-processing Free + +STARK is an **end-to-end** tracking approach, which directly predicts one accurate bounding box as the tracking result. +Besides, STARK does not use any hyperparameters-sensitive post-processing, leading to stable performances. + +### Real-Time Speed +STARK-ST50 and STARK-ST101 run at **40FPS** and **30FPS** respectively on a Tesla V100 GPU. + +### Strong performance +| Tracker | LaSOT (AUC)| GOT-10K (AO)| TrackingNet (AUC)| +|---|---|---|---| +|**STARK**|**67.1**|**68.8**|**82.0**| +|TransT|64.9|67.1|81.4| +|TrDiMP|63.7|67.1|78.4| +|Siam R-CNN|64.8|64.9|81.2| + +### Purely PyTorch-based Code + +STARK is implemented purely based on the PyTorch. + +## Install the environment +**Option1**: Use the Anaconda +``` +conda create -n stark python=3.6 +conda activate stark +bash install.sh +``` +**Option2**: Use the docker file + +We provide the complete docker at [here](https://hub.docker.com/repository/docker/alphabin/stark) + +## Data Preparation +Put the tracking datasets in ./data. It should look like: + ``` + ${STARK_ROOT} + -- data + -- lasot + |-- airplane + |-- basketball + |-- bear + ... + -- got10k + |-- test + |-- train + |-- val + -- coco + |-- annotations + |-- images + -- trackingnet + |-- TRAIN_0 + |-- TRAIN_1 + ... + |-- TRAIN_11 + |-- TEST + ``` +Run the following command to set paths for this project +``` +python tracking/create_default_local_file.py --workspace_dir . --data_dir ./data --save_dir . +``` +After running this command, you can also modify paths by editing these two files +``` +lib/train/admin/local.py # paths about training +lib/test/evaluation/local.py # paths about testing +``` + +## Train STARK +Training with multiple GPUs using DDP +``` +# STARK-S50 +python tracking/train.py --script stark_s --config baseline --save_dir . --mode multiple --nproc_per_node 8 # STARK-S50 +# STARK-ST50 +python tracking/train.py --script stark_st1 --config baseline --save_dir . --mode multiple --nproc_per_node 8 # STARK-ST50 Stage1 +python tracking/train.py --script stark_st2 --config baseline --save_dir . --mode multiple --nproc_per_node 8 --script_prv stark_st1 --config_prv baseline # STARK-ST50 Stage2 +# STARK-ST101 +python tracking/train.py --script stark_st1 --config baseline_R101 --save_dir . --mode multiple --nproc_per_node 8 # STARK-ST101 Stage1 +python tracking/train.py --script stark_st2 --config baseline_R101 --save_dir . --mode multiple --nproc_per_node 8 --script_prv stark_st1 --config_prv baseline_R101 # STARK-ST101 Stage2 +``` +(Optionally) Debugging training with a single GPU +``` +python tracking/train.py --script stark_s --config baseline --save_dir . --mode single +``` +## Test and evaluate STARK on benchmarks + +- LaSOT +``` +python tracking/test.py stark_st baseline --dataset lasot --threads 32 +python tracking/analysis_results.py # need to modify tracker configs and names +``` +- GOT10K-test +``` +python tracking/test.py stark_st baseline_got10k_only --dataset got10k_test --threads 32 +python lib/test/utils/transform_got10k.py --tracker_name stark_st --cfg_name baseline_got10k_only +``` +- TrackingNet +``` +python tracking/test.py stark_st baseline --dataset trackingnet --threads 32 +python lib/test/utils/transform_trackingnet.py --tracker_name stark_st --cfg_name baseline +``` +- VOT2020 +Before evaluating "STARK+AR" on VOT2020, please install some extra packages following [external/AR/README.md](external/AR/README.md) +``` +cd external/vot20/ +export PYTHONPATH=:$PYTHONPATH +bash exp.sh +``` +- VOT2020-LT +``` +cd external/vot20_lt/ +export PYTHONPATH=:$PYTHONPATH +bash exp.sh +``` +## Test FLOPs, Params, and Speed +``` +# Profiling STARK-S50 model +python tracking/profile_model.py --script stark_s --config baseline +# Profiling STARK-ST50 model +python tracking/profile_model.py --script stark_st2 --config baseline +# Profiling STARK-ST101 model +python tracking/profile_model.py --script stark_st2 --config baseline_R101 +``` + +## Model Zoo +The trained models, the training logs, and the raw tracking results are provided in the [model zoo](MODEL_ZOO.md) + +## Acknowledgments +* Thanks for the great [PyTracking](https://github.com/visionml/pytracking) Library, which helps us to quickly implement our ideas. +* We use the implementation of the DETR from the official repo [https://github.com/facebookresearch/detr](https://github.com/facebookresearch/detr). diff --git a/Stark/experiments/stark_s/baseline.yaml b/Stark/experiments/stark_s/baseline.yaml new file mode 100755 index 0000000..d1273a8 --- /dev/null +++ b/Stark/experiments/stark_s/baseline.yaml @@ -0,0 +1,85 @@ +DATA: + MAX_SAMPLE_INTERVAL: 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + TRAIN: + DATASETS_NAME: + - LASOT + - GOT10K_vottrain + - COCO17 + - TRACKINGNET + DATASETS_RATIO: + - 1 + - 1 + - 1 + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + TYPE: resnet50 + HEAD_TYPE: CORNER + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + SCHEDULER: + TYPE: step + DECAY_RATE: 0.1 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 500 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 \ No newline at end of file diff --git a/Stark/experiments/stark_s/baseline_got10k_only.yaml b/Stark/experiments/stark_s/baseline_got10k_only.yaml new file mode 100755 index 0000000..a789fb7 --- /dev/null +++ b/Stark/experiments/stark_s/baseline_got10k_only.yaml @@ -0,0 +1,79 @@ +DATA: + MAX_SAMPLE_INTERVAL: 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + TRAIN: + DATASETS_NAME: + - GOT10K_train_full + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + TYPE: resnet50 + HEAD_TYPE: CORNER + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + SCHEDULER: + TYPE: step + DECAY_RATE: 0.1 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 500 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 \ No newline at end of file diff --git a/Stark/experiments/stark_st1/baseline.yaml b/Stark/experiments/stark_st1/baseline.yaml new file mode 100755 index 0000000..600c9fa --- /dev/null +++ b/Stark/experiments/stark_st1/baseline.yaml @@ -0,0 +1,81 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - LASOT + - GOT10K_vottrain + - COCO17 + - TRACKINGNET + DATASETS_RATIO: + - 1 + - 1 + - 1 + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet50 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 diff --git a/Stark/experiments/stark_st1/baseline_R101.yaml b/Stark/experiments/stark_st1/baseline_R101.yaml new file mode 100755 index 0000000..7174588 --- /dev/null +++ b/Stark/experiments/stark_st1/baseline_R101.yaml @@ -0,0 +1,81 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - LASOT + - GOT10K_vottrain + - COCO17 + - TRACKINGNET + DATASETS_RATIO: + - 1 + - 1 + - 1 + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet101 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 diff --git a/Stark/experiments/stark_st1/baseline_R101_got10k_only.yaml b/Stark/experiments/stark_st1/baseline_R101_got10k_only.yaml new file mode 100755 index 0000000..e3e5aa9 --- /dev/null +++ b/Stark/experiments/stark_st1/baseline_R101_got10k_only.yaml @@ -0,0 +1,75 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - GOT10K_train_full + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet101 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 diff --git a/Stark/experiments/stark_st1/baseline_got10k_only.yaml b/Stark/experiments/stark_st1/baseline_got10k_only.yaml new file mode 100755 index 0000000..6354d28 --- /dev/null +++ b/Stark/experiments/stark_st1/baseline_got10k_only.yaml @@ -0,0 +1,75 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - GOT10K_train_full + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet50 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 500 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GIOU_WEIGHT: 2.0 + GRAD_CLIP_NORM: 0.1 + L1_WEIGHT: 5.0 + LR: 0.0001 + LR_DROP_EPOCH: 400 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 20 + WEIGHT_DECAY: 0.0001 diff --git a/Stark/experiments/stark_st2/baseline.yaml b/Stark/experiments/stark_st2/baseline.yaml new file mode 100755 index 0000000..95bab4f --- /dev/null +++ b/Stark/experiments/stark_st2/baseline.yaml @@ -0,0 +1,92 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - LASOT + - GOT10K_vottrain + - COCO17 + - TRACKINGNET + DATASETS_RATIO: + - 1 + - 1 + - 1 + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + NLAYER_HEAD: 3 + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet50 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 50 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GRAD_CLIP_NORM: 0.1 + LR: 0.0001 + LR_DROP_EPOCH: 40 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 10 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 50 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 + UPDATE_INTERVALS: + LASOT: [200] + GOT10K_TEST: [200] + TRACKINGNET: [25] + VOT20: [10] + VOT20LT: [200] diff --git a/Stark/experiments/stark_st2/baseline_R101.yaml b/Stark/experiments/stark_st2/baseline_R101.yaml new file mode 100755 index 0000000..06502cb --- /dev/null +++ b/Stark/experiments/stark_st2/baseline_R101.yaml @@ -0,0 +1,92 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - LASOT + - GOT10K_vottrain + - COCO17 + - TRACKINGNET + DATASETS_RATIO: + - 1 + - 1 + - 1 + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + NLAYER_HEAD: 3 + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet101 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 50 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GRAD_CLIP_NORM: 0.1 + LR: 0.0001 + LR_DROP_EPOCH: 40 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 10 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 50 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 + UPDATE_INTERVALS: + LASOT: [200] + GOT10K_TEST: [200] + TRACKINGNET: [25] + VOT20: [10] + VOT20LT: [100] \ No newline at end of file diff --git a/Stark/experiments/stark_st2/baseline_R101_got10k_only.yaml b/Stark/experiments/stark_st2/baseline_R101_got10k_only.yaml new file mode 100755 index 0000000..4f1f9ea --- /dev/null +++ b/Stark/experiments/stark_st2/baseline_R101_got10k_only.yaml @@ -0,0 +1,80 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - GOT10K_train_full + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + NLAYER_HEAD: 3 + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet101 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 50 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GRAD_CLIP_NORM: 0.1 + LR: 0.0001 + LR_DROP_EPOCH: 40 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 10 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 50 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 \ No newline at end of file diff --git a/Stark/experiments/stark_st2/baseline_got10k_only.yaml b/Stark/experiments/stark_st2/baseline_got10k_only.yaml new file mode 100755 index 0000000..2642a90 --- /dev/null +++ b/Stark/experiments/stark_st2/baseline_got10k_only.yaml @@ -0,0 +1,80 @@ +DATA: + SAMPLER_MODE: trident_pro + MAX_SAMPLE_INTERVAL: + - 200 + MEAN: + - 0.485 + - 0.456 + - 0.406 + SEARCH: + CENTER_JITTER: 4.5 + FACTOR: 5.0 + SCALE_JITTER: 0.5 + SIZE: 320 + NUMBER: 1 + STD: + - 0.229 + - 0.224 + - 0.225 + TEMPLATE: + CENTER_JITTER: 0 + FACTOR: 2.0 + SCALE_JITTER: 0 + SIZE: 128 + NUMBER: 2 + TRAIN: + DATASETS_NAME: + - GOT10K_train_full + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 60000 + VAL: + DATASETS_NAME: + - GOT10K_votval + DATASETS_RATIO: + - 1 + SAMPLE_PER_EPOCH: 10000 +MODEL: + HEAD_TYPE: CORNER + NLAYER_HEAD: 3 + BACKBONE: + DILATION: false + OUTPUT_LAYERS: + - layer3 + STRIDE: 16 + TYPE: resnet50 + HIDDEN_DIM: 256 + NUM_OBJECT_QUERIES: 1 + POSITION_EMBEDDING: sine + PREDICT_MASK: false + TRANSFORMER: + DEC_LAYERS: 6 + DIM_FEEDFORWARD: 2048 + DIVIDE_NORM: false + DROPOUT: 0.1 + ENC_LAYERS: 6 + NHEADS: 8 + PRE_NORM: false +TRAIN: + BACKBONE_MULTIPLIER: 0.1 + BATCH_SIZE: 16 + DEEP_SUPERVISION: false + EPOCH: 50 + FREEZE_BACKBONE_BN: true + FREEZE_LAYERS: + - conv1 + - layer1 + GRAD_CLIP_NORM: 0.1 + LR: 0.0001 + LR_DROP_EPOCH: 40 + NUM_WORKER: 8 + OPTIMIZER: ADAMW + PRINT_INTERVAL: 50 + VAL_EPOCH_INTERVAL: 10 + WEIGHT_DECAY: 0.0001 +TEST: + EPOCH: 50 + SEARCH_FACTOR: 5.0 + SEARCH_SIZE: 320 + TEMPLATE_FACTOR: 2.0 + TEMPLATE_SIZE: 128 \ No newline at end of file diff --git a/Stark/external/AR/README.md b/Stark/external/AR/README.md new file mode 100755 index 0000000..eba8066 --- /dev/null +++ b/Stark/external/AR/README.md @@ -0,0 +1,42 @@ +# Alpha-Refine +## Introduction +Alpha-Refine is the winner of the VOT Real-Time Challenge 2020, which has great ability to predict high-quality masks. +In this work, we combine the STARK tracker with Alpha-Refine to test on the VOT2020 benchamark. + +## Installation +After the environment has been installed according to the README.md of STARK, you only need to install a few more packages as shown below. + +* Install ninja-build for Precise ROI pooling +```bash +sudo apt-get install ninja-build +``` +In case of issues, we refer to https://github.com/vacancy/PreciseRoIPooling. + +* Install the Precise ROI pooling +``` +cd ltr/external +git clone https://github.com/vacancy/PreciseRoIPooling.git +cd ../.. +``` +* Add the project path to environment variables +``` +export PYTHONPATH=:$PYTHONPATH +``` + +* Setup the environment + +Create the default environment setting files. +```bash +# Environment settings for pytracking. Saved at pytracking/evaluation/local.py +python -c "from pytracking.evaluation.environment import create_default_local_file; create_default_local_file()" + +# Environment settings for ltr. Saved at ltr/admin/local.py +python -c "from ltr.admin.environment import create_default_local_file; create_default_local_file()" +``` + +You can modify these files to set the paths to datasets, results paths etc. + +* Download the pre-trained Alpha-Refine network +Download the network for [Alpha-Refine](https://drive.google.com/open?id=1qOQRfaRMbQ2nmgX1NFjoQHfXOAn609QM) +and put it under the ltr/checkpoints/ltr/ARcm_seg/ARcm_coco_seg_only_mask_384 dir. + diff --git a/Stark/external/AR/ltr/README.md b/Stark/external/AR/ltr/README.md new file mode 100755 index 0000000..23b5d94 --- /dev/null +++ b/Stark/external/AR/ltr/README.md @@ -0,0 +1,75 @@ +# LTR + +A general PyTorch based framework for learning tracking representations. +## Table of Contents + +* [Quick Start](#quick-start) +* [Overview](#overview) +* [Trackers](#trackers) + * [PrDiMP](#PrDiMP) + * [DiMP](#DiMP) + * [ATOM](#ATOM) +* [Training your own networks](#training-your-own-networks) + +## Quick Start +The installation script will automatically generate a local configuration file "admin/local.py". In case the file was not generated, run ```admin.environment.create_default_local_file()``` to generate it. Next, set the paths to the training workspace, +i.e. the directory where the checkpoints will be saved. Also set the paths to the datasets you want to use. If all the dependencies have been correctly installed, you can train a network using the run_training.py script in the correct conda environment. +```bash +conda activate pytracking +python run_training.py train_module train_name +``` +Here, ```train_module``` is the sub-module inside ```train_settings``` and ```train_name``` is the name of the train setting file to be used. + +For example, you can train using the included default ATOM settings by running: +```bash +python run_training bbreg atom_default +``` + + +## Overview +The framework consists of the following sub-modules. + - [actors](actors): Contains the actor classes for different trainings. The actor class is responsible for passing the input data through the network can calculating losses. + - [admin](admin): Includes functions for loading networks, tensorboard etc. and also contains environment settings. + - [dataset](dataset): Contains integration of a number of training datasets, namely [TrackingNet](https://tracking-net.org/), [GOT-10k](http://got-10k.aitestunion.com/), [LaSOT](https://cis.temple.edu/lasot/), + [ImageNet-VID](http://image-net.org/), [DAVIS](https://davischallenge.org), [YouTube-VOS](https://youtube-vos.org), [MS-COCO](http://cocodataset.org/#home), [SBD](http://home.bharathh.info/pubs/codes/SBD), [LVIS](https://www.lvisdataset.org), [ECSSD](http://www.cse.cuhk.edu.hk/leojia/projects/hsaliency/dataset.html), [MSRA10k](https://mmcheng.net/msra10k), and [HKU-IS](https://sites.google.com/site/ligb86/hkuis). Additionally, it includes modules to generate synthetic videos from image datasets. + - [data_specs](data_specs): Information about train/val splits of different datasets. + - [data](data): Contains functions for processing data, e.g. loading images, data augmentations, sampling frames from videos. + - [external](external): External libraries needed for training. Added as submodules. + - [models](models): Contains different layers and network definitions. + - [trainers](trainers): The main class which runs the training. + - [train_settings](train_settings): Contains settings files, specifying the training of a network. + +## Trackers + The framework currently contains the training code for the following trackers. + +### PrDiMP + The following setting files can be used train the DiMP networks, or to know the exact training details. + - [dimp.prdimp18](train_settings/dimp/prdimp18.py): The default settings used for training the PrDiMP model with ResNet-18 backbone. + - [dimp.prdimp50](train_settings/dimp/prdimp50.py): The default settings used for training the PrDiMP model with ResNet-50 backbone. + - [dimp.super_dimp](train_settings/dimp/super_dimp.py): Combines the bounding-box regressor of PrDiMP with the standard DiMP classifier and better training and inference settings. + +### DiMP + The following setting files can be used train the DiMP networks, or to know the exact training details. + - [dimp.dimp18](train_settings/dimp/dimp18.py): The default settings used for training the DiMP model with ResNet-18 backbone. + - [dimp.dimp50](train_settings/dimp/dimp50.py): The default settings used for training the DiMP model with ResNet-50 backbone. + +### ATOM + The following setting file can be used train the ATOM network, or to know the exact training details. + - [bbreg.atom](train_settings/bbreg/atom_paper.py): The settings used in the paper for training the network in ATOM. + - [bbreg.atom](train_settings/bbreg/atom.py): Newer settings used for training the network in ATOM, also utilizing the GOT10k dataset. + - [bbreg.atom](train_settings/bbreg/atom_prob_ml.py): Settings for ATOM with the probabilistic bounding box regression proposed in [this paper](https://arxiv.org/abs/1909.12297). + - [bbreg.atom](train_settings/bbreg/atom_paper.py): The baseline ATOM* setting evaluated in [this paper](https://arxiv.org/abs/1909.12297). + +## Training your own networks +To train a custom network using the toolkit, the following components need to be specified in the train settings. For reference, see [atom.py](train_settings/bbreg/atom.py). +- Datasets: The datasets to be used for training. A number of standard tracking datasets are already available in ```dataset``` module. +- Processing: This function should perform the necessary post-processing of the data, e.g. cropping of target region, data augmentations etc. +- Sampler: Determines how the frames are sampled from a video sequence to form the batches. +- Network: The network module to be trained. +- Objective: The training objective. +- Actor: The trainer passes the training batch to the actor who is responsible for passing the data through the network correctly, and calculating the training loss. +- Optimizer: Optimizer to be used, e.g. Adam. +- Trainer: The main class which runs the epochs and saves checkpoints. + + + \ No newline at end of file diff --git a/Stark/external/AR/ltr/__init__.py b/Stark/external/AR/ltr/__init__.py new file mode 100755 index 0000000..a7b6f67 --- /dev/null +++ b/Stark/external/AR/ltr/__init__.py @@ -0,0 +1,3 @@ +from .admin.loading import load_network +from .admin.model_constructor import model_constructor +from .admin.multigpu import MultiGPU \ No newline at end of file diff --git a/Stark/external/AR/ltr/actors/__init__.py b/Stark/external/AR/ltr/actors/__init__.py new file mode 100755 index 0000000..c269c6e --- /dev/null +++ b/Stark/external/AR/ltr/actors/__init__.py @@ -0,0 +1,3 @@ +from .base_actor import BaseActor +from .bbreg import AtomActor +from .tracking import DiMPActor \ No newline at end of file diff --git a/Stark/external/AR/ltr/actors/base_actor.py b/Stark/external/AR/ltr/actors/base_actor.py new file mode 100755 index 0000000..6424272 --- /dev/null +++ b/Stark/external/AR/ltr/actors/base_actor.py @@ -0,0 +1,44 @@ +from pytracking import TensorDict + + +class BaseActor: + """ Base class for actor. The actor class handles the passing of the data through the network + and calculation the loss""" + def __init__(self, net, objective): + """ + args: + net - The network to train + objective - The loss function + """ + self.net = net + self.objective = objective + + def __call__(self, data: TensorDict): + """ Called in each training iteration. Should pass in input data through the network, calculate the loss, and + return the training stats for the input data + args: + data - A TensorDict containing all the necessary data blocks. + + returns: + loss - loss for the input data + stats - a dict containing detailed losses + """ + raise NotImplementedError + + def to(self, device): + """ Move the network to device + args: + device - device to use. 'cpu' or 'cuda' + """ + self.net.to(device) + + def train(self, mode=True): + """ Set whether the network is in train mode. + args: + mode (True) - Bool specifying whether in training mode. + """ + self.net.train(mode) + + def eval(self): + """ Set network to eval mode""" + self.train(False) \ No newline at end of file diff --git a/Stark/external/AR/ltr/actors/bbreg.py b/Stark/external/AR/ltr/actors/bbreg.py new file mode 100755 index 0000000..f07f49e --- /dev/null +++ b/Stark/external/AR/ltr/actors/bbreg.py @@ -0,0 +1,58 @@ +from . import BaseActor + + +class AtomActor(BaseActor): + """ Actor for training the IoU-Net in ATOM""" + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals' and 'proposal_iou'. + + returns: + loss - the training loss + states - dict containing detailed losses + """ + # Run network to obtain IoU prediction for each proposal in 'test_proposals' + iou_pred = self.net(data['train_images'], data['test_images'], data['train_anno'], data['test_proposals']) + + iou_pred = iou_pred.view(-1, iou_pred.shape[2]) + iou_gt = data['proposal_iou'].view(-1, data['proposal_iou'].shape[2]) + + # Compute loss + loss = self.objective(iou_pred, iou_gt) + + # Return training stats + stats = {'Loss/total': loss.item(), + 'Loss/iou': loss.item()} + + return loss, stats + + +class AtomBBKLActor(BaseActor): + """ Actor for training the IoU-Net in ATOM with BBKL""" + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_density', and 'gt_density'. + + returns: + loss - the training loss + states - dict containing detailed losses + """ + # Run network to obtain IoU prediction for each proposal in 'test_proposals' + bb_scores = self.net(data['train_images'], data['test_images'], data['train_anno'], data['test_proposals']) + + bb_scores = bb_scores.view(-1, bb_scores.shape[2]) + proposal_density = data['proposal_density'].view(-1, data['proposal_density'].shape[2]) + gt_density = data['gt_density'].view(-1, data['gt_density'].shape[2]) + + # Compute loss + loss = self.objective(bb_scores, sample_density=proposal_density, gt_density=gt_density, mc_dim=1) + + # Return training stats + stats = {'Loss/total': loss.item(), + 'Loss/bb_ce': loss.item()} + + return loss, stats diff --git a/Stark/external/AR/ltr/actors/tracking.py b/Stark/external/AR/ltr/actors/tracking.py new file mode 100755 index 0000000..9562477 --- /dev/null +++ b/Stark/external/AR/ltr/actors/tracking.py @@ -0,0 +1,193 @@ +from . import BaseActor +import torch + + +class DiMPActor(BaseActor): + """Actor for training the DiMP network.""" + def __init__(self, net, objective, loss_weight=None): + super().__init__(net, objective) + if loss_weight is None: + loss_weight = {'iou': 1.0, 'test_clf': 1.0} + self.loss_weight = loss_weight + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_iou' and 'test_label'. + + returns: + loss - the training loss + stats - dict containing detailed losses + """ + # Run network + target_scores, iou_pred = self.net(train_imgs=data['train_images'], + test_imgs=data['test_images'], + train_bb=data['train_anno'], + test_proposals=data['test_proposals']) + + # Classification losses for the different optimization iterations + clf_losses_test = [self.objective['test_clf'](s, data['test_label'], data['test_anno']) for s in target_scores] + + # Loss of the final filter + clf_loss_test = clf_losses_test[-1] + loss_target_classifier = self.loss_weight['test_clf'] * clf_loss_test + + # Compute loss for ATOM IoUNet + loss_iou = self.loss_weight['iou'] * self.objective['iou'](iou_pred, data['proposal_iou']) + + # Loss for the initial filter iteration + loss_test_init_clf = 0 + if 'test_init_clf' in self.loss_weight.keys(): + loss_test_init_clf = self.loss_weight['test_init_clf'] * clf_losses_test[0] + + # Loss for the intermediate filter iterations + loss_test_iter_clf = 0 + if 'test_iter_clf' in self.loss_weight.keys(): + test_iter_weights = self.loss_weight['test_iter_clf'] + if isinstance(test_iter_weights, list): + loss_test_iter_clf = sum([a*b for a, b in zip(test_iter_weights, clf_losses_test[1:-1])]) + else: + loss_test_iter_clf = (test_iter_weights / (len(clf_losses_test) - 2)) * sum(clf_losses_test[1:-1]) + + # Total loss + loss = loss_iou + loss_target_classifier + loss_test_init_clf + loss_test_iter_clf + + # Log stats + stats = {'Loss/total': loss.item(), + 'Loss/iou': loss_iou.item(), + 'Loss/target_clf': loss_target_classifier.item()} + if 'test_init_clf' in self.loss_weight.keys(): + stats['Loss/test_init_clf'] = loss_test_init_clf.item() + if 'test_iter_clf' in self.loss_weight.keys(): + stats['Loss/test_iter_clf'] = loss_test_iter_clf.item() + stats['ClfTrain/test_loss'] = clf_loss_test.item() + if len(clf_losses_test) > 0: + stats['ClfTrain/test_init_loss'] = clf_losses_test[0].item() + if len(clf_losses_test) > 2: + stats['ClfTrain/test_iter_loss'] = sum(clf_losses_test[1:-1]).item() / (len(clf_losses_test) - 2) + + return loss, stats + + +class KLDiMPActor(BaseActor): + """Actor for training the DiMP network.""" + def __init__(self, net, objective, loss_weight=None): + super().__init__(net, objective) + if loss_weight is None: + loss_weight = {'bb_ce': 1.0} + self.loss_weight = loss_weight + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_iou' and 'test_label'. + + returns: + loss - the training loss + stats - dict containing detailed losses + """ + # Run network + target_scores, bb_scores = self.net(train_imgs=data['train_images'], + test_imgs=data['test_images'], + train_bb=data['train_anno'], + test_proposals=data['test_proposals']) + + # Reshape bb reg variables + is_valid = data['test_anno'][:, :, 0] < 99999.0 + bb_scores = bb_scores[is_valid, :] + proposal_density = data['proposal_density'][is_valid, :] + gt_density = data['gt_density'][is_valid, :] + + # Compute loss + bb_ce = self.objective['bb_ce'](bb_scores, sample_density=proposal_density, gt_density=gt_density, mc_dim=1) + loss_bb_ce = self.loss_weight['bb_ce'] * bb_ce + + # If standard DiMP classifier is used + loss_target_classifier = 0 + loss_test_init_clf = 0 + loss_test_iter_clf = 0 + if 'test_clf' in self.loss_weight.keys(): + # Classification losses for the different optimization iterations + clf_losses_test = [self.objective['test_clf'](s, data['test_label'], data['test_anno']) for s in target_scores] + + # Loss of the final filter + clf_loss_test = clf_losses_test[-1] + loss_target_classifier = self.loss_weight['test_clf'] * clf_loss_test + + # Loss for the initial filter iteration + if 'test_init_clf' in self.loss_weight.keys(): + loss_test_init_clf = self.loss_weight['test_init_clf'] * clf_losses_test[0] + + # Loss for the intermediate filter iterations + if 'test_iter_clf' in self.loss_weight.keys(): + test_iter_weights = self.loss_weight['test_iter_clf'] + if isinstance(test_iter_weights, list): + loss_test_iter_clf = sum([a * b for a, b in zip(test_iter_weights, clf_losses_test[1:-1])]) + else: + loss_test_iter_clf = (test_iter_weights / (len(clf_losses_test) - 2)) * sum(clf_losses_test[1:-1]) + + # If PrDiMP classifier is used + loss_clf_ce = 0 + loss_clf_ce_init = 0 + loss_clf_ce_iter = 0 + if 'clf_ce' in self.loss_weight.keys(): + # Classification losses for the different optimization iterations + clf_ce_losses = [self.objective['clf_ce'](s, data['test_label_density'], grid_dim=(-2,-1)) for s in target_scores] + + # Loss of the final filter + clf_ce = clf_ce_losses[-1] + loss_clf_ce = self.loss_weight['clf_ce'] * clf_ce + + # Loss for the initial filter iteration + if 'clf_ce_init' in self.loss_weight.keys(): + loss_clf_ce_init = self.loss_weight['clf_ce_init'] * clf_ce_losses[0] + + # Loss for the intermediate filter iterations + if 'clf_ce_iter' in self.loss_weight.keys() and len(clf_ce_losses) > 2: + test_iter_weights = self.loss_weight['clf_ce_iter'] + if isinstance(test_iter_weights, list): + loss_clf_ce_iter = sum([a * b for a, b in zip(test_iter_weights, clf_ce_losses[1:-1])]) + else: + loss_clf_ce_iter = (test_iter_weights / (len(clf_ce_losses) - 2)) * sum(clf_ce_losses[1:-1]) + + # Total loss + loss = loss_bb_ce + loss_clf_ce + loss_clf_ce_init + loss_clf_ce_iter + \ + loss_target_classifier + loss_test_init_clf + loss_test_iter_clf + + if torch.isinf(loss) or torch.isnan(loss): + raise Exception('ERROR: Loss was nan or inf!!!') + + # Log stats + stats = {'Loss/total': loss.item(), + 'Loss/bb_ce': bb_ce.item(), + 'Loss/loss_bb_ce': loss_bb_ce.item()} + if 'test_clf' in self.loss_weight.keys(): + stats['Loss/target_clf'] = loss_target_classifier.item() + if 'test_init_clf' in self.loss_weight.keys(): + stats['Loss/test_init_clf'] = loss_test_init_clf.item() + if 'test_iter_clf' in self.loss_weight.keys(): + stats['Loss/test_iter_clf'] = loss_test_iter_clf.item() + if 'clf_ce' in self.loss_weight.keys(): + stats['Loss/clf_ce'] = loss_clf_ce.item() + if 'clf_ce_init' in self.loss_weight.keys(): + stats['Loss/clf_ce_init'] = loss_clf_ce_init.item() + if 'clf_ce_iter' in self.loss_weight.keys() and len(clf_ce_losses) > 2: + stats['Loss/clf_ce_iter'] = loss_clf_ce_iter.item() + + if 'test_clf' in self.loss_weight.keys(): + stats['ClfTrain/test_loss'] = clf_loss_test.item() + if len(clf_losses_test) > 0: + stats['ClfTrain/test_init_loss'] = clf_losses_test[0].item() + if len(clf_losses_test) > 2: + stats['ClfTrain/test_iter_loss'] = sum(clf_losses_test[1:-1]).item() / (len(clf_losses_test) - 2) + + if 'clf_ce' in self.loss_weight.keys(): + stats['ClfTrain/clf_ce'] = clf_ce.item() + if len(clf_ce_losses) > 0: + stats['ClfTrain/clf_ce_init'] = clf_ce_losses[0].item() + if len(clf_ce_losses) > 2: + stats['ClfTrain/clf_ce_iter'] = sum(clf_ce_losses[1:-1]).item() / (len(clf_ce_losses) - 2) + + return loss, stats diff --git a/Stark/external/AR/ltr/admin/__init__.py b/Stark/external/AR/ltr/admin/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/admin/environment.py b/Stark/external/AR/ltr/admin/environment.py new file mode 100755 index 0000000..3509023 --- /dev/null +++ b/Stark/external/AR/ltr/admin/environment.py @@ -0,0 +1,53 @@ +import importlib +import os +from collections import OrderedDict + + +def create_default_local_file(): + path = os.path.join(os.path.dirname(__file__), 'local.py') + + empty_str = '\'\'' + default_settings = OrderedDict({ + 'workspace_dir': empty_str, + 'tensorboard_dir': 'self.workspace_dir + \'/tensorboard/\'', + 'lasot_dir': empty_str, + 'got10k_dir': empty_str, + 'trackingnet_dir': empty_str, + 'coco_dir': empty_str, + 'lvis_dir': empty_str, + 'sbd_dir': empty_str, + 'imagenet_dir': empty_str, + 'imagenetdet_dir': empty_str, + 'ecssd_dir': empty_str, + 'hkuis_dir': empty_str, + 'msra10k_dir': empty_str, + 'davis_dir': empty_str, + 'youtubevos_dir': empty_str}) + + comment = {'workspace_dir': 'Base directory for saving network checkpoints.', + 'tensorboard_dir': 'Directory for tensorboard files.'} + + with open(path, 'w') as f: + f.write('class EnvironmentSettings:\n') + f.write(' def __init__(self):\n') + + for attr, attr_val in default_settings.items(): + comment_str = None + if attr in comment: + comment_str = comment[attr] + if comment_str is None: + f.write(' self.{} = {}\n'.format(attr, attr_val)) + else: + f.write(' self.{} = {} # {}\n'.format(attr, attr_val, comment_str)) + + +def env_settings(): + env_module_name = 'ltr.admin.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.EnvironmentSettings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. Then try to run again.'.format(env_file)) diff --git a/Stark/external/AR/ltr/admin/loading.py b/Stark/external/AR/ltr/admin/loading.py new file mode 100755 index 0000000..93496c9 --- /dev/null +++ b/Stark/external/AR/ltr/admin/loading.py @@ -0,0 +1,150 @@ +import torch +import os +import sys +from pathlib import Path +import importlib +import inspect +from ltr.admin import settings as ws_settings + + +def load_trained_network(workspace_dir, network_path, checkpoint=None): + """OUTDATED. Use load_pretrained instead!""" + checkpoint_dir = os.path.join(workspace_dir, 'checkpoints') + directory = '{}/{}'.format(checkpoint_dir, network_path) + + net, _ = load_network(directory, checkpoint) + return net + + +def load_pretrained(module, name, checkpoint=None, **kwargs): + """Load a network trained using the LTR framework. This is useful when you want to initialize your new network with + a previously trained model. + args: + module - Name of the train script module. I.e. the name of the folder in ltr/train_scripts. + name - The name of the train_script. + checkpoint - You can supply the checkpoint number or the full path to the checkpoint file (see load_network). + **kwargs - These are passed to load_network (see that function). + """ + + settings = ws_settings.Settings() + network_dir = os.path.join(settings.env.workspace_dir, 'checkpoints', 'ltr', module, name) + return load_network(network_dir=network_dir, checkpoint=checkpoint, **kwargs) + + +def load_network(network_dir=None, checkpoint=None, constructor_fun_name=None, constructor_module=None, **kwargs): + """Loads a network checkpoint file. + + Can be called in two different ways: + load_checkpoint(network_dir): + Loads the checkpoint file given by the path. If checkpoint_dir is a directory, + it tries to find the latest checkpoint in that directory. + + load_checkpoint(network_dir, checkpoint=epoch_num): + Loads the network at the given epoch number (int). + + The extra keyword arguments are supplied to the network constructor to replace saved ones. + """ + + if network_dir is not None: + net_path = Path(network_dir) + else: + net_path = None + + if net_path.is_file(): + checkpoint = str(net_path) + + if checkpoint is None: + # Load most recent checkpoint + checkpoint_list = sorted(net_path.glob('*.pth.tar')) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No matching checkpoint file found') + elif isinstance(checkpoint, int): + # Checkpoint is the epoch number + checkpoint_list = sorted(net_path.glob('*_ep{:04d}.pth.tar'.format(checkpoint))) + if not checkpoint_list or len(checkpoint_list) == 0: + raise Exception('No matching checkpoint file found') + if len(checkpoint_list) > 1: + raise Exception('Multiple matching checkpoint files found') + else: + checkpoint_path = checkpoint_list[0] + elif isinstance(checkpoint, str): + # Checkpoint is the path + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + checkpoint_dict = torch_load_legacy(checkpoint_path) + + # Construct network model + if 'constructor' in checkpoint_dict and checkpoint_dict['constructor'] is not None: + net_constr = checkpoint_dict['constructor'] + if constructor_fun_name is not None: + net_constr.fun_name = constructor_fun_name + if constructor_module is not None: + net_constr.fun_module = constructor_module + # Legacy networks before refactoring + if net_constr.fun_module.startswith('dlframework.'): + net_constr.fun_module = net_constr.fun_module[len('dlframework.'):] + net_fun = getattr(importlib.import_module(net_constr.fun_module), net_constr.fun_name) + net_fun_args = list(inspect.signature(net_fun).parameters.keys()) + for arg, val in kwargs.items(): + if arg in net_fun_args: + net_constr.kwds[arg] = val + else: + print('WARNING: Keyword argument "{}" not found when loading network. It was ignored.'.format(arg)) + net = net_constr.get() + else: + raise RuntimeError('No constructor for the given network.') + + net.load_state_dict(checkpoint_dict['net']) + + net.constructor = checkpoint_dict['constructor'] + if 'net_info' in checkpoint_dict and checkpoint_dict['net_info'] is not None: + net.info = checkpoint_dict['net_info'] + + return net, checkpoint_dict + + +def load_weights(net, path, strict=True): + checkpoint_dict = torch.load(path) + weight_dict = checkpoint_dict['net'] + net.load_state_dict(weight_dict, strict=strict) + return net + + +def torch_load_legacy(path): + """Load network with legacy environment.""" + + # Setup legacy env (for older networks) + _setup_legacy_env() + + # Load network + checkpoint_dict = torch.load(path, map_location='cpu') + + # Cleanup legacy + _cleanup_legacy_env() + + return checkpoint_dict + + +def _setup_legacy_env(): + importlib.import_module('ltr') + sys.modules['dlframework'] = sys.modules['ltr'] + sys.modules['dlframework.common'] = sys.modules['ltr'] + importlib.import_module('ltr.admin') + sys.modules['dlframework.common.utils'] = sys.modules['ltr.admin'] + for m in ('model_constructor', 'stats', 'settings', 'local'): + importlib.import_module('ltr.admin.' + m) + sys.modules['dlframework.common.utils.' + m] = sys.modules['ltr.admin.' + m] + + +def _cleanup_legacy_env(): + del_modules = [] + for m in sys.modules.keys(): + if m.startswith('dlframework'): + del_modules.append(m) + for m in del_modules: + del sys.modules[m] diff --git a/Stark/external/AR/ltr/admin/model_constructor.py b/Stark/external/AR/ltr/admin/model_constructor.py new file mode 100755 index 0000000..a2c717f --- /dev/null +++ b/Stark/external/AR/ltr/admin/model_constructor.py @@ -0,0 +1,45 @@ +from functools import wraps +import importlib + + +def model_constructor(f): + """ Wraps the function 'f' which returns the network. An extra field 'constructor' is added to the network returned + by 'f'. This field contains an instance of the 'NetConstructor' class, which contains the information needed to + re-construct the network, such as the name of the function 'f', the function arguments etc. Thus, the network can + be easily constructed from a saved checkpoint by calling NetConstructor.get() function. + """ + @wraps(f) + def f_wrapper(*args, **kwds): + net_constr = NetConstructor(f.__name__, f.__module__, args, kwds) + output = f(*args, **kwds) + if isinstance(output, (tuple, list)): + # Assume first argument is the network + output[0].constructor = net_constr + else: + output.constructor = net_constr + return output + return f_wrapper + + +class NetConstructor: + """ Class to construct networks. Takes as input the function name (e.g. atom_resnet18), the name of the module + which contains the network function (e.g. ltr.models.bbreg.atom) and the arguments for the network + function. The class object can then be stored along with the network weights to re-construct the network.""" + def __init__(self, fun_name, fun_module, args, kwds): + """ + args: + fun_name - The function which returns the network + fun_module - the module which contains the network function + args - arguments which are passed to the network function + kwds - arguments which are passed to the network function + """ + self.fun_name = fun_name + self.fun_module = fun_module + self.args = args + self.kwds = kwds + + def get(self): + """ Rebuild the network by calling the network function with the correct arguments. """ + net_module = importlib.import_module(self.fun_module) + net_fun = getattr(net_module, self.fun_name) + return net_fun(*self.args, **self.kwds) diff --git a/Stark/external/AR/ltr/admin/multigpu.py b/Stark/external/AR/ltr/admin/multigpu.py new file mode 100755 index 0000000..86a77fb --- /dev/null +++ b/Stark/external/AR/ltr/admin/multigpu.py @@ -0,0 +1,15 @@ +import torch.nn as nn + + +def is_multi_gpu(net): + return isinstance(net, (MultiGPU, nn.DataParallel)) + + +class MultiGPU(nn.DataParallel): + """Wraps a network to allow simple multi-GPU training.""" + def __getattr__(self, item): + try: + return super().__getattr__(item) + except: + pass + return getattr(self.module, item) \ No newline at end of file diff --git a/Stark/external/AR/ltr/admin/settings.py b/Stark/external/AR/ltr/admin/settings.py new file mode 100755 index 0000000..0221e74 --- /dev/null +++ b/Stark/external/AR/ltr/admin/settings.py @@ -0,0 +1,13 @@ +from ltr.admin.environment import env_settings + + +class Settings: + """ Training settings, e.g. the paths to datasets and networks.""" + def __init__(self): + self.set_default() + + def set_default(self): + self.env = env_settings() + self.use_gpu = True + + diff --git a/Stark/external/AR/ltr/admin/stats.py b/Stark/external/AR/ltr/admin/stats.py new file mode 100755 index 0000000..34887fc --- /dev/null +++ b/Stark/external/AR/ltr/admin/stats.py @@ -0,0 +1,71 @@ + + +class StatValue: + def __init__(self): + self.clear() + + def reset(self): + self.val = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val): + self.val = val + self.history.append(self.val) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self): + self.clear() + self.has_new_data = False + + def reset(self): + self.avg = 0 + self.val = 0 + self.sum = 0 + self.count = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def new_epoch(self): + if self.count > 0: + self.history.append(self.avg) + self.reset() + self.has_new_data = True + else: + self.has_new_data = False + + +def topk_accuracy(output, target, topk=(1,)): + """Computes the precision@k for the specified values of k""" + single_input = not isinstance(topk, (tuple, list)) + if single_input: + topk = (topk,) + + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)[0] + res.append(correct_k * 100.0 / batch_size) + + if single_input: + return res[0] + + return res diff --git a/Stark/external/AR/ltr/admin/tensorboard.py b/Stark/external/AR/ltr/admin/tensorboard.py new file mode 100755 index 0000000..94d12ba --- /dev/null +++ b/Stark/external/AR/ltr/admin/tensorboard.py @@ -0,0 +1,28 @@ +import os +from collections import OrderedDict +try: + from torch.utils.tensorboard import SummaryWriter +except: + print('WARNING: You are using tensorboardX instead sis you have a too old pytorch version.') + from tensorboardX import SummaryWriter + + +class TensorboardWriter: + def __init__(self, directory, loader_names): + self.directory = directory + self.writer = OrderedDict({name: SummaryWriter(os.path.join(self.directory, name)) for name in loader_names}) + + def write_info(self, module_name, script_name, description): + tb_info_writer = SummaryWriter(os.path.join(self.directory, 'info')) + tb_info_writer.add_text('Modulet_name', module_name) + tb_info_writer.add_text('Script_name', script_name) + tb_info_writer.add_text('Description', description) + tb_info_writer.close() + + def write_epoch(self, stats: OrderedDict, epoch: int, ind=-1): + for loader_name, loader_stats in stats.items(): + if loader_stats is None: + continue + for var_name, val in loader_stats.items(): + if hasattr(val, 'history') and getattr(val, 'has_new_data', True): + self.writer[loader_name].add_scalar(var_name, val.history[ind], epoch) \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/__init__.py b/Stark/external/AR/ltr/data/__init__.py new file mode 100755 index 0000000..f29ac0f --- /dev/null +++ b/Stark/external/AR/ltr/data/__init__.py @@ -0,0 +1 @@ +from .loader import LTRLoader \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/bounding_box_utils.py b/Stark/external/AR/ltr/data/bounding_box_utils.py new file mode 100755 index 0000000..df0c31a --- /dev/null +++ b/Stark/external/AR/ltr/data/bounding_box_utils.py @@ -0,0 +1,94 @@ +import torch + + +def rect_to_rel(bb, sz_norm=None): + """Convert standard rectangular parametrization of the bounding box [x, y, w, h] + to relative parametrization [cx/sw, cy/sh, log(w), log(h)], where [cx, cy] is the center coordinate. + args: + bb - N x 4 tensor of boxes. + sz_norm - [N] x 2 tensor of value of [sw, sh] (optional). sw=w and sh=h if not given. + """ + + c = bb[...,:2] + 0.5 * bb[...,2:] + if sz_norm is None: + c_rel = c / bb[...,2:] + else: + c_rel = c / sz_norm + sz_rel = torch.log(bb[...,2:]) + return torch.cat((c_rel, sz_rel), dim=-1) + + +def rel_to_rect(bb, sz_norm=None): + """Inverts the effect of rect_to_rel. See above.""" + + sz = torch.exp(bb[...,2:]) + if sz_norm is None: + c = bb[...,:2] * sz + else: + c = bb[...,:2] * sz_norm + tl = c - 0.5 * sz + return torch.cat((tl, sz), dim=-1) + + +def masks_to_bboxes(mask, fmt='c'): + + """ Convert a mask tensor to one or more bounding boxes. + Note: This function is a bit new, make sure it does what it says. /Andreas + :param mask: Tensor of masks, shape = (..., H, W) + :param fmt: bbox layout. 'c' => "center + size" or (x_center, y_center, width, height) + 't' => "top left + size" or (x_left, y_top, width, height) + 'v' => "vertices" or (x_left, y_top, x_right, y_bottom) + :return: tensor containing a batch of bounding boxes, shape = (..., 4) + """ + batch_shape = mask.shape[:-2] + mask = mask.reshape((-1, *mask.shape[-2:])) + bboxes = [] + + for m in mask: + mx = m.sum(dim=-2).nonzero() + my = m.sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + bboxes.append(bb) + + bboxes = torch.tensor(bboxes, dtype=torch.float32, device=mask.device) + bboxes = bboxes.reshape(batch_shape + (4,)) + + if fmt == 'v': + return bboxes + + x1 = bboxes[..., :2] + s = bboxes[..., 2:] - x1 + 1 + + if fmt == 'c': + return torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + return torch.cat((x1, s), dim=-1) + + raise ValueError("Undefined bounding box layout '%s'" % fmt) + + +def masks_to_bboxes_multi(mask, ids, fmt='c'): + assert mask.dim() == 2 + bboxes = [] + + for id in ids: + mx = (mask == id).sum(dim=-2).nonzero() + my = (mask == id).float().sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + + bb = torch.tensor(bb, dtype=torch.float32, device=mask.device) + + x1 = bb[:2] + s = bb[2:] - x1 + 1 + + if fmt == 'v': + pass + elif fmt == 'c': + bb = torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + bb = torch.cat((x1, s), dim=-1) + else: + raise ValueError("Undefined bounding box layout '%s'" % fmt) + bboxes.append(bb) + + return bboxes diff --git a/Stark/external/AR/ltr/data/image_loader.py b/Stark/external/AR/ltr/data/image_loader.py new file mode 100755 index 0000000..636ec0a --- /dev/null +++ b/Stark/external/AR/ltr/data/image_loader.py @@ -0,0 +1,103 @@ +import jpeg4py +import cv2 as cv +from PIL import Image +import numpy as np + +davis_palette = np.repeat(np.expand_dims(np.arange(0,256), 1), 3, 1).astype(np.uint8) +davis_palette[:22, :] = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], + [0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128], + [64, 0, 0], [191, 0, 0], [64, 128, 0], [191, 128, 0], + [64, 0, 128], [191, 0, 128], [64, 128, 128], [191, 128, 128], + [0, 64, 0], [128, 64, 0], [0, 191, 0], [128, 191, 0], + [0, 64, 128], [128, 64, 128]] + + +def default_image_loader(path): + """The default image loader, reads the image from the given path. It first tries to use the jpeg4py_loader, + but reverts to the opencv_loader if the former is not available.""" + if default_image_loader.use_jpeg4py is None: + # Try using jpeg4py + im = jpeg4py_loader(path) + if im is None: + default_image_loader.use_jpeg4py = False + print('Using opencv_loader instead.') + else: + default_image_loader.use_jpeg4py = True + return im + if default_image_loader.use_jpeg4py: + return jpeg4py_loader(path) + return opencv_loader(path) + +default_image_loader.use_jpeg4py = None + + +def jpeg4py_loader(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_loader(path): + """ Read image using opencv's imread function and returns it in rgb format""" + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def jpeg4py_loader_w_failsafe(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except: + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_seg_loader(path): + """ Read segmentation annotation using opencv's imread function""" + try: + return cv.imread(path) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def imread_indexed(filename): + """ Load indexed image with given filename. Used to read segmentation annotations.""" + + im = Image.open(filename) + + annotation = np.atleast_3d(im)[...,0] + return annotation + + +def imwrite_indexed(filename, array, color_palette=None): + """ Save indexed image as png. Used to save segmentation annotation.""" + + if color_palette is None: + color_palette = davis_palette + + if np.atleast_3d(array).shape[2] != 1: + raise Exception("Saving indexed PNGs requires 2D array.") + + im = Image.fromarray(array) + im.putpalette(color_palette.ravel()) + im.save(filename, format='PNG') \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/loader.py b/Stark/external/AR/ltr/data/loader.py new file mode 100755 index 0000000..bd51bbc --- /dev/null +++ b/Stark/external/AR/ltr/data/loader.py @@ -0,0 +1,190 @@ +import torch +import torch.utils.data.dataloader +import importlib +import collections +from torch._six import string_classes, int_classes +from pytracking import TensorDict, TensorList + + +def _check_use_shared_memory(): + if hasattr(torch.utils.data.dataloader, '_use_shared_memory'): + return getattr(torch.utils.data.dataloader, '_use_shared_memory') + collate_lib = importlib.import_module('torch.utils.data._utils.collate') + if hasattr(collate_lib, '_use_shared_memory'): + return getattr(collate_lib, '_use_shared_memory') + return torch.utils.data.get_worker_info() is not None + + +def ltr_collate(batch): + """Puts each data field into a tensor with outer dimension batch size""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 0, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 0) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +def ltr_collate_stack1(batch): + """Puts each data field into a tensor. The tensors are stacked at dim=1 to form the batch""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 1, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 1) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate_stack1(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate_stack1(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +class LTRLoader(torch.utils.data.dataloader.DataLoader): + """ + Data loader. Combines a dataset and a sampler, and provides + single- or multi-process iterators over the dataset. + + Note: The only difference with default pytorch DataLoader is that an additional option stack_dim is available to + select along which dimension the data should be stacked to form a batch. + + Arguments: + dataset (Dataset): dataset from which to load the data. + batch_size (int, optional): how many samples per batch to load + (default: 1). + shuffle (bool, optional): set to ``True`` to have the data reshuffled + at every epoch (default: False). + sampler (Sampler, optional): defines the strategy to draw samples from + the dataset. If specified, ``shuffle`` must be False. + batch_sampler (Sampler, optional): like sampler, but returns a batch of + indices at a time. Mutually exclusive with batch_size, shuffle, + sampler, and drop_last. + num_workers (int, optional): how many subprocesses to use for data + loading. 0 means that the data will be loaded in the main process. + (default: 0) + collate_fn (callable, optional): merges a list of samples to form a mini-batch. + stack_dim (int): Dimension along which to stack to form the batch. (default: 0) + pin_memory (bool, optional): If ``True``, the data loader will copy tensors + into CUDA pinned memory before returning them. + drop_last (bool, optional): set to ``True`` to drop the last incomplete batch, + if the dataset size is not divisible by the batch size. If ``False`` and + the size of dataset is not divisible by the batch size, then the last batch + will be smaller. (default: False) + timeout (numeric, optional): if positive, the timeout value for collecting a batch + from workers. Should always be non-negative. (default: 0) + worker_init_fn (callable, optional): If not None, this will be called on each + worker subprocess with the worker id (an int in ``[0, num_workers - 1]``) as + input, after seeding and before data loading. (default: None) + + .. note:: By default, each worker will have its PyTorch seed set to + ``base_seed + worker_id``, where ``base_seed`` is a long generated + by main process using its RNG. However, seeds for other libraies + may be duplicated upon initializing workers (w.g., NumPy), causing + each worker to return identical random numbers. (See + :ref:`dataloader-workers-random-seed` section in FAQ.) You may + use ``torch.initial_seed()`` to access the PyTorch seed for each + worker in :attr:`worker_init_fn`, and use it to set other seeds + before data loading. + + .. warning:: If ``spawn`` start method is used, :attr:`worker_init_fn` cannot be an + unpicklable object, e.g., a lambda function. + """ + + __initialized = False + + def __init__(self, name, dataset, training=True, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, + num_workers=0, epoch_interval=1, collate_fn=None, stack_dim=0, pin_memory=False, drop_last=False, + timeout=0, worker_init_fn=None): + if collate_fn is None: + if stack_dim == 0: + collate_fn = ltr_collate + elif stack_dim == 1: + collate_fn = ltr_collate_stack1 + else: + raise ValueError('Stack dim no supported. Must be 0 or 1.') + + super(LTRLoader, self).__init__(dataset, batch_size, shuffle, sampler, batch_sampler, + num_workers, collate_fn, pin_memory, drop_last, + timeout, worker_init_fn) + + self.name = name + self.training = training + self.epoch_interval = epoch_interval + self.stack_dim = stack_dim \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/processing.py b/Stark/external/AR/ltr/data/processing.py new file mode 100755 index 0000000..9acd68f --- /dev/null +++ b/Stark/external/AR/ltr/data/processing.py @@ -0,0 +1,662 @@ +import torch +import torchvision.transforms as transforms +from pytracking import TensorDict +import ltr.data.processing_utils as prutils + + +def stack_tensors(x): + if isinstance(x, (list, tuple)) and isinstance(x[0], torch.Tensor): + return torch.stack(x) + return x + + +class BaseProcessing: + """ Base class for Processing. Processing class is used to process the data returned by a dataset, before passing it + through the network. For example, it can be used to crop a search region around the object, apply various data + augmentations, etc.""" + def __init__(self, transform=transforms.ToTensor(), train_transform=None, test_transform=None, joint_transform=None): + """ + args: + transform - The set of transformations to be applied on the images. Used only if train_transform or + test_transform is None. + train_transform - The set of transformations to be applied on the train images. If None, the 'transform' + argument is used instead. + test_transform - The set of transformations to be applied on the test images. If None, the 'transform' + argument is used instead. + joint_transform - The set of transformations to be applied 'jointly' on the train and test images. For + example, it can be used to convert both test and train images to grayscale. + """ + self.transform = {'train': transform if train_transform is None else train_transform, + 'test': transform if test_transform is None else test_transform, + 'joint': joint_transform} + + def __call__(self, data: TensorDict): + raise NotImplementedError + + +class ATOMProcessing(BaseProcessing): + """ The processing class used for training ATOM. The images are processed in the following way. + First, the target bounding box is jittered by adding some noise. Next, a square region (called search region ) + centered at the jittered target center, and of area search_area_factor^2 times the area of the jittered box is + cropped from the image. The reason for jittering the target box is to avoid learning the bias that the target is + always at the center of the search region. The search region is then resized to a fixed size given by the + argument output_sz. A set of proposals are then generated for the test images by jittering the ground truth box. + + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generates proposals by adding noise to the input box + args: + box - input box + + returns: + torch.Tensor - Array of shape (num_proposals, 4) containing proposals + torch.Tensor - Array of shape (num_proposals,) containing IoU overlap of each proposal with the input box. The + IoU is mapped to [-1, 1] + """ + # Generate proposals + num_proposals = self.proposal_params['boxes_per_frame'] + proposal_method = self.proposal_params.get('proposal_method', 'default') + + if proposal_method == 'default': + proposals = torch.zeros((num_proposals, 4)) + gt_iou = torch.zeros(num_proposals) + for i in range(num_proposals): + proposals[i, :], gt_iou[i] = prutils.perturb_box(box, min_iou=self.proposal_params['min_iou'], + sigma_factor=self.proposal_params['sigma_factor']) + elif proposal_method == 'gmm': + proposals, _, _ = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + num_samples=num_proposals) + gt_iou = prutils.iou(box.view(1,4), proposals.view(-1,4)) + + # Map to [-1, 1] + gt_iou = gt_iou * 2 - 1 + return proposals, gt_iou + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_iou' + """ + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + frame2_proposals, gt_iou = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = list(frame2_proposals) + data['proposal_iou'] = list(gt_iou) + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + +class KLBBregProcessing(BaseProcessing): + """ Based on ATOMProcessing. It supports training ATOM using the Maximum Likelihood or KL-divergence based learning + introduced in [https://arxiv.org/abs/1909.12297] and in PrDiMP [https://arxiv.org/abs/2003.12565]. + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + gt_sigma=self.proposal_params['gt_sigma'], + num_samples=self.proposal_params[ + 'boxes_per_frame'], + add_mean_box=self.proposal_params.get( + 'add_mean_box', False)) + + return proposals, proposal_density, gt_density + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_density', 'gt_density' + """ + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes, _ = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + +class ATOMwKLProcessing(BaseProcessing): + """Same as ATOMProcessing but using the GMM-based sampling of proposal boxes used in KLBBregProcessing.""" + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + self.proposal_params['gt_sigma'], + self.proposal_params['boxes_per_frame']) + + iou = prutils.iou_gen(proposals, box.view(1, 4)) + return proposals, proposal_density, gt_density, iou + + def __call__(self, data: TensorDict): + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density, proposal_iou = zip( + *[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + data['proposal_iou'] = proposal_iou + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + + +class DiMPProcessing(BaseProcessing): + """ The processing class used for training DiMP. The images are processed in the following way. + First, the target bounding box is jittered by adding some noise. Next, a square region (called search region ) + centered at the jittered target center, and of area search_area_factor^2 times the area of the jittered box is + cropped from the image. The reason for jittering the target box is to avoid learning the bias that the target is + always at the center of the search region. The search region is then resized to a fixed size given by the + argument output_sz. A Gaussian label centered at the target is generated for each image. These label functions are + used for computing the loss of the predicted classification model on the test images. A set of proposals are + also generated for the test images by jittering the ground truth box. These proposals are used to train the + bounding box estimating branch. + + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, crop_type='replicate', + max_scale_change=None, mode='pair', proposal_params=None, label_function_params=None, *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + crop_type - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + label_function_params - Arguments for the label generation process. See _generate_label_function for details. + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.crop_type = crop_type + self.mode = mode + self.max_scale_change = max_scale_change + + self.proposal_params = proposal_params + self.label_function_params = label_function_params + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generates proposals by adding noise to the input box + args: + box - input box + + returns: + torch.Tensor - Array of shape (num_proposals, 4) containing proposals + torch.Tensor - Array of shape (num_proposals,) containing IoU overlap of each proposal with the input box. The + IoU is mapped to [-1, 1] + """ + # Generate proposals + num_proposals = self.proposal_params['boxes_per_frame'] + proposal_method = self.proposal_params.get('proposal_method', 'default') + + if proposal_method == 'default': + proposals = torch.zeros((num_proposals, 4)) + gt_iou = torch.zeros(num_proposals) + + for i in range(num_proposals): + proposals[i, :], gt_iou[i] = prutils.perturb_box(box, min_iou=self.proposal_params['min_iou'], + sigma_factor=self.proposal_params['sigma_factor']) + elif proposal_method == 'gmm': + proposals, _, _ = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + num_samples=num_proposals) + gt_iou = prutils.iou(box.view(1, 4), proposals.view(-1, 4)) + else: + raise ValueError('Unknown proposal method.') + + # Map to [-1, 1] + gt_iou = gt_iou * 2 - 1 + return proposals, gt_iou + + def _generate_label_function(self, target_bb): + """ Generates the gaussian label function centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_function_params['sigma_factor'], + self.label_function_params['kernel_sz'], + self.label_function_params['feature_sz'], self.output_sz, + end_pad_if_even=self.label_function_params.get('end_pad_if_even', True)) + + return gauss_label + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_iou', + 'test_label' (optional), 'train_label' (optional), 'test_label_density' (optional), 'train_label_density' (optional) + """ + + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + crops, boxes = prutils.target_image_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz, mode=self.crop_type, + max_scale_change=self.max_scale_change) + + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + if self.proposal_params: + frame2_proposals, gt_iou = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = list(frame2_proposals) + data['proposal_iou'] = list(gt_iou) + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + # Generate label functions + if self.label_function_params is not None: + data['train_label'] = self._generate_label_function(data['train_anno']) + data['test_label'] = self._generate_label_function(data['test_anno']) + + return data + + +class KLDiMPProcessing(BaseProcessing): + """ The processing class used for training PrDiMP that additionally supports the probabilistic classifier and + bounding box regressor. See DiMPProcessing for details. + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, crop_type='replicate', + max_scale_change=None, mode='pair', proposal_params=None, + label_function_params=None, label_density_params=None, *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + crop_type - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + label_function_params - Arguments for the label generation process. See _generate_label_function for details. + label_density_params - Arguments for the label density generation process. See _generate_label_function for details. + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.crop_type = crop_type + self.mode = mode + self.max_scale_change = max_scale_change + + self.proposal_params = proposal_params + self.label_function_params = label_function_params + self.label_density_params = label_density_params + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generate proposal sample boxes from a GMM proposal distribution and compute their ground-truth density. + This is used for ML and KL based regression learning of the bounding box regressor. + args: + box - input bounding box + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + gt_sigma=self.proposal_params['gt_sigma'], + num_samples=self.proposal_params['boxes_per_frame'], + add_mean_box=self.proposal_params.get('add_mean_box', False)) + + return proposals, proposal_density, gt_density + + def _generate_label_function(self, target_bb): + """ Generates the gaussian label function centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_function_params['sigma_factor'], + self.label_function_params['kernel_sz'], + self.label_function_params['feature_sz'], self.output_sz, + end_pad_if_even=self.label_function_params.get('end_pad_if_even', True)) + + return gauss_label + + def _generate_label_density(self, target_bb): + """ Generates the gaussian label density centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + feat_sz = self.label_density_params['feature_sz'] * self.label_density_params.get('interp_factor', 1) + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_density_params['sigma_factor'], + self.label_density_params['kernel_sz'], + feat_sz, self.output_sz, + end_pad_if_even=self.label_density_params.get('end_pad_if_even', True), + density=True, + uni_bias=self.label_density_params.get('uni_weight', 0.0)) + + gauss_label *= (gauss_label > self.label_density_params.get('threshold', 0.0)).float() + + if self.label_density_params.get('normalize', False): + g_sum = gauss_label.sum(dim=(-2,-1)) + valid = g_sum>0.01 + gauss_label[valid, :, :] /= g_sum[valid].view(-1, 1, 1) + gauss_label[~valid, :, :] = 1.0 / (gauss_label.shape[-2] * gauss_label.shape[-1]) + + gauss_label *= 1.0 - self.label_density_params.get('shrink', 0.0) + + return gauss_label + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_density', 'gt_density', + 'test_label' (optional), 'train_label' (optional), 'test_label_density' (optional), 'train_label_density' (optional) + """ + + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + crops, boxes = prutils.target_image_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz, mode=self.crop_type, + max_scale_change=self.max_scale_change) + + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + + for s in ['train', 'test']: + is_distractor = data.get('is_distractor_{}_frame'.format(s), None) + if is_distractor is not None: + for is_dist, box in zip(is_distractor, data[s+'_anno']): + if is_dist: + box[0] = 99999999.9 + box[1] = 99999999.9 + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + # Generate label functions + if self.label_function_params is not None: + data['train_label'] = self._generate_label_function(data['train_anno']) + data['test_label'] = self._generate_label_function(data['test_anno']) + if self.label_density_params is not None: + data['train_label_density'] = self._generate_label_density(data['train_anno']) + data['test_label_density'] = self._generate_label_density(data['test_anno']) + + return data diff --git a/Stark/external/AR/ltr/data/processing_utils.py b/Stark/external/AR/ltr/data/processing_utils.py new file mode 100755 index 0000000..50765f7 --- /dev/null +++ b/Stark/external/AR/ltr/data/processing_utils.py @@ -0,0 +1,627 @@ +import torch +import math +import cv2 as cv +import random +import torch.nn.functional as F +from .bounding_box_utils import rect_to_rel, rel_to_rect + + +def sample_target(im, target_bb, search_area_factor, output_sz=None, mask=None): + """ Extracts a square crop centered at target_bb box, of area search_area_factor^2 times target_bb area + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + float - the factor by which the crop has been resized to make the crop size equal output_size + """ + x, y, w, h = target_bb.tolist() + + # Crop image + crop_sz = math.ceil(math.sqrt(w * h) * search_area_factor) + + if crop_sz < 1: + raise Exception('Too small bounding box.') + + x1 = round(x + 0.5 * w - crop_sz * 0.5) + x2 = x1 + crop_sz + + y1 = round(y + 0.5 * h - crop_sz * 0.5) + y2 = y1 + crop_sz + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + if output_sz is not None: + resize_factor = output_sz / crop_sz + im_crop_padded = cv.resize(im_crop_padded, (output_sz, output_sz)) + + if mask is None: + return im_crop_padded, resize_factor + mask_crop_padded = \ + F.interpolate(mask_crop_padded[None, None], (output_sz, output_sz), mode='bilinear', align_corners=False)[0, 0] + return im_crop_padded, resize_factor, mask_crop_padded + + else: + if mask is None: + return im_crop_padded, 1.0 + return im_crop_padded, 1.0, mask_crop_padded + + +def transform_image_to_crop(box_in: torch.Tensor, box_extract: torch.Tensor, resize_factor: float, + crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box_in - the box for which the co-ordinates are to be transformed + box_extract - the box about which the image crop has been extracted. + resize_factor - the ratio between the original image scale and the scale of the image crop + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + box_extract_center = box_extract[0:2] + 0.5 * box_extract[2:4] + + box_in_center = box_in[0:2] + 0.5 * box_in[2:4] + + box_out_center = (crop_sz - 1) / 2 + (box_in_center - box_extract_center) * resize_factor + box_out_wh = box_in[2:4] * resize_factor + + box_out = torch.cat((box_out_center - 0.5 * box_out_wh, box_out_wh)) + return box_out + + +def jittered_center_crop(frames, box_extract, box_gt, search_area_factor, output_sz, masks=None): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. The extracted crops are then resized to output_sz. Further, the co-ordinates of the box + box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if masks is None: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz) + for f, a in zip(frames, box_extract)] + frames_crop, resize_factors = zip(*crops_resize_factors) + masks_crop = None + else: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz, m) + for f, a, m in zip(frames, box_extract, masks)] + frames_crop, resize_factors, masks_crop = zip(*crops_resize_factors) + + crop_sz = torch.Tensor([output_sz, output_sz]) + + # find the bb location in the crop + box_crop = [transform_image_to_crop(a_gt, a_ex, rf, crop_sz) + for a_gt, a_ex, rf in zip(box_gt, box_extract, resize_factors)] + + return frames_crop, box_crop, masks_crop + + +def sample_target_adaptive(im, target_bb, search_area_factor, output_sz, mode: str = 'replicate', + max_scale_change=None, mask=None): + """ Extracts a crop centered at target_bb box, of area search_area_factor^2. If the crop area contains regions + outside the image, it is shifted so that the it is inside the image. Further, if the crop area exceeds the image + size, a smaller crop which fits the image is returned instead. + + args: + im - Input numpy image to crop. + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + mode - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mask - Optional mask to apply the same crop. + + returns: + numpy image - Extracted crop. + torch.Tensor - A bounding box denoting the cropped region in the image. + numpy mask - Cropped mask returned only if mask is not None. + """ + + if max_scale_change is None: + max_scale_change = float('inf') + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + output_sz = torch.Tensor(output_sz) + + im_h = im.shape[0] + im_w = im.shape[1] + + bbx, bby, bbw, bbh = target_bb.tolist() + + # Crop image + crop_sz_x, crop_sz_y = (output_sz * ( + target_bb[2:].prod() / output_sz.prod()).sqrt() * search_area_factor).ceil().long().tolist() + + # Get new sample size if forced inside the image + if mode == 'inside' or mode == 'inside_major': + # Calculate rescaling factor if outside the image + rescale_factor = [crop_sz_x / im_w, crop_sz_y / im_h] + if mode == 'inside': + rescale_factor = max(rescale_factor) + elif mode == 'inside_major': + rescale_factor = min(rescale_factor) + rescale_factor = min(max(1, rescale_factor), max_scale_change) + + crop_sz_x = math.floor(crop_sz_x / rescale_factor) + crop_sz_y = math.floor(crop_sz_y / rescale_factor) + + if crop_sz_x < 1 or crop_sz_y < 1: + raise Exception('Too small bounding box.') + + x1 = round(bbx + 0.5 * bbw - crop_sz_x * 0.5) + x2 = x1 + crop_sz_x + + y1 = round(bby + 0.5 * bbh - crop_sz_y * 0.5) + y2 = y1 + crop_sz_y + + # Move box inside image + shift_x = max(0, -x1) + min(0, im_w - x2) + x1 += shift_x + x2 += shift_x + + shift_y = max(0, -y1) + min(0, im_h - y2) + y1 += shift_y + y2 += shift_y + + out_x = (max(0, -x1) + max(0, x2 - im_w)) // 2 + out_y = (max(0, -y1) + max(0, y2 - im_h)) // 2 + shift_x = (-x1 - out_x) * (out_x > 0) + shift_y = (-y1 - out_y) * (out_y > 0) + + x1 += shift_x + x2 += shift_x + y1 += shift_y + y2 += shift_y + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + # Resize image + im_out = cv.resize(im_crop_padded, tuple(output_sz.long().tolist())) + + if mask is not None: + mask_out = \ + F.interpolate(mask_crop_padded[None, None], tuple(output_sz.flip(0).long().tolist()), mode='nearest')[0, 0] + + crop_box = torch.Tensor([x1, y1, x2 - x1, y2 - y1]) + + if mask is None: + return im_out, crop_box + else: + return im_out, crop_box, mask_out + + +def crop_and_resize(im, box, crop_bb, output_sz, mask=None): + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + + im_h = im.shape[0] + im_w = im.shape[1] + + if crop_bb[2] < 1 or crop_bb[3] < 1: + raise Exception('Too small bounding box.') + + x1 = crop_bb[0] + x2 = crop_bb[0] + crop_bb[2] + + y1 = crop_bb[1] + y2 = crop_bb[1] + crop_bb[3] + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + # Resize image + im_out = cv.resize(im_crop_padded, output_sz) + + if mask is not None: + mask_out = F.interpolate(mask_crop_padded[None, None], (output_sz[1], output_sz[0]), mode='nearest')[0, 0] + + rescale_factor = output_sz[0] / crop_bb[2] + + # Hack + if box is not None: + box_crop = box.clone() + box_crop[0] -= crop_bb[0] + box_crop[1] -= crop_bb[1] + + box_crop *= rescale_factor + else: + box_crop = None + + if mask is None: + return im_out, box_crop + else: + return im_out, box_crop, mask_out + + +def transform_box_to_crop(box: torch.Tensor, crop_box: torch.Tensor, crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box - the box for which the co-ordinates are to be transformed + crop_box - bounding box defining the crop in the original image + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + + box_out = box.clone() + box_out[:2] -= crop_box[:2] + + scale_factor = crop_sz / crop_box[2:] + + box_out[:2] *= scale_factor + box_out[2:] *= scale_factor + return box_out + + +def target_image_crop(frames, box_extract, box_gt, search_area_factor, output_sz, mode: str = 'replicate', + max_scale_change=None, masks=None): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. If the crop area contains regions outside the image, it is shifted / shrunk so that it + completely fits inside the image. The extracted crops are then resized to output_sz. Further, the co-ordinates of + the box box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + mode - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + masks - Optional masks to apply the same crop. + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + + if masks is None: + frame_crops_boxes = [sample_target_adaptive(f, a, search_area_factor, output_sz, mode, max_scale_change) + for f, a in zip(frames, box_extract)] + + frames_crop, crop_boxes = zip(*frame_crops_boxes) + else: + frame_crops_boxes_masks = [ + sample_target_adaptive(f, a, search_area_factor, output_sz, mode, max_scale_change, mask=m) + for f, a, m in zip(frames, box_extract, masks)] + + frames_crop, crop_boxes, masks_crop = zip(*frame_crops_boxes_masks) + + crop_sz = torch.Tensor(output_sz) + + # find the bb location in the crop + box_crop = [transform_box_to_crop(bb_gt, crop_bb, crop_sz) + for bb_gt, crop_bb in zip(box_gt, crop_boxes)] + + if masks is None: + return frames_crop, box_crop + else: + return frames_crop, box_crop, masks_crop + + +def iou(reference, proposals): + """Compute the IoU between a reference box with multiple proposal boxes. + + args: + reference - Tensor of shape (1, 4). + proposals - Tensor of shape (num_proposals, 4) + + returns: + torch.Tensor - Tensor of shape (num_proposals,) containing IoU of reference box with each proposal box. + """ + + # Intersection box + tl = torch.max(reference[:, :2], proposals[:, :2]) + br = torch.min(reference[:, :2] + reference[:, 2:], proposals[:, :2] + proposals[:, 2:]) + sz = (br - tl).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = reference[:, 2:].prod(dim=1) + proposals[:, 2:].prod(dim=1) - intersection + + return intersection / union + + +def rand_uniform(a, b, shape=1): + """ sample numbers uniformly between a and b. + args: + a - lower bound + b - upper bound + shape - shape of the output tensor + + returns: + torch.Tensor - tensor of shape=shape + """ + return (b - a) * torch.rand(shape) + a + + +def perturb_box(box, min_iou=0.5, sigma_factor=0.1): + """ Perturb the input box by adding gaussian noise to the co-ordinates + + args: + box - input box + min_iou - minimum IoU overlap between input box and the perturbed box + sigma_factor - amount of perturbation, relative to the box size. Can be either a single element, or a list of + sigma_factors, in which case one of them will be uniformly sampled. Further, each of the + sigma_factor element can be either a float, or a tensor + of shape (4,) specifying the sigma_factor per co-ordinate + + returns: + torch.Tensor - the perturbed box + """ + + if isinstance(sigma_factor, list): + # If list, sample one sigma_factor as current sigma factor + c_sigma_factor = random.choice(sigma_factor) + else: + c_sigma_factor = sigma_factor + + if not isinstance(c_sigma_factor, torch.Tensor): + c_sigma_factor = c_sigma_factor * torch.ones(4) + + perturb_factor = torch.sqrt(box[2] * box[3]) * c_sigma_factor + + # multiple tries to ensure that the perturbed box has iou > min_iou with the input box + for i_ in range(100): + c_x = box[0] + 0.5 * box[2] + c_y = box[1] + 0.5 * box[3] + c_x_per = random.gauss(c_x, perturb_factor[0]) + c_y_per = random.gauss(c_y, perturb_factor[1]) + + w_per = random.gauss(box[2], perturb_factor[2]) + h_per = random.gauss(box[3], perturb_factor[3]) + + if w_per <= 1: + w_per = box[2] * rand_uniform(0.15, 0.5) + + if h_per <= 1: + h_per = box[3] * rand_uniform(0.15, 0.5) + + box_per = torch.Tensor([c_x_per - 0.5 * w_per, c_y_per - 0.5 * h_per, w_per, h_per]).round() + + if box_per[2] <= 1: + box_per[2] = box[2] * rand_uniform(0.15, 0.5) + + if box_per[3] <= 1: + box_per[3] = box[3] * rand_uniform(0.15, 0.5) + + box_iou = iou(box.view(1, 4), box_per.view(1, 4)) + + # if there is sufficient overlap, return + if box_iou > min_iou: + return box_per, box_iou + + # else reduce the perturb factor + perturb_factor *= 0.9 + + return box_per, box_iou + + +def gauss_1d(sz, sigma, center, end_pad=0, density=False): + k = torch.arange(-(sz - 1) / 2, (sz + 1) / 2 + end_pad).reshape(1, -1) + gauss = torch.exp(-1.0 / (2 * sigma ** 2) * (k - center.reshape(-1, 1)) ** 2) + if density: + gauss /= math.sqrt(2 * math.pi) * sigma + return gauss + + +def gauss_2d(sz, sigma, center, end_pad=(0, 0), density=False): + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + return gauss_1d(sz[0].item(), sigma[0], center[:, 0], end_pad[0], density).reshape(center.shape[0], 1, -1) * \ + gauss_1d(sz[1].item(), sigma[1], center[:, 1], end_pad[1], density).reshape(center.shape[0], -1, 1) + + +def gaussian_label_function(target_bb, sigma_factor, kernel_sz, feat_sz, image_sz, end_pad_if_even=True, density=False, + uni_bias=0): + """Construct Gaussian label function.""" + + if isinstance(kernel_sz, (float, int)): + kernel_sz = (kernel_sz, kernel_sz) + if isinstance(feat_sz, (float, int)): + feat_sz = (feat_sz, feat_sz) + if isinstance(image_sz, (float, int)): + image_sz = (image_sz, image_sz) + + image_sz = torch.Tensor(image_sz) + feat_sz = torch.Tensor(feat_sz) + + target_center = target_bb[:, 0:2] + 0.5 * target_bb[:, 2:4] + target_center_norm = (target_center - image_sz / 2) / image_sz + + center = feat_sz * target_center_norm + 0.5 * \ + torch.Tensor([(kernel_sz[0] + 1) % 2, (kernel_sz[1] + 1) % 2]) + + sigma = sigma_factor * feat_sz.prod().sqrt().item() + + if end_pad_if_even: + end_pad = (int(kernel_sz[0] % 2 == 0), int(kernel_sz[1] % 2 == 0)) + else: + end_pad = (0, 0) + + gauss_label = gauss_2d(feat_sz, sigma, center, end_pad, density=density) + if density: + sz = (feat_sz + torch.Tensor(end_pad)).prod() + label = (1.0 - uni_bias) * gauss_label + uni_bias / sz + else: + label = gauss_label + uni_bias + return label + + +def gauss_density_centered(x, std): + """Evaluate the probability density of a Gaussian centered at zero. + args: + x - Samples. + std - List of standard deviations + """ + return torch.exp(-0.5 * (x / std) ** 2) / (math.sqrt(2 * math.pi) * std) + + +def gmm_density_centered(x, std): + """Evaluate the probability density of a GMM centered at zero. + args: + x - Samples. Assumes dim=-1 is the component dimension and dim=-2 is feature dimension. Rest are sample dimension. + std - Tensor of standard deviations + """ + if x.dim() == std.dim() - 1: + x = x.unsqueeze(-1) + elif not (x.dim() == std.dim() and x.shape[-1] == 1): + raise ValueError('Last dimension must be the gmm stds.') + return gauss_density_centered(x, std).prod(-2).mean(-1) + + +def sample_gmm_centered(std, num_samples=1): + """Sample from a GMM distribution centered at zero: + args: + std - Tensor of standard deviations + num_samples - number of samples + """ + num_components = std.shape[-1] + num_dims = std.numel() // num_components + + std = std.view(1, num_dims, num_components) + + # Sample component ids + k = torch.randint(num_components, (num_samples,), dtype=torch.int64) + std_samp = std[0, :, k].t() + + # Sample + x_centered = std_samp * torch.randn(num_samples, num_dims) + prob_dens = gmm_density_centered(x_centered, std) + + return x_centered, prob_dens + + +def sample_gmm(mean, std, num_samples=1): + """Sample from a GMM distribution: + args: + mean - a single mean vector + std - Tensor of standard deviations + num_samples - number of samples + """ + num_dims = mean.numel() + num_components = std.shape[-1] + + mean = mean.view(1, num_dims) + std = std.view(1, -1, num_components) + + # Sample component ids + k = torch.randint(num_components, (num_samples,), dtype=torch.int64) + std_samp = std[0, :, k].t() + + # Sample + x_centered = std_samp * torch.randn(num_samples, num_dims) + x = x_centered + mean + prob_dens = gmm_density_centered(x_centered, std) + + return x, prob_dens + + +def sample_box_gmm(mean_box, proposal_sigma, gt_sigma=None, num_samples=1, add_mean_box=False): + """Sample boxes from a Gaussian mixture model. + args: + mean_box - Center (or mean) bounding box + proposal_sigma - List of standard deviations for each Gaussian + gt_sigma - Standard deviation of the ground truth distribution + num_samples - Number of sampled boxes + add_mean_box - Also add mean box as first element + + returns: + proposals, proposal density and ground truth density for all samples + """ + center_std = torch.Tensor([s[0] for s in proposal_sigma]) + sz_std = torch.Tensor([s[1] for s in proposal_sigma]) + std = torch.stack([center_std, center_std, sz_std, sz_std]) + + mean_box = mean_box.view(1, 4) + sz_norm = mean_box[:, 2:].clone() + + # Sample boxes + proposals_rel_centered, proposal_density = sample_gmm_centered(std, num_samples) + + # Add mean and map back + mean_box_rel = rect_to_rel(mean_box, sz_norm) + proposals_rel = proposals_rel_centered + mean_box_rel + proposals = rel_to_rect(proposals_rel, sz_norm) + + if gt_sigma is None or gt_sigma[0] == 0 and gt_sigma[1] == 0: + gt_density = torch.zeros_like(proposal_density) + else: + std_gt = torch.Tensor([gt_sigma[0], gt_sigma[0], gt_sigma[1], gt_sigma[1]]).view(1, 4) + gt_density = gauss_density_centered(proposals_rel_centered, std_gt).prod(-1) + + if add_mean_box: + proposals = torch.cat((mean_box, proposals)) + proposal_density = torch.cat((torch.Tensor([-1]), proposal_density)) + gt_density = torch.cat((torch.Tensor([1]), gt_density)) + + return proposals, proposal_density, gt_density \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/processing_utils_SE.py b/Stark/external/AR/ltr/data/processing_utils_SE.py new file mode 100755 index 0000000..82a6e38 --- /dev/null +++ b/Stark/external/AR/ltr/data/processing_utils_SE.py @@ -0,0 +1,450 @@ +import torch +import math +import cv2 as cv +import random + +import numpy as np + +def stack_tensors(x): + if isinstance(x, list) and isinstance(x[0], torch.Tensor): + return torch.stack(x) + return x + + +'''Added on 2019.12.23''' +def sample_target_SE(im, target_bb, search_area_factor, output_sz=None, mode=cv.BORDER_REPLICATE): + """ Extracts a crop centered at target_bb box, of size search_area_factor times target_bb(Both height and width) + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + float - the factor by which the crop has been resized to make the crop size equal output_size + """ + + x, y, w, h = target_bb.tolist() + + # Crop image + ws = math.ceil(search_area_factor * w) + hs = math.ceil(search_area_factor * h) + + if ws < 1 or hs < 1: + raise Exception('Too small bounding box.') + + x1 = round(x + 0.5*w - ws*0.5) + x2 = x1 + ws + + y1 = round(y + 0.5 * h - hs * 0.5) + y2 = y1 + hs + + x1_pad = max(0, -x1) + x2_pad = max(x2-im.shape[1]+1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2-im.shape[0]+1, 0) + + # Crop target + im_crop = im[y1+y1_pad:y2-y2_pad, x1+x1_pad:x2-x2_pad, :] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, mode) + + if output_sz is not None: + w_rsz_f = output_sz / ws + h_rsz_f = output_sz / hs + im_crop_padded_rsz = cv.resize(im_crop_padded, (output_sz, output_sz)) + if len(im_crop_padded_rsz.shape)==2: + im_crop_padded_rsz = im_crop_padded_rsz[...,np.newaxis] + return im_crop_padded_rsz, h_rsz_f, w_rsz_f + else: + return im_crop_padded, 1.0, 1.0 +'''把mask映射到原图上''' +def map_mask_back(im, target_bb, search_area_factor, mask, mode=cv.BORDER_REPLICATE): + """ Extracts a crop centered at target_bb box, of size search_area_factor times target_bb(Both height and width) + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + float - the factor by which the crop has been resized to make the crop size equal output_size + """ + H,W = (im.shape[0],im.shape[1]) + base = np.zeros((H,W)) + x, y, w, h = target_bb.tolist() + + # Crop image + ws = math.ceil(search_area_factor * w) + hs = math.ceil(search_area_factor * h) + + if ws < 1 or hs < 1: + raise Exception('Too small bounding box.') + + x1 = round(x + 0.5*w - ws*0.5) + x2 = x1 + ws + + y1 = round(y + 0.5 * h - hs * 0.5) + y2 = y1 + hs + + x1_pad = max(0, -x1) + x2_pad = max(x2-im.shape[1]+1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2-im.shape[0]+1, 0) + + '''pad base''' + base_padded = cv.copyMakeBorder(base, y1_pad, y2_pad, x1_pad, x2_pad, mode) + '''Resize mask''' + mask_rsz = cv.resize(mask,(ws,hs)) + '''fill region with mask''' + base_padded[y1+y1_pad:y2+y1_pad, x1+x1_pad:x2+x1_pad] = mask_rsz.copy() + '''crop base_padded to get final mask''' + final_mask = base_padded[y1_pad:y1_pad+H,x1_pad:x1_pad+W] + assert (final_mask.shape == (H,W)) + return final_mask + +'''Added on 2019.12.23''' +def transform_image_to_crop_SE(box_in: torch.Tensor, box_extract: torch.Tensor, resize_factor_h: float, resize_factor_w: float, + crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box_in - the box for which the co-ordinates are to be transformed + box_extract - the box about which the image crop has been extracted. + resize_factor - the ratio between the original image scale and the scale of the image crop + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + box_extract_center = box_extract[0:2] + 0.5*box_extract[2:4] + + box_in_center = box_in[0:2] + 0.5*box_in[2:4] + + box_out_xc = (crop_sz[0] -1)/2 + (box_in_center[0] - box_extract_center[0])*resize_factor_w + box_out_yc = (crop_sz[0] -1)/2 + (box_in_center[1] - box_extract_center[1])*resize_factor_h + box_out_w = box_in[2] * resize_factor_w + box_out_h = box_in[3] * resize_factor_h + + '''2019.12.28 为了避免出现(x1,y1)小于0,或者(x2,y2)大于256的情况,这里我对它们加上了一些限制''' + max_sz = crop_sz[0].item() + box_out_x1 = torch.clamp(box_out_xc - 0.5 * box_out_w,0,max_sz) + box_out_y1 = torch.clamp(box_out_yc - 0.5 * box_out_h,0,max_sz) + box_out_x2 = torch.clamp(box_out_xc + 0.5 * box_out_w,0,max_sz) + box_out_y2 = torch.clamp(box_out_yc + 0.5 * box_out_h,0,max_sz) + box_out_w_new = box_out_x2 - box_out_x1 + box_out_h_new = box_out_y2 - box_out_y1 + box_out = torch.stack((box_out_x1, box_out_y1, box_out_w_new, box_out_h_new)) + return box_out + +def centered_crop(frames, anno, area_factor, output_sz): + crops_resize_factors = [sample_target(f, a, area_factor, output_sz) + for f, a in zip(frames, anno)] + + frames_crop, resize_factors = zip(*crops_resize_factors) + + crop_sz = torch.Tensor([output_sz, output_sz]) + + # find the bb location in the crop + anno_crop = [transform_image_to_crop(a, a, rf, crop_sz) + for a, rf in zip(anno, resize_factors)] + + return frames_crop, anno_crop + +'''Added by Bin Yan 2019.12.23, +changed on 2020.1.4(add a new args: "get_bbox_coord")''' +def jittered_center_crop_SE(frames, box_extract, box_gt, search_area_factor, output_sz, get_bbox_coord=True, mode=cv.BORDER_REPLICATE): + """ + Crop a patch centered at box_extract. The height and width of cropped region is search_area_factor times that of box_extract. + The extracted crops are then resized to output_sz. Further, the co-ordinates of the box box_gt are transformed to the image crop co-ordinates + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + '''call function "sample_target_SE" and function "transform_image_to_crop_SE"''' + '''get cropped patch(fixed size)''' + crops_resize_factors = [sample_target_SE(f, a, search_area_factor, output_sz, mode=mode) + for f, a in zip(frames, box_extract)] + + frames_crop, resize_factors_h, resize_factors_w = zip(*crops_resize_factors) + if get_bbox_coord: + crop_sz = torch.Tensor([output_sz, output_sz]) + + # find the bb location in the crop + '''get GT's cooridinate on the cropped patch''' + box_crop = [transform_image_to_crop_SE(a_gt, a_ex, h_rsf, w_rsf, crop_sz) + for a_gt, a_ex, h_rsf, w_rsf in zip(box_gt, box_extract, resize_factors_h, resize_factors_w)] + + return frames_crop, box_crop + else: + return frames_crop + +def sample_target_nopad(im, target_bb, search_area_factor, output_sz): + """ Extracts a crop centered at target_bb box, of area search_area_factor^2. If the crop area contains regions + outside the image, it is shifted so that the it is inside the image. Further, if the crop area exceeds the image + size, a smaller crop which fits the image is returned instead. + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + torch.Tensor - a bounding box denoting the cropped region in the image. + """ + + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + output_sz = torch.Tensor(output_sz) + + im_h = im.shape[0] + im_w = im.shape[1] + + bbx, bby, bbw, bbh = target_bb.tolist() + + # Crop image + crop_sz_x, crop_sz_y = (output_sz * (target_bb[2:].prod()/output_sz.prod()).sqrt() * search_area_factor).ceil() + + # Calculate rescaling factor if outside the image + rescale_factor = max(1, crop_sz_x/im_w, crop_sz_y/im_h) + crop_sz_x = math.floor(crop_sz_x / rescale_factor) + crop_sz_y = math.floor(crop_sz_y / rescale_factor) + + if crop_sz_x < 1 or crop_sz_y < 1: + raise Exception('Too small bounding box.') + + x1 = round(bbx + 0.5*bbw - crop_sz_x*0.5) + x2 = x1 + crop_sz_x + + y1 = round(bby + 0.5*bbh - crop_sz_y*0.5) + y2 = y1 + crop_sz_y + + # Move box inside image + shift_x = max(0, -x1) + min(0, im_w - x2) + x1 += shift_x + x2 += shift_x + + shift_y = max(0, -y1) + min(0, im_h - y2) + y1 += shift_y + y2 += shift_y + + # Crop and resize image + im_crop = im[y1:y2, x1:x2, :] + im_out = cv.resize(im_crop, tuple(output_sz.long().tolist())) + + crop_box = torch.Tensor([x1, y1, x2-x1, y2-y1]) + return im_out, crop_box + + +def transform_box_to_crop(box: torch.Tensor, crop_box: torch.Tensor, crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box - the box for which the co-ordinates are to be transformed + crop_box - bounding box defining the crop in the original image + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + + box_out = box.clone() + box_out[:2] -= crop_box[:2] + + scale_factor = crop_sz / crop_box[2:] + + box_out[:2] *= scale_factor + box_out[2:] *= scale_factor + return box_out + + +def jittered_center_crop_nopad(frames, box_extract, box_gt, search_area_factor, output_sz): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. If the crop area contains regions outside the image, it is shifted / shrunk so that it + completely fits inside the image. The extracted crops are then resized to output_sz. Further, the co-ordinates of + the box box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + + frame_crops_boxes = [sample_target_nopad(f, a, search_area_factor, output_sz) + for f, a in zip(frames, box_extract)] + + frames_crop, crop_boxes = zip(*frame_crops_boxes) + + crop_sz = torch.Tensor(output_sz) + + # find the bb location in the crop + box_crop = [transform_box_to_crop(bb_gt, crop_bb, crop_sz) + for bb_gt, crop_bb in zip(box_gt, crop_boxes)] + + return frames_crop, box_crop + + +def iou(reference, proposals): + """Compute the IoU between a reference box with multiple proposal boxes. + + args: + reference - Tensor of shape (1, 4). + proposals - Tensor of shape (num_proposals, 4) + + returns: + torch.Tensor - Tensor of shape (num_proposals,) containing IoU of reference box with each proposal box. + """ + + # Intersection box + tl = torch.max(reference[:,:2], proposals[:,:2]) + br = torch.min(reference[:,:2] + reference[:,2:], proposals[:,:2] + proposals[:,2:]) + sz = (br - tl).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = reference[:,2:].prod(dim=1) + proposals[:,2:].prod(dim=1) - intersection + + return intersection / union + + +def rand_uniform(a, b, shape=1): + """ sample numbers uniformly between a and b. + args: + a - lower bound + b - upper bound + shape - shape of the output tensor + + returns: + torch.Tensor - tensor of shape=shape + """ + return (b - a) * torch.rand(shape) + a + + +def perturb_box(box, min_iou=0.5, sigma_factor=0.1): + """ Perturb the input box by adding gaussian noise to the co-ordinates + + args: + box - input box + min_iou - minimum IoU overlap between input box and the perturbed box + sigma_factor - amount of perturbation, relative to the box size. Can be either a single element, or a list of + sigma_factors, in which case one of them will be uniformly sampled. Further, each of the + sigma_factor element can be either a float, or a tensor + of shape (4,) specifying the sigma_factor per co-ordinate + + returns: + torch.Tensor - the perturbed box + """ + + if isinstance(sigma_factor, list): + # If list, sample one sigma_factor as current sigma factor + c_sigma_factor = random.choice(sigma_factor) + else: + c_sigma_factor = sigma_factor + + if not isinstance(c_sigma_factor, torch.Tensor): + c_sigma_factor = c_sigma_factor * torch.ones(4) + + perturb_factor = torch.sqrt(box[2]*box[3])*c_sigma_factor + + # multiple tries to ensure that the perturbed box has iou > min_iou with the input box + for i_ in range(100): + c_x = box[0] + 0.5*box[2] + c_y = box[1] + 0.5 * box[3] + c_x_per = random.gauss(c_x, perturb_factor[0]) + c_y_per = random.gauss(c_y, perturb_factor[1]) + + w_per = random.gauss(box[2], perturb_factor[2]) + h_per = random.gauss(box[3], perturb_factor[3]) + + if w_per <= 1: + w_per = box[2]*rand_uniform(0.15, 0.5) + + if h_per <= 1: + h_per = box[3]*rand_uniform(0.15, 0.5) + + box_per = torch.Tensor([c_x_per - 0.5*w_per, c_y_per - 0.5*h_per, w_per, h_per]).round() + + if box_per[2] <= 1: + box_per[2] = box[2]*rand_uniform(0.15, 0.5) + + if box_per[3] <= 1: + box_per[3] = box[3]*rand_uniform(0.15, 0.5) + + box_iou = iou(box.view(1, 4), box_per.view(1, 4)) + + # if there is sufficient overlap, return + if box_iou > min_iou: + return box_per, box_iou + + # else reduce the perturb factor + perturb_factor *= 0.9 + + return box_per, box_iou + + +def gauss_1d(sz, sigma, center, end_pad=0): + k = torch.arange(-(sz-1)/2, (sz+1)/2 + end_pad).reshape(1, -1) + return torch.exp(-1.0/(2*sigma**2) * (k - center.reshape(-1, 1))**2) + + +def gauss_2d(sz, sigma, center, end_pad=(0, 0)): + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + return gauss_1d(sz[0].item(), sigma[0], center[:, 0], end_pad[0]).reshape(center.shape[0], 1, -1) * \ + gauss_1d(sz[1].item(), sigma[1], center[:, 1], end_pad[1]).reshape(center.shape[0], -1, 1) + + +def gaussian_label_function(target_bb, sigma_factor, kernel_sz, feat_sz, image_sz, end_pad_if_even=True): + """Construct Gaussian label function.""" + + if isinstance(kernel_sz, (float, int)): + kernel_sz = (kernel_sz, kernel_sz) + if isinstance(feat_sz, (float, int)): + feat_sz = (feat_sz, feat_sz) + if isinstance(image_sz, (float, int)): + image_sz = (image_sz, image_sz) + + image_sz = torch.Tensor(image_sz) + feat_sz = torch.Tensor(feat_sz) + + target_center = target_bb[:, 0:2] + 0.5 * target_bb[:, 2:4] + target_center_norm = (target_center - image_sz / 2) / image_sz + + center = feat_sz * target_center_norm + 0.5 * \ + torch.Tensor([(kernel_sz[0] + 1) % 2, (kernel_sz[1] + 1) % 2]) + + sigma = sigma_factor * feat_sz.prod().sqrt().item() + + if end_pad_if_even: + end_pad = (int(kernel_sz[0]%2 == 0), int(kernel_sz[1]%2 == 0)) + else: + end_pad = (0, 0) + + gauss_label = gauss_2d(feat_sz, sigma, center, end_pad) + return gauss_label + diff --git a/Stark/external/AR/ltr/data/sampler.py b/Stark/external/AR/ltr/data/sampler.py new file mode 100755 index 0000000..d041bc4 --- /dev/null +++ b/Stark/external/AR/ltr/data/sampler.py @@ -0,0 +1,189 @@ +import random +import torch.utils.data +from pytracking import TensorDict + + +def no_processing(data): + return data + + +class TrackingSampler(torch.utils.data.Dataset): + """ Class responsible for sampling frames from training sequences to form batches. Each training sample is a + tuple consisting of i) a set of train frames, used to learn the DiMP classification model and obtain the + modulation vector for IoU-Net, and ii) a set of test frames on which target classification loss for the predicted + DiMP model, and the IoU prediction loss for the IoU-Net is calculated. + + The sampling is done in the following ways. First a dataset is selected at random. Next, a sequence is selected + from that dataset. A base frame is then sampled randomly from the sequence. Next, a set of 'train frames' and + 'test frames' are sampled from the sequence from the range [base_frame_id - max_gap, base_frame_id] and + (base_frame_id, base_frame_id + max_gap] respectively. Only the frames in which the target is visible are sampled. + If enough visible frames are not found, the 'max_gap' is increased gradually till enough frames are found. + + The sampled frames are then passed through the input 'processing' function for the necessary processing- + """ + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames, num_train_frames=1, processing=no_processing, frame_sample_mode='causal'): + """ + args: + datasets - List of datasets to be used for training + p_datasets - List containing the probabilities by which each dataset will be sampled + samples_per_epoch - Number of training samples per epoch + max_gap - Maximum gap, in frame numbers, between the train frames and the test frames. + num_test_frames - Number of test frames to sample. + num_train_frames - Number of train frames to sample. + processing - An instance of Processing class which performs the necessary processing of the data. + frame_sample_mode - Either 'causal' or 'interval'. If 'causal', then the test frames are sampled in a causally, + otherwise randomly within the interval. + """ + self.datasets = datasets + + # If p not provided, sample uniformly from all videos + if p_datasets is None: + p_datasets = [len(d) for d in self.datasets] + + # Normalize + p_total = sum(p_datasets) + self.p_datasets = [x / p_total for x in p_datasets] + + self.samples_per_epoch = samples_per_epoch + self.max_gap = max_gap + self.num_test_frames = num_test_frames + self.num_train_frames = num_train_frames + self.processing = processing + self.frame_sample_mode = frame_sample_mode + + def __len__(self): + return self.samples_per_epoch + + def _sample_visible_ids(self, visible, num_ids=1, min_id=None, max_id=None): + """ Samples num_ids frames between min_id and max_id for which target is visible + + args: + visible - 1d Tensor indicating whether target is visible for each frame + num_ids - number of frames to be samples + min_id - Minimum allowed frame number + max_id - Maximum allowed frame number + + returns: + list - List of sampled frame numbers. None if not sufficient visible frames could be found. + """ + if num_ids == 0: + return [] + if min_id is None or min_id < 0: + min_id = 0 + if max_id is None or max_id > len(visible): + max_id = len(visible) + + valid_ids = [i for i in range(min_id, max_id) if visible[i]] + + # No visible ids + if len(valid_ids) == 0: + return None + + return random.choices(valid_ids, k=num_ids) + + def __getitem__(self, index): + """ + args: + index (int): Index (Ignored since we sample randomly) + + returns: + TensorDict - dict containing all the data blocks + """ + + # Select a dataset + dataset = random.choices(self.datasets, self.p_datasets)[0] + is_video_dataset = dataset.is_video_sequence() + + # Sample a sequence with enough visible frames + enough_visible_frames = False + while not enough_visible_frames: + # Sample a sequence + seq_id = random.randint(0, dataset.get_num_sequences() - 1) + + # Sample frames + seq_info_dict = dataset.get_sequence_info(seq_id) + visible = seq_info_dict['visible'] + + enough_visible_frames = visible.type(torch.int64).sum().item() > 2 * ( + self.num_test_frames + self.num_train_frames) and len(visible) >= 20 + + enough_visible_frames = enough_visible_frames or not is_video_dataset + + if is_video_dataset: + train_frame_ids = None + test_frame_ids = None + gap_increase = 0 + + if self.frame_sample_mode == 'interval': + # Sample frame numbers within interval defined by the first frame + while test_frame_ids is None: + base_frame_id = self._sample_visible_ids(visible, num_ids=1) + extra_train_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_train_frames - 1, + min_id=base_frame_id[ + 0] - self.max_gap - gap_increase, + max_id=base_frame_id[ + 0] + self.max_gap + gap_increase) + if extra_train_frame_ids is None: + gap_increase += 5 + continue + train_frame_ids = base_frame_id + extra_train_frame_ids + test_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_test_frames, + min_id=train_frame_ids[0] - self.max_gap - gap_increase, + max_id=train_frame_ids[0] + self.max_gap + gap_increase) + gap_increase += 5 # Increase gap until a frame is found + + elif self.frame_sample_mode == 'causal': + # Sample test and train frames in a causal manner, i.e. test_frame_ids > train_frame_ids + while test_frame_ids is None: + base_frame_id = self._sample_visible_ids(visible, num_ids=1, min_id=self.num_train_frames - 1, + max_id=len(visible) - self.num_test_frames) + prev_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_train_frames - 1, + min_id=base_frame_id[0] - self.max_gap - gap_increase, + max_id=base_frame_id[0]) + if prev_frame_ids is None: + gap_increase += 5 + continue + train_frame_ids = base_frame_id + prev_frame_ids + test_frame_ids = self._sample_visible_ids(visible, min_id=train_frame_ids[0] + 1, + max_id=train_frame_ids[0] + self.max_gap + gap_increase, + num_ids=self.num_test_frames) + # Increase gap until a frame is found + gap_increase += 5 + else: + # In case of image dataset, just repeat the image to generate synthetic video + train_frame_ids = [1] * self.num_train_frames + test_frame_ids = [1] * self.num_test_frames + + train_frames, train_anno, meta_obj_train = dataset.get_frames(seq_id, train_frame_ids, seq_info_dict) + test_frames, test_anno, meta_obj_test = dataset.get_frames(seq_id, test_frame_ids, seq_info_dict) + + data = TensorDict({'train_images': train_frames, + 'train_anno': train_anno['bbox'], + 'test_images': test_frames, + 'test_anno': test_anno['bbox'], + 'dataset': dataset.get_name(), + 'test_class': meta_obj_test.get('object_class_name')}) + + return self.processing(data) + + +class DiMPSampler(TrackingSampler): + """ See TrackingSampler.""" + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames, num_train_frames=1, processing=no_processing, frame_sample_mode='causal'): + super().__init__(datasets=datasets, p_datasets=p_datasets, samples_per_epoch=samples_per_epoch, max_gap=max_gap, + num_test_frames=num_test_frames, num_train_frames=num_train_frames, processing=processing, + frame_sample_mode=frame_sample_mode) + + +class ATOMSampler(TrackingSampler): + """ See TrackingSampler.""" + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames=1, num_train_frames=1, processing=no_processing, frame_sample_mode='interval'): + super().__init__(datasets=datasets, p_datasets=p_datasets, samples_per_epoch=samples_per_epoch, max_gap=max_gap, + num_test_frames=num_test_frames, num_train_frames=num_train_frames, processing=processing, + frame_sample_mode=frame_sample_mode) \ No newline at end of file diff --git a/Stark/external/AR/ltr/data/transforms.py b/Stark/external/AR/ltr/data/transforms.py new file mode 100755 index 0000000..958c779 --- /dev/null +++ b/Stark/external/AR/ltr/data/transforms.py @@ -0,0 +1,440 @@ +import random +import numpy as np +import math +import cv2 as cv +import torch +import torch.nn.functional as F +import torchvision.transforms.functional as tvisf + + +class Transform: + """A set of transformations, used for e.g. data augmentation. + Args of constructor: + transforms: An arbitrary number of transformations, derived from the TransformBase class. + They are applied in the order they are given. + + The Transform object can jointly transform images, bounding boxes and segmentation masks. + This is done by calling the object with the following key-word arguments (all are optional). + + The following arguments are inputs to be transformed. They are either supplied as a single instance, or a list of instances. + image - Image + coords - 2xN dimensional Tensor of 2D image coordinates [y, x] + bbox - Bounding box on the form [x, y, w, h] + mask - Segmentation mask with discrete classes + + The following parameters can be supplied with calling the transform object: + joint [Bool] - If True then transform all images/coords/bbox/mask in the list jointly using the same transformation. + Otherwise each tuple (images, coords, bbox, mask) will be transformed independently using + different random rolls. Default: True. + new_roll [Bool] - If False, then no new random roll is performed, and the saved result from the previous roll + is used instead. Default: True. + + Check the DiMPProcessing class for examples. + """ + + def __init__(self, *transforms): + if len(transforms) == 1 and isinstance(transforms[0], (list, tuple)): + transforms = transforms[0] + self.transforms = transforms + self._valid_inputs = ['image', 'coords', 'bbox', 'mask'] + self._valid_args = ['joint', 'new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + + def __call__(self, **inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + for v in inputs.keys(): + if v not in self._valid_all: + raise ValueError('Incorrect input \"{}\" to transform. Only supports inputs {} and arguments {}.'.format(v, self._valid_inputs, self._valid_args)) + + joint_mode = inputs.get('joint', True) + new_roll = inputs.get('new_roll', True) + + if not joint_mode: + out = zip(*[self(**inp) for inp in self._split_inputs(inputs)]) + return tuple(list(o) for o in out) + + out = {k: v for k, v in inputs.items() if k in self._valid_inputs} + + for t in self.transforms: + out = t(**out, joint=joint_mode, new_roll=new_roll) + if len(var_names) == 1: + return out[var_names[0]] + # Make sure order is correct + return tuple(out[v] for v in var_names) + + def _split_inputs(self, inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + split_inputs = [{k: v for k, v in zip(var_names, vals)} for vals in zip(*[inputs[vn] for vn in var_names])] + for arg_name, arg_val in filter(lambda it: it[0]!='joint' and it[0] in self._valid_args, inputs.items()): + if isinstance(arg_val, list): + for inp, av in zip(split_inputs, arg_val): + inp[arg_name] = av + else: + for inp in split_inputs: + inp[arg_name] = arg_val + return split_inputs + + def __repr__(self): + format_string = self.__class__.__name__ + '(' + for t in self.transforms: + format_string += '\n' + format_string += ' {0}'.format(t) + format_string += '\n)' + return format_string + + +class TransformBase: + """Base class for transformation objects. See the Transform class for details.""" + def __init__(self): + self._valid_inputs = ['image', 'coords', 'bbox', 'mask'] + self._valid_args = ['new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + self._rand_params = None + + def __call__(self, **inputs): + # Split input + input_vars = {k: v for k, v in inputs.items() if k in self._valid_inputs} + input_args = {k: v for k, v in inputs.items() if k in self._valid_args} + + # Roll random parameters for the transform + if input_args.get('new_roll', True): + rand_params = self.roll() + if rand_params is None: + rand_params = () + elif not isinstance(rand_params, tuple): + rand_params = (rand_params,) + self._rand_params = rand_params + + outputs = dict() + for var_name, var in input_vars.items(): + if var is not None: + transform_func = getattr(self, 'transform_' + var_name) + if var_name in ['coords', 'bbox']: + params = (self._get_image_size(input_vars),) + self._rand_params + else: + params = self._rand_params + if isinstance(var, (list, tuple)): + outputs[var_name] = [transform_func(x, *params) for x in var] + else: + outputs[var_name] = transform_func(var, *params) + return outputs + + def _get_image_size(self, inputs): + im = None + for var_name in ['image', 'mask']: + if inputs.get(var_name) is not None: + im = inputs[var_name] + break + if im is None: + return None + if isinstance(im, (list, tuple)): + im = im[0] + if isinstance(im, np.ndarray): + return im.shape[:2] + if torch.is_tensor(im): + return (im.shape[-2], im.shape[-1]) + raise Exception('Unknown image type') + + def roll(self): + return None + + def transform_image(self, image, *rand_params): + """Must be deterministic""" + return image + + def transform_coords(self, coords, image_shape, *rand_params): + """Must be deterministic""" + return coords + + def transform_bbox(self, bbox, image_shape, *rand_params): + """Assumes [x, y, w, h]""" + # Check if not overloaded + if self.transform_coords.__code__ == TransformBase.transform_coords.__code__: + return bbox + + coord = bbox.clone().view(-1,2).t().flip(0) + + x1 = coord[1, 0] + x2 = coord[1, 0] + coord[1, 1] + + y1 = coord[0, 0] + y2 = coord[0, 0] + coord[0, 1] + + coord_all = torch.tensor([[y1, y1, y2, y2], [x1, x2, x2, x1]]) + + coord_transf = self.transform_coords(coord_all, image_shape, *rand_params).flip(0) + tl = torch.min(coord_transf, dim=1)[0] + sz = torch.max(coord_transf, dim=1)[0] - tl + bbox_out = torch.cat((tl, sz), dim=-1).reshape(bbox.shape) + return bbox_out + + def transform_mask(self, mask, *rand_params): + """Must be deterministic""" + return mask + + +class ToTensor(TransformBase): + """Convert to a Tensor""" + + def transform_image(self, image): + # handle numpy array + if image.ndim == 2: + image = image[:, :, None] + + image = torch.from_numpy(image.transpose((2, 0, 1))) + # backward compatibility + if isinstance(image, torch.ByteTensor): + return image.float().div(255) + else: + return image + + def transfrom_mask(self, mask): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + + + +class ToTensorAndJitter(TransformBase): + """Convert to a Tensor and jitter brightness""" + def __init__(self, brightness_jitter=0.0, normalize=True): + super().__init__() + self.brightness_jitter = brightness_jitter + self.normalize = normalize + + def roll(self): + return np.random.uniform(max(0, 1 - self.brightness_jitter), 1 + self.brightness_jitter) + + def transform_image(self, image, brightness_factor): + # handle numpy array + image = torch.from_numpy(image.transpose((2, 0, 1))) + + # backward compatibility + if self.normalize: + return image.float().mul(brightness_factor/255.0).clamp(0.0, 1.0) + else: + return image.float().mul(brightness_factor).clamp(0.0, 255.0) + + def transform_mask(self, mask, brightness_factor): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + else: + return mask + + +class Normalize(TransformBase): + """Normalize image""" + def __init__(self, mean, std, inplace=False): + super().__init__() + self.mean = mean + self.std = std + self.inplace = inplace + + def transform_image(self, image): + return tvisf.normalize(image, self.mean, self.std, self.inplace) + + +class ToGrayscale(TransformBase): + """Converts image to grayscale with probability""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + self.color_weights = np.array([0.2989, 0.5870, 0.1140], dtype=np.float32) + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_grayscale): + if do_grayscale: + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) + return np.stack([img_gray, img_gray, img_gray], axis=2) + # return np.repeat(np.sum(img * self.color_weights, axis=2, keepdims=True).astype(np.uint8), 3, axis=2) + return image + + +class ToBGR(TransformBase): + """Converts image to BGR""" + def transform_image(self, image): + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_bgr = cv.cvtColor(image, cv.COLOR_RGB2BGR) + return img_bgr + + +class RandomHorizontalFlip(TransformBase): + """Horizontally flip image randomly with a probability p.""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_flip): + if do_flip: + if torch.is_tensor(image): + return image.flip((2,)) + return np.fliplr(image).copy() + return image + + def transform_coords(self, coords, image_shape, do_flip): + if do_flip: + coords = coords.clone() + coords[1,:] = (image_shape[1] - 1) - coords[1,:] + return coords + + def transform_mask(self, mask, do_flip): + if do_flip: + if torch.is_tensor(mask): + return mask.flip((-1,)) + return np.fliplr(mask).copy() + return mask + + +class Blur(TransformBase): + """ Blur the image by applying a gaussian kernel with given sigma""" + def __init__(self, sigma): + super().__init__() + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def transform_image(self, image): + if torch.is_tensor(image): + sz = image.shape[2:] + im1 = F.conv2d(image.view(-1, 1, sz[0], sz[1]), self.filter[0], padding=(self.filter_size[0], 0)) + return F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(-1,sz[0],sz[1]) + else: + raise NotImplementedError + + +class RandomBlur(TransformBase): + """ Blur the image, with a given probability, by applying a gaussian kernel with given sigma""" + def __init__(self, sigma, probability=0.1): + super().__init__() + self.probability = probability + + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def roll(self): + return random.random() < self.probability + + def transform(self, image, do_blur=None): + if do_blur is None: + do_blur = False + + if do_blur: + if torch.is_tensor(image): + sz = image.shape[1:] + im1 = F.conv2d(image.view(-1, 1, sz[0], sz[1]), self.filter[0], padding=(self.filter_size[0], 0)) + return F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(-1,sz[0],sz[1]) + else: + raise NotImplementedError + else: + return image + + +class RandomAffine(TransformBase): + """Apply random affine transformation.""" + def __init__(self, p_flip=0.0, max_rotation=0.0, max_shear=0.0, max_scale=0.0, max_ar_factor=0.0, + border_mode='constant', pad_amount=0): + super().__init__() + self.p_flip = p_flip + self.max_rotation = max_rotation + self.max_shear = max_shear + self.max_scale = max_scale + self.max_ar_factor = max_ar_factor + + if border_mode == 'constant': + self.border_flag = cv.BORDER_CONSTANT + elif border_mode == 'replicate': + self.border_flag == cv.BORDER_REPLICATE + else: + raise Exception + + self.pad_amount = pad_amount + + def roll(self): + do_flip = random.random() < self.p_flip + theta = random.uniform(-self.max_rotation, self.max_rotation) + + shear_x = random.uniform(-self.max_shear, self.max_shear) + shear_y = random.uniform(-self.max_shear, self.max_shear) + + ar_factor = np.exp(random.uniform(-self.max_ar_factor, self.max_ar_factor)) + scale_factor = np.exp(random.uniform(-self.max_scale, self.max_scale)) + + return do_flip, theta, (shear_x, shear_y), (scale_factor, scale_factor * ar_factor) + + def _construct_t_mat(self, image_shape, do_flip, theta, shear_values, scale_factors): + im_h, im_w = image_shape + t_mat = np.identity(3) + + if do_flip: + if do_flip: + t_mat[0, 0] = -1.0 + t_mat[0, 2] = im_w + + t_rot = cv.getRotationMatrix2D((im_w * 0.5, im_h * 0.5), theta, 1.0) + t_rot = np.concatenate((t_rot, np.array([0.0, 0.0, 1.0]).reshape(1, 3))) + + t_shear = np.array([[1.0, shear_values[0], -shear_values[0] * 0.5 * im_w], + [shear_values[1], 1.0, -shear_values[1] * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_scale = np.array([[scale_factors[0], 0.0, (1.0 - scale_factors[0]) * 0.5 * im_w], + [0.0, scale_factors[1], (1.0 - scale_factors[1]) * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_mat = t_scale @ t_rot @ t_shear @ t_mat + + t_mat[0, 2] += self.pad_amount + t_mat[1, 2] += self.pad_amount + + t_mat = t_mat[:2, :] + + return t_mat + + def transform_image(self, image, do_flip, theta, shear_values, scale_factors): + if torch.is_tensor(image): + raise Exception('Only supported for numpy input') + + t_mat = self._construct_t_mat(image.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (image.shape[1] + 2*self.pad_amount, image.shape[0] + 2*self.pad_amount) + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_LINEAR, + borderMode=self.border_flag) + + return image_t + + def transform_coords(self, coords, image_shape, do_flip, theta, shear_values, scale_factors): + t_mat = self._construct_t_mat(image_shape, do_flip, theta, shear_values, scale_factors) + + t_mat_tensor = torch.from_numpy(t_mat).float() + + coords_xy1 = torch.stack((coords[1, :], coords[0, :], torch.ones_like(coords[1, :]))) + + coords_xy_t = torch.mm(t_mat_tensor, coords_xy1) + + return coords_xy_t[[1, 0], :] + + def transform_mask(self, mask, do_flip, theta, shear_values, scale_factors): + t_mat = self._construct_t_mat(mask.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (mask.shape[1] + 2*self.pad_amount, mask.shape[0] + 2*self.pad_amount) + + mask_t = cv.warpAffine(mask.numpy(), t_mat, output_sz, flags=cv.INTER_NEAREST, + borderMode=self.border_flag) + + return torch.from_numpy(mask_t) diff --git a/Stark/external/AR/ltr/dataset/__init__.py b/Stark/external/AR/ltr/dataset/__init__.py new file mode 100755 index 0000000..17d547c --- /dev/null +++ b/Stark/external/AR/ltr/dataset/__init__.py @@ -0,0 +1,15 @@ +from .lasot import Lasot +from .got10k import Got10k +from .tracking_net import TrackingNet +from .imagenetvid import ImagenetVID +from .coco import MSCOCO +from .coco_seq import MSCOCOSeq +from .youtubevos import YouTubeVOS +from .davis import Davis +from .lvis import LVIS +from .ecssd import ECSSD +from .msra10k import MSRA10k +from .hku_is import HKUIS +from .sbd import SBD +from .synthetic_video import SyntheticVideo +from .synthetic_video_blend import SyntheticVideoBlend diff --git a/Stark/external/AR/ltr/dataset/base_image_dataset.py b/Stark/external/AR/ltr/dataset/base_image_dataset.py new file mode 100755 index 0000000..814dd52 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/base_image_dataset.py @@ -0,0 +1,92 @@ +import torch.utils.data +from ltr.data.image_loader import jpeg4py_loader + + +class BaseImageDataset(torch.utils.data.Dataset): + """ Base class for image datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.image_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_images() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_images(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.image_list) + + def has_class_info(self): + return False + + def get_class_name(self, image_id): + return None + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_images_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_image_info(self, seq_id): + """ Returns information about a particular image, + + args: + seq_id - index of the image + + returns: + Dict + """ + raise NotImplementedError + + def get_image(self, image_id, anno=None): + """ Get a image + + args: + image_id - index of image + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + image - + anno - + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/Stark/external/AR/ltr/dataset/base_video_dataset.py b/Stark/external/AR/ltr/dataset/base_video_dataset.py new file mode 100755 index 0000000..e440195 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/base_video_dataset.py @@ -0,0 +1,109 @@ +import torch.utils.data +from ltr.data.image_loader import jpeg4py_loader + + +class BaseVideoDataset(torch.utils.data.Dataset): + """ Base class for video datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.sequence_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_sequences() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def is_video_sequence(self): + """ Returns whether the dataset is a video dataset or an image dataset + + returns: + bool - True if a video dataset + """ + return True + + def is_synthetic_video_dataset(self): + """ Returns whether the dataset contains real videos or synthetic + + returns: + bool - True if a video dataset + """ + return False + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_sequences(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.sequence_list) + + def has_class_info(self): + return False + + def has_occlusion_info(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_sequences_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_sequence_info(self, seq_id): + """ Returns information about a particular sequences, + + args: + seq_id - index of the sequence + + returns: + Dict + """ + raise NotImplementedError + + def get_frames(self, seq_id, frame_ids, anno=None): + """ Get a set of frames from a particular sequence + + args: + seq_id - index of sequence + frame_ids - a list of frame numbers + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + list - List of frames corresponding to frame_ids + list - List of dicts for each frame + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/Stark/external/AR/ltr/dataset/coco.py b/Stark/external/AR/ltr/dataset/coco.py new file mode 100755 index 0000000..e8b008d --- /dev/null +++ b/Stark/external/AR/ltr/dataset/coco.py @@ -0,0 +1,156 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader +import torch +from pycocotools.coco import COCO +import random +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class MSCOCO(BaseImageDataset): + """ The COCO object detection dataset. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None, + split="train", version="2014"): + """ + args: + root - path to coco root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() # the parent class thing would happen in the sampler + + self.image_list = self._get_image_list(min_area=min_area) + + if data_fraction is not None: + self.image_list = random.sample(self.image_list, int(len(self.image_list) * data_fraction)) + self.im_per_class = self._build_im_per_class() + + def _get_image_list(self, min_area=None): + ann_list = list(self.coco_set.anns.keys()) + image_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + if min_area is not None: + image_list = [a for a in image_list if self.coco_set.anns[a]['area'] > min_area] + + return image_list + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def has_segmentation_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def _build_im_per_class(self): + im_per_class = {} + for i, im in enumerate(self.image_list): + class_name = self.cats[self.coco_set.anns[im]['category_id']]['name'] + if class_name not in im_per_class: + im_per_class[class_name] = [i] + else: + im_per_class[class_name].append(i) + + return im_per_class + + def get_images_in_class(self, class_name): + return self.im_per_class[class_name] + + def get_image_info(self, im_id): + anno = self._get_anno(im_id) + + bbox = torch.Tensor(anno['bbox']).view(4,) + + mask = torch.Tensor(self.coco_set.annToMask(anno)) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, im_id): + anno = self.coco_set.anns[self.image_list[im_id]] + + return anno + + def _get_image(self, im_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.image_list[im_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, im_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_class_name(self, im_id): + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + return cat_dict_current['name'] + + def get_image(self, image_id, anno=None): + frame = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/coco_seq.py b/Stark/external/AR/ltr/dataset/coco_seq.py new file mode 100755 index 0000000..90a1e5b --- /dev/null +++ b/Stark/external/AR/ltr/dataset/coco_seq.py @@ -0,0 +1,168 @@ +import os +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +import torch +import random +from pycocotools.coco import COCO +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class MSCOCOSeq(BaseVideoDataset): + """ The COCO dataset. COCO is an image dataset. Thus, we treat each image as a sequence of length 1. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, split="train", version="2014"): + """ + args: + root - path to the coco dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + data_fraction (None) - Fraction of images to be used. The images are selected randomly. If None, all the + images will be used + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + # Load the COCO set. + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() + + self.sequence_list = self._get_sequence_list() + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + self.seq_per_class = self._build_seq_per_class() + + def _get_sequence_list(self): + ann_list = list(self.coco_set.anns.keys()) + seq_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + return seq_list + + def is_video_sequence(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def _build_seq_per_class(self): + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = self.cats[self.coco_set.anns[seq]['category_id']]['name'] + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def get_sequence_info(self, seq_id): + anno = self._get_anno(seq_id) + + bbox = torch.Tensor(anno['bbox']).view(1, 4) + + mask = torch.Tensor(self.coco_set.annToMask(anno)).unsqueeze(dim=0) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, seq_id): + anno = self.coco_set.anns[self.sequence_list[seq_id]] + + return anno + + def _get_frames(self, seq_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.sequence_list[seq_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, seq_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + + def get_class_name(self, seq_id): + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + return cat_dict_current['name'] + + def get_frames(self, seq_id=None, frame_ids=None, anno=None): + # COCO is an image dataset. Thus we replicate the image denoted by seq_id len(frame_ids) times, and return a + # list containing these replicated images. + frame = self._get_frames(seq_id) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0, ...] for _ in frame_ids] + + object_meta = self.get_meta_info(seq_id) + + return frame_list, anno_frames, object_meta diff --git a/Stark/external/AR/ltr/dataset/davis.py b/Stark/external/AR/ltr/dataset/davis.py new file mode 100755 index 0000000..66ac216 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/davis.py @@ -0,0 +1,83 @@ +from pathlib import Path +from ltr.dataset.vos_base import VOSDatasetBase, VOSMeta +from pytracking.evaluation import Sequence +from ltr.admin.environment import env_settings +from ltr.data.image_loader import jpeg4py_loader + + +class Davis(VOSDatasetBase): + """ The Davis VOS dataset + + Publication: + A Benchmark Dataset and Evaluation Methodology for Video Object Segmentation + F. Perazzi, J. Pont-Tuset, B. McWilliams, L. Van Gool, M. Gross, and A. Sorkine-Hornung + CVPR, 2016 + http://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Perazzi_A_Benchmark_Dataset_CVPR_2016_paper.pdf + + Download the dataset from https://davischallenge.org/davis2017/code.html + """ + def __init__(self, root=None, sequences=None, version='2017', split='train', multiobj=True, + vis_threshold=10, image_loader=jpeg4py_loader): + """ + args: + root - Dataset root path. If unset, it uses the path in your local.py config. + sequences - List of sequence names. Limit to a subset of sequences if not None. + version - '2016' or '2017 + split - Any name in DAVIS/ImageSets/ + multiobj - Whether the dataset will return all objects in a sequence or multiple sequences with one object + in each. + vis_threshold - Minimum number of pixels required to consider a target object "visible". + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + if version == '2017': + if split in ['train', 'val']: + root = env_settings().davis_dir if root is None else root + elif split in ['test-dev']: + root = env_settings().davis_testdev_dir if root is None else root + else: + raise Exception('Unknown split {}'.format(split)) + else: + root = env_settings().davis16_dir if root is None else root + + super().__init__(name='DAVIS', root=Path(root), version=version, split=split, multiobj=multiobj, + vis_threshold=vis_threshold, image_loader=image_loader) + + dset_path = self.root + self._jpeg_path = dset_path / 'JPEGImages' / '480p' + self._anno_path = dset_path / 'Annotations' / '480p' + + meta_path = dset_path / "generated_meta.json" + if meta_path.exists(): + self.gmeta = VOSMeta(filename=meta_path) + else: + self.gmeta = VOSMeta.generate('DAVIS', self._jpeg_path, self._anno_path) + self.gmeta.save(meta_path) + + if sequences is None: + if self.split != 'all': + fname = dset_path / 'ImageSets' / self.version / (self.split + '.txt') + sequences = open(fname).read().splitlines() + else: + sequences = [p for p in sorted(self._jpeg_path.glob("*")) if p.is_dir()] + + self.sequence_names = sequences + self._samples = [] + + for seq in sequences: + obj_ids = self.gmeta.get_obj_ids(seq) + if self.multiobj: # Multiple objects per sample + self._samples.append((seq, obj_ids)) + else: # One object per sample + self._samples.extend([(seq, [obj_id]) for obj_id in obj_ids]) + + print("%s loaded." % self.get_name()) + + def _construct_sequence(self, sequence_info): + + seq_name = sequence_info['sequence'] + images, gt_labels, gt_bboxes = self.get_paths_and_bboxes(sequence_info) + + return Sequence(name=seq_name, frames=images, dataset='DAVIS', ground_truth_rect=gt_bboxes, + ground_truth_seg=gt_labels, object_ids=sequence_info['object_ids'], + multiobj_mode=self.multiobj) diff --git a/Stark/external/AR/ltr/dataset/ecssd.py b/Stark/external/AR/ltr/dataset/ecssd.py new file mode 100755 index 0000000..8ac054f --- /dev/null +++ b/Stark/external/AR/ltr/dataset/ecssd.py @@ -0,0 +1,84 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, opencv_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class ECSSD(BaseImageDataset): + """ + Extended Complex Scene Saliency Dataset (ECSSD) + + Publication: + Hierarchical Image Saliency Detection on Extended CSSD + Jianping Shi, Qiong Yan, Li Xu, Jiaya Jia + TPAMI, 2016 + https://arxiv.org/pdf/1408.5418.pdf + + Download the dataset from http://www.cse.cuhk.edu.hk/leojia/projects/hsaliency/dataset.html + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to ECSSD root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().ecssd_dir if root is None else root + super().__init__('ECSSD', root, image_loader) + + self.image_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + images = [] + + for i in range(1, 1001): + a = imread_indexed(os.path.join(self.root, 'ground_truth_mask', '{:04d}.png'.format(i))) + + if min_area is None or (a > 0).sum() > min_area: + images.append(i) + + return images + + def get_name(self): + return 'ecssd' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = imread_indexed(os.path.join(self.root, 'ground_truth_mask', '{:04d}.png'.format(self.image_list[im_id]))) + + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_loader(os.path.join(self.root, 'images', '{:04d}.jpg'.format(self.image_list[image_id]))) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/got10k.py b/Stark/external/AR/ltr/dataset/got10k.py new file mode 100755 index 0000000..72013de --- /dev/null +++ b/Stark/external/AR/ltr/dataset/got10k.py @@ -0,0 +1,183 @@ +import os +import os.path +import numpy as np +import torch +import csv +import pandas +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +from ltr.admin.environment import env_settings + + +class Got10k(BaseVideoDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, split=None, seq_ids=None, data_fraction=None): + """ + args: + root - path to the got-10k training data. Note: This should point to the 'train' folder inside GOT-10k + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + split - 'train' or 'val'. Note: The validation split here is a subset of the official got-10k train split, + not NOT the official got-10k validation split. To use the official validation split, provide that as + the root folder instead. + seq_ids - List containing the ids of the videos to be used for training. Note: Only one of 'split' or 'seq_ids' + options can be used at the same time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().got10k_dir if root is None else root + super().__init__('GOT10k', root, image_loader) + + # all folders inside the root + self.sequence_list = self._get_sequence_list() + + # seq_id is the index of the folder inside the got10k root path + if split is not None: + if seq_ids is not None: + raise ValueError('Cannot set both split_name and seq_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_train_split.txt') + elif split == 'val': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_val_split.txt') + elif split == 'vottrain': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_train_split.txt') + elif split == 'votval': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_val_split.txt') + else: + raise ValueError('Unknown split name.') + seq_ids = pandas.read_csv(file_path, header=None, squeeze=True, dtype=np.int64).values.tolist() + elif seq_ids is None: + seq_ids = list(range(0, len(self.sequence_list))) + + self.sequence_list = [self.sequence_list[i] for i in seq_ids] + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.sequence_meta_info = self._load_meta_info() + self.seq_per_class = self._build_seq_per_class() + + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def get_name(self): + return 'got10k' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def _load_meta_info(self): + sequence_meta_info = {s: self._read_meta(os.path.join(self.root, s)) for s in self.sequence_list} + return sequence_meta_info + + def _read_meta(self, seq_path): + try: + with open(os.path.join(seq_path, 'meta_info.ini')) as f: + meta_info = f.readlines() + object_meta = OrderedDict({'object_class_name': meta_info[5].split(': ')[-1][:-1], + 'motion_class': meta_info[6].split(': ')[-1][:-1], + 'major_class': meta_info[7].split(': ')[-1][:-1], + 'root_class': meta_info[8].split(': ')[-1][:-1], + 'motion_adverb': meta_info[9].split(': ')[-1][:-1]}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def _build_seq_per_class(self): + seq_per_class = {} + + for i, s in enumerate(self.sequence_list): + object_class = self.sequence_meta_info[s]['object_class_name'] + if object_class in seq_per_class: + seq_per_class[object_class].append(i) + else: + seq_per_class[object_class] = [i] + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _get_sequence_list(self): + with open(os.path.join(self.root, 'list.txt')) as f: + dir_list = list(csv.reader(f)) + dir_list = [dir_name[0] for dir_name in dir_list] + return dir_list + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "absence.label") + cover_file = os.path.join(seq_path, "cover.label") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + with open(cover_file, 'r', newline='') as f: + cover = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + + target_visible = ~occlusion & (cover>0).byte() + + visible_ratio = cover.float() / 8 + return target_visible, visible_ratio + + def _get_sequence_path(self, seq_id): + return os.path.join(self.root, self.sequence_list[seq_id]) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible, visible_ratio = self._read_target_visible(seq_path) + visible = visible & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible, 'visible_ratio': visible_ratio} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def get_class_name(self, seq_id): + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + return obj_meta['object_class_name'] + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return frame_list, anno_frames, obj_meta diff --git a/Stark/external/AR/ltr/dataset/hku_is.py b/Stark/external/AR/ltr/dataset/hku_is.py new file mode 100755 index 0000000..75c7871 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/hku_is.py @@ -0,0 +1,90 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, opencv_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class HKUIS(BaseImageDataset): + """ + HKU-IS salient object detection dataset + + Publication: + Visual saliency based on multiscale deep features + Guanbin Li and Yizhou Yu + CVPR, 2015 + https://arxiv.org/pdf/1503.08663.pdf + + Dowload dataset from https://sites.google.com/site/ligb86/hkuis + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to HKU-IS root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().hkuis_dir if root is None else root + super().__init__('HKUIS', root, image_loader) + + self.image_list, self.anno_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + files_list = os.listdir(os.path.join(self.root, 'imgs')) + image_list = [f[:-4] for f in files_list] + + images = [] + annos = [] + + for f in image_list: + a = imread_indexed(os.path.join(self.root, 'gt', '{}.png'.format(f))) + + if min_area is None or (a > 0).sum() > min_area: + im = opencv_loader(os.path.join(self.root, 'imgs', '{}.png'.format(f))) + images.append(im) + annos.append(a) + + return images, annos + + def get_name(self): + return 'hku-is' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = self.anno_list[im_id] + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_list[image_id] + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/imagenetvid.py b/Stark/external/AR/ltr/dataset/imagenetvid.py new file mode 100755 index 0000000..74d0b23 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/imagenetvid.py @@ -0,0 +1,161 @@ +import os +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import default_image_loader +import xml.etree.ElementTree as ET +import json +import torch +import random +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +def get_target_to_image_ratio(seq): + anno = torch.Tensor(seq['anno']) + img_sz = torch.Tensor(seq['image_size']) + return (anno[0, 2:4].prod() / (img_sz.prod())).sqrt() + + +class ImagenetVID(BaseVideoDataset): + """ Imagenet VID dataset. + + Publication: + ImageNet Large Scale Visual Recognition Challenge + Olga Russakovsky, Jia Deng, Hao Su, Jonathan Krause, Sanjeev Satheesh, Sean Ma, Zhiheng Huang, Andrej Karpathy, + Aditya Khosla, Michael Bernstein, Alexander C. Berg and Li Fei-Fei + IJCV, 2015 + https://arxiv.org/pdf/1409.0575.pdf + + Download the dataset from http://image-net.org/ + """ + def __init__(self, root=None, image_loader=default_image_loader, min_length=0, max_target_area=1): + """ + args: + root - path to the imagenet vid dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + min_length - Minimum allowed sequence length. + max_target_area - max allowed ratio between target area and image area. Can be used to filter out targets + which cover complete image. + """ + root = env_settings().imagenet_dir if root is None else root + super().__init__(root, image_loader) + + cache_file = os.path.join(root, 'cache.json') + if os.path.isfile(cache_file): + # If available, load the pre-processed cache file containing meta-info for each sequence + with open(cache_file, 'r') as f: + sequence_list_dict = json.load(f) + + self.sequence_list = sequence_list_dict + else: + # Else process the imagenet annotations and generate the cache file + self.sequence_list = self._process_anno(root) + + with open(cache_file, 'w') as f: + json.dump(self.sequence_list, f) + + # Filter the sequences based on min_length and max_target_area in the first frame + self.sequence_list = [x for x in self.sequence_list if len(x['anno']) >= min_length and + get_target_to_image_ratio(x) < max_target_area] + + def get_name(self): + return 'imagenetvid' + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_sequence_info(self, seq_id): + bb_anno = torch.Tensor(self.sequence_list[seq_id]['anno']) + valid = (bb_anno[:, 2] > 0) & (bb_anno[:, 3] > 0) + visible = torch.ByteTensor(self.sequence_list[seq_id]['target_visible']) & valid.byte() + return {'bbox': bb_anno, 'valid': valid, 'visible': visible} + + def _get_frame(self, sequence, frame_id): + set_name = 'ILSVRC2015_VID_train_{:04d}'.format(sequence['set_id']) + vid_name = 'ILSVRC2015_train_{:08d}'.format(sequence['vid_id']) + frame_number = frame_id + sequence['start_frame'] + + frame_path = os.path.join(self.root, 'Data', 'VID', 'train', set_name, vid_name, + '{:06d}.JPEG'.format(frame_number)) + return self.image_loader(frame_path) + + def get_frames(self, seq_id, frame_ids, anno=None): + sequence = self.sequence_list[seq_id] + + frame_list = [self._get_frame(sequence, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + # Create anno dict + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + # added the class info to the meta info + object_meta = OrderedDict({'object_class': sequence['class_name'], + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta + + def _process_anno(self, root): + # Builds individual tracklets + base_vid_anno_path = os.path.join(root, 'Annotations', 'VID', 'train') + + all_sequences = [] + for set in sorted(os.listdir(base_vid_anno_path)): + set_id = int(set.split('_')[-1]) + for vid in sorted(os.listdir(os.path.join(base_vid_anno_path, set))): + + vid_id = int(vid.split('_')[-1]) + anno_files = sorted(os.listdir(os.path.join(base_vid_anno_path, set, vid))) + + frame1_anno = ET.parse(os.path.join(base_vid_anno_path, set, vid, anno_files[0])) + image_size = [int(frame1_anno.find('size/width').text), int(frame1_anno.find('size/height').text)] + + objects = [ET.ElementTree(file=os.path.join(base_vid_anno_path, set, vid, f)).findall('object') + for f in anno_files] + + tracklets = {} + + # Find all tracklets along with start frame + for f_id, all_targets in enumerate(objects): + for target in all_targets: + tracklet_id = target.find('trackid').text + if tracklet_id not in tracklets: + tracklets[tracklet_id] = f_id + + for tracklet_id, tracklet_start in tracklets.items(): + tracklet_anno = [] + target_visible = [] + class_name_id = None + + for f_id in range(tracklet_start, len(objects)): + found = False + for target in objects[f_id]: + if target.find('trackid').text == tracklet_id: + if not class_name_id: + class_name_id = target.find('name').text + x1 = int(target.find('bndbox/xmin').text) + y1 = int(target.find('bndbox/ymin').text) + x2 = int(target.find('bndbox/xmax').text) + y2 = int(target.find('bndbox/ymax').text) + + tracklet_anno.append([x1, y1, x2 - x1, y2 - y1]) + target_visible.append(target.find('occluded').text == '0') + + found = True + break + if not found: + break + + new_sequence = {'set_id': set_id, 'vid_id': vid_id, 'class_name': class_name_id, + 'start_frame': tracklet_start, 'anno': tracklet_anno, + 'target_visible': target_visible, 'image_size': image_size} + all_sequences.append(new_sequence) + + return all_sequences diff --git a/Stark/external/AR/ltr/dataset/lasot.py b/Stark/external/AR/ltr/dataset/lasot.py new file mode 100755 index 0000000..7918220 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/lasot.py @@ -0,0 +1,168 @@ +import os +import os.path +import torch +import numpy as np +import pandas +import csv +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +from ltr.admin.environment import env_settings + + +class Lasot(BaseVideoDataset): + """ LaSOT dataset. + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, vid_ids=None, split=None, data_fraction=None): + """ + args: + root - path to the lasot dataset. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + vid_ids - List containing the ids of the videos (1 - 20) used for training. If vid_ids = [1, 3, 5], then the + videos with subscripts -1, -3, and -5 from each class will be used for training. + split - If split='train', the official train split (protocol-II) is used for training. Note: Only one of + vid_ids or split option can be used at a time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().lasot_dir if root is None else root + super().__init__('LaSOT', root, image_loader) + + # Keep a list of all classes + self.class_list = [f for f in os.listdir(self.root)] + self.class_to_id = {cls_name: cls_id for cls_id, cls_name in enumerate(self.class_list)} + + self.sequence_list = self._build_sequence_list(vid_ids, split) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.seq_per_class = self._build_class_list() + + def _build_sequence_list(self, vid_ids=None, split=None): + if split is not None: + if vid_ids is not None: + raise ValueError('Cannot set both split_name and vid_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'lasot_train_split.txt') + else: + raise ValueError('Unknown split name.') + sequence_list = pandas.read_csv(file_path, header=None, squeeze=True).values.tolist() + elif vid_ids is not None: + sequence_list = [c+'-'+str(v) for c in self.class_list for v in vid_ids] + else: + raise ValueError('Set either split_name or vid_ids.') + + return sequence_list + + def _build_class_list(self): + seq_per_class = {} + for seq_id, seq_name in enumerate(self.sequence_list): + class_name = seq_name.split('-')[0] + if class_name in seq_per_class: + seq_per_class[class_name].append(seq_id) + else: + seq_per_class[class_name] = [seq_id] + + return seq_per_class + + def get_name(self): + return 'lasot' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "full_occlusion.txt") + out_of_view_file = os.path.join(seq_path, "out_of_view.txt") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + with open(out_of_view_file, 'r') as f: + out_of_view = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + + target_visible = ~occlusion & ~out_of_view + + return target_visible + + def _get_sequence_path(self, seq_id): + seq_name = self.sequence_list[seq_id] + class_name = seq_name.split('-')[0] + vid_id = seq_name.split('-')[1] + + return os.path.join(self.root, class_name, class_name + '-' + vid_id) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = self._read_target_visible(seq_path) & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, 'img', '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def _get_class(self, seq_path): + raw_class = seq_path.split('/')[-2] + return raw_class + + def get_class_name(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + obj_class = self._get_class(seq_path) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + + obj_class = self._get_class(seq_path) + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/external/AR/ltr/dataset/lvis.py b/Stark/external/AR/ltr/dataset/lvis.py new file mode 100755 index 0000000..276c02f --- /dev/null +++ b/Stark/external/AR/ltr/dataset/lvis.py @@ -0,0 +1,152 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader_w_failsafe +import torch +import random +import lvis.lvis as lvis_pk +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class LVIS(BaseImageDataset): + """ The LVIS object detection dataset + + Publication: + LVIS: A Dataset for Large Vocabulary Instance Segmentation + Agrim Gupta, Piotr Dollár, and Ross Girshick + CVPR, 2019 + https://arxiv.org/pdf/1908.03195.pdf + + Download the images along with annotations from https://www.lvisdataset.org/dataset. The root folder should be + organized as follows. + - lvis_root + - annotations + - lvis_v0.5_train.json + - lvis_v0.5_val.json + - images + - val2017 + - train2017 + + Note: You also have to install the lvis Python API from https://github.com/lvis-dataset/lvis-api + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader_w_failsafe, data_fraction=None, min_area=None, split="train"): + """ + args: + root - path to lvis root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + split - 'train' or 'val'. + """ + root = env_settings().lvis_dir if root is None else root + super().__init__('LVIS', root, image_loader) + + self.img_pth = os.path.join(root, 'images', f'{split}2017/') + self.anno_path = os.path.join(root, 'annotations', f'lvis_v0.5_{split}.json') + + # Load the LVIS set. + self.lvis_set = lvis_pk.LVIS(self.anno_path) + + self.cats = self.lvis_set.cats + + self.class_list = self.get_class_list() # the parent class thing would happen in the sampler + + self.image_list = self._get_image_list(min_area=min_area) + + if data_fraction is not None: + self.image_list = random.sample(self.image_list, int(len(self.image_list) * data_fraction)) + self.im_per_class = self._build_im_per_class() + + def _get_image_list(self, min_area=None): + im_list = list(self.lvis_set.anns.keys()) # No 'iscrowd' information in LVIS + + if min_area is not None: + im_list = [s for s in im_list if self.lvis_set.anns[s]['area'] > min_area] + + return im_list + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'lvis' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def _build_im_per_class(self): + im_per_class = {} + for i, im in enumerate(self.image_list): + class_name = self.cats[self.lvis_set.anns[im]['category_id']]['name'] + if class_name not in im_per_class: + im_per_class[class_name] = [i] + else: + im_per_class[class_name].append(i) + + return im_per_class + + def get_images_in_class(self, class_name): + return self.im_per_class[class_name] + + def get_image_info(self, im_id): + anno = self._get_anno(im_id) + + bbox = torch.Tensor(anno['bbox']).view(4,) + + mask = torch.Tensor(self.lvis_set.ann_to_mask(anno)) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, im_id): + anno = self.lvis_set.anns[self.image_list[im_id]] + + return anno + + def _get_image(self, im_id): + path = self.lvis_set.load_imgs([self.lvis_set.anns[self.image_list[im_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, im_id): + try: + cat_dict_current = self.cats[self.lvis_set.anns[self.image_list[im_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': None, # No 'supercategory' information available in LVIS + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_class_name(self, im_id): + cat_dict_current = self.cats[self.lvis_set.anns[self.image_list[im_id]]['category_id']] + return cat_dict_current['name'] + + def get_image(self, image_id, anno=None): + frame = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/msra10k.py b/Stark/external/AR/ltr/dataset/msra10k.py new file mode 100755 index 0000000..d1ab972 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/msra10k.py @@ -0,0 +1,87 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class MSRA10k(BaseImageDataset): + """ + MSRA10k salient object detection dataset + + Publication: + Global contrast based salient region detection + Ming-Ming Cheng, Niloy J. Mitra, Xiaolei Huang, Philip H. S. Torr, and Shi-Min Hu + TPAMI, 2015 + https://mmcheng.net/mftp/Papers/SaliencyTPAMI.pdf + + Download dataset from https://mmcheng.net/msra10k/ + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to MSRA10k root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().msra10k_dir if root is None else root + super().__init__('MSRA10k', root, image_loader) + + self.image_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + files_list = os.listdir(os.path.join(self.root, 'Imgs')) + image_list = [f[:-4] for f in files_list if f[-3:] == 'jpg'] + + images = [] + + for f in image_list: + a = imread_indexed(os.path.join(self.root, 'Imgs', '{}.png'.format(f))) + + if min_area is None or (a > 0).sum() > min_area: + images.append(f) + + return images + + def get_name(self): + return 'msra10k' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = imread_indexed(os.path.join(self.root, 'Imgs', '{}.png'.format(self.image_list[im_id]))) + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_loader(os.path.join(self.root, 'Imgs', '{}.jpg'.format(self.image_list[image_id]))) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/sbd.py b/Stark/external/AR/ltr/dataset/sbd.py new file mode 100755 index 0000000..6e98090 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/sbd.py @@ -0,0 +1,115 @@ +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader_w_failsafe +import torch +from collections import OrderedDict +import os +from scipy.io import loadmat +from ltr.data.bounding_box_utils import masks_to_bboxes + +from ltr.admin.environment import env_settings + + +class SBD(BaseImageDataset): + """ + Semantic Boundaries Dataset and Benchmark (SBD) + + Publication: + Semantic contours from inverse detectors + Bharath Hariharan, Pablo Arbelaez, Lubomir Bourdev, Subhransu Maji and Jitendra Malik + ICCV, 2011 + http://home.bharathh.info/pubs/pdfs/BharathICCV2011.pdf + + Download dataset from: http://home.bharathh.info/pubs/codes/SBD/download.html + """ + def __init__(self, root=None, image_loader=jpeg4py_loader_w_failsafe, data_fraction=None, split="train"): + """ + args: + root - path to SBD root folder + image_loader - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + split - dataset split ("train", "train_noval", "val") + """ + root = env_settings().sbd_dir if root is None else root + super().__init__('SBD', root, image_loader) + + assert split in ["train", "train_noval", "val"] + + self.root = root + + self.image_path_list, self.anno_file_list = self._load_dataset(split) + + # Load mat fine + anno_list = [loadmat(a) for a in self.anno_file_list] + + self.image_list = self._construct_image_list(anno_list) + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, split): + split_f = os.path.join(self.root, split.rstrip('\n') + '.txt') + + with open(os.path.join(split_f), "r") as f: + file_names = [x.strip() for x in f.readlines()] + + image_list = [os.path.join(self.root, 'img', x + ".jpg") for x in file_names] + anno_list = [os.path.join(self.root, 'inst', x + ".mat") for x in file_names] + + assert (len(image_list) == len(anno_list)) + + return image_list, anno_list + + def _get_mask_from_mat(self, mat): + return torch.tensor(mat['GTinst'][0]['Segmentation'][0]) + + def _construct_image_list(self, anno_list): + image_list = [] + + for im_id, a in enumerate(anno_list): + mask = self._get_mask_from_mat(a) + for instance_id in range(1, mask.max().item() + 1): + image_list.append((im_id, instance_id)) + + return image_list + + def get_name(self): + return 'sbd' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + image_id, instance_id = self.image_list[im_id] + anno_mat = loadmat(self.anno_file_list[image_id]) + mask = self._get_mask_from_mat(anno_mat) + + mask = (mask == instance_id).float() + bbox = masks_to_bboxes(mask, fmt='t') + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_image(self, im_id): + image_id, _ = self.image_list[im_id] + + img = self.image_loader(self.image_path_list[image_id]) + return img + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_image(self, image_id, anno=None): + image = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return image, anno, object_meta diff --git a/Stark/external/AR/ltr/dataset/synthetic_video.py b/Stark/external/AR/ltr/dataset/synthetic_video.py new file mode 100755 index 0000000..8dbfa04 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/synthetic_video.py @@ -0,0 +1,82 @@ +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class SyntheticVideo(BaseVideoDataset): + """ + Create a synthetic video dataset from an image dataset by applying a random transformation to images. + """ + def __init__(self, base_image_dataset, transform=None): + """ + args: + base_image_dataset - Image dataset used for generating synthetic videos + transform - Set of transforms to be applied to the images to generate synthetic video. + """ + super().__init__(base_image_dataset.get_name() + '_syn_vid', base_image_dataset.root, + base_image_dataset.image_loader) + self.base_image_dataset = base_image_dataset + self.transform = transform + + def get_name(self): + return self.name + + def is_video_sequence(self): + return False + + def has_class_info(self): + return self.base_image_dataset.has_class_info() + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return self.base_image_dataset.get_num_images() + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.get_images_in_class[class_name] + + def get_sequence_info(self, seq_id): + image_info = self.base_image_dataset.get_image_info(seq_id) + + image_info = {k: v.unsqueeze(0) for k, v in image_info.items()} + return image_info + + def get_class_name(self, seq_id): + return self.base_image_dataset.get_class_name(seq_id) + + def get_frames(self, seq_id, frame_ids, anno=None): + frame, anno, object_meta = self.base_image_dataset.get_image(seq_id, anno=anno) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0].clone() for f_id in frame_ids] + + if self.transform is not None: + if 'mask' in anno_frames.keys(): + frame_list, anno_frames['bbox'], anno_frames['mask'] = self.transform(image=frame_list, + bbox=anno_frames['bbox'], + mask=anno_frames['mask'], + joint=False) + + anno_frames['bbox'] = [masks_to_bboxes(m, fmt='t') for m in anno_frames['mask']] + else: + frame_list, anno_frames['bbox'] = self.transform(image=frame_list, + bbox=anno_frames['bbox'], + joint=False) + + object_meta = OrderedDict({'object_class_name': self.get_class_name(seq_id), + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/external/AR/ltr/dataset/synthetic_video_blend.py b/Stark/external/AR/ltr/dataset/synthetic_video_blend.py new file mode 100755 index 0000000..96404a2 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/synthetic_video_blend.py @@ -0,0 +1,162 @@ +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.bounding_box_utils import masks_to_bboxes +import random +import torch + + +class SyntheticVideoBlend(BaseVideoDataset): + """ + Create a synthetic video by applying random transformations to an object (foreground) and pasting it in a + background image. Currently, the foreground object is pasted at random locations in different frames. + """ + def __init__(self, foreground_image_dataset, background_image_dataset, foreground_transform=None, + background_transform=None): + """ + args: + foreground_image_dataset - A segmentation dataset from which foreground objects are cropped using the + segmentation mask + background_image_dataset - Dataset used to sample background image for the synthetic video + foreground_transform - Random transformations to be applied to the foreground object in every frame + background_transform - Random transformations to be applied to the background image in every frame + """ + assert foreground_image_dataset.has_segmentation_info() + + super().__init__(foreground_image_dataset.get_name() + '_syn_vid_blend', foreground_image_dataset.root, + foreground_image_dataset.image_loader) + self.foreground_image_dataset = foreground_image_dataset + self.background_image_dataset = background_image_dataset + + self.foreground_transform = foreground_transform + self.background_transform = background_transform + + def get_name(self): + return self.name + + def is_video_sequence(self): + return False + + def has_class_info(self): + return self.foreground_image_dataset.has_class_info() + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return self.foreground_image_dataset.get_num_images() + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.get_images_in_class[class_name] + + def get_sequence_info(self, seq_id): + image_info = self.foreground_image_dataset.get_image_info(seq_id) + + image_info = {k: v.unsqueeze(0) for k, v in image_info.items()} + return image_info + + def get_class_name(self, seq_id): + return self.foreground_image_dataset.get_class_name(seq_id) + + def _paste_target(self, fg_image, fg_box, fg_mask, bg_image, paste_loc): + fg_mask = fg_mask.view(fg_mask.shape[0], fg_mask.shape[1], 1) + fg_box = fg_box.long().tolist() + + x1 = int(paste_loc[0] - 0.5 * fg_box[2]) + x2 = x1 + fg_box[2] + + y1 = int(paste_loc[1] - 0.5 * fg_box[3]) + y2 = y1 + fg_box[3] + + x1_pad = max(-x1, 0) + y1_pad = max(-y1, 0) + + x2_pad = max(x2 - bg_image.shape[1], 0) + y2_pad = max(y2 - bg_image.shape[0], 0) + + bg_mask = torch.zeros((bg_image.shape[0], bg_image.shape[1], 1), dtype=fg_mask.dtype, + device=fg_mask.device) + + if x1_pad >= fg_mask.shape[1] or x2_pad >= fg_mask.shape[1] or y1_pad >= fg_mask.shape[0] or y2_pad >= \ + fg_mask.shape[0]: + return bg_image, bg_mask.squeeze(-1) + + fg_mask_patch = fg_mask[fg_box[1] + y1_pad:fg_box[1] + fg_box[3] - y2_pad, + fg_box[0] + x1_pad:fg_box[0] + fg_box[2] - x2_pad, :] + + fg_image_patch = fg_image[fg_box[1] + y1_pad:fg_box[1] + fg_box[3] - y2_pad, + fg_box[0] + x1_pad:fg_box[0] + fg_box[2] - x2_pad, :] + + bg_image[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] = \ + bg_image[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] * (1 - fg_mask_patch.numpy()) \ + + fg_mask_patch.numpy() * fg_image_patch + + bg_mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] = fg_mask_patch + + return bg_image, bg_mask.squeeze(-1) + + def get_frames(self, seq_id, frame_ids, anno=None): + # Handle foreground + fg_frame, fg_anno, fg_object_meta = self.foreground_image_dataset.get_image(seq_id, anno=anno) + + fg_frame_list = [fg_frame.copy() for _ in frame_ids] + + fg_anno_frames = {} + for key, value in fg_anno.items(): + fg_anno_frames[key] = [value[0].clone() for f_id in frame_ids] + + if self.foreground_transform is not None: + fg_frame_list, fg_anno_frames['bbox'], fg_anno_frames['mask'] = self.foreground_transform( + image=fg_frame_list, + bbox=fg_anno_frames['bbox'], + mask=fg_anno_frames['mask'], + joint=False) + + # Sample a random background + bg_seq_id = random.randint(0, self.background_image_dataset.get_num_images() - 1) + + bg_frame, bg_anno, _ = self.background_image_dataset.get_image(bg_seq_id) + + bg_frame_list = [bg_frame.copy() for _ in frame_ids] + + bg_anno_frames = {} + for key, value in bg_anno.items(): + # Note: Since we get bg anno from image dataset, it does not has frame dimension + bg_anno_frames[key] = [value.clone() for f_id in frame_ids] + + if self.background_transform is not None: + if 'mask' in bg_anno_frames.keys(): + bg_frame_list, bg_anno_frames['bbox'], bg_anno_frames['mask'] = self.background_transform( + image=bg_frame_list, + bbox=bg_anno_frames['bbox'], + mask=bg_anno_frames['mask'], + joint=False) + else: + bg_frame_list, bg_anno_frames['bbox'] = self.background_transform( + image=bg_frame_list, + bbox=bg_anno_frames['bbox'], + joint=False) + + for i in range(len(frame_ids)): + # To be safe, get target bb for the mask + bbox = masks_to_bboxes(fg_anno_frames['mask'][i], fmt='t') + + loc_y = random.randint(0, bg_frame_list[i].shape[0] - 1) + loc_x = random.randint(0, bg_frame_list[i].shape[1] - 1) + + paste_loc = (loc_x, loc_y) + fg_frame_list[i], fg_anno_frames['mask'][i] = self._paste_target(fg_frame_list[i], bbox, + fg_anno_frames['mask'][i], + bg_frame_list[i], paste_loc) + + fg_anno_frames['bbox'][i] = masks_to_bboxes(fg_anno_frames['mask'][i], fmt='t') + + object_meta = OrderedDict({'object_class_name': self.get_class_name(seq_id), + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return fg_frame_list, fg_anno_frames, object_meta diff --git a/Stark/external/AR/ltr/dataset/tracking_net.py b/Stark/external/AR/ltr/dataset/tracking_net.py new file mode 100755 index 0000000..2862adf --- /dev/null +++ b/Stark/external/AR/ltr/dataset/tracking_net.py @@ -0,0 +1,151 @@ +import torch +import os +import os.path +import numpy as np +import pandas +import random +from collections import OrderedDict + +from ltr.data.image_loader import jpeg4py_loader +from .base_video_dataset import BaseVideoDataset +from ltr.admin.environment import env_settings + + +def list_sequences(root, set_ids): + """ Lists all the videos in the input set_ids. Returns a list of tuples (set_id, video_name) + + args: + root: Root directory to TrackingNet + set_ids: Sets (0-11) which are to be used + + returns: + list - list of tuples (set_id, video_name) containing the set_id and video_name for each sequence + """ + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, "TRAIN_" + str(s), "anno") + + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + sequence_list += sequences_cur_set + + return sequence_list + + +class TrackingNet(BaseVideoDataset): + """ TrackingNet dataset. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, set_ids=None, data_fraction=None): + """ + args: + root - The path to the TrackingNet folder, containing the training sets. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + set_ids (None) - List containing the ids of the TrackingNet sets to be used for training. If None, all the + sets (0 - 11) will be used. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().trackingnet_dir if root is None else root + super().__init__('TrackingNet', root, image_loader) + + if set_ids is None: + set_ids = [i for i in range(12)] + + self.set_ids = set_ids + + # Keep a list of all videos. Sequence list is a list of tuples (set_id, video_name) containing the set_id and + # video_name for each sequence + self.sequence_list = list_sequences(self.root, self.set_ids) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list) * data_fraction)) + + self.seq_to_class_map, self.seq_per_class = self._load_class_info() + + # we do not have the class_lists for the tracking net + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def _load_class_info(self): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + class_map_path = os.path.join(ltr_path, 'data_specs', 'trackingnet_classmap.txt') + + with open(class_map_path, 'r') as f: + seq_to_class_map = {seq_class.split('\t')[0]: seq_class.rstrip().split('\t')[1] for seq_class in f} + + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = seq_to_class_map[seq[1]] + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_to_class_map, seq_per_class + + def get_name(self): + return 'trackingnet' + + def has_class_info(self): + return True + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + bb_anno_file = os.path.join(self.root, "TRAIN_" + str(set_id), "anno", vid_name + ".txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, + low_memory=False).values + return torch.tensor(gt) + + def get_sequence_info(self, seq_id): + bbox = self._read_bb_anno(seq_id) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame(self, seq_id, frame_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + frame_path = os.path.join(self.root, "TRAIN_" + str(set_id), "frames", vid_name, str(frame_id) + ".jpg") + return self.image_loader(frame_path) + + def _get_class(self, seq_id): + seq_name = self.sequence_list[seq_id][1] + return self.seq_to_class_map[seq_name] + + def get_class_name(self, seq_id): + obj_class = self._get_class(seq_id) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + frame_list = [self._get_frame(seq_id, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + obj_class = self._get_class(seq_id) + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/external/AR/ltr/dataset/vos_base.py b/Stark/external/AR/ltr/dataset/vos_base.py new file mode 100755 index 0000000..50a4fbe --- /dev/null +++ b/Stark/external/AR/ltr/dataset/vos_base.py @@ -0,0 +1,398 @@ +import torch +from pathlib import Path +from collections import OrderedDict, defaultdict +import json +import numpy as np +import os + +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader, imread_indexed +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class VOSMeta: + def __init__(self, data=None, filename=None): + if filename is not None: + self.load(filename) + elif data is not None: + self._data = data + else: + raise ValueError("Must set either data or filename parameter") + + def save(self, gen_meta: Path): + gen_meta.parent.mkdir(exist_ok=True, parents=True) + json.dump(self._data, open(gen_meta, "w")) + + def load(self, gen_meta: Path): + if not gen_meta.exists(): + print("Generated metadata file %s is not found." % gen_meta) + print("Find and run VOSMeta.generate() to create it.") + raise FileNotFoundError(gen_meta) + self._data = json.load(open(gen_meta), object_pairs_hook=OrderedDict) + + @classmethod + def generate(cls, dset_name: str, dset_images_path: Path, dset_annos_path: Path): + """ + Count the annotation mask pixels per object, per frame, in all sequences in a dataset + :param dset_name: Dataset name, for printing the progress bar. + :param dset_annos_path: Path to annotations directory, containing sequence directories, + with annotation frames in them. + + :return: Dataset meta dict: + + {'sequence0': + { + 'shape': (height, width) + + 'obj_sizes': # Object pixels per frame + {'frame0': {'object0': px_count, 'object1': px_count, ...}, + 'frame1': {'object0': px_count, 'object1': px_count, ...}, + ... }, + + 'bboxes': # Bounding boxes per frame + {'frame0': {'object0': bbox, 'object1': bbox, ...}, + 'frame1': {'object0': bbox, 'object1': bbox, ...}, + ... }, + ... + } + """ + assert(dset_annos_path.exists()) + + dset_meta = OrderedDict() + sequences = [p.stem for p in sorted(dset_annos_path.glob("*")) if p.is_dir()] + + try: + from tqdm import tqdm + except: + def tqdm(x, *args, **kwargs): + return x + + for seq in tqdm(sequences, desc=dset_name, unit="seq"): + + obj_sizes2 = defaultdict(OrderedDict) + bboxes = defaultdict(OrderedDict) + shape = None + frame_names = [file.stem for file in sorted((dset_images_path / seq).glob("*.jpg"))] + anno_paths = list(sorted((dset_annos_path / seq).glob("*.png"))) + + # Extract information from the given label frames + for path in anno_paths: + f_id = path.stem + + # Count label-pixels per frame + labels = imread_indexed(path) + # labels = np.array(Image.open(path)) + obj_ids, obj_sizes = np.unique(labels, return_counts=True) + obj_ids = [str(oid) for oid in obj_ids] + obj_sizes = obj_sizes.tolist() + + if '0' in obj_ids: # Remove background id + obj_ids = obj_ids[1:] + obj_sizes = obj_sizes[1:] + obj_sizes2[f_id] = OrderedDict(zip(obj_ids, obj_sizes)) + + # Generate per-label bounding boxes + for obj_id in obj_ids: + bboxes[f_id][obj_id] = cls._mask_to_bbox(labels == int(obj_id)) + + if shape is None: + shape = labels.shape[:2] + + # Format result + + dset_meta[seq] = dict(shape=shape, obj_sizes=obj_sizes2, bboxes=bboxes, frame_names=frame_names) + + return VOSMeta(dset_meta) + + @staticmethod + def _mask_to_bbox(mask: np.ndarray): + + mask = mask.astype(int) + xs = mask.sum(axis=-2).nonzero()[0].tolist() + ys = mask.sum(axis=-1).nonzero()[0].tolist() + + if len(ys) > 0 and len(xs) > 0: + x, y, w, h = xs[0], ys[0], xs[-1] - xs[0], ys[-1] - ys[0] + else: + x, y, w, h = 0, 0, 0, 0 + + return [x, y, w, h] + + @staticmethod + def _transpose_nested_dict(d): + """ Permute a 2-level nested dict such that the inner and outer keys swap places. """ + d2 = defaultdict(OrderedDict) + for key1, inner in d.items(): + for key2, value in inner.items(): + d2[key2][key1] = value + return d2 + + def select_split(self, dataset_name, split): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + sequences = set([s.strip() for s in open(os.path.join(ltr_path, 'data_specs', dataset_name + '_' + split + '.txt')).readlines()]) + all_sequences = set(self._data.keys()) + to_remove = all_sequences.difference(sequences) + for seq_name in to_remove: + self._data.pop(seq_name) + + def get_sequence_names(self): + return list(self._data.keys()) + + def get_shape(self, seq_name): + """ Sequence image shape (h,w) """ + h, w = self._data[seq_name]['shape'] + return h, w + + def get_obj_ids(self, seq_name): + """ All objects in the sequence """ + return list(self.get_obj_sizes_per_object(seq_name).keys()) + + def get_frame_names(self, seq_name): + """ All filename stems of the frames in the sequence """ + return self._data[seq_name]['frame_names'] + + def enable_all_frames(self, dset_images_path): + """ For YouTubeVOS: Update the frame names with (jpeg) files from the _all_frames set + :param dset_images_path: /path/to/train_all_frames/JPEGImages (or valid or test) + :param seq: Sequence name + :return: + """ + + # Try load the cached index + idx_file = dset_images_path.parent / "frame_names.json" + if idx_file.exists(): + print('Loading cached frame names from %s' % idx_file) + all_frame_names = json.load(open(idx_file)) + else: + # Cache the data to the user's home directory (guaranteed to be writable) + all_frame_names = dict() + user_idx_file = Path.home() / (dset_images_path.parent.stem + "_frame_names.json") + print('Indexing YouTubeVOS "all_frames" frame names to %s' % user_idx_file) + for seq in self._data: + all_frame_names[seq] = [file.stem for file in sorted((dset_images_path / seq).glob("*.jpg"))] + json.dump(all_frame_names, open(user_idx_file, "w")) + print('Done. Move %s to %s to load faster next time.' % (user_idx_file, idx_file)) + + for seq, frame_names in all_frame_names.items(): + self._data[seq]['frame_names'] = frame_names + + def get_aspect_ratio(self, seq_name): + """ Sequence aspect ratio """ + h, w = self._data[seq_name]['shape'] + return w / h + + def get_obj_sizes_per_frame(self, seq_name): + """ Get object pixel counts, grouped by frame names """ + return self._data[seq_name]['obj_sizes'] + + def get_bboxes_per_frame(self, seq_name): + """ Object bounding boxes, grouped by frame names """ + return self._data[seq_name]['bboxes'] + + def get_obj_sizes_per_object(self, seq_name): + """ Object pixel counts, grouped by object """ + return self._transpose_nested_dict(self.get_obj_sizes_per_frame(seq_name)) + + def get_bboxes_per_object(self, seq_name): + """ Object bounding boxes, grouped by object """ + return self._transpose_nested_dict(self.get_bboxes_per_frame(seq_name)) + + @staticmethod + def generate_datasets_meta(src, dst=Path("~/vosdataset_meta").expanduser()): + VOSMeta.generate("SyntheticCoco", src / "JPEGImages", src / "Annotations").save(src / "generated_meta.json") + + +class VOSDatasetBase(BaseVideoDataset): + + """ Generic VOS dataset reader base class, for both DAVIS and YouTubeVOS """ + + def __init__(self, name: str, root: Path, version=None, split='train', + multiobj=True, vis_threshold=10, image_loader=jpeg4py_loader): + """ + :param root: Dataset root path, eg /path/to/DAVIS or /path/to/YouTubeVOS/ + Note: YouTubeVOS 2018 and 2019 are expected to be in + /path/to/YouTubeVOS/2018 and /path/to/YouTubeVOS/2019, respectively + :param name: 'DAVIS' or 'YouTubeVOS' (case sensitive) + :param version: DAVIS: '2016', '2017, YouTubeVOS: '2018' or '2019' + :param split: DAVIS: Any name in DAVIS/ImageSets/, + YouTubeVOS: 'test', 'train', 'valid' or 'jjtrain', 'jjvalid' + :param multiobj: Whether the dataset will return all objects in a sequence or + multiple sequences with one object in each. + :param vis_threshold: Minimum number of pixels required to consider a target object "visible". + :param image_loader: Image loader. + """ + + assert root.exists() and root.is_dir() + + super().__init__(name, root, image_loader) + + self.version = version + self.split = split + self.vis_threshold = vis_threshold + self.multiobj = multiobj + + def _load_image(self, path): + im = self.image_loader(str(path)) + assert im is not None + im = np.atleast_3d(im) + return im + + @staticmethod + def _load_anno(path): + if not path.exists(): + return None + # im = np.atleast_3d(np.array(Image.open(path))) + im = imread_indexed(path) + return im + + def get_num_sequences(self): + return len(self._samples) + + def get_sequence_info(self, sample_id): + """ Get sample meta data. + :param sample_id: Sample to query. + :return: dict of metadata: + sequence: Sequence name + frame_shape: (height, width) of the images + frame_names: List of frame filename stems in the sequence + object_ids: Id numbers of all objects occurring in the sequence + obj_sizes: Matrix shape=(frames, object) of the number of pixels for each object in each frame + Coordinates in this matrix relate to the frame_names and object_ids + visible: Boolean matrix of the same shape as obj_sizes. Entries with more pixels + than self.visible_threshold are True. + """ + m = self.gmeta + seq_name, obj_ids = self._samples[sample_id] + f_names = m.get_frame_names(seq_name) # All frames + + f2i = {f: i for i, f in enumerate(f_names)} # Frame name to matrix index + o2i = {o: i for i, o in enumerate(obj_ids)} # Object id to matrix index + + # Get a matrix of object sizes: shape=(frames, objects) + obj_sizes = torch.zeros((len(f_names), len(obj_ids)), dtype=torch.int) + sizes_per_object = m.get_obj_sizes_per_object(seq_name) + + for obj_id in obj_ids: + frames = sizes_per_object[obj_id] + oid = o2i[obj_id] + for f, sz in frames.items(): + obj_sizes[f2i[f], oid] = sz + + visible = (obj_sizes > self.vis_threshold).byte() + + return dict(sequence=seq_name, frame_shape=m.get_shape(seq_name), frame_names=f_names, object_ids=obj_ids, + object_sizes=obj_sizes, visible=visible, valid=visible) + + def get_paths_and_bboxes(self, sequence_info): + + seq_name = sequence_info['sequence'] + annos_root = self._anno_path / seq_name + images_root = self._jpeg_path / seq_name + + frame_names = sequence_info['frame_names'] + f2i = {f: i for i, f in enumerate(frame_names)} + + images = [str(images_root / (f + ".jpg")) for f in frame_names] + + # Find the frames where ground truth is available and + # get the bounding boxes and segmentation labels of those frames + all_bboxes = self.gmeta.get_bboxes_per_frame(seq_name) + gt_labels = [str(annos_root / (f + ".png")) if f in all_bboxes.keys() else None for f in frame_names] + + gt_bboxes = OrderedDict() + for obj_id in sequence_info['object_ids']: + gt_bboxes[obj_id] = np.array([all_bboxes.get(frame, {}).get(obj_id, [-1, -1, -1, -1]) for frame in frame_names]) + + return images, gt_labels, gt_bboxes + + def _construct_sequence(self, sequence_info): + raise NotImplementedError + + def get_sequence_list(self): + if len(self.sequence_list) > 0: + return self.sequence_list + self.sequence_list = [self._construct_sequence(self.get_sequence_info(i)) for i in range(len(self._samples))] + return self.sequence_list + + def __len__(self): + return len(self._samples) + + def _get_image_path(self, meta, frame_id): + return self._jpeg_path / meta['sequence'] / (meta['frame_names'][frame_id] + ".jpg") + + def _get_anno_path(self, meta, frame_id): + return self._anno_path / meta['sequence'] / (meta['frame_names'][frame_id] + ".png") + + def get_frames(self, sample_id, frame_ids, anno=None): + """ Fetch frames with the given ids. + :param sample_id: Sample to get. + :param frame_ids: List of frame indices in the sequence belonging to the sample_id + :return: dict of metadata and data: + sequence: Sequence name + images: List of images. No entries may be None + labels: List of label/mask images. Entries may be None if the data is missing + bboxes: List of bounding boxes. Entries may be None if the data is missing + """ + seq_name, obj_ids = self._samples[sample_id] + + meta = self.get_sequence_info(sample_id) if anno is None else anno + frame_names = meta['frame_names'] + images = [self._load_image(self._jpeg_path / seq_name / (frame_names[f] + ".jpg")) for f in frame_ids] + labels = [self._load_anno(self._anno_path / seq_name / (frame_names[f] + ".png")) for f in frame_ids] + + # Generate bounding boxes for the requested objects + bboxes = [] + for lb in labels: + lb = torch.from_numpy(lb.squeeze()) + frame_bbs = {} + for obj_id in obj_ids: + bbox = masks_to_bboxes(lb == int(obj_id), fmt='t') + if bbox[3] == 0 or bbox[2] == 0: + print("!") + frame_bbs[obj_id] = bbox + bboxes.append(frame_bbs) + + # Insert empty bboxes for missing object ids + for bbox in bboxes: + for obj_id in obj_ids: + if obj_id not in bbox: + bbox[obj_id] = torch.zeros(4, dtype=torch.float32) + + # Remap to object id 1, if requested - for training + if not self.multiobj: + assert len(obj_ids) == 1 + obj_id = obj_ids[0] + labels = [torch.Tensor(lb == int(obj_id)) for lb in labels] + bboxes = [bbox[obj_id] for bbox in bboxes] + else: + labels = [torch.Tensor(lb) for lb in labels] + + object_meta = {key: meta[key] for key in ['sequence', 'frame_shape', 'frame_names', 'object_ids']} + + anno_frames = dict(bbox=bboxes, mask=labels) + for key in ['object_sizes', 'visible', 'valid']: + value = meta[key] + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return images, anno_frames, object_meta + + def get_name(self): + return "%s/%s/%s" % (self.name, self.version, self.split) + + def has_class_info(self): + return False + + def has_occlusion_info(self): + return True + + def get_num_classes(self): + return 0 + + def get_class_list(self): + return [] + + def get_sequences_in_class(self, class_name): + raise [] + + def has_segmentation_info(self): + return True diff --git a/Stark/external/AR/ltr/dataset/youtubevos.py b/Stark/external/AR/ltr/dataset/youtubevos.py new file mode 100755 index 0000000..dd3b3c4 --- /dev/null +++ b/Stark/external/AR/ltr/dataset/youtubevos.py @@ -0,0 +1,192 @@ +from pathlib import Path +import os +from ltr.dataset.vos_base import VOSDatasetBase, VOSMeta +from pytracking.evaluation import Sequence +import json +from ltr.admin.environment import env_settings +from ltr.data.image_loader import jpeg4py_loader + + +class YouTubeVOSMeta: + """ Thin wrapper for YouTubeVOS meta data + meta.json + { + "videos": { + "": { + "objects": { + "": { + "category": "", + "frames": [ + "", + "", + ] + } + } + } + } + } + # is the same as the pixel values of object in annotated segmentation PNG files. + # is the 5-digit index of frame in video, and not necessary to start from 0. + """ + + def __init__(self, dset_split_path): + self._data = json.load(open(dset_split_path / 'meta.json'))['videos'] + + def sequences(self): + return list(self._data.keys()) + + def seq_frames(self, seq_name): + """ All filename stems of the frames in the sequence """ + frames = set() + for obj_id in self.object_ids(seq_name): + for f in self.object_frames(seq_name, obj_id): + frames.add(f) + return list(sorted(frames)) + + def object_ids(self, seq_name): + """ All objects in the sequence """ + return list(self._data[seq_name]['objects'].keys()) + + def object_category(self, seq_name, obj_id): + return self._data[seq_name]['objects'][str(obj_id)]['category'] + + def object_frames(self, seq_name, obj_id): + return self._data[seq_name]['objects'][str(obj_id)]['frames'] + + def object_first_frame(self, seq_name, obj_id): + return self.object_frames(seq_name, obj_id)[0] + + +class YouTubeVOS(VOSDatasetBase): + """ + YoutubeVOS video object segmentation dataset. + + Publication: + YouTube-VOS: A Large-Scale Video Object Segmentation Benchmark + Ning Xu, Linjie Yang, Yuchen Fan, Dingcheng Yue, Yuchen Liang, Jianchao Yang, and Thomas Huang + ECCV, 2018 + https://arxiv.org/pdf/1809.03327.pdf + + Download dataset from: https://youtube-vos.org/dataset/ + """ + def __init__(self, root=None, version='2019', split='train', cleanup=None, all_frames=False, sequences=None, + multiobj=True, vis_threshold=10, image_loader=jpeg4py_loader): + """ + args: + root - Dataset root path. If unset, it uses the path in your local.py config. + version - '2018' or '2019' + split - 'test', 'train', 'valid', or 'jjtrain', 'jjvalid'. 'jjvalid' corresponds to a custom validation + dataset consisting of 300 videos randomly sampled from the train set. 'jjtrain' contains the + remaining videos used for training. + cleanup - List of actions to take to to clean up known problems in the dataset. + 'aspects': remove frames with weird aspect ratios, + 'starts': fix up start frames from original meta data + all_frames - Whether to use an "all_frames" split. + sequences - List of sequence names. Limit to a subset of sequences if not None. + multiobj - Whether the dataset will return all objects in a sequence or multiple sequences with one + object in each. + vis_threshold - Minimum number of pixels required to consider a target object "visible". + image_loader - Image loader. + """ + root = env_settings().youtubevos_dir if root is None else root + super().__init__(name="YouTubeVOS", root=Path(root), version=version, split=split, multiobj=multiobj, + vis_threshold=vis_threshold, image_loader=image_loader) + + split_folder = self.split + if self.split.startswith("jj"): + split_folder = "train" + + dset_path = self.root / self.version / split_folder + + self._anno_path = dset_path / 'Annotations' + + if all_frames: + self._jpeg_path = self.root / self.version / (split_folder + "_all_frames") / 'JPEGImages' + else: + self._jpeg_path = dset_path / 'JPEGImages' + + self.meta = YouTubeVOSMeta(dset_path) + meta_path = dset_path / "generated_meta.json" + if meta_path.exists(): + self.gmeta = VOSMeta(filename=meta_path) + else: + self.gmeta = VOSMeta.generate('YouTubeVOS', self._jpeg_path, self._anno_path) + self.gmeta.save(meta_path) + + if all_frames: + self.gmeta.enable_all_frames(self._jpeg_path) + + if self.split not in ['train', 'valid', 'test']: + self.gmeta.select_split('youtubevos', self.split) + + if sequences is None: + sequences = self.gmeta.get_sequence_names() + + to_remove = set() + cleanup = {} if cleanup is None else set(cleanup) + + if 'aspect' in cleanup: + # Remove sequences with unusual aspect ratios + for seq_name in sequences: + a = self.gmeta.get_aspect_ratio(seq_name) + if a < 1.45 or a > 1.9: + to_remove.add(seq_name) + + if 'starts' in cleanup: + # Fix incorrect start frames for some objects found with ytvos_start_frames_test() + bad_start_frames = [("0e27472bea", '2', ['00055', '00060'], '00065'), + ("5937b08d69", '4', ['00000'], '00005'), + ("5e1ce354fd", '5', ['00010', '00015'], '00020'), + ("7053e4f41e", '2', ['00000', '00005', '00010', '00015'], '00020'), + ("720e3fa04c", '2', ['00050'], '00055'), + ("c73c8e747f", '2', ['00035'], '00040')] + for seq_name, obj_id, bad_frames, good_frame in bad_start_frames: + # bad_frames is from meta.json included with the dataset + # good_frame is from the generated meta - and the first actual frame where the object was seen. + if seq_name in self.meta._data: + frames = self.meta.object_frames(seq_name, obj_id) + for f in bad_frames: + frames.remove(f) + assert frames[0] == good_frame + + sequences = [seq for seq in sequences if seq not in to_remove] + + self.sequence_names = sequences + self._samples = [] + + for seq in sequences: + obj_ids = self.meta.object_ids(seq) + if self.multiobj: # Multiple objects per sample + self._samples.append((seq, obj_ids)) + else: # One object per sample + self._samples.extend([(seq, [obj_id]) for obj_id in obj_ids]) + + print("%s loaded." % self.get_name()) + if len(to_remove) > 0: + print(" %d sequences were removed, (%d remaining)." % (len(to_remove), len(sequences))) + + def _construct_sequence(self, sequence_info): + + seq_name = sequence_info['sequence'] + frame_names = sequence_info['frame_names'] + fname_to_fid = {f: i for i, f in enumerate(frame_names)} + images, gt_segs, gt_bboxes = self.get_paths_and_bboxes(sequence_info) + + init_data = dict() + for obj_id in sequence_info['object_ids']: + if obj_id == '0': + print("!") + f_name = self.meta.object_first_frame(seq_name, obj_id) + f_id = fname_to_fid[f_name] + if f_id not in init_data: + init_data[f_id] = {'object_ids': [obj_id], + 'bbox': {obj_id: gt_bboxes[obj_id][f_id,:]}, + 'mask': os.path.join(os.path.dirname(gt_segs[f_id]), (f_name + ".png"))} + assert init_data[f_id]['mask'] in gt_segs # If this fails, some file is missing + else: + init_data[f_id]['object_ids'].append(obj_id) + init_data[f_id]['bbox'][obj_id] = gt_bboxes[obj_id][f_id,:] + + return Sequence(name=seq_name, frames=images, dataset='YouTubeVOS', ground_truth_rect=gt_bboxes, + init_data=init_data, ground_truth_seg=gt_segs, object_ids=sequence_info['object_ids'], + multiobj_mode=self.multiobj) diff --git a/Stark/external/AR/ltr/models/AR_seg_mask/AR_seg_mask.py b/Stark/external/AR/ltr/models/AR_seg_mask/AR_seg_mask.py new file mode 100755 index 0000000..4681958 --- /dev/null +++ b/Stark/external/AR/ltr/models/AR_seg_mask/AR_seg_mask.py @@ -0,0 +1,119 @@ +import torch.nn as nn +from ltr.models.neck import CorrNL +from ltr import model_constructor +import torch +import ltr.models.backbone.resnet_seg as resnet_seg + +from ltr.models.head import seg_network +from easydict import EasyDict as edict + +'''2020.4.14 replace mask head with frtm for higher-quality mask''' +'''2020.4.22 Only use the mask branch''' + + +class ARnet_seg_mask(nn.Module): + """ Scale Estimation network module with three branches: bbox, coner and mask. """ + def __init__(self, feature_extractor, neck_module, head_module, used_layers, + extractor_grad=True,output_size=(256,256)): + """ + args: + feature_extractor - backbone feature extractor + bb_regressor - IoU prediction module + bb_regressor_layer - List containing the name of the layers from feature_extractor, which are input to + bb_regressor + extractor_grad - Bool indicating whether backbone feature extractor requires gradients + """ + super(ARnet_seg_mask, self).__init__() + + self.feature_extractor = feature_extractor + self.neck = neck_module + self.refiner = head_module + self.used_layers = used_layers + self.output_size = output_size + + if not extractor_grad: + for p in self.feature_extractor.parameters(): + p.requires_grad_(False) + + def forward(self, train_imgs, test_imgs, train_bb, mode='train'): + """ Forward pass + Note: If the training is done in sequence mode, that is, test_imgs.dim() == 5, then the batch dimension + corresponds to the first dimensions. test_imgs is thus of the form [sequence, batch, feature, row, col] + """ + self.forward_ref(train_imgs, train_bb) + pred_dict = self.forward_test(test_imgs, mode) + return pred_dict + + def forward_ref(self, train_imgs, train_bb): + """ Forward pass of reference branch. + size of train_imgs is (1,batch,3,H,W), train_bb is (1,batch,4)""" + num_sequences = train_imgs.shape[-4] # batch + num_train_images = train_imgs.shape[0] if train_imgs.dim() == 5 else 1 # 1 + + # Extract backbone features + '''train_feat OrderedDict, key:'layer4' ''' + train_feat_dict = self.extract_backbone_features(train_imgs.view(-1, *train_imgs.shape[-3:])) # 输入size是(batch,3,256,256) + + train_feat_list = [feat for feat in train_feat_dict.values()] #list,其中每个元素对应一层输出的特征(tensor) + + # get reference feature + self.neck.get_ref_kernel(train_feat_list, train_bb.view(num_train_images, num_sequences, 4)) + + + def forward_test(self, test_imgs, mode='train'): + """ Forward pass of test branch. size of test_imgs is (1,batch,3,256,256)""" + output = {} + # Extract backbone features + test_feat_dict = self.extract_backbone_features(test_imgs.view(-1, *test_imgs.shape[-3:]), + layers=['layer1','layer2','layer3','layer4','layer5'])# 输入size是(batch,3,256,256) + '''list,tensor''' + # Save low-level feature list + # Lfeat_list = [feat for name, feat in test_feat_dict.items() if name != 'layer3'] + + # fuse feature from two branches + fusion_feat = self.neck.fuse_feat([test_feat_dict['layer4']]) + # Obtain bbox prediction + if mode=='train': + output['mask'] = torch.sigmoid(self.refiner(fusion_feat, test_feat_dict, self.output_size)) + elif mode == 'mask': + output = torch.sigmoid(self.refiner(fusion_feat, test_feat_dict, self.output_size)) + else: + raise ValueError("mode should be train or test") + return output + + def extract_backbone_features(self, im, layers=None): + if layers is None: + layers = self.used_layers + return self.feature_extractor(im, layers) + + def extract_features(self, im, layers): + return self.feature_extractor(im, layers) + + + +@model_constructor +def ARnet_seg_mask_resnet50(backbone_pretrained=True,used_layers=('layer4',),pool_size=None): + # backbone + backbone_net = resnet_seg.resnet50(pretrained=backbone_pretrained) + # neck + neck_net = CorrNL.CorrNL(pool_size=pool_size) + # multiple heads + '''create segnet''' + in_channels = 1024 + # disc_params = edict(layer="layer4", in_channels=in_channels, c_channels=96, out_channels=64) # non-local feat (64 channels rather than 1) + '''2020.4.22 change "out_channels" to pool_size * pool_size''' + disc_params = edict(layer="layer4", in_channels=in_channels, c_channels=96, out_channels=pool_size*pool_size) # non-local feat (64 channels rather than 1) + refnet_params = edict( + layers=("layer5", "layer4", "layer3", "layer2"), + nchannels=64, use_batch_norm=True) + disc_params.in_channels = backbone_net.get_out_channels()[disc_params.layer] + + p = refnet_params + refinement_layers_channels = {L: nch for L, nch in backbone_net.get_out_channels().items() if L in p.layers} + refiner = seg_network.SegNetwork(disc_params.out_channels, p.nchannels, refinement_layers_channels, p.use_batch_norm) + '''create Alpha-Refine''' + net = ARnet_seg_mask(feature_extractor=backbone_net, neck_module=neck_net, + head_module=refiner, + used_layers=used_layers, extractor_grad=True, + output_size=(int(pool_size*2*16),int(pool_size*2*16))) + return net diff --git a/Stark/external/AR/ltr/models/AR_seg_mask/__init__.py b/Stark/external/AR/ltr/models/AR_seg_mask/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/__init__.py b/Stark/external/AR/ltr/models/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/backbone/__init__.py b/Stark/external/AR/ltr/models/backbone/__init__.py new file mode 100755 index 0000000..11e398e --- /dev/null +++ b/Stark/external/AR/ltr/models/backbone/__init__.py @@ -0,0 +1,2 @@ +from .resnet import resnet18, resnet50, resnet_baby +from .resnet18_vggm import resnet18_vggmconv1 diff --git a/Stark/external/AR/ltr/models/backbone/base.py b/Stark/external/AR/ltr/models/backbone/base.py new file mode 100755 index 0000000..0964da8 --- /dev/null +++ b/Stark/external/AR/ltr/models/backbone/base.py @@ -0,0 +1,47 @@ +import torch +import torch.nn as nn + + +class Backbone(nn.Module): + """Base class for backbone networks. Handles freezing layers etc. + args: + frozen_layers - Name of layers to freeze. Either list of strings, 'none' or 'all'. Default: 'none'. + """ + def __init__(self, frozen_layers=()): + super().__init__() + + if isinstance(frozen_layers, str): + if frozen_layers.lower() == 'none': + frozen_layers = () + elif frozen_layers.lower() != 'all': + raise ValueError('Unknown option for frozen layers: \"{}\". Should be \"all\", \"none\" or list of layer names.'.format(frozen_layers)) + + self.frozen_layers = frozen_layers + self._is_frozen_nograd = False + + + def train(self, mode=True): + super().train(mode) + if mode == True: + self._set_frozen_to_eval() + if not self._is_frozen_nograd: + self._set_frozen_to_nograd() + self._is_frozen_nograd = True + + + def _set_frozen_to_eval(self): + if isinstance(self.frozen_layers, str) and self.frozen_layers.lower() == 'all': + self.eval() + else: + for layer in self.frozen_layers: + getattr(self, layer).eval() + + + def _set_frozen_to_nograd(self): + if isinstance(self.frozen_layers, str) and self.frozen_layers.lower() == 'all': + for p in self.parameters(): + p.requires_grad_(False) + else: + for layer in self.frozen_layers: + for p in getattr(self, layer).parameters(): + p.requires_grad_(False) \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/backbone/resnet.py b/Stark/external/AR/ltr/models/backbone/resnet.py new file mode 100755 index 0000000..6a1dabc --- /dev/null +++ b/Stark/external/AR/ltr/models/backbone/resnet.py @@ -0,0 +1,274 @@ +import math +import torch.nn as nn +from collections import OrderedDict +import torch.utils.model_zoo as model_zoo +from torchvision.models.resnet import model_urls +from .base import Backbone + + +def conv3x3(in_planes, out_planes, stride=1, dilation=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1, use_bn=True): + super(BasicBlock, self).__init__() + self.use_bn = use_bn + self.conv1 = conv3x3(inplanes, planes, stride, dilation=dilation) + + if use_bn: + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes, dilation=dilation) + + if use_bn: + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + + if self.use_bn: + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + + if self.use_bn: + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(Backbone): + """ ResNet network module. Allows extracting specific feature blocks.""" + def __init__(self, block, layers, output_layers, num_classes=1000, inplanes=64, dilation_factor=1, frozen_layers=()): + self.inplanes = inplanes + super(ResNet, self).__init__(frozen_layers=frozen_layers) + self.output_layers = output_layers + self.conv1 = nn.Conv2d(3, inplanes, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(inplanes) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + stride = [1 + (dilation_factor < l) for l in (8, 4, 2)] + self.layer1 = self._make_layer(block, inplanes, layers[0], dilation=max(dilation_factor//8, 1)) + self.layer2 = self._make_layer(block, inplanes*2, layers[1], stride=stride[0], dilation=max(dilation_factor//4, 1)) + self.layer3 = self._make_layer(block, inplanes*4, layers[2], stride=stride[1], dilation=max(dilation_factor//2, 1)) + self.layer4 = self._make_layer(block, inplanes*8, layers[3], stride=stride[2], dilation=dilation_factor) + + out_feature_strides = {'conv1': 4, 'layer1': 4, 'layer2': 4*stride[0], 'layer3': 4*stride[0]*stride[1], + 'layer4': 4*stride[0]*stride[1]*stride[2]} + + # TODO better way? + if isinstance(self.layer1[0], BasicBlock): + out_feature_channels = {'conv1': inplanes, 'layer1': inplanes, 'layer2': inplanes*2, 'layer3': inplanes*4, + 'layer4': inplanes*8} + elif isinstance(self.layer1[0], Bottleneck): + base_num_channels = 4 * inplanes + out_feature_channels = {'conv1': inplanes, 'layer1': base_num_channels, 'layer2': base_num_channels * 2, + 'layer3': base_num_channels * 4, 'layer4': base_num_channels * 8} + else: + raise Exception('block not supported') + + self._out_feature_strides = out_feature_strides + self._out_feature_channels = out_feature_channels + + # self.avgpool = nn.AvgPool2d(7, stride=1) + self.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.fc = nn.Linear(inplanes*8 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def out_feature_strides(self, layer=None): + if layer is None: + return self._out_feature_strides + else: + return self._out_feature_strides[layer] + + def out_feature_channels(self, layer=None): + if layer is None: + return self._out_feature_channels + else: + return self._out_feature_channels[layer] + + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + def forward(self, x, output_layers=None): + """ Forward pass with input x. The output_layers specify the feature blocks which must be returned """ + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + if self._add_output_and_check('conv1', x, outputs, output_layers): + return outputs + + x = self.maxpool(x) + + x = self.layer1(x) + + if self._add_output_and_check('layer1', x, outputs, output_layers): + return outputs + + x = self.layer2(x) + + if self._add_output_and_check('layer2', x, outputs, output_layers): + return outputs + + x = self.layer3(x) + + if self._add_output_and_check('layer3', x, outputs, output_layers): + return outputs + + x = self.layer4(x) + + if self._add_output_and_check('layer4', x, outputs, output_layers): + return outputs + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + if self._add_output_and_check('fc', x, outputs, output_layers): + return outputs + + if len(output_layers) == 1 and output_layers[0] == 'default': + return x + + raise ValueError('output_layer is wrong.') + + +def resnet_baby(output_layers=None, pretrained=False, inplanes=16, **kwargs): + """Constructs a ResNet-18 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(BasicBlock, [2, 2, 2, 2], output_layers, inplanes=inplanes, **kwargs) + + if pretrained: + raise NotImplementedError + return model + + +def resnet18(output_layers=None, pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(BasicBlock, [2, 2, 2, 2], output_layers, **kwargs) + + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet50(output_layers=None, pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(Bottleneck, [3, 4, 6, 3], output_layers, **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/backbone/resnet18_vggm.py b/Stark/external/AR/ltr/models/backbone/resnet18_vggm.py new file mode 100755 index 0000000..5333abf --- /dev/null +++ b/Stark/external/AR/ltr/models/backbone/resnet18_vggm.py @@ -0,0 +1,159 @@ +import math +import torch +import torch.nn as nn +from collections import OrderedDict +from torchvision.models.resnet import BasicBlock +from .base import Backbone + + +class SpatialCrossMapLRN(nn.Module): + def __init__(self, local_size=1, alpha=1.0, beta=0.75, k=1, ACROSS_CHANNELS=True): + super(SpatialCrossMapLRN, self).__init__() + self.ACROSS_CHANNELS = ACROSS_CHANNELS + if ACROSS_CHANNELS: + self.average=nn.AvgPool3d(kernel_size=(local_size, 1, 1), + stride=1, + padding=(int((local_size-1.0)/2), 0, 0)) + else: + self.average=nn.AvgPool2d(kernel_size=local_size, + stride=1, + padding=int((local_size-1.0)/2)) + self.alpha = alpha + self.beta = beta + self.k = k + + def forward(self, x): + if self.ACROSS_CHANNELS: + div = x.pow(2).unsqueeze(1) + div = self.average(div).squeeze(1) + div = div.mul(self.alpha).add(self.k).pow(self.beta) + else: + div = x.pow(2) + div = self.average(div) + div = div.mul(self.alpha).add(self.k).pow(self.beta) + x = x.div(div) + return x + + +class ResNetVGGm1(Backbone): + + def __init__(self, block, layers, output_layers, num_classes=1000, frozen_layers=()): + self.inplanes = 64 + super(ResNetVGGm1, self).__init__(frozen_layers=frozen_layers) + self.output_layers = output_layers + self.vggmconv1 = nn.Conv2d(3,96,(7, 7),(2, 2), padding=3) + self.vgglrn = SpatialCrossMapLRN(5, 0.0005, 0.75, 2) + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + # self.avgpool = nn.AvgPool2d(7, stride=1) + self.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.fc = nn.Linear(512 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + + def forward(self, x, output_layers=None): + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + if 'vggconv1' in output_layers: + c1 = self.vgglrn(self.relu(self.vggmconv1(x))) + if self._add_output_and_check('vggconv1', c1, outputs, output_layers): + return outputs + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + if self._add_output_and_check('conv1', x, outputs, output_layers): + return outputs + + x = self.maxpool(x) + + x = self.layer1(x) + + if self._add_output_and_check('layer1', x, outputs, output_layers): + return outputs + + x = self.layer2(x) + + if self._add_output_and_check('layer2', x, outputs, output_layers): + return outputs + + x = self.layer3(x) + + if self._add_output_and_check('layer3', x, outputs, output_layers): + return outputs + + x = self.layer4(x) + + if self._add_output_and_check('layer4', x, outputs, output_layers): + return outputs + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + if self._add_output_and_check('fc', x, outputs, output_layers): + return outputs + + if len(output_layers) == 1 and output_layers[0] == 'default': + return x + + raise ValueError('output_layer is wrong.') + + +def resnet18_vggmconv1(output_layers=None, path=None, **kwargs): + """Constructs a ResNet-18 model with first-layer VGGm features. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['vggconv1', 'conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNetVGGm1(BasicBlock, [2, 2, 2, 2], output_layers, **kwargs) + + if path is not None: + model.load_state_dict(torch.load(path), strict=False) + return model \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/backbone/resnet_seg.py b/Stark/external/AR/ltr/models/backbone/resnet_seg.py new file mode 100755 index 0000000..7d14cc7 --- /dev/null +++ b/Stark/external/AR/ltr/models/backbone/resnet_seg.py @@ -0,0 +1,244 @@ +import math +import torch.nn as nn +from collections import OrderedDict +import torch.utils.model_zoo as model_zoo +from torchvision.models.resnet import model_urls +'''2020.4.14 newly added''' +from collections import OrderedDict as odict +from ltr.models.head.utils import get_out_channels + +def conv3x3(in_planes, out_planes, stride=1, dilation=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride, dilation=dilation) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + """ ResNet network module. Allows extracting specific feature blocks.""" + def __init__(self, block, layers, output_layers, num_classes=1000, inplanes=64, dilation_factor=1): + self.inplanes = inplanes + super(ResNet, self).__init__() + self.output_layers = output_layers + self.conv1 = nn.Conv2d(3, inplanes, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(inplanes) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + stride = [1 + (dilation_factor < l) for l in (8, 4, 2)] + self.layer1 = self._make_layer(block, inplanes, layers[0], dilation=max(dilation_factor//8, 1)) + self.layer2 = self._make_layer(block, inplanes*2, layers[1], stride=stride[0], dilation=max(dilation_factor//4, 1)) + self.layer3 = self._make_layer(block, inplanes*4, layers[2], stride=stride[1], dilation=max(dilation_factor//2, 1)) + self.layer4 = self._make_layer(block, inplanes*8, layers[3], stride=stride[2], dilation=dilation_factor) + # self.avgpool = nn.AvgPool2d(7, stride=1) + self.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.fc = nn.Linear(inplanes*8 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + '''2020.4.14 newly added''' + self._out_channels = odict( # Deep-to-shallow order is required by SegNetwork + layer5=get_out_channels(self.layer4), + layer4=get_out_channels(self.layer3), + layer3=get_out_channels(self.layer2), + layer2=get_out_channels(self.layer1), + layer1=get_out_channels(self.conv1)) + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + def forward(self, x, output_layers=None): + """ Forward pass with input x. The output_layers specify the feature blocks which must be returned """ + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x)# conv1: (batch,64,128,128) + '''2020.4.14 change names for every layers''' + if self._add_output_and_check('layer1', x, outputs, output_layers): + return outputs + + x = self.layer1(x) # (batch,256,64,64) + if self._add_output_and_check('layer2', x, outputs, output_layers): + return outputs + + x = self.layer2(x) # (batch,512,32,32) + + if self._add_output_and_check('layer3', x, outputs, output_layers): + return outputs + + x = self.layer3(x) # (batch,1024,16,16) + + if self._add_output_and_check('layer4', x, outputs, output_layers): + return outputs + + x = self.layer4(x) + + if self._add_output_and_check('layer5', x, outputs, output_layers): + return outputs + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + if self._add_output_and_check('fc', x, outputs, output_layers): + return outputs + + if len(output_layers) == 1 and output_layers[0] == 'default': + return x + + raise ValueError('output_layer is wrong.') + + '''2020.4.14 newly added''' + def get_out_channels(self): + return self._out_channels + + +def resnet18(output_layers=None, pretrained=False, dilation_factor=1): + """Constructs a ResNet-18 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(BasicBlock, [2, 2, 2, 2], output_layers, dilation_factor=dilation_factor) + + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet50(output_layers=None, pretrained=False, dilation_factor=1): + """Constructs a ResNet-50 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(Bottleneck, [3, 4, 6, 3], output_layers, dilation_factor=dilation_factor) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model + +'''newly added''' +def resnet101(output_layers=None, pretrained=False, dilation_factor=1): + """Constructs a ResNet-101 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(Bottleneck, [3, 4, 23, 3], output_layers, dilation_factor=dilation_factor) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + return model + diff --git a/Stark/external/AR/ltr/models/bbreg/__init__.py b/Stark/external/AR/ltr/models/bbreg/__init__.py new file mode 100755 index 0000000..bb6162f --- /dev/null +++ b/Stark/external/AR/ltr/models/bbreg/__init__.py @@ -0,0 +1 @@ +from .atom_iou_net import AtomIoUNet diff --git a/Stark/external/AR/ltr/models/bbreg/atom.py b/Stark/external/AR/ltr/models/bbreg/atom.py new file mode 100755 index 0000000..203384c --- /dev/null +++ b/Stark/external/AR/ltr/models/bbreg/atom.py @@ -0,0 +1,85 @@ +import torch.nn as nn +import ltr.models.backbone as backbones +import ltr.models.bbreg as bbmodels +from ltr import model_constructor + + +class ATOMnet(nn.Module): + """ ATOM network module""" + def __init__(self, feature_extractor, bb_regressor, bb_regressor_layer, extractor_grad=True): + """ + args: + feature_extractor - backbone feature extractor + bb_regressor - IoU prediction module + bb_regressor_layer - List containing the name of the layers from feature_extractor, which are input to + bb_regressor + extractor_grad - Bool indicating whether backbone feature extractor requires gradients + """ + super(ATOMnet, self).__init__() + + self.feature_extractor = feature_extractor + self.bb_regressor = bb_regressor + self.bb_regressor_layer = bb_regressor_layer + + if not extractor_grad: + for p in self.feature_extractor.parameters(): + p.requires_grad_(False) + + def forward(self, train_imgs, test_imgs, train_bb, test_proposals): + """ Forward pass + Note: If the training is done in sequence mode, that is, test_imgs.dim() == 5, then the batch dimension + corresponds to the first dimensions. test_imgs is thus of the form [sequence, batch, feature, row, col] + """ + num_sequences = train_imgs.shape[-4] + num_train_images = train_imgs.shape[0] if train_imgs.dim() == 5 else 1 + num_test_images = test_imgs.shape[0] if test_imgs.dim() == 5 else 1 + + # Extract backbone features + train_feat = self.extract_backbone_features(train_imgs.reshape(-1, *train_imgs.shape[-3:])) + test_feat = self.extract_backbone_features(test_imgs.reshape(-1, *test_imgs.shape[-3:])) + + train_feat_iou = [feat for feat in train_feat.values()] + test_feat_iou = [feat for feat in test_feat.values()] + + # Obtain iou prediction + iou_pred = self.bb_regressor(train_feat_iou, test_feat_iou, + train_bb.reshape(num_train_images, num_sequences, 4), + test_proposals.reshape(num_train_images, num_sequences, -1, 4)) + return iou_pred + + def extract_backbone_features(self, im, layers=None): + if layers is None: + layers = self.bb_regressor_layer + return self.feature_extractor(im, layers) + + def extract_features(self, im, layers): + return self.feature_extractor(im, layers) + + + +@model_constructor +def atom_resnet18(iou_input_dim=(256,256), iou_inter_dim=(256,256), backbone_pretrained=True): + # backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained) + + # Bounding box regressor + iou_predictor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + net = ATOMnet(feature_extractor=backbone_net, bb_regressor=iou_predictor, bb_regressor_layer=['layer2', 'layer3'], + extractor_grad=False) + + return net + + +@model_constructor +def atom_resnet50(iou_input_dim=(256,256), iou_inter_dim=(256,256), backbone_pretrained=True): + # backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained) + + # Bounding box regressor + iou_predictor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + net = ATOMnet(feature_extractor=backbone_net, bb_regressor=iou_predictor, bb_regressor_layer=['layer2', 'layer3'], + extractor_grad=False) + + return net diff --git a/Stark/external/AR/ltr/models/bbreg/atom_iou_net.py b/Stark/external/AR/ltr/models/bbreg/atom_iou_net.py new file mode 100755 index 0000000..15f0f73 --- /dev/null +++ b/Stark/external/AR/ltr/models/bbreg/atom_iou_net.py @@ -0,0 +1,179 @@ +import torch.nn as nn +import torch +from ltr.models.layers.blocks import LinearBlock +from ltr.external.PreciseRoIPooling.pytorch.prroi_pool import PrRoIPool2D + + +def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1): + return nn.Sequential( + nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=True), + nn.BatchNorm2d(out_planes), + nn.ReLU(inplace=True)) + + +class AtomIoUNet(nn.Module): + """Network module for IoU prediction. Refer to the ATOM paper for an illustration of the architecture. + It uses two backbone feature layers as input. + args: + input_dim: Feature dimensionality of the two input backbone layers. + pred_input_dim: Dimensionality input the the prediction network. + pred_inter_dim: Intermediate dimensionality in the prediction network.""" + + def __init__(self, input_dim=(128,256), pred_input_dim=(256,256), pred_inter_dim=(256,256)): + super().__init__() + # _r for reference, _t for test + self.conv3_1r = conv(input_dim[0], 128, kernel_size=3, stride=1) + self.conv3_1t = conv(input_dim[0], 256, kernel_size=3, stride=1) + + self.conv3_2t = conv(256, pred_input_dim[0], kernel_size=3, stride=1) + + self.prroi_pool3r = PrRoIPool2D(3, 3, 1/8) + self.prroi_pool3t = PrRoIPool2D(5, 5, 1/8) + + self.fc3_1r = conv(128, 256, kernel_size=3, stride=1, padding=0) + + self.conv4_1r = conv(input_dim[1], 256, kernel_size=3, stride=1) + self.conv4_1t = conv(input_dim[1], 256, kernel_size=3, stride=1) + + self.conv4_2t = conv(256, pred_input_dim[1], kernel_size=3, stride=1) + + self.prroi_pool4r = PrRoIPool2D(1, 1, 1/16) + self.prroi_pool4t = PrRoIPool2D(3, 3, 1 / 16) + + self.fc34_3r = conv(256 + 256, pred_input_dim[0], kernel_size=1, stride=1, padding=0) + self.fc34_4r = conv(256 + 256, pred_input_dim[1], kernel_size=1, stride=1, padding=0) + + self.fc3_rt = LinearBlock(pred_input_dim[0], pred_inter_dim[0], 5) + self.fc4_rt = LinearBlock(pred_input_dim[1], pred_inter_dim[1], 3) + + self.iou_predictor = nn.Linear(pred_inter_dim[0]+pred_inter_dim[1], 1, bias=True) + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d) or isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight.data, mode='fan_in') + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + # In earlier versions batch norm parameters was initialized with default initialization, + # which changed in pytorch 1.2. In 1.1 and earlier the weight was set to U(0,1). + # So we use the same initialization here. + # m.weight.data.fill_(1) + m.weight.data.uniform_() + m.bias.data.zero_() + + def forward(self, feat1, feat2, bb1, proposals2): + """Runs the ATOM IoUNet during training operation. + This forward pass is mainly used for training. Call the individual functions during tracking instead. + args: + feat1: Features from the reference frames (4 or 5 dims). + feat2: Features from the test frames (4 or 5 dims). + bb1: Target boxes (x,y,w,h) in image coords in the reference samples. Dims (images, sequences, 4). + proposals2: Proposal boxes for which the IoU will be predicted (images, sequences, num_proposals, 4).""" + + assert bb1.dim() == 3 + assert proposals2.dim() == 4 + + num_images = proposals2.shape[0] + num_sequences = proposals2.shape[1] + + # Extract first train sample + feat1 = [f[0,...] if f.dim()==5 else f.reshape(-1, num_sequences, *f.shape[-3:])[0,...] for f in feat1] + bb1 = bb1[0,...] + + # Get modulation vector + modulation = self.get_modulation(feat1, bb1) + + iou_feat = self.get_iou_feat(feat2) + + modulation = [f.reshape(1, num_sequences, -1).repeat(num_images, 1, 1).reshape(num_sequences*num_images, -1) for f in modulation] + + proposals2 = proposals2.reshape(num_sequences*num_images, -1, 4) + pred_iou = self.predict_iou(modulation, iou_feat, proposals2) + return pred_iou.reshape(num_images, num_sequences, -1) + + def predict_iou(self, modulation, feat, proposals): + """Predicts IoU for the give proposals. + args: + modulation: Modulation vectors for the targets. Dims (batch, feature_dim). + feat: IoU features (from get_iou_feat) for test images. Dims (batch, feature_dim, H, W). + proposals: Proposal boxes for which the IoU will be predicted (batch, num_proposals, 4).""" + + fc34_3_r, fc34_4_r = modulation + c3_t, c4_t = feat + + batch_size = c3_t.size()[0] + + # Modulation + c3_t_att = c3_t * fc34_3_r.reshape(batch_size, -1, 1, 1) + c4_t_att = c4_t * fc34_4_r.reshape(batch_size, -1, 1, 1) + + # Add batch_index to rois + batch_index = torch.arange(batch_size, dtype=torch.float32).reshape(-1, 1).to(c3_t.device) + + # Push the different rois for the same image along the batch dimension + num_proposals_per_batch = proposals.shape[1] + + # input proposals2 is in format xywh, convert it to x0y0x1y1 format + proposals_xyxy = torch.cat((proposals[:, :, 0:2], proposals[:, :, 0:2] + proposals[:, :, 2:4]), dim=2) + + # Add batch index + roi2 = torch.cat((batch_index.reshape(batch_size, -1, 1).expand(-1, num_proposals_per_batch, -1), + proposals_xyxy), dim=2) + roi2 = roi2.reshape(-1, 5).to(proposals_xyxy.device) + + roi3t = self.prroi_pool3t(c3_t_att, roi2) + roi4t = self.prroi_pool4t(c4_t_att, roi2) + + fc3_rt = self.fc3_rt(roi3t) + fc4_rt = self.fc4_rt(roi4t) + + fc34_rt_cat = torch.cat((fc3_rt, fc4_rt), dim=1) + + iou_pred = self.iou_predictor(fc34_rt_cat).reshape(batch_size, num_proposals_per_batch) + + return iou_pred + + def get_modulation(self, feat, bb): + """Get modulation vectors for the targets. + args: + feat: Backbone features from reference images. Dims (batch, feature_dim, H, W). + bb: Target boxes (x,y,w,h) in image coords in the reference samples. Dims (batch, 4).""" + + feat3_r, feat4_r = feat + + c3_r = self.conv3_1r(feat3_r) + + # Add batch_index to rois + batch_size = bb.shape[0] + batch_index = torch.arange(batch_size, dtype=torch.float32).reshape(-1, 1).to(bb.device) + + # input bb is in format xywh, convert it to x0y0x1y1 format + bb = bb.clone() + bb[:, 2:4] = bb[:, 0:2] + bb[:, 2:4] + roi1 = torch.cat((batch_index, bb), dim=1) + + roi3r = self.prroi_pool3r(c3_r, roi1) + + c4_r = self.conv4_1r(feat4_r) + roi4r = self.prroi_pool4r(c4_r, roi1) + + fc3_r = self.fc3_1r(roi3r) + + # Concatenate from block 3 and 4 + fc34_r = torch.cat((fc3_r, roi4r), dim=1) + + fc34_3_r = self.fc34_3r(fc34_r) + fc34_4_r = self.fc34_4r(fc34_r) + + return fc34_3_r, fc34_4_r + + def get_iou_feat(self, feat2): + """Get IoU prediction features from a 4 or 5 dimensional backbone input.""" + feat2 = [f.reshape(-1, *f.shape[-3:]) if f.dim()==5 else f for f in feat2] + feat3_t, feat4_t = feat2 + c3_t = self.conv3_2t(self.conv3_1t(feat3_t)) + c4_t = self.conv4_2t(self.conv4_1t(feat4_t)) + + return c3_t, c4_t diff --git a/Stark/external/AR/ltr/models/head/__init__.py b/Stark/external/AR/ltr/models/head/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/head/seg_network.py b/Stark/external/AR/ltr/models/head/seg_network.py new file mode 100755 index 0000000..f7f02e2 --- /dev/null +++ b/Stark/external/AR/ltr/models/head/seg_network.py @@ -0,0 +1,206 @@ +import torch +from torch import nn as nn +from torch.nn import functional as F +from ltr.models.head.utils import conv, relu, interpolate, adaptive_cat + + +class TSE(nn.Module): + + def __init__(self, fc, ic, oc): + super().__init__() + + nc = ic + oc + self.reduce = nn.Sequential(conv(fc, oc, 1), relu(), conv(oc, oc, 1)) + self.transform = nn.Sequential(conv(nc, nc, 3), relu(), conv(nc, nc, 3), relu(), conv(nc, oc, 3), relu()) + + def forward(self, ft, score, x=None): + h = self.reduce(ft) + hpool = F.adaptive_avg_pool2d(h, (1, 1)) if x is None else x + h = adaptive_cat((h, score), dim=1, ref_tensor=0) + h = self.transform(h) + return h, hpool + + +class CAB(nn.Module): + + def __init__(self, oc, deepest): + super().__init__() + + self.convreluconv = nn.Sequential(conv(2 * oc, oc, 1), relu(), conv(oc, oc, 1)) + self.deepest = deepest + + def forward(self, deeper, shallower, att_vec=None): + + shallow_pool = F.adaptive_avg_pool2d(shallower, (1, 1)) + deeper_pool = deeper if self.deepest else F.adaptive_avg_pool2d(deeper, (1, 1)) + if att_vec is not None: + global_pool = torch.cat([shallow_pool, deeper_pool, att_vec], dim=1) + else: + global_pool = torch.cat((shallow_pool, deeper_pool), dim=1) + conv_1x1 = self.convreluconv(global_pool) + inputs = shallower * torch.sigmoid(conv_1x1) + out = inputs + interpolate(deeper, inputs.shape[-2:]) + + return out + + +class RRB(nn.Module): + + def __init__(self, oc, use_bn=False): + super().__init__() + self.conv1x1 = conv(oc, oc, 1) + if use_bn: + self.bblock = nn.Sequential(conv(oc, oc, 3), nn.BatchNorm2d(oc), relu(), conv(oc, oc, 3, bias=False)) + else: + self.bblock = nn.Sequential(conv(oc, oc, 3), relu(), conv(oc, oc, 3, bias=False)) # Basic block + + def forward(self, x): + h = self.conv1x1(x) + return F.relu(h + self.bblock(h)) + + +class Upsampler(nn.Module): + + def __init__(self, in_channels=64): + super().__init__() + + self.conv1 = conv(in_channels, in_channels // 2, 3) + self.conv2 = conv(in_channels // 2, 1, 3) + + def forward(self, x, image_size): + print(x.shape) + x = F.interpolate(x, (2 * x.shape[-2], 2 * x.shape[-1]), mode='bicubic', align_corners=False) + x = F.relu(self.conv1(x)) + x = F.interpolate(x, image_size[-2:], mode='bicubic', align_corners=False) + x = self.conv2(x) + return x + + +class PyrUpBicubic2d(nn.Module): + + def __init__(self, channels): + super().__init__() + + self.channels = channels + + def kernel(d): + x = d + torch.arange(-1, 3, dtype=torch.float32) + x = torch.abs(x) + a = -0.75 + f = (x < 1).float() * ((a + 2) * x * x * x - (a + 3) * x * x + 1) + \ + ((x >= 1) * (x < 2)).float() * (a * x * x * x - 5 * a * x * x + 8 * a * x - 4 * a) + W = f.reshape(1, 1, 1, len(x)).float() + Wt = W.permute(0, 1, 3, 2) + return W, Wt + + We, We_t = kernel(-0.25) + Wo, Wo_t = kernel(-0.25 - 0.5) + + # Building non-separable filters for now. It would make sense to + # have separable filters if it proves to be faster. + + # .contiguous() is needed until a bug is fixed in nn.Conv2d. + self.W00 = (We_t @ We).expand(channels, 1, 4, 4).contiguous() + self.W01 = (We_t @ Wo).expand(channels, 1, 4, 4).contiguous() + self.W10 = (Wo_t @ We).expand(channels, 1, 4, 4).contiguous() + self.W11 = (Wo_t @ Wo).expand(channels, 1, 4, 4).contiguous() + + def forward(self, input): + + if input.device != self.W00.device: + self.W00 = self.W00.to(input.device) + self.W01 = self.W01.to(input.device) + self.W10 = self.W10.to(input.device) + self.W11 = self.W11.to(input.device) + + a = F.pad(input, (2, 2, 2, 2), 'replicate') + + I00 = F.conv2d(a, self.W00, groups=self.channels) + I01 = F.conv2d(a, self.W01, groups=self.channels) + I10 = F.conv2d(a, self.W10, groups=self.channels) + I11 = F.conv2d(a, self.W11, groups=self.channels) + + n, c, h, w = I11.shape + + J0 = torch.stack((I00, I01), dim=-1).view(n, c, h, 2 * w) + J1 = torch.stack((I10, I11), dim=-1).view(n, c, h, 2 * w) + out = torch.stack((J0, J1), dim=-2).view(n, c, 2 * h, 2 * w) + + out = F.pad(out, (-1, -1, -1, -1)) + return out + + +class BackwardCompatibleUpsampler(nn.Module): + """ Upsampler with bicubic interpolation that works with Pytorch 1.0.1 """ + + def __init__(self, in_channels=64): + super().__init__() + + self.conv1 = conv(in_channels, in_channels // 2, 3) + self.up1 = PyrUpBicubic2d(in_channels) + self.conv2 = conv(in_channels // 2, 1, 3) + self.up2 = PyrUpBicubic2d(in_channels // 2) + + def forward(self, x, image_size): + x = self.up1(x) + x = F.relu(self.conv1(x)) + x = self.up2(x) + x = F.interpolate(x, image_size[-2:], mode='bilinear', align_corners=False) + x = self.conv2(x) + return x + + +class SegNetwork(nn.Module): + + def __init__(self, in_channels=1, out_channels=32, ft_channels=None, use_bn=False): + + super().__init__() + + assert ft_channels is not None + self.ft_channels = ft_channels + + self.TSE = nn.ModuleDict() + self.RRB1 = nn.ModuleDict() + self.CAB = nn.ModuleDict() + self.RRB2 = nn.ModuleDict() + + ic = in_channels + oc = out_channels + + for L, fc in self.ft_channels.items(): + self.TSE[L] = TSE(fc, ic, oc) + self.RRB1[L] = RRB(oc, use_bn=use_bn) + self.CAB[L] = CAB(oc, L == 'layer5') + self.RRB2[L] = RRB(oc, use_bn=use_bn) + + #if torch.__version__ == '1.0.1' + self.project = BackwardCompatibleUpsampler(out_channels) + #self.project = Upsampler(out_channels) + + def forward(self, scores, features, image_size): + + num_targets = scores.shape[0] + num_fmaps = features[next(iter(self.ft_channels))].shape[0] + if num_targets > num_fmaps: + multi_targets = True + else: + multi_targets = False + + x = None + for i, L in enumerate(self.ft_channels): + ft = features[L] + s = interpolate(scores, ft.shape[-2:]) # Resample scores to match features size + + if multi_targets: + h, hpool = self.TSE[L](ft.repeat(num_targets, 1, 1, 1), s, x) + else: + h, hpool = self.TSE[L](ft, s, x) + + h = self.RRB1[L](h) + h = self.CAB[L](hpool, h) + x = self.RRB2[L](h) + + x = self.project(x, image_size) + return x + + diff --git a/Stark/external/AR/ltr/models/head/utils.py b/Stark/external/AR/ltr/models/head/utils.py new file mode 100755 index 0000000..97b0611 --- /dev/null +++ b/Stark/external/AR/ltr/models/head/utils.py @@ -0,0 +1,121 @@ +from collections import OrderedDict as odict + +import numpy as np +import torch +from torch import nn as nn +from torch.nn import functional as F + + +def text_bargraph(values): + blocks = np.array(('u', ' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', 'o')) + nsteps = len(blocks) - 2 - 1 + hstep = 1 / (2 * nsteps) + values = np.array(values) + nans = np.isnan(values) + values[nans] = 0 # '░' + indices = ((values + hstep) * nsteps + 1).astype(np.int) + indices[values < 0] = 0 + indices[values > 1] = len(blocks) - 1 + graph = blocks[indices] + graph[nans] = '░' + graph = str.join('', graph) + return graph + + +class ModuleWrapper: + """ A wrapper for hiding modules from PyTorch, so that the same module can be used in multiple places. + and yet saved only once in a checkpoint, or not at all. """ + + # https://stackoverflow.com/questions/1466676/create-a-wrapper-class-to-call-a-pre-and-post-function-around-existing-functions + + def __init__(self, wrapped_module): + self.__wrapped_module__ = wrapped_module + + def __getattr__(self, attr): + orig_attr = self.__wrapped_module__.__getattribute__(attr) + if callable(orig_attr): + def hooked(*args, **kwargs): + result = orig_attr(*args, **kwargs) + # prevent wrapped_class from becoming unwrapped + if result == self.__wrapped_module__: + return self + return result + + return hooked + else: + return orig_attr + + def __call__(self, *args, **kwargs): + return self.__wrapped_module__(*args, **kwargs) + + +def conv(ic, oc, ksize, bias=True, dilation=1, stride=1): + return nn.Conv2d(ic, oc, ksize, padding=ksize // 2, bias=bias, dilation=dilation, stride=stride) + + +def relu(negative_slope=0.0, inplace=False): + return nn.LeakyReLU(negative_slope, inplace=inplace) + + +def interpolate(t, sz): + sz = sz.tolist() if torch.is_tensor(sz) else sz + return F.interpolate(t, sz, mode='bilinear', align_corners=False) if t.shape[-2:] != sz else t + + +def adaptive_cat(seq, dim=0, ref_tensor=0): + sz = seq[ref_tensor].shape[-2:] + t = torch.cat([interpolate(t, sz) for t in seq], dim=dim) + return t + + +def get_out_channels(layer): + if hasattr(layer, 'out_channels'): + oc = layer.out_channels + elif hasattr(layer, '_modules'): + oc = get_out_channels(layer._modules) + else: + ocs = [] + for key in reversed(layer): + ocs.append(get_out_channels(layer[key])) + + oc = 0 + for elem in ocs: + if elem: + return elem + + return oc + + +def is_finite(t): + return (torch.isnan(t) + torch.isinf(t)) == 0 + + +class AverageMeter: + """Computes and stores the average and current value""" + + def __init__(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.seq_avg = [] + + def reset(self): + self.__init__() + + def update(self, val, n=1): + if not np.isnan(val): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def update_multi(self, val): + val = np.array(val) + v = val[~np.isnan(val)] + n = len(v) + self.val = val + self.sum += np.nansum(v) + self.count += n + self.avg = self.sum / self.count + diff --git a/Stark/external/AR/ltr/models/layers/__init__.py b/Stark/external/AR/ltr/models/layers/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/layers/activation.py b/Stark/external/AR/ltr/models/layers/activation.py new file mode 100755 index 0000000..403aedf --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/activation.py @@ -0,0 +1,67 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def softmax_reg(x: torch.Tensor, dim, reg=None): + """Softmax with optinal denominator regularization.""" + if reg is None: + return torch.softmax(x, dim=dim) + dim %= x.dim() + if isinstance(reg, (float, int)): + reg = x.new_tensor([reg]) + reg = reg.expand([1 if d==dim else x.shape[d] for d in range(x.dim())]) + x = torch.cat((x, reg), dim=dim) + return torch.softmax(x, dim=dim)[[slice(-1) if d==dim else slice(None) for d in range(x.dim())]] + + + +class MLU(nn.Module): + r"""MLU activation + """ + def __init__(self, min_val, inplace=False): + super().__init__() + self.min_val = min_val + self.inplace = inplace + + def forward(self, input): + return F.elu(F.leaky_relu(input, 1/self.min_val, inplace=self.inplace), self.min_val, inplace=self.inplace) + + +class LeakyReluPar(nn.Module): + r"""LeakyRelu parametric activation + """ + + def forward(self, x, a): + return (1.0 - a)/2.0 * torch.abs(x) + (1.0 + a)/2.0 * x + +class LeakyReluParDeriv(nn.Module): + r"""Derivative of the LeakyRelu parametric activation, wrt x. + """ + + def forward(self, x, a): + return (1.0 - a)/2.0 * torch.sign(x.detach()) + (1.0 + a)/2.0 + + +class BentIdentPar(nn.Module): + r"""BentIdent parametric activation + """ + def __init__(self, b=1.0): + super().__init__() + self.b = b + + def forward(self, x, a): + return (1.0 - a)/2.0 * (torch.sqrt(x*x + 4.0*self.b*self.b) - 2.0*self.b) + (1.0 + a)/2.0 * x + + +class BentIdentParDeriv(nn.Module): + r"""BentIdent parametric activation deriv + """ + def __init__(self, b=1.0): + super().__init__() + self.b = b + + def forward(self, x, a): + return (1.0 - a)/2.0 * (x / torch.sqrt(x*x + 4.0*self.b*self.b)) + (1.0 + a)/2.0 + diff --git a/Stark/external/AR/ltr/models/layers/blocks.py b/Stark/external/AR/ltr/models/layers/blocks.py new file mode 100755 index 0000000..aef88c5 --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/blocks.py @@ -0,0 +1,36 @@ +from torch import nn + + +def conv_block(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1, bias=True, + batch_norm=True, relu=True, padding_mode='zeros'): + layers = [] + assert padding_mode == 'zeros' or padding_mode == 'replicate' + + if padding_mode == 'replicate' and padding > 0: + assert isinstance(padding, int) + layers.append(nn.ReflectionPad2d(padding)) + padding = 0 + + layers.append(nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=bias)) + if batch_norm: + layers.append(nn.BatchNorm2d(out_planes)) + if relu: + layers.append(nn.ReLU(inplace=True)) + return nn.Sequential(*layers) + + +class LinearBlock(nn.Module): + def __init__(self, in_planes, out_planes, input_sz, bias=True, batch_norm=True, relu=True): + super().__init__() + self.linear = nn.Linear(in_planes*input_sz*input_sz, out_planes, bias=bias) + self.bn = nn.BatchNorm2d(out_planes) if batch_norm else None + self.relu = nn.ReLU(inplace=True) if relu else None + + def forward(self, x): + x = self.linear(x.reshape(x.shape[0], -1)) + if self.bn is not None: + x = self.bn(x.reshape(x.shape[0], x.shape[1], 1, 1)) + if self.relu is not None: + x = self.relu(x) + return x.reshape(x.shape[0], -1) \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/layers/distance.py b/Stark/external/AR/ltr/models/layers/distance.py new file mode 100755 index 0000000..f0b7bc0 --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/distance.py @@ -0,0 +1,41 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class DistanceMap(nn.Module): + """Generate a distance map from a origin center location. + args: + num_bins: Number of bins in the map. + bin_displacement: Displacement of the bins. + """ + def __init__(self, num_bins, bin_displacement=1.0): + super().__init__() + self.num_bins = num_bins + self.bin_displacement = bin_displacement + + def forward(self, center, output_sz): + """Create the distance map. + args: + center: Torch tensor with (y,x) center position. Dims (batch, 2) + output_sz: Size of output distance map. 2-dimensional tuple.""" + + center = center.view(-1,2) + + bin_centers = torch.arange(self.num_bins, dtype=torch.float32, device=center.device).view(1, -1, 1, 1) + + k0 = torch.arange(output_sz[0], dtype=torch.float32, device=center.device).view(1,1,-1,1) + k1 = torch.arange(output_sz[1], dtype=torch.float32, device=center.device).view(1,1,1,-1) + + d0 = k0 - center[:,0].view(-1,1,1,1) + d1 = k1 - center[:,1].view(-1,1,1,1) + + dist = torch.sqrt(d0*d0 + d1*d1) + bin_diff = dist / self.bin_displacement - bin_centers + + bin_val = torch.cat((F.relu(1.0 - torch.abs(bin_diff[:,:-1,:,:]), inplace=True), + (1.0 + bin_diff[:,-1:,:,:]).clamp(0, 1)), dim=1) + + return bin_val + + diff --git a/Stark/external/AR/ltr/models/layers/filter.py b/Stark/external/AR/ltr/models/layers/filter.py new file mode 100755 index 0000000..1f38a20 --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/filter.py @@ -0,0 +1,183 @@ +import torch +import torch.nn.functional as F + + +def apply_filter(feat, filter, dilation_factors=None): + """Applies the filter on the input features (feat). The number of groups is automatically calculated. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + filter: The filter to apply. Must have dimensions (sequences, feat_dim, fH, fW) or (sequences, filters, feat_dim/groups, fH, fW) + output: + scores: Output of filtering. Dimensions (images_in_sequence, sequences, yH, yW) or (images_in_sequence, sequences, filters, yH, yW) + """ + + multiple_filters = (filter.dim() == 5) + + padding = (filter.shape[-2] // 2, filter.shape[-1] // 2) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = filter.shape[1] if multiple_filters else 1 + num_channels = feat.shape[-3] + groups = num_channels // filter.shape[-3] + + assert num_filters % groups == 0 and num_channels % groups == 0 + + if multiple_filters: + if dilation_factors is None: + scores = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), filter.view(-1, *filter.shape[-3:]), + padding=padding, groups=num_sequences*groups) + + return scores.view(num_images, num_sequences, -1, scores.shape[-2], scores.shape[-1]) + else: + scores_all = [] + start_id = 0 + + for d_factor, num_filters_with_d in dilation_factors.items(): + f_d = filter[:, start_id:start_id+num_filters_with_d, ...].contiguous() + + padding_d = [p+d_factor-1 for p in padding] + scores_d = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), + f_d.view(-1, *f_d.shape[-3:]), + padding=padding_d, groups=num_sequences * groups, + dilation=d_factor) + scores_d = scores_d.view(num_images, num_sequences, -1, scores_d.shape[-2], scores_d.shape[-1]) + scores_all.append(scores_d) + start_id += num_filters_with_d + + scores = torch.cat(scores_all, dim=2) + return scores + + scores = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), filter, + padding=padding, groups=num_sequences) + + return scores.view(num_images, num_sequences, scores.shape[-2], scores.shape[-1]) + + +def apply_feat_transpose(feat, input, filter_ksz, training=True, groups=1): + """Applies the transposed operation off apply_filter w.r.t. filter itself. Can be used to compute the filter gradient. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + input: Input activation (e.g. residuals). Must have dimensions (images_in_sequence, sequences, yH, yW) or + (images_in_sequence, sequences, filters, yH, yW) + training: Choose the faster implementation whether training or not. + output: + Output of transposed operation. Dimensions (sequences, feat_dim, fH, fW) + """ + + if groups != 1: + raise NotImplementedError('Not implemented other values of group.') + + if training or input.dim() == 5: + return _apply_feat_transpose_v3(feat, input, filter_ksz) + return _apply_feat_transpose_v2(feat, input, filter_ksz) + + +def _apply_feat_transpose_v1(feat, input, filter_ksz): + """This one is slow as hell!!!!""" + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + feat_sz = (feat.shape[-2], feat.shape[-1]) + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + # trans_pad = sz + padding - filter_ksz + trans_pad = [sz + ksz//2 - ksz for sz, ksz in zip(feat_sz, filter_ksz)] + + filter_grad = F.conv_transpose2d(input.flip((2, 3)).view(1, -1, input.shape[-2], input.shape[-1]), + feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + return filter_grad.view(num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=0) + + +def _apply_feat_transpose_v2(feat, input, filter_ksz): + """Fast forward and slow backward""" + + multiple_filters = (input.dim() == 5) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = input.shape[2] if multiple_filters else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [(ksz-1)//2 for ksz in filter_ksz] + + if multiple_filters: + filter_grad = F.conv2d(input.reshape(-1, num_filters, input.shape[-2], input.shape[-1]).permute(1,0,2,3), + feat.reshape(-1, 1, feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + if num_images == 1: + return filter_grad.view(num_filters, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).flip((3,4)).permute(1,0,2,3,4) + return filter_grad.view(num_filters, num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).flip((3,4)).permute(1,0,2,3,4) + + filter_grad = F.conv2d(input.reshape(1, -1, input.shape[-2], input.shape[-1]), + feat.reshape(-1, 1, feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + return filter_grad.view(num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=0).flip((2,3)) + + +def _apply_feat_transpose_v3(feat, input, filter_ksz): + """Slow forward fast backward""" + + multiple_filters = (input.dim() == 5) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = input.shape[2] if multiple_filters else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [ksz//2 for ksz in filter_ksz] + + filter_grad = F.conv2d(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]).permute(1,0,2,3), + input.reshape(-1, 1, input.shape[-2], input.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + if multiple_filters: + if num_images == 1: + return filter_grad.view(-1, num_sequences, num_filters, filter_grad.shape[-2], filter_grad.shape[-1]).permute(1,2,0,3,4) + return filter_grad.view(-1, num_images, num_sequences, num_filters, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).permute(1,2,0,3,4) + + if num_images == 1: + return filter_grad.permute(1,0,2,3) + return filter_grad.view(-1, num_images, num_sequences, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).permute(1,0,2,3) + + +def _apply_feat_transpose_v4(feat, input, filter_ksz): + """Slow forward fast backward""" + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [ksz//2 for ksz in filter_ksz] + + filter_grad = F.conv2d(feat.permute(2,1,0,3,4).reshape(feat.shape[-3], -1, feat.shape[-2], feat.shape[-1]), + input.permute(1,0,2,3), + padding=trans_pad, groups=num_sequences) + + return filter_grad.permute(1,0,2,3) + + + +def filter_gradient(feat, filter, label=None, training=True): + """Computes gradient of the filter when applied on the input features and ground truth label. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + filter: The filter to apply. Must have dimensions (sequences, feat_dim, fH, fW) + label: Ground truth label in the L2 loss. Dimensions (images_in_sequence, sequences, yH, yW) + output: + filter_gradient: Dimensions same as input filter (sequences, feat_dim, fH, fW) + """ + + residuals = apply_filter(feat, filter) + if label is not None: + residuals = residuals - label + filter_ksz = (filter.shape[-2], filter.shape[-1]) + return apply_feat_transpose(feat, residuals, filter_ksz, training=training) diff --git a/Stark/external/AR/ltr/models/layers/normalization.py b/Stark/external/AR/ltr/models/layers/normalization.py new file mode 100755 index 0000000..9f14cbc --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/normalization.py @@ -0,0 +1,21 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class InstanceL2Norm(nn.Module): + """Instance L2 normalization. + """ + def __init__(self, size_average=True, eps=1e-5, scale=1.0): + super().__init__() + self.size_average = size_average + self.eps = eps + self.scale = scale + + def forward(self, input): + if self.size_average: + return input * (self.scale * ((input.shape[1] * input.shape[2] * input.shape[3]) / ( + torch.sum((input * input).view(input.shape[0], 1, 1, -1), dim=3, keepdim=True) + self.eps)).sqrt()) + else: + return input * (self.scale / (torch.sum((input * input).view(input.shape[0], 1, 1, -1), dim=3, keepdim=True) + self.eps).sqrt()) + diff --git a/Stark/external/AR/ltr/models/layers/transform.py b/Stark/external/AR/ltr/models/layers/transform.py new file mode 100755 index 0000000..5b55f9c --- /dev/null +++ b/Stark/external/AR/ltr/models/layers/transform.py @@ -0,0 +1,25 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from collections import OrderedDict + + +def interpolate(x, sz): + """Interpolate 4D tensor x to size sz.""" + sz = sz.tolist() if torch.is_tensor(sz) else sz + return F.interpolate(x, sz, mode='bilinear', align_corners=False) if x.shape[-2:] != sz else x + + +class InterpCat(nn.Module): + """Interpolate and concatenate features of different resolutions.""" + + def forward(self, input): + if isinstance(input, (dict, OrderedDict)): + input = list(input.values()) + + output_shape = None + for x in input: + if output_shape is None or output_shape[0] > x.shape[-2]: + output_shape = x.shape[-2:] + + return torch.cat([interpolate(x, output_shape) for x in input], dim=-3) diff --git a/Stark/external/AR/ltr/models/loss/__init__.py b/Stark/external/AR/ltr/models/loss/__init__.py new file mode 100755 index 0000000..f815704 --- /dev/null +++ b/Stark/external/AR/ltr/models/loss/__init__.py @@ -0,0 +1 @@ +from .target_classification import LBHinge diff --git a/Stark/external/AR/ltr/models/loss/kl_regression.py b/Stark/external/AR/ltr/models/loss/kl_regression.py new file mode 100755 index 0000000..c65d7c4 --- /dev/null +++ b/Stark/external/AR/ltr/models/loss/kl_regression.py @@ -0,0 +1,70 @@ +import math +import torch +import torch.nn as nn +from torch.nn import functional as F + + +class KLRegression(nn.Module): + """KL-divergence loss for probabilistic regression. + It is computed using Monte Carlo (MC) samples from an arbitrary distribution.""" + + def __init__(self, eps=0.0): + super().__init__() + self.eps = eps + + def forward(self, scores, sample_density, gt_density, mc_dim=-1): + """Args: + scores: predicted score values + sample_density: probability density of the sample distribution + gt_density: probability density of the ground truth distribution + mc_dim: dimension of the MC samples""" + + exp_val = scores - torch.log(sample_density + self.eps) + + L = torch.logsumexp(exp_val, dim=mc_dim) - math.log(scores.shape[mc_dim]) - \ + torch.mean(scores * (gt_density / (sample_density + self.eps)), dim=mc_dim) + + return L.mean() + + +class MLRegression(nn.Module): + """Maximum likelihood loss for probabilistic regression. + It is computed using Monte Carlo (MC) samples from an arbitrary distribution.""" + + def __init__(self, eps=0.0): + super().__init__() + self.eps = eps + + def forward(self, scores, sample_density, gt_density=None, mc_dim=-1): + """Args: + scores: predicted score values. First sample must be ground-truth + sample_density: probability density of the sample distribution + gt_density: not used + mc_dim: dimension of the MC samples. Only mc_dim=1 supported""" + + assert mc_dim == 1 + assert (sample_density[:,0,...] == -1).all() + + exp_val = scores[:, 1:, ...] - torch.log(sample_density[:, 1:, ...] + self.eps) + + L = torch.logsumexp(exp_val, dim=mc_dim) - math.log(scores.shape[mc_dim] - 1) - scores[:, 0, ...] + loss = L.mean() + return loss + + +class KLRegressionGrid(nn.Module): + """KL-divergence loss for probabilistic regression. + It is computed using the grid integration strategy.""" + + def forward(self, scores, gt_density, grid_dim=-1, grid_scale=1.0): + """Args: + scores: predicted score values + gt_density: probability density of the ground truth distribution + grid_dim: dimension(s) of the grid + grid_scale: area of one grid cell""" + + score_corr = grid_scale * torch.sum(scores * gt_density, dim=grid_dim) + + L = torch.logsumexp(scores, dim=grid_dim) + math.log(grid_scale) - score_corr + + return L.mean() diff --git a/Stark/external/AR/ltr/models/loss/target_classification.py b/Stark/external/AR/ltr/models/loss/target_classification.py new file mode 100755 index 0000000..50eaaa4 --- /dev/null +++ b/Stark/external/AR/ltr/models/loss/target_classification.py @@ -0,0 +1,31 @@ +import torch.nn as nn +import torch +from torch.nn import functional as F + + +class LBHinge(nn.Module): + """Loss that uses a 'hinge' on the lower bound. + This means that for samples with a label value smaller than the threshold, the loss is zero if the prediction is + also smaller than that threshold. + args: + error_matric: What base loss to use (MSE by default). + threshold: Threshold to use for the hinge. + clip: Clip the loss if it is above this value. + """ + def __init__(self, error_metric=nn.MSELoss(), threshold=None, clip=None): + super().__init__() + self.error_metric = error_metric + self.threshold = threshold if threshold is not None else -100 + self.clip = clip + + def forward(self, prediction, label, target_bb=None): + negative_mask = (label < self.threshold).float() + positive_mask = (1.0 - negative_mask) + + prediction = negative_mask * F.relu(prediction) + positive_mask * prediction + + loss = self.error_metric(prediction, positive_mask * label) + + if self.clip is not None: + loss = torch.min(loss, torch.tensor([self.clip], device=loss.device)) + return loss diff --git a/Stark/external/AR/ltr/models/meta/__init__.py b/Stark/external/AR/ltr/models/meta/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/meta/steepestdescent.py b/Stark/external/AR/ltr/models/meta/steepestdescent.py new file mode 100755 index 0000000..a81af5b --- /dev/null +++ b/Stark/external/AR/ltr/models/meta/steepestdescent.py @@ -0,0 +1,92 @@ +import math +import torch +import torch.nn as nn +from pytracking import TensorList +from ltr.models.layers import activation + + +class GNSteepestDescent(nn.Module): + """General module for steepest descent based meta learning.""" + def __init__(self, residual_module, num_iter=1, compute_losses=False, detach_length=float('Inf'), + parameter_batch_dim=0, residual_batch_dim=0, steplength_reg=0.0, + filter_dilation_factors=None): + super().__init__() + + self.residual_module = residual_module + self.num_iter = num_iter + self.compute_losses = compute_losses + self.detach_length = detach_length + self.steplength_reg = steplength_reg + self._parameter_batch_dim = parameter_batch_dim + self._residual_batch_dim = residual_batch_dim + self.filter_dilation_factors = filter_dilation_factors + + def _sqr_norm(self, x: TensorList, batch_dim=0): + sum_keep_batch_dim = lambda e: e.sum(dim=[d for d in range(e.dim()) if d != batch_dim]) + return sum((x * x).apply(sum_keep_batch_dim)) + + + def _compute_loss(self, res): + return sum((res * res).sum()) / sum(res.numel()) + + + def forward(self, meta_parameter: TensorList, num_iter=None, *args, **kwargs): + # Make sure grad is enabled + torch_grad_enabled = torch.is_grad_enabled() + torch.set_grad_enabled(True) + + num_iter = self.num_iter if num_iter is None else num_iter + + meta_parameter_iterates = [meta_parameter] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + meta_parameter = meta_parameter.detach() + + meta_parameter.requires_grad_(True) + + # Compute residual vector + r = self.residual_module(meta_parameter, filter_dilation_factors=self.filter_dilation_factors, **kwargs) + + if self.compute_losses: + losses.append(self._compute_loss(r)) + + # Compute gradient of loss + u = r.clone() + g = TensorList(torch.autograd.grad(r, meta_parameter, u, create_graph=True)) + + # Multiply gradient with Jacobian + h = TensorList(torch.autograd.grad(g, u, g, create_graph=True)) + + # Compute squared norms + ip_gg = self._sqr_norm(g, batch_dim=self._parameter_batch_dim) + ip_hh = self._sqr_norm(h, batch_dim=self._residual_batch_dim) + + # Compute step length + alpha = ip_gg / (ip_hh + self.steplength_reg * ip_gg).clamp(1e-8) + + # Compute optimization step + step = g.apply(lambda e: alpha.reshape([-1 if d==self._parameter_batch_dim else 1 for d in range(e.dim())]) * e) + + # Add step to parameter + meta_parameter = meta_parameter - step + + meta_parameter_iterates.append(meta_parameter) + + + if self.compute_losses: + losses.append(self._compute_loss(self.residual_module(meta_parameter, + filter_dilation_factors=self.filter_dilation_factors, + **kwargs))) + + # Reset the grad enabled flag + torch.set_grad_enabled(torch_grad_enabled) + if not torch_grad_enabled: + meta_parameter.detach_() + for w in meta_parameter_iterates: + w.detach_() + for l in losses: + l.detach_() + + return meta_parameter, meta_parameter_iterates, losses diff --git a/Stark/external/AR/ltr/models/neck/CorrNL.py b/Stark/external/AR/ltr/models/neck/CorrNL.py new file mode 100755 index 0000000..e40d9d0 --- /dev/null +++ b/Stark/external/AR/ltr/models/neck/CorrNL.py @@ -0,0 +1,115 @@ +import torch.nn as nn +import torch +from ltr.external.PreciseRoIPooling.pytorch.prroi_pool import PrRoIPool2D +from torch.nn import functional as F +from ltr.models.neck.neck_utils import * + +class CorrNL(nn.Module): + """Network module for IoU prediction. Refer to the ATOM paper for an illustration of the architecture. + It uses two backbone feature layers as input. + args: + input_dim: Feature dimensionality of the two input backbone layers. + pred_input_dim: Dimensionality input the the prediction network. + pred_inter_dim: Intermediate dimensionality in the prediction network.""" + + def __init__(self, pool_size=8, use_NL=True): + super().__init__() + self.prroi_pool = PrRoIPool2D(pool_size, pool_size, 1/16) + num_corr_channel = pool_size*pool_size + self.channel_attention = SEModule(num_corr_channel,reduction=4) + self.spatial_attention = NONLocalBlock2D(in_channels=num_corr_channel) + self.use_NL = use_NL + def forward(self, feat1, feat2, bb1): + """Runs the ATOM IoUNet during training operation. + This forward pass is mainly used for training. Call the individual functions during tracking instead. + args: + feat1: Features from the reference frames (4 or 5 dims). + feat2: Features from the test frames (4 or 5 dims). + bb1: Target boxes (x,y,w,h) in image coords in the reference samples. Dims (images, sequences, 4). + proposals2: Proposal boxes for which the IoU will be predicted (images, sequences, num_proposals, 4).""" + + assert bb1.dim() == 3 + # num_images, num_sequences = bb1.size()[:2] # 1, 64 + + # Extract first train sample + if len(feat1)==1: + feat1 = feat1[0] # size为(64,C,H,W) + feat2 = feat2[0] # size为(64,C,H,W) + bb1 = bb1[0,...] # (64,4) + else: + raise ValueError("Only support single-layer feature map") + '''get PrRoIPool feature ''' + # Add batch_index to rois + batch_size = bb1.shape[0] + batch_index = torch.arange(batch_size, dtype=torch.float32).view(-1, 1).to(bb1.device) # (64,1) + # input bb is in format xywh, convert it to x0y0x1y1 format + bb1 = bb1.clone() + bb1[:, 2:4] = bb1[:, 0:2] + bb1[:, 2:4] + roi1 = torch.cat((batch_index, bb1), dim=1) #(64,1),(64,4) ---> (64,5) + feat_roi1 = self.prroi_pool(feat1, roi1) # (64,C,H,W) + feat_corr,_ = self.corr_fun(feat_roi1, feat2) + # print('相关后的特征维度是:',feat_corr.size())#(batch,StxSt,Sr,Sr) + '''channel attention: Squeeze and Excitation''' + feat_ca = self.channel_attention(feat_corr) # 计算通道注意力特征 + '''spatial attention: Non-local 2D''' + feat_sa = self.spatial_attention(feat_ca) + return feat_sa + + def get_ref_kernel(self, feat1, bb1): + assert bb1.dim() == 3 + # num_images, num_sequences = bb1.size()[:2] # 1, 64 + + # Extract first train sample + if len(feat1) == 1: + feat1 = feat1[0] # size为(64,C,H,W) + bb1 = bb1[0, ...] # (64,4) + else: + raise ValueError("Only support single-layer feature map") + '''get PrRoIPool feature ''' + # Add batch_index to rois + batch_size = bb1.shape[0] + batch_index = torch.arange(batch_size, dtype=torch.float32).view(-1, 1).to(bb1.device) # (64,1) + # input bb is in format xywh, convert it to x0y0x1y1 format + bb1 = bb1.clone() + bb1[:, 2:4] = bb1[:, 0:2] + bb1[:, 2:4] + roi1 = torch.cat((batch_index, bb1), dim=1) # (64,1),(64,4) ---> (64,5) + '''注意: feat1 and roi1 must be cuda tensor''' + self.ref_kernel = self.prroi_pool(feat1.float(), roi1) # (64,C,H,W) + # self.ref_kernel.half() + + def fuse_feat(self, feat2): + '''fuse features from reference and test branch''' + if len(feat2) == 1: + feat2 = feat2[0] + '''Step1: pixel-wise correlation''' + feat_corr,_ = self.corr_fun(self.ref_kernel, feat2) + # print('相关后的特征维度是:',feat_corr.size())#(batch,StxSt,Sr,Sr) (batch,64,16,16) + '''Step2: channel attention: Squeeze and Excitation''' + feat_ca = self.channel_attention(feat_corr) # 计算通道注意力特征 + if not self.use_NL: + # print('not use non-local') + return feat_ca + else: + '''Step3: spatial attention: Non-local 2D''' + feat_sa = self.spatial_attention(feat_ca) + return feat_sa + + + def corr_fun(self, Kernel_tmp, Feature, KERs=None): + size = Kernel_tmp.size() + CORR = [] + Kernel = [] + for i in range(len(Feature)): + ker = Kernel_tmp[i:i + 1] + fea = Feature[i:i + 1] + ker = ker.view(size[1], size[2] * size[3]).transpose(0, 1) + ker = ker.unsqueeze(2).unsqueeze(3) + if not (type(KERs) == type(None)): + ker = torch.cat([ker, KERs[i]], 0) + co = F.conv2d(fea, ker.contiguous()) + CORR.append(co) + ker = ker.unsqueeze(0) + Kernel.append(ker) + corr = torch.cat(CORR, 0) + Kernel = torch.cat(Kernel, 0) + return corr, Kernel diff --git a/Stark/external/AR/ltr/models/neck/neck_utils.py b/Stark/external/AR/ltr/models/neck/neck_utils.py new file mode 100755 index 0000000..6506203 --- /dev/null +++ b/Stark/external/AR/ltr/models/neck/neck_utils.py @@ -0,0 +1,133 @@ +import torch.nn as nn +import torch +from torch.nn import functional as F + +def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1): + return nn.Sequential( + nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=True), + nn.BatchNorm2d(out_planes), + nn.ReLU(inplace=True)) + +'''Channel attention module''' +class SEModule(nn.Module): + + def __init__(self, channels, reduction=4): + super(SEModule, self).__init__() + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc1 = nn.Conv2d(channels, channels // reduction, kernel_size=1, + padding=0) + self.relu = nn.ReLU(inplace=True) + self.fc2 = nn.Conv2d(channels // reduction, channels, kernel_size=1, + padding=0) + self.sigmoid = nn.Sigmoid() + + def forward(self, x): + module_input = x + x = self.avg_pool(x) + x = self.fc1(x) + x = self.relu(x) + x = self.fc2(x) + x = self.sigmoid(x) + return module_input * x +'''Non-local module''' +class _NonLocalBlockND(nn.Module): + def __init__(self, in_channels, inter_channels=None, dimension=3, sub_sample=True, bn_layer=True): + """ + :param in_channels: + :param inter_channels: + :param dimension: + :param sub_sample: + :param bn_layer: + """ + super(_NonLocalBlockND, self).__init__() + + assert dimension in [1, 2, 3] + + self.dimension = dimension + self.sub_sample = sub_sample + + self.in_channels = in_channels + self.inter_channels = inter_channels + + if self.inter_channels is None: + self.inter_channels = in_channels // 2 + if self.inter_channels == 0: + self.inter_channels = 1 + + if dimension == 3: + conv_nd = nn.Conv3d + max_pool_layer = nn.MaxPool3d(kernel_size=(1, 2, 2)) + bn = nn.BatchNorm3d + elif dimension == 2: + conv_nd = nn.Conv2d + max_pool_layer = nn.MaxPool2d(kernel_size=(2, 2)) + bn = nn.BatchNorm2d + else: + conv_nd = nn.Conv1d + max_pool_layer = nn.MaxPool1d(kernel_size=(2)) + bn = nn.BatchNorm1d + + self.g = conv_nd(in_channels=self.in_channels, out_channels=self.inter_channels, + kernel_size=1, stride=1, padding=0) + + if bn_layer: + self.W = nn.Sequential( + conv_nd(in_channels=self.inter_channels, out_channels=self.in_channels, + kernel_size=1, stride=1, padding=0), + bn(self.in_channels) + ) + nn.init.constant_(self.W[1].weight, 0) + nn.init.constant_(self.W[1].bias, 0) + else: + self.W = conv_nd(in_channels=self.inter_channels, out_channels=self.in_channels, + kernel_size=1, stride=1, padding=0) + nn.init.constant_(self.W.weight, 0) + nn.init.constant_(self.W.bias, 0) + + self.theta = conv_nd(in_channels=self.in_channels, out_channels=self.inter_channels, + kernel_size=1, stride=1, padding=0) + self.phi = conv_nd(in_channels=self.in_channels, out_channels=self.inter_channels, + kernel_size=1, stride=1, padding=0) + + if sub_sample: + self.g = nn.Sequential(self.g, max_pool_layer) + self.phi = nn.Sequential(self.phi, max_pool_layer) + + def forward(self, x, return_nl_map=False): + """ + :param x: (b, c, t, h, w) + :param return_nl_map: if True return z, nl_map, else only return z. + :return: + """ + + batch_size = x.size(0) + + g_x = self.g(x).view(batch_size, self.inter_channels, -1) + g_x = g_x.permute(0, 2, 1) + + theta_x = self.theta(x).view(batch_size, self.inter_channels, -1) + theta_x = theta_x.permute(0, 2, 1) + phi_x = self.phi(x).view(batch_size, self.inter_channels, -1) + f = torch.matmul(theta_x, phi_x) + f_div_C = F.softmax(f, -1) + + y = torch.matmul(f_div_C, g_x) + y = y.permute(0, 2, 1).contiguous() + y = y.view(batch_size, self.inter_channels, *x.size()[2:]) + W_y = self.W(y) + z = W_y + x + + if return_nl_map: + return z, f_div_C + return z + +class NONLocalBlock2D(_NonLocalBlockND): + def __init__(self, in_channels, inter_channels=None, sub_sample=True, bn_layer=True): + super(NONLocalBlock2D, self).__init__(in_channels, + inter_channels=inter_channels, + dimension=2, sub_sample=sub_sample, + bn_layer=bn_layer,) + + + diff --git a/Stark/external/AR/ltr/models/target_classifier/__init__.py b/Stark/external/AR/ltr/models/target_classifier/__init__.py new file mode 100755 index 0000000..71f76c0 --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/__init__.py @@ -0,0 +1 @@ +from .linear_filter import LinearFilter diff --git a/Stark/external/AR/ltr/models/target_classifier/features.py b/Stark/external/AR/ltr/models/target_classifier/features.py new file mode 100755 index 0000000..f4e74f0 --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/features.py @@ -0,0 +1,69 @@ +import torch +from torch import nn +import torch.nn.functional as F +from torchvision.models.resnet import BasicBlock, Bottleneck +from ltr.models.layers.normalization import InstanceL2Norm +from ltr.models.layers.transform import InterpCat + + +def residual_basic_block(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + interp_cat=False, final_relu=False, init_pool=False): + """Construct a network block based on the BasicBlock used in ResNet 18 and 34.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + if interp_cat: + feat_layers.append(InterpCat()) + if init_pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + for i in range(num_blocks): + odim = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim + feat_layers.append(BasicBlock(feature_dim, odim)) + if final_conv: + feat_layers.append(nn.Conv2d(feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if final_relu: + feat_layers.append(nn.ReLU(inplace=True)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + return nn.Sequential(*feat_layers) + + +def residual_basic_block_pool(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + pool=True): + """Construct a network block based on the BasicBlock used in ResNet.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + for i in range(num_blocks): + odim = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim + feat_layers.append(BasicBlock(feature_dim, odim)) + if final_conv: + feat_layers.append(nn.Conv2d(feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + + return nn.Sequential(*feat_layers) + + +def residual_bottleneck(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + interp_cat=False, final_relu=False, final_pool=False): + """Construct a network block based on the Bottleneck block used in ResNet.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + if interp_cat: + feat_layers.append(InterpCat()) + for i in range(num_blocks): + planes = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim // 4 + feat_layers.append(Bottleneck(4*feature_dim, planes)) + if final_conv: + feat_layers.append(nn.Conv2d(4*feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if final_relu: + feat_layers.append(nn.ReLU(inplace=True)) + if final_pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + return nn.Sequential(*feat_layers) \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/target_classifier/initializer.py b/Stark/external/AR/ltr/models/target_classifier/initializer.py new file mode 100755 index 0000000..6458105 --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/initializer.py @@ -0,0 +1,248 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +from ltr.external.PreciseRoIPooling.pytorch.prroi_pool import PrRoIPool2D +from ltr.models.layers.blocks import conv_block +import math + + +class FilterPool(nn.Module): + """Pool the target region in a feature map. + args: + filter_size: Size of the filter. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region.""" + + def __init__(self, filter_size=1, feature_stride=16, pool_square=False): + super().__init__() + self.prroi_pool = PrRoIPool2D(filter_size, filter_size, 1/feature_stride) + self.pool_square = pool_square + + def forward(self, feat, bb): + """Pool the regions in bb. + args: + feat: Input feature maps. Dims (num_samples, feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (num_samples, 4). + returns: + pooled_feat: Pooled features. Dims (num_samples, feat_dim, wH, wW).""" + + # Add batch_index to rois + bb = bb.reshape(-1,4) + num_images_total = bb.shape[0] + batch_index = torch.arange(num_images_total, dtype=torch.float32).reshape(-1, 1).to(bb.device) + + # input bb is in format xywh, convert it to x0y0x1y1 format + pool_bb = bb.clone() + + if self.pool_square: + bb_sz = pool_bb[:, 2:4].prod(dim=1, keepdim=True).sqrt() + pool_bb[:, :2] += pool_bb[:, 2:]/2 - bb_sz/2 + pool_bb[:, 2:] = bb_sz + + pool_bb[:, 2:4] = pool_bb[:, 0:2] + pool_bb[:, 2:4] + roi1 = torch.cat((batch_index, pool_bb), dim=1) + + return self.prroi_pool(feat, roi1) + + + +class FilterInitializer(nn.Module): + """Initializes a target classification filter by applying a number of conv layers before and after pooling the target region. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end. + num_filter_pre_convs: Conv layers before pooling. + num_filter_post_convs: Conv layers after pooling.""" + + def __init__(self, filter_size=1, feature_dim=256, feature_stride=16, pool_square=False, filter_norm=True, + num_filter_pre_convs=1, num_filter_post_convs=0): + super().__init__() + + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Make pre conv + pre_conv_layers = [] + for i in range(num_filter_pre_convs): + pre_conv_layers.append(conv_block(feature_dim, feature_dim, kernel_size=3, padding=1)) + self.filter_pre_layers = nn.Sequential(*pre_conv_layers) if pre_conv_layers else None + + # Make post conv + post_conv_layers = [] + for i in range(num_filter_post_convs): + post_conv_layers.append(conv_block(feature_dim, feature_dim, kernel_size=1, padding=0)) + post_conv_layers.append(nn.Conv2d(feature_dim, feature_dim, kernel_size=1, padding=0)) + self.filter_post_layers = nn.Sequential(*post_conv_layers) + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = bb.shape[0] if bb.dim() == 3 else 1 + + if self.filter_pre_layers is not None: + feat = self.filter_pre_layers(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1])) + + feat_post = self.filter_pool(feat, bb) + weights = self.filter_post_layers(feat_post) + + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights + + +class FilterInitializerLinear(nn.Module): + """Initializes a target classification filter by applying a linear conv layer and then pooling the target region. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end. + conv_ksz: Kernel size of the conv layer before pooling.""" + + def __init__(self, filter_size=1, feature_dim=256, feature_stride=16, pool_square=False, filter_norm=True, + conv_ksz=3, init_weights='default'): + super().__init__() + + self.filter_conv = nn.Conv2d(feature_dim, feature_dim, kernel_size=conv_ksz, padding=conv_ksz // 2) + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + if init_weights == 'default': + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif init_weights == 'zero': + m.weight.data.zero_() + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = feat.shape[0] + + feat = self.filter_conv(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1])) + + weights = self.filter_pool(feat, bb) + + # If multiple input images, compute the initial filter as the average filter. + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights + + + +class FilterInitializerZero(nn.Module): + """Initializes a target classification filter with zeros. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality.""" + + def __init__(self, filter_size=1, feature_dim=256): + super().__init__() + + self.filter_size = (feature_dim, filter_size, filter_size) + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + + return feat.new_zeros(num_sequences, self.filter_size[0], self.filter_size[1], self.filter_size[2]) + + +class FilterInitializerSiamese(nn.Module): + """Initializes a target classification filter by only pooling the target region (similar to Siamese trackers). + args: + filter_size: Size of the filter. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end.""" + + def __init__(self, filter_size=1, feature_stride=16, pool_square=False, filter_norm=True): + super().__init__() + + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = feat.shape[0] + + feat = feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]) + weights = self.filter_pool(feat, bb) + + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights diff --git a/Stark/external/AR/ltr/models/target_classifier/linear_filter.py b/Stark/external/AR/ltr/models/target_classifier/linear_filter.py new file mode 100755 index 0000000..600cc50 --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/linear_filter.py @@ -0,0 +1,131 @@ +import torch.nn as nn +import ltr.models.layers.filter as filter_layer +import math + + +class LinearFilter(nn.Module): + """Target classification filter module. + args: + filter_size: Size of filter (int). + filter_initialize: Filter initializer module. + filter_optimizer: Filter optimizer module. + feature_extractor: Feature extractor module applied to the input backbone features.""" + + def __init__(self, filter_size, filter_initializer, filter_optimizer=None, feature_extractor=None): + super().__init__() + + self.filter_size = filter_size + + # Modules + self.filter_initializer = filter_initializer + self.filter_optimizer = filter_optimizer + self.feature_extractor = feature_extractor + + # Init weights + for m in self.feature_extractor.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, train_feat, test_feat, train_bb, *args, **kwargs): + """Learns a target classification filter based on the train samples and return the resulting classification + scores on the test samples. + The forward function is ONLY used for training. Call the individual functions during tracking. + args: + train_feat: Backbone features for the train samples (4 or 5 dims). + test_feat: Backbone features for the test samples (4 or 5 dims). + trian_bb: Target boxes (x,y,w,h) for the train samples in image coordinates. Dims (images, sequences, 4). + *args, **kwargs: These are passed to the optimizer module. + returns: + test_scores: Classification scores on the test samples.""" + + assert train_bb.dim() == 3 + + num_sequences = train_bb.shape[1] + + if train_feat.dim() == 5: + train_feat = train_feat.reshape(-1, *train_feat.shape[-3:]) + if test_feat.dim() == 5: + test_feat = test_feat.reshape(-1, *test_feat.shape[-3:]) + + # Extract features + train_feat = self.extract_classification_feat(train_feat, num_sequences) + test_feat = self.extract_classification_feat(test_feat, num_sequences) + + # Train filter + filter, filter_iter, losses = self.get_filter(train_feat, train_bb, *args, **kwargs) + + # Classify samples using all return filters + test_scores = [self.classify(f, test_feat) for f in filter_iter] + + return test_scores + + def extract_classification_feat(self, feat, num_sequences=None): + """Extract classification features based on the input backbone features.""" + if self.feature_extractor is None: + return feat + if num_sequences is None: + return self.feature_extractor(feat) + + output = self.feature_extractor(feat) + return output.reshape(-1, num_sequences, *output.shape[-3:]) + + def classify(self, weights, feat): + """Run classifier (filter) on the features (feat).""" + + scores = filter_layer.apply_filter(feat, weights) + + return scores + + def get_filter(self, feat, bb, *args, **kwargs): + """Outputs the learned filter based on the input features (feat) and target boxes (bb) by running the + filter initializer and optimizer. Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + *args, **kwargs: These are passed to the optimizer module. + returns: + weights: The final oprimized weights. Dims (sequences, feat_dim, wH, wW). + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + weights = self.filter_initializer(feat, bb) + + if self.filter_optimizer is not None: + weights, weights_iter, losses = self.filter_optimizer(weights, feat=feat, bb=bb, *args, **kwargs) + else: + weights_iter = [weights] + losses = None + + return weights, weights_iter, losses + + def train_classifier(self, backbone_feat, bb): + num_sequences = bb.shape[1] + + if backbone_feat.dim() == 5: + backbone_feat = backbone_feat.reshape(-1, *backbone_feat.shape[-3:]) + + # Extract features + train_feat = self.extract_classification_feat(backbone_feat, num_sequences) + + # Get filters from each iteration + final_filter, _, train_losses = self.get_filter(train_feat, bb) + return final_filter, train_losses + + def track_frame(self, filter_weights, backbone_feat): + if backbone_feat.dim() == 5: + num_sequences = backbone_feat.shape[1] + backbone_feat = backbone_feat.reshape(-1, *backbone_feat.shape[-3:]) + else: + num_sequences = None + + test_feat = self.extract_classification_feat(backbone_feat, num_sequences) + + scores = filter_layer.apply_filter(test_feat, filter_weights) + + return scores \ No newline at end of file diff --git a/Stark/external/AR/ltr/models/target_classifier/optimizer.py b/Stark/external/AR/ltr/models/target_classifier/optimizer.py new file mode 100755 index 0000000..c99c23f --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/optimizer.py @@ -0,0 +1,439 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +import ltr.models.layers.filter as filter_layer +import ltr.models.layers.activation as activation +from ltr.models.layers.distance import DistanceMap +import math + + + +class DiMPSteepestDescentGN(nn.Module): + """Optimizer module for DiMP. + It unrolls the steepest descent with Gauss-Newton iterations to optimize the target filter. + Moreover it learns parameters in the loss itself, as described in the DiMP paper. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + init_filter_reg: Initial filter regularization weight (which is then learned). + init_gauss_sigma: The standard deviation to use for the initialization of the label function. + num_dist_bins: Number of distance bins used for learning the loss label, mask and weight. + bin_displacement: The displacement of the bins (level of discritization). + mask_init_factor: Parameter controlling the initialization of the target mask. + score_act: Type of score activation (target mask computation) to use. The default 'relu' is what is described in the paper. + act_param: Parameter for the score_act. + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + mask_act: What activation to do on the output of the mask computation ('sigmoid' or 'linear'). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, + init_filter_reg=1e-2, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, mask_init_factor=4.0, + score_act='relu', act_param=None, min_filter_reg=1e-3, mask_act='sigmoid', + detach_length=float('Inf'), alpha_eps=0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.distance_map = DistanceMap(num_dist_bins, bin_displacement) + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.alpha_eps = alpha_eps + + # Distance coordinates + d = torch.arange(num_dist_bins, dtype=torch.float32).reshape(1,-1,1,1) * bin_displacement + if init_gauss_sigma == 0: + init_gauss = torch.zeros_like(d) + init_gauss[0,0,0,0] = 1 + else: + init_gauss = torch.exp(-1/2 * (d / init_gauss_sigma)**2) + + # Module that predicts the target label function (y in the paper) + self.label_map_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.label_map_predictor.weight.data = init_gauss - init_gauss.min() + + # Module that predicts the target mask (m in the paper) + mask_layers = [nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False)] + if mask_act == 'sigmoid': + mask_layers.append(nn.Sigmoid()) + init_bias = 0.0 + elif mask_act == 'linear': + init_bias = 0.5 + else: + raise ValueError('Unknown activation') + self.target_mask_predictor = nn.Sequential(*mask_layers) + self.target_mask_predictor[0].weight.data = mask_init_factor * torch.tanh(2.0 - d) + init_bias + + # Module that predicts the residual weights (v in the paper) + self.spatial_weight_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.spatial_weight_predictor.weight.data.fill_(1.0) + + # The score actvation and its derivative + if score_act == 'bentpar': + self.score_activation = activation.BentIdentPar(act_param) + self.score_activation_deriv = activation.BentIdentParDeriv(act_param) + elif score_act == 'relu': + self.score_activation = activation.LeakyReluPar() + self.score_activation_deriv = activation.LeakyReluParDeriv() + else: + raise ValueError('Unknown score activation') + + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute distance map + dmap_offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).reshape(-1, 2).flip((1,)) - dmap_offset + dist_map = self.distance_map(center, output_sz) + + # Compute label map masks and weight + label_map = self.label_map_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + target_mask = self.target_mask_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + spatial_weight = self.spatial_weight_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + + # Get total sample weights + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) * spatial_weight + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(num_images, num_sequences, 1, 1) * spatial_weight + + backprop_through_learning = (self.detach_length > 0) + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if not backprop_through_learning or (i > 0 and i % self.detach_length == 0): + weights = weights.detach() + + # Compute residuals + scores = filter_layer.apply_filter(feat, weights) + scores_act = self.score_activation(scores, target_mask) + score_mask = self.score_activation_deriv(scores, target_mask) + residuals = sample_weight * (scores_act - label_map) + + if compute_losses: + losses.append(((residuals**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + # Compute gradient + residuals_mapped = score_mask * (sample_weight * residuals) + weights_grad = filter_layer.apply_feat_transpose(feat, residuals_mapped, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Jacobian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + scores_grad = sample_weight * (score_mask * scores_grad) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = ((scores_grad * scores_grad).reshape(num_images, num_sequences, -1).sum(dim=(0,2)) + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + scores = self.score_activation(scores, target_mask) + losses.append((((sample_weight * (scores - label_map))**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + return weights, weight_iterates, losses + + + +class DiMPL2SteepestDescentGN(nn.Module): + """A simpler optimizer module that uses L2 loss. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + gauss_sigma: The standard deviation of the label function. + hinge_threshold: Threshold for the hinge-based loss (see DiMP paper). + init_filter_reg: Initial filter regularization weight (which is then learned). + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, gauss_sigma=1.0, hinge_threshold=-999, + init_filter_reg=1e-2, min_filter_reg=1e-3, detach_length=float('Inf'), alpha_eps=0.0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.hinge_threshold = hinge_threshold + self.gauss_sigma = gauss_sigma + self.alpha_eps = alpha_eps + + def get_label(self, center, output_sz): + center = center.reshape(center.shape[0], -1, center.shape[-1]) + k0 = torch.arange(output_sz[0], dtype=torch.float32).reshape(1, 1, -1, 1).to(center.device) + k1 = torch.arange(output_sz[1], dtype=torch.float32).reshape(1, 1, 1, -1).to(center.device) + g0 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * (k0 - center[:,:,0].reshape(*center.shape[:2], 1, 1)) ** 2) + g1 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * (k1 - center[:,:,1].reshape(*center.shape[:2], 1, 1)) ** 2) + gauss = g0 * g1 + return gauss + + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute distance map + dmap_offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).flip((-1,)) - dmap_offset + label_map = self.get_label(center, output_sz) + target_mask = (label_map > self.hinge_threshold).float() + label_map *= target_mask + + # Get total sample weights + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(num_images, num_sequences, 1, 1) + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + weights = weights.detach() + + # Compute residuals + scores = filter_layer.apply_filter(feat, weights) + scores_act = target_mask * scores + (1.0 - target_mask) * F.relu(scores) + score_mask = target_mask + (1.0 - target_mask) * (scores.detach() > 0).float() + residuals = sample_weight * (scores_act - label_map) + + if compute_losses: + losses.append(((residuals**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + # Compute gradient + residuals_mapped = score_mask * (sample_weight * residuals) + weights_grad = filter_layer.apply_feat_transpose(feat, residuals_mapped, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Jacobian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + scores_grad = sample_weight * (score_mask * scores_grad) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = ((scores_grad * scores_grad).reshape(num_images, num_sequences, -1).sum(dim=(0,2)) + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + scores = target_mask * scores + (1.0 - target_mask) * F.relu(scores) + losses.append((((sample_weight * (scores - label_map))**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + return weights, weight_iterates, losses + + +class PrDiMPSteepestDescentNewton(nn.Module): + """Optimizer module for PrDiMP. + It unrolls the steepest descent with Newton iterations to optimize the target filter. See the PrDiMP paper. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + init_filter_reg: Initial filter regularization weight (which is then learned). + gauss_sigma: The standard deviation to use for the label density function. + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + init_uni_weight: Weight of uniform label distribution. + normalize_label: Wheter to normalize the label distribution. + label_shrink: How much to shrink to label distribution. + softmax_reg: Regularization in the denominator of the SoftMax. + label_threshold: Threshold probabilities smaller than this. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, + init_filter_reg=1e-2, gauss_sigma=1.0, min_filter_reg=1e-3, detach_length=float('Inf'), + alpha_eps=0.0, init_uni_weight=None, normalize_label=False, label_shrink=0, softmax_reg=None, label_threshold=0.0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.gauss_sigma = gauss_sigma + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.alpha_eps = alpha_eps + self.uni_weight = 0 if init_uni_weight is None else init_uni_weight + self.normalize_label = normalize_label + self.label_shrink = label_shrink + self.softmax_reg = softmax_reg + self.label_threshold = label_threshold + + def get_label_density(self, center, output_sz): + center = center.reshape(center.shape[0], -1, center.shape[-1]) + k0 = torch.arange(output_sz[0], dtype=torch.float32).reshape(1, 1, -1, 1).to(center.device) + k1 = torch.arange(output_sz[1], dtype=torch.float32).reshape(1, 1, 1, -1).to(center.device) + dist0 = (k0 - center[:,:,0].reshape(*center.shape[:2], 1, 1)) ** 2 + dist1 = (k1 - center[:,:,1].reshape(*center.shape[:2], 1, 1)) ** 2 + if self.gauss_sigma == 0: + dist0_view = dist0.reshape(-1, dist0.shape[-2]) + dist1_view = dist1.reshape(-1, dist1.shape[-1]) + one_hot0 = torch.zeros_like(dist0_view) + one_hot1 = torch.zeros_like(dist1_view) + one_hot0[torch.arange(one_hot0.shape[0]), dist0_view.argmin(dim=-1)] = 1.0 + one_hot1[torch.arange(one_hot1.shape[0]), dist1_view.argmin(dim=-1)] = 1.0 + gauss = one_hot0.reshape(dist0.shape) * one_hot1.reshape(dist1.shape) + else: + g0 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * dist0) + g1 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * dist1) + gauss = (g0 / (2*math.pi*self.gauss_sigma**2)) * g1 + gauss = gauss * (gauss > self.label_threshold).float() + if self.normalize_label: + gauss /= (gauss.sum(dim=(-2,-1), keepdim=True) + 1e-8) + label_dens = (1.0 - self.label_shrink)*((1.0 - self.uni_weight) * gauss + self.uni_weight / (output_sz[0]*output_sz[1])) + return label_dens + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute label density + offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).flip((-1,)) - offset + label_density = self.get_label_density(center, output_sz) + + # Get total sample weights + if sample_weight is None: + sample_weight = torch.Tensor([1.0 / num_images]).to(feat.device) + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.reshape(num_images, num_sequences, 1, 1) + + exp_reg = 0 if self.softmax_reg is None else math.exp(self.softmax_reg) + def _compute_loss(scores, weights): + return torch.sum(sample_weight.reshape(sample_weight.shape[0], -1) * + (torch.log(scores.exp().sum(dim=(-2, -1)) + exp_reg) - (label_density * scores).sum(dim=(-2, -1)))) / num_sequences +\ + reg_weight * (weights ** 2).sum() / num_sequences + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + weights = weights.detach() + + # Compute "residuals" + scores = filter_layer.apply_filter(feat, weights) + scores_softmax = activation.softmax_reg(scores.reshape(num_images, num_sequences, -1), dim=2, reg=self.softmax_reg).reshape(scores.shape) + res = sample_weight*(scores_softmax - label_density) + + if compute_losses: + losses.append(_compute_loss(scores, weights)) + + # Compute gradient + weights_grad = filter_layer.apply_feat_transpose(feat, res, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Hessian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + sm_scores_grad = scores_softmax * scores_grad + hes_scores_grad = sm_scores_grad - scores_softmax * torch.sum(sm_scores_grad, dim=(-2,-1), keepdim=True) + grad_hes_grad = (scores_grad * hes_scores_grad).reshape(num_images, num_sequences, -1).sum(dim=2).clamp(min=0) + grad_hes_grad = (sample_weight.reshape(sample_weight.shape[0], -1) * grad_hes_grad).sum(dim=0) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = (grad_hes_grad + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + losses.append(_compute_loss(scores, weights)) + + return weights, weight_iterates, losses diff --git a/Stark/external/AR/ltr/models/target_classifier/residual_modules.py b/Stark/external/AR/ltr/models/target_classifier/residual_modules.py new file mode 100755 index 0000000..fcc8772 --- /dev/null +++ b/Stark/external/AR/ltr/models/target_classifier/residual_modules.py @@ -0,0 +1,85 @@ +import torch +import torch.nn as nn +import math +import ltr.models.layers.filter as filter_layer +import ltr.models.layers.activation as activation +from ltr.models.layers.distance import DistanceMap +from pytracking import TensorList + + +class LinearFilterLearnGen(nn.Module): + def __init__(self, feat_stride=16, init_filter_reg=1e-2, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, score_act='bentpar', act_param=None, mask_act='sigmoid'): + super().__init__() + + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.feat_stride = feat_stride + self.distance_map = DistanceMap(num_dist_bins, bin_displacement) + + # Distance coordinates + d = torch.arange(num_dist_bins, dtype=torch.float32).reshape(1,-1,1,1) * bin_displacement + if init_gauss_sigma == 0: + init_gauss = torch.zeros_like(d) + init_gauss[0,0,0,0] = 1 + else: + init_gauss = torch.exp(-1/2 * (d / init_gauss_sigma)**2) + + self.label_map_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.label_map_predictor.weight.data = init_gauss - init_gauss.min() + + mask_layers = [nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False)] + if mask_act == 'sigmoid': + mask_layers.append(nn.Sigmoid()) + init_bias = 0.0 + elif mask_act == 'linear': + init_bias = 0.5 + else: + raise ValueError('Unknown activation') + self.target_mask_predictor = nn.Sequential(*mask_layers) + self.target_mask_predictor[0].weight.data = mask_init_factor * torch.tanh(2.0 - d) + init_bias + + self.spatial_weight_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.spatial_weight_predictor.weight.data.fill_(1.0) + + if score_act == 'bentpar': + self.score_activation = activation.BentIdentPar(act_param) + elif score_act == 'relu': + self.score_activation = activation.LeakyReluPar() + else: + raise ValueError('Unknown activation') + + + def forward(self, meta_parameter: TensorList, feat, bb, sample_weight=None, is_distractor=None): + filter = meta_parameter[0] + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (filter.shape[-2], filter.shape[-1]) + + # Compute scores + scores = filter_layer.apply_filter(feat, filter) + + # Compute distance map + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).reshape(-1, 2).flip((1,)) + if is_distractor is not None: + center[is_distractor.reshape(-1), :] = 99999 + dist_map = self.distance_map(center, scores.shape[-2:]) + + # Compute label map masks and weight + label_map = self.label_map_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + target_mask = self.target_mask_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + spatial_weight = self.spatial_weight_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) * spatial_weight + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(-1, 1, 1, 1) * spatial_weight + + # Compute data residual + scores_act = self.score_activation(scores, target_mask) + data_residual = sample_weight * (scores_act - label_map) + + # Compute regularization residual. Put batch in second dimension + reg_residual = self.filter_reg*filter.reshape(1, num_sequences, -1) + + return TensorList([data_residual, reg_residual]) diff --git a/Stark/external/AR/ltr/models/tracking/__init__.py b/Stark/external/AR/ltr/models/tracking/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/models/tracking/dimpnet.py b/Stark/external/AR/ltr/models/tracking/dimpnet.py new file mode 100755 index 0000000..e4f8504 --- /dev/null +++ b/Stark/external/AR/ltr/models/tracking/dimpnet.py @@ -0,0 +1,342 @@ +import math +import torch +import torch.nn as nn +from collections import OrderedDict +from ltr.models.meta import steepestdescent +import ltr.models.target_classifier.linear_filter as target_clf +import ltr.models.target_classifier.features as clf_features +import ltr.models.target_classifier.initializer as clf_initializer +import ltr.models.target_classifier.optimizer as clf_optimizer +import ltr.models.bbreg as bbmodels +import ltr.models.backbone as backbones +from ltr import model_constructor + + +class DiMPnet(nn.Module): + """The DiMP network. + args: + feature_extractor: Backbone feature extractor network. Must return a dict of feature maps + classifier: Target classification module. + bb_regressor: Bounding box regression module. + classification_layer: Name of the backbone feature layer to use for classification. + bb_regressor_layer: Names of the backbone layers to use for bounding box regression.""" + + def __init__(self, feature_extractor, classifier, bb_regressor, classification_layer, bb_regressor_layer): + super().__init__() + + self.feature_extractor = feature_extractor + self.classifier = classifier + self.bb_regressor = bb_regressor + self.classification_layer = [classification_layer] if isinstance(classification_layer, str) else classification_layer + self.bb_regressor_layer = bb_regressor_layer + self.output_layers = sorted(list(set(self.classification_layer + self.bb_regressor_layer))) + + + def forward(self, train_imgs, test_imgs, train_bb, test_proposals, *args, **kwargs): + """Runs the DiMP network the way it is applied during training. + The forward function is ONLY used for training. Call the individual functions during tracking. + args: + train_imgs: Train image samples (images, sequences, 3, H, W). + test_imgs: Test image samples (images, sequences, 3, H, W). + trian_bb: Target boxes (x,y,w,h) for the train images. Dims (images, sequences, 4). + test_proposals: Proposal boxes to use for the IoUNet (bb_regressor) module. + *args, **kwargs: These are passed to the classifier module. + returns: + test_scores: Classification scores on the test samples. + iou_pred: Predicted IoU scores for the test_proposals.""" + + assert train_imgs.dim() == 5 and test_imgs.dim() == 5, 'Expect 5 dimensional inputs' + + # Extract backbone features + train_feat = self.extract_backbone_features(train_imgs.reshape(-1, *train_imgs.shape[-3:])) + test_feat = self.extract_backbone_features(test_imgs.reshape(-1, *test_imgs.shape[-3:])) + + # Classification features + train_feat_clf = self.get_backbone_clf_feat(train_feat) + test_feat_clf = self.get_backbone_clf_feat(test_feat) + + # Run classifier module + target_scores = self.classifier(train_feat_clf, test_feat_clf, train_bb, *args, **kwargs) + + # Get bb_regressor features + train_feat_iou = self.get_backbone_bbreg_feat(train_feat) + test_feat_iou = self.get_backbone_bbreg_feat(test_feat) + + # Run the IoUNet module + iou_pred = self.bb_regressor(train_feat_iou, test_feat_iou, train_bb, test_proposals) + + return target_scores, iou_pred + + def get_backbone_clf_feat(self, backbone_feat): + feat = OrderedDict({l: backbone_feat[l] for l in self.classification_layer}) + if len(self.classification_layer) == 1: + return feat[self.classification_layer[0]] + return feat + + def get_backbone_bbreg_feat(self, backbone_feat): + return [backbone_feat[l] for l in self.bb_regressor_layer] + + def extract_classification_feat(self, backbone_feat): + return self.classifier.extract_classification_feat(self.get_backbone_clf_feat(backbone_feat)) + + def extract_backbone_features(self, im, layers=None): + if layers is None: + layers = self.output_layers + return self.feature_extractor(im, layers) + + def extract_features(self, im, layers=None): + if layers is None: + layers = self.bb_regressor_layer + ['classification'] + if 'classification' not in layers: + return self.feature_extractor(im, layers) + backbone_layers = sorted(list(set([l for l in layers + self.classification_layer if l != 'classification']))) + all_feat = self.feature_extractor(im, backbone_layers) + all_feat['classification'] = self.extract_classification_feat(all_feat) + return OrderedDict({l: all_feat[l] for l in layers}) + + + +@model_constructor +def dimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + score_act='relu', act_param=None, target_mask_act='sigmoid', + detach_length=float('Inf'), frozen_backbone_layers=()): + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPSteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, init_gauss_sigma=init_gauss_sigma, + num_dist_bins=num_dist_bins, + bin_displacement=bin_displacement, + mask_init_factor=mask_init_factor, + score_act=score_act, act_param=act_param, mask_act=target_mask_act, + detach_length=detach_length) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def dimpnet50(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=0, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=512, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + score_act='relu', act_param=None, target_mask_act='sigmoid', + detach_length=float('Inf'), frozen_backbone_layers=()): + + # Backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + if classification_layer == 'layer3': + feature_dim = 256 + elif classification_layer == 'layer4': + feature_dim = 512 + else: + raise Exception + + clf_feature_extractor = clf_features.residual_bottleneck(feature_dim=feature_dim, + num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPSteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, init_gauss_sigma=init_gauss_sigma, + num_dist_bins=num_dist_bins, + bin_displacement=bin_displacement, + mask_init_factor=mask_init_factor, + score_act=score_act, act_param=act_param, mask_act=target_mask_act, + detach_length=detach_length) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + + +@model_constructor +def L2dimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), hinge_threshold=-999, gauss_sigma=1.0, alpha_eps=0): + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPL2SteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, hinge_threshold=hinge_threshold, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def klcedimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, gauss_sigma=1.0, + iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), alpha_eps=0.0, train_feature_extractor=True, + init_uni_weight=None, optim_min_reg=1e-3, init_initializer='default', normalize_label=False, + label_shrink=0, softmax_reg=None, label_threshold=0, final_relu=False, init_pool_square=False, + frozen_backbone_layers=()): + + if not train_feature_extractor: + frozen_backbone_layers = 'all' + + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim, final_relu=final_relu) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim, init_weights=init_initializer, + pool_square=init_pool_square) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.PrDiMPSteepestDescentNewton(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps, + init_uni_weight=init_uni_weight, + min_filter_reg=optim_min_reg, normalize_label=normalize_label, + label_shrink=label_shrink, softmax_reg=softmax_reg, + label_threshold=label_threshold) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def klcedimpnet50(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=0, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=512, gauss_sigma=1.0, + iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), alpha_eps=0.0, train_feature_extractor=True, + init_uni_weight=None, optim_min_reg=1e-3, init_initializer='default', normalize_label=False, + label_shrink=0, softmax_reg=None, label_threshold=0, final_relu=False, frozen_backbone_layers=()): + + if not train_feature_extractor: + frozen_backbone_layers = 'all' + + # Backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_bottleneck(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim, final_relu=final_relu) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim, init_weights=init_initializer) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.PrDiMPSteepestDescentNewton(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps, + init_uni_weight=init_uni_weight, + min_filter_reg=optim_min_reg, normalize_label=normalize_label, + label_shrink=label_shrink, softmax_reg=softmax_reg, + label_threshold=label_threshold) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net diff --git a/Stark/external/AR/ltr/run_training.py b/Stark/external/AR/ltr/run_training.py new file mode 100755 index 0000000..f6faebd --- /dev/null +++ b/Stark/external/AR/ltr/run_training.py @@ -0,0 +1,55 @@ +import os +import sys +import argparse +import importlib +import multiprocessing +import cv2 as cv +import torch.backends.cudnn + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +import ltr.admin.settings as ws_settings + + +def run_training(train_module, train_name, cudnn_benchmark=True): + """Run a train scripts in train_settings. + args: + train_module: Name of module in the "train_settings/" folder. + train_name: Name of the train settings file. + cudnn_benchmark: Use cudnn benchmark or not (default is True). + """ + + # This is needed to avoid strange crashes related to opencv + cv.setNumThreads(0) + + torch.backends.cudnn.benchmark = cudnn_benchmark + + print('Training: {} {}'.format(train_module, train_name)) + + settings = ws_settings.Settings() + settings.module_name = train_module + settings.script_name = train_name + settings.project_path = 'ltr/{}/{}'.format(train_module, train_name) + + expr_module = importlib.import_module('ltr.train_settings.{}.{}'.format(train_module, train_name)) + expr_func = getattr(expr_module, 'run') + + expr_func(settings) + + +def main(): + parser = argparse.ArgumentParser(description='Run a train scripts in train_settings.') + parser.add_argument('train_module', type=str, help='Name of module in the "train_settings/" folder.') + parser.add_argument('train_name', type=str, help='Name of the train settings file.') + parser.add_argument('--cudnn_benchmark', type=bool, default=True, help='Set cudnn benchmark on (1) or off (0) (default is on).') + + args = parser.parse_args() + + run_training(args.train_module, args.train_name, args.cudnn_benchmark) + + +if __name__ == '__main__': + multiprocessing.set_start_method('spawn', force=True) + main() diff --git a/Stark/external/AR/ltr/train_settings/__init__.py b/Stark/external/AR/ltr/train_settings/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/train_settings/bbreg/__init__.py b/Stark/external/AR/ltr/train_settings/bbreg/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/train_settings/bbreg/atom.py b/Stark/external/AR/ltr/train_settings/bbreg/atom.py new file mode 100755 index 0000000..c6f6b47 --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/bbreg/atom.py @@ -0,0 +1,95 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet with default settings, but additionally using GOT10k for training.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 16, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=50, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=50, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/bbreg/atom_gmm_sampl.py b/Stark/external/AR/ltr/train_settings/bbreg/atom_gmm_sampl.py new file mode 100755 index 0000000..c91776b --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/bbreg/atom_gmm_sampl.py @@ -0,0 +1,96 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet using the baseline ATOM* settings in [https://arxiv.org/abs/1909.12297].' \ + 'Unlike standard ATOM, it employs the GMM-based proposal sampling and minor parameter changes.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'proposal_method': 'gmm', 'boxes_per_frame': 128, 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=200, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=200, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/bbreg/atom_paper.py b/Stark/external/AR/ltr/train_settings/bbreg/atom_paper.py new file mode 100755 index 0000000..ce69596 --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/bbreg/atom_paper.py @@ -0,0 +1,94 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet with default settings according to the paper.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(11))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + trackingnet_val = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(11,12))) + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 16, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, trackingnet_train, coco_train], [1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=50, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([trackingnet_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=50, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/bbreg/atom_prob_ml.py b/Stark/external/AR/ltr/train_settings/bbreg/atom_prob_ml.py new file mode 100755 index 0000000..3cd9284 --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/bbreg/atom_prob_ml.py @@ -0,0 +1,97 @@ +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.bbreg as bbreg_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM using the probabilistic maximum likelihood trained regression model for bounding-box' \ + 'regression presented in [https://arxiv.org/abs/1909.12297].' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0, 0), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)], + 'add_mean_box': True} + data_processing_train = processing.KLBBregProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.KLBBregProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=200, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=200, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = klreg_losses.MLRegression() + actor = bbreg_actors.AtomBBKLActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/dimp/__init__.py b/Stark/external/AR/ltr/train_settings/dimp/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/ltr/train_settings/dimp/dimp18.py b/Stark/external/AR/ltr/train_settings/dimp/dimp18.py new file mode 100755 index 0000000..d138807 --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/dimp/dimp18.py @@ -0,0 +1,118 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for DiMP with ResNet18 as backbone.' + settings.batch_size = 26 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/init_loss', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 8, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + data_processing_train = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=30, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=30, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet18(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, final_conv=True, optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'iou': nn.MSELoss(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'iou': 1, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = actors.DiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters()}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/dimp/dimp50.py b/Stark/external/AR/ltr/train_settings/dimp/dimp50.py new file mode 100755 index 0000000..043b91e --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/dimp/dimp50.py @@ -0,0 +1,119 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for DiMP with ResNet50 as backbone.' + settings.batch_size = 10 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/clf_ce', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 8, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + data_processing_train = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=30, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=30, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'iou': nn.MSELoss(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'iou': 1, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = actors.DiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters()}, + {'params': actor.net.feature_extractor.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/dimp/prdimp18.py b/Stark/external/AR/ltr/train_settings/dimp/prdimp18.py new file mode 100755 index 0000000..ccf891d --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/dimp/prdimp18.py @@ -0,0 +1,119 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for PrDiMP with ResNet18 as backbone.' + settings.batch_size = 26 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + settings.print_stats = ['Loss/total', 'Loss/bb_ce', 'ClfTrain/clf_ce'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz, 'normalize': True} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.klcedimpnet18(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, final_conv=True, optim_init_step=1.0, optim_init_reg=0.05, optim_min_reg=0.05, + gauss_sigma=output_sigma * settings.feature_sz, alpha_eps=0.05, normalize_label=True, init_initializer='zero') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'clf_ce': klreg_losses.KLRegressionGrid()} + + loss_weight = {'bb_ce': 0.0025, 'clf_ce': 0.25, 'clf_ce_init': 0.25, 'clf_ce_iter': 1.0} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.parameters(), 'lr': 1e-3}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters()}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/dimp/prdimp50.py b/Stark/external/AR/ltr/train_settings/dimp/prdimp50.py new file mode 100755 index 0000000..55cfe4f --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/dimp/prdimp50.py @@ -0,0 +1,120 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for PrDiMP with ResNet50 as backbone.' + settings.batch_size = 10 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + settings.print_stats = ['Loss/total', 'Loss/bb_ce', 'ClfTrain/clf_ce'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz, 'normalize': True} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.klcedimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=1.0, optim_init_reg=0.05, optim_min_reg=0.05, + gauss_sigma=output_sigma * settings.feature_sz, alpha_eps=0.05, normalize_label=True, init_initializer='zero') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'clf_ce': klreg_losses.KLRegressionGrid()} + + loss_weight = {'bb_ce': 0.0025, 'clf_ce': 0.25, 'clf_ce_init': 0.25, 'clf_ce_iter': 1.0} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.parameters(), 'lr': 1e-3}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/train_settings/dimp/super_dimp.py b/Stark/external/AR/ltr/train_settings/dimp/super_dimp.py new file mode 100755 index 0000000..a43575d --- /dev/null +++ b/Stark/external/AR/ltr/train_settings/dimp/super_dimp.py @@ -0,0 +1,132 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'SuperDiMP: Combines the DiMP classifier with the PrDiMP bounding box regressor and better' \ + 'training settings (larger batch size, inside_major cropping, and flipping augmentation.' \ + 'Gives results significantly better than both DiMP-50 and PrDiMP-50.' + settings.batch_size = 20 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 6.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 22 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 5.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/init_loss', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05), + tfm.RandomHorizontalFlip(probability=0.5)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.RandomHorizontalFlip(probability=0.5), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + crop_type='inside_major', + max_scale_change=1.5, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + crop_type='inside_major', + max_scale_change=1.5, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=40000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=10000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu', + frozen_backbone_layers=['conv1', 'bn1', 'layer1', 'layer2']) + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'bb_ce': 0.01, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.layer3.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/Stark/external/AR/ltr/trainers/__init__.py b/Stark/external/AR/ltr/trainers/__init__.py new file mode 100755 index 0000000..b4555a3 --- /dev/null +++ b/Stark/external/AR/ltr/trainers/__init__.py @@ -0,0 +1,2 @@ +from .base_trainer import BaseTrainer +from .ltr_trainer import LTRTrainer \ No newline at end of file diff --git a/Stark/external/AR/ltr/trainers/base_trainer.py b/Stark/external/AR/ltr/trainers/base_trainer.py new file mode 100755 index 0000000..535211d --- /dev/null +++ b/Stark/external/AR/ltr/trainers/base_trainer.py @@ -0,0 +1,206 @@ +import os +import glob +import torch +import traceback +from ltr.admin import loading, multigpu + + +class BaseTrainer: + """Base trainer class. Contains functions for training and saving/loading chackpoints. + Trainer classes should inherit from this one and overload the train_epoch function.""" + + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + self.actor = actor + self.optimizer = optimizer + self.lr_scheduler = lr_scheduler + self.loaders = loaders + + self.update_settings(settings) + + self.epoch = 0 + self.stats = {} + + self.device = getattr(settings, 'device', None) + if self.device is None: + self.device = torch.device("cuda:0" if torch.cuda.is_available() and settings.use_gpu else "cpu") + + self.actor.to(self.device) + + def update_settings(self, settings=None): + """Updates the trainer settings. Must be called to update internal settings.""" + if settings is not None: + self.settings = settings + + if self.settings.env.workspace_dir is not None: + self.settings.env.workspace_dir = os.path.expanduser(self.settings.env.workspace_dir) + self._checkpoint_dir = os.path.join(self.settings.env.workspace_dir, 'checkpoints') + if not os.path.exists(self._checkpoint_dir): + os.makedirs(self._checkpoint_dir) + else: + self._checkpoint_dir = None + + + def train(self, max_epochs, load_latest=False, fail_safe=True): + """Do training for the given number of epochs. + args: + max_epochs - Max number of training epochs, + load_latest - Bool indicating whether to resume from latest epoch. + fail_safe - Bool indicating whether the training to automatically restart in case of any crashes. + """ + + epoch = -1 + num_tries = 10 + for i in range(num_tries): + try: + if load_latest: + self.load_checkpoint() + + for epoch in range(self.epoch+1, max_epochs+1): + self.epoch = epoch + + self.train_epoch() + + if self.lr_scheduler is not None: + self.lr_scheduler.step() + + if self._checkpoint_dir: + self.save_checkpoint() + except: + print('Training crashed at epoch {}'.format(epoch)) + if fail_safe: + self.epoch -= 1 + load_latest = True + print('Traceback for the error!') + print(traceback.format_exc()) + print('Restarting training from last epoch ...') + else: + raise + + print('Finished training!') + + + def train_epoch(self): + raise NotImplementedError + + + def save_checkpoint(self): + """Saves a checkpoint of the network and other variables.""" + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + state = { + 'epoch': self.epoch, + 'actor_type': actor_type, + 'net_type': net_type, + 'net': net.state_dict(), + 'net_info': getattr(net, 'info', None), + 'constructor': getattr(net, 'constructor', None), + 'optimizer': self.optimizer.state_dict(), + 'stats': self.stats, + 'settings': self.settings + } + + + directory = '{}/{}'.format(self._checkpoint_dir, self.settings.project_path) + if not os.path.exists(directory): + os.makedirs(directory) + + # First save as a tmp file + tmp_file_path = '{}/{}_ep{:04d}.tmp'.format(directory, net_type, self.epoch) + torch.save(state, tmp_file_path) + + file_path = '{}/{}_ep{:04d}.pth.tar'.format(directory, net_type, self.epoch) + + # Now rename to actual checkpoint. os.rename seems to be atomic if files are on same filesystem. Not 100% sure + os.rename(tmp_file_path, file_path) + + + def load_checkpoint(self, checkpoint = None, fields = None, ignore_fields = None, load_constructor = False): + """Loads a network checkpoint file. + + Can be called in three different ways: + load_checkpoint(): + Loads the latest epoch from the workspace. Use this to continue training. + load_checkpoint(epoch_num): + Loads the network at the given epoch number (int). + load_checkpoint(path_to_checkpoint): + Loads the file from the given absolute path (str). + """ + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + + if checkpoint is None: + # Load most recent checkpoint + checkpoint_list = sorted(glob.glob('{}/{}/{}_ep*.pth.tar'.format(self._checkpoint_dir, + self.settings.project_path, net_type))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + print('No matching checkpoint file found') + return + elif isinstance(checkpoint, int): + # Checkpoint is the epoch number + checkpoint_path = '{}/{}/{}_ep{:04d}.pth.tar'.format(self._checkpoint_dir, self.settings.project_path, + net_type, checkpoint) + elif isinstance(checkpoint, str): + # checkpoint is the path + if os.path.isdir(checkpoint): + checkpoint_list = sorted(glob.glob('{}/*_ep*.pth.tar'.format(checkpoint))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No checkpoint found') + else: + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + checkpoint_dict = loading.torch_load_legacy(checkpoint_path) + + assert net_type == checkpoint_dict['net_type'], 'Network is not of correct type.' + + if fields is None: + fields = checkpoint_dict.keys() + if ignore_fields is None: + ignore_fields = ['settings'] + + # Never load the scheduler. It exists in older checkpoints. + ignore_fields.extend(['lr_scheduler', 'constructor', 'net_type', 'actor_type', 'net_info']) + + # Load all fields + for key in fields: + if key in ignore_fields: + continue + if key == 'net': + net.load_state_dict(checkpoint_dict[key]) + elif key == 'optimizer': + self.optimizer.load_state_dict(checkpoint_dict[key]) + else: + setattr(self, key, checkpoint_dict[key]) + + # Set the net info + if load_constructor and 'constructor' in checkpoint_dict and checkpoint_dict['constructor'] is not None: + net.constructor = checkpoint_dict['constructor'] + if 'net_info' in checkpoint_dict and checkpoint_dict['net_info'] is not None: + net.info = checkpoint_dict['net_info'] + + # Update the epoch in lr scheduler + if 'epoch' in fields: + self.lr_scheduler.last_epoch = self.epoch + + return True diff --git a/Stark/external/AR/ltr/trainers/ltr_trainer.py b/Stark/external/AR/ltr/trainers/ltr_trainer.py new file mode 100755 index 0000000..25030ac --- /dev/null +++ b/Stark/external/AR/ltr/trainers/ltr_trainer.py @@ -0,0 +1,136 @@ +import os +from collections import OrderedDict +from ltr.trainers import BaseTrainer +from ltr.admin.stats import AverageMeter, StatValue +from ltr.admin.tensorboard import TensorboardWriter +import torch +import time + + +class LTRTrainer(BaseTrainer): + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + super().__init__(actor, loaders, optimizer, settings, lr_scheduler) + + self._set_default_settings() + + # Initialize statistics variables + self.stats = OrderedDict({loader.name: None for loader in self.loaders}) + + # Initialize tensorboard + tensorboard_writer_dir = os.path.join(self.settings.env.tensorboard_dir, self.settings.project_path) + self.tensorboard_writer = TensorboardWriter(tensorboard_writer_dir, [l.name for l in loaders]) + + self.move_data_to_gpu = getattr(settings, 'move_data_to_gpu', True) + + def _set_default_settings(self): + # Dict of all default values + default = {'print_interval': 10, + 'print_stats': None, + 'description': ''} + + for param, default_value in default.items(): + if getattr(self.settings, param, None) is None: + setattr(self.settings, param, default_value) + + def cycle_dataset(self, loader): + """Do a cycle of training or validation.""" + + self.actor.train(loader.training) + torch.set_grad_enabled(loader.training) + + self._init_timing() + + for i, data in enumerate(loader, 1): + # get inputs + if self.move_data_to_gpu: + data = data.to(self.device) + + data['epoch'] = self.epoch + data['settings'] = self.settings + + # forward pass + loss, stats = self.actor(data) + + # backward pass and update weights + if loader.training: + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + # update statistics + batch_size = data['train_images'].shape[loader.stack_dim] + self._update_stats(stats, batch_size, loader) + + # print statistics + self._print_stats(i, loader, batch_size) + + def train_epoch(self): + """Do one epoch for each loader.""" + for loader in self.loaders: + if self.epoch % loader.epoch_interval == 0: + self.cycle_dataset(loader) + + self._stats_new_epoch() + self._write_tensorboard() + + def _init_timing(self): + self.num_frames = 0 + self.start_time = time.time() + self.prev_time = self.start_time + + def _update_stats(self, new_stats: OrderedDict, batch_size, loader): + # Initialize stats if not initialized yet + if loader.name not in self.stats.keys() or self.stats[loader.name] is None: + self.stats[loader.name] = OrderedDict({name: AverageMeter() for name in new_stats.keys()}) + + for name, val in new_stats.items(): + if name not in self.stats[loader.name].keys(): + self.stats[loader.name][name] = AverageMeter() + self.stats[loader.name][name].update(val, batch_size) + + def _print_stats(self, i, loader, batch_size): + self.num_frames += batch_size + current_time = time.time() + batch_fps = batch_size / (current_time - self.prev_time) + average_fps = self.num_frames / (current_time - self.start_time) + self.prev_time = current_time + if i % self.settings.print_interval == 0 or i == loader.__len__(): + print_str = '[%s: %d, %d / %d] ' % (loader.name, self.epoch, i, loader.__len__()) + print_str += 'FPS: %.1f (%.1f) , ' % (average_fps, batch_fps) + for name, val in self.stats[loader.name].items(): + if (self.settings.print_stats is None or name in self.settings.print_stats) and hasattr(val, 'avg'): + print_str += '%s: %.5f , ' % (name, val.avg) + print(print_str[:-5]) + + def _stats_new_epoch(self): + # Record learning rate + for loader in self.loaders: + if loader.training: + lr_list = self.lr_scheduler.get_lr() + for i, lr in enumerate(lr_list): + var_name = 'LearningRate/group{}'.format(i) + if var_name not in self.stats[loader.name].keys(): + self.stats[loader.name][var_name] = StatValue() + self.stats[loader.name][var_name].update(lr) + + for loader_stats in self.stats.values(): + if loader_stats is None: + continue + for stat_value in loader_stats.values(): + if hasattr(stat_value, 'new_epoch'): + stat_value.new_epoch() + + def _write_tensorboard(self): + if self.epoch == 1: + self.tensorboard_writer.write_info(self.settings.module_name, self.settings.script_name, self.settings.description) + + self.tensorboard_writer.write_epoch(self.stats, self.epoch) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/ARcm_seg.py b/Stark/external/AR/pytracking/ARcm_seg.py new file mode 100755 index 0000000..70cad5b --- /dev/null +++ b/Stark/external/AR/pytracking/ARcm_seg.py @@ -0,0 +1,106 @@ +import os +import sys +import torch +import numpy as np +import cv2 +import torch.nn as nn +from external.AR.pytracking.utils.loading import load_network +from external.AR.ltr.data.processing_utils_SE import sample_target_SE, transform_image_to_crop_SE, map_mask_back +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + + +def mask_torch2numpy(Pmask): + Pmask_arr = np.array(Pmask.squeeze().cpu()) # (H,W) (0,1) + return Pmask_arr + + +class ARcm_seg(object): + def __init__(self, refine_net_dir, search_factor=2.0, input_sz=256): + self.refine_network = self.get_network(refine_net_dir) + self.search_factor = search_factor + self.input_sz = input_sz + self.mean = np.array([0.485, 0.456, 0.406]).reshape((1,1,3)) + self.std = np.array([0.229, 0.224, 0.225]).reshape((1,1,3)) + + def initialize(self, frame1, bbox1): + ''' + :param frame1: cv array (H,W,3) + :param bbox1: ndarray (4,) + :return: + ''' + '''Step1: get cropped patch(tensor)''' + patch1, h_f, w_f = sample_target_SE(frame1, bbox1, self.search_factor, self.input_sz, mode=cv2.BORDER_CONSTANT) + patch1_tensor = self.img_preprocess(patch1) + '''Step2: get GT's cooridinate on the cropped patch(tensor)''' + crop_sz = torch.Tensor((self.input_sz, self.input_sz)) + bbox1_tensor = self.gt_preprocess(bbox1) # (4,) + bbox1_crop_tensor = transform_image_to_crop_SE(bbox1_tensor, bbox1_tensor, h_f, w_f, crop_sz).cuda() + '''Step3: forward prop (reference branch)''' + with torch.no_grad(): + self.refine_network.forward_ref(patch1_tensor, bbox1_crop_tensor) + + '''refine''' + def get_mask(self, Cframe, Cbbox, dtm=None, vis=False): + ''' + :param Cframe: Current frame(cv2 array) + :param Cbbox: Current bbox (ndarray) (x1,y1,w,h) + :return: mask + ''' + '''Step1: get cropped patch(tensor)''' + Cpatch, h_f, w_f = sample_target_SE(Cframe, Cbbox, self.search_factor, self.input_sz, mode=cv2.BORDER_CONSTANT) + Cpatch_tensor = self.img_preprocess(Cpatch) + + '''Step2: forward prop (test branch)''' + with torch.no_grad(): + if dtm is not None: + '''2020.4.26 support input dtm''' + pred = self.refine_network.forward_test(Cpatch_tensor, dtm, mode='mask') + else: + pred = self.refine_network.forward_test(Cpatch_tensor,mode='mask') + Pmask_arr = mask_torch2numpy(pred) + mask_arr = map_mask_back(Cframe, Cbbox, self.search_factor, Pmask_arr, + mode=cv2.BORDER_CONSTANT) + if vis: + return mask_arr, Cpatch, Pmask_arr + else: + return mask_arr + + def get_network(self,checkpoint_dir): + network = load_network(checkpoint_dir) + network.cuda() + network.eval() + return network + + def img_preprocess(self,img_arr): + '''---> Pytorch tensor(RGB),Normal(-1 to 1,subtract mean, divide std) + input img_arr (H,W,3) + output (1,1,3,H,W) + ''' + norm_img = ((img_arr/255.0) - self.mean)/(self.std) + img_f32 = norm_img.astype(np.float32) + img_tensor = torch.from_numpy(img_f32).cuda() + img_tensor = img_tensor.permute((2,0,1)) + return img_tensor.unsqueeze(dim=0).unsqueeze(dim=0) + + def gt_preprocess(self,gt_arr): + ''' + :param gt: ndarray (4,) + :return: torch tensor (4,) + ''' + return torch.from_numpy(gt_arr.astype(np.float32)) + + +def add_frame_mask(frame, mask, threshold=0.5): + mask_new = (mask>threshold)*255 #(H,W) + frame_new = frame.copy().astype(np.float) + frame_new[...,1] += 0.3*mask_new + frame_new = frame_new.clip(0,255).astype(np.uint8) + return frame_new + + +def add_frame_bbox(frame, refined_box, color): + x1, y1, w, h = refined_box.tolist() + cv2.rectangle(frame, (int(x1), int(y1)), (int(x1 + w), int(y1 + h)), color, 2) + return frame diff --git a/Stark/external/AR/pytracking/VOT/tracker_DiMP.m b/Stark/external/AR/pytracking/VOT/tracker_DiMP.m new file mode 100755 index 0000000..cf99917 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT/tracker_DiMP.m @@ -0,0 +1,32 @@ +% Set path to the python in the pytracking conda environment +python_path = 'PATH_TO_CONDA_INSTALLATION/envs/pytracking/bin/python'; + +% Set path to pytracking +pytracking_path = 'PATH_TO_VISIONML/pytracking'; + +% Set path to trax installation. Check +% https://trax.readthedocs.io/en/latest/tutorial_compiling.html for +% compilation information +trax_path = 'PATH_TO_VOT_TOOLKIT/native/trax'; + +tracker_name = 'dimp'; % Name of the tracker to evaluate +runfile_name = 'dimp18_vot'; % Name of the parameter file to use +debug = 0; + +%% +tracker_label = [tracker_name, '_', runfile_name]; + +% Generate python command +tracker_command = sprintf(['%s -c "import sys; sys.path.append(''%s'');', ... + 'sys.path.append(''%s/support/python'');', ... + 'import run_vot;', ... + 'run_vot.run_vot(''%s'', ''%s'', debug=%d)"'],... + python_path, pytracking_path, trax_path, ... + tracker_name, runfile_name, debug); + + +tracker_interpreter = python_path; + +tracker_linkpath = {[trax_path, '/build'],... + [trax_path, '/build/support/client'],... + [trax_path, '/build/support/opencv']}; diff --git a/Stark/external/AR/pytracking/VOT/trackers.ini b/Stark/external/AR/pytracking/VOT/trackers.ini new file mode 100755 index 0000000..61ae10e --- /dev/null +++ b/Stark/external/AR/pytracking/VOT/trackers.ini @@ -0,0 +1,12 @@ +[DiMP] # +label = DiMP +protocol = traxpython + +command = run_vot; run_vot.run_vot2020('dimp', 'dimp50') # Set the tracker name and the parameter name + +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = PATH_TO_PYTRACKING + +# Additional environment paths +#env_PATH = ;${PATH} + diff --git a/Stark/external/AR/pytracking/VOT/vot.py b/Stark/external/AR/pytracking/VOT/vot.py new file mode 100755 index 0000000..22b4b55 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT/vot.py @@ -0,0 +1,116 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016, 2019 + +""" + +import sys +import copy +import collections + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [str(x) for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, Rectangle) or isinstance(region, Polygon)) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return tuple(image) + + request = self._trax.wait() + + if request.type == 'frame': + image = [str(x) for k, x in request.image.items()] + if len(image) == 1: + image = image[0] + return tuple(image) + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() + diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_065.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_065.py new file mode 100755 index 0000000..96839f8 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_065.py @@ -0,0 +1,6 @@ +from pytracking.VOT2020_super_only_mask_384_HP.dimp_alpha_seg_class import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '1' +# run_vot_exp('dimp','dimp50_vot19','SEbcm',0.60,VIS=False) +run_vot_exp('dimp','super_dimp','ARcm_coco_seg_only_mask_384',0.65,VIS=False) +# run_vot_exp('dimp','super_dimp','ARcm_coco_seg_only_mask_384',0.65,VIS=True) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_seg_class.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_seg_class.py new file mode 100755 index 0000000..41d1bee --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/dimp_alpha_seg_class.py @@ -0,0 +1,159 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + +import cv2 +import torch +import vot +import sys +import time +'''Refine module & Pytracking base trackers''' +# from common_path import * +import os +'''2020.4.24 Use new pytracking library(New DiMP)''' +from pytracking.evaluation import Tracker +'''2020.4.15 ARcm_seg model''' +from pytracking.ARcm_seg import ARcm_seg +'''other utils''' +from pytracking.vot20_utils import * +'''''' +'''DiMP-alpha class''' + + +class DIMP_ALPHA(object): + def __init__(self, tracker_name='dimp', para_name='dimp50_vot19', + refine_model_name='ARcm_coco_seg', threshold=0.15): + self.THRES = threshold + '''create tracker''' + '''DIMP''' + tracker_info = Tracker(tracker_name, para_name, None) + params = tracker_info.get_parameters() + params.visualization = False + params.debug = False + params.visdom_info = {'use_visdom': False, 'server': '127.0.0.1', 'port': 8097} + self.dimp = tracker_info.tracker_class(params) + '''Alpha-Refine''' + project_path = os.path.join(os.path.dirname(__file__),'..','..') + refine_root = os.path.join(project_path, 'ltr/checkpoints/ltr/ARcm_seg/') + refine_path = os.path.join(refine_root, refine_model_name) + '''2020.4.25 input size: 384x384''' + self.alpha = ARcm_seg(refine_path,input_sz=384) + + def initialize(self, img_RGB, mask): + region = rect_from_mask(mask) + self.H, self.W, _ = img_RGB.shape + gt_bbox_np = np.array(region).astype(np.float32) + '''Initialize dimp for specific video''' + gt_bbox_torch = torch.from_numpy(gt_bbox_np) + init_info = {} + init_info['init_bbox'] = gt_bbox_torch + _ = self.dimp.initialize(img_RGB, init_info) + '''initilize refinement module for specific video''' + self.alpha.initialize(img_RGB, np.array(gt_bbox_np)) + + def track(self, img_RGB): + '''TRACK''' + '''base tracker''' + outputs = self.dimp.track(img_RGB) + pred_bbox = outputs['target_bbox'] + '''Step1: Post-Process''' + x1, y1, w, h = pred_bbox + # add boundary and min size limit + x1, y1, x2, y2 = bbox_clip(x1, y1, x1 + w, y1 + h, (self.H, self.W)) + w = x2 - x1 + h = y2 - y1 + new_pos = torch.from_numpy(np.array([y1 + h / 2, x1 + w / 2]).astype(np.float32)) + new_target_sz = torch.from_numpy(np.array([h, w]).astype(np.float32)) + new_scale = torch.sqrt(new_target_sz.prod() / self.dimp.base_target_sz.prod()) + ##### update + self.dimp.pos = new_pos.clone() + self.dimp.target_sz = new_target_sz + self.dimp.target_scale = new_scale + bbox_new = [x1,y1,w,h] + '''Step2: Mask report''' + pred_mask, search, search_mask = self.alpha.get_mask(img_RGB, np.array(bbox_new),vis=True) + final_mask = (pred_mask > self.THRES).astype(np.uint8) + search_region = search.astype(np.uint8) + search_mask = (search_mask > self.THRES).astype(np.uint8) + return bbox_new, final_mask, search_region, search_mask + + +def run_vot_exp(tracker_name,para_name,refine_model_name,threshold,VIS=False): + + torch.set_num_threads(1) + # torch.cuda.set_device(CUDA_ID) # set GPU id + # save_root = os.path.join('/media/masterbin-iiau/WIN_SSD/vot20_debug',para_name) + save_root = os.path.join('/home/alphabin/Desktop/AlphaRefine_submit/vot20_debug',para_name) + if VIS and (not os.path.exists(save_root)): + os.mkdir(save_root) + tracker = DIMP_ALPHA(tracker_name=tracker_name,para_name=para_name, + refine_model_name=refine_model_name,threshold=threshold) + handle = vot.VOT("mask") + selection = handle.region() + imagefile = handle.frame() + if not imagefile: + sys.exit(0) + if VIS: + '''for vis''' + seq_name = imagefile.split('/')[-3] + save_v_dir = os.path.join(save_root,seq_name) + if not os.path.exists(save_v_dir): + os.mkdir(save_v_dir) + cur_time = int(time.time() % 10000) + save_dir = os.path.join(save_v_dir, str(cur_time)) + if not os.path.exists(save_dir): + os.makedirs(save_dir) + + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + # mask given by the toolkit ends with the target (zero-padding to the right and down is needed) + mask = make_full_size(selection, (image.shape[1], image.shape[0])) + tracker.initialize(image, mask) + + while True: + imagefile = handle.frame() + if not imagefile: + break + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + b1, m, search, search_m = tracker.track(image) + handle.report(m) + if VIS: + '''Visualization''' + # original image + image_ori = image[:,:,::-1].copy() # RGB --> BGR + image_name = imagefile.split('/')[-1] + save_path = os.path.join(save_dir, image_name) + cv2.imwrite(save_path, image_ori) + # dimp box + image_b = image_ori.copy() + cv2.rectangle(image_b, (int(b1[0]), int(b1[1])), + (int(b1[0] + b1[2]), int(b1[1] + b1[3])), (0, 0, 255), 2) + image_b_name = image_name.replace('.jpg','_bbox.jpg') + save_path = os.path.join(save_dir, image_b_name) + cv2.imwrite(save_path, image_b) + # search region + search_bgr = search[:,:,::-1].copy() + search_name = image_name.replace('.jpg', '_search.jpg') + save_path = os.path.join(save_dir, search_name) + cv2.imwrite(save_path, search_bgr) + # search region mask + search_bgr_m = search_bgr.astype(np.float32) + search_bgr_m[:, :, 1] += 127.0 * search_m + search_bgr_m[:, :, 2] += 127.0 * search_m + contours, _ = cv2.findContours(search_m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + search_bgr_m = cv2.drawContours(search_bgr_m, contours, -1, (0, 255, 255), 4) + search_bgr_m = search_bgr_m.clip(0,255).astype(np.uint8) + search_name_m = image_name.replace('.jpg', '_search_mask.jpg') + save_path = os.path.join(save_dir, search_name_m) + cv2.imwrite(save_path, search_bgr_m) + # original image + mask + image_m = image_ori.copy().astype(np.float32) + image_m[:, :, 1] += 127.0 * m + image_m[:, :, 2] += 127.0 * m + contours, _ = cv2.findContours(m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + image_m = cv2.drawContours(image_m, contours, -1, (0, 255, 255), 2) + image_m = image_m.clip(0, 255).astype(np.uint8) + image_mask_name_m = image_name.replace('.jpg', '_mask.jpg') + save_path = os.path.join(save_dir, image_mask_name_m) + cv2.imwrite(save_path, image_m) diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_alpha_seg_class.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_alpha_seg_class.py new file mode 100755 index 0000000..724ec79 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_alpha_seg_class.py @@ -0,0 +1,136 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + +import cv2 +import torch +import vot +import sys +import time +import os +from lib.test.evaluation import Tracker +from pytracking.ARcm_seg import ARcm_seg +from pytracking.vot20_utils import * + + +class STARK_ALPHA_SEG(object): + def __init__(self, tracker_name='stark_s', para_name='baseline', + refine_model_name='ARcm_coco_seg', threshold=0.15): + self.THRES = threshold + '''create tracker''' + '''STARK''' + tracker_info = Tracker(tracker_name, para_name, "vot20", None) + params = tracker_info.get_parameters() + params.visualization = False + params.debug = False + params.visdom_info = {'use_visdom': False, 'server': '127.0.0.1', 'port': 8097} + self.stark = tracker_info.create_tracker(params) + '''Alpha-Refine''' + project_path = os.path.join(os.path.dirname(__file__), '..', '..') + refine_root = os.path.join(project_path, 'ltr/checkpoints/ltr/ARcm_seg/') + refine_path = os.path.join(refine_root, refine_model_name) + '''2020.4.25 input size: 384x384''' + self.alpha = ARcm_seg(refine_path, input_sz=384) + + def initialize(self, img_RGB, mask): + region = rect_from_mask(mask) + self.H, self.W, _ = img_RGB.shape + gt_bbox_np = np.array(region).astype(np.float32) + '''Initialize STARK for specific video''' + init_info = {'init_bbox': list(gt_bbox_np)} + _ = self.stark.initialize(img_RGB, init_info) + '''initilize refinement module for specific video''' + self.alpha.initialize(img_RGB, np.array(gt_bbox_np)) + + def track(self, img_RGB): + '''TRACK''' + '''base tracker''' + outputs = self.stark.track(img_RGB) + pred_bbox = outputs['target_bbox'] + '''Step2: Mask report''' + pred_mask, search, search_mask = self.alpha.get_mask(img_RGB, np.array(pred_bbox), vis=True) + final_mask = (pred_mask > self.THRES).astype(np.uint8) + search_region = search.astype(np.uint8) + search_mask = (search_mask > self.THRES).astype(np.uint8) + return pred_bbox, final_mask, search_region, search_mask + + +def run_vot_exp(tracker_name, para_name, refine_model_name, threshold, VIS=False): + + torch.set_num_threads(1) + # torch.cuda.set_device(CUDA_ID) # set GPU id + # save_root = os.path.join('/media/masterbin-iiau/WIN_SSD/vot20_debug',para_name) + save_root = os.path.join('/data/sda/v-yanbi/iccv21/LittleBoy/vot20/vot20_debug', para_name) + if VIS and (not os.path.exists(save_root)): + os.makedirs(save_root) + tracker = STARK_ALPHA_SEG(tracker_name=tracker_name, para_name=para_name, + refine_model_name=refine_model_name, threshold=threshold) + handle = vot.VOT("mask") + selection = handle.region() + imagefile = handle.frame() + if not imagefile: + sys.exit(0) + if VIS: + '''for vis''' + seq_name = imagefile.split('/')[-3] + save_v_dir = os.path.join(save_root,seq_name) + if not os.path.exists(save_v_dir): + os.mkdir(save_v_dir) + cur_time = int(time.time() % 10000) + save_dir = os.path.join(save_v_dir, str(cur_time)) + if not os.path.exists(save_dir): + os.makedirs(save_dir) + + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + # mask given by the toolkit ends with the target (zero-padding to the right and down is needed) + mask = make_full_size(selection, (image.shape[1], image.shape[0])) + tracker.initialize(image, mask) + + while True: + imagefile = handle.frame() + if not imagefile: + break + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + b1, m, search, search_m = tracker.track(image) + handle.report(m) + if VIS: + '''Visualization''' + # original image + image_ori = image[:,:,::-1].copy() # RGB --> BGR + image_name = imagefile.split('/')[-1] + save_path = os.path.join(save_dir, image_name) + cv2.imwrite(save_path, image_ori) + # dimp box + image_b = image_ori.copy() + cv2.rectangle(image_b, (int(b1[0]), int(b1[1])), + (int(b1[0] + b1[2]), int(b1[1] + b1[3])), (0, 0, 255), 2) + image_b_name = image_name.replace('.jpg','_bbox.jpg') + save_path = os.path.join(save_dir, image_b_name) + cv2.imwrite(save_path, image_b) + # search region + search_bgr = search[:,:,::-1].copy() + search_name = image_name.replace('.jpg', '_search.jpg') + save_path = os.path.join(save_dir, search_name) + cv2.imwrite(save_path, search_bgr) + # search region mask + search_bgr_m = search_bgr.astype(np.float32) + search_bgr_m[:, :, 1] += 127.0 * search_m + search_bgr_m[:, :, 2] += 127.0 * search_m + contours, _ = cv2.findContours(search_m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + search_bgr_m = cv2.drawContours(search_bgr_m, contours, -1, (0, 255, 255), 4) + search_bgr_m = search_bgr_m.clip(0,255).astype(np.uint8) + search_name_m = image_name.replace('.jpg', '_search_mask.jpg') + save_path = os.path.join(save_dir, search_name_m) + cv2.imwrite(save_path, search_bgr_m) + # original image + mask + image_m = image_ori.copy().astype(np.float32) + image_m[:, :, 1] += 127.0 * m + image_m[:, :, 2] += 127.0 * m + contours, _ = cv2.findContours(m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + image_m = cv2.drawContours(image_m, contours, -1, (0, 255, 255), 2) + image_m = image_m.clip(0, 255).astype(np.uint8) + image_mask_name_m = image_name.replace('.jpg', '_mask.jpg') + save_path = os.path.join(save_dir, image_mask_name_m) + cv2.imwrite(save_path, image_m) diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_s50_ar.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_s50_ar.py new file mode 100755 index 0000000..ff2b590 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_s50_ar.py @@ -0,0 +1,5 @@ +from pytracking.VOT2020_super_only_mask_384_HP.stark_alpha_seg_class import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '3' +run_vot_exp('stark_s', 'baseline', + 'ARcm_coco_seg_only_mask_384', 0.65, VIS=False) diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st101_ar.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st101_ar.py new file mode 100755 index 0000000..a51d1a3 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st101_ar.py @@ -0,0 +1,5 @@ +from pytracking.VOT2020_super_only_mask_384_HP.stark_alpha_seg_class import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '2' +run_vot_exp('stark_st', 'baseline_R101', + 'ARcm_coco_seg_only_mask_384', 0.65, VIS=False) diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st50_ar.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st50_ar.py new file mode 100755 index 0000000..92ca152 --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/stark_st50_ar.py @@ -0,0 +1,5 @@ +from pytracking.VOT2020_super_only_mask_384_HP.stark_alpha_seg_class import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '1' +run_vot_exp('stark_st', 'baseline', + 'ARcm_coco_seg_only_mask_384', 0.65, VIS=False) diff --git a/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/vot.py b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/vot.py new file mode 100755 index 0000000..53e5a1f --- /dev/null +++ b/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP/vot.py @@ -0,0 +1,113 @@ +""" +\file vot.py +@brief Python utility functions for VOT integration +@author Luka Cehovin, Alessio Dore +@date 2016 +""" + +import sys +import copy +import collections +import numpy as np + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON, trax.Region.MASK]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels, customMetadata=dict(vot="python")) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + elif isinstance(request.region, trax.Mask): + self._region = request.region.array(True) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [x.path() for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + Arguments: + region: region for the frame + """ + assert(isinstance(region, (Rectangle, Polygon, np.ndarray))) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + elif isinstance(region, np.ndarray): + tregion = trax.Mask.create(region) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + image = [x.path() for k, x in request.image.items()] + if len(image) == 1: + return image[0] + return image + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() diff --git a/Stark/external/AR/pytracking/__init__.py b/Stark/external/AR/pytracking/__init__.py new file mode 100755 index 0000000..7a12375 --- /dev/null +++ b/Stark/external/AR/pytracking/__init__.py @@ -0,0 +1 @@ +from pytracking.libs import TensorList, TensorDict diff --git a/Stark/external/AR/pytracking/analysis/__init__.py b/Stark/external/AR/pytracking/analysis/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/analysis/evaluate_vos.py b/Stark/external/AR/pytracking/analysis/evaluate_vos.py new file mode 100755 index 0000000..6b14302 --- /dev/null +++ b/Stark/external/AR/pytracking/analysis/evaluate_vos.py @@ -0,0 +1,199 @@ +import os +import numpy as np +import torch +import pandas as pd +from collections import OrderedDict +from ltr.data.image_loader import imread_indexed +from pytracking.evaluation import get_dataset +from pathlib import Path +from pytracking.analysis.plot_results import generate_formatted_report + +import pytracking.analysis.vos_utils as utils + +# Originally db_eval_sequence() in the davis challenge toolkit: +def evaluate_sequence(seq_name, segmentations, annotations, object_info, measure='J'): + """ + Evaluate video sequence results. + + Arguments: + segmentations (dict of ndarray): segmentation labels. + annotations (dict of ndarray): ground-truth labels. + object_info dict: {object_id: first_frame_index} + + measure evaluation metric (J,F) + """ + + results = dict(raw=OrderedDict()) + + _measures = {'J': utils.davis_jaccard_measure, 'F': utils.davis_f_measure} + _statistics = {'decay': utils.decay, 'mean': utils.mean, 'recall': utils.recall, 'std': utils.std} + + for obj_id, first_frame in object_info.items(): + + r = np.ones((len(annotations))) * np.nan + + for i, (an, sg) in enumerate(zip(annotations, segmentations)): + if list(annotations.keys()).index(first_frame) < i < len(annotations) - 1: + r[i] = _measures[measure](annotations[an] == obj_id, segmentations[sg] == obj_id) + + results['raw'][obj_id] = r + + for stat, stat_fn in _statistics.items(): + results[stat] = [float(stat_fn(r)) for r in results['raw'].values()] + + return results + + +def evaluate_dataset(results_path, dset_name, measure='J', to_file=True, scores=False, sequences=None, quiet=False): + dset = get_dataset(dset_name) + results = OrderedDict() + dset_scores = [] + dset_decay = [] + dset_recall = [] + + if to_file: + f = open(results_path / ("evaluation-%s.txt" % measure), "w") + + def _print(msg): + if not quiet: + print(msg) + if to_file: + print(msg, file=f) + + if sequences is not None: + sequences = [sequences] if not isinstance(sequences, (list, tuple)) else sequences + + target_names = [] + for j, sequence in enumerate(dset): + if (sequences is not None) and (sequence.name not in sequences): + continue + + # Load all frames + frames = sequence.ground_truth_seg + + annotations = OrderedDict() + segmentations = OrderedDict() + + for f in frames: + if f is None: + continue + + file = Path(f) + annotations[file.name] = imread_indexed(file) + if not scores: + segmentations[file.name] = imread_indexed(os.path.join(results_path, sequence.name, file.name)) + else: + raise NotImplementedError + # Find object ids and starting frames + + object_info = dict() + + for f_id, d in sequence.init_data.items(): + for obj_id in d['object_ids']: + object_info[int(obj_id)] = Path(d['mask']).name + + if 0 in object_info: # Remove background + object_info.pop(0) + + # Evaluate + n_seqs = len(dset) + n_objs = len(object_info) + seq_name = sequence.name + + _print("%d/%d: %s: %d object%s" % (j + 1, n_seqs, seq_name, n_objs, "s" if n_objs > 1 else "")) + r = evaluate_sequence(seq_name, segmentations, annotations, object_info, measure=measure) + results[seq_name] = r + + # Print scores, per frame and object, ignoring NaNs + + per_obj_score = [] # Per-object accuracies, averaged over the sequence + per_frame_score = [] # Per-frame accuracies, averaged over the objects + + for obj_id, score in r['raw'].items(): + target_names.append('{}_{}'.format(seq_name, obj_id)) + per_frame_score.append(score) + s = utils.mean(score) # Sequence average for one object + per_obj_score.append(s) + if n_objs > 1: + _print("joint {obj}: acc {score:.3f} ┊{apf}┊".format(obj=obj_id, score=s, apf=utils.text_bargraph(score))) + + # Print mean object score per frame and final score + dset_decay.extend(r['decay']) + dset_recall.extend(r['recall']) + dset_scores.extend(per_obj_score) + + seq_score = utils.mean(per_obj_score) # Final score + seq_mean_score = utils.nanmean(np.array(per_frame_score), axis=0) # Mean object score per frame + + # Print sequence results + _print("final : acc {seq:.3f} ({dset:.3f}) ┊{apf}┊".format( + seq=seq_score, dset=np.mean(dset_scores), apf=utils.text_bargraph(seq_mean_score))) + + _print("%s: %.3f, recall: %.3f, decay: %.3f" % (measure, utils.mean(dset_scores), utils.mean(dset_recall), utils.mean(dset_decay))) + + if to_file: + f.close() + + return target_names, dset_scores, dset_recall, dset_decay + + +def evaluate_vos(trackers, dataset='yt2019_jjval', force=False): + """ evaluate a list of trackers on a vos dataset. + + args: + trackers - list of trackers to evaluate + dataset - name of the dataset + force - Force re-evaluation. If False, the pre-computed results are loaded if available + """ + csv_name_global = f'{dataset}_global_results.csv' + csv_name_per_sequence = f'{dataset}_per-sequence_results.csv' + + table_g_all = [] + table_seq_all = [] + scores = {'J-Mean': [], 'J-Recall': [], 'J-Decay': []} + display_names = [] + for t in trackers: + if t.display_name is not None: + disp_name = t.display_name + elif t.run_id is not None: + disp_name = '{} {}_{:03d}'.format(t.name, t.parameter_name, t.run_id) + else: + disp_name = '{} {}'.format(t.name, t.parameter_name) + + display_names.append(disp_name) + results_path = t.segmentation_dir + + csv_name_global_path = os.path.join(results_path, csv_name_global) + csv_name_per_sequence_path = os.path.join(results_path, csv_name_per_sequence) + if os.path.exists(csv_name_global_path) and os.path.exists(csv_name_per_sequence_path) and not force: + table_g = pd.read_csv(csv_name_global_path) + table_seq = pd.read_csv(csv_name_per_sequence_path) + else: + seq_names, dset_scores, dset_recall, dset_decay = evaluate_dataset(results_path, dataset, measure='J', + to_file=False, scores=False, + sequences=None) + g_measures = ['J-Mean', 'J-Recall', 'J-Decay'] + g_res = np.array([utils.mean(dset_scores), utils.mean(dset_recall), utils.mean(dset_decay)]) + g_res = np.reshape(g_res, [1, len(g_res)]) + + table_g = pd.DataFrame(data=g_res, columns=g_measures) + with open(csv_name_global_path, 'w') as f: + table_g.to_csv(f, index=False, float_format="%.3f") + + seq_measures = ['Sequence', 'J-Mean', 'J-Recall', 'J-Decay'] + + table_seq = pd.DataFrame(data=list(zip(seq_names, dset_scores, dset_recall, dset_decay)), columns=seq_measures) + with open(csv_name_per_sequence_path, 'w') as f: + table_seq.to_csv(f, index=False, float_format="%.3f") + + scores['J-Mean'].append(table_g['J-Mean'].values[0]*100) + scores['J-Recall'].append(table_g['J-Recall'].values[0]*100) + scores['J-Decay'].append(table_g['J-Decay'].values[0]*100) + + table_g_all.append(table_g) + table_seq_all.append(table_seq) + + report = generate_formatted_report(display_names, scores) + print(report) + + return table_g_all, table_seq_all diff --git a/Stark/external/AR/pytracking/analysis/extract_results.py b/Stark/external/AR/pytracking/analysis/extract_results.py new file mode 100755 index 0000000..c54cfbd --- /dev/null +++ b/Stark/external/AR/pytracking/analysis/extract_results.py @@ -0,0 +1,183 @@ +import os +import sys +import importlib +import numpy as np +from pytracking.utils.load_text import load_text +import torch +import pickle +from tqdm import tqdm + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation.environment import env_settings + + +def calc_err_center(pred_bb, anno_bb, normalized=False): + pred_center = pred_bb[:, :2] + 0.5 * (pred_bb[:, 2:] - 1.0) + anno_center = anno_bb[:, :2] + 0.5 * (anno_bb[:, 2:] - 1.0) + + if normalized: + pred_center = pred_center / anno_bb[:, 2:] + anno_center = anno_center / anno_bb[:, 2:] + + err_center = ((pred_center - anno_center)**2).sum(1).sqrt() + return err_center + + +def calc_iou_overlap(pred_bb, anno_bb): + tl = torch.max(pred_bb[:, :2], anno_bb[:, :2]) + br = torch.min(pred_bb[:, :2] + pred_bb[:, 2:] - 1.0, anno_bb[:, :2] + anno_bb[:, 2:] - 1.0) + sz = (br - tl + 1.0).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = pred_bb[:, 2:].prod(dim=1) + anno_bb[:, 2:].prod(dim=1) - intersection + + return intersection / union + + +def calc_seq_err_robust(pred_bb, anno_bb, dataset, target_visible=None): + pred_bb = pred_bb.clone() + + # Check if invalid values are present + if torch.isnan(pred_bb).any() or (pred_bb[:, 2:] < 0.0).any(): + raise Exception('Error: Invalid results') + + if torch.isnan(anno_bb).any(): + if dataset == 'uav': + pass + else: + raise Exception('Warning: NaNs in annotation') + + if (pred_bb[:, 2:] == 0.0).any(): + for i in range(1, pred_bb.shape[0]): + if (pred_bb[i, 2:] == 0.0).any() and not torch.isnan(anno_bb[i, :]).any(): + pred_bb[i, :] = pred_bb[i-1, :] + + if pred_bb.shape[0] != anno_bb.shape[0]: + if dataset == 'lasot': + if pred_bb.shape[0] > anno_bb.shape[0]: + # For monkey-17, there is a mismatch for some trackers. + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + raise Exception('Mis-match in tracker prediction and GT lengths') + else: + # print('Warning: Mis-match in tracker prediction and GT lengths') + if pred_bb.shape[0] > anno_bb.shape[0]: + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + pad = torch.zeros((anno_bb.shape[0] - pred_bb.shape[0], 4)).type_as(pred_bb) + pred_bb = torch.cat((pred_bb, pad), dim=0) + + pred_bb[0, :] = anno_bb[0, :] + + if target_visible is not None: + target_visible = target_visible.bool() + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) & target_visible + else: + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) + + err_center = calc_err_center(pred_bb, anno_bb) + err_center_normalized = calc_err_center(pred_bb, anno_bb, normalized=True) + err_overlap = calc_iou_overlap(pred_bb, anno_bb) + + # handle invalid anno cases + if dataset in ['uav']: + err_center[~valid] = -1.0 + else: + err_center[~valid] = float("Inf") + err_center_normalized[~valid] = -1.0 + err_overlap[~valid] = -1.0 + + if dataset == 'lasot': + err_center_normalized[~target_visible] = float("Inf") + err_center[~target_visible] = float("Inf") + + if torch.isnan(err_overlap).any(): + raise Exception('Nans in calculated overlap') + return err_overlap, err_center, err_center_normalized, valid + + +def extract_results(trackers, dataset, report_name, skip_missing_seq=False, plot_bin_gap=0.05, + exclude_invalid_frames=False): + settings = env_settings() + eps = 1e-16 + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + if not os.path.exists(result_plot_path): + os.makedirs(result_plot_path) + + threshold_set_overlap = torch.arange(0.0, 1.0 + plot_bin_gap, plot_bin_gap, dtype=torch.float64) + threshold_set_center = torch.arange(0, 51, dtype=torch.float64) + threshold_set_center_norm = torch.arange(0, 51, dtype=torch.float64) / 100.0 + + avg_overlap_all = torch.zeros((len(dataset), len(trackers)), dtype=torch.float64) + ave_success_rate_plot_overlap = torch.zeros((len(dataset), len(trackers), threshold_set_overlap.numel()), + dtype=torch.float32) + ave_success_rate_plot_center = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + ave_success_rate_plot_center_norm = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + + valid_sequence = torch.ones(len(dataset), dtype=torch.uint8) + + for seq_id, seq in enumerate(tqdm(dataset)): + # Load anno + anno_bb = torch.tensor(seq.ground_truth_rect) + target_visible = torch.tensor(seq.target_visible, dtype=torch.uint8) if seq.target_visible is not None else None + for trk_id, trk in enumerate(trackers): + # Load results + base_results_path = '{}/{}'.format(trk.results_dir, seq.name) + results_path = '{}.txt'.format(base_results_path) + + if os.path.isfile(results_path): + pred_bb = torch.tensor(load_text(str(results_path), delimiter=('\t', ','), dtype=np.float64)) + else: + if skip_missing_seq: + valid_sequence[seq_id] = 0 + break + else: + raise Exception('Result not found. {}'.format(results_path)) + + # Calculate measures + err_overlap, err_center, err_center_normalized, valid_frame = calc_seq_err_robust( + pred_bb, anno_bb, seq.dataset, target_visible) + + avg_overlap_all[seq_id, trk_id] = err_overlap[valid_frame].mean() + + if exclude_invalid_frames: + seq_length = valid_frame.long().sum() + else: + seq_length = anno_bb.shape[0] + + if seq_length <= 0: + raise Exception('Seq length zero') + + ave_success_rate_plot_overlap[seq_id, trk_id, :] = (err_overlap.view(-1, 1) > threshold_set_overlap.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center[seq_id, trk_id, :] = (err_center.view(-1, 1) <= threshold_set_center.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center_norm[seq_id, trk_id, :] = (err_center_normalized.view(-1, 1) <= threshold_set_center_norm.view(1, -1)).sum(0).float() / seq_length + + print('\n\nComputed results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + # Prepare dictionary for saving data + seq_names = [s.name for s in dataset] + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + + eval_data = {'sequences': seq_names, 'trackers': tracker_names, + 'valid_sequence': valid_sequence.tolist(), + 'ave_success_rate_plot_overlap': ave_success_rate_plot_overlap.tolist(), + 'ave_success_rate_plot_center': ave_success_rate_plot_center.tolist(), + 'ave_success_rate_plot_center_norm': ave_success_rate_plot_center_norm.tolist(), + 'avg_overlap_all': avg_overlap_all.tolist(), + 'threshold_set_overlap': threshold_set_overlap.tolist(), + 'threshold_set_center': threshold_set_center.tolist(), + 'threshold_set_center_norm': threshold_set_center_norm.tolist()} + + with open(result_plot_path + '/eval_data.pkl', 'wb') as fh: + pickle.dump(eval_data, fh) + + return eval_data diff --git a/Stark/external/AR/pytracking/analysis/playback_results.py b/Stark/external/AR/pytracking/analysis/playback_results.py new file mode 100755 index 0000000..f611f72 --- /dev/null +++ b/Stark/external/AR/pytracking/analysis/playback_results.py @@ -0,0 +1,176 @@ +import os +import sys +import importlib +import numpy as np +import torch +import time +import matplotlib.patches as patches +import cv2 as cv +import matplotlib.pyplot as plt +from pytracking.analysis.plot_results import get_plot_draw_styles +from pytracking.utils.plotting import draw_figure +from pytracking.evaluation import get_dataset, trackerlist + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + + +class Display: + def __init__(self, sequence_length, plot_draw_styles, sequence_name): + self.active = True + self.frame_number = 0 + self.pause_mode = True + self.step_size = 0 + self.step_direction = 'forward' + self.fig, self.ax = plt.subplots(1) + self.fig.canvas.mpl_connect('key_press_event', self.key_callback_fn) + plt.tight_layout() + + self.sequence_length = sequence_length + self.sequence_name = sequence_name + self.plot_draw_styles = plot_draw_styles + + def key_callback_fn(self, event): + if event.key == ' ': + self.pause_mode = not self.pause_mode + self.step_size = 0 + self.step_direction = 'forward' + elif event.key == 'right': + if self.pause_mode: + self.frame_number += 1 + + if self.frame_number >= self.sequence_length: + self.frame_number = self.sequence_length - 1 + elif self.step_direction == 'stop': + self.step_direction = 'forward' + self.step_size = 0 + elif self.step_direction == 'backward' and self.step_size == 0: + self.step_direction = 'stop' + else: + self.step_size += 1 + elif event.key == 'left': + if self.pause_mode: + self.frame_number -= 1 + + if self.frame_number < 0: + self.frame_number = 0 + elif self.step_direction == 'stop': + self.step_direction = 'backward' + self.step_size = 0 + elif self.step_direction == 'forward' and self.step_size == 0: + self.step_direction = 'stop' + else: + self.step_size -= 1 + elif event.key == 'escape' or event.key == 'q': + self.active = False + + def _get_speed(self): + delta = 0 + if self.step_direction == 'forward': + delta = 2 ** abs(self.step_size) + elif self.step_direction == 'backward': + delta = -1 * 2 ** abs(self.step_size) + + return delta + + def step(self): + delta = self._get_speed() + + self.frame_number += delta + if self.frame_number < 0: + self.frame_number = 0 + elif self.frame_number >= self.sequence_length: + self.frame_number = self.sequence_length - 1 + + def show(self, image, bb_list, trackers, gt=None): + self.ax.cla() + self.ax.imshow(image) + + # Draw rects + rect_handles = [] + for i, bb in enumerate(bb_list): + rect = patches.Rectangle((bb[0], bb[1]), bb[2], bb[3], linewidth=1, + edgecolor=self.plot_draw_styles[i]['color'], facecolor='none') + self.ax.add_patch(rect) + + rect_handles.append(patches.Rectangle((bb[0], bb[1]), bb[2], bb[3], linewidth=1, + edgecolor=self.plot_draw_styles[i]['color'], + facecolor=self.plot_draw_styles[i]['color'], + label=trackers[i])) + + if gt is not None: + rect = patches.Rectangle((gt[0], gt[1]), gt[2], gt[3], linewidth=2, edgecolor='g', + facecolor='none') + self.ax.add_patch(rect) + rect_handles.append(rect) + + self.ax.set_axis_off() + self.ax.axis('equal') + plt.legend(handles=rect_handles, loc=4, borderaxespad=0.) + mode = 'manual' if self.pause_mode else 'auto ' + speed = self._get_speed() + self.fig.suptitle('Sequence: {} Mode: {} Speed: {:d}x'.format(self.sequence_name, mode, speed), + fontsize=14) + draw_figure(self.fig) + + +def read_image(image_file: str): + im = cv.imread(image_file) + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + + +def _get_display_name(tracker): + if tracker.display_name is None: + if tracker.run_id is not None: + return '{}_{}_{:03d}'.format(tracker.name, tracker.parameter_name, tracker.run_id) + else: + return '{}_{}'.format(tracker.name, tracker.parameter_name) + else: + return tracker.display_name + + +def playback_results(trackers, sequence): + """ + Playback saved results of input trackers for a particular sequence. You can navigate the sequence using left/right + arrow keys. You can also change to 'auto' mode by pressing space bar, in which case the sequence will be replayed + at a particular speed. The speed for playback in 'auto' mode can be controlled using the left/right arrow keys. + You can exit the application using escape or q keys. + """ + plot_draw_styles = get_plot_draw_styles() + + tracker_results = [] + # Load results + for trk_id, trk in enumerate(trackers): + # Load results + base_results_path = '{}/{}'.format(trk.results_dir, sequence.name) + results_path = '{}.txt'.format(base_results_path) + + if os.path.isfile(results_path): + try: + pred_bb = torch.tensor(np.loadtxt(str(results_path), dtype=np.float64)) + except: + pred_bb = torch.tensor(np.loadtxt(str(results_path), delimiter=',', dtype=np.float64)) + else: + raise Exception('Result not found. {}'.format(results_path)) + + tracker_results.append(pred_bb) + + # Convert to list of shape seq_length * num_trackers * 4 + tracker_results = torch.stack(tracker_results, dim=1).tolist() + tracker_names = [_get_display_name(t) for t in trackers] + + display = Display(len(tracker_results), plot_draw_styles, sequence.name) + + while display.active: + frame_number = display.frame_number + image = read_image(sequence.frames[frame_number]) + + display.show(image, tracker_results[frame_number], tracker_names) + + time.sleep(0.01) + if display.pause_mode and display.frame_number == frame_number: + time.sleep(0.1) + elif not display.pause_mode: + display.step() + diff --git a/Stark/external/AR/pytracking/analysis/plot_results.py b/Stark/external/AR/pytracking/analysis/plot_results.py new file mode 100755 index 0000000..f75cb3d --- /dev/null +++ b/Stark/external/AR/pytracking/analysis/plot_results.py @@ -0,0 +1,483 @@ +import tikzplotlib +import matplotlib +import matplotlib.pyplot as plt +import os +import torch +import pickle +import json +from pytracking.evaluation.environment import env_settings +from pytracking.analysis.extract_results import extract_results + + +def get_plot_draw_styles(): + plot_draw_style = [{'color': (1.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 1.0), 'line_style': '-'}, + {'color': (0.5, 0.5, 0.5), 'line_style': '-'}, + {'color': (136.0 / 255.0, 0.0, 21.0 / 255.0), 'line_style': '-'}, + {'color': (1.0, 127.0 / 255.0, 39.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 162.0 / 255.0, 232.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 0.5, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.5, 0.2), 'line_style': '-'}, + {'color': (0.1, 0.4, 0.0), 'line_style': '-'}, + {'color': (0.6, 0.3, 0.9), 'line_style': '-'}, + {'color': (0.4, 0.7, 0.1), 'line_style': '-'}, + {'color': (0.2, 0.1, 0.7), 'line_style': '-'}, + {'color': (0.7, 0.6, 0.2), 'line_style': '-'}] + + return plot_draw_style + + +def check_eval_data_is_valid(eval_data, trackers, dataset): + """ Checks if the pre-computed results are valid""" + seq_names = [s.name for s in dataset] + seq_names_saved = eval_data['sequences'] + + tracker_names_f = [(t.name, t.parameter_name, t.run_id) for t in trackers] + tracker_names_f_saved = [(t['name'], t['param'], t['run_id']) for t in eval_data['trackers']] + + return seq_names == seq_names_saved and tracker_names_f == tracker_names_f_saved + + +def merge_multiple_runs(eval_data): + new_tracker_names = [] + ave_success_rate_plot_overlap_merged = [] + ave_success_rate_plot_center_merged = [] + ave_success_rate_plot_center_norm_merged = [] + avg_overlap_all_merged = [] + + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) + + trackers = eval_data['trackers'] + merged = torch.zeros(len(trackers), dtype=torch.uint8) + for i in range(len(trackers)): + if merged[i]: + continue + base_tracker = trackers[i] + new_tracker_names.append(base_tracker) + + match = [t['name'] == base_tracker['name'] and t['param'] == base_tracker['param'] for t in trackers] + match = torch.tensor(match) + + ave_success_rate_plot_overlap_merged.append(ave_success_rate_plot_overlap[:, match, :].mean(1)) + ave_success_rate_plot_center_merged.append(ave_success_rate_plot_center[:, match, :].mean(1)) + ave_success_rate_plot_center_norm_merged.append(ave_success_rate_plot_center_norm[:, match, :].mean(1)) + avg_overlap_all_merged.append(avg_overlap_all[:, match].mean(1)) + + merged[match] = 1 + + ave_success_rate_plot_overlap_merged = torch.stack(ave_success_rate_plot_overlap_merged, dim=1) + ave_success_rate_plot_center_merged = torch.stack(ave_success_rate_plot_center_merged, dim=1) + ave_success_rate_plot_center_norm_merged = torch.stack(ave_success_rate_plot_center_norm_merged, dim=1) + avg_overlap_all_merged = torch.stack(avg_overlap_all_merged, dim=1) + + eval_data['trackers'] = new_tracker_names + eval_data['ave_success_rate_plot_overlap'] = ave_success_rate_plot_overlap_merged.tolist() + eval_data['ave_success_rate_plot_center'] = ave_success_rate_plot_center_merged.tolist() + eval_data['ave_success_rate_plot_center_norm'] = ave_success_rate_plot_center_norm_merged.tolist() + eval_data['avg_overlap_all'] = avg_overlap_all_merged.tolist() + + return eval_data + + +def get_tracker_display_name(tracker): + if tracker['disp_name'] is None: + if tracker['run_id'] is None: + disp_name = '{}_{}'.format(tracker['name'], tracker['param']) + else: + disp_name = '{}_{}_{:03d}'.format(tracker['name'], tracker['param'], + tracker['run_id']) + else: + disp_name = tracker['disp_name'] + + return disp_name + + +def plot_draw_save(y, x, scores, trackers, plot_draw_styles, result_plot_path, plot_opts): + # Plot settings + font_size = plot_opts.get('font_size', 12) + font_size_axis = plot_opts.get('font_size_axis', 13) + line_width = plot_opts.get('line_width', 2) + font_size_legend = plot_opts.get('font_size_legend', 13) + + plot_type = plot_opts['plot_type'] + legend_loc = plot_opts['legend_loc'] + + xlabel = plot_opts['xlabel'] + ylabel = plot_opts['ylabel'] + xlim = plot_opts['xlim'] + ylim = plot_opts['ylim'] + + title = plot_opts['title'] + + matplotlib.rcParams.update({'font.size': font_size}) + matplotlib.rcParams.update({'axes.titlesize': font_size_axis}) + matplotlib.rcParams.update({'axes.titleweight': 'black'}) + matplotlib.rcParams.update({'axes.labelsize': font_size_axis}) + + fig, ax = plt.subplots() + + index_sort = scores.argsort(descending=False) + + plotted_lines = [] + legend_text = [] + + for id, id_sort in enumerate(index_sort): + line = ax.plot(x.tolist(), y[id_sort, :].tolist(), + linewidth=line_width, + color=plot_draw_styles[index_sort.numel() - id - 1]['color'], + linestyle=plot_draw_styles[index_sort.numel() - id - 1]['line_style']) + + plotted_lines.append(line[0]) + + tracker = trackers[id_sort] + disp_name = get_tracker_display_name(tracker) + + legend_text.append('{} [{:.1f}]'.format(disp_name, scores[id_sort])) + + ax.legend(plotted_lines[::-1], legend_text[::-1], loc=legend_loc, fancybox=False, edgecolor='black', + fontsize=font_size_legend, framealpha=1.0) + + ax.set(xlabel=xlabel, + ylabel=ylabel, + xlim=xlim, ylim=ylim, + title=title) + + ax.grid(True, linestyle='-.') + fig.tight_layout() + + tikzplotlib.save('{}/{}_plot.tex'.format(result_plot_path, plot_type)) + fig.savefig('{}/{}_plot.pdf'.format(result_plot_path, plot_type), dpi=300, format='pdf', transparent=True) + plt.draw() + + +def check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation=False, **kwargs): + # Load data + settings = env_settings() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data_path = os.path.join(result_plot_path, 'eval_data.pkl') + + if os.path.isfile(eval_data_path) and not force_evaluation: + with open(eval_data_path, 'rb') as fh: + eval_data = pickle.load(fh) + else: + # print('Pre-computed evaluation data not found. Computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + + if not check_eval_data_is_valid(eval_data, trackers, dataset): + # print('Pre-computed evaluation data invalid. Re-computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + else: + # Update display names + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + eval_data['trackers'] = tracker_names + + return eval_data + + +def get_auc_curve(ave_success_rate_plot_overlap, valid_sequence): + ave_success_rate_plot_overlap = ave_success_rate_plot_overlap[valid_sequence, :, :] + auc_curve = ave_success_rate_plot_overlap.mean(0) * 100.0 + auc = auc_curve.mean(-1) + + return auc_curve, auc + + +def get_prec_curve(ave_success_rate_plot_center, valid_sequence): + ave_success_rate_plot_center = ave_success_rate_plot_center[valid_sequence, :, :] + prec_curve = ave_success_rate_plot_center.mean(0) * 100.0 + prec_score = prec_curve[:, 20] + + return prec_curve, prec_score + + +def plot_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), force_evaluation=False, **kwargs): + """ + Plot results for the given trackers + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success', + 'prec' (precision), and 'norm_prec' (normalized precision) + """ + # Load data + settings = env_settings() + + plot_draw_styles = get_plot_draw_styles() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nPlotting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + print('\nGenerating plots for: {}'.format(report_name)) + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 100), 'title': 'Success plot'} + plot_draw_save(auc_curve, threshold_set_overlap, auc, tracker_names, plot_draw_styles, result_plot_path, success_plot_opts) + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + threshold_set_center = torch.tensor(eval_data['threshold_set_center']) + + precision_plot_opts = {'plot_type': 'precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold [pixels]', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 50), 'ylim': (0, 100), 'title': 'Precision plot'} + plot_draw_save(prec_curve, threshold_set_center, prec_score, tracker_names, plot_draw_styles, result_plot_path, + precision_plot_opts) + + # ******************************** Norm Precision Plot ************************************** + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + threshold_set_center_norm = torch.tensor(eval_data['threshold_set_center_norm']) + + norm_precision_plot_opts = {'plot_type': 'norm_precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 0.5), 'ylim': (0, 100), 'title': 'Normalized Precision plot'} + plot_draw_save(prec_curve, threshold_set_center_norm, prec_score, tracker_names, plot_draw_styles, result_plot_path, + norm_precision_plot_opts) + + plt.show() + + +def generate_formatted_report(row_labels, scores, table_name=''): + name_width = max([len(d) for d in row_labels] + [len(table_name)]) + 5 + min_score_width = 10 + + report_text = '\n{label: <{width}} |'.format(label=table_name, width=name_width) + + score_widths = [max(min_score_width, len(k) + 3) for k in scores.keys()] + + for s, s_w in zip(scores.keys(), score_widths): + report_text = '{prev} {s: <{width}} |'.format(prev=report_text, s=s, width=s_w) + + report_text = '{prev}\n'.format(prev=report_text) + + for trk_id, d_name in enumerate(row_labels): + # display name + report_text = '{prev}{tracker: <{width}} |'.format(prev=report_text, tracker=d_name, + width=name_width) + for (score_type, score_value), s_w in zip(scores.items(), score_widths): + report_text = '{prev} {score: <{width}} |'.format(prev=report_text, + score='{:0.2f}'.format(score_value[trk_id].item()), + width=s_w) + report_text = '{prev}\n'.format(prev=report_text) + + return report_text + + +def print_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), **kwargs): + """ Print the results for the given trackers in a formatted table + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success' (prints AUC, OP50, and OP75 scores), + 'prec' (prints precision score), and 'norm_prec' (prints normalized precision score) + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nReporting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + scores = {} + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + scores['AUC'] = auc + scores['OP50'] = auc_curve[:, threshold_set_overlap == 0.50] + scores['OP75'] = auc_curve[:, threshold_set_overlap == 0.75] + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + scores['Precision'] = prec_score + + # ******************************** Norm Precision Plot ********************************* + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + norm_prec_curve, norm_prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + scores['Norm Precision'] = norm_prec_score + + # Print + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + report_text = generate_formatted_report(tracker_disp_names, scores, table_name=report_name) + print(report_text) + + +def plot_got_success(trackers, report_name): + """ Plot success plot for GOT-10k dataset using the json reports. + Save the json reports from http://got-10k.aitestunion.com/leaderboard in the directory set to + env_settings.got_reports_path + + The tracker name in the experiment file should be set to the name of the report file for that tracker, + e.g. DiMP50_report_2019_09_02_15_44_25 if the report is name DiMP50_report_2019_09_02_15_44_25.json + + args: + trackers - List of trackers to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + """ + # Load data + settings = env_settings() + plot_draw_styles = get_plot_draw_styles() + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + auc_curve = torch.zeros((len(trackers), 101)) + scores = torch.zeros(len(trackers)) + + # Load results + tracker_names = [] + for trk_id, trk in enumerate(trackers): + json_path = '{}/{}.json'.format(settings.got_reports_path, trk.name) + + if os.path.isfile(json_path): + with open(json_path, 'r') as f: + eval_data = json.load(f) + else: + raise Exception('Report not found {}'.format(json_path)) + + if len(eval_data.keys()) > 1: + raise Exception + + # First field is the tracker name. Index it out + eval_data = eval_data[list(eval_data.keys())[0]] + if 'succ_curve' in eval_data.keys(): + curve = eval_data['succ_curve'] + ao = eval_data['ao'] + elif 'overall' in eval_data.keys() and 'succ_curve' in eval_data['overall'].keys(): + curve = eval_data['overall']['succ_curve'] + ao = eval_data['overall']['ao'] + else: + raise Exception('Invalid JSON file {}'.format(json_path)) + + auc_curve[trk_id, :] = torch.tensor(curve) * 100.0 + scores[trk_id] = ao * 100.0 + + tracker_names.append({'name': trk.name, 'param': trk.parameter_name, 'run_id': trk.run_id, + 'disp_name': trk.display_name}) + + threshold_set_overlap = torch.arange(0.0, 1.01, 0.01, dtype=torch.float64) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 100), 'title': 'Success plot'} + plot_draw_save(auc_curve, threshold_set_overlap, scores, tracker_names, plot_draw_styles, result_plot_path, + success_plot_opts) + plt.show() + + +def print_per_sequence_results(trackers, dataset, report_name, merge_results=False, + filter_criteria=None, **kwargs): + """ Print per-sequence results for the given trackers. Additionally, the sequences to list can be filtered using + the filter criteria. + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + filter_criteria - Filter sequence results which are reported. Following modes are supported + None: No filtering. Display results for all sequences in dataset + 'ao_min': Only display sequences for which the minimum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences where at least one tracker performs poorly. + 'ao_max': Only display sequences for which the maximum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences all tracker performs poorly. + 'delta_ao': Only display sequences for which the performance of different trackers vary by at + least filter_criteria['threshold'] in average overlap (AO) score. This mode can + be used to select sequences where the behaviour of the trackers greatly differ + between each other. + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + sequence_names = eval_data['sequences'] + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) * 100.0 + + # Filter sequences + if filter_criteria is not None: + if filter_criteria['mode'] == 'ao_min': + min_ao = avg_overlap_all.min(dim=1)[0] + valid_sequence = valid_sequence & (min_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'ao_max': + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & (max_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'delta_ao': + min_ao = avg_overlap_all.min(dim=1)[0] + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & ((max_ao - min_ao) > filter_criteria['threshold']) + else: + raise Exception + + avg_overlap_all = avg_overlap_all[valid_sequence, :] + sequence_names = [s + ' (ID={})'.format(i) for i, (s, v) in enumerate(zip(sequence_names, valid_sequence.tolist())) if v] + + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + + scores_per_tracker = {k: avg_overlap_all[:, i] for i, k in enumerate(tracker_disp_names)} + report_text = generate_formatted_report(sequence_names, scores_per_tracker) + + print(report_text) diff --git a/Stark/external/AR/pytracking/analysis/vos_utils.py b/Stark/external/AR/pytracking/analysis/vos_utils.py new file mode 100755 index 0000000..49f46d6 --- /dev/null +++ b/Stark/external/AR/pytracking/analysis/vos_utils.py @@ -0,0 +1,235 @@ +import warnings +import numpy as np +from skimage.morphology import binary_dilation, disk +from math import floor + + +def text_bargraph(values): + + blocks = np.array(('u', ' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', 'o')) + nsteps = len(blocks)-2-1 + hstep = 1 / (2*nsteps) + values = np.array(values) + nans = np.isnan(values) + values[nans] = 0 # '░' + indices = ((values + hstep) * nsteps + 1).astype(np.int) + indices[values < 0] = 0 + indices[values > 1] = len(blocks)-1 + graph = blocks[indices] + graph[nans] = '░' + graph = str.join('', graph) + return graph + + +# ---------------------------------------------------------------------------- +# The 2017 DAVIS Challenge on Video Object Segmentation +# ----------------------------------------------------------------------------- +# Copyright (c) 2017 Federico Perazzi +# Licensed under the BSD License [see LICENSE for details] +# Written by Federico Perazzi (federico@disneyresearch.com) +# Adapted from DAVIS 2016 (Federico Perazzi) +# ---------------------------------------------------------------------------- + +# Originally db_eval_iou() in the davis challenge toolkit: +def davis_jaccard_measure(fg_mask, gt_mask): + """ Compute region similarity as the Jaccard Index. + + :param fg_mask: (ndarray): binary segmentation map. + :param gt_mask: (ndarray): binary annotation map. + :return: jaccard (float): region similarity + """ + + gt_mask = gt_mask.astype(np.bool) + fg_mask = fg_mask.astype(np.bool) + + if np.isclose(np.sum(gt_mask), 0) and np.isclose(np.sum(fg_mask), 0): + return 1 + else: + return np.sum((gt_mask & fg_mask)) / \ + np.sum((gt_mask | fg_mask), dtype=np.float32) + + +def davis_jaccard_measure_torch(fg_mask, gt_mask): + """ Compute region similarity as the Jaccard Index. + + :param fg_mask: (ndarray): binary segmentation map. + :param gt_mask: (ndarray): binary annotation map. + :return: jaccard (float): region similarity + """ + + #gt_mask = gt_mask.astype(np.bool) + #fg_mask = fg_mask.astype(np.bool) + + if gt_mask.sum() == 0 and fg_mask.sum() == 0: + return 1 + else: + return (gt_mask & fg_mask).sum() / \ + (gt_mask | fg_mask).sum().float() + +# Originally db_eval_boundary() in the davis challenge toolkit: +def davis_f_measure(foreground_mask, gt_mask, bound_th=0.008): + """ + Compute mean,recall and decay from per-frame evaluation. + Calculates precision/recall for boundaries between foreground_mask and + gt_mask using morphological operators to speed it up. + + Arguments: + foreground_mask (ndarray): binary segmentation image. + gt_mask (ndarray): binary annotated image. + + Returns: + F (float): boundaries F-measure + P (float): boundaries precision + R (float): boundaries recall + """ + assert np.atleast_3d(foreground_mask).shape[2] == 1 + + bound_pix = bound_th if bound_th >= 1 else \ + np.ceil(bound_th * np.linalg.norm(foreground_mask.shape)) + + # Get the pixel boundaries of both masks + fg_boundary = seg2bmap(foreground_mask) + gt_boundary = seg2bmap(gt_mask) + + fg_dil = binary_dilation(fg_boundary, disk(bound_pix)) + gt_dil = binary_dilation(gt_boundary, disk(bound_pix)) + + # Get the intersection + gt_match = gt_boundary * fg_dil + fg_match = fg_boundary * gt_dil + + # Area of the intersection + n_fg = np.sum(fg_boundary) + n_gt = np.sum(gt_boundary) + + # % Compute precision and recall + if n_fg == 0 and n_gt > 0: + precision = 1 + recall = 0 + elif n_fg > 0 and n_gt == 0: + precision = 0 + recall = 1 + elif n_fg == 0 and n_gt == 0: + precision = 1 + recall = 1 + else: + precision = np.sum(fg_match) / float(n_fg) + recall = np.sum(gt_match) / float(n_gt) + + # Compute F measure + if precision + recall == 0: + F = 0 + else: + F = 2 * precision * recall / (precision + recall) + + return F + + +def seg2bmap(seg, width=None, height=None): + """ + From a segmentation, compute a binary boundary map with 1 pixel wide + boundaries. The boundary pixels are offset by 1/2 pixel towards the + origin from the actual segment boundary. + + Arguments: + seg : Segments labeled from 1..k. + width : Width of desired bmap <= seg.shape[1] + height : Height of desired bmap <= seg.shape[0] + + Returns: + bmap (ndarray): Binary boundary map. + + David Martin + January 2003 + """ + + seg = seg.astype(np.bool) + seg[seg > 0] = 1 + + assert np.atleast_3d(seg).shape[2] == 1 + + width = seg.shape[1] if width is None else width + height = seg.shape[0] if height is None else height + + h, w = seg.shape[:2] + + ar1 = float(width) / float(height) + ar2 = float(w) / float(h) + + assert not (width > w | height > h | abs(ar1 - ar2) > 0.01), \ + 'Can''t convert %dx%d seg to %dx%d bmap.' % (w, h, width, height) + + e = np.zeros_like(seg) + s = np.zeros_like(seg) + se = np.zeros_like(seg) + + e[:, :-1] = seg[:, 1:] + s[:-1, :] = seg[1:, :] + se[:-1, :-1] = seg[1:, 1:] + + b = seg ^ e | seg ^ s | seg ^ se + b[-1, :] = seg[-1, :] ^ e[-1, :] + b[:, -1] = seg[:, -1] ^ s[:, -1] + b[-1, -1] = 0 + + if w == width and h == height: + bmap = b + else: + bmap = np.zeros((height, width)) + for x in range(w): + for y in range(h): + if b[y, x]: + j = 1 + floor((y - 1) + height / h) + i = 1 + floor((x - 1) + width / h) + bmap[j, i] = 1 + + return bmap + + +def nanmean(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + return np.nanmean(*args, **kwargs) + + +def mean(X): + """ + Compute average ignoring NaN values. + """ + return np.nanmean(X) + + +def recall(X, threshold=0.5): + """ + Fraction of values of X scoring higher than 'threshold' + """ + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + x = X[~np.isnan(X)] + x = mean(x > threshold) + return x + + +def decay(X, n_bins=4): + """ + Performance loss over time. + """ + X = X[~np.isnan(X)] + ids = np.round(np.linspace(1, len(X), n_bins + 1) + 1e-10) - 1 + ids = ids.astype(np.uint8) + + D_bins = [X[ids[i]:ids[i + 1] + 1] for i in range(0, 4)] + + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + D = np.nanmean(D_bins[0]) - np.nanmean(D_bins[3]) + return D + + +def std(X): + """ + Compute standard deviation. + """ + return np.nanstd(X) + + diff --git a/Stark/external/AR/pytracking/evaluation/__init__.py b/Stark/external/AR/pytracking/evaluation/__init__.py new file mode 100755 index 0000000..5ee6d34 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/__init__.py @@ -0,0 +1,3 @@ +from .data import Sequence +from .tracker import Tracker, trackerlist +from .datasets import get_dataset \ No newline at end of file diff --git a/Stark/external/AR/pytracking/evaluation/data.py b/Stark/external/AR/pytracking/evaluation/data.py new file mode 100755 index 0000000..6446efb --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/data.py @@ -0,0 +1,169 @@ +import numpy as np +from pytracking.evaluation.environment import env_settings +from ltr.data.image_loader import imread_indexed +from collections import OrderedDict + + +class BaseDataset: + """Base class for all datasets.""" + def __init__(self): + self.env_settings = env_settings() + + def __len__(self): + """Overload this function in your dataset. This should return number of sequences in the dataset.""" + raise NotImplementedError + + def get_sequence_list(self): + """Overload this in your dataset. Should return the list of sequences in the dataset.""" + raise NotImplementedError + + +class Sequence: + """Class for the sequence in an evaluation.""" + def __init__(self, name, frames, dataset, ground_truth_rect, ground_truth_seg=None, init_data=None, + object_class=None, target_visible=None, object_ids=None, multiobj_mode=False): + self.name = name + self.frames = frames + self.dataset = dataset + self.ground_truth_rect = ground_truth_rect + self.ground_truth_seg = ground_truth_seg + self.object_class = object_class + self.target_visible = target_visible + self.object_ids = object_ids + self.multiobj_mode = multiobj_mode + self.init_data = self._construct_init_data(init_data) + self._ensure_start_frame() + + def _ensure_start_frame(self): + # Ensure start frame is 0 + start_frame = min(list(self.init_data.keys())) + if start_frame > 0: + self.frames = self.frames[start_frame:] + if self.ground_truth_rect is not None: + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + for obj_id, gt in self.ground_truth_rect.items(): + self.ground_truth_rect[obj_id] = gt[start_frame:,:] + else: + self.ground_truth_rect = self.ground_truth_rect[start_frame:,:] + if self.ground_truth_seg is not None: + self.ground_truth_seg = self.ground_truth_seg[start_frame:] + assert len(self.frames) == len(self.ground_truth_seg) + + if self.target_visible is not None: + self.target_visible = self.target_visible[start_frame:] + self.init_data = {frame-start_frame: val for frame, val in self.init_data.items()} + + def _construct_init_data(self, init_data): + if init_data is not None: + if not self.multiobj_mode: + assert self.object_ids is None or len(self.object_ids) == 1 + for frame, init_val in init_data.items(): + if 'bbox' in init_val and isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = init_val['bbox'][self.object_ids[0]] + # convert to list + for frame, init_val in init_data.items(): + if 'bbox' in init_val: + if isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = OrderedDict({obj_id: list(init) for obj_id, init in init_val['bbox'].items()}) + else: + init_val['bbox'] = list(init_val['bbox']) + else: + init_data = {0: dict()} # Assume start from frame 0 + + if self.object_ids is not None: + init_data[0]['object_ids'] = self.object_ids + + if self.ground_truth_rect is not None: + if self.multiobj_mode: + assert isinstance(self.ground_truth_rect, (dict, OrderedDict)) + init_data[0]['bbox'] = OrderedDict({obj_id: list(gt[0,:]) for obj_id, gt in self.ground_truth_rect.items()}) + else: + assert self.object_ids is None or len(self.object_ids) == 1 + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + init_data[0]['bbox'] = list(self.ground_truth_rect[self.object_ids[0]][0, :]) + else: + init_data[0]['bbox'] = list(self.ground_truth_rect[0,:]) + + if self.ground_truth_seg is not None: + init_data[0]['mask'] = self.ground_truth_seg[0] + + return init_data + + def init_info(self): + info = self.frame_info(frame_num=0) + return info + + def frame_info(self, frame_num): + info = self.object_init_data(frame_num=frame_num) + return info + + def init_bbox(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_bbox') + + def init_mask(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_mask') + + def get_info(self, keys, frame_num=None): + info = dict() + for k in keys: + val = self.get(k, frame_num=frame_num) + if val is not None: + info[k] = val + return info + + def object_init_data(self, frame_num=None) -> dict: + if frame_num is None: + frame_num = 0 + if frame_num not in self.init_data: + return dict() + + init_data = dict() + for key, val in self.init_data[frame_num].items(): + if val is None: + continue + init_data['init_'+key] = val + + if 'init_mask' in init_data and init_data['init_mask'] is not None: + anno = imread_indexed(init_data['init_mask']) + if not self.multiobj_mode and self.object_ids is not None: + assert len(self.object_ids) == 1 + anno = (anno == int(self.object_ids[0])).astype(np.uint8) + init_data['init_mask'] = anno + + if self.object_ids is not None: + init_data['object_ids'] = self.object_ids + init_data['sequence_object_ids'] = self.object_ids + + return init_data + + def target_class(self, frame_num=None): + return self.object_class + + def get(self, name, frame_num=None): + return getattr(self, name)(frame_num) + + def __repr__(self): + return "{self.__class__.__name__} {self.name}, length={len} frames".format(self=self, len=len(self.frames)) + + + +class SequenceList(list): + """List of sequences. Supports the addition operator to concatenate sequence lists.""" + def __getitem__(self, item): + if isinstance(item, str): + for seq in self: + if seq.name == item: + return seq + raise IndexError('Sequence name not in the dataset.') + elif isinstance(item, int): + return super(SequenceList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return SequenceList([super(SequenceList, self).__getitem__(i) for i in item]) + else: + return SequenceList(super(SequenceList, self).__getitem__(item)) + + def __add__(self, other): + return SequenceList(super(SequenceList, self).__add__(other)) + + def copy(self): + return SequenceList(super(SequenceList, self).copy()) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/evaluation/datasets.py b/Stark/external/AR/pytracking/evaluation/datasets.py new file mode 100755 index 0000000..6f39e2e --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/datasets.py @@ -0,0 +1,61 @@ +from collections import namedtuple +import importlib +from pytracking.evaluation.data import SequenceList + +DatasetInfo = namedtuple('DatasetInfo', ['module', 'class_name', 'kwargs']) + +pt = "pytracking.evaluation.%sdataset" # Useful abbreviations to reduce the clutter + +dataset_dict = dict( + otb=DatasetInfo(module=pt % "otb", class_name="OTBDataset", kwargs=dict()), + nfs=DatasetInfo(module=pt % "nfs", class_name="NFSDataset", kwargs=dict()), + uav=DatasetInfo(module=pt % "uav", class_name="UAVDataset", kwargs=dict()), + tpl=DatasetInfo(module=pt % "tpl", class_name="TPLDataset", kwargs=dict()), + tpl_nootb=DatasetInfo(module=pt % "tpl", class_name="TPLDataset", kwargs=dict(exclude_otb=True)), + vot=DatasetInfo(module=pt % "vot", class_name="VOTDataset", kwargs=dict()), + trackingnet=DatasetInfo(module=pt % "trackingnet", class_name="TrackingNetDataset", kwargs=dict()), + got10k_test=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='test')), + got10k_val=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='val')), + got10k_ltrval=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='ltrval')), + lasot=DatasetInfo(module=pt % "lasot", class_name="LaSOTDataset", kwargs=dict()), + dv2017_val=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", kwargs=dict(version='2017', split='val')), + dv2016_val=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", kwargs=dict(version='2016', split='val')), + dv2017_test_dev=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", + kwargs=dict(version='2017', split='test-dev')), + dv2017_test_chal=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", + kwargs=dict(version='2017', split='test-challenge')), + yt2019_test=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='test')), + yt2019_valid=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='valid')), + yt2019_valid_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='valid', all_frames=True)), + yt2018_valid_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2018', split='valid', all_frames=True)), + yt2018_jjval=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2018', split='jjvalid')), + yt2019_jjval=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='jjvalid', cleanup=['starts'])), + yt2019_jjval_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='jjvalid', all_frames=True, cleanup=['starts'])), +) + + +def load_dataset(name: str): + """ Import and load a single dataset.""" + name = name.lower() + dset_info = dataset_dict.get(name) + if dset_info is None: + raise ValueError('Unknown dataset \'%s\'' % name) + + m = importlib.import_module(dset_info.module) + dataset = getattr(m, dset_info.class_name)(**dset_info.kwargs) # Call the constructor + return dataset.get_sequence_list() + + +def get_dataset(*args): + """ Get a single or set of datasets.""" + dset = SequenceList() + for name in args: + dset.extend(load_dataset(name)) + return dset \ No newline at end of file diff --git a/Stark/external/AR/pytracking/evaluation/environment.py b/Stark/external/AR/pytracking/evaluation/environment.py new file mode 100755 index 0000000..171adac --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/environment.py @@ -0,0 +1,66 @@ +import importlib +import os + + +class EnvSettings: + def __init__(self): + pytracking_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + + self.results_path = '{}/tracking_results/'.format(pytracking_path) + self.segmentation_path = '{}/segmentation_results/'.format(pytracking_path) + self.network_path = '{}/networks/'.format(pytracking_path) + self.result_plot_path = '{}/result_plots/'.format(pytracking_path) + self.otb_path = '' + self.nfs_path = '' + self.uav_path = '' + self.tpl_path = '' + self.vot_path = '' + self.got10k_path = '' + self.lasot_path = '' + self.trackingnet_path = '' + self.davis_dir = '' + self.youtubevos_dir = '' + + self.got_packed_results_path = '' + self.got_reports_path = '' + self.tn_packed_results_path = '' + + +def create_default_local_file(): + comment = {'results_path': 'Where to store tracking results', + 'network_path': 'Where tracking networks are stored.'} + + path = os.path.join(os.path.dirname(__file__), 'local.py') + with open(path, 'w') as f: + settings = EnvSettings() + + f.write('from pytracking.evaluation.environment import EnvSettings\n\n') + f.write('def local_env_settings():\n') + f.write(' settings = EnvSettings()\n\n') + f.write(' # Set your local paths here.\n\n') + + for attr in dir(settings): + comment_str = None + if attr in comment: + comment_str = comment[attr] + attr_val = getattr(settings, attr) + if not attr.startswith('__') and not callable(attr_val): + if comment_str is None: + f.write(' settings.{} = \'{}\'\n'.format(attr, attr_val)) + else: + f.write(' settings.{} = \'{}\' # {}\n'.format(attr, attr_val, comment_str)) + f.write('\n return settings\n\n') + + +def env_settings(): + env_module_name = 'pytracking.evaluation.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.local_env_settings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + # Create a default file + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. ' + 'Then try to run again.'.format(env_file)) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/evaluation/got10kdataset.py b/Stark/external/AR/pytracking/evaluation/got10kdataset.py new file mode 100755 index 0000000..43bb3b7 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/got10kdataset.py @@ -0,0 +1,56 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text +import os + + +class GOT10KDataset(BaseDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + def __init__(self, split): + super().__init__() + # Split can be test, val, or ltrval (a validation split consisting of videos from the official train set) + if split == 'test' or split == 'val': + self.base_path = os.path.join(self.env_settings.got10k_path, split) + else: + self.base_path = os.path.join(self.env_settings.got10k_path, 'train') + + self.sequence_list = self._get_sequence_list(split) + self.split = split + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + anno_path = '{}/{}/groundtruth.txt'.format(self.base_path, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + frames_path = '{}/{}'.format(self.base_path, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'got10k', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self, split): + with open('{}/list.txt'.format(self.base_path)) as f: + sequence_list = f.read().splitlines() + + if split == 'ltrval': + with open('{}/got10k_val_split.txt'.format(self.env_settings.dataspec_path)) as f: + seq_ids = f.read().splitlines() + + sequence_list = [sequence_list[int(x)] for x in seq_ids] + return sequence_list diff --git a/Stark/external/AR/pytracking/evaluation/lasotdataset.py b/Stark/external/AR/pytracking/evaluation/lasotdataset.py new file mode 100755 index 0000000..fdefcbf --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/lasotdataset.py @@ -0,0 +1,342 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class LaSOTDataset(BaseDataset): + """ + LaSOT test set consisting of 280 videos (see Protocol-II in the LaSOT paper) + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.lasot_path + self.sequence_list = self._get_sequence_list() + self.clean_list = self.clean_seq_list() + + def clean_seq_list(self): + clean_lst = [] + for i in range(len(self.sequence_list)): + cls, _ = self.sequence_list[i].split('-') + clean_lst.append(cls) + return clean_lst + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + class_name = sequence_name.split('-')[0] + anno_path = '{}/{}/{}/groundtruth.txt'.format(self.base_path, class_name, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + occlusion_label_path = '{}/{}/{}/full_occlusion.txt'.format(self.base_path, class_name, sequence_name) + + # NOTE: pandas backed seems super super slow for loading occlusion/oov masks + full_occlusion = load_text(str(occlusion_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + out_of_view_label_path = '{}/{}/{}/out_of_view.txt'.format(self.base_path, class_name, sequence_name) + out_of_view = load_text(str(out_of_view_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + target_visible = np.logical_and(full_occlusion == 0, out_of_view == 0) + + frames_path = '{}/{}/{}/img'.format(self.base_path, class_name, sequence_name) + + frames_list = ['{}/{:08d}.jpg'.format(frames_path, frame_number) for frame_number in range(1, ground_truth_rect.shape[0] + 1)] + + target_class = class_name + return Sequence(sequence_name, frames_list, 'lasot', ground_truth_rect.reshape(-1, 4), + object_class=target_class, target_visible=target_visible) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list = ['airplane-1', + 'airplane-9', + 'airplane-13', + 'airplane-15', + 'basketball-1', + 'basketball-6', + 'basketball-7', + 'basketball-11', + 'bear-2', + 'bear-4', + 'bear-6', + 'bear-17', + 'bicycle-2', + 'bicycle-7', + 'bicycle-9', + 'bicycle-18', + 'bird-2', + 'bird-3', + 'bird-15', + 'bird-17', + 'boat-3', + 'boat-4', + 'boat-12', + 'boat-17', + 'book-3', + 'book-10', + 'book-11', + 'book-19', + 'bottle-1', + 'bottle-12', + 'bottle-14', + 'bottle-18', + 'bus-2', + 'bus-5', + 'bus-17', + 'bus-19', + 'car-2', + 'car-6', + 'car-9', + 'car-17', + 'cat-1', + 'cat-3', + 'cat-18', + 'cat-20', + 'cattle-2', + 'cattle-7', + 'cattle-12', + 'cattle-13', + 'spider-14', + 'spider-16', + 'spider-18', + 'spider-20', + 'coin-3', + 'coin-6', + 'coin-7', + 'coin-18', + 'crab-3', + 'crab-6', + 'crab-12', + 'crab-18', + 'surfboard-12', + 'surfboard-4', + 'surfboard-5', + 'surfboard-8', + 'cup-1', + 'cup-4', + 'cup-7', + 'cup-17', + 'deer-4', + 'deer-8', + 'deer-10', + 'deer-14', + 'dog-1', + 'dog-7', + 'dog-15', + 'dog-19', + 'guitar-3', + 'guitar-8', + 'guitar-10', + 'guitar-16', + 'person-1', + 'person-5', + 'person-10', + 'person-12', + 'pig-2', + 'pig-10', + 'pig-13', + 'pig-18', + 'rubicCube-1', + 'rubicCube-6', + 'rubicCube-14', + 'rubicCube-19', + 'swing-10', + 'swing-14', + 'swing-17', + 'swing-20', + 'drone-13', + 'drone-15', + 'drone-2', + 'drone-7', + 'pool-12', + 'pool-15', + 'pool-3', + 'pool-7', + 'rabbit-10', + 'rabbit-13', + 'rabbit-17', + 'rabbit-19', + 'racing-10', + 'racing-15', + 'racing-16', + 'racing-20', + 'robot-1', + 'robot-19', + 'robot-5', + 'robot-8', + 'sepia-13', + 'sepia-16', + 'sepia-6', + 'sepia-8', + 'sheep-3', + 'sheep-5', + 'sheep-7', + 'sheep-9', + 'skateboard-16', + 'skateboard-19', + 'skateboard-3', + 'skateboard-8', + 'tank-14', + 'tank-16', + 'tank-6', + 'tank-9', + 'tiger-12', + 'tiger-18', + 'tiger-4', + 'tiger-6', + 'train-1', + 'train-11', + 'train-20', + 'train-7', + 'truck-16', + 'truck-3', + 'truck-6', + 'truck-7', + 'turtle-16', + 'turtle-5', + 'turtle-8', + 'turtle-9', + 'umbrella-17', + 'umbrella-19', + 'umbrella-2', + 'umbrella-9', + 'yoyo-15', + 'yoyo-17', + 'yoyo-19', + 'yoyo-7', + 'zebra-10', + 'zebra-14', + 'zebra-16', + 'zebra-17', + 'elephant-1', + 'elephant-12', + 'elephant-16', + 'elephant-18', + 'goldfish-3', + 'goldfish-7', + 'goldfish-8', + 'goldfish-10', + 'hat-1', + 'hat-2', + 'hat-5', + 'hat-18', + 'kite-4', + 'kite-6', + 'kite-10', + 'kite-15', + 'motorcycle-1', + 'motorcycle-3', + 'motorcycle-9', + 'motorcycle-18', + 'mouse-1', + 'mouse-8', + 'mouse-9', + 'mouse-17', + 'flag-3', + 'flag-9', + 'flag-5', + 'flag-2', + 'frog-3', + 'frog-4', + 'frog-20', + 'frog-9', + 'gametarget-1', + 'gametarget-2', + 'gametarget-7', + 'gametarget-13', + 'hand-2', + 'hand-3', + 'hand-9', + 'hand-16', + 'helmet-5', + 'helmet-11', + 'helmet-19', + 'helmet-13', + 'licenseplate-6', + 'licenseplate-12', + 'licenseplate-13', + 'licenseplate-15', + 'electricfan-1', + 'electricfan-10', + 'electricfan-18', + 'electricfan-20', + 'chameleon-3', + 'chameleon-6', + 'chameleon-11', + 'chameleon-20', + 'crocodile-3', + 'crocodile-4', + 'crocodile-10', + 'crocodile-14', + 'gecko-1', + 'gecko-5', + 'gecko-16', + 'gecko-19', + 'fox-2', + 'fox-3', + 'fox-5', + 'fox-20', + 'giraffe-2', + 'giraffe-10', + 'giraffe-13', + 'giraffe-15', + 'gorilla-4', + 'gorilla-6', + 'gorilla-9', + 'gorilla-13', + 'hippo-1', + 'hippo-7', + 'hippo-9', + 'hippo-20', + 'horse-1', + 'horse-4', + 'horse-12', + 'horse-15', + 'kangaroo-2', + 'kangaroo-5', + 'kangaroo-11', + 'kangaroo-14', + 'leopard-1', + 'leopard-7', + 'leopard-16', + 'leopard-20', + 'lion-1', + 'lion-5', + 'lion-12', + 'lion-20', + 'lizard-1', + 'lizard-3', + 'lizard-6', + 'lizard-13', + 'microphone-2', + 'microphone-6', + 'microphone-14', + 'microphone-16', + 'monkey-3', + 'monkey-4', + 'monkey-9', + 'monkey-17', + 'shark-2', + 'shark-3', + 'shark-5', + 'shark-6', + 'squirrel-8', + 'squirrel-11', + 'squirrel-13', + 'squirrel-19', + 'volleyball-1', + 'volleyball-13', + 'volleyball-18', + 'volleyball-19'] + return sequence_list diff --git a/Stark/external/AR/pytracking/evaluation/mobifacedataset.py b/Stark/external/AR/pytracking/evaluation/mobifacedataset.py new file mode 100755 index 0000000..486fff6 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/mobifacedataset.py @@ -0,0 +1,68 @@ +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +import glob +import numpy as np +import os.path as osp +from collections import OrderedDict +import pandas as pd + + +class MobifaceDataset(BaseDataset): + """ Mobiface dataset. + Publication: + MobiFace: A Novel Dataset for Mobile Face Tracking in the Wild + Yiming Lin, Shiyang Cheng, Jie Shen, Maja Pantic + arXiv:1805.09749, 2018 + https://arxiv.org/pdf/1805.09749v2 + + Download dataset from https://mobiface.github.io/ + """ + def __init__(self, split): + """ + args: + split - Split to use. Can be i) 'train': official training set, ii) 'test': official test set, iii) 'all': whole dataset. + """ + super().__init__() + self.base_path = self.env_settings.mobiface_path + self.sequence_list = self._get_sequence_list(split) + self.split = split + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _get_sequence_list(self, split): + + self.train_meta_fn = osp.join(self.base_path, 'train.meta.csv') + self.test_meta_fn = osp.join(self.base_path, 'test.meta.csv') + self.train_meta = pd.read_csv(self.train_meta_fn,index_col=0).transpose().to_dict() + self.test_meta = pd.read_csv(self.test_meta_fn,index_col=0).transpose().to_dict() + if split == 'train': + self.meta = self.train_meta + elif split == 'test': + self.meta = self.test_meta + else: + self.meta = {**self.train_meta, **self.test_meta} # In Python 3.5 or greater + self.meta = OrderedDict(sorted(self.meta.items(), key=lambda t: t[0])) + self.anno_files = [] + for k,v in self.meta.items(): + if k in self.train_meta.keys(): + self.anno_files.append(osp.abspath(osp.join(self.base_path,'train', k+'.annot.csv'))) + else: + self.anno_files.append(osp.abspath(osp.join(self.base_path,'test', k+'.annot.csv'))) + self.seq_names = sorted(list(self.meta.keys())) + self.seq_dirs = [fn[:-len('.annot.csv')] for fn in self.anno_files] + return self.seq_names + + def _construct_sequence(self, sequence_name): + index = self.seq_names.index(sequence_name) + img_files = sorted(glob.glob(self.seq_dirs[index]+'/*.jpg')) + if len(img_files) == 0: + img_files = sorted(glob.glob(self.seq_dirs[index]+'.png')) + with open(self.anno_files[index], 'r') as f: + anno = np.loadtxt(f, delimiter=',', skiprows=1, dtype=int) + anno = anno[:,1:] + assert anno.shape[1] == 4 + + return Sequence(sequence_name, img_files, anno.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) diff --git a/Stark/external/AR/pytracking/evaluation/multi_object_wrapper.py b/Stark/external/AR/pytracking/evaluation/multi_object_wrapper.py new file mode 100755 index 0000000..885cd9e --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/multi_object_wrapper.py @@ -0,0 +1,187 @@ +import numpy as np +from collections import OrderedDict +import time +import copy + + +class MultiObjectWrapper: + def __init__(self, base_tracker_class, params, visdom=None, fast_load=False): + self.base_tracker_class = base_tracker_class + self.params = params + self.visdom = visdom + + self.initialized_ids = [] + self.trackers = OrderedDict() + + self.fast_load = fast_load + if self.fast_load: + self.tracker_copy = self.base_tracker_class(self.params) + if hasattr(self.tracker_copy, 'initialize_features'): + self.tracker_copy.initialize_features() + + def create_tracker(self): + tracker = None + if self.fast_load: + try: + tracker = copy.deepcopy(self.tracker_copy) + except: + pass + if tracker is None: + tracker = self.base_tracker_class(self.params) + tracker.visdom = self.visdom + return tracker + + def _split_info(self, info): + info_split = OrderedDict() + init_other = OrderedDict() # Init other contains init info for all other objects + for obj_id in info['init_object_ids']: + info_split[obj_id] = dict() + init_other[obj_id] = dict() + info_split[obj_id]['object_ids'] = [obj_id] + info_split[obj_id]['sequence_object_ids'] = info['sequence_object_ids'] + if 'init_bbox' in info: + info_split[obj_id]['init_bbox'] = info['init_bbox'][obj_id] + init_other[obj_id]['init_bbox'] = info['init_bbox'][obj_id] + if 'init_mask' in info: + info_split[obj_id]['init_mask'] = (info['init_mask'] == int(obj_id)).astype(np.uint8) + init_other[obj_id]['init_mask'] = info_split[obj_id]['init_mask'] + for obj_info in info_split.values(): + obj_info['init_other'] = init_other + return info_split + + def _set_defaults(self, tracker_out: dict, defaults=None): + defaults = {} if defaults is None else defaults + + for key, val in defaults.items(): + if tracker_out.get(key) is None: + tracker_out[key] = val + + return tracker_out + + def default_merge(self, out_all): + out_merged = OrderedDict() + + out_first = list(out_all.values())[0] + out_types = out_first.keys() + + # Merge segmentation mask + if 'segmentation' in out_types and out_first['segmentation'] is not None: + # Stack all masks + # If a tracker outputs soft segmentation mask, use that. Else use the binary segmentation + segmentation_maps = [out.get('segmentation_soft', out['segmentation']) for out in out_all.values()] + segmentation_maps = np.stack(segmentation_maps) + + obj_ids = np.array([0, *map(int, out_all.keys())], dtype=np.uint8) + segm_threshold = getattr(self.params, 'segmentation_threshold', 0.5) + merged_segmentation = obj_ids[np.where(segmentation_maps.max(axis=0) > segm_threshold, + segmentation_maps.argmax(axis=0) + 1, 0)] + + out_merged['segmentation'] = merged_segmentation + + # Merge other fields + for key in out_types: + if key == 'segmentation': + pass + else: + out_merged[key] = {obj_id: out[key] for obj_id, out in out_all.items()} + + return out_merged + + def merge_outputs(self, out_all): + if hasattr(self.base_tracker_class, 'merge_results'): + out_merged = self.base_tracker_class.merge_results(out_all) + else: + out_merged = self.default_merge(out_all) + + return out_merged + + def initialize(self, image, info: dict) -> dict: + self.initialized_ids = [] + self.trackers = OrderedDict() + + if len(info['init_object_ids']) == 0: + return None + + object_ids = info['object_ids'] + + init_info_split = self._split_info(info) + self.trackers = OrderedDict({obj_id: self.create_tracker() for obj_id in object_ids}) + + out_all = OrderedDict() + # Run individual trackers for each object + for obj_id in info['init_object_ids']: + start_time = time.time() + out = self.trackers[obj_id].initialize(image, init_info_split[obj_id]) + if out is None: + out = {} + + init_default = {'target_bbox': init_info_split[obj_id].get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info_split[obj_id].get('init_mask')} + + out = self._set_defaults(out, init_default) + out_all[obj_id] = out + + # Merge results + out_merged = self.merge_outputs(out_all) + + self.initialized_ids = info['init_object_ids'].copy() + return out_merged + + def track(self, image, info: dict = None) -> dict: + if info is None: + info = {} + + prev_output = info.get('previous_output', OrderedDict()) + + if info.get('init_object_ids', False): + init_info_split = self._split_info(info) + for obj_init_info in init_info_split.values(): + obj_init_info['previous_output'] = prev_output + + info['init_other'] = list(init_info_split.values())[0]['init_other'] + + out_all = OrderedDict() + for obj_id in self.initialized_ids: + start_time = time.time() + + out = self.trackers[obj_id].track(image, info) + + default = {'time': time.time() - start_time} + out = self._set_defaults(out, default) + out_all[obj_id] = out + + # Initialize new + if info.get('init_object_ids', False): + for obj_id in info['init_object_ids']: + if not obj_id in self.trackers: + self.trackers[obj_id] = self.create_tracker() + + start_time = time.time() + out = self.trackers[obj_id].initialize(image, init_info_split[obj_id]) + if out is None: + out = {} + + init_default = {'target_bbox': init_info_split[obj_id].get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info_split[obj_id].get('init_mask')} + + out = self._set_defaults(out, init_default) + out_all[obj_id] = out + + self.initialized_ids.extend(info['init_object_ids']) + + # Merge results + out_merged = self.merge_outputs(out_all) + + return out_merged + + def visdom_draw_tracking(self, image, box, segmentation): + if isinstance(box, (OrderedDict, dict)): + box = [v for k, v in box.items()] + else: + box = (box,) + if segmentation is None: + self.visdom.register((image, *box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, *box, segmentation), 'Tracking', 1, 'Tracking') diff --git a/Stark/external/AR/pytracking/evaluation/nfsdataset.py b/Stark/external/AR/pytracking/evaluation/nfsdataset.py new file mode 100755 index 0000000..4733e7a --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/nfsdataset.py @@ -0,0 +1,153 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class NFSDataset(BaseDataset): + """ NFS dataset. + + Publication: + Need for Speed: A Benchmark for Higher Frame Rate Object Tracking + H. Kiani Galoogahi, A. Fagg, C. Huang, D. Ramanan, and S.Lucey + ICCV, 2017 + http://openaccess.thecvf.com/content_ICCV_2017/papers/Galoogahi_Need_for_Speed_ICCV_2017_paper.pdf + + Download the dataset from http://ci2cv.net/nfs/index.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.nfs_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter='\t', dtype=np.float64) + + return Sequence(sequence_info['name'], frames, 'nfs', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "nfs_Gymnastics", "path": "sequences/Gymnastics", "startFrame": 1, "endFrame": 368, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Gymnastics.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_MachLoop_jet", "path": "sequences/MachLoop_jet", "startFrame": 1, "endFrame": 99, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_MachLoop_jet.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_Skiing_red", "path": "sequences/Skiing_red", "startFrame": 1, "endFrame": 69, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Skiing_red.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_Skydiving", "path": "sequences/Skydiving", "startFrame": 1, "endFrame": 196, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Skydiving.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_airboard_1", "path": "sequences/airboard_1", "startFrame": 1, "endFrame": 425, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airboard_1.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_airplane_landing", "path": "sequences/airplane_landing", "startFrame": 1, "endFrame": 81, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airplane_landing.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_airtable_3", "path": "sequences/airtable_3", "startFrame": 1, "endFrame": 482, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airtable_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_1", "path": "sequences/basketball_1", "startFrame": 1, "endFrame": 282, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_1.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_2", "path": "sequences/basketball_2", "startFrame": 1, "endFrame": 102, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_3", "path": "sequences/basketball_3", "startFrame": 1, "endFrame": 421, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_6", "path": "sequences/basketball_6", "startFrame": 1, "endFrame": 224, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_7", "path": "sequences/basketball_7", "startFrame": 1, "endFrame": 240, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_7.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_basketball_player", "path": "sequences/basketball_player", "startFrame": 1, "endFrame": 369, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_player.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_basketball_player_2", "path": "sequences/basketball_player_2", "startFrame": 1, "endFrame": 437, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_player_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_beach_flipback_person", "path": "sequences/beach_flipback_person", "startFrame": 1, "endFrame": 61, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_beach_flipback_person.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_bee", "path": "sequences/bee", "startFrame": 1, "endFrame": 45, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bee.txt", "object_class": "insect", 'occlusion': False}, + {"name": "nfs_biker_acrobat", "path": "sequences/biker_acrobat", "startFrame": 1, "endFrame": 128, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_acrobat.txt", "object_class": "bicycle", 'occlusion': False}, + {"name": "nfs_biker_all_1", "path": "sequences/biker_all_1", "startFrame": 1, "endFrame": 113, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_all_1.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_biker_head_2", "path": "sequences/biker_head_2", "startFrame": 1, "endFrame": 132, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_head_2.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_biker_head_3", "path": "sequences/biker_head_3", "startFrame": 1, "endFrame": 254, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_head_3.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_biker_upper_body", "path": "sequences/biker_upper_body", "startFrame": 1, "endFrame": 194, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_upper_body.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_biker_whole_body", "path": "sequences/biker_whole_body", "startFrame": 1, "endFrame": 572, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_whole_body.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_billiard_2", "path": "sequences/billiard_2", "startFrame": 1, "endFrame": 604, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_3", "path": "sequences/billiard_3", "startFrame": 1, "endFrame": 698, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_6", "path": "sequences/billiard_6", "startFrame": 1, "endFrame": 771, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_7", "path": "sequences/billiard_7", "startFrame": 1, "endFrame": 724, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_7.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_8", "path": "sequences/billiard_8", "startFrame": 1, "endFrame": 778, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_8.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_bird_2", "path": "sequences/bird_2", "startFrame": 1, "endFrame": 476, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bird_2.txt", "object_class": "bird", 'occlusion': False}, + {"name": "nfs_book", "path": "sequences/book", "startFrame": 1, "endFrame": 288, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_book.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_bottle", "path": "sequences/bottle", "startFrame": 1, "endFrame": 2103, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bottle.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_bowling_1", "path": "sequences/bowling_1", "startFrame": 1, "endFrame": 303, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_1.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_2", "path": "sequences/bowling_2", "startFrame": 1, "endFrame": 710, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_2.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_3", "path": "sequences/bowling_3", "startFrame": 1, "endFrame": 271, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_3.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_6", "path": "sequences/bowling_6", "startFrame": 1, "endFrame": 260, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_bowling_ball", "path": "sequences/bowling_ball", "startFrame": 1, "endFrame": 275, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_ball.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bunny", "path": "sequences/bunny", "startFrame": 1, "endFrame": 705, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bunny.txt", "object_class": "mammal", 'occlusion': False}, + {"name": "nfs_car", "path": "sequences/car", "startFrame": 1, "endFrame": 2020, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car.txt", "object_class": "car", 'occlusion': True}, + {"name": "nfs_car_camaro", "path": "sequences/car_camaro", "startFrame": 1, "endFrame": 36, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_camaro.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_drifting", "path": "sequences/car_drifting", "startFrame": 1, "endFrame": 173, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_drifting.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_jumping", "path": "sequences/car_jumping", "startFrame": 1, "endFrame": 22, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_jumping.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_rc_rolling", "path": "sequences/car_rc_rolling", "startFrame": 1, "endFrame": 62, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_rc_rolling.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_rc_rotating", "path": "sequences/car_rc_rotating", "startFrame": 1, "endFrame": 80, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_rc_rotating.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_side", "path": "sequences/car_side", "startFrame": 1, "endFrame": 108, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_side.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_white", "path": "sequences/car_white", "startFrame": 1, "endFrame": 2063, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_white.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_cheetah", "path": "sequences/cheetah", "startFrame": 1, "endFrame": 167, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cheetah.txt", "object_class": "mammal", 'occlusion': True}, + {"name": "nfs_cup", "path": "sequences/cup", "startFrame": 1, "endFrame": 1281, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cup.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_cup_2", "path": "sequences/cup_2", "startFrame": 1, "endFrame": 182, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cup_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_dog", "path": "sequences/dog", "startFrame": 1, "endFrame": 1030, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dog_1", "path": "sequences/dog_1", "startFrame": 1, "endFrame": 168, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_1.txt", "object_class": "dog", 'occlusion': False}, + {"name": "nfs_dog_2", "path": "sequences/dog_2", "startFrame": 1, "endFrame": 594, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_2.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dog_3", "path": "sequences/dog_3", "startFrame": 1, "endFrame": 200, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_3.txt", "object_class": "dog", 'occlusion': False}, + {"name": "nfs_dogs", "path": "sequences/dogs", "startFrame": 1, "endFrame": 198, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dogs.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dollar", "path": "sequences/dollar", "startFrame": 1, "endFrame": 1426, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dollar.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_drone", "path": "sequences/drone", "startFrame": 1, "endFrame": 70, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_drone.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_ducks_lake", "path": "sequences/ducks_lake", "startFrame": 1, "endFrame": 107, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_ducks_lake.txt", "object_class": "bird", 'occlusion': False}, + {"name": "nfs_exit", "path": "sequences/exit", "startFrame": 1, "endFrame": 359, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_exit.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_first", "path": "sequences/first", "startFrame": 1, "endFrame": 435, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_first.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_flower", "path": "sequences/flower", "startFrame": 1, "endFrame": 448, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_flower.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_footbal_skill", "path": "sequences/footbal_skill", "startFrame": 1, "endFrame": 131, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_footbal_skill.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_helicopter", "path": "sequences/helicopter", "startFrame": 1, "endFrame": 310, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_helicopter.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_horse_jumping", "path": "sequences/horse_jumping", "startFrame": 1, "endFrame": 117, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_horse_jumping.txt", "object_class": "horse", 'occlusion': True}, + {"name": "nfs_horse_running", "path": "sequences/horse_running", "startFrame": 1, "endFrame": 139, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_horse_running.txt", "object_class": "horse", 'occlusion': False}, + {"name": "nfs_iceskating_6", "path": "sequences/iceskating_6", "startFrame": 1, "endFrame": 603, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_iceskating_6.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_jellyfish_5", "path": "sequences/jellyfish_5", "startFrame": 1, "endFrame": 746, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_jellyfish_5.txt", "object_class": "invertebrate", 'occlusion': False}, + {"name": "nfs_kid_swing", "path": "sequences/kid_swing", "startFrame": 1, "endFrame": 169, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_kid_swing.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_motorcross", "path": "sequences/motorcross", "startFrame": 1, "endFrame": 39, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_motorcross.txt", "object_class": "vehicle", 'occlusion': True}, + {"name": "nfs_motorcross_kawasaki", "path": "sequences/motorcross_kawasaki", "startFrame": 1, "endFrame": 65, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_motorcross_kawasaki.txt", "object_class": "vehicle", 'occlusion': False}, + {"name": "nfs_parkour", "path": "sequences/parkour", "startFrame": 1, "endFrame": 58, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_parkour.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_person_scooter", "path": "sequences/person_scooter", "startFrame": 1, "endFrame": 413, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_person_scooter.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_pingpong_2", "path": "sequences/pingpong_2", "startFrame": 1, "endFrame": 1277, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_pingpong_7", "path": "sequences/pingpong_7", "startFrame": 1, "endFrame": 1290, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_7.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_pingpong_8", "path": "sequences/pingpong_8", "startFrame": 1, "endFrame": 296, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_8.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_purse", "path": "sequences/purse", "startFrame": 1, "endFrame": 968, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_purse.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_rubber", "path": "sequences/rubber", "startFrame": 1, "endFrame": 1328, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_rubber.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_running", "path": "sequences/running", "startFrame": 1, "endFrame": 677, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_running_100_m", "path": "sequences/running_100_m", "startFrame": 1, "endFrame": 313, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_100_m.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_running_100_m_2", "path": "sequences/running_100_m_2", "startFrame": 1, "endFrame": 337, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_100_m_2.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_running_2", "path": "sequences/running_2", "startFrame": 1, "endFrame": 363, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_shuffleboard_1", "path": "sequences/shuffleboard_1", "startFrame": 1, "endFrame": 42, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_1.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_2", "path": "sequences/shuffleboard_2", "startFrame": 1, "endFrame": 41, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_4", "path": "sequences/shuffleboard_4", "startFrame": 1, "endFrame": 62, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_4.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_5", "path": "sequences/shuffleboard_5", "startFrame": 1, "endFrame": 32, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_5.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_6", "path": "sequences/shuffleboard_6", "startFrame": 1, "endFrame": 52, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_6.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_2", "path": "sequences/shuffletable_2", "startFrame": 1, "endFrame": 372, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_3", "path": "sequences/shuffletable_3", "startFrame": 1, "endFrame": 368, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_3.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_4", "path": "sequences/shuffletable_4", "startFrame": 1, "endFrame": 101, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_4.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_ski_long", "path": "sequences/ski_long", "startFrame": 1, "endFrame": 274, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_ski_long.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_soccer_ball", "path": "sequences/soccer_ball", "startFrame": 1, "endFrame": 163, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_ball_2", "path": "sequences/soccer_ball_2", "startFrame": 1, "endFrame": 1934, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_ball_3", "path": "sequences/soccer_ball_3", "startFrame": 1, "endFrame": 1381, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_player_2", "path": "sequences/soccer_player_2", "startFrame": 1, "endFrame": 475, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_player_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_soccer_player_3", "path": "sequences/soccer_player_3", "startFrame": 1, "endFrame": 319, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_player_3.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_stop_sign", "path": "sequences/stop_sign", "startFrame": 1, "endFrame": 302, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_stop_sign.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_suv", "path": "sequences/suv", "startFrame": 1, "endFrame": 2584, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_suv.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_tiger", "path": "sequences/tiger", "startFrame": 1, "endFrame": 1556, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_tiger.txt", "object_class": "mammal", 'occlusion': False}, + {"name": "nfs_walking", "path": "sequences/walking", "startFrame": 1, "endFrame": 555, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_walking.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_walking_3", "path": "sequences/walking_3", "startFrame": 1, "endFrame": 1427, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_walking_3.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_water_ski_2", "path": "sequences/water_ski_2", "startFrame": 1, "endFrame": 47, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_water_ski_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_yoyo", "path": "sequences/yoyo", "startFrame": 1, "endFrame": 67, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_yoyo.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_zebra_fish", "path": "sequences/zebra_fish", "startFrame": 1, "endFrame": 671, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_zebra_fish.txt", "object_class": "fish", 'occlusion': False}, + ] + + return sequence_info_list diff --git a/Stark/external/AR/pytracking/evaluation/otbdataset.py b/Stark/external/AR/pytracking/evaluation/otbdataset.py new file mode 100755 index 0000000..2230c57 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/otbdataset.py @@ -0,0 +1,254 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class OTBDataset(BaseDataset): + """ OTB-2015 dataset + + Publication: + Object Tracking Benchmark + Wu, Yi, Jongwoo Lim, and Ming-hsuan Yan + TPAMI, 2015 + http://faculty.ucmerced.edu/mhyang/papers/pami15_tracking_benchmark.pdf + + Download the dataset from http://cvlab.hanyang.ac.kr/tracker_benchmark/index.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.otb_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + # NOTE: OTB has some weird annos which panda cannot handle + ground_truth_rect = load_text(str(anno_path), delimiter=(',', None), dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'otb', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "Basketball", "path": "Basketball/img", "startFrame": 1, "endFrame": 725, "nz": 4, "ext": "jpg", "anno_path": "Basketball/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Biker", "path": "Biker/img", "startFrame": 1, "endFrame": 142, "nz": 4, "ext": "jpg", "anno_path": "Biker/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Bird1", "path": "Bird1/img", "startFrame": 1, "endFrame": 408, "nz": 4, "ext": "jpg", "anno_path": "Bird1/groundtruth_rect.txt", + "object_class": "bird"}, + {"name": "Bird2", "path": "Bird2/img", "startFrame": 1, "endFrame": 99, "nz": 4, "ext": "jpg", "anno_path": "Bird2/groundtruth_rect.txt", + "object_class": "bird"}, + {"name": "BlurBody", "path": "BlurBody/img", "startFrame": 1, "endFrame": 334, "nz": 4, "ext": "jpg", "anno_path": "BlurBody/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "BlurCar1", "path": "BlurCar1/img", "startFrame": 247, "endFrame": 988, "nz": 4, "ext": "jpg", "anno_path": "BlurCar1/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar2", "path": "BlurCar2/img", "startFrame": 1, "endFrame": 585, "nz": 4, "ext": "jpg", "anno_path": "BlurCar2/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar3", "path": "BlurCar3/img", "startFrame": 3, "endFrame": 359, "nz": 4, "ext": "jpg", "anno_path": "BlurCar3/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar4", "path": "BlurCar4/img", "startFrame": 18, "endFrame": 397, "nz": 4, "ext": "jpg", "anno_path": "BlurCar4/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurFace", "path": "BlurFace/img", "startFrame": 1, "endFrame": 493, "nz": 4, "ext": "jpg", "anno_path": "BlurFace/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "BlurOwl", "path": "BlurOwl/img", "startFrame": 1, "endFrame": 631, "nz": 4, "ext": "jpg", "anno_path": "BlurOwl/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Board", "path": "Board/img", "startFrame": 1, "endFrame": 698, "nz": 5, "ext": "jpg", "anno_path": "Board/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Bolt", "path": "Bolt/img", "startFrame": 1, "endFrame": 350, "nz": 4, "ext": "jpg", "anno_path": "Bolt/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Bolt2", "path": "Bolt2/img", "startFrame": 1, "endFrame": 293, "nz": 4, "ext": "jpg", "anno_path": "Bolt2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Box", "path": "Box/img", "startFrame": 1, "endFrame": 1161, "nz": 4, "ext": "jpg", "anno_path": "Box/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Boy", "path": "Boy/img", "startFrame": 1, "endFrame": 602, "nz": 4, "ext": "jpg", "anno_path": "Boy/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Car1", "path": "Car1/img", "startFrame": 1, "endFrame": 1020, "nz": 4, "ext": "jpg", "anno_path": "Car1/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car2", "path": "Car2/img", "startFrame": 1, "endFrame": 913, "nz": 4, "ext": "jpg", "anno_path": "Car2/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car24", "path": "Car24/img", "startFrame": 1, "endFrame": 3059, "nz": 4, "ext": "jpg", "anno_path": "Car24/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car4", "path": "Car4/img", "startFrame": 1, "endFrame": 659, "nz": 4, "ext": "jpg", "anno_path": "Car4/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "CarDark", "path": "CarDark/img", "startFrame": 1, "endFrame": 393, "nz": 4, "ext": "jpg", "anno_path": "CarDark/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "CarScale", "path": "CarScale/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", "anno_path": "CarScale/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "ClifBar", "path": "ClifBar/img", "startFrame": 1, "endFrame": 472, "nz": 4, "ext": "jpg", "anno_path": "ClifBar/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Coke", "path": "Coke/img", "startFrame": 1, "endFrame": 291, "nz": 4, "ext": "jpg", "anno_path": "Coke/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Couple", "path": "Couple/img", "startFrame": 1, "endFrame": 140, "nz": 4, "ext": "jpg", "anno_path": "Couple/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Coupon", "path": "Coupon/img", "startFrame": 1, "endFrame": 327, "nz": 4, "ext": "jpg", "anno_path": "Coupon/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Crossing", "path": "Crossing/img", "startFrame": 1, "endFrame": 120, "nz": 4, "ext": "jpg", "anno_path": "Crossing/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Crowds", "path": "Crowds/img", "startFrame": 1, "endFrame": 347, "nz": 4, "ext": "jpg", "anno_path": "Crowds/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dancer", "path": "Dancer/img", "startFrame": 1, "endFrame": 225, "nz": 4, "ext": "jpg", "anno_path": "Dancer/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dancer2", "path": "Dancer2/img", "startFrame": 1, "endFrame": 150, "nz": 4, "ext": "jpg", "anno_path": "Dancer2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "David", "path": "David/img", "startFrame": 300, "endFrame": 770, "nz": 4, "ext": "jpg", "anno_path": "David/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "David2", "path": "David2/img", "startFrame": 1, "endFrame": 537, "nz": 4, "ext": "jpg", "anno_path": "David2/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "David3", "path": "David3/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", "anno_path": "David3/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Deer", "path": "Deer/img", "startFrame": 1, "endFrame": 71, "nz": 4, "ext": "jpg", "anno_path": "Deer/groundtruth_rect.txt", + "object_class": "mammal"}, + {"name": "Diving", "path": "Diving/img", "startFrame": 1, "endFrame": 215, "nz": 4, "ext": "jpg", "anno_path": "Diving/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dog", "path": "Dog/img", "startFrame": 1, "endFrame": 127, "nz": 4, "ext": "jpg", "anno_path": "Dog/groundtruth_rect.txt", + "object_class": "dog"}, + {"name": "Dog1", "path": "Dog1/img", "startFrame": 1, "endFrame": 1350, "nz": 4, "ext": "jpg", "anno_path": "Dog1/groundtruth_rect.txt", + "object_class": "dog"}, + {"name": "Doll", "path": "Doll/img", "startFrame": 1, "endFrame": 3872, "nz": 4, "ext": "jpg", "anno_path": "Doll/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "DragonBaby", "path": "DragonBaby/img", "startFrame": 1, "endFrame": 113, "nz": 4, "ext": "jpg", "anno_path": "DragonBaby/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Dudek", "path": "Dudek/img", "startFrame": 1, "endFrame": 1145, "nz": 4, "ext": "jpg", "anno_path": "Dudek/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "FaceOcc1", "path": "FaceOcc1/img", "startFrame": 1, "endFrame": 892, "nz": 4, "ext": "jpg", "anno_path": "FaceOcc1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "FaceOcc2", "path": "FaceOcc2/img", "startFrame": 1, "endFrame": 812, "nz": 4, "ext": "jpg", "anno_path": "FaceOcc2/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Fish", "path": "Fish/img", "startFrame": 1, "endFrame": 476, "nz": 4, "ext": "jpg", "anno_path": "Fish/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "FleetFace", "path": "FleetFace/img", "startFrame": 1, "endFrame": 707, "nz": 4, "ext": "jpg", "anno_path": "FleetFace/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Football", "path": "Football/img", "startFrame": 1, "endFrame": 362, "nz": 4, "ext": "jpg", "anno_path": "Football/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Football1", "path": "Football1/img", "startFrame": 1, "endFrame": 74, "nz": 4, "ext": "jpg", "anno_path": "Football1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman1", "path": "Freeman1/img", "startFrame": 1, "endFrame": 326, "nz": 4, "ext": "jpg", "anno_path": "Freeman1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman3", "path": "Freeman3/img", "startFrame": 1, "endFrame": 460, "nz": 4, "ext": "jpg", "anno_path": "Freeman3/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman4", "path": "Freeman4/img", "startFrame": 1, "endFrame": 283, "nz": 4, "ext": "jpg", "anno_path": "Freeman4/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Girl", "path": "Girl/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", "anno_path": "Girl/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Girl2", "path": "Girl2/img", "startFrame": 1, "endFrame": 1500, "nz": 4, "ext": "jpg", "anno_path": "Girl2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Gym", "path": "Gym/img", "startFrame": 1, "endFrame": 767, "nz": 4, "ext": "jpg", "anno_path": "Gym/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human2", "path": "Human2/img", "startFrame": 1, "endFrame": 1128, "nz": 4, "ext": "jpg", "anno_path": "Human2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human3", "path": "Human3/img", "startFrame": 1, "endFrame": 1698, "nz": 4, "ext": "jpg", "anno_path": "Human3/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human4_2", "path": "Human4/img", "startFrame": 1, "endFrame": 667, "nz": 4, "ext": "jpg", "anno_path": "Human4/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Human5", "path": "Human5/img", "startFrame": 1, "endFrame": 713, "nz": 4, "ext": "jpg", "anno_path": "Human5/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human6", "path": "Human6/img", "startFrame": 1, "endFrame": 792, "nz": 4, "ext": "jpg", "anno_path": "Human6/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human7", "path": "Human7/img", "startFrame": 1, "endFrame": 250, "nz": 4, "ext": "jpg", "anno_path": "Human7/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human8", "path": "Human8/img", "startFrame": 1, "endFrame": 128, "nz": 4, "ext": "jpg", "anno_path": "Human8/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human9", "path": "Human9/img", "startFrame": 1, "endFrame": 305, "nz": 4, "ext": "jpg", "anno_path": "Human9/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Ironman", "path": "Ironman/img", "startFrame": 1, "endFrame": 166, "nz": 4, "ext": "jpg", "anno_path": "Ironman/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Jogging_1", "path": "Jogging/img", "startFrame": 1, "endFrame": 307, "nz": 4, "ext": "jpg", "anno_path": "Jogging/groundtruth_rect.1.txt", + "object_class": "person"}, + {"name": "Jogging_2", "path": "Jogging/img", "startFrame": 1, "endFrame": 307, "nz": 4, "ext": "jpg", "anno_path": "Jogging/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Jump", "path": "Jump/img", "startFrame": 1, "endFrame": 122, "nz": 4, "ext": "jpg", "anno_path": "Jump/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Jumping", "path": "Jumping/img", "startFrame": 1, "endFrame": 313, "nz": 4, "ext": "jpg", "anno_path": "Jumping/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "KiteSurf", "path": "KiteSurf/img", "startFrame": 1, "endFrame": 84, "nz": 4, "ext": "png", "anno_path": "KiteSurf/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Lemming", "path": "Lemming/img", "startFrame": 1, "endFrame": 1336, "nz": 4, "ext": "jpg", "anno_path": "Lemming/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Liquor", "path": "Liquor/img", "startFrame": 1, "endFrame": 1741, "nz": 4, "ext": "jpg", "anno_path": "Liquor/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Man", "path": "Man/img", "startFrame": 1, "endFrame": 134, "nz": 4, "ext": "jpg", "anno_path": "Man/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Matrix", "path": "Matrix/img", "startFrame": 1, "endFrame": 100, "nz": 4, "ext": "jpg", "anno_path": "Matrix/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Mhyang", "path": "Mhyang/img", "startFrame": 1, "endFrame": 1490, "nz": 4, "ext": "jpg", "anno_path": "Mhyang/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "MotorRolling", "path": "MotorRolling/img", "startFrame": 1, "endFrame": 164, "nz": 4, "ext": "jpg", "anno_path": "MotorRolling/groundtruth_rect.txt", + "object_class": "vehicle"}, + {"name": "MountainBike", "path": "MountainBike/img", "startFrame": 1, "endFrame": 228, "nz": 4, "ext": "jpg", "anno_path": "MountainBike/groundtruth_rect.txt", + "object_class": "bicycle"}, + {"name": "Panda", "path": "Panda/img", "startFrame": 1, "endFrame": 1000, "nz": 4, "ext": "jpg", "anno_path": "Panda/groundtruth_rect.txt", + "object_class": "mammal"}, + {"name": "RedTeam", "path": "RedTeam/img", "startFrame": 1, "endFrame": 1918, "nz": 4, "ext": "jpg", "anno_path": "RedTeam/groundtruth_rect.txt", + "object_class": "vehicle"}, + {"name": "Rubik", "path": "Rubik/img", "startFrame": 1, "endFrame": 1997, "nz": 4, "ext": "jpg", "anno_path": "Rubik/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Shaking", "path": "Shaking/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", "anno_path": "Shaking/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Singer1", "path": "Singer1/img", "startFrame": 1, "endFrame": 351, "nz": 4, "ext": "jpg", "anno_path": "Singer1/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Singer2", "path": "Singer2/img", "startFrame": 1, "endFrame": 366, "nz": 4, "ext": "jpg", "anno_path": "Singer2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skater", "path": "Skater/img", "startFrame": 1, "endFrame": 160, "nz": 4, "ext": "jpg", "anno_path": "Skater/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skater2", "path": "Skater2/img", "startFrame": 1, "endFrame": 435, "nz": 4, "ext": "jpg", "anno_path": "Skater2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skating1", "path": "Skating1/img", "startFrame": 1, "endFrame": 400, "nz": 4, "ext": "jpg", "anno_path": "Skating1/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skating2_1", "path": "Skating2/img", "startFrame": 1, "endFrame": 473, "nz": 4, "ext": "jpg", "anno_path": "Skating2/groundtruth_rect.1.txt", + "object_class": "person"}, + {"name": "Skating2_2", "path": "Skating2/img", "startFrame": 1, "endFrame": 473, "nz": 4, "ext": "jpg", "anno_path": "Skating2/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Skiing", "path": "Skiing/img", "startFrame": 1, "endFrame": 81, "nz": 4, "ext": "jpg", "anno_path": "Skiing/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Soccer", "path": "Soccer/img", "startFrame": 1, "endFrame": 392, "nz": 4, "ext": "jpg", "anno_path": "Soccer/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Subway", "path": "Subway/img", "startFrame": 1, "endFrame": 175, "nz": 4, "ext": "jpg", "anno_path": "Subway/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Surfer", "path": "Surfer/img", "startFrame": 1, "endFrame": 376, "nz": 4, "ext": "jpg", "anno_path": "Surfer/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Suv", "path": "Suv/img", "startFrame": 1, "endFrame": 945, "nz": 4, "ext": "jpg", "anno_path": "Suv/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Sylvester", "path": "Sylvester/img", "startFrame": 1, "endFrame": 1345, "nz": 4, "ext": "jpg", "anno_path": "Sylvester/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Tiger1", "path": "Tiger1/img", "startFrame": 1, "endFrame": 354, "nz": 4, "ext": "jpg", "anno_path": "Tiger1/groundtruth_rect.txt", "initOmit": 5, + "object_class": "other"}, + {"name": "Tiger2", "path": "Tiger2/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", "anno_path": "Tiger2/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Toy", "path": "Toy/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", "anno_path": "Toy/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Trans", "path": "Trans/img", "startFrame": 1, "endFrame": 124, "nz": 4, "ext": "jpg", "anno_path": "Trans/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Trellis", "path": "Trellis/img", "startFrame": 1, "endFrame": 569, "nz": 4, "ext": "jpg", "anno_path": "Trellis/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Twinnings", "path": "Twinnings/img", "startFrame": 1, "endFrame": 472, "nz": 4, "ext": "jpg", "anno_path": "Twinnings/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Vase", "path": "Vase/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", "anno_path": "Vase/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Walking", "path": "Walking/img", "startFrame": 1, "endFrame": 412, "nz": 4, "ext": "jpg", "anno_path": "Walking/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Walking2", "path": "Walking2/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", "anno_path": "Walking2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Woman", "path": "Woman/img", "startFrame": 1, "endFrame": 597, "nz": 4, "ext": "jpg", "anno_path": "Woman/groundtruth_rect.txt", + "object_class": "person"} + ] + + return sequence_info_list diff --git a/Stark/external/AR/pytracking/evaluation/running.py b/Stark/external/AR/pytracking/evaluation/running.py new file mode 100755 index 0000000..eef8f15 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/running.py @@ -0,0 +1,150 @@ +import numpy as np +import multiprocessing +import os +import sys +from itertools import product +from collections import OrderedDict +from pytracking.evaluation import Sequence, Tracker +from ltr.data.image_loader import imwrite_indexed + + +def _save_tracker_output(seq: Sequence, tracker: Tracker, output: dict): + """Saves the output of the tracker.""" + + if not os.path.exists(tracker.results_dir): + os.makedirs(tracker.results_dir) + + base_results_path = os.path.join(tracker.results_dir, seq.name) + segmentation_path = os.path.join(tracker.segmentation_dir, seq.name) + + frame_names = [os.path.splitext(os.path.basename(f))[0] for f in seq.frames] + + def save_bb(file, data): + tracked_bb = np.array(data).astype(int) + np.savetxt(file, tracked_bb, delimiter='\t', fmt='%d') + + def save_time(file, data): + exec_times = np.array(data).astype(float) + np.savetxt(file, exec_times, delimiter='\t', fmt='%f') + + def _convert_dict(input_dict): + data_dict = {} + for elem in input_dict: + for k, v in elem.items(): + if k in data_dict.keys(): + data_dict[k].append(v) + else: + data_dict[k] = [v, ] + return data_dict + + for key, data in output.items(): + # If data is empty + if not data: + continue + + if key == 'target_bbox': + if isinstance(data[0], (dict, OrderedDict)): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + bbox_file = '{}_{}.txt'.format(base_results_path, obj_id) + save_bb(bbox_file, d) + else: + # Single-object mode + bbox_file = '{}.txt'.format(base_results_path) + save_bb(bbox_file, data) + + elif key == 'time': + if isinstance(data[0], dict): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + timings_file = '{}_{}_time.txt'.format(base_results_path, obj_id) + save_time(timings_file, d) + else: + timings_file = '{}_time.txt'.format(base_results_path) + save_time(timings_file, data) + + elif key == 'segmentation': + assert len(frame_names) == len(data) + if not os.path.exists(segmentation_path): + os.makedirs(segmentation_path) + for frame_name, frame_seg in zip(frame_names, data): + imwrite_indexed(os.path.join(segmentation_path, '{}.png'.format(frame_name)), frame_seg) + + +def run_sequence(seq: Sequence, tracker: Tracker, debug=False, visdom_info=None): + """Runs a tracker on a sequence.""" + + def _results_exist(): + if seq.object_ids is None: + bbox_file = '{}/{}.txt'.format(tracker.results_dir, seq.name) + return os.path.isfile(bbox_file) + else: + bbox_files = ['{}/{}_{}.txt'.format(tracker.results_dir, seq.name, obj_id) for obj_id in seq.object_ids] + missing = [not os.path.isfile(f) for f in bbox_files] + return sum(missing) == 0 + + visdom_info = {} if visdom_info is None else visdom_info + + if _results_exist() and not debug: + print('FPS: {}'.format(-1)) + return + + print('Tracker: {} {} {} , Sequence: {}'.format(tracker.name, tracker.parameter_name, tracker.run_id, seq.name)) + + if debug: + output = tracker.run_sequence(seq, debug=debug, visdom_info=visdom_info) + else: + try: + output = tracker.run_sequence(seq, debug=debug, visdom_info=visdom_info) + except Exception as e: + print(e) + return + + sys.stdout.flush() + + if isinstance(output['time'][0], (dict, OrderedDict)): + exec_time = sum([sum(times.values()) for times in output['time']]) + num_frames = len(output['time']) + else: + exec_time = sum(output['time']) + num_frames = len(output['time']) + + print('FPS: {}'.format(num_frames / exec_time)) + + if not debug: + _save_tracker_output(seq, tracker, output) + + +def run_dataset(dataset, trackers, debug=False, threads=0, visdom_info=None): + """Runs a list of trackers on a dataset. + args: + dataset: List of Sequence instances, forming a dataset. + trackers: List of Tracker instances. + debug: Debug level. + threads: Number of threads to use (default 0). + visdom_info: Dict containing information about the server for visdom + """ + multiprocessing.set_start_method('spawn', force=True) + + print('Evaluating {:4d} trackers on {:5d} sequences'.format(len(trackers), len(dataset))) + + multiprocessing.set_start_method('spawn', force=True) + + visdom_info = {} if visdom_info is None else visdom_info + + if threads == 0: + mode = 'sequential' + else: + mode = 'parallel' + + if mode == 'sequential': + for seq in dataset: + for tracker_info in trackers: + run_sequence(seq, tracker_info, debug=debug, visdom_info=visdom_info) + elif mode == 'parallel': + param_list = [(seq, tracker_info, debug, visdom_info) for seq, tracker_info in product(dataset, trackers)] + with multiprocessing.Pool(processes=threads) as pool: + pool.starmap(run_sequence, param_list) + print('Done') diff --git a/Stark/external/AR/pytracking/evaluation/tpldataset.py b/Stark/external/AR/pytracking/evaluation/tpldataset.py new file mode 100755 index 0000000..0d77b2b --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/tpldataset.py @@ -0,0 +1,328 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class TPLDataset(BaseDataset): + """ + Temple Color 128 dataset + + Publication: + Encoding Color Information for Visual Tracking: Algorithms and Benchmark + P. Liang, E. Blasch, and H. Ling + TIP, 2015 + http://www.dabi.temple.edu/~hbling/publication/TColor-128.pdf + + Download the dataset from http://www.dabi.temple.edu/~hbling/data/TColor-128/TColor-128.html + """ + def __init__(self, exclude_otb=False): + """ + args: + exclude_otb (bool) - If True, sequences overlapping with the OTB dataset are excluded + """ + super().__init__() + self.base_path = self.env_settings.tpl_path + self.sequence_info_list = self._get_sequence_info_list(exclude_otb) + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter=(',', None), dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'tpl', ground_truth_rect[init_omit:,:]) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self, exclude_otb=False): + sequence_info_list = [ + {"name": "tpl_Skating2", "path": "tpl_Skating2/img", "startFrame": 1, "endFrame": 707, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating2/Skating2_gt.txt"}, + {"name": "tpl_Pool_ce3", "path": "tpl_Pool_ce3/img", "startFrame": 1, "endFrame": 124, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce3/Pool_ce3_gt.txt"}, + {"name": "tpl_Microphone_ce1", "path": "tpl_Microphone_ce1/img", "startFrame": 1, "endFrame": 204, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Microphone_ce1/Microphone_ce1_gt.txt"}, + {"name": "tpl_Torus", "path": "tpl_Torus/img", "startFrame": 1, "endFrame": 264, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Torus/Torus_gt.txt"}, + {"name": "tpl_Lemming", "path": "tpl_Lemming/img", "startFrame": 1, "endFrame": 1336, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Lemming/Lemming_gt.txt"}, + {"name": "tpl_Eagle_ce", "path": "tpl_Eagle_ce/img", "startFrame": 1, "endFrame": 112, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Eagle_ce/Eagle_ce_gt.txt"}, + {"name": "tpl_Skating_ce2", "path": "tpl_Skating_ce2/img", "startFrame": 1, "endFrame": 497, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating_ce2/Skating_ce2_gt.txt"}, + {"name": "tpl_Yo_yos_ce3", "path": "tpl_Yo_yos_ce3/img", "startFrame": 1, "endFrame": 201, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce3/Yo-yos_ce3_gt.txt"}, + {"name": "tpl_Board", "path": "tpl_Board/img", "startFrame": 1, "endFrame": 598, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Board/Board_gt.txt"}, + {"name": "tpl_Tennis_ce3", "path": "tpl_Tennis_ce3/img", "startFrame": 1, "endFrame": 204, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce3/Tennis_ce3_gt.txt"}, + {"name": "tpl_SuperMario_ce", "path": "tpl_SuperMario_ce/img", "startFrame": 1, "endFrame": 146, "nz": 4, + "ext": "jpg", "anno_path": "tpl_SuperMario_ce/SuperMario_ce_gt.txt"}, + {"name": "tpl_Yo_yos_ce1", "path": "tpl_Yo_yos_ce1/img", "startFrame": 1, "endFrame": 235, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce1/Yo-yos_ce1_gt.txt"}, + {"name": "tpl_Soccer", "path": "tpl_Soccer/img", "startFrame": 1, "endFrame": 392, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Soccer/Soccer_gt.txt"}, + {"name": "tpl_Fish_ce2", "path": "tpl_Fish_ce2/img", "startFrame": 1, "endFrame": 573, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Fish_ce2/Fish_ce2_gt.txt"}, + {"name": "tpl_Liquor", "path": "tpl_Liquor/img", "startFrame": 1, "endFrame": 1741, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Liquor/Liquor_gt.txt"}, + {"name": "tpl_Plane_ce2", "path": "tpl_Plane_ce2/img", "startFrame": 1, "endFrame": 653, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plane_ce2/Plane_ce2_gt.txt"}, + {"name": "tpl_Couple", "path": "tpl_Couple/img", "startFrame": 1, "endFrame": 140, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Couple/Couple_gt.txt"}, + {"name": "tpl_Logo_ce", "path": "tpl_Logo_ce/img", "startFrame": 1, "endFrame": 610, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Logo_ce/Logo_ce_gt.txt"}, + {"name": "tpl_Hand_ce2", "path": "tpl_Hand_ce2/img", "startFrame": 1, "endFrame": 251, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hand_ce2/Hand_ce2_gt.txt"}, + {"name": "tpl_Kite_ce2", "path": "tpl_Kite_ce2/img", "startFrame": 1, "endFrame": 658, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce2/Kite_ce2_gt.txt"}, + {"name": "tpl_Walking", "path": "tpl_Walking/img", "startFrame": 1, "endFrame": 412, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Walking/Walking_gt.txt"}, + {"name": "tpl_David", "path": "tpl_David/img", "startFrame": 300, "endFrame": 770, "nz": 4, "ext": "jpg", + "anno_path": "tpl_David/David_gt.txt"}, + {"name": "tpl_Boat_ce1", "path": "tpl_Boat_ce1/img", "startFrame": 1, "endFrame": 377, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Boat_ce1/Boat_ce1_gt.txt"}, + {"name": "tpl_Airport_ce", "path": "tpl_Airport_ce/img", "startFrame": 1, "endFrame": 148, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Airport_ce/Airport_ce_gt.txt"}, + {"name": "tpl_Tiger2", "path": "tpl_Tiger2/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Tiger2/Tiger2_gt.txt"}, + {"name": "tpl_Suitcase_ce", "path": "tpl_Suitcase_ce/img", "startFrame": 1, "endFrame": 184, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Suitcase_ce/Suitcase_ce_gt.txt"}, + {"name": "tpl_TennisBall_ce", "path": "tpl_TennisBall_ce/img", "startFrame": 1, "endFrame": 288, "nz": 4, + "ext": "jpg", "anno_path": "tpl_TennisBall_ce/TennisBall_ce_gt.txt"}, + {"name": "tpl_Singer_ce1", "path": "tpl_Singer_ce1/img", "startFrame": 1, "endFrame": 214, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Singer_ce1/Singer_ce1_gt.txt"}, + {"name": "tpl_Pool_ce2", "path": "tpl_Pool_ce2/img", "startFrame": 1, "endFrame": 133, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce2/Pool_ce2_gt.txt"}, + {"name": "tpl_Surf_ce3", "path": "tpl_Surf_ce3/img", "startFrame": 1, "endFrame": 279, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce3/Surf_ce3_gt.txt"}, + {"name": "tpl_Bird", "path": "tpl_Bird/img", "startFrame": 1, "endFrame": 99, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bird/Bird_gt.txt"}, + {"name": "tpl_Crossing", "path": "tpl_Crossing/img", "startFrame": 1, "endFrame": 120, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Crossing/Crossing_gt.txt"}, + {"name": "tpl_Plate_ce1", "path": "tpl_Plate_ce1/img", "startFrame": 1, "endFrame": 142, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plate_ce1/Plate_ce1_gt.txt"}, + {"name": "tpl_Cup", "path": "tpl_Cup/img", "startFrame": 1, "endFrame": 303, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Cup/Cup_gt.txt"}, + {"name": "tpl_Surf_ce2", "path": "tpl_Surf_ce2/img", "startFrame": 1, "endFrame": 391, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce2/Surf_ce2_gt.txt"}, + {"name": "tpl_Busstation_ce2", "path": "tpl_Busstation_ce2/img", "startFrame": 6, "endFrame": 400, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Busstation_ce2/Busstation_ce2_gt.txt"}, + {"name": "tpl_Charger_ce", "path": "tpl_Charger_ce/img", "startFrame": 1, "endFrame": 298, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Charger_ce/Charger_ce_gt.txt"}, + {"name": "tpl_Pool_ce1", "path": "tpl_Pool_ce1/img", "startFrame": 1, "endFrame": 166, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce1/Pool_ce1_gt.txt"}, + {"name": "tpl_MountainBike", "path": "tpl_MountainBike/img", "startFrame": 1, "endFrame": 228, "nz": 4, + "ext": "jpg", "anno_path": "tpl_MountainBike/MountainBike_gt.txt"}, + {"name": "tpl_Guitar_ce1", "path": "tpl_Guitar_ce1/img", "startFrame": 1, "endFrame": 268, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Guitar_ce1/Guitar_ce1_gt.txt"}, + {"name": "tpl_Busstation_ce1", "path": "tpl_Busstation_ce1/img", "startFrame": 1, "endFrame": 363, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Busstation_ce1/Busstation_ce1_gt.txt"}, + {"name": "tpl_Diving", "path": "tpl_Diving/img", "startFrame": 1, "endFrame": 231, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Diving/Diving_gt.txt"}, + {"name": "tpl_Skating_ce1", "path": "tpl_Skating_ce1/img", "startFrame": 1, "endFrame": 409, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating_ce1/Skating_ce1_gt.txt"}, + {"name": "tpl_Hurdle_ce2", "path": "tpl_Hurdle_ce2/img", "startFrame": 27, "endFrame": 330, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hurdle_ce2/Hurdle_ce2_gt.txt"}, + {"name": "tpl_Plate_ce2", "path": "tpl_Plate_ce2/img", "startFrame": 1, "endFrame": 181, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plate_ce2/Plate_ce2_gt.txt"}, + {"name": "tpl_CarDark", "path": "tpl_CarDark/img", "startFrame": 1, "endFrame": 393, "nz": 4, "ext": "jpg", + "anno_path": "tpl_CarDark/CarDark_gt.txt"}, + {"name": "tpl_Singer_ce2", "path": "tpl_Singer_ce2/img", "startFrame": 1, "endFrame": 999, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Singer_ce2/Singer_ce2_gt.txt"}, + {"name": "tpl_Shaking", "path": "tpl_Shaking/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Shaking/Shaking_gt.txt"}, + {"name": "tpl_Iceskater", "path": "tpl_Iceskater/img", "startFrame": 1, "endFrame": 500, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Iceskater/Iceskater_gt.txt"}, + {"name": "tpl_Badminton_ce2", "path": "tpl_Badminton_ce2/img", "startFrame": 1, "endFrame": 705, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Badminton_ce2/Badminton_ce2_gt.txt"}, + {"name": "tpl_Spiderman_ce", "path": "tpl_Spiderman_ce/img", "startFrame": 1, "endFrame": 351, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Spiderman_ce/Spiderman_ce_gt.txt"}, + {"name": "tpl_Kite_ce1", "path": "tpl_Kite_ce1/img", "startFrame": 1, "endFrame": 484, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce1/Kite_ce1_gt.txt"}, + {"name": "tpl_Skyjumping_ce", "path": "tpl_Skyjumping_ce/img", "startFrame": 1, "endFrame": 938, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skyjumping_ce/Skyjumping_ce_gt.txt"}, + {"name": "tpl_Ball_ce1", "path": "tpl_Ball_ce1/img", "startFrame": 1, "endFrame": 391, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce1/Ball_ce1_gt.txt"}, + {"name": "tpl_Yo_yos_ce2", "path": "tpl_Yo_yos_ce2/img", "startFrame": 1, "endFrame": 454, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce2/Yo-yos_ce2_gt.txt"}, + {"name": "tpl_Ironman", "path": "tpl_Ironman/img", "startFrame": 1, "endFrame": 166, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Ironman/Ironman_gt.txt"}, + {"name": "tpl_FaceOcc1", "path": "tpl_FaceOcc1/img", "startFrame": 1, "endFrame": 892, "nz": 4, + "ext": "jpg", "anno_path": "tpl_FaceOcc1/FaceOcc1_gt.txt"}, + {"name": "tpl_Surf_ce1", "path": "tpl_Surf_ce1/img", "startFrame": 1, "endFrame": 404, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce1/Surf_ce1_gt.txt"}, + {"name": "tpl_Ring_ce", "path": "tpl_Ring_ce/img", "startFrame": 1, "endFrame": 201, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Ring_ce/Ring_ce_gt.txt"}, + {"name": "tpl_Surf_ce4", "path": "tpl_Surf_ce4/img", "startFrame": 1, "endFrame": 135, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce4/Surf_ce4_gt.txt"}, + {"name": "tpl_Ball_ce4", "path": "tpl_Ball_ce4/img", "startFrame": 1, "endFrame": 538, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce4/Ball_ce4_gt.txt"}, + {"name": "tpl_Bikeshow_ce", "path": "tpl_Bikeshow_ce/img", "startFrame": 1, "endFrame": 361, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bikeshow_ce/Bikeshow_ce_gt.txt"}, + {"name": "tpl_Kobe_ce", "path": "tpl_Kobe_ce/img", "startFrame": 1, "endFrame": 582, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Kobe_ce/Kobe_ce_gt.txt"}, + {"name": "tpl_Tiger1", "path": "tpl_Tiger1/img", "startFrame": 1, "endFrame": 354, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Tiger1/Tiger1_gt.txt"}, + {"name": "tpl_Skiing", "path": "tpl_Skiing/img", "startFrame": 1, "endFrame": 81, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Skiing/Skiing_gt.txt"}, + {"name": "tpl_Tennis_ce1", "path": "tpl_Tennis_ce1/img", "startFrame": 1, "endFrame": 454, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce1/Tennis_ce1_gt.txt"}, + {"name": "tpl_Carchasing_ce4", "path": "tpl_Carchasing_ce4/img", "startFrame": 1, "endFrame": 442, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce4/Carchasing_ce4_gt.txt"}, + {"name": "tpl_Walking2", "path": "tpl_Walking2/img", "startFrame": 1, "endFrame": 500, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Walking2/Walking2_gt.txt"}, + {"name": "tpl_Sailor_ce", "path": "tpl_Sailor_ce/img", "startFrame": 1, "endFrame": 402, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Sailor_ce/Sailor_ce_gt.txt"}, + {"name": "tpl_Railwaystation_ce", "path": "tpl_Railwaystation_ce/img", "startFrame": 1, "endFrame": 413, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Railwaystation_ce/Railwaystation_ce_gt.txt"}, + {"name": "tpl_Bee_ce", "path": "tpl_Bee_ce/img", "startFrame": 1, "endFrame": 90, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bee_ce/Bee_ce_gt.txt"}, + {"name": "tpl_Girl", "path": "tpl_Girl/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Girl/Girl_gt.txt"}, + {"name": "tpl_Subway", "path": "tpl_Subway/img", "startFrame": 1, "endFrame": 175, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Subway/Subway_gt.txt"}, + {"name": "tpl_David3", "path": "tpl_David3/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", + "anno_path": "tpl_David3/David3_gt.txt"}, + {"name": "tpl_Electricalbike_ce", "path": "tpl_Electricalbike_ce/img", "startFrame": 1, "endFrame": 818, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Electricalbike_ce/Electricalbike_ce_gt.txt"}, + {"name": "tpl_Michaeljackson_ce", "path": "tpl_Michaeljackson_ce/img", "startFrame": 1, "endFrame": 393, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Michaeljackson_ce/Michaeljackson_ce_gt.txt"}, + {"name": "tpl_Woman", "path": "tpl_Woman/img", "startFrame": 1, "endFrame": 597, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Woman/Woman_gt.txt"}, + {"name": "tpl_TableTennis_ce", "path": "tpl_TableTennis_ce/img", "startFrame": 1, "endFrame": 198, "nz": 4, + "ext": "jpg", "anno_path": "tpl_TableTennis_ce/TableTennis_ce_gt.txt"}, + {"name": "tpl_Motorbike_ce", "path": "tpl_Motorbike_ce/img", "startFrame": 1, "endFrame": 563, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Motorbike_ce/Motorbike_ce_gt.txt"}, + {"name": "tpl_Baby_ce", "path": "tpl_Baby_ce/img", "startFrame": 1, "endFrame": 296, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Baby_ce/Baby_ce_gt.txt"}, + {"name": "tpl_Gym", "path": "tpl_Gym/img", "startFrame": 1, "endFrame": 766, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Gym/Gym_gt.txt"}, + {"name": "tpl_Matrix", "path": "tpl_Matrix/img", "startFrame": 1, "endFrame": 100, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Matrix/Matrix_gt.txt"}, + {"name": "tpl_Kite_ce3", "path": "tpl_Kite_ce3/img", "startFrame": 1, "endFrame": 528, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce3/Kite_ce3_gt.txt"}, + {"name": "tpl_Fish_ce1", "path": "tpl_Fish_ce1/img", "startFrame": 1, "endFrame": 401, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Fish_ce1/Fish_ce1_gt.txt"}, + {"name": "tpl_Hand_ce1", "path": "tpl_Hand_ce1/img", "startFrame": 1, "endFrame": 401, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hand_ce1/Hand_ce1_gt.txt"}, + {"name": "tpl_Doll", "path": "tpl_Doll/img", "startFrame": 1, "endFrame": 3872, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Doll/Doll_gt.txt"}, + {"name": "tpl_Carchasing_ce3", "path": "tpl_Carchasing_ce3/img", "startFrame": 1, "endFrame": 572, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce3/Carchasing_ce3_gt.txt"}, + {"name": "tpl_Thunder_ce", "path": "tpl_Thunder_ce/img", "startFrame": 1, "endFrame": 375, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Thunder_ce/Thunder_ce_gt.txt"}, + {"name": "tpl_Singer2", "path": "tpl_Singer2/img", "startFrame": 1, "endFrame": 366, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Singer2/Singer2_gt.txt"}, + {"name": "tpl_Basketball", "path": "tpl_Basketball/img", "startFrame": 1, "endFrame": 725, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball/Basketball_gt.txt"}, + {"name": "tpl_Hand", "path": "tpl_Hand/img", "startFrame": 1, "endFrame": 244, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Hand/Hand_gt.txt"}, + {"name": "tpl_Cup_ce", "path": "tpl_Cup_ce/img", "startFrame": 1, "endFrame": 338, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Cup_ce/Cup_ce_gt.txt"}, + {"name": "tpl_MotorRolling", "path": "tpl_MotorRolling/img", "startFrame": 1, "endFrame": 164, "nz": 4, + "ext": "jpg", "anno_path": "tpl_MotorRolling/MotorRolling_gt.txt"}, + {"name": "tpl_Boat_ce2", "path": "tpl_Boat_ce2/img", "startFrame": 1, "endFrame": 412, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Boat_ce2/Boat_ce2_gt.txt"}, + {"name": "tpl_CarScale", "path": "tpl_CarScale/img", "startFrame": 1, "endFrame": 252, "nz": 4, + "ext": "jpg", "anno_path": "tpl_CarScale/CarScale_gt.txt"}, + {"name": "tpl_Sunshade", "path": "tpl_Sunshade/img", "startFrame": 1, "endFrame": 172, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Sunshade/Sunshade_gt.txt"}, + {"name": "tpl_Football1", "path": "tpl_Football1/img", "startFrame": 1, "endFrame": 74, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Football1/Football1_gt.txt"}, + {"name": "tpl_Singer1", "path": "tpl_Singer1/img", "startFrame": 1, "endFrame": 351, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Singer1/Singer1_gt.txt"}, + {"name": "tpl_Hurdle_ce1", "path": "tpl_Hurdle_ce1/img", "startFrame": 1, "endFrame": 300, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hurdle_ce1/Hurdle_ce1_gt.txt"}, + {"name": "tpl_Basketball_ce3", "path": "tpl_Basketball_ce3/img", "startFrame": 1, "endFrame": 441, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce3/Basketball_ce3_gt.txt"}, + {"name": "tpl_Toyplane_ce", "path": "tpl_Toyplane_ce/img", "startFrame": 1, "endFrame": 405, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Toyplane_ce/Toyplane_ce_gt.txt"}, + {"name": "tpl_Skating1", "path": "tpl_Skating1/img", "startFrame": 1, "endFrame": 400, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating1/Skating1_gt.txt"}, + {"name": "tpl_Juice", "path": "tpl_Juice/img", "startFrame": 1, "endFrame": 404, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Juice/Juice_gt.txt"}, + {"name": "tpl_Biker", "path": "tpl_Biker/img", "startFrame": 1, "endFrame": 180, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Biker/Biker_gt.txt"}, + {"name": "tpl_Boy", "path": "tpl_Boy/img", "startFrame": 1, "endFrame": 602, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Boy/Boy_gt.txt"}, + {"name": "tpl_Jogging1", "path": "tpl_Jogging1/img", "startFrame": 1, "endFrame": 307, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Jogging1/Jogging1_gt.txt"}, + {"name": "tpl_Deer", "path": "tpl_Deer/img", "startFrame": 1, "endFrame": 71, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Deer/Deer_gt.txt"}, + {"name": "tpl_Panda", "path": "tpl_Panda/img", "startFrame": 1, "endFrame": 241, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Panda/Panda_gt.txt"}, + {"name": "tpl_Coke", "path": "tpl_Coke/img", "startFrame": 1, "endFrame": 291, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Coke/Coke_gt.txt"}, + {"name": "tpl_Carchasing_ce1", "path": "tpl_Carchasing_ce1/img", "startFrame": 1, "endFrame": 501, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce1/Carchasing_ce1_gt.txt"}, + {"name": "tpl_Badminton_ce1", "path": "tpl_Badminton_ce1/img", "startFrame": 1, "endFrame": 579, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Badminton_ce1/Badminton_ce1_gt.txt"}, + {"name": "tpl_Trellis", "path": "tpl_Trellis/img", "startFrame": 1, "endFrame": 569, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Trellis/Trellis_gt.txt"}, + {"name": "tpl_Face_ce2", "path": "tpl_Face_ce2/img", "startFrame": 1, "endFrame": 148, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Face_ce2/Face_ce2_gt.txt"}, + {"name": "tpl_Ball_ce2", "path": "tpl_Ball_ce2/img", "startFrame": 1, "endFrame": 603, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce2/Ball_ce2_gt.txt"}, + {"name": "tpl_Skiing_ce", "path": "tpl_Skiing_ce/img", "startFrame": 1, "endFrame": 511, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skiing_ce/Skiing_ce_gt.txt"}, + {"name": "tpl_Jogging2", "path": "tpl_Jogging2/img", "startFrame": 1, "endFrame": 307, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Jogging2/Jogging2_gt.txt"}, + {"name": "tpl_Bike_ce1", "path": "tpl_Bike_ce1/img", "startFrame": 1, "endFrame": 801, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bike_ce1/Bike_ce1_gt.txt"}, + {"name": "tpl_Bike_ce2", "path": "tpl_Bike_ce2/img", "startFrame": 1, "endFrame": 812, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bike_ce2/Bike_ce2_gt.txt"}, + {"name": "tpl_Ball_ce3", "path": "tpl_Ball_ce3/img", "startFrame": 1, "endFrame": 273, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce3/Ball_ce3_gt.txt"}, + {"name": "tpl_Girlmov", "path": "tpl_Girlmov/img", "startFrame": 1, "endFrame": 1500, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Girlmov/Girlmov_gt.txt"}, + {"name": "tpl_Bolt", "path": "tpl_Bolt/img", "startFrame": 1, "endFrame": 350, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bolt/Bolt_gt.txt"}, + {"name": "tpl_Basketball_ce2", "path": "tpl_Basketball_ce2/img", "startFrame": 1, "endFrame": 455, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce2/Basketball_ce2_gt.txt"}, + {"name": "tpl_Bicycle", "path": "tpl_Bicycle/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bicycle/Bicycle_gt.txt"}, + {"name": "tpl_Face_ce", "path": "tpl_Face_ce/img", "startFrame": 1, "endFrame": 620, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Face_ce/Face_ce_gt.txt"}, + {"name": "tpl_Basketball_ce1", "path": "tpl_Basketball_ce1/img", "startFrame": 1, "endFrame": 496, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce1/Basketball_ce1_gt.txt"}, + {"name": "tpl_Messi_ce", "path": "tpl_Messi_ce/img", "startFrame": 1, "endFrame": 272, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Messi_ce/Messi_ce_gt.txt"}, + {"name": "tpl_Tennis_ce2", "path": "tpl_Tennis_ce2/img", "startFrame": 1, "endFrame": 305, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce2/Tennis_ce2_gt.txt"}, + {"name": "tpl_Microphone_ce2", "path": "tpl_Microphone_ce2/img", "startFrame": 1, "endFrame": 103, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Microphone_ce2/Microphone_ce2_gt.txt"}, + {"name": "tpl_Guitar_ce2", "path": "tpl_Guitar_ce2/img", "startFrame": 1, "endFrame": 313, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Guitar_ce2/Guitar_ce2_gt.txt"} + + ] + + otb_sequences = ['tpl_Skating2', 'tpl_Lemming', 'tpl_Board', 'tpl_Soccer', 'tpl_Liquor', 'tpl_Couple', 'tpl_Walking', 'tpl_David', 'tpl_Tiger2', 'tpl_Bird', 'tpl_Crossing', 'tpl_MountainBike', + 'tpl_Diving', 'tpl_CarDark', 'tpl_Shaking', 'tpl_Ironman', 'tpl_FaceOcc1', 'tpl_Tiger1', 'tpl_Skiing', 'tpl_Walking2', 'tpl_Girl', 'tpl_Girlmov', 'tpl_Subway', 'tpl_David3', 'tpl_Woman', + 'tpl_Gym', 'tpl_Matrix', 'tpl_Doll', 'tpl_Singer2', 'tpl_Basketball', 'tpl_MotorRolling', 'tpl_CarScale', 'tpl_Football1', 'tpl_Singer1', 'tpl_Skating1', 'tpl_Biker', + 'tpl_Boy', 'tpl_Jogging1', 'tpl_Deer', 'tpl_Panda', 'tpl_Coke', 'tpl_Trellis', 'tpl_Jogging2', 'tpl_Bolt', ] + if exclude_otb: + sequence_info_list_nootb = [] + for seq in sequence_info_list: + if seq['name'] not in otb_sequences: + sequence_info_list_nootb.append(seq) + + sequence_info_list = sequence_info_list_nootb + + return sequence_info_list diff --git a/Stark/external/AR/pytracking/evaluation/tracker.py b/Stark/external/AR/pytracking/evaluation/tracker.py new file mode 100755 index 0000000..f6aad5b --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/tracker.py @@ -0,0 +1,693 @@ +import importlib +import os +import numpy as np +from collections import OrderedDict +from pytracking.evaluation.environment import env_settings +import time +import cv2 as cv +from pytracking.utils.visdom import Visdom +import matplotlib.pyplot as plt +import matplotlib.patches as patches +from pytracking.utils.plotting import draw_figure, overlay_mask +from pytracking.utils.convert_vot_anno_to_rect import convert_vot_anno_to_rect +from ltr.data.bounding_box_utils import masks_to_bboxes +from pytracking.evaluation.multi_object_wrapper import MultiObjectWrapper +import torch + + +_tracker_disp_colors = {1: (0, 255, 0), 2: (0, 0, 255), 3: (255, 0, 0), + 4: (255, 255, 255), 5: (0, 0, 0), 6: (0, 255, 128), + 7: (123, 123, 123), 8: (255, 128, 0), 9: (128, 0, 255)} + + +def trackerlist(name: str, parameter_name: str, run_ids = None, display_name: str = None): + """Generate list of trackers. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_ids: A single or list of run_ids. + display_name: Name to be displayed in the result plots. + """ + if run_ids is None or isinstance(run_ids, int): + run_ids = [run_ids] + return [Tracker(name, parameter_name, run_id, display_name) for run_id in run_ids] + + +class Tracker: + """Wraps the tracker for evaluation and running purposes. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_id: The run id. + display_name: Name to be displayed in the result plots. + """ + + def __init__(self, name: str, parameter_name: str, run_id: int = None, display_name: str = None): + assert run_id is None or isinstance(run_id, int) + + self.name = name + self.parameter_name = parameter_name + self.run_id = run_id + self.display_name = display_name + + env = env_settings() + if self.run_id is None: + self.results_dir = '{}/{}/{}'.format(env.results_path, self.name, self.parameter_name) + self.segmentation_dir = '{}/{}/{}'.format(env.segmentation_path, self.name, self.parameter_name) + else: + self.results_dir = '{}/{}/{}_{:03d}'.format(env.results_path, self.name, self.parameter_name, self.run_id) + self.segmentation_dir = '{}/{}/{}_{:03d}'.format(env.segmentation_path, self.name, self.parameter_name, self.run_id) + + tracker_module_abspath = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'tracker', self.name)) + if os.path.isdir(tracker_module_abspath): + tracker_module = importlib.import_module('pytracking.tracker.{}'.format(self.name)) + self.tracker_class = tracker_module.get_tracker_class() + else: + self.tracker_class = None + + self.visdom = None + + + def _init_visdom(self, visdom_info, debug): + visdom_info = {} if visdom_info is None else visdom_info + self.pause_mode = False + self.step = False + if debug > 0 and visdom_info.get('use_visdom', True): + try: + self.visdom = Visdom(debug, {'handler': self._visdom_ui_handler, 'win_id': 'Tracking'}, + visdom_info=visdom_info) + + # Show help + help_text = 'You can pause/unpause the tracker by pressing ''space'' with the ''Tracking'' window ' \ + 'selected. During paused mode, you can track for one frame by pressing the right arrow key.' \ + 'To enable/disable plotting of a data block, tick/untick the corresponding entry in ' \ + 'block list.' + self.visdom.register(help_text, 'text', 1, 'Help') + except: + time.sleep(0.5) + print('!!! WARNING: Visdom could not start, so using matplotlib visualization instead !!!\n' + '!!! Start Visdom in a separate terminal window by typing \'visdom\' !!!') + + def _visdom_ui_handler(self, data): + if data['event_type'] == 'KeyPress': + if data['key'] == ' ': + self.pause_mode = not self.pause_mode + + elif data['key'] == 'ArrowRight' and self.pause_mode: + self.step = True + + + def create_tracker(self, params): + tracker = self.tracker_class(params) + tracker.visdom = self.visdom + return tracker + + def run_sequence(self, seq, visualization=None, debug=None, visdom_info=None, multiobj_mode=None): + """Run tracker on sequence. + args: + seq: Sequence to run the tracker on. + visualization: Set visualization flag (None means default value specified in the parameters). + debug: Set debug level (None means default value specified in the parameters). + visdom_info: Visdom info. + multiobj_mode: Which mode to use for multiple objects. + """ + params = self.get_parameters() + visualization_ = visualization + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + if visualization is None: + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + if visualization_ and self.visdom is None: + self.init_visualization() + + # Get init information + init_info = seq.init_info() + is_single_object = not seq.multiobj_mode + + if multiobj_mode is None: + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default' or is_single_object: + tracker = self.create_tracker(params) + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + output = self._track_sequence(tracker, seq, init_info) + return output + + def _track_sequence(self, tracker, seq, init_info): + # Define outputs + # Each field in output is a list containing tracker prediction for each frame. + + # In case of single object tracking mode: + # target_bbox[i] is the predicted bounding box for frame i + # time[i] is the processing time for frame i + # segmentation[i] is the segmentation mask for frame i (numpy array) + + # In case of multi object tracking mode: + # target_bbox[i] is an OrderedDict, where target_bbox[i][obj_id] is the predicted box for target obj_id in + # frame i + # time[i] is either the processing time for frame i, or an OrderedDict containing processing times for each + # object in frame i + # segmentation[i] is the multi-label segmentation mask for frame i (numpy array) + + output = {'target_bbox': [], + 'time': [], + 'segmentation': []} + + def _store_outputs(tracker_out: dict, defaults=None): + defaults = {} if defaults is None else defaults + for key in output.keys(): + val = tracker_out.get(key, defaults.get(key, None)) + if key in tracker_out or val is not None: + output[key].append(val) + + # Initialize + image = self._read_image(seq.frames[0]) + + if tracker.params.visualization and self.visdom is None: + self.visualize(image, init_info.get('init_bbox')) + + start_time = time.time() + out = tracker.initialize(image, init_info) + if out is None: + out = {} + + prev_output = OrderedDict(out) + + init_default = {'target_bbox': init_info.get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info.get('init_mask')} + + _store_outputs(out, init_default) + + for frame_num, frame_path in enumerate(seq.frames[1:], start=1): + while True: + if not self.pause_mode: + break + elif self.step: + self.step = False + break + else: + time.sleep(0.1) + + image = self._read_image(frame_path) + + start_time = time.time() + + info = seq.frame_info(frame_num) + info['previous_output'] = prev_output + + out = tracker.track(image, info) + prev_output = OrderedDict(out) + _store_outputs(out, {'time': time.time() - start_time}) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + for key in ['target_bbox', 'segmentation']: + if key in output and len(output[key]) <= 1: + output.pop(key) + + return output + + def run_video(self, videofilepath, optional_box=None, debug=None, visdom_info=None): + """Run the tracker with the vieofile. + args: + debug: Debug level. + """ + + params = self.get_parameters() + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = self.name + params.param_name = self.parameter_name + self._init_visdom(visdom_info, debug_) + + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default': + tracker = self.create_tracker(params) + if hasattr(tracker, 'initialize_features'): + tracker.initialize_features() + + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom, fast_load=True) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + assert os.path.isfile(videofilepath), "Invalid param {}".format(videofilepath) + ", videofilepath must be a valid videofile" + + cap = cv.VideoCapture(videofilepath) + display_name = 'Display: ' + tracker.params.tracker_name + cv.namedWindow(display_name, cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO) + cv.resizeWindow(display_name, 960, 720) + success, frame = cap.read() + cv.imshow(display_name, frame) + + def _build_init_info(box): + return {'init_bbox': OrderedDict({1: box}), 'init_object_ids': [1, ], 'object_ids': [1, ], + 'sequence_object_ids': [1, ]} + + if success is not True: + print("Read frame from {} failed.".format(videofilepath)) + exit(-1) + if optional_box is not None: + assert isinstance(optional_box, list, tuple) + assert len(optional_box) == 4, "valid box's foramt is [x,y,w,h]" + tracker.initialize(frame, _build_init_info(optional_box)) + else: + while True: + # cv.waitKey() + frame_disp = frame.copy() + + cv.putText(frame_disp, 'Select target ROI and press ENTER', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, + 1.5, (0, 0, 0), 1) + + x, y, w, h = cv.selectROI(display_name, frame_disp, fromCenter=False) + init_state = [x, y, w, h] + tracker.initialize(frame, _build_init_info(init_state)) + break + + while True: + ret, frame = cap.read() + + if frame is None: + return + + frame_disp = frame.copy() + + # Draw box + out = tracker.track(frame) + state = [int(s) for s in out['target_bbox'][1]] + cv.rectangle(frame_disp, (state[0], state[1]), (state[2] + state[0], state[3] + state[1]), + (0, 255, 0), 5) + + font_color = (0, 0, 0) + cv.putText(frame_disp, 'Tracking!', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press r to reset', (20, 55), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press q to quit', (20, 80), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + + # Display the resulting frame + cv.imshow(display_name, frame_disp) + key = cv.waitKey(1) + if key == ord('q'): + break + elif key == ord('r'): + ret, frame = cap.read() + frame_disp = frame.copy() + + cv.putText(frame_disp, 'Select target ROI and press ENTER', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1.5, + (0, 0, 0), 1) + + cv.imshow(display_name, frame_disp) + x, y, w, h = cv.selectROI(display_name, frame_disp, fromCenter=False) + init_state = [x, y, w, h] + tracker.initialize(frame, _build_init_info(init_state)) + + # When everything done, release the capture + cap.release() + cv.destroyAllWindows() + + + def run_webcam(self, debug=None, visdom_info=None): + """Run the tracker with the webcam. + args: + debug: Debug level. + """ + + params = self.get_parameters() + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = self.name + params.param_name = self.parameter_name + + self._init_visdom(visdom_info, debug_) + + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default': + tracker = self.create_tracker(params) + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom, fast_load=True) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + class UIControl: + def __init__(self): + self.mode = 'init' # init, select, track + self.target_tl = (-1, -1) + self.target_br = (-1, -1) + self.new_init = False + + def mouse_callback(self, event, x, y, flags, param): + if event == cv.EVENT_LBUTTONDOWN and self.mode == 'init': + self.target_tl = (x, y) + self.target_br = (x, y) + self.mode = 'select' + elif event == cv.EVENT_MOUSEMOVE and self.mode == 'select': + self.target_br = (x, y) + elif event == cv.EVENT_LBUTTONDOWN and self.mode == 'select': + self.target_br = (x, y) + self.mode = 'init' + self.new_init = True + + def get_tl(self): + return self.target_tl if self.target_tl[0] < self.target_br[0] else self.target_br + + def get_br(self): + return self.target_br if self.target_tl[0] < self.target_br[0] else self.target_tl + + def get_bb(self): + tl = self.get_tl() + br = self.get_br() + + bb = [min(tl[0], br[0]), min(tl[1], br[1]), abs(br[0] - tl[0]), abs(br[1] - tl[1])] + return bb + + ui_control = UIControl() + cap = cv.VideoCapture(0) + display_name = 'Display: ' + self.name + cv.namedWindow(display_name, cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO) + cv.resizeWindow(display_name, 960, 720) + cv.setMouseCallback(display_name, ui_control.mouse_callback) + + next_object_id = 1 + sequence_object_ids = [] + prev_output = OrderedDict() + while True: + # Capture frame-by-frame + ret, frame = cap.read() + frame_disp = frame.copy() + + info = OrderedDict() + info['previous_output'] = prev_output + + if ui_control.new_init: + ui_control.new_init = False + init_state = ui_control.get_bb() + + info['init_object_ids'] = [next_object_id, ] + info['init_bbox'] = OrderedDict({next_object_id: init_state}) + sequence_object_ids.append(next_object_id) + + next_object_id += 1 + + # Draw box + if ui_control.mode == 'select': + cv.rectangle(frame_disp, ui_control.get_tl(), ui_control.get_br(), (255, 0, 0), 2) + + if len(sequence_object_ids) > 0: + info['sequence_object_ids'] = sequence_object_ids + out = tracker.track(frame, info) + prev_output = OrderedDict(out) + + if 'segmentation' in out: + frame_disp = overlay_mask(frame_disp, out['segmentation']) + + if 'target_bbox' in out: + for obj_id, state in out['target_bbox'].items(): + state = [int(s) for s in state] + cv.rectangle(frame_disp, (state[0], state[1]), (state[2] + state[0], state[3] + state[1]), + _tracker_disp_colors[obj_id], 5) + + # Put text + font_color = (0, 0, 0) + cv.putText(frame_disp, 'Select target', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, font_color, 1) + cv.putText(frame_disp, 'Press r to reset', (20, 55), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press q to quit', (20, 85), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + + # Display the resulting frame + cv.imshow(display_name, frame_disp) + key = cv.waitKey(1) + if key == ord('q'): + break + elif key == ord('r'): + next_object_id = 1 + sequence_object_ids = [] + prev_output = OrderedDict() + + info = OrderedDict() + + info['object_ids'] = [] + info['init_object_ids'] = [] + info['init_bbox'] = OrderedDict() + tracker.initialize(frame, info) + ui_control.mode = 'init' + + # When everything done, release the capture + cap.release() + cv.destroyAllWindows() + + def run_vot2020(self, debug=None, visdom_info=None): + params = self.get_parameters() + params.tracker_name = self.name + params.param_name = self.parameter_name + params.run_id = self.run_id + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + + tracker = self.create_tracker(params) + tracker.initialize_features() + + output_segmentation = tracker.predicts_segmentation_mask() + + import pytracking.evaluation.vot2020 as vot + + def _convert_anno_to_list(vot_anno): + vot_anno = [vot_anno[0], vot_anno[1], vot_anno[2], vot_anno[3]] + return vot_anno + + def _convert_image_path(image_path): + return image_path + + """Run tracker on VOT.""" + + if output_segmentation: + handle = vot.VOT("mask") + else: + handle = vot.VOT("rectangle") + + vot_anno = handle.region() + + image_path = handle.frame() + if not image_path: + return + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + + if output_segmentation: + vot_anno_mask = vot.make_full_size(vot_anno, (image.shape[1], image.shape[0])) + bbox = masks_to_bboxes(torch.from_numpy(vot_anno_mask), fmt='t').squeeze().tolist() + else: + bbox = _convert_anno_to_list(vot_anno) + vot_anno_mask = None + + out = tracker.initialize(image, {'init_mask': vot_anno_mask, 'init_bbox': bbox}) + + if out is None: + out = {} + prev_output = OrderedDict(out) + + # Track + while True: + image_path = handle.frame() + if not image_path: + break + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + + info = OrderedDict() + info['previous_output'] = prev_output + + out = tracker.track(image, info) + prev_output = OrderedDict(out) + + if output_segmentation: + pred = out['segmentation'].astype(np.uint8) + else: + state = out['target_bbox'] + pred = vot.Rectangle(*state) + handle.report(pred, 1.0) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + + def run_vot(self, debug=None, visdom_info=None): + params = self.get_parameters() + params.tracker_name = self.name + params.param_name = self.parameter_name + params.run_id = self.run_id + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + + tracker = self.create_tracker(params) + tracker.initialize_features() + + import pytracking.evaluation.vot as vot + + def _convert_anno_to_list(vot_anno): + vot_anno = [vot_anno[0][0][0], vot_anno[0][0][1], vot_anno[0][1][0], vot_anno[0][1][1], + vot_anno[0][2][0], vot_anno[0][2][1], vot_anno[0][3][0], vot_anno[0][3][1]] + return vot_anno + + def _convert_image_path(image_path): + image_path_new = image_path[20:- 2] + return "".join(image_path_new) + + """Run tracker on VOT.""" + + handle = vot.VOT("polygon") + + vot_anno_polygon = handle.region() + vot_anno_polygon = _convert_anno_to_list(vot_anno_polygon) + + init_state = convert_vot_anno_to_rect(vot_anno_polygon, tracker.params.vot_anno_conversion_type) + + image_path = handle.frame() + if not image_path: + return + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + tracker.initialize(image, {'init_bbox': init_state}) + + # Track + while True: + image_path = handle.frame() + if not image_path: + break + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + out = tracker.track(image) + state = out['target_bbox'] + + handle.report(vot.Rectangle(state[0], state[1], state[2], state[3])) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + def get_parameters(self): + """Get parameters.""" + param_module = importlib.import_module('pytracking.parameter.{}.{}'.format(self.name, self.parameter_name)) + params = param_module.parameters() + return params + + + def init_visualization(self): + self.pause_mode = False + self.fig, self.ax = plt.subplots(1) + self.fig.canvas.mpl_connect('key_press_event', self.press) + plt.tight_layout() + + + def visualize(self, image, state, segmentation=None): + self.ax.cla() + self.ax.imshow(image) + if segmentation is not None: + self.ax.imshow(segmentation, alpha=0.5) + + if isinstance(state, (OrderedDict, dict)): + boxes = [v for k, v in state.items()] + else: + boxes = (state,) + + for i, box in enumerate(boxes, start=1): + col = _tracker_disp_colors[i] + col = [float(c) / 255.0 for c in col] + rect = patches.Rectangle((box[0], box[1]), box[2], box[3], linewidth=1, edgecolor=col, facecolor='none') + self.ax.add_patch(rect) + + if getattr(self, 'gt_state', None) is not None: + gt_state = self.gt_state + rect = patches.Rectangle((gt_state[0], gt_state[1]), gt_state[2], gt_state[3], linewidth=1, edgecolor='g', facecolor='none') + self.ax.add_patch(rect) + self.ax.set_axis_off() + self.ax.axis('equal') + draw_figure(self.fig) + + if self.pause_mode: + keypress = False + while not keypress: + keypress = plt.waitforbuttonpress() + + def reset_tracker(self): + pass + + def press(self, event): + if event.key == 'p': + self.pause_mode = not self.pause_mode + print("Switching pause mode!") + elif event.key == 'r': + self.reset_tracker() + print("Resetting target pos to gt!") + + def _read_image(self, image_file: str): + im = cv.imread(image_file) + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + + + diff --git a/Stark/external/AR/pytracking/evaluation/trackingnetdataset.py b/Stark/external/AR/pytracking/evaluation/trackingnetdataset.py new file mode 100755 index 0000000..09e5f0f --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/trackingnetdataset.py @@ -0,0 +1,58 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +import os +from pytracking.utils.load_text import load_text + + +class TrackingNetDataset(BaseDataset): + """ TrackingNet test set. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.trackingnet_path + + sets = 'TEST' + if not isinstance(sets, (list, tuple)): + if sets == 'TEST': + sets = ['TEST'] + elif sets == 'TRAIN': + sets = ['TRAIN_{}'.format(i) for i in range(5)] + + self.sequence_list = self._list_sequences(self.base_path, sets) + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(set, seq_name) for set, seq_name in self.sequence_list]) + + def _construct_sequence(self, set, sequence_name): + anno_path = '{}/{}/anno/{}.txt'.format(self.base_path, set, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64, backend='numpy') + + frames_path = '{}/{}/frames/{}'.format(self.base_path, set, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'trackingnet', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _list_sequences(self, root, set_ids): + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, s, "anno") + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + + sequence_list += sequences_cur_set + + return sequence_list diff --git a/Stark/external/AR/pytracking/evaluation/uavdataset.py b/Stark/external/AR/pytracking/evaluation/uavdataset.py new file mode 100755 index 0000000..1c6d099 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/uavdataset.py @@ -0,0 +1,299 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class UAVDataset(BaseDataset): + """ UAV123 dataset. + + Publication: + A Benchmark and Simulator for UAV Tracking. + Matthias Mueller, Neil Smith and Bernard Ghanem + ECCV, 2016 + https://ivul.kaust.edu.sa/Documents/Publications/2016/A%20Benchmark%20and%20Simulator%20for%20UAV%20Tracking.pdf + + Download the dataset from https://ivul.kaust.edu.sa/Pages/pub-benchmark-simulator-uav.aspx + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.uav_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'uav', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "uav_bike1", "path": "data_seq/UAV123/bike1", "startFrame": 1, "endFrame": 3085, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike1.txt", "object_class": "vehicle"}, + {"name": "uav_bike2", "path": "data_seq/UAV123/bike2", "startFrame": 1, "endFrame": 553, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike2.txt", "object_class": "vehicle"}, + {"name": "uav_bike3", "path": "data_seq/UAV123/bike3", "startFrame": 1, "endFrame": 433, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike3.txt", "object_class": "vehicle"}, + {"name": "uav_bird1_1", "path": "data_seq/UAV123/bird1", "startFrame": 1, "endFrame": 253, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_1.txt", "object_class": "bird"}, + {"name": "uav_bird1_2", "path": "data_seq/UAV123/bird1", "startFrame": 775, "endFrame": 1477, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_2.txt", "object_class": "bird"}, + {"name": "uav_bird1_3", "path": "data_seq/UAV123/bird1", "startFrame": 1573, "endFrame": 2437, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_3.txt", "object_class": "bird"}, + {"name": "uav_boat1", "path": "data_seq/UAV123/boat1", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat1.txt", "object_class": "vessel"}, + {"name": "uav_boat2", "path": "data_seq/UAV123/boat2", "startFrame": 1, "endFrame": 799, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat2.txt", "object_class": "vessel"}, + {"name": "uav_boat3", "path": "data_seq/UAV123/boat3", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat3.txt", "object_class": "vessel"}, + {"name": "uav_boat4", "path": "data_seq/UAV123/boat4", "startFrame": 1, "endFrame": 553, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat4.txt", "object_class": "vessel"}, + {"name": "uav_boat5", "path": "data_seq/UAV123/boat5", "startFrame": 1, "endFrame": 505, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat5.txt", "object_class": "vessel"}, + {"name": "uav_boat6", "path": "data_seq/UAV123/boat6", "startFrame": 1, "endFrame": 805, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat6.txt", "object_class": "vessel"}, + {"name": "uav_boat7", "path": "data_seq/UAV123/boat7", "startFrame": 1, "endFrame": 535, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat7.txt", "object_class": "vessel"}, + {"name": "uav_boat8", "path": "data_seq/UAV123/boat8", "startFrame": 1, "endFrame": 685, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat8.txt", "object_class": "vessel"}, + {"name": "uav_boat9", "path": "data_seq/UAV123/boat9", "startFrame": 1, "endFrame": 1399, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat9.txt", "object_class": "vessel"}, + {"name": "uav_building1", "path": "data_seq/UAV123/building1", "startFrame": 1, "endFrame": 469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building1.txt", "object_class": "other"}, + {"name": "uav_building2", "path": "data_seq/UAV123/building2", "startFrame": 1, "endFrame": 577, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building2.txt", "object_class": "other"}, + {"name": "uav_building3", "path": "data_seq/UAV123/building3", "startFrame": 1, "endFrame": 829, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building3.txt", "object_class": "other"}, + {"name": "uav_building4", "path": "data_seq/UAV123/building4", "startFrame": 1, "endFrame": 787, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building4.txt", "object_class": "other"}, + {"name": "uav_building5", "path": "data_seq/UAV123/building5", "startFrame": 1, "endFrame": 481, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building5.txt", "object_class": "other"}, + {"name": "uav_car1_1", "path": "data_seq/UAV123/car1", "startFrame": 1, "endFrame": 751, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_1.txt", "object_class": "car"}, + {"name": "uav_car1_2", "path": "data_seq/UAV123/car1", "startFrame": 751, "endFrame": 1627, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_2.txt", "object_class": "car"}, + {"name": "uav_car1_3", "path": "data_seq/UAV123/car1", "startFrame": 1627, "endFrame": 2629, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_3.txt", "object_class": "car"}, + {"name": "uav_car10", "path": "data_seq/UAV123/car10", "startFrame": 1, "endFrame": 1405, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car10.txt", "object_class": "car"}, + {"name": "uav_car11", "path": "data_seq/UAV123/car11", "startFrame": 1, "endFrame": 337, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car11.txt", "object_class": "car"}, + {"name": "uav_car12", "path": "data_seq/UAV123/car12", "startFrame": 1, "endFrame": 499, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car12.txt", "object_class": "car"}, + {"name": "uav_car13", "path": "data_seq/UAV123/car13", "startFrame": 1, "endFrame": 415, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car13.txt", "object_class": "car"}, + {"name": "uav_car14", "path": "data_seq/UAV123/car14", "startFrame": 1, "endFrame": 1327, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car14.txt", "object_class": "car"}, + {"name": "uav_car15", "path": "data_seq/UAV123/car15", "startFrame": 1, "endFrame": 469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car15.txt", "object_class": "car"}, + {"name": "uav_car16_1", "path": "data_seq/UAV123/car16", "startFrame": 1, "endFrame": 415, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car16_1.txt", "object_class": "car"}, + {"name": "uav_car16_2", "path": "data_seq/UAV123/car16", "startFrame": 415, "endFrame": 1993, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car16_2.txt", "object_class": "car"}, + {"name": "uav_car17", "path": "data_seq/UAV123/car17", "startFrame": 1, "endFrame": 1057, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car17.txt", "object_class": "car"}, + {"name": "uav_car18", "path": "data_seq/UAV123/car18", "startFrame": 1, "endFrame": 1207, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car18.txt", "object_class": "car"}, + {"name": "uav_car1_s", "path": "data_seq/UAV123/car1_s", "startFrame": 1, "endFrame": 1475, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_s.txt", "object_class": "car"}, + {"name": "uav_car2", "path": "data_seq/UAV123/car2", "startFrame": 1, "endFrame": 1321, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car2.txt", "object_class": "car"}, + {"name": "uav_car2_s", "path": "data_seq/UAV123/car2_s", "startFrame": 1, "endFrame": 320, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car2_s.txt", "object_class": "car"}, + {"name": "uav_car3", "path": "data_seq/UAV123/car3", "startFrame": 1, "endFrame": 1717, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car3.txt", "object_class": "car"}, + {"name": "uav_car3_s", "path": "data_seq/UAV123/car3_s", "startFrame": 1, "endFrame": 1300, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car3_s.txt", "object_class": "car"}, + {"name": "uav_car4", "path": "data_seq/UAV123/car4", "startFrame": 1, "endFrame": 1345, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car4.txt", "object_class": "car"}, + {"name": "uav_car4_s", "path": "data_seq/UAV123/car4_s", "startFrame": 1, "endFrame": 830, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car4_s.txt", "object_class": "car"}, + {"name": "uav_car5", "path": "data_seq/UAV123/car5", "startFrame": 1, "endFrame": 745, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car5.txt", "object_class": "car"}, + {"name": "uav_car6_1", "path": "data_seq/UAV123/car6", "startFrame": 1, "endFrame": 487, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_1.txt", "object_class": "car"}, + {"name": "uav_car6_2", "path": "data_seq/UAV123/car6", "startFrame": 487, "endFrame": 1807, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_2.txt", "object_class": "car"}, + {"name": "uav_car6_3", "path": "data_seq/UAV123/car6", "startFrame": 1807, "endFrame": 2953, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_3.txt", "object_class": "car"}, + {"name": "uav_car6_4", "path": "data_seq/UAV123/car6", "startFrame": 2953, "endFrame": 3925, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_4.txt", "object_class": "car"}, + {"name": "uav_car6_5", "path": "data_seq/UAV123/car6", "startFrame": 3925, "endFrame": 4861, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_5.txt", "object_class": "car"}, + {"name": "uav_car7", "path": "data_seq/UAV123/car7", "startFrame": 1, "endFrame": 1033, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car7.txt", "object_class": "car"}, + {"name": "uav_car8_1", "path": "data_seq/UAV123/car8", "startFrame": 1, "endFrame": 1357, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car8_1.txt", "object_class": "car"}, + {"name": "uav_car8_2", "path": "data_seq/UAV123/car8", "startFrame": 1357, "endFrame": 2575, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car8_2.txt", "object_class": "car"}, + {"name": "uav_car9", "path": "data_seq/UAV123/car9", "startFrame": 1, "endFrame": 1879, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car9.txt", "object_class": "car"}, + {"name": "uav_group1_1", "path": "data_seq/UAV123/group1", "startFrame": 1, "endFrame": 1333, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_1.txt", "object_class": "person"}, + {"name": "uav_group1_2", "path": "data_seq/UAV123/group1", "startFrame": 1333, "endFrame": 2515, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_2.txt", "object_class": "person"}, + {"name": "uav_group1_3", "path": "data_seq/UAV123/group1", "startFrame": 2515, "endFrame": 3925, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_3.txt", "object_class": "person"}, + {"name": "uav_group1_4", "path": "data_seq/UAV123/group1", "startFrame": 3925, "endFrame": 4873, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_4.txt", "object_class": "person"}, + {"name": "uav_group2_1", "path": "data_seq/UAV123/group2", "startFrame": 1, "endFrame": 907, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_1.txt", "object_class": "person"}, + {"name": "uav_group2_2", "path": "data_seq/UAV123/group2", "startFrame": 907, "endFrame": 1771, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_2.txt", "object_class": "person"}, + {"name": "uav_group2_3", "path": "data_seq/UAV123/group2", "startFrame": 1771, "endFrame": 2683, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_3.txt", "object_class": "person"}, + {"name": "uav_group3_1", "path": "data_seq/UAV123/group3", "startFrame": 1, "endFrame": 1567, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_1.txt", "object_class": "person"}, + {"name": "uav_group3_2", "path": "data_seq/UAV123/group3", "startFrame": 1567, "endFrame": 2827, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_2.txt", "object_class": "person"}, + {"name": "uav_group3_3", "path": "data_seq/UAV123/group3", "startFrame": 2827, "endFrame": 4369, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_3.txt", "object_class": "person"}, + {"name": "uav_group3_4", "path": "data_seq/UAV123/group3", "startFrame": 4369, "endFrame": 5527, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_4.txt", "object_class": "person"}, + {"name": "uav_person1", "path": "data_seq/UAV123/person1", "startFrame": 1, "endFrame": 799, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person1.txt", "object_class": "person"}, + {"name": "uav_person10", "path": "data_seq/UAV123/person10", "startFrame": 1, "endFrame": 1021, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person10.txt", "object_class": "person"}, + {"name": "uav_person11", "path": "data_seq/UAV123/person11", "startFrame": 1, "endFrame": 721, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person11.txt", "object_class": "person"}, + {"name": "uav_person12_1", "path": "data_seq/UAV123/person12", "startFrame": 1, "endFrame": 601, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person12_1.txt", "object_class": "person"}, + {"name": "uav_person12_2", "path": "data_seq/UAV123/person12", "startFrame": 601, "endFrame": 1621, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person12_2.txt", "object_class": "person"}, + {"name": "uav_person13", "path": "data_seq/UAV123/person13", "startFrame": 1, "endFrame": 883, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person13.txt", "object_class": "person"}, + {"name": "uav_person14_1", "path": "data_seq/UAV123/person14", "startFrame": 1, "endFrame": 847, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person14_1.txt", "object_class": "person"}, + {"name": "uav_person14_2", "path": "data_seq/UAV123/person14", "startFrame": 847, "endFrame": 1813, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person14_2.txt", "object_class": "person"}, + {"name": "uav_person14_3", "path": "data_seq/UAV123/person14", "startFrame": 1813, "endFrame": 2923, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person14_3.txt", "object_class": "person"}, + {"name": "uav_person15", "path": "data_seq/UAV123/person15", "startFrame": 1, "endFrame": 1339, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person15.txt", "object_class": "person"}, + {"name": "uav_person16", "path": "data_seq/UAV123/person16", "startFrame": 1, "endFrame": 1147, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person16.txt", "object_class": "person"}, + {"name": "uav_person17_1", "path": "data_seq/UAV123/person17", "startFrame": 1, "endFrame": 1501, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person17_1.txt", "object_class": "person"}, + {"name": "uav_person17_2", "path": "data_seq/UAV123/person17", "startFrame": 1501, "endFrame": 2347, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person17_2.txt", "object_class": "person"}, + {"name": "uav_person18", "path": "data_seq/UAV123/person18", "startFrame": 1, "endFrame": 1393, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person18.txt", "object_class": "person"}, + {"name": "uav_person19_1", "path": "data_seq/UAV123/person19", "startFrame": 1, "endFrame": 1243, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person19_1.txt", "object_class": "person"}, + {"name": "uav_person19_2", "path": "data_seq/UAV123/person19", "startFrame": 1243, "endFrame": 2791, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person19_2.txt", "object_class": "person"}, + {"name": "uav_person19_3", "path": "data_seq/UAV123/person19", "startFrame": 2791, "endFrame": 4357, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person19_3.txt", "object_class": "person"}, + {"name": "uav_person1_s", "path": "data_seq/UAV123/person1_s", "startFrame": 1, "endFrame": 1600, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person1_s.txt", "object_class": "person"}, + {"name": "uav_person2_1", "path": "data_seq/UAV123/person2", "startFrame": 1, "endFrame": 1189, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_1.txt", "object_class": "person"}, + {"name": "uav_person2_2", "path": "data_seq/UAV123/person2", "startFrame": 1189, "endFrame": 2623, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_2.txt", "object_class": "person"}, + {"name": "uav_person20", "path": "data_seq/UAV123/person20", "startFrame": 1, "endFrame": 1783, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person20.txt", "object_class": "person"}, + {"name": "uav_person21", "path": "data_seq/UAV123/person21", "startFrame": 1, "endFrame": 487, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person21.txt", "object_class": "person"}, + {"name": "uav_person22", "path": "data_seq/UAV123/person22", "startFrame": 1, "endFrame": 199, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person22.txt", "object_class": "person"}, + {"name": "uav_person23", "path": "data_seq/UAV123/person23", "startFrame": 1, "endFrame": 397, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person23.txt", "object_class": "person"}, + {"name": "uav_person2_s", "path": "data_seq/UAV123/person2_s", "startFrame": 1, "endFrame": 250, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_s.txt", "object_class": "person"}, + {"name": "uav_person3", "path": "data_seq/UAV123/person3", "startFrame": 1, "endFrame": 643, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person3.txt", "object_class": "person"}, + {"name": "uav_person3_s", "path": "data_seq/UAV123/person3_s", "startFrame": 1, "endFrame": 505, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person3_s.txt", "object_class": "person"}, + {"name": "uav_person4_1", "path": "data_seq/UAV123/person4", "startFrame": 1, "endFrame": 1501, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person4_1.txt", "object_class": "person"}, + {"name": "uav_person4_2", "path": "data_seq/UAV123/person4", "startFrame": 1501, "endFrame": 2743, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person4_2.txt", "object_class": "person"}, + {"name": "uav_person5_1", "path": "data_seq/UAV123/person5", "startFrame": 1, "endFrame": 877, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person5_1.txt", "object_class": "person"}, + {"name": "uav_person5_2", "path": "data_seq/UAV123/person5", "startFrame": 877, "endFrame": 2101, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person5_2.txt", "object_class": "person"}, + {"name": "uav_person6", "path": "data_seq/UAV123/person6", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person6.txt", "object_class": "person"}, + {"name": "uav_person7_1", "path": "data_seq/UAV123/person7", "startFrame": 1, "endFrame": 1249, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person7_1.txt", "object_class": "person"}, + {"name": "uav_person7_2", "path": "data_seq/UAV123/person7", "startFrame": 1249, "endFrame": 2065, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person7_2.txt", "object_class": "person"}, + {"name": "uav_person8_1", "path": "data_seq/UAV123/person8", "startFrame": 1, "endFrame": 1075, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person8_1.txt", "object_class": "person"}, + {"name": "uav_person8_2", "path": "data_seq/UAV123/person8", "startFrame": 1075, "endFrame": 1525, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person8_2.txt", "object_class": "person"}, + {"name": "uav_person9", "path": "data_seq/UAV123/person9", "startFrame": 1, "endFrame": 661, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person9.txt", "object_class": "person"}, + {"name": "uav_truck1", "path": "data_seq/UAV123/truck1", "startFrame": 1, "endFrame": 463, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck1.txt", "object_class": "truck"}, + {"name": "uav_truck2", "path": "data_seq/UAV123/truck2", "startFrame": 1, "endFrame": 385, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck2.txt", "object_class": "truck"}, + {"name": "uav_truck3", "path": "data_seq/UAV123/truck3", "startFrame": 1, "endFrame": 535, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck3.txt", "object_class": "truck"}, + {"name": "uav_truck4_1", "path": "data_seq/UAV123/truck4", "startFrame": 1, "endFrame": 577, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck4_1.txt", "object_class": "truck"}, + {"name": "uav_truck4_2", "path": "data_seq/UAV123/truck4", "startFrame": 577, "endFrame": 1261, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck4_2.txt", "object_class": "truck"}, + {"name": "uav_uav1_1", "path": "data_seq/UAV123/uav1", "startFrame": 1, "endFrame": 1555, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_1.txt", "object_class": "aircraft"}, + {"name": "uav_uav1_2", "path": "data_seq/UAV123/uav1", "startFrame": 1555, "endFrame": 2377, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_2.txt", "object_class": "aircraft"}, + {"name": "uav_uav1_3", "path": "data_seq/UAV123/uav1", "startFrame": 2473, "endFrame": 3469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_3.txt", "object_class": "aircraft"}, + {"name": "uav_uav2", "path": "data_seq/UAV123/uav2", "startFrame": 1, "endFrame": 133, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav2.txt", "object_class": "aircraft"}, + {"name": "uav_uav3", "path": "data_seq/UAV123/uav3", "startFrame": 1, "endFrame": 265, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav3.txt", "object_class": "aircraft"}, + {"name": "uav_uav4", "path": "data_seq/UAV123/uav4", "startFrame": 1, "endFrame": 157, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav4.txt", "object_class": "aircraft"}, + {"name": "uav_uav5", "path": "data_seq/UAV123/uav5", "startFrame": 1, "endFrame": 139, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav5.txt", "object_class": "aircraft"}, + {"name": "uav_uav6", "path": "data_seq/UAV123/uav6", "startFrame": 1, "endFrame": 109, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav6.txt", "object_class": "aircraft"}, + {"name": "uav_uav7", "path": "data_seq/UAV123/uav7", "startFrame": 1, "endFrame": 373, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav7.txt", "object_class": "aircraft"}, + {"name": "uav_uav8", "path": "data_seq/UAV123/uav8", "startFrame": 1, "endFrame": 301, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav8.txt", "object_class": "aircraft"}, + {"name": "uav_wakeboard1", "path": "data_seq/UAV123/wakeboard1", "startFrame": 1, "endFrame": 421, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard1.txt", "object_class": "person"}, + {"name": "uav_wakeboard10", "path": "data_seq/UAV123/wakeboard10", "startFrame": 1, "endFrame": 469, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/wakeboard10.txt", "object_class": "person"}, + {"name": "uav_wakeboard2", "path": "data_seq/UAV123/wakeboard2", "startFrame": 1, "endFrame": 733, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard2.txt", "object_class": "person"}, + {"name": "uav_wakeboard3", "path": "data_seq/UAV123/wakeboard3", "startFrame": 1, "endFrame": 823, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard3.txt", "object_class": "person"}, + {"name": "uav_wakeboard4", "path": "data_seq/UAV123/wakeboard4", "startFrame": 1, "endFrame": 697, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard4.txt", "object_class": "person"}, + {"name": "uav_wakeboard5", "path": "data_seq/UAV123/wakeboard5", "startFrame": 1, "endFrame": 1675, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard5.txt", "object_class": "person"}, + {"name": "uav_wakeboard6", "path": "data_seq/UAV123/wakeboard6", "startFrame": 1, "endFrame": 1165, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard6.txt", "object_class": "person"}, + {"name": "uav_wakeboard7", "path": "data_seq/UAV123/wakeboard7", "startFrame": 1, "endFrame": 199, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard7.txt", "object_class": "person"}, + {"name": "uav_wakeboard8", "path": "data_seq/UAV123/wakeboard8", "startFrame": 1, "endFrame": 1543, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard8.txt", "object_class": "person"}, + {"name": "uav_wakeboard9", "path": "data_seq/UAV123/wakeboard9", "startFrame": 1, "endFrame": 355, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard9.txt", "object_class": "person"} + ] + + return sequence_info_list diff --git a/Stark/external/AR/pytracking/evaluation/vot.py b/Stark/external/AR/pytracking/evaluation/vot.py new file mode 100755 index 0000000..6d2aad1 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/vot.py @@ -0,0 +1,174 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016 + +""" + +import sys +import copy +import collections + +try: + import trax + import trax.server + TRAX = True +except ImportError: + TRAX = False + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +def parse_region(string): + tokens = map(float, string.split(',')) + if len(tokens) == 4: + return Rectangle(tokens[0], tokens[1], tokens[2], tokens[3]) + elif len(tokens) % 2 == 0 and len(tokens) > 4: + return Polygon([Point(tokens[i],tokens[i+1]) for i in xrange(0,len(tokens),2)]) + return None + +def encode_region(region): + if isinstance(region, Polygon): + return ','.join(['{},{}'.format(p.x,p.y) for p in region.points]) + elif isinstance(region, Rectangle): + return '{},{},{},{}'.format(region.x, region.y, region.width, region.height) + else: + return "" + +def convert_region(region, to): + + if to == 'rectangle': + + if isinstance(region, Rectangle): + return copy.copy(region) + elif isinstance(region, Polygon): + top = sys.float_info.max + bottom = sys.float_info.min + left = sys.float_info.max + right = sys.float_info.min + + for point in region.points: + top = min(top, point.y) + bottom = max(bottom, point.y) + left = min(left, point.x) + right = max(right, point.x) + + return Rectangle(left, top, right - left, bottom - top) + + else: + return None + if to == 'polygon': + + if isinstance(region, Rectangle): + points = [] + points.append((region.x, region.y)) + points.append((region.x + region.width, region.y)) + points.append((region.x + region.width, region.y + region.height)) + points.append((region.x, region.y + region.height)) + return Polygon(points) + + elif isinstance(region, Polygon): + return copy.copy(region) + else: + return None + + return None + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in ['rectangle', 'polygon']) + if TRAX: + options = trax.server.ServerOptions(region_format, trax.image.PATH) + self._trax = trax.server.Server(options) + + request = self._trax.wait() + assert(request.type == 'initialize') + if request.region.type == 'polygon': + self._region = Polygon([Point(x[0], x[1]) for x in request.region.points]) + else: + self._region = Rectangle(request.region.x, request.region.y, request.region.width, request.region.height) + self._image = str(request.image) + self._trax.status(request.region) + else: + self._files = [x.strip('\n') for x in open('images.txt', 'r').readlines()] + self._frame = 0 + self._region = convert_region(parse_region(open('region.txt', 'r').readline()), region_format) + self._result = [] + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = 0): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, Rectangle) or isinstance(region, Polygon)) + if TRAX: + if isinstance(region, Polygon): + tregion = trax.region.Polygon([(x.x, x.y) for x in region.points]) + else: + tregion = trax.region.Rectangle(region.x, region.y, region.width, region.height) + self._trax.status(tregion, {"confidence" : confidence}) + else: + self._result.append(region) + self._frame += 1 + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if TRAX: + if hasattr(self, "_image"): + image = str(self._image) + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + return str(request.image) + else: + return None + + else: + if self._frame >= len(self._files): + return None + return self._files[self._frame] + + def quit(self): + if TRAX: + self._trax.quit() + elif hasattr(self, '_result'): + with open('output.txt', 'w') as f: + for r in self._result: + f.write(encode_region(r)) + f.write('\n') + + def __del__(self): + self.quit() + diff --git a/Stark/external/AR/pytracking/evaluation/vot2020.py b/Stark/external/AR/pytracking/evaluation/vot2020.py new file mode 100755 index 0000000..8310900 --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/vot2020.py @@ -0,0 +1,143 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016 + +""" + +import sys +import copy +import collections +import numpy as np + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + + +def make_full_size(x, output_sz): + ''' + zero-pad input x (right and down) to match output_sz + x: numpy array e.g., binary mask + output_sz: size of the output [width, height] + ''' + if x.shape[0] == output_sz[1] and x.shape[1] == output_sz[0]: + return x + pad_x = output_sz[0] - x.shape[1] + if pad_x < 0: + x = x[:, :x.shape[1] + pad_x] + # padding has to be set to zero, otherwise pad function fails + pad_x = 0 + pad_y = output_sz[1] - x.shape[0] + if pad_y < 0: + x = x[:x.shape[0] + pad_y, :] + # padding has to be set to zero, otherwise pad function fails + pad_y = 0 + return np.pad(x, ((0, pad_y), (0, pad_x)), 'constant', constant_values=0) + + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON, trax.Region.MASK]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels, customMetadata=dict(vot="python")) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + if isinstance(request.region, trax.Mask): + self._region = request.region.array(True) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [x.path() for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, (Rectangle, Polygon, np.ndarray))) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + if isinstance(region, np.ndarray): + tregion = trax.Mask.create(region) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + image = [x.path() for k, x in request.image.items()] + if len(image) == 1: + return image[0] + return image + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() diff --git a/Stark/external/AR/pytracking/evaluation/votdataset.py b/Stark/external/AR/pytracking/evaluation/votdataset.py new file mode 100755 index 0000000..f11bc6a --- /dev/null +++ b/Stark/external/AR/pytracking/evaluation/votdataset.py @@ -0,0 +1,122 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList + + +class VOTDataset(BaseDataset): + """ + VOT2018 dataset + + Publication: + The sixth Visual Object Tracking VOT2018 challenge results. + Matej Kristan, Ales Leonardis, Jiri Matas, Michael Felsberg, Roman Pfugfelder, Luka Cehovin Zajc, Tomas Vojir, + Goutam Bhat, Alan Lukezic et al. + ECCV, 2018 + https://prints.vicos.si/publications/365 + + Download the dataset from http://www.votchallenge.net/vot2018/dataset.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.vot_path + self.sequence_list = self._get_sequence_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + sequence_path = sequence_name + nz = 8 + ext = 'jpg' + start_frame = 1 + + anno_path = '{}/{}/groundtruth.txt'.format(self.base_path, sequence_name) + try: + ground_truth_rect = np.loadtxt(str(anno_path), dtype=np.float64) + except: + ground_truth_rect = np.loadtxt(str(anno_path), delimiter=',', dtype=np.float64) + + end_frame = ground_truth_rect.shape[0] + + frames = ['{base_path}/{sequence_path}/color/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) + for frame_num in range(start_frame, end_frame+1)] + + # Convert gt + if ground_truth_rect.shape[1] > 4: + gt_x_all = ground_truth_rect[:, [0, 2, 4, 6]] + gt_y_all = ground_truth_rect[:, [1, 3, 5, 7]] + + x1 = np.amin(gt_x_all, 1).reshape(-1,1) + y1 = np.amin(gt_y_all, 1).reshape(-1,1) + x2 = np.amax(gt_x_all, 1).reshape(-1,1) + y2 = np.amax(gt_y_all, 1).reshape(-1,1) + + ground_truth_rect = np.concatenate((x1, y1, x2-x1, y2-y1), 1) + return Sequence(sequence_name, frames, 'vot', ground_truth_rect) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list= ['ants1', + 'ants3', + 'bag', + 'ball1', + 'ball2', + 'basketball', + 'birds1', + 'blanket', + 'bmx', + 'bolt1', + 'bolt2', + 'book', + 'butterfly', + 'car1', + 'conduction1', + 'crabs1', + 'crossing', + 'dinosaur', + 'drone_across', + 'drone_flip', + 'drone1', + 'fernando', + 'fish1', + 'fish2', + 'fish3', + 'flamingo1', + 'frisbee', + 'girl', + 'glove', + 'godfather', + 'graduate', + 'gymnastics1', + 'gymnastics2', + 'gymnastics3', + 'hand', + 'handball1', + 'handball2', + 'helicopter', + 'iceskater1', + 'iceskater2', + 'leaves', + 'matrix', + 'motocross1', + 'motocross2', + 'nature', + 'pedestrian1', + 'rabbit', + 'racing', + 'road', + 'shaking', + 'sheep', + 'singer2', + 'singer3', + 'soccer1', + 'soccer2', + 'soldier', + 'tiger', + 'traffic', + 'wiper', + 'zebrafish1'] + + return sequence_list diff --git a/Stark/external/AR/pytracking/experiments/__init__.py b/Stark/external/AR/pytracking/experiments/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/experiments/myexperiments.py b/Stark/external/AR/pytracking/experiments/myexperiments.py new file mode 100755 index 0000000..afe2a02 --- /dev/null +++ b/Stark/external/AR/pytracking/experiments/myexperiments.py @@ -0,0 +1,19 @@ +from pytracking.evaluation import Tracker, get_dataset, trackerlist + + +def atom_nfs_uav(): + # Run three runs of ATOM on NFS and UAV datasets + trackers = trackerlist('atom', 'default', range(3)) + + dataset = get_dataset('nfs', 'uav') + return trackers, dataset + + +def uav_test(): + # Run DiMP18, ATOM and ECO on the UAV dataset + trackers = trackerlist('dimp', 'dimp18', range(1)) + \ + trackerlist('atom', 'default', range(1)) + \ + trackerlist('eco', 'default', range(1)) + + dataset = get_dataset('uav') + return trackers, dataset diff --git a/Stark/external/AR/pytracking/features/__init__.py b/Stark/external/AR/pytracking/features/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/features/augmentation.py b/Stark/external/AR/pytracking/features/augmentation.py new file mode 100755 index 0000000..95dc4f3 --- /dev/null +++ b/Stark/external/AR/pytracking/features/augmentation.py @@ -0,0 +1,232 @@ +import numpy as np +import math +import torch +import torch.nn.functional as F +import cv2 as cv +import random +from pytracking.features.preprocessing import numpy_to_torch, torch_to_numpy + + +class Transform: + """Base data augmentation transform class.""" + + def __init__(self, output_sz = None, shift = None): + self.output_sz = output_sz + self.shift = (0,0) if shift is None else shift + + def __call__(self, image, is_mask=False): + raise NotImplementedError + + def crop_to_output(self, image): + if isinstance(image, torch.Tensor): + imsz = image.shape[2:] + if self.output_sz is None: + pad_h = 0 + pad_w = 0 + else: + pad_h = (self.output_sz[0] - imsz[0]) / 2 + pad_w = (self.output_sz[1] - imsz[1]) / 2 + + pad_left = math.floor(pad_w) + self.shift[1] + pad_right = math.ceil(pad_w) - self.shift[1] + pad_top = math.floor(pad_h) + self.shift[0] + pad_bottom = math.ceil(pad_h) - self.shift[0] + + return F.pad(image, (pad_left, pad_right, pad_top, pad_bottom), 'replicate') + else: + raise NotImplementedError + +class Identity(Transform): + """Identity transformation.""" + def __call__(self, image, is_mask=False): + return self.crop_to_output(image) + +class FlipHorizontal(Transform): + """Flip along horizontal axis.""" + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image.flip((3,))) + else: + return np.fliplr(image) + +class FlipVertical(Transform): + """Flip along vertical axis.""" + def __call__(self, image: torch.Tensor, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image.flip((2,))) + else: + return np.flipud(image) + +class Translation(Transform): + """Translate.""" + def __init__(self, translation, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.shift = (self.shift[0] + translation[0], self.shift[1] + translation[1]) + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image) + else: + raise NotImplementedError + +class Scale(Transform): + """Scale.""" + def __init__(self, scale_factor, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.scale_factor = scale_factor + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + # Calculate new size. Ensure that it is even so that crop/pad becomes easier + h_orig, w_orig = image.shape[2:] + + if h_orig != w_orig: + raise NotImplementedError + + h_new = round(h_orig /self.scale_factor) + h_new += (h_new - h_orig) % 2 + w_new = round(w_orig /self.scale_factor) + w_new += (w_new - w_orig) % 2 + + image_resized = F.interpolate(image, [h_new, w_new], mode='bilinear') + + return self.crop_to_output(image_resized) + else: + raise NotImplementedError + + +class Affine(Transform): + """Affine transformation.""" + def __init__(self, transform_matrix, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.transform_matrix = transform_matrix + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(numpy_to_torch(self(torch_to_numpy(image)))) + else: + return cv.warpAffine(image, self.transform_matrix, image.shape[1::-1], borderMode=cv.BORDER_REPLICATE) + + +class Rotate(Transform): + """Rotate with given angle.""" + def __init__(self, angle, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.angle = math.pi * angle/180 + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(numpy_to_torch(self(torch_to_numpy(image)))) + else: + c = (np.expand_dims(np.array(image.shape[:2]),1)-1)/2 + R = np.array([[math.cos(self.angle), math.sin(self.angle)], + [-math.sin(self.angle), math.cos(self.angle)]]) + H =np.concatenate([R, c - R @ c], 1) + return cv.warpAffine(image, H, image.shape[1::-1], borderMode=cv.BORDER_REPLICATE) + + +class Blur(Transform): + """Blur with given sigma (can be axis dependent).""" + def __init__(self, sigma, output_sz = None, shift = None): + super().__init__(output_sz, shift) + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + sz = image.shape[2:] + im1 = F.conv2d(image.view(-1,1,sz[0],sz[1]), self.filter[0], padding=(self.filter_size[0],0)) + return self.crop_to_output(F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(1,-1,sz[0],sz[1])) + else: + raise NotImplementedError + + +class RandomAffine(Transform): + """Affine transformation.""" + def __init__(self, p_flip=0.0, max_rotation=0.0, max_shear=0.0, max_scale=0.0, max_ar_factor=0.0, + border_mode='constant', output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.p_flip = p_flip + self.max_rotation = max_rotation + self.max_shear = max_shear + self.max_scale = max_scale + self.max_ar_factor = max_ar_factor + + self.pad_amount = 0 + if border_mode == 'constant': + self.border_flag = cv.BORDER_CONSTANT + elif border_mode == 'replicate': + self.border_flag == cv.BORDER_REPLICATE + else: + raise Exception + + self.roll_values = self.roll() + + def roll(self): + do_flip = random.random() < self.p_flip + theta = random.uniform(-self.max_rotation, self.max_rotation) + + shear_x = random.uniform(-self.max_shear, self.max_shear) + shear_y = random.uniform(-self.max_shear, self.max_shear) + + ar_factor = np.exp(random.uniform(-self.max_ar_factor, self.max_ar_factor)) + scale_factor = np.exp(random.uniform(-self.max_scale, self.max_scale)) + + return do_flip, theta, (shear_x, shear_y), (scale_factor, scale_factor * ar_factor) + + def _construct_t_mat(self, image_shape, do_flip, theta, shear_values, scale_factors): + im_h, im_w = image_shape + t_mat = np.identity(3) + + if do_flip: + if do_flip: + t_mat[0, 0] = -1.0 + t_mat[0, 2] = im_w + + t_rot = cv.getRotationMatrix2D((im_w * 0.5, im_h * 0.5), theta, 1.0) + t_rot = np.concatenate((t_rot, np.array([0.0, 0.0, 1.0]).reshape(1, 3))) + + t_shear = np.array([[1.0, shear_values[0], -shear_values[0] * 0.5 * im_w], + [shear_values[1], 1.0, -shear_values[1] * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_scale = np.array([[scale_factors[0], 0.0, (1.0 - scale_factors[0]) * 0.5 * im_w], + [0.0, scale_factors[1], (1.0 - scale_factors[1]) * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_mat = t_scale @ t_rot @ t_shear @ t_mat + + t_mat[0, 2] += self.pad_amount + t_mat[1, 2] += self.pad_amount + + t_mat = t_mat[:2, :] + + return t_mat + + def __call__(self, image, is_mask=False): + input_tensor = torch.is_tensor(image) + if input_tensor: + image = torch_to_numpy(image) + + do_flip, theta, shear_values, scale_factors = self.roll_values + t_mat = self._construct_t_mat(image.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (image.shape[1] + 2*self.pad_amount, image.shape[0] + 2*self.pad_amount) + + if not is_mask: + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_LINEAR, + borderMode=self.border_flag) + else: + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_NEAREST, + borderMode=self.border_flag) + image_t = image_t.reshape(image.shape) + + if input_tensor: + image_t = numpy_to_torch(image_t) + + return self.crop_to_output(image_t) diff --git a/Stark/external/AR/pytracking/features/color.py b/Stark/external/AR/pytracking/features/color.py new file mode 100755 index 0000000..c24cbac --- /dev/null +++ b/Stark/external/AR/pytracking/features/color.py @@ -0,0 +1,26 @@ +import torch +from pytracking.features.featurebase import FeatureBase + + +class RGB(FeatureBase): + """RGB feature normalized to [-0.5, 0.5].""" + def dim(self): + return 3 + + def stride(self): + return self.pool_stride + + def extract(self, im: torch.Tensor): + return im/255 - 0.5 + + +class Grayscale(FeatureBase): + """Grayscale feature normalized to [-0.5, 0.5].""" + def dim(self): + return 1 + + def stride(self): + return self.pool_stride + + def extract(self, im: torch.Tensor): + return torch.mean(im/255 - 0.5, 1, keepdim=True) diff --git a/Stark/external/AR/pytracking/features/deep.py b/Stark/external/AR/pytracking/features/deep.py new file mode 100755 index 0000000..69ed6f5 --- /dev/null +++ b/Stark/external/AR/pytracking/features/deep.py @@ -0,0 +1,150 @@ +from pytracking.features.featurebase import FeatureBase, MultiFeatureBase +import torch +import torchvision +from pytracking import TensorList +from pytracking.evaluation.environment import env_settings +import os +from pytracking.utils.loading import load_network +from ltr.models.backbone.resnet18_vggm import resnet18_vggmconv1 + +normalize = torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + +class ResNet18m1(MultiFeatureBase): + """ResNet18 feature together with the VGG-m conv1 layer. + args: + output_layers: List of layers to output. + net_path: Relative or absolute net path (default should be fine). + use_gpu: Use GPU or CPU. + """ + + def __init__(self, output_layers, net_path=None, use_gpu=True, *args, **kwargs): + super(ResNet18m1, self).__init__(*args, **kwargs) + + for l in output_layers: + if l not in ['vggconv1', 'conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer') + + self.output_layers = list(output_layers) + self.use_gpu = use_gpu + self.net_path = 'resnet18_vggmconv1/resnet18_vggmconv1.pth' if net_path is None else net_path + + def initialize(self): + + if isinstance(self.pool_stride, int) and self.pool_stride == 1: + self.pool_stride = [1] * len(self.output_layers) + + self.layer_stride = {'vggconv1': 2, 'conv1': 2, 'layer1': 4, 'layer2': 8, 'layer3': 16, 'layer4': 32, + 'fc': None} + self.layer_dim = {'vggconv1': 96, 'conv1': 64, 'layer1': 64, 'layer2': 128, 'layer3': 256, 'layer4': 512, + 'fc': None} + + self.mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1) + self.std = torch.Tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1) + + if os.path.isabs(self.net_path): + net_path_full = [self.net_path] + else: + root_paths = env_settings().network_path + if isinstance(root_paths, str): + root_paths = [root_paths] + net_path_full = [os.path.join(root, self.net_path) for root in root_paths] + + self.net = None + for net_path in net_path_full: + try: + self.net = resnet18_vggmconv1(self.output_layers, path=net_path) + break + except: + pass + if self.net is None: + raise Exception('Did not find network file {}'.format(self.net_path)) + + if self.use_gpu: + self.net.cuda() + self.net.eval() + + def dim(self): + return TensorList([self.layer_dim[l] for l in self.output_layers]) + + def stride(self): + return TensorList([s * self.layer_stride[l] for l, s in zip(self.output_layers, self.pool_stride)]) + + def extract(self, im: torch.Tensor): + im = im / 255 + im -= self.mean + im /= self.std + + if self.use_gpu: + im = im.cuda() + + with torch.no_grad(): + return TensorList(self.net(im).values()) + + +class ATOMResNet18(MultiFeatureBase): + """ResNet18 feature with the ATOM IoUNet. + args: + output_layers: List of layers to output. + net_path: Relative or absolute net path (default should be fine). + use_gpu: Use GPU or CPU. + """ + + def __init__(self, output_layers=('layer3',), net_path='atom_iou', use_gpu=True, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.output_layers = list(output_layers) + self.use_gpu = use_gpu + self.net_path = net_path + + def initialize(self): + self.net = load_network(self.net_path) + + if self.use_gpu: + self.net.cuda() + self.net.eval() + + self.iou_predictor = self.net.bb_regressor + + self.layer_stride = {'conv1': 2, 'layer1': 4, 'layer2': 8, 'layer3': 16, 'layer4': 32, 'classification': 16, + 'fc': None} + self.layer_dim = {'conv1': 64, 'layer1': 64, 'layer2': 128, 'layer3': 256, 'layer4': 512, 'classification': 256, + 'fc': None} + + self.iounet_feature_layers = self.net.bb_regressor_layer + + if isinstance(self.pool_stride, int) and self.pool_stride == 1: + self.pool_stride = [1] * len(self.output_layers) + + self.feature_layers = sorted(list(set(self.output_layers + self.iounet_feature_layers))) + + self.mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1) + self.std = torch.Tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1) + + def dim(self): + return TensorList([self.layer_dim[l] for l in self.output_layers]) + + def stride(self): + return TensorList([s * self.layer_stride[l] for l, s in zip(self.output_layers, self.pool_stride)]) + + def extract(self, im: torch.Tensor): + im = im / 255 + im -= self.mean + im /= self.std + + if self.use_gpu: + im = im.cuda() + + with torch.no_grad(): + output_features = self.net.extract_features(im, self.feature_layers) + + # Store the raw resnet features which are input to iounet + self.iounet_backbone_features = TensorList( + [output_features[layer].clone() for layer in self.iounet_feature_layers]) + + # Store the processed features from iounet, just before pooling + with torch.no_grad(): + self.iounet_features = TensorList(self.iou_predictor.get_iou_feat(self.iounet_backbone_features)) + + return TensorList([output_features[layer] for layer in self.output_layers]) diff --git a/Stark/external/AR/pytracking/features/extractor.py b/Stark/external/AR/pytracking/features/extractor.py new file mode 100755 index 0000000..032b1a4 --- /dev/null +++ b/Stark/external/AR/pytracking/features/extractor.py @@ -0,0 +1,143 @@ +import torch +from pytracking.features.preprocessing import sample_patch +from pytracking import TensorList + +class ExtractorBase: + """Base feature extractor class. + args: + features: List of features. + """ + def __init__(self, features): + self.features = features + + def initialize(self): + for f in self.features: + f.initialize() + + +class SingleResolutionExtractor(ExtractorBase): + """Single resolution feature extractor. + args: + features: List of features. + """ + def __init__(self, features): + super().__init__(features) + + self.feature_stride = self.features[0].stride() + if isinstance(self.feature_stride, (list, TensorList)): + self.feature_stride = self.feature_stride[0] + + def stride(self): + return self.feature_stride + + def size(self, input_sz): + return input_sz // self.stride() + + def extract(self, im, pos, scales, image_sz): + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + im_patches = torch.cat([sample_patch(im, pos, s*image_sz, image_sz) for s in scales]) + + # Compute features + feature_map = torch.cat(TensorList([f.get_feature(im_patches) for f in self.features]).unroll(), dim=1) + + return feature_map + + +class MultiResolutionExtractor(ExtractorBase): + """Multi-resolution feature extractor. + args: + features: List of features. + """ + def __init__(self, features, patch_mode='replicate', max_scale_change=None): + super().__init__(features) + self.patch_mode = patch_mode + self.max_scale_change = max_scale_change + self.is_color = None + + def stride(self): + return torch.Tensor(TensorList([f.stride() for f in self.features if self._return_feature(f)]).unroll().list()) + + def size(self, input_sz): + return TensorList([f.size(input_sz) for f in self.features if self._return_feature(f)]).unroll() + + def dim(self): + return TensorList([f.dim() for f in self.features if self._return_feature(f)]).unroll() + + def get_fparams(self, name: str = None): + if name is None: + return [f.fparams for f in self.features if self._return_feature(f)] + return TensorList([getattr(f.fparams, name) for f in self.features if self._return_feature(f)]).unroll() + + def get_attribute(self, name: str, ignore_missing: bool = False): + if ignore_missing: + return TensorList([getattr(f, name) for f in self.features if self._return_feature(f) and hasattr(f, name)]) + else: + return TensorList([getattr(f, name, None) for f in self.features if self._return_feature(f)]) + + def get_unique_attribute(self, name: str): + feat = None + for f in self.features: + if self._return_feature(f) and hasattr(f, name): + if feat is not None: + raise RuntimeError('The attribute was not unique.') + feat = f + if feat is None: + raise RuntimeError('The attribute did not exist') + return getattr(feat, name) + + def _return_feature(self, f): + return self.is_color is None or self.is_color and f.use_for_color or not self.is_color and f.use_for_gray + + def set_is_color(self, is_color: bool): + self.is_color = is_color + + def extract(self, im, pos, scales, image_sz, return_patches=False): + """Extract features. + args: + im: Image. + pos: Center position for extraction. + scales: Image scales to extract features from. + image_sz: Size to resize the image samples to before extraction. + """ + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + patch_iter, coord_iter = zip(*(sample_patch(im, pos, s*image_sz, image_sz, mode=self.patch_mode, + max_scale_change=self.max_scale_change) for s in scales)) + im_patches = torch.cat(list(patch_iter)) + patch_coords = torch.cat(list(coord_iter)) + + # im_patches = torch.cat([sample_patch(im, pos, s*image_sz, image_sz) for s in scales]) + + # Compute features + feature_map = TensorList([f.get_feature(im_patches) for f in self.features]).unroll() + + if return_patches: + return feature_map, patch_coords, im_patches + else: + return feature_map, patch_coords + + def extract_transformed(self, im, pos, scale, image_sz, transforms): + """Extract features from a set of transformed image samples. + args: + im: Image. + pos: Center position for extraction. + scale: Image scale to extract features from. + image_sz: Size to resize the image samples to before extraction. + transforms: A set of image transforms to apply. + """ + + # Get image patche + im_patch, _ = sample_patch(im, pos, scale*image_sz, image_sz) + + # Apply transforms + im_patches = torch.cat([T(im_patch) for T in transforms]) + + # Compute features + feature_map = TensorList([f.get_feature(im_patches) for f in self.features]).unroll() + + return feature_map diff --git a/Stark/external/AR/pytracking/features/featurebase.py b/Stark/external/AR/pytracking/features/featurebase.py new file mode 100755 index 0000000..cdd5130 --- /dev/null +++ b/Stark/external/AR/pytracking/features/featurebase.py @@ -0,0 +1,110 @@ +import torch +import torch.nn.functional as F +from pytracking import TensorList + + +class FeatureBase: + """Base feature class. + args: + fparams: Feature specific parameters. + pool_stride: Amount of average pooling to apply do downsample the feature map. + output_size: Alternatively, specify the output size of the feature map. Adaptive average pooling will be applied. + normalize_power: The power exponent for the normalization. None means no normalization (default). + use_for_color: Use this feature for color images. + use_for_gray: Use this feature for grayscale images. + """ + def __init__(self, fparams = None, pool_stride = None, output_size = None, normalize_power = None, use_for_color = True, use_for_gray = True): + self.fparams = fparams + self.pool_stride = 1 if pool_stride is None else pool_stride + self.output_size = output_size + self.normalize_power = normalize_power + self.use_for_color = use_for_color + self.use_for_gray = use_for_gray + + def initialize(self): + pass + + def dim(self): + raise NotImplementedError + + def stride(self): + raise NotImplementedError + + def size(self, im_sz): + if self.output_size is None: + return im_sz // self.stride() + if isinstance(im_sz, torch.Tensor): + return torch.Tensor([self.output_size[0], self.output_size[1]]) + return self.output_size + + def extract(self, im): + """Performs feature extraction.""" + raise NotImplementedError + + def get_feature(self, im: torch.Tensor): + """Get the feature. Generally, call this function. + args: + im: image patch as a torch.Tensor. + """ + + # Return empty tensor if it should not be used + is_color = im.shape[1] == 3 + if is_color and not self.use_for_color or not is_color and not self.use_for_gray: + return torch.Tensor([]) + + # Extract feature + feat = self.extract(im) + + # Pool/downsample + if self.output_size is not None: + feat = F.adaptive_avg_pool2d(feat, self.output_size) + elif self.pool_stride != 1: + feat = F.avg_pool2d(feat, self.pool_stride, self.pool_stride) + + # Normalize + if self.normalize_power is not None: + feat /= (torch.sum(feat.abs().view(feat.shape[0],1,1,-1)**self.normalize_power, dim=3, keepdim=True) / + (feat.shape[1]*feat.shape[2]*feat.shape[3]) + 1e-10)**(1/self.normalize_power) + + return feat + + +class MultiFeatureBase(FeatureBase): + """Base class for features potentially having multiple feature blocks as output (like CNNs). + See FeatureBase for more info. + """ + def size(self, im_sz): + if self.output_size is None: + return TensorList([im_sz // s for s in self.stride()]) + if isinstance(im_sz, torch.Tensor): + return TensorList([im_sz // s if sz is None else torch.Tensor([sz[0], sz[1]]) for sz, s in zip(self.output_size, self.stride())]) + + def get_feature(self, im: torch.Tensor): + """Get the feature. Generally, call this function. + args: + im: image patch as a torch.Tensor. + """ + + # Return empty tensor if it should not be used + is_color = im.shape[1] == 3 + if is_color and not self.use_for_color or not is_color and not self.use_for_gray: + return torch.Tensor([]) + + feat_list = self.extract(im) + + output_sz = [None]*len(feat_list) if self.output_size is None else self.output_size + + # Pool/downsample + for i, (sz, s) in enumerate(zip(output_sz, self.pool_stride)): + if sz is not None: + feat_list[i] = F.adaptive_avg_pool2d(feat_list[i], sz) + elif s != 1: + feat_list[i] = F.avg_pool2d(feat_list[i], s, s) + + # Normalize + if self.normalize_power is not None: + for feat in feat_list: + feat /= (torch.sum(feat.abs().view(feat.shape[0],1,1,-1)**self.normalize_power, dim=3, keepdim=True) / + (feat.shape[1]*feat.shape[2]*feat.shape[3]) + 1e-10)**(1/self.normalize_power) + + return feat_list \ No newline at end of file diff --git a/Stark/external/AR/pytracking/features/net_wrappers.py b/Stark/external/AR/pytracking/features/net_wrappers.py new file mode 100755 index 0000000..e1614d9 --- /dev/null +++ b/Stark/external/AR/pytracking/features/net_wrappers.py @@ -0,0 +1,75 @@ +import torch +from pytracking.utils.loading import load_network + + +class NetWrapper: + """Used for wrapping networks in pytracking. + Network modules and functions can be accessed directly as if they were members of this class.""" + _rec_iter=0 + def __init__(self, net_path, use_gpu=True, initialize=False, **kwargs): + self.net_path = net_path + self.use_gpu = use_gpu + self.net = None + self.net_kwargs = kwargs + if initialize: + self.initialize() + + def __getattr__(self, name): + if self._rec_iter > 0: + self._rec_iter = 0 + return None + self._rec_iter += 1 + try: + ret_val = getattr(self.net, name) + except Exception as e: + self._rec_iter = 0 + raise e + self._rec_iter = 0 + return ret_val + + def load_network(self): + self.net = load_network(self.net_path, **self.net_kwargs) + if self.use_gpu: + self.cuda() + self.eval() + + def initialize(self): + self.load_network() + + +class NetWithBackbone(NetWrapper): + """Wraps a network with a common backbone. + Assumes the network have a 'extract_backbone_features(image)' function.""" + + def __init__(self, net_path, use_gpu=True, initialize=False, image_format='rgb', + mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), **kwargs): + super().__init__(net_path, use_gpu, initialize, **kwargs) + + self.image_format = image_format + self._mean = torch.Tensor(mean).view(1, -1, 1, 1) + self._std = torch.Tensor(std).view(1, -1, 1, 1) + + def initialize(self, image_format='rgb', mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)): + super().initialize() + + def preprocess_image(self, im: torch.Tensor): + """Normalize the image with the mean and standard deviation used by the network.""" + + if self.image_format in ['rgb', 'bgr']: + im = im/255 + + if self.image_format in ['bgr', 'bgr255']: + im = im[:, [2, 1, 0], :, :] + im -= self._mean + im /= self._std + + if self.use_gpu: + im = im.cuda() + + return im + + def extract_backbone(self, im: torch.Tensor): + """Extract backbone features from the network. + Expects a float tensor image with pixel range [0, 255].""" + im = self.preprocess_image(im) + return self.net.extract_backbone_features(im) diff --git a/Stark/external/AR/pytracking/features/preprocessing.py b/Stark/external/AR/pytracking/features/preprocessing.py new file mode 100755 index 0000000..f9a54c4 --- /dev/null +++ b/Stark/external/AR/pytracking/features/preprocessing.py @@ -0,0 +1,145 @@ +import torch +import torch.nn.functional as F +import numpy as np + + +def numpy_to_torch(a: np.ndarray): + return torch.from_numpy(a).float().permute(2, 0, 1).unsqueeze(0) + + +def torch_to_numpy(a: torch.Tensor): + return a.squeeze(0).permute(1,2,0).numpy() + + +def sample_patch_transformed(im, pos, scale, image_sz, transforms, is_mask=False): + """Extract transformed image samples. + args: + im: Image. + pos: Center position for extraction. + scale: Image scale to extract features from. + image_sz: Size to resize the image samples to before extraction. + transforms: A set of image transforms to apply. + """ + + # Get image patche + im_patch, _ = sample_patch(im, pos, scale*image_sz, image_sz, is_mask=is_mask) + + # Apply transforms + im_patches = torch.cat([T(im_patch, is_mask=is_mask) for T in transforms]) + + return im_patches + + +def sample_patch_multiscale(im, pos, scales, image_sz, mode: str='replicate', max_scale_change=None): + """Extract image patches at multiple scales. + args: + im: Image. + pos: Center position for extraction. + scales: Image scales to extract image patches from. + image_sz: Size to resize the image samples to + mode: how to treat image borders: 'replicate' (default), 'inside' or 'inside_major' + max_scale_change: maximum allowed scale change when using 'inside' and 'inside_major' mode + """ + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + patch_iter, coord_iter = zip(*(sample_patch(im, pos, s*image_sz, image_sz, mode=mode, + max_scale_change=max_scale_change) for s in scales)) + im_patches = torch.cat(list(patch_iter)) + patch_coords = torch.cat(list(coord_iter)) + + return im_patches, patch_coords + + +def sample_patch(im: torch.Tensor, pos: torch.Tensor, sample_sz: torch.Tensor, output_sz: torch.Tensor = None, + mode: str = 'replicate', max_scale_change=None, is_mask=False): + """Sample an image patch. + + args: + im: Image + pos: center position of crop + sample_sz: size to crop + output_sz: size to resize to + mode: how to treat image borders: 'replicate' (default), 'inside' or 'inside_major' + max_scale_change: maximum allowed scale change when using 'inside' and 'inside_major' mode + """ + + # if mode not in ['replicate', 'inside']: + # raise ValueError('Unknown border mode \'{}\'.'.format(mode)) + + # copy and convert + posl = pos.long().clone() + + pad_mode = mode + + # Get new sample size if forced inside the image + if mode == 'inside' or mode == 'inside_major': + pad_mode = 'replicate' + im_sz = torch.Tensor([im.shape[2], im.shape[3]]) + shrink_factor = (sample_sz.float() / im_sz) + if mode == 'inside': + shrink_factor = shrink_factor.max() + elif mode == 'inside_major': + shrink_factor = shrink_factor.min() + shrink_factor.clamp_(min=1, max=max_scale_change) + sample_sz = (sample_sz.float() / shrink_factor).long() + + # Compute pre-downsampling factor + if output_sz is not None: + resize_factor = torch.min(sample_sz.float() / output_sz.float()).item() + df = int(max(int(resize_factor - 0.1), 1)) + else: + df = int(1) + + sz = sample_sz.float() / df # new size + + # Do downsampling + if df > 1: + os = posl % df # offset + posl = (posl - os) / df # new position + im2 = im[..., os[0].item()::df, os[1].item()::df] # downsample + else: + im2 = im + + # compute size to crop + szl = torch.max(sz.round(), torch.Tensor([2])).long() + + # Extract top and bottom coordinates + tl = posl - (szl - 1)/2 + br = posl + szl/2 + 1 + + # Shift the crop to inside + if mode == 'inside' or mode == 'inside_major': + im2_sz = torch.LongTensor([im2.shape[2], im2.shape[3]]) + shift = (-tl).clamp(0) - (br - im2_sz).clamp(0) + tl += shift + br += shift + + outside = ((-tl).clamp(0) + (br - im2_sz).clamp(0)) // 2 + shift = (-tl - outside) * (outside > 0).long() + tl += shift + br += shift + + # Get image patch + # im_patch = im2[...,tl[0].item():br[0].item(),tl[1].item():br[1].item()] + + # Get image patch + if not is_mask: + im_patch = F.pad(im2, (-tl[1].item(), br[1].item() - im2.shape[3], -tl[0].item(), br[0].item() - im2.shape[2]), pad_mode) + else: + im_patch = F.pad(im2, (-tl[1].item(), br[1].item() - im2.shape[3], -tl[0].item(), br[0].item() - im2.shape[2])) + + # Get image coordinates + patch_coord = df * torch.cat((tl, br)).view(1,4) + + if output_sz is None or (im_patch.shape[-2] == output_sz[0] and im_patch.shape[-1] == output_sz[1]): + return im_patch.clone(), patch_coord + + # Resample + if not is_mask: + im_patch = F.interpolate(im_patch, output_sz.long().tolist(), mode='bilinear') + else: + im_patch = F.interpolate(im_patch, output_sz.long().tolist(), mode='nearest') + + return im_patch, patch_coord diff --git a/Stark/external/AR/pytracking/features/util.py b/Stark/external/AR/pytracking/features/util.py new file mode 100755 index 0000000..6f546b6 --- /dev/null +++ b/Stark/external/AR/pytracking/features/util.py @@ -0,0 +1,27 @@ +import torch +from pytracking.features.featurebase import FeatureBase + + +class Concatenate(FeatureBase): + """A feature that concatenates other features. + args: + features: List of features to concatenate. + """ + def __init__(self, features, pool_stride = None, normalize_power = None, use_for_color = True, use_for_gray = True): + super(Concatenate, self).__init__(pool_stride, normalize_power, use_for_color, use_for_gray) + self.features = features + + self.input_stride = self.features[0].stride() + + for feat in self.features: + if self.input_stride != feat.stride(): + raise ValueError('Strides for the features must be the same for a bultiresolution feature.') + + def dim(self): + return sum([f.dim() for f in self.features]) + + def stride(self): + return self.pool_stride * self.input_stride + + def extract(self, im: torch.Tensor): + return torch.cat([f.get_feature(im) for f in self.features], 1) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/libs/__init__.py b/Stark/external/AR/pytracking/libs/__init__.py new file mode 100755 index 0000000..0b47e6b --- /dev/null +++ b/Stark/external/AR/pytracking/libs/__init__.py @@ -0,0 +1,2 @@ +from .tensorlist import TensorList +from .tensordict import TensorDict \ No newline at end of file diff --git a/Stark/external/AR/pytracking/libs/complex.py b/Stark/external/AR/pytracking/libs/complex.py new file mode 100755 index 0000000..917e342 --- /dev/null +++ b/Stark/external/AR/pytracking/libs/complex.py @@ -0,0 +1,211 @@ +import torch +from pytracking.libs.tensorlist import tensor_operation + + +def is_complex(a: torch.Tensor) -> bool: + return a.dim() >= 4 and a.shape[-1] == 2 + + +def is_real(a: torch.Tensor) -> bool: + return not is_complex(a) + + +@tensor_operation +def mult(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of complex tensors.""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + # a is real + return mult_real_cplx(a, b) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return mult_real_cplx(b, a) + + # Both complex + c = mult_real_cplx(a[..., 0], b) + c[..., 0] -= a[..., 1] * b[..., 1] + c[..., 1] += a[..., 1] * b[..., 0] + return c + + +@tensor_operation +def mult_conj(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of complex tensors, with conjugate on b: a*conj(b).""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + # a is real + return mult_real_cplx(a, conj(b)) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return mult_real_cplx(b, a) + + # Both complex + c = mult_real_cplx(b[...,0], a) + c[..., 0] += a[..., 1] * b[..., 1] + c[..., 1] -= a[..., 0] * b[..., 1] + return c + + +@tensor_operation +def mult_real_cplx(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of real tensor a with complex tensor b.""" + + if is_real(b): + raise ValueError('Last dimension must have length 2.') + + return a.unsqueeze(-1) * b + + +@tensor_operation +def div(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex division of complex tensors.""" + + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return div_cplx_real(a, b) + + return div_cplx_real(mult_conj(a, b), abs_sqr(b)) + + +@tensor_operation +def div_cplx_real(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex division of complex tensor a with real tensor b.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a / b.unsqueeze(-1) + + +@tensor_operation +def abs_sqr(a: torch.Tensor): + """Squared absolute value.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return torch.sum(a*a, -1) + + +@tensor_operation +def abs(a: torch.Tensor): + """Absolute value.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return torch.sqrt(abs_sqr(a)) + + +@tensor_operation +def conj(a: torch.Tensor): + """Complex conjugate.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + # return a * torch.Tensor([1, -1], device=a.device) + return complex(a[...,0], -a[...,1]) + + +@tensor_operation +def real(a: torch.Tensor): + """Real part.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a[..., 0] + + +@tensor_operation +def imag(a: torch.Tensor): + """Imaginary part.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a[..., 1] + + +@tensor_operation +def complex(a: torch.Tensor, b: torch.Tensor = None): + """Create complex tensor from real and imaginary part.""" + + if b is None: + b = a.new_zeros(a.shape) + elif a is None: + a = b.new_zeros(b.shape) + + return torch.cat((a.unsqueeze(-1), b.unsqueeze(-1)), -1) + + +@tensor_operation +def mtimes(a: torch.Tensor, b: torch.Tensor, conj_a=False, conj_b=False): + """Complex matrix multiplication of complex tensors. + The dimensions (-3, -2) are matrix multiplied. -1 is the complex dimension.""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + return mtimes_real_complex(a, b, conj_b=conj_b) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + return mtimes_complex_real(a, b, conj_a=conj_a) + + if not conj_a and not conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) - torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 0], b[..., 1]) + torch.matmul(a[..., 1], b[..., 0])) + if conj_a and not conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) + torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 0], b[..., 1]) - torch.matmul(a[..., 1], b[..., 0])) + if not conj_a and conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) + torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 1], b[..., 0]) - torch.matmul(a[..., 0], b[..., 1])) + if conj_a and conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) - torch.matmul(a[..., 1], b[..., 1]), + -torch.matmul(a[..., 0], b[..., 1]) - torch.matmul(a[..., 1], b[..., 0])) + + +@tensor_operation +def mtimes_real_complex(a: torch.Tensor, b: torch.Tensor, conj_b=False): + if is_real(b): + raise ValueError('Incorrect dimensions.') + + if not conj_b: + return complex(torch.matmul(a, b[..., 0]), torch.matmul(a, b[..., 1])) + if conj_b: + return complex(torch.matmul(a, b[..., 0]), -torch.matmul(a, b[..., 1])) + + +@tensor_operation +def mtimes_complex_real(a: torch.Tensor, b: torch.Tensor, conj_a=False): + if is_real(a): + raise ValueError('Incorrect dimensions.') + + if not conj_a: + return complex(torch.matmul(a[..., 0], b), torch.matmul(a[..., 1], b)) + if conj_a: + return complex(torch.matmul(a[..., 0], b), -torch.matmul(a[..., 1], b)) + + +@tensor_operation +def exp_imag(a: torch.Tensor): + """Complex exponential with imaginary input: e^(i*a)""" + + a = a.unsqueeze(-1) + return torch.cat((torch.cos(a), torch.sin(a)), -1) + + + diff --git a/Stark/external/AR/pytracking/libs/dcf.py b/Stark/external/AR/pytracking/libs/dcf.py new file mode 100755 index 0000000..ae5d88c --- /dev/null +++ b/Stark/external/AR/pytracking/libs/dcf.py @@ -0,0 +1,164 @@ +import torch +import math +from pytracking import fourier +from pytracking import complex +import torch.nn.functional as F + + +def hann1d(sz: int, centered = True) -> torch.Tensor: + """1D cosine window.""" + if centered: + return 0.5 * (1 - torch.cos((2 * math.pi / (sz + 1)) * torch.arange(1, sz + 1).float())) + w = 0.5 * (1 + torch.cos((2 * math.pi / (sz + 2)) * torch.arange(0, sz//2 + 1).float())) + return torch.cat([w, w[1:sz-sz//2].flip((0,))]) + + +def hann2d(sz: torch.Tensor, centered = True) -> torch.Tensor: + """2D cosine window.""" + return hann1d(sz[0].item(), centered).reshape(1, 1, -1, 1) * hann1d(sz[1].item(), centered).reshape(1, 1, 1, -1) + + +def hann2d_clipped(sz: torch.Tensor, effective_sz: torch.Tensor, centered = True) -> torch.Tensor: + """1D clipped cosine window.""" + + # Ensure that the difference is even + effective_sz += (effective_sz - sz) % 2 + effective_window = hann1d(effective_sz[0].item(), True).reshape(1, 1, -1, 1) * hann1d(effective_sz[1].item(), True).reshape(1, 1, 1, -1) + + pad = (sz - effective_sz) / 2 + + window = F.pad(effective_window, (pad[1].item(), pad[1].item(), pad[0].item(), pad[0].item()), 'replicate') + + if centered: + return window + else: + mid = (sz / 2).int() + window_shift_lr = torch.cat((window[:, :, :, mid[1]:], window[:, :, :, :mid[1]]), 3) + return torch.cat((window_shift_lr[:, :, mid[0]:, :], window_shift_lr[:, :, :mid[0], :]), 2) + + +def gauss_fourier(sz: int, sigma: float, half: bool = False) -> torch.Tensor: + if half: + k = torch.arange(0, int(sz/2+1)) + else: + k = torch.arange(-int((sz-1)/2), int(sz/2+1)) + return (math.sqrt(2*math.pi) * sigma / sz) * torch.exp(-2 * (math.pi * sigma * k.float() / sz)**2) + + +def gauss_spatial(sz, sigma, center=0, end_pad=0): + k = torch.arange(-(sz-1)/2, (sz+1)/2+end_pad) + return torch.exp(-1.0/(2*sigma**2) * (k - center)**2) + + +def label_function(sz: torch.Tensor, sigma: torch.Tensor): + return gauss_fourier(sz[0].item(), sigma[0].item()).reshape(1, 1, -1, 1) * gauss_fourier(sz[1].item(), sigma[1].item(), True).reshape(1, 1, 1, -1) + +def label_function_spatial(sz: torch.Tensor, sigma: torch.Tensor, center: torch.Tensor = torch.zeros(2), end_pad: torch.Tensor = torch.zeros(2)): + """The origin is in the middle of the image.""" + return gauss_spatial(sz[0].item(), sigma[0].item(), center[0], end_pad[0].item()).reshape(1, 1, -1, 1) * \ + gauss_spatial(sz[1].item(), sigma[1].item(), center[1], end_pad[1].item()).reshape(1, 1, 1, -1) + + +def cubic_spline_fourier(f, a): + """The continuous Fourier transform of a cubic spline kernel.""" + + bf = (6*(1 - torch.cos(2 * math.pi * f)) + 3*a*(1 - torch.cos(4 * math.pi * f)) + - (6 + 8*a)*math.pi*f*torch.sin(2 * math.pi * f) - 2*a*math.pi*f*torch.sin(4 * math.pi * f)) \ + / (4 * math.pi**4 * f**4) + + bf[f == 0] = 1 + + return bf + + +def get_interp_fourier(sz: torch.Tensor, method='ideal', bicubic_param=0.5, centering=True, windowing=False, device='cpu'): + + ky, kx = fourier.get_frequency_coord(sz) + + if method=='ideal': + interp_y = torch.ones(ky.shape) / sz[0] + interp_x = torch.ones(kx.shape) / sz[1] + elif method=='bicubic': + interp_y = cubic_spline_fourier(ky / sz[0], bicubic_param) / sz[0] + interp_x = cubic_spline_fourier(kx / sz[1], bicubic_param) / sz[1] + else: + raise ValueError('Unknown method.') + + if centering: + interp_y = complex.mult(interp_y, complex.exp_imag((-math.pi/sz[0]) * ky)) + interp_x = complex.mult(interp_x, complex.exp_imag((-math.pi/sz[1]) * kx)) + + if windowing: + raise NotImplementedError + + return interp_y.to(device), interp_x.to(device) + + +def interpolate_dft(a: torch.Tensor, interp_fs) -> torch.Tensor: + + if isinstance(interp_fs, torch.Tensor): + return complex.mult(a, interp_fs) + if isinstance(interp_fs, (tuple, list)): + return complex.mult(complex.mult(a, interp_fs[0]), interp_fs[1]) + raise ValueError('"interp_fs" must be tensor or tuple of tensors.') + + +def get_reg_filter(sz: torch.Tensor, target_sz: torch.Tensor, params): + """Computes regularization filter in CCOT and ECO.""" + + if not params.use_reg_window: + return params.reg_window_min * torch.ones(1,1,1,1) + + if getattr(params, 'reg_window_square', False): + target_sz = target_sz.prod().sqrt() * torch.ones(2) + + # Normalization factor + reg_scale = 0.5 * target_sz + + # Construct grid + if getattr(params, 'reg_window_centered', True): + wrg = torch.arange(-int((sz[0]-1)/2), int(sz[0]/2+1), dtype=torch.float32).view(1,1,-1,1) + wcg = torch.arange(-int((sz[1]-1)/2), int(sz[1]/2+1), dtype=torch.float32).view(1,1,1,-1) + else: + wrg = torch.cat([torch.arange(0, int(sz[0]/2+1), dtype=torch.float32), + torch.arange(-int((sz[0] - 1) / 2), 0, dtype=torch.float32)]).view(1,1,-1,1) + wcg = torch.cat([torch.arange(0, int(sz[1]/2+1), dtype=torch.float32), + torch.arange(-int((sz[1] - 1) / 2), 0, dtype=torch.float32)]).view(1,1,1,-1) + + # Construct regularization window + reg_window = (params.reg_window_edge - params.reg_window_min) * \ + (torch.abs(wrg/reg_scale[0])**params.reg_window_power + + torch.abs(wcg/reg_scale[1])**params.reg_window_power) + params.reg_window_min + + # Compute DFT and enforce sparsity + reg_window_dft = torch.rfft(reg_window, 2) / sz.prod() + reg_window_dft_abs = complex.abs(reg_window_dft) + reg_window_dft[reg_window_dft_abs < params.reg_sparsity_threshold * reg_window_dft_abs.max(), :] = 0 + + # Do the inverse transform to correct for the window minimum + reg_window_sparse = torch.irfft(reg_window_dft, 2, signal_sizes=sz.long().tolist()) + reg_window_dft[0,0,0,0,0] += params.reg_window_min - sz.prod() * reg_window_sparse.min() + reg_window_dft = complex.real(fourier.rfftshift2(reg_window_dft)) + + # Remove zeros + max_inds,_ = reg_window_dft.nonzero().max(dim=0) + mid_ind = int((reg_window_dft.shape[2]-1)/2) + top = max_inds[-2].item() + 1 + bottom = 2*mid_ind - max_inds[-2].item() + right = max_inds[-1].item() + 1 + reg_window_dft = reg_window_dft[..., bottom:top, :right] + if reg_window_dft.shape[-1] > 1: + reg_window_dft = torch.cat([reg_window_dft[..., 1:].flip((2, 3)), reg_window_dft], -1) + + return reg_window_dft + + +def max2d(a: torch.Tensor) -> (torch.Tensor, torch.Tensor): + """Computes maximum and argmax in the last two dimensions.""" + + max_val_row, argmax_row = torch.max(a, dim=-2) + max_val, argmax_col = torch.max(max_val_row, dim=-1) + argmax_row = argmax_row.view(argmax_col.numel(),-1)[torch.arange(argmax_col.numel()), argmax_col.view(-1)] + argmax_row = argmax_row.reshape(argmax_col.shape) + argmax = torch.cat((argmax_row.unsqueeze(-1), argmax_col.unsqueeze(-1)), -1) + return max_val, argmax diff --git a/Stark/external/AR/pytracking/libs/fourier.py b/Stark/external/AR/pytracking/libs/fourier.py new file mode 100755 index 0000000..6cbad18 --- /dev/null +++ b/Stark/external/AR/pytracking/libs/fourier.py @@ -0,0 +1,146 @@ +import torch +import torch.nn.functional as F +from pytracking import complex, TensorList +from pytracking.libs.tensorlist import tensor_operation + + +@tensor_operation +def rfftshift2(a: torch.Tensor): + h = a.shape[2] + 2 + return torch.cat((a[:,:,(h-1)//2:,...], a[:,:,:h//2,...]), 2) + + +@tensor_operation +def irfftshift2(a: torch.Tensor): + mid = int((a.shape[2]-1)/2) + return torch.cat((a[:,:,mid:,...], a[:,:,:mid,...]), 2) + + +@tensor_operation +def cfft2(a): + """Do FFT and center the low frequency component. + Always produces odd (full) output sizes.""" + + return rfftshift2(torch.rfft(a, 2)) + + +@tensor_operation +def cifft2(a, signal_sizes=None): + """Do inverse FFT corresponding to cfft2.""" + + return torch.irfft(irfftshift2(a), 2, signal_sizes=signal_sizes) + + +@tensor_operation +def sample_fs(a: torch.Tensor, grid_sz: torch.Tensor = None, rescale = True): + """Samples the Fourier series.""" + + # Size of the fourier series + sz = torch.Tensor([a.shape[2], 2*a.shape[3]-1]).float() + + # Default grid + if grid_sz is None or sz[0] == grid_sz[0] and sz[1] == grid_sz[1]: + if rescale: + return sz.prod().item() * cifft2(a) + return cifft2(a) + + if sz[0] > grid_sz[0] or sz[1] > grid_sz[1]: + raise ValueError("Only grid sizes that are smaller than the Fourier series size are supported.") + + tot_pad = (grid_sz - sz).tolist() + is_even = [s.item() % 2 == 0 for s in sz] + + # Compute paddings + pad_top = int((tot_pad[0]+1)/2) if is_even[0] else int(tot_pad[0]/2) + pad_bottom = int(tot_pad[0] - pad_top) + pad_right = int((tot_pad[1]+1)/2) + + if rescale: + return grid_sz.prod().item() * cifft2(F.pad(a, (0, 0, 0, pad_right, pad_top, pad_bottom)), signal_sizes=grid_sz.long().tolist()) + else: + return cifft2(F.pad(a, (0, 0, 0, pad_right, pad_top, pad_bottom)), signal_sizes=grid_sz.long().tolist()) + + +def get_frequency_coord(sz, add_complex_dim = False, device='cpu'): + """Frequency coordinates.""" + + ky = torch.arange(-int((sz[0]-1)/2), int(sz[0]/2+1), dtype=torch.float32, device=device).view(1,1,-1,1) + kx = torch.arange(0, int(sz[1]/2+1), dtype=torch.float32, device=device).view(1,1,1,-1) + + if add_complex_dim: + ky = ky.unsqueeze(-1) + kx = kx.unsqueeze(-1) + + return ky, kx + + +@tensor_operation +def shift_fs(a: torch.Tensor, shift: torch.Tensor): + """Shift a sample a in the Fourier domain. + Params: + a : The fourier coefficiens of the sample. + shift : The shift to be performed normalized to the range [-pi, pi].""" + + if a.dim() != 5: + raise ValueError('a must be the Fourier coefficients, a 5-dimensional tensor.') + + if shift[0] == 0 and shift[1] == 0: + return a + + ky, kx = get_frequency_coord((a.shape[2], 2*a.shape[3]-1), device=a.device) + + return complex.mult(complex.mult(a, complex.exp_imag(shift[0].item()*ky)), complex.exp_imag(shift[1].item()*kx)) + + +def sum_fs(a: TensorList) -> torch.Tensor: + """Sum a list of Fourier series expansions.""" + + s = None + mid = None + + for e in sorted(a, key=lambda elem: elem.shape[-3], reverse=True): + if s is None: + s = e.clone() + mid = int((s.shape[-3] - 1) / 2) + else: + # Compute coordinates + top = mid - int((e.shape[-3] - 1) / 2) + bottom = mid + int(e.shape[-3] / 2) + 1 + right = e.shape[-2] + + # Add the data + s[..., top:bottom, :right, :] += e + + return s + + +def sum_fs12(a: TensorList) -> torch.Tensor: + """Sum a list of Fourier series expansions.""" + + s = None + mid = None + + for e in sorted(a, key=lambda elem: elem.shape[0], reverse=True): + if s is None: + s = e.clone() + mid = int((s.shape[0] - 1) / 2) + else: + # Compute coordinates + top = mid - int((e.shape[0] - 1) / 2) + bottom = mid + int(e.shape[0] / 2) + 1 + right = e.shape[1] + + # Add the data + s[top:bottom, :right, ...] += e + + return s + + +@tensor_operation +def inner_prod_fs(a: torch.Tensor, b: torch.Tensor): + if complex.is_complex(a) and complex.is_complex(b): + return 2 * (a.reshape(-1) @ b.reshape(-1)) - a[:, :, :, 0, :].reshape(-1) @ b[:, :, :, 0, :].reshape(-1) + elif complex.is_real(a) and complex.is_real(b): + return 2 * (a.reshape(-1) @ b.reshape(-1)) - a[:, :, :, 0].reshape(-1) @ b[:, :, :, 0].reshape(-1) + else: + raise NotImplementedError('Not implemented for mixed real and complex.') \ No newline at end of file diff --git a/Stark/external/AR/pytracking/libs/operation.py b/Stark/external/AR/pytracking/libs/operation.py new file mode 100755 index 0000000..20fa3d8 --- /dev/null +++ b/Stark/external/AR/pytracking/libs/operation.py @@ -0,0 +1,42 @@ +import torch +import torch.nn.functional as F +from pytracking.libs.tensorlist import tensor_operation, TensorList + + +@tensor_operation +def conv2d(input: torch.Tensor, weight: torch.Tensor, bias: torch.Tensor = None, stride=1, padding=0, dilation=1, groups=1, mode=None): + """Standard conv2d. Returns the input if weight=None.""" + + if weight is None: + return input + + ind = None + if mode is not None: + if padding != 0: + raise ValueError('Cannot input both padding and mode.') + if mode == 'same': + padding = (weight.shape[2]//2, weight.shape[3]//2) + if weight.shape[2] % 2 == 0 or weight.shape[3] % 2 == 0: + ind = (slice(-1) if weight.shape[2] % 2 == 0 else slice(None), + slice(-1) if weight.shape[3] % 2 == 0 else slice(None)) + elif mode == 'valid': + padding = (0, 0) + elif mode == 'full': + padding = (weight.shape[2]-1, weight.shape[3]-1) + else: + raise ValueError('Unknown mode for padding.') + + out = F.conv2d(input, weight, bias=bias, stride=stride, padding=padding, dilation=dilation, groups=groups) + if ind is None: + return out + return out[:,:,ind[0],ind[1]] + + +@tensor_operation +def conv1x1(input: torch.Tensor, weight: torch.Tensor): + """Do a convolution with a 1x1 kernel weights. Implemented with matmul, which can be faster than using conv.""" + + if weight is None: + return input + + return torch.conv2d(input, weight) diff --git a/Stark/external/AR/pytracking/libs/optimization.py b/Stark/external/AR/pytracking/libs/optimization.py new file mode 100755 index 0000000..43a09c4 --- /dev/null +++ b/Stark/external/AR/pytracking/libs/optimization.py @@ -0,0 +1,714 @@ +import torch +import torch.autograd +import math +from pytracking.libs import TensorList +from pytracking.utils.plotting import plot_graph +from ltr.models.layers.activation import softmax_reg + + +class L2Problem: + """Base class for representing an L2 optimization problem.""" + + def __call__(self, x: TensorList) -> TensorList: + """Shall compute the residuals of the problem.""" + raise NotImplementedError + + def ip_input(self, a, b): + """Inner product of the input space.""" + return sum(a.view(-1) @ b.view(-1)) + + def ip_output(self, a, b): + """Inner product of the output space.""" + return sum(a.view(-1) @ b.view(-1)) + + def M1(self, x): + """M1 preconditioner.""" + return x + + def M2(self, x): + """M2 preconditioner.""" + return x + +class MinimizationProblem: + """General minimization problem.""" + def __call__(self, x: TensorList) -> TensorList: + """Shall compute the loss.""" + raise NotImplementedError + + def ip_input(self, a, b): + """Inner product of the input space.""" + return sum(a.view(-1) @ b.view(-1)) + + def M1(self, x): + return x + + def M2(self, x): + return x + + +class ConjugateGradientBase: + """Conjugate Gradient optimizer base class. Implements the CG loop.""" + + def __init__(self, fletcher_reeves = True, standard_alpha = True, direction_forget_factor = 0, debug = False): + self.fletcher_reeves = fletcher_reeves + self.standard_alpha = standard_alpha + self.direction_forget_factor = direction_forget_factor + self.debug = debug + + # State + self.p = None + self.rho = torch.ones(1) + self.r_prev = None + + # Right hand side + self.b = None + + def reset_state(self): + self.p = None + self.rho = torch.ones(1) + self.r_prev = None + + + def run_CG(self, num_iter, x=None, eps=0.0): + """Main conjugate gradient method. + + args: + num_iter: Number of iterations. + x: Initial guess. Assumed zero if None. + eps: Stop if the residual norm gets smaller than this. + """ + + # Apply forgetting factor + if self.direction_forget_factor == 0: + self.reset_state() + elif self.p is not None: + self.rho /= self.direction_forget_factor + + if x is None: + r = self.b.clone() + else: + r = self.b - self.A(x) + + # Norms of residuals etc for debugging + resvec = None + if self.debug: + normr = self.residual_norm(r) + resvec = torch.zeros(num_iter+1) + resvec[0] = normr + + # Loop over iterations + for ii in range(num_iter): + # Preconditioners + y = self.M1(r) + z = self.M2(y) + + rho1 = self.rho + self.rho = self.ip(r, z) + + if self.check_zero(self.rho): + if self.debug: + print('Stopped CG since rho = 0') + if resvec is not None: + resvec = resvec[:ii+1] + return x, resvec + + if self.p is None: + self.p = z.clone() + else: + if self.fletcher_reeves: + beta = self.rho / rho1 + else: + rho2 = self.ip(self.r_prev, z) + beta = (self.rho - rho2) / rho1 + + beta = beta.clamp(0) + self.p = z + self.p * beta + + q = self.A(self.p) + pq = self.ip(self.p, q) + + if self.standard_alpha: + alpha = self.rho / pq + else: + alpha = self.ip(self.p, r) / pq + + # Save old r for PR formula + if not self.fletcher_reeves: + self.r_prev = r.clone() + + # Form new iterate + if x is None: + x = self.p * alpha + else: + x += self.p * alpha + + if ii < num_iter - 1 or self.debug: + r -= q * alpha + + if eps > 0.0 or self.debug: + normr = self.residual_norm(r) + + if self.debug: + self.evaluate_CG_iteration(x) + resvec[ii+1] = normr + + if eps > 0 and normr <= eps: + if self.debug: + print('Stopped CG since norm smaller than eps') + break + + if resvec is not None: + resvec = resvec[:ii+2] + + return x, resvec + + + def A(self, x): + # Implements the left hand operation + raise NotImplementedError + + def ip(self, a, b): + # Implements the inner product + return a.view(-1) @ b.view(-1) + + def residual_norm(self, r): + res = self.ip(r, r).sum() + if isinstance(res, (TensorList, list, tuple)): + res = sum(res) + return res.sqrt() + + def check_zero(self, s, eps = 0.0): + ss = s.abs() <= eps + if isinstance(ss, (TensorList, list, tuple)): + ss = sum(ss) + return ss.item() > 0 + + def M1(self, x): + # M1 preconditioner + return x + + def M2(self, x): + # M2 preconditioner + return x + + def evaluate_CG_iteration(self, x): + pass + + + +class ConjugateGradient(ConjugateGradientBase): + """Conjugate Gradient optimizer, performing single linearization of the residuals in the start.""" + + def __init__(self, problem: L2Problem, variable: TensorList, cg_eps = 0.0, fletcher_reeves = True, + standard_alpha = True, direction_forget_factor = 0, debug = False, plotting = False, visdom=None): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or plotting) + + self.problem = problem + self.x = variable + + self.plotting = plotting + self.fig_num = (10,11) + self.visdom = visdom + + self.cg_eps = cg_eps + self.f0 = None + self.g = None + self.dfdxt_g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + self.dfdxt_g = None + + + def run(self, num_cg_iter): + """Run the oprimizer with the provided number of iterations.""" + + if num_cg_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(2) + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Create copy with graph detached + self.g = self.f0.detach() + + if self.debug: + lossvec[0] = self.problem.ip_output(self.g, self.g) + + self.g.requires_grad_(True) + + # Get df/dx^t @ f0 + self.dfdxt_g = TensorList(torch.autograd.grad(self.f0, self.x, self.g, create_graph=True)) + + # Get the right hand side + self.b = - self.dfdxt_g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.f0 = self.problem(self.x) + lossvec[-1] = self.problem.ip_output(self.f0, self.f0) + self.residuals = torch.cat((self.residuals, res)) + self.losses = torch.cat((self.losses, lossvec)) + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.residuals, 'lineplot', 3, 'CG residuals') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + + self.x.detach_() + self.clear_temp() + + + def A(self, x): + dfdx_x = torch.autograd.grad(self.dfdxt_g, self.g, x, retain_graph=True) + return TensorList(torch.autograd.grad(self.f0, self.x, dfdx_x, retain_graph=True)) + + def ip(self, a, b): + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + + +class GaussNewtonCG(ConjugateGradientBase): + """Gauss-Newton with Conjugate Gradient optimizer.""" + + def __init__(self, problem: L2Problem, variable: TensorList, cg_eps = 0.0, fletcher_reeves = True, + standard_alpha = True, direction_forget_factor = 0, debug = False, analyze = False, plotting = False, + visdom=None): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or analyze or plotting) + + self.problem = problem + self.x = variable + + self.analyze_convergence = analyze + self.plotting = plotting + self.fig_num = (10,11,12) + self.visdom = visdom + + self.cg_eps = cg_eps + self.f0 = None + self.g = None + self.dfdxt_g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + self.dfdxt_g = None + + + def run_GN(self, *args, **kwargs): + return self.run(*args, **kwargs) + + + def run(self, num_cg_iter, num_gn_iter=None): + """Run the optimizer. + args: + num_cg_iter: Number of CG iterations per GN iter. If list, then each entry specifies number of CG iterations + and number of GN iterations is given by the length of the list. + num_gn_iter: Number of GN iterations. Shall only be given if num_cg_iter is an integer. + """ + + if isinstance(num_cg_iter, int): + if num_gn_iter is None: + raise ValueError('Must specify number of GN iter if CG iter is constant') + num_cg_iter = [num_cg_iter]*num_gn_iter + + num_gn_iter = len(num_cg_iter) + if num_gn_iter == 0: + return + + if self.analyze_convergence: + self.evaluate_CG_iteration(0) + + # Outer loop for running the GN iterations. + for cg_iter in num_cg_iter: + self.run_GN_iter(cg_iter) + + if self.debug: + if not self.analyze_convergence: + self.f0 = self.problem(self.x) + loss = self.problem.ip_output(self.f0, self.f0) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.residuals, 'lineplot', 3, 'CG residuals') + + if self.analyze_convergence: + self.visdom.register(self.gradient_mags, 'lineplot', 4, 'Gradient magnitude') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + if self.analyze_convergence: + plot_graph(self.gradient_mags, self.fig_num[2], 'Gradient magnitude') + + + self.x.detach_() + self.clear_temp() + + return self.losses, self.residuals + + + def run_GN_iter(self, num_cg_iter): + """Runs a single GN iteration.""" + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Create copy with graph detached + self.g = self.f0.detach() + + if self.debug and not self.analyze_convergence: + loss = self.problem.ip_output(self.g, self.g) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + self.g.requires_grad_(True) + + # Get df/dx^t @ f0 + self.dfdxt_g = TensorList(torch.autograd.grad(self.f0, self.x, self.g, create_graph=True)) + + # Get the right hand side + self.b = - self.dfdxt_g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + + + def A(self, x): + dfdx_x = torch.autograd.grad(self.dfdxt_g, self.g, x, retain_graph=True) + return TensorList(torch.autograd.grad(self.f0, self.x, dfdx_x, retain_graph=True)) + + def ip(self, a, b): + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + def evaluate_CG_iteration(self, delta_x): + if self.analyze_convergence: + x = (self.x + delta_x).detach() + x.requires_grad_(True) + + # compute loss and gradient + f = self.problem(x) + loss = self.problem.ip_output(f, f) + grad = TensorList(torch.autograd.grad(loss, x)) + + # store in the vectors + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + self.gradient_mags = torch.cat((self.gradient_mags, sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().detach().view(-1))) + + +class GradientDescentL2: + """Gradient descent with momentum for L2 problems.""" + + def __init__(self, problem: L2Problem, variable: TensorList, step_length: float, momentum: float = 0.0, debug = False, plotting = False, visdom=None): + + self.problem = problem + self.x = variable + + self.step_legnth = step_length + self.momentum = momentum + + self.debug = debug or plotting + self.plotting = plotting + self.fig_num = (10,11) + self.visdom = visdom + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + self.residuals = None + + self.clear_temp() + + + def clear_temp(self): + self.f0 = None + self.dir = None + + + def run(self, num_iter, dummy = None): + + if num_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(num_iter+1) + grad_mags = torch.zeros(num_iter+1) + + for i in range(num_iter): + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Compute loss + loss = self.problem.ip_output(self.f0, self.f0) + + # Compute grad + grad = TensorList(torch.autograd.grad(loss, self.x)) + + # Update direction + if self.dir is None: + self.dir = grad + else: + self.dir = grad + self.momentum * self.dir + + self.x.detach_() + self.x -= self.step_legnth * self.dir + + if self.debug: + lossvec[i] = loss.item() + grad_mags[i] = sum(grad.view(-1) @ grad.view(-1)).sqrt().item() + + if self.debug: + self.x.requires_grad_(True) + self.f0 = self.problem(self.x) + loss = self.problem.ip_output(self.f0, self.f0) + grad = TensorList(torch.autograd.grad(loss, self.x)) + lossvec[-1] = self.problem.ip_output(self.f0, self.f0).item() + grad_mags[-1] = sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().item() + self.losses = torch.cat((self.losses, lossvec)) + self.gradient_mags = torch.cat((self.gradient_mags, grad_mags)) + + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.gradient_mags, 'lineplot', 4, 'Gradient magnitude') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.gradient_mags, self.fig_num[1], title='Gradient magnitude') + + self.x.detach_() + self.clear_temp() + + + +class NewtonCG(ConjugateGradientBase): + """Newton with Conjugate Gradient. Handels general minimization problems.""" + + def __init__(self, problem: MinimizationProblem, variable: TensorList, init_hessian_reg = 0.0, hessian_reg_factor = 1.0, + cg_eps = 0.0, fletcher_reeves = True, standard_alpha = True, direction_forget_factor = 0, + debug = False, analyze = False, plotting = False, fig_num=(10, 11, 12)): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or analyze or plotting) + + self.problem = problem + self.x = variable + + self.analyze_convergence = analyze + self.plotting = plotting + self.fig_num = fig_num + + self.hessian_reg = init_hessian_reg + self.hessian_reg_factor = hessian_reg_factor + self.cg_eps = cg_eps + self.f0 = None + self.g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + + + def run(self, num_cg_iter, num_newton_iter=None): + + if isinstance(num_cg_iter, int): + if num_cg_iter == 0: + return + if num_newton_iter is None: + num_newton_iter = 1 + num_cg_iter = [num_cg_iter] * num_newton_iter + + num_newton_iter = len(num_cg_iter) + if num_newton_iter == 0: + return + + if self.analyze_convergence: + self.evaluate_CG_iteration(0) + + for cg_iter in num_cg_iter: + self.run_newton_iter(cg_iter) + self.hessian_reg *= self.hessian_reg_factor + + if self.debug: + if not self.analyze_convergence: + loss = self.problem(self.x) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + if self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + if self.analyze_convergence: + plot_graph(self.gradient_mags, self.fig_num[2], 'Gradient magnitude') + + self.x.detach_() + self.clear_temp() + + return self.losses, self.residuals + + + def run_newton_iter(self, num_cg_iter): + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + if self.debug and not self.analyze_convergence: + self.losses = torch.cat((self.losses, self.f0.detach().cpu().view(-1))) + + # Gradient of loss + self.g = TensorList(torch.autograd.grad(self.f0, self.x, create_graph=True)) + + # Get the right hand side + self.b = - self.g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + + + def A(self, x): + return TensorList(torch.autograd.grad(self.g, self.x, x, retain_graph=True)) + self.hessian_reg * x + + def ip(self, a, b): + # Implements the inner product + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + def evaluate_CG_iteration(self, delta_x): + if self.analyze_convergence: + x = (self.x + delta_x).detach() + x.requires_grad_(True) + + # compute loss and gradient + loss = self.problem(x) + grad = TensorList(torch.autograd.grad(loss, x)) + + # store in the vectors + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + self.gradient_mags = torch.cat((self.gradient_mags, sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().detach().view(-1))) + + +class GradientDescent: + """Gradient descent for general minimization problems.""" + + def __init__(self, problem: MinimizationProblem, variable: TensorList, step_length: float, momentum: float = 0.0, + debug = False, plotting = False, fig_num=(10,11)): + + self.problem = problem + self.x = variable + + self.step_legnth = step_length + self.momentum = momentum + + self.debug = debug or plotting + self.plotting = plotting + self.fig_num = fig_num + + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + self.residuals = None + + self.clear_temp() + + + def clear_temp(self): + self.dir = None + + + def run(self, num_iter, dummy = None): + + if num_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(num_iter+1) + grad_mags = torch.zeros(num_iter+1) + + for i in range(num_iter): + self.x.requires_grad_(True) + + # Evaluate function at current estimate + loss = self.problem(self.x) + + # Compute grad + grad = TensorList(torch.autograd.grad(loss, self.x)) + + # Update direction + if self.dir is None: + self.dir = grad + else: + self.dir = grad + self.momentum * self.dir + + self.x.detach_() + self.x -= self.step_legnth * self.dir + + if self.debug: + lossvec[i] = loss.item() + grad_mags[i] = sum(grad.view(-1) @ grad.view(-1)).sqrt().item() + + if self.debug: + self.x.requires_grad_(True) + loss = self.problem(self.x) + grad = TensorList(torch.autograd.grad(loss, self.x)) + lossvec[-1] = loss.item() + grad_mags[-1] = sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().item() + self.losses = torch.cat((self.losses, lossvec)) + self.gradient_mags = torch.cat((self.gradient_mags, grad_mags)) + if self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.gradient_mags, self.fig_num[1], title='Gradient magnitude') + + self.x.detach_() + self.clear_temp() \ No newline at end of file diff --git a/Stark/external/AR/pytracking/libs/tensordict.py b/Stark/external/AR/pytracking/libs/tensordict.py new file mode 100755 index 0000000..9b2fe7f --- /dev/null +++ b/Stark/external/AR/pytracking/libs/tensordict.py @@ -0,0 +1,36 @@ +from collections import OrderedDict +import torch +import copy + + +class TensorDict(OrderedDict): + """Container mainly used for dicts of torch tensors. Extends OrderedDict with pytorch functionality.""" + + def concat(self, other): + """Concatenates two dicts without copying internal data.""" + return TensorDict(self, **other) + + def copy(self): + return TensorDict(super(TensorDict, self).copy()) + + def __deepcopy__(self, memodict={}): + return TensorDict(copy.deepcopy(list(self), memodict)) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorDict\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorDict({n: getattr(e, name)(*args, **kwargs) if hasattr(e, name) else e for n, e in self.items()}) + return apply_attr + + def attribute(self, attr: str, *args): + return TensorDict({n: getattr(e, attr, *args) for n, e in self.items()}) + + def apply(self, fn, *args, **kwargs): + return TensorDict({n: fn(e, *args, **kwargs) for n, e in self.items()}) + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorDict, list)) + diff --git a/Stark/external/AR/pytracking/libs/tensorlist.py b/Stark/external/AR/pytracking/libs/tensorlist.py new file mode 100755 index 0000000..0e9227e --- /dev/null +++ b/Stark/external/AR/pytracking/libs/tensorlist.py @@ -0,0 +1,212 @@ +import functools +import torch +import copy + + +class TensorList(list): + """Container mainly used for lists of torch tensors. Extends lists with pytorch functionality.""" + + def __init__(self, list_of_tensors = None): + if list_of_tensors is None: + list_of_tensors = list() + super(TensorList, self).__init__(list_of_tensors) + + def __deepcopy__(self, memodict={}): + return TensorList(copy.deepcopy(list(self), memodict)) + + def __getitem__(self, item): + if isinstance(item, int): + return super(TensorList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return TensorList([super(TensorList, self).__getitem__(i) for i in item]) + else: + return TensorList(super(TensorList, self).__getitem__(item)) + + def __add__(self, other): + if TensorList._iterable(other): + return TensorList([e1 + e2 for e1, e2 in zip(self, other)]) + return TensorList([e + other for e in self]) + + def __radd__(self, other): + if TensorList._iterable(other): + return TensorList([e2 + e1 for e1, e2 in zip(self, other)]) + return TensorList([other + e for e in self]) + + def __iadd__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] += e2 + else: + for i in range(len(self)): + self[i] += other + return self + + def __sub__(self, other): + if TensorList._iterable(other): + return TensorList([e1 - e2 for e1, e2 in zip(self, other)]) + return TensorList([e - other for e in self]) + + def __rsub__(self, other): + if TensorList._iterable(other): + return TensorList([e2 - e1 for e1, e2 in zip(self, other)]) + return TensorList([other - e for e in self]) + + def __isub__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] -= e2 + else: + for i in range(len(self)): + self[i] -= other + return self + + def __mul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 * e2 for e1, e2 in zip(self, other)]) + return TensorList([e * other for e in self]) + + def __rmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 * e1 for e1, e2 in zip(self, other)]) + return TensorList([other * e for e in self]) + + def __imul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] *= e2 + else: + for i in range(len(self)): + self[i] *= other + return self + + def __truediv__(self, other): + if TensorList._iterable(other): + return TensorList([e1 / e2 for e1, e2 in zip(self, other)]) + return TensorList([e / other for e in self]) + + def __rtruediv__(self, other): + if TensorList._iterable(other): + return TensorList([e2 / e1 for e1, e2 in zip(self, other)]) + return TensorList([other / e for e in self]) + + def __itruediv__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] /= e2 + else: + for i in range(len(self)): + self[i] /= other + return self + + def __matmul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 @ e2 for e1, e2 in zip(self, other)]) + return TensorList([e @ other for e in self]) + + def __rmatmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 @ e1 for e1, e2 in zip(self, other)]) + return TensorList([other @ e for e in self]) + + def __imatmul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] @= e2 + else: + for i in range(len(self)): + self[i] @= other + return self + + def __mod__(self, other): + if TensorList._iterable(other): + return TensorList([e1 % e2 for e1, e2 in zip(self, other)]) + return TensorList([e % other for e in self]) + + def __rmod__(self, other): + if TensorList._iterable(other): + return TensorList([e2 % e1 for e1, e2 in zip(self, other)]) + return TensorList([other % e for e in self]) + + def __pos__(self): + return TensorList([+e for e in self]) + + def __neg__(self): + return TensorList([-e for e in self]) + + def __le__(self, other): + if TensorList._iterable(other): + return TensorList([e1 <= e2 for e1, e2 in zip(self, other)]) + return TensorList([e <= other for e in self]) + + def __ge__(self, other): + if TensorList._iterable(other): + return TensorList([e1 >= e2 for e1, e2 in zip(self, other)]) + return TensorList([e >= other for e in self]) + + def concat(self, other): + return TensorList(super(TensorList, self).__add__(other)) + + def copy(self): + return TensorList(super(TensorList, self).copy()) + + def unroll(self): + if not any(isinstance(t, TensorList) for t in self): + return self + + new_list = TensorList() + for t in self: + if isinstance(t, TensorList): + new_list.extend(t.unroll()) + else: + new_list.append(t) + return new_list + + def list(self): + return list(self) + + def attribute(self, attr: str, *args): + return TensorList([getattr(e, attr, *args) for e in self]) + + def apply(self, fn): + return TensorList([fn(e) for e in self]) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorList\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorList([getattr(e, name)(*args, **kwargs) for e in self]) + + return apply_attr + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorList, list)) + + + +def tensor_operation(op): + def islist(a): + return isinstance(a, TensorList) + + @functools.wraps(op) + def oplist(*args, **kwargs): + if len(args) == 0: + raise ValueError('Must be at least one argument without keyword (i.e. operand).') + + if len(args) == 1: + if islist(args[0]): + return TensorList([op(a, **kwargs) for a in args[0]]) + else: + # Multiple operands, assume max two + if islist(args[0]) and islist(args[1]): + return TensorList([op(a, b, *args[2:], **kwargs) for a, b in zip(*args[:2])]) + if islist(args[0]): + return TensorList([op(a, *args[1:], **kwargs) for a in args[0]]) + if islist(args[1]): + return TensorList([op(args[0], b, *args[2:], **kwargs) for b in args[1]]) + + # None of the operands are lists + return op(*args, **kwargs) + + return oplist diff --git a/Stark/external/AR/pytracking/parameter/__init__.py b/Stark/external/AR/pytracking/parameter/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/parameter/atom/__init__.py b/Stark/external/AR/pytracking/parameter/atom/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/parameter/atom/atom_gmm_sampl.py b/Stark/external/AR/pytracking/parameter/atom/atom_gmm_sampl.py new file mode 100755 index 0000000..5230e26 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/atom/atom_gmm_sampl.py @@ -0,0 +1,105 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = (1e-2, 5e-2) # 1 # Gradient step length in the bounding box refinement 5e-3 2e-2 + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_gmm_sampl', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/Stark/external/AR/pytracking/parameter/atom/atom_prob_ml.py b/Stark/external/AR/pytracking/parameter/atom/atom_prob_ml.py new file mode 100755 index 0000000..185c827 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/atom/atom_prob_ml.py @@ -0,0 +1,105 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = (2e-4, 10e-4) # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_prob_ml', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/Stark/external/AR/pytracking/parameter/atom/default.py b/Stark/external/AR/pytracking/parameter/atom/default.py new file mode 100755 index 0000000..16f9eea --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/atom/default.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/Stark/external/AR/pytracking/parameter/atom/default_vot.py b/Stark/external/AR/pytracking/parameter/atom/default_vot.py new file mode 100755 index 0000000..9d34e5d --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/atom/default_vot.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (14 * 16) ** 2 # Maximum image sample size + params.min_image_sample_size = (14 * 16) ** 2 # Minimum image sample size + params.search_area_scale = 4 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.0075 # Learning rate + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4, 4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = True # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1 / 3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = -1 # Absolute score threshold to detect target missing + params.distractor_threshold = 100 # Relative threshold to find distractors + params.hard_negative_threshold = 0.3 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.7 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, + normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + params.vot_anno_conversion_type = 'preserve_area' + return params \ No newline at end of file diff --git a/Stark/external/AR/pytracking/parameter/atom/multiscale_no_iounet.py b/Stark/external/AR/pytracking/parameter/atom/multiscale_no_iounet.py new file mode 100755 index 0000000..f89fa74 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/atom/multiscale_no_iounet.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = 1.02**torch.arange(-2, 3).float() # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = False # Use IoU net or not + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/__init__.py b/Stark/external/AR/pytracking/parameter/dimp/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/parameter/dimp/dimp18.py b/Stark/external/AR/pytracking/parameter/dimp/dimp18.py new file mode 100755 index 0000000..84a4636 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/dimp18.py @@ -0,0 +1,68 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp18.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/dimp18_vot.py b/Stark/external/AR/pytracking/parameter/dimp/dimp18_vot.py new file mode 100755 index 0000000..bd83125 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/dimp18_vot.py @@ -0,0 +1,72 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 14 * 16 + params.search_area_scale = 4 + params.feature_size_odd = False + + # Learning parameters + params.sample_memory_size = 250 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 25 + params.net_opt_update_iter = 3 + params.net_opt_hn_iter = 3 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45, -45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3, 1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6, -0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp18.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/dimp50.py b/Stark/external/AR/pytracking/parameter/dimp/dimp50.py new file mode 100755 index 0000000..201f2db --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/dimp50.py @@ -0,0 +1,68 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot.py b/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot.py new file mode 100755 index 0000000..a9c03cb --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 14 * 16 + params.search_area_scale = 4 + + # Learning parameters + params.sample_memory_size = 250 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 25 + params.net_opt_update_iter = 3 + params.net_opt_hn_iter = 3 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45, -45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3, 1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6, -0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot19.py b/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot19.py new file mode 100755 index 0000000..45167b6 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/dimp50_vot19.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 16 * 16 + params.search_area_scale = 4.5 + + # Learning parameters + params.sample_memory_size = 100 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 15 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 2 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [-5, 10, -30, 60], + 'blur': [(2, 0.2), (1, 3)], + 'relativeshift': [(0.6, 0.6), (-0.6, -0.6)], + 'dropout': (3, 0.2)} + + params.augmentation_expansion_factor = 1.4 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 3 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/prdimp18.py b/Stark/external/AR/pytracking/parameter/dimp/prdimp18.py new file mode 100755 index 0000000..93ab213 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/prdimp18.py @@ -0,0 +1,69 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.score_preprocess = 'softmax' + params.target_not_found_threshold = 0.04 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path='prdimp18.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/prdimp50.py b/Stark/external/AR/pytracking/parameter/dimp/prdimp50.py new file mode 100755 index 0000000..4e716d7 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/prdimp50.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 22*16 + params.search_area_scale = 6 + params.border_mode = 'inside_major' + params.patch_max_scale_change = 1.5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.score_preprocess = 'softmax' + params.target_not_found_threshold = 0.04 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path='prdimp50.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/dimp/super_dimp.py b/Stark/external/AR/pytracking/parameter/dimp/super_dimp.py new file mode 100755 index 0000000..f87e47a --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/dimp/super_dimp.py @@ -0,0 +1,70 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 22*16 + params.search_area_scale = 6 + params.border_mode = 'inside_major' + params.patch_max_scale_change = 1.5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path='super_dimp.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/Stark/external/AR/pytracking/parameter/eco/__init__.py b/Stark/external/AR/pytracking/parameter/eco/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/parameter/eco/default.py b/Stark/external/AR/pytracking/parameter/eco/default.py new file mode 100755 index 0000000..fddbf51 --- /dev/null +++ b/Stark/external/AR/pytracking/parameter/eco/default.py @@ -0,0 +1,97 @@ +from pytracking.utils import TrackerParams, FeatureParams +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + # Feature specific parameters + shallow_params = TrackerParams() + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = 250**2 # Maximum image sample size + params.min_image_sample_size = 200**2 # Minimum image sample size + params.search_area_scale = 4.5 # Scale relative to target size + + # Conjugate Gradient parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 100 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 10 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = 75 # Forgetting rate of the last conjugate direction + params.precond_data_param = 0.3 # Weight of the data term in the preconditioner + params.precond_reg_param = 0.15 # Weight of the regularization term in the preconditioner + params.precond_proj_param = 35 # Weight of the projection matrix part in the preconditioner + + # Learning parameters + shallow_params.learning_rate = 0.025 + deep_params.learning_rate = 0.0075 + shallow_params.output_sigma_factor = 1/16 + deep_params.output_sigma_factor = 1/4 + + # Training parameters + params.sample_memory_size = 200 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Detection parameters + params.scale_factors = 1.02**torch.arange(-2, 3).float() # What scales to use for localization + params.score_upsample_factor = 1 # How much Fourier upsampling to use + params.score_fusion_strategy = 'weightedsum' # Fusion strategy + shallow_params.translation_weight = 0.4 # Weight of this feature + deep_params.translation_weight = 1 - shallow_params.translation_weight + + # Init augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'shift': [(6, 6), (-6, 6), (6, -6), (-6,-6)], + 'dropout': (7, 0.2)} + + # Whether to use augmentation for this feature + deep_params.use_augmentation = True + shallow_params.use_augmentation = True + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + # params.proj_init_method = 'pca' # Method for initializing the projection matrix + params.projection_reg = 5e-8 # Regularization paremeter of the projection matrix + shallow_params.compressed_dim = 16 # Dimension output of projection matrix for shallow features + deep_params.compressed_dim = 64 # Dimension output of projection matrix for deep features + + # Interpolation parameters + params.interpolation_method = 'bicubic' # The kind of interpolation kernel + params.interpolation_bicubic_a = -0.75 # The parameter for the bicubic interpolation kernel + params.interpolation_centering = True # Center the kernel at the feature sample + params.interpolation_windowing = False # Do additional windowing on the Fourier coefficients of the kernel + + # Regularization parameters + shallow_params.use_reg_window = True # Use spatial regularization or not + shallow_params.reg_window_min = 1e-4 # The minimum value of the regularization window + shallow_params.reg_window_edge = 10e-3 # The impact of the spatial regularization + shallow_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + shallow_params.reg_sparsity_threshold = 0.05 # A relative threshold of which DFT coefficients that should be set to zero + + deep_params.use_reg_window = True # Use spatial regularization or not + deep_params.reg_window_min = 10e-4 # The minimum value of the regularization window + deep_params.reg_window_edge = 50e-3 # The impact of the spatial regularization + deep_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + deep_params.reg_sparsity_threshold = 0.1 # A relative threshold of which DFT coefficients that should be set to zero + + + fparams = FeatureParams(feature_params=[shallow_params, deep_params]) + features = deep.ResNet18m1(output_layers=['vggconv1', 'layer3'], use_gpu=params.use_gpu, fparams=fparams, + pool_stride=[2, 1], normalize_power=2) + + params.features = MultiResolutionExtractor([features]) + + return params \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/__init__.py b/Stark/external/AR/pytracking/tracker/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/tracker/atom/__init__.py b/Stark/external/AR/pytracking/tracker/atom/__init__.py new file mode 100755 index 0000000..f0778c0 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/atom/__init__.py @@ -0,0 +1,4 @@ +from .atom import ATOM + +def get_tracker_class(): + return ATOM \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/atom/atom.py b/Stark/external/AR/pytracking/tracker/atom/atom.py new file mode 100755 index 0000000..ac18b0a --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/atom/atom.py @@ -0,0 +1,836 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import torch.nn +import math +import time +from pytracking import dcf, fourier, TensorList, operation +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor +from pytracking.libs.optimization import GaussNewtonCG, ConjugateGradient, GradientDescentL2 +from .optim import ConvProblem, FactorizedConvProblem +from pytracking.features import augmentation +import ltr.data.bounding_box_utils as bbutils + + +class ATOM(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.features.initialize() + self.features_initialized = True + + + def initialize(self, image, info: dict) -> dict: + state = info['init_bbox'] + + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize features + self.initialize_features() + + # Check if image is color + self.params.features.set_is_color(image.shape[2] == 3) + + # Get feature specific params + self.fparams = self.params.features.get_fparams('feature_params') + + tic = time.time() + + # Get position and size + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Set search area + self.target_scale = 1.0 + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + if search_area > self.params.max_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.max_image_sample_size) + elif search_area < self.params.min_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.min_image_sample_size) + + # Check if IoUNet is used + self.use_iou_net = self.params.get('use_iou_net', True) + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Use odd square search area and set sizes + feat_max_stride = max(self.params.features.stride()) + if self.params.get('search_area_shape', 'square') == 'square': + self.img_sample_sz = torch.round(torch.sqrt(torch.prod(self.base_target_sz * self.params.search_area_scale))) * torch.ones(2) + elif self.params.search_area_shape == 'initrect': + self.img_sample_sz = torch.round(self.base_target_sz * self.params.search_area_scale) + else: + raise ValueError('Unknown search area shape') + if self.params.feature_size_odd: + self.img_sample_sz += feat_max_stride - self.img_sample_sz % (2 * feat_max_stride) + else: + self.img_sample_sz += feat_max_stride - (self.img_sample_sz + feat_max_stride) % (2 * feat_max_stride) + + # Set sizes + self.img_support_sz = self.img_sample_sz + self.feature_sz = self.params.features.size(self.img_sample_sz) + self.output_sz = self.params.score_upsample_factor * self.img_support_sz # Interpolated size of the output + self.kernel_size = self.fparams.attribute('kernel_size') + + self.iou_img_sample_sz = self.img_sample_sz + + # Optimization options + self.params.precond_learning_rate = self.fparams.attribute('learning_rate') + if self.params.CG_forgetting_rate is None or max(self.params.precond_learning_rate) >= 1: + self.params.direction_forget_factor = 0 + else: + self.params.direction_forget_factor = (1 - max(self.params.precond_learning_rate))**self.params.CG_forgetting_rate + + self.output_window = None + if self.params.get('window_output', False): + if self.params.get('use_clipped_window', False): + self.output_window = dcf.hann2d_clipped(self.output_sz.long(), self.output_sz.long()*self.params.effective_search_area / self.params.search_area_scale, centered=False).to(self.params.device) + else: + self.output_window = dcf.hann2d(self.output_sz.long(), centered=False).to(self.params.device) + + # Initialize some learning things + self.init_learning() + + # Convert image + im = numpy_to_torch(image) + self.im = im # For debugging only + + # Setup scale bounds + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + x = self.generate_init_samples(im) + + # Initialize iounet + if self.use_iou_net: + self.init_iou_net() + + # Initialize projection matrix + self.init_projection_matrix(x) + + # Transform to get the training sample + train_x = self.preprocess_sample(x) + + # Generate label function + init_y = self.init_label_function(train_x) + + # Init memory + self.init_memory(train_x) + + # Init optimizer and do initial optimization + self.init_optimization(train_x, init_y) + + self.pos_iounet = self.pos.clone() + + out = {'time': time.time() - tic} + return out + + + def init_optimization(self, train_x, init_y): + # Initialize filter + filter_init_method = self.params.get('filter_init_method', 'zeros') + self.filter = TensorList( + [x.new_zeros(1, cdim, sz[0], sz[1]) for x, cdim, sz in zip(train_x, self.compressed_dim, self.kernel_size)]) + if filter_init_method == 'zeros': + pass + elif filter_init_method == 'randn': + for f in self.filter: + f.normal_(0, 1/f.numel()) + else: + raise ValueError('Unknown "filter_init_method"') + + # Get parameters + self.params.update_projection_matrix = self.params.get('update_projection_matrix', True) and self.params.use_projection_matrix + optimizer = self.params.get('optimizer', 'GaussNewtonCG') + + # Setup factorized joint optimization + if self.params.update_projection_matrix: + self.joint_problem = FactorizedConvProblem(self.init_training_samples, init_y, self.filter_reg, + self.fparams.attribute('projection_reg'), self.params, self.init_sample_weights, + self.projection_activation, self.response_activation) + + # Variable containing both filter and projection matrix + joint_var = self.filter.concat(self.projection_matrix) + + # Initialize optimizer + analyze_convergence = self.params.get('analyze_convergence', False) + if optimizer == 'GaussNewtonCG': + self.joint_optimizer = GaussNewtonCG(self.joint_problem, joint_var, debug=(self.params.debug >= 1), + plotting=(self.params.debug >= 3), analyze=analyze_convergence, + visdom=self.visdom) + elif optimizer == 'GradientDescentL2': + self.joint_optimizer = GradientDescentL2(self.joint_problem, joint_var, self.params.optimizer_step_length, self.params.optimizer_momentum, plotting=(self.params.debug >= 3), debug=(self.params.debug >= 1), + visdom=self.visdom) + + # Do joint optimization + if isinstance(self.params.init_CG_iter, (list, tuple)): + self.joint_optimizer.run(self.params.init_CG_iter) + else: + self.joint_optimizer.run(self.params.init_CG_iter // self.params.init_GN_iter, self.params.init_GN_iter) + + if analyze_convergence: + opt_name = 'CG' if self.params.get('CG_optimizer', True) else 'GD' + for val_name, values in zip(['loss', 'gradient'], [self.joint_optimizer.losses, self.joint_optimizer.gradient_mags]): + val_str = ' '.join(['{:.8e}'.format(v.item()) for v in values]) + file_name = '{}_{}.txt'.format(opt_name, val_name) + with open(file_name, 'a') as f: + f.write(val_str + '\n') + raise RuntimeError('Exiting') + + # Re-project samples with the new projection matrix + compressed_samples = self.project_sample(self.init_training_samples, self.projection_matrix) + for train_samp, init_samp in zip(self.training_samples, compressed_samples): + train_samp[:init_samp.shape[0],...] = init_samp + + self.hinge_mask = None + + # Initialize optimizer + self.conv_problem = ConvProblem(self.training_samples, self.y, self.filter_reg, self.sample_weights, self.response_activation) + + if optimizer == 'GaussNewtonCG': + self.filter_optimizer = ConjugateGradient(self.conv_problem, self.filter, fletcher_reeves=self.params.fletcher_reeves, + direction_forget_factor=self.params.direction_forget_factor, debug=(self.params.debug>=1), + plotting=(self.params.debug>=3), visdom=self.visdom) + elif optimizer == 'GradientDescentL2': + self.filter_optimizer = GradientDescentL2(self.conv_problem, self.filter, self.params.optimizer_step_length, + self.params.optimizer_momentum, debug=(self.params.debug >= 1), + plotting=(self.params.debug>=3), visdom=self.visdom) + + # Transfer losses from previous optimization + if self.params.update_projection_matrix: + self.filter_optimizer.residuals = self.joint_optimizer.residuals + self.filter_optimizer.losses = self.joint_optimizer.losses + + if not self.params.update_projection_matrix: + self.filter_optimizer.run(self.params.init_CG_iter) + + # Post optimization + self.filter_optimizer.run(self.params.post_init_CG_iter) + + # Free memory + del self.init_training_samples + if self.params.use_projection_matrix: + del self.joint_problem, self.joint_optimizer + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + self.im = im # For debugging only + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.pos.round() + sample_scales = self.target_scale * self.params.scale_factors + test_x = self.extract_processed_sample(im, self.pos, sample_scales, self.img_sample_sz) + + # Compute scores + scores_raw = self.apply_filter(test_x) + translation_vec, scale_ind, s, flag = self.localize_target(scores_raw) + + # Update position and scale + if flag != 'not_found': + if self.use_iou_net: + update_scale_flag = self.params.get('update_scale_when_uncertain', True) or flag != 'uncertain' + if self.params.get('use_classifier', True): + self.update_state(sample_pos + translation_vec) + self.refine_target_box(sample_pos, sample_scales[scale_ind], scale_ind, update_scale_flag) + elif self.params.get('use_classifier', True): + self.update_state(sample_pos + translation_vec, sample_scales[scale_ind]) + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + self.debug_info['max_score'] = max_score + self.debug_info['flag'] = flag + + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map') + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # ------- UPDATE ------- # + + # Check flags and set learning rate if hard negative + update_flag = flag not in ['not_found', 'uncertain'] + hard_negative = (flag == 'hard_negative') + learning_rate = self.params.hard_negative_learning_rate if hard_negative else None + + if update_flag: + # Get train sample + train_x = TensorList([x[scale_ind:scale_ind+1, ...] for x in test_x]) + + # Create label for sample + train_y = self.get_label_function(sample_pos, sample_scales[scale_ind]) + + # Update memory + self.update_memory(train_x, train_y, learning_rate) + + # Train filter + if hard_negative: + self.filter_optimizer.run(self.params.hard_negative_CG_iter) + elif (self.frame_num-1) % self.params.train_skipping == 0: + self.filter_optimizer.run(self.params.CG_iter) + + # Set the pos of the tracker to iounet pos + if self.use_iou_net and flag != 'not_found': + self.pos = self.pos_iounet.clone() + + # Return new state + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + out = {'target_bbox': new_state.tolist()} + return out + + + def apply_filter(self, sample_x: TensorList): + return operation.conv2d(sample_x, self.filter, mode='same') + + def localize_target(self, scores_raw): + # Weighted sum (if multiple features) with interpolation in fourier domain + weight = self.fparams.attribute('translation_weight', 1.0) + scores_raw = weight * scores_raw + sf_weighted = fourier.cfft2(scores_raw) / (scores_raw.size(2) * scores_raw.size(3)) + for i, (sz, ksz) in enumerate(zip(self.feature_sz, self.kernel_size)): + sf_weighted[i] = fourier.shift_fs(sf_weighted[i], math.pi * (1 - torch.Tensor([ksz[0]%2, ksz[1]%2]) / sz)) + + scores_fs = fourier.sum_fs(sf_weighted) + scores = fourier.sample_fs(scores_fs, self.output_sz) + + if self.output_window is not None and not self.params.get('perform_hn_without_windowing', False): + scores *= self.output_window + + if self.params.get('advanced_localization', False): + return self.localize_advanced(scores) + + # Get maximum + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp.float().cpu() + + # Convert to displacements in the base scale + disp = (max_disp + self.output_sz / 2) % self.output_sz - self.output_sz / 2 + + # Compute translation vector and scale change factor + translation_vec = disp[scale_ind, ...].view(-1) * (self.img_support_sz / self.output_sz) * self.target_scale + translation_vec *= self.params.scale_factors[scale_ind] + + # Shift the score output for visualization purposes + if self.params.debug >= 2: + sz = scores.shape[-2:] + scores = torch.cat([scores[...,sz[0]//2:,:], scores[...,:sz[0]//2,:]], -2) + scores = torch.cat([scores[...,:,sz[1]//2:], scores[...,:,:sz[1]//2]], -1) + + return translation_vec, scale_ind, scores, None + + def localize_advanced(self, scores): + """Dows the advanced localization with hard negative detection and target not found.""" + + sz = scores.shape[-2:] + + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores_orig = scores.clone() + + scores_orig = torch.cat([scores_orig[..., (sz[0] + 1) // 2:, :], scores_orig[..., :(sz[0] + 1) // 2, :]], -2) + scores_orig = torch.cat([scores_orig[..., :, (sz[1] + 1) // 2:], scores_orig[..., :, :(sz[1] + 1) // 2]], -1) + + scores *= self.output_window + + # Shift scores back + scores = torch.cat([scores[...,(sz[0]+1)//2:,:], scores[...,:(sz[0]+1)//2,:]], -2) + scores = torch.cat([scores[...,:,(sz[1]+1)//2:], scores[...,:,:(sz[1]+1)//2]], -1) + + # Find maximum + max_score1, max_disp1 = dcf.max2d(scores) + _, scale_ind = torch.max(max_score1, dim=0) + max_score1 = max_score1[scale_ind] + max_disp1 = max_disp1[scale_ind,...].float().cpu().view(-1) + target_disp1 = max_disp1 - self.output_sz // 2 + translation_vec1 = target_disp1 * (self.img_support_sz / self.output_sz) * self.target_scale + + if max_score1.item() < self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores, 'not_found' + + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores = scores_orig + + # Mask out target neighborhood + target_neigh_sz = self.params.target_neighborhood_scale * self.target_sz / self.target_scale + tneigh_top = max(round(max_disp1[0].item() - target_neigh_sz[0].item() / 2), 0) + tneigh_bottom = min(round(max_disp1[0].item() + target_neigh_sz[0].item() / 2 + 1), sz[0]) + tneigh_left = max(round(max_disp1[1].item() - target_neigh_sz[1].item() / 2), 0) + tneigh_right = min(round(max_disp1[1].item() + target_neigh_sz[1].item() / 2 + 1), sz[1]) + scores_masked = scores[scale_ind:scale_ind+1,...].clone() + scores_masked[...,tneigh_top:tneigh_bottom,tneigh_left:tneigh_right] = 0 + + # Find new maximum + max_score2, max_disp2 = dcf.max2d(scores_masked) + max_disp2 = max_disp2.float().cpu().view(-1) + target_disp2 = max_disp2 - self.output_sz // 2 + translation_vec2 = target_disp2 * (self.img_support_sz / self.output_sz) * self.target_scale + + # Handle the different cases + if max_score2 > self.params.distractor_threshold * max_score1: + disp_norm1 = torch.sqrt(torch.sum(target_disp1**2)) + disp_norm2 = torch.sqrt(torch.sum(target_disp2**2)) + disp_threshold = self.params.dispalcement_scale * math.sqrt(sz[0] * sz[1]) / 2 + + if disp_norm2 > disp_threshold and disp_norm1 < disp_threshold: + return translation_vec1, scale_ind, scores, 'hard_negative' + if disp_norm2 < disp_threshold and disp_norm1 > disp_threshold: + return translation_vec2, scale_ind, scores, 'hard_negative' + if disp_norm2 > disp_threshold and disp_norm1 > disp_threshold: + return translation_vec1, scale_ind, scores, 'uncertain' + + # If also the distractor is close, return with highest score + return translation_vec1, scale_ind, scores, 'uncertain' + + if max_score2 > self.params.hard_negative_threshold * max_score1 and max_score2 > self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores, 'hard_negative' + + return translation_vec1, scale_ind, scores, None + + + def extract_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + return self.params.features.extract(im, pos, scales, sz)[0] + + def get_iou_features(self): + return self.params.features.get_unique_attribute('iounet_features') + + def get_iou_backbone_features(self): + return self.params.features.get_unique_attribute('iounet_backbone_features') + + def extract_processed_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor) -> (TensorList, TensorList): + x = self.extract_sample(im, pos, scales, sz) + return self.preprocess_sample(self.project_sample(x)) + + def preprocess_sample(self, x: TensorList) -> (TensorList, TensorList): + if self.params.get('_feature_window', False): + x = x * self.feature_window + return x + + def project_sample(self, x: TensorList, proj_matrix = None): + # Apply projection matrix + if proj_matrix is None: + proj_matrix = self.projection_matrix + return operation.conv2d(x, proj_matrix).apply(self.projection_activation) + + def init_learning(self): + # Get window function + self.feature_window = TensorList([dcf.hann2d(sz).to(self.params.device) for sz in self.feature_sz]) + + # Filter regularization + self.filter_reg = self.fparams.attribute('filter_reg') + + # Activation function after the projection matrix (phi_1 in the paper) + projection_activation = self.params.get('projection_activation', 'none') + if isinstance(projection_activation, tuple): + projection_activation, act_param = projection_activation + + if projection_activation == 'none': + self.projection_activation = lambda x: x + elif projection_activation == 'relu': + self.projection_activation = torch.nn.ReLU(inplace=True) + elif projection_activation == 'elu': + self.projection_activation = torch.nn.ELU(inplace=True) + elif projection_activation == 'mlu': + self.projection_activation = lambda x: F.elu(F.leaky_relu(x, 1 / act_param), act_param) + else: + raise ValueError('Unknown activation') + + # Activation function after the output scores (phi_2 in the paper) + response_activation = self.params.get('response_activation', 'none') + if isinstance(response_activation, tuple): + response_activation, act_param = response_activation + + if response_activation == 'none': + self.response_activation = lambda x: x + elif response_activation == 'relu': + self.response_activation = torch.nn.ReLU(inplace=True) + elif response_activation == 'elu': + self.response_activation = torch.nn.ELU(inplace=True) + elif response_activation == 'mlu': + self.response_activation = lambda x: F.elu(F.leaky_relu(x, 1 / act_param), act_param) + else: + raise ValueError('Unknown activation') + + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + """Generate augmented initial samples.""" + + # Compute augmentation size + aug_expansion_factor = self.params.get('augmentation_expansion_factor', None) + aug_expansion_sz = self.img_sample_sz.clone() + aug_output_sz = None + if aug_expansion_factor is not None and aug_expansion_factor != 1: + aug_expansion_sz = (self.img_sample_sz * aug_expansion_factor).long() + aug_expansion_sz += (aug_expansion_sz - self.img_sample_sz.long()) % 2 + aug_expansion_sz = aug_expansion_sz.float() + aug_output_sz = self.img_sample_sz.long().tolist() + + # Random shift operator + get_rand_shift = lambda: None + random_shift_factor = self.params.get('random_shift_factor', 0) + if random_shift_factor > 0: + get_rand_shift = lambda: ((torch.rand(2) - 0.5) * self.img_sample_sz * random_shift_factor).long().tolist() + + # Create transofmations + self.transforms = [augmentation.Identity(aug_output_sz)] + if 'shift' in self.params.augmentation: + self.transforms.extend([augmentation.Translation(shift, aug_output_sz) for shift in self.params.augmentation['shift']]) + if 'relativeshift' in self.params.augmentation: + get_absolute = lambda shift: (torch.Tensor(shift) * self.img_sample_sz/2).long().tolist() + self.transforms.extend([augmentation.Translation(get_absolute(shift), aug_output_sz) for shift in self.params.augmentation['relativeshift']]) + if 'fliplr' in self.params.augmentation and self.params.augmentation['fliplr']: + self.transforms.append(augmentation.FlipHorizontal(aug_output_sz, get_rand_shift())) + if 'blur' in self.params.augmentation: + self.transforms.extend([augmentation.Blur(sigma, aug_output_sz, get_rand_shift()) for sigma in self.params.augmentation['blur']]) + if 'scale' in self.params.augmentation: + self.transforms.extend([augmentation.Scale(scale_factor, aug_output_sz, get_rand_shift()) for scale_factor in self.params.augmentation['scale']]) + if 'rotate' in self.params.augmentation: + self.transforms.extend([augmentation.Rotate(angle, aug_output_sz, get_rand_shift()) for angle in self.params.augmentation['rotate']]) + + # Generate initial samples + init_samples = self.params.features.extract_transformed(im, self.pos, self.target_scale, aug_expansion_sz, self.transforms) + + # Remove augmented samples for those that shall not have + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if not use_aug: + init_samples[i] = init_samples[i][0:1, ...] + + # Add dropout samples + if 'dropout' in self.params.augmentation: + num, prob = self.params.augmentation['dropout'] + self.transforms.extend(self.transforms[:1]*num) + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if use_aug: + init_samples[i] = torch.cat([init_samples[i], F.dropout2d(init_samples[i][0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + return init_samples + + + def init_projection_matrix(self, x): + # Set if using projection matrix + self.params.use_projection_matrix = self.params.get('use_projection_matrix', True) + + if self.params.use_projection_matrix: + self.compressed_dim = self.fparams.attribute('compressed_dim', None) + + proj_init_method = self.params.get('proj_init_method', 'pca') + if proj_init_method == 'pca': + x_mat = TensorList([e.permute(1, 0, 2, 3).reshape(e.shape[1], -1).clone() for e in x]) + x_mat -= x_mat.mean(dim=1, keepdim=True) + cov_x = x_mat @ x_mat.t() + self.projection_matrix = TensorList( + [None if cdim is None else torch.svd(C)[0][:, :cdim].t().unsqueeze(-1).unsqueeze(-1).clone() for C, cdim in + zip(cov_x, self.compressed_dim)]) + elif proj_init_method == 'randn': + self.projection_matrix = TensorList( + [None if cdim is None else ex.new_zeros(cdim,ex.shape[1],1,1).normal_(0,1/math.sqrt(ex.shape[1])) for ex, cdim in + zip(x, self.compressed_dim)]) + else: + self.compressed_dim = x.size(1) + self.projection_matrix = TensorList([None]*len(x)) + + def init_label_function(self, train_x): + # Allocate label function + self.y = TensorList([x.new_zeros(self.params.sample_memory_size, 1, x.shape[2], x.shape[3]) for x in train_x]) + + # Output sigma factor + output_sigma_factor = self.fparams.attribute('output_sigma_factor') + self.sigma = (self.feature_sz / self.img_support_sz * self.base_target_sz).prod().sqrt() * output_sigma_factor * torch.ones(2) + + # Center pos in normalized coords + target_center_norm = (self.pos - self.pos.round()) / (self.target_scale * self.img_support_sz) + + # Generate label functions + for y, sig, sz, ksz, x in zip(self.y, self.sigma, self.feature_sz, self.kernel_size, train_x): + center_pos = sz * target_center_norm + 0.5 * torch.Tensor([(ksz[0] + 1) % 2, (ksz[1] + 1) % 2]) + for i, T in enumerate(self.transforms[:x.shape[0]]): + sample_center = center_pos + torch.Tensor(T.shift) / self.img_support_sz * sz + y[i, 0, ...] = dcf.label_function_spatial(sz, sig, sample_center) + + # Return only the ones to use for initial training + return TensorList([y[:x.shape[0], ...] for y, x in zip(self.y, train_x)]) + + + def init_memory(self, train_x): + # Initialize first-frame training samples + self.num_init_samples = train_x.size(0) + self.init_sample_weights = TensorList([x.new_ones(1) / x.shape[0] for x in train_x]) + self.init_training_samples = train_x + + # Sample counters and weights + self.num_stored_samples = self.num_init_samples.copy() + self.previous_replace_ind = [None] * len(self.num_stored_samples) + self.sample_weights = TensorList([x.new_zeros(self.params.sample_memory_size) for x in train_x]) + for sw, init_sw, num in zip(self.sample_weights, self.init_sample_weights, self.num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [x.new_zeros(self.params.sample_memory_size, cdim, x.shape[2], x.shape[3]) for x, cdim in + zip(train_x, self.compressed_dim)]) + + def update_memory(self, sample_x: TensorList, sample_y: TensorList, learning_rate = None): + replace_ind = self.update_sample_weights(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.num_init_samples, self.fparams, learning_rate) + self.previous_replace_ind = replace_ind + for train_samp, x, ind in zip(self.training_samples, sample_x, replace_ind): + train_samp[ind:ind+1,...] = x + for y_memory, y, ind in zip(self.y, sample_y, replace_ind): + y_memory[ind:ind+1,...] = y + if self.hinge_mask is not None: + for m, y, ind in zip(self.hinge_mask, sample_y, replace_ind): + m[ind:ind+1,...] = (y >= self.params.hinge_threshold).float() + self.num_stored_samples += 1 + + + def update_sample_weights(self, sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, fparams, learning_rate = None): + # Update weights and get index to replace in memory + replace_ind = [] + for sw, prev_ind, num_samp, num_init, fpar in zip(sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, fparams): + lr = learning_rate + if lr is None: + lr = fpar.learning_rate + + init_samp_weight = getattr(fpar, 'init_samples_minimum_weight', None) + if init_samp_weight == 0: + init_samp_weight = None + s_ind = 0 if init_samp_weight is None else num_init + + if num_samp == 0 or lr == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + _, r_ind = torch.min(sw[s_ind:], 0) + r_ind = r_ind.item() + s_ind + + # Update weights + if prev_ind is None: + sw /= 1 - lr + sw[r_ind] = lr + else: + sw[r_ind] = sw[prev_ind] / (1 - lr) + + sw /= sw.sum() + if init_samp_weight is not None and sw[:num_init].sum() < init_samp_weight: + sw /= init_samp_weight + sw[num_init:].sum() + sw[:num_init] = init_samp_weight / num_init + + replace_ind.append(r_ind) + + return replace_ind + + def get_label_function(self, sample_pos, sample_scale): + # Generate label function + train_y = TensorList() + target_center_norm = (self.pos - sample_pos) / (sample_scale * self.img_support_sz) + for sig, sz, ksz in zip(self.sigma, self.feature_sz, self.kernel_size): + center = sz * target_center_norm + 0.5 * torch.Tensor([(ksz[0] + 1) % 2, (ksz[1] + 1) % 2]) + train_y.append(dcf.label_function_spatial(sz, sig, center)) + return train_y + + def update_state(self, new_pos, new_scale = None): + # Update scale + if new_scale is not None: + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = 0.2 + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + def get_iounet_box(self, pos, sz, sample_pos, sample_scale): + """All inputs in original image coordinates""" + box_center = (pos - sample_pos) / sample_scale + (self.iou_img_sample_sz - 1) / 2 + box_sz = sz / sample_scale + target_ul = box_center - (box_sz - 1) / 2 + return torch.cat([target_ul.flip((0,)), box_sz.flip((0,))]) + + def init_iou_net(self): + # Setup IoU net + self.iou_predictor = self.params.features.get_unique_attribute('iou_predictor') + for p in self.iou_predictor.parameters(): + p.requires_grad = False + + # Get target boxes for the different augmentations + self.iou_target_box = self.get_iounet_box(self.pos, self.target_sz, self.pos.round(), self.target_scale) + target_boxes = TensorList() + if self.params.iounet_augmentation: + for T in self.transforms: + if not isinstance(T, (augmentation.Identity, augmentation.Translation, augmentation.FlipHorizontal, augmentation.FlipVertical, augmentation.Blur)): + break + target_boxes.append(self.iou_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + else: + target_boxes.append(self.iou_target_box.clone()) + target_boxes = torch.cat(target_boxes.view(1,4), 0).to(self.params.device) + + # Get iou features + iou_backbone_features = self.get_iou_backbone_features() + + # Remove other augmentations such as rotation + iou_backbone_features = TensorList([x[:target_boxes.shape[0],...] for x in iou_backbone_features]) + + # Extract target feat + with torch.no_grad(): + target_feat = self.iou_predictor.get_modulation(iou_backbone_features, target_boxes) + self.target_feat = TensorList([x.detach().mean(0) for x in target_feat]) + + if self.params.get('iounet_not_use_reference', False): + self.target_feat = TensorList([torch.full_like(tf, tf.norm() / tf.numel()) for tf in self.target_feat]) + + + def refine_target_box(self, sample_pos, sample_scale, scale_ind, update_scale = True): + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features() + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + init_boxes = init_box.view(1,4).clone() + if self.params.num_init_random_boxes > 0: + # Get random initial boxes + square_box_sz = init_box[2:].prod().sqrt() + rand_factor = square_box_sz * torch.cat([self.params.box_jitter_pos * torch.ones(2), self.params.box_jitter_sz * torch.ones(2)]) + minimal_edge_size = init_box[2:].min()/3 + rand_bb = (torch.rand(self.params.num_init_random_boxes, 4) - 0.5) * rand_factor + new_sz = (init_box[2:] + rand_bb[:,2:]).clamp(minimal_edge_size) + new_center = (init_box[:2] + init_box[2:]/2) + rand_bb[:,:2] + init_boxes = torch.cat([new_center - new_sz/2, new_sz], 1) + init_boxes = torch.cat([init_box.view(1,4), init_boxes]) + + # Refine boxes by maximizing iou + output_boxes, output_iou = self.optimize_boxes(iou_features, init_boxes) + + # Remove weird boxes with extreme aspect ratios + output_boxes[:, 2:].clamp_(1) + aspect_ratio = output_boxes[:,2] / output_boxes[:,3] + keep_ind = (aspect_ratio < self.params.maximal_aspect_ratio) * (aspect_ratio > 1/self.params.maximal_aspect_ratio) + output_boxes = output_boxes[keep_ind,:] + output_iou = output_iou[keep_ind] + + # If no box found + if output_boxes.shape[0] == 0: + return + + # Take average of top k boxes + k = self.params.get('iounet_k', 5) + topk = min(k, output_boxes.shape[0]) + _, inds = torch.topk(output_iou, topk) + predicted_box = output_boxes[inds, :].mean(0) + predicted_iou = output_iou.view(-1, 1)[inds, :].mean(0) + + # Update position + new_pos = predicted_box[:2] + predicted_box[2:]/2 - (self.iou_img_sample_sz - 1) / 2 + new_pos = new_pos.flip((0,)) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + def optimize_boxes(self, iou_features, init_boxes): + # Optimize iounet boxes + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + init_step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + init_step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]]).to( + self.params.device).view(1, 1, 4) + box_refinement_space = self.params.get('box_refinement_space', 'default') + + step_length = init_step_length * output_boxes.new_ones(1, output_boxes.shape[1], 1) + outputs_prev = -99999999 * output_boxes.new_ones(1, output_boxes.shape[1]) + step = torch.zeros_like(output_boxes) + + if box_refinement_space == 'default': + # Optimization using bounding box space used in original IoUNet + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init = output_boxes.clone().detach() + bb_init.requires_grad = True + + outputs = self.iou_predictor.predict_iou(self.target_feat, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient=torch.ones_like(outputs)) + + # Update mask and step length + update_mask = (outputs.detach() > outputs_prev) | (self.params.box_refinement_step_decay >= 1) + update_mask_float = update_mask.view(1, -1, 1).float() + step_length[~update_mask, :] *= self.params.box_refinement_step_decay + outputs_prev = outputs.detach().clone() + + # Update proposal + step = update_mask_float * step_length * bb_init.grad * bb_init[:, :, 2:].repeat(1, 1, 2) - ( + 1.0 - update_mask_float) * step + output_boxes = bb_init + step + output_boxes.detach_() + + elif box_refinement_space == 'relative': + # Optimization using relative bounding box space + sz_norm = output_boxes[:, :1, 2:].clone() + output_boxes_rel = bbutils.rect_to_rel(output_boxes, sz_norm) + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init_rel = output_boxes_rel.clone().detach() + bb_init_rel.requires_grad = True + + bb_init = bbutils.rel_to_rect(bb_init_rel, sz_norm) + outputs = self.iou_predictor.predict_iou(self.target_feat, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient=torch.ones_like(outputs)) + + # Update mask and step length + update_mask = (outputs.detach() > outputs_prev) | (self.params.box_refinement_step_decay >= 1) + update_mask_float = update_mask.view(1, -1, 1).float() + step_length[~update_mask, :] *= self.params.box_refinement_step_decay + outputs_prev = outputs.detach().clone() + + # Update proposal + step = update_mask_float * step_length * bb_init_rel.grad - (1.0 - update_mask_float) * step + output_boxes_rel = bb_init_rel + step + output_boxes_rel.detach_() + + # for s in outputs.view(-1): + # print('{:.2f} '.format(s.item()), end='') + # print('') + # print('') + + output_boxes = bbutils.rel_to_rect(output_boxes_rel, sz_norm) + + else: + raise ValueError('Unknown box_refinement_space {}'.format(box_refinement_space)) + + return output_boxes.view(-1, 4).cpu(), outputs.detach().view(-1).cpu() diff --git a/Stark/external/AR/pytracking/tracker/atom/optim.py b/Stark/external/AR/pytracking/tracker/atom/optim.py new file mode 100755 index 0000000..2f4b989 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/atom/optim.py @@ -0,0 +1,99 @@ +import torch +from pytracking import optimization, TensorList, operation +import math + + +class FactorizedConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, y:TensorList, filter_reg: torch.Tensor, projection_reg, params, sample_weights: TensorList, + projection_activation, response_activation): + self.training_samples = training_samples + self.y = y + self.filter_reg = filter_reg + self.sample_weights = sample_weights + self.params = params + self.projection_reg = projection_reg + self.projection_activation = projection_activation + self.response_activation = response_activation + + self.diag_M = self.filter_reg.concat(projection_reg) + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters, projection_matrices] + :return: [data_terms, filter_regularizations, proj_mat_regularizations] + """ + filter = x[:len(x)//2] # w2 in paper + P = x[len(x)//2:] # w1 in paper + + # Do first convolution + compressed_samples = operation.conv1x1(self.training_samples, P).apply(self.projection_activation) + + # Do second convolution + residuals = operation.conv2d(compressed_samples, filter, mode='same').apply(self.response_activation) + + # Compute data residuals + residuals = residuals - self.y + + residuals = self.sample_weights.sqrt().view(-1, 1, 1, 1) * residuals + + # Add regularization for projection matrix + residuals.extend(self.filter_reg.apply(math.sqrt) * filter) + + # Add regularization for projection matrix + residuals.extend(self.projection_reg.apply(math.sqrt) * P) + + return residuals + + + def ip_input(self, a: TensorList, b: TensorList): + num = len(a) // 2 # Number of filters + a_filter = a[:num] + b_filter = b[:num] + a_P = a[num:] + b_P = b[num:] + + # Filter inner product + # ip_out = a_filter.reshape(-1) @ b_filter.reshape(-1) + ip_out = operation.conv2d(a_filter, b_filter).view(-1) + + # Add projection matrix part + # ip_out += a_P.reshape(-1) @ b_P.reshape(-1) + ip_out += operation.conv2d(a_P.view(1,-1,1,1), b_P.view(1,-1,1,1)).view(-1) + + # Have independent inner products for each filter + return ip_out.concat(ip_out.clone()) + + def M1(self, x: TensorList): + return x / self.diag_M + + +class ConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, y:TensorList, filter_reg: torch.Tensor, sample_weights: TensorList, response_activation): + self.training_samples = training_samples + self.y = y + self.filter_reg = filter_reg + self.sample_weights = sample_weights + self.response_activation = response_activation + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters] + :return: [data_terms, filter_regularizations] + """ + # Do convolution and compute residuals + residuals = operation.conv2d(self.training_samples, x, mode='same').apply(self.response_activation) + residuals = residuals - self.y + + residuals = self.sample_weights.sqrt().view(-1, 1, 1, 1) * residuals + + # Add regularization for projection matrix + residuals.extend(self.filter_reg.apply(math.sqrt) * x) + + return residuals + + def ip_input(self, a: TensorList, b: TensorList): + # return a.reshape(-1) @ b.reshape(-1) + # return (a * b).sum() + return operation.conv2d(a, b).view(-1) diff --git a/Stark/external/AR/pytracking/tracker/base/__init__.py b/Stark/external/AR/pytracking/tracker/base/__init__.py new file mode 100755 index 0000000..945e713 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/base/__init__.py @@ -0,0 +1 @@ +from .basetracker import BaseTracker \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/base/basetracker.py b/Stark/external/AR/pytracking/tracker/base/basetracker.py new file mode 100755 index 0000000..a485691 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/base/basetracker.py @@ -0,0 +1,29 @@ +from _collections import OrderedDict + +class BaseTracker: + """Base class for all trackers.""" + + def __init__(self, params): + self.params = params + self.visdom = None + + + def initialize(self, image, info: dict) -> dict: + """Overload this function in your tracker. This should initialize the model.""" + raise NotImplementedError + + + def track(self, image, info: dict = None) -> dict: + """Overload this function in your tracker. This should track in the frame and update the model.""" + raise NotImplementedError + + + def visdom_draw_tracking(self, image, box, segmentation=None): + if isinstance(box, OrderedDict): + box = [v for k, v in box.items()] + else: + box = (box,) + if segmentation is None: + self.visdom.register((image, *box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, *box, segmentation), 'Tracking', 1, 'Tracking') \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/dimp/__init__.py b/Stark/external/AR/pytracking/tracker/dimp/__init__.py new file mode 100755 index 0000000..d605970 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/dimp/__init__.py @@ -0,0 +1,4 @@ +from .dimp import DiMP + +def get_tracker_class(): + return DiMP \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/dimp/dimp.py b/Stark/external/AR/pytracking/tracker/dimp/dimp.py new file mode 100755 index 0000000..d2c666b --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/dimp/dimp.py @@ -0,0 +1,866 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import math +import time +from pytracking import dcf, TensorList +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor, plot_graph +from pytracking.features.preprocessing import sample_patch_multiscale, sample_patch_transformed +from pytracking.features import augmentation +import ltr.data.bounding_box_utils as bbutils +from ltr.models.target_classifier.initializer import FilterInitializerZero +from ltr.models.layers import activation + + +class DiMP(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.net.initialize() + self.features_initialized = True + + def initialize(self, image, info: dict) -> dict: + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize network + self.initialize_features() + + # The DiMP network + self.net = self.params.net + + # Time initialization + tic = time.time() + + # Convert image + im = numpy_to_torch(image) + + # Get target position and size + state = info['init_bbox'] + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Get object id + self.object_id = info.get('object_ids', [None])[0] + self.id_str = '' if self.object_id is None else ' {}'.format(self.object_id) + + # Set sizes + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + sz = self.params.image_sample_size + sz = torch.Tensor([sz, sz] if isinstance(sz, int) else sz) + if self.params.get('use_image_aspect_ratio', False): + sz = self.image_sz * sz.prod().sqrt() / self.image_sz.prod().sqrt() + stride = self.params.get('feature_stride', 32) + sz = torch.round(sz / stride) * stride + self.img_sample_sz = sz + self.img_support_sz = self.img_sample_sz + + # Set search area + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + self.target_scale = math.sqrt(search_area) / self.img_sample_sz.prod().sqrt() + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Setup scale factors + if not self.params.has('scale_factors'): + self.params.scale_factors = torch.ones(1) + elif isinstance(self.params.scale_factors, (list, tuple)): + self.params.scale_factors = torch.Tensor(self.params.scale_factors) + + # Setup scale bounds + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + init_backbone_feat = self.generate_init_samples(im) + + # Initialize classifier + self.init_classifier(init_backbone_feat) + + # Initialize IoUNet + if self.params.get('use_iou_net', True): + self.init_iou_net(init_backbone_feat) + + out = {'time': time.time() - tic} + return out + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + + # ------- LOCALIZATION ------- # + + # Extract backbone features + backbone_feat, sample_coords, im_patches = self.extract_backbone_features(im, self.get_centered_sample_pos(), + self.target_scale * self.params.scale_factors, + self.img_sample_sz) + # Extract classification features + test_x = self.get_classification_features(backbone_feat) + + # Location of sample + sample_pos, sample_scales = self.get_sample_location(sample_coords) + + # Compute classification scores + scores_raw = self.classify_target(test_x) + + # Localize the target + translation_vec, scale_ind, s, flag = self.localize_target(scores_raw, sample_pos, sample_scales) + new_pos = sample_pos[scale_ind,:] + translation_vec + + # Update position and scale + if flag != 'not_found': + if self.params.get('use_iou_net', True): + update_scale_flag = self.params.get('update_scale_when_uncertain', True) or flag != 'uncertain' + if self.params.get('use_classifier', True): + self.update_state(new_pos) + self.refine_target_box(backbone_feat, sample_pos[scale_ind,:], sample_scales[scale_ind], scale_ind, update_scale_flag) + elif self.params.get('use_classifier', True): + self.update_state(new_pos, sample_scales[scale_ind]) + + + # ------- UPDATE ------- # + + update_flag = flag not in ['not_found', 'uncertain'] + hard_negative = (flag == 'hard_negative') + learning_rate = self.params.get('hard_negative_learning_rate', None) if hard_negative else None + + if update_flag and self.params.get('update_classifier', False): + # Get train sample + train_x = test_x[scale_ind:scale_ind+1, ...] + + # Create target_box and label for spatial sample + target_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos[scale_ind,:], sample_scales[scale_ind]) + + # Update the classifier model + self.update_classifier(train_x, target_box, learning_rate, s[scale_ind,...]) + + # Set the pos of the tracker to iounet pos + if self.params.get('use_iou_net', True) and flag != 'not_found' and hasattr(self, 'pos_iounet'): + self.pos = self.pos_iounet.clone() + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + + # Visualize and set debug info + self.search_area_box = torch.cat((sample_coords[scale_ind,[1,0]], sample_coords[scale_ind,[3,2]] - sample_coords[scale_ind,[1,0]] - 1)) + self.debug_info['flag' + self.id_str] = flag + self.debug_info['max_score' + self.id_str] = max_score + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map' + self.id_str) + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # Compute output bounding box + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + if self.params.get('output_not_found_box', False) and flag == 'not_found': + output_state = [-1, -1, -1, -1] + else: + output_state = new_state.tolist() + '''2020.4.26 ''' + out = {'target_bbox': output_state, + 'dcf_center':new_pos[[1,0]]} + return out + + + def get_sample_location(self, sample_coord): + """Get the location of the extracted sample.""" + sample_coord = sample_coord.float() + sample_pos = 0.5*(sample_coord[:,:2] + sample_coord[:,2:] - 1) + sample_scales = ((sample_coord[:,2:] - sample_coord[:,:2]) / self.img_sample_sz).prod(dim=1).sqrt() + return sample_pos, sample_scales + + def get_centered_sample_pos(self): + """Get the center position for the new sample. Make sure the target is correctly centered.""" + return self.pos + ((self.feature_sz + self.kernel_size) % 2) * self.target_scale * \ + self.img_support_sz / (2*self.feature_sz) + + def classify_target(self, sample_x: TensorList): + """Classify target by applying the DiMP filter.""" + with torch.no_grad(): + scores = self.net.classifier.classify(self.target_filter, sample_x) + return scores + + def localize_target(self, scores, sample_pos, sample_scales): + """Run the target localization.""" + + scores = scores.squeeze(1) + + preprocess_method = self.params.get('score_preprocess', 'none') + if preprocess_method == 'none': + pass + elif preprocess_method == 'exp': + scores = scores.exp() + elif preprocess_method == 'softmax': + reg_val = getattr(self.net.classifier.filter_optimizer, 'softmax_reg', None) + scores_view = scores.view(scores.shape[0], -1) + scores_softmax = activation.softmax_reg(scores_view, dim=-1, reg=reg_val) + scores = scores_softmax.view(scores.shape) + else: + raise Exception('Unknown score_preprocess in params.') + + score_filter_ksz = self.params.get('score_filter_ksz', 1) + if score_filter_ksz > 1: + assert score_filter_ksz % 2 == 1 + kernel = scores.new_ones(1,1,score_filter_ksz,score_filter_ksz) + scores = F.conv2d(scores.view(-1,1,*scores.shape[-2:]), kernel, padding=score_filter_ksz//2).view(scores.shape) + + if self.params.get('advanced_localization', False): + return self.localize_advanced(scores, sample_pos, sample_scales) + + # Get maximum + score_sz = torch.Tensor(list(scores.shape[-2:])) + score_center = (score_sz - 1)/2 + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp[scale_ind,...].float().cpu().view(-1) + target_disp = max_disp - score_center + + # Compute translation vector and scale change factor + output_sz = score_sz - (self.kernel_size + 1) % 2 + translation_vec = target_disp * (self.img_support_sz / output_sz) * sample_scales[scale_ind] + + return translation_vec, scale_ind, scores, None + + + def localize_advanced(self, scores, sample_pos, sample_scales): + """Run the target advanced localization (as in ATOM).""" + + sz = scores.shape[-2:] + score_sz = torch.Tensor(list(sz)) + output_sz = score_sz - (self.kernel_size + 1) % 2 + score_center = (score_sz - 1)/2 + + scores_hn = scores + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores_hn = scores.clone() + scores *= self.output_window + + max_score1, max_disp1 = dcf.max2d(scores) + _, scale_ind = torch.max(max_score1, dim=0) + sample_scale = sample_scales[scale_ind] + max_score1 = max_score1[scale_ind] + max_disp1 = max_disp1[scale_ind,...].float().cpu().view(-1) + target_disp1 = max_disp1 - score_center + translation_vec1 = target_disp1 * (self.img_support_sz / output_sz) * sample_scale + + if max_score1.item() < self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores_hn, 'not_found' + if max_score1.item() < self.params.get('uncertain_threshold', -float('inf')): + return translation_vec1, scale_ind, scores_hn, 'uncertain' + if max_score1.item() < self.params.get('hard_sample_threshold', -float('inf')): + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + + # Mask out target neighborhood + target_neigh_sz = self.params.target_neighborhood_scale * (self.target_sz / sample_scale) * (output_sz / self.img_support_sz) + + tneigh_top = max(round(max_disp1[0].item() - target_neigh_sz[0].item() / 2), 0) + tneigh_bottom = min(round(max_disp1[0].item() + target_neigh_sz[0].item() / 2 + 1), sz[0]) + tneigh_left = max(round(max_disp1[1].item() - target_neigh_sz[1].item() / 2), 0) + tneigh_right = min(round(max_disp1[1].item() + target_neigh_sz[1].item() / 2 + 1), sz[1]) + scores_masked = scores_hn[scale_ind:scale_ind + 1, ...].clone() + scores_masked[...,tneigh_top:tneigh_bottom,tneigh_left:tneigh_right] = 0 + + # Find new maximum + max_score2, max_disp2 = dcf.max2d(scores_masked) + max_disp2 = max_disp2.float().cpu().view(-1) + target_disp2 = max_disp2 - score_center + translation_vec2 = target_disp2 * (self.img_support_sz / output_sz) * sample_scale + + prev_target_vec = (self.pos - sample_pos[scale_ind,:]) / ((self.img_support_sz / output_sz) * sample_scale) + + # Handle the different cases + if max_score2 > self.params.distractor_threshold * max_score1: + disp_norm1 = torch.sqrt(torch.sum((target_disp1-prev_target_vec)**2)) + disp_norm2 = torch.sqrt(torch.sum((target_disp2-prev_target_vec)**2)) + disp_threshold = self.params.dispalcement_scale * math.sqrt(sz[0] * sz[1]) / 2 + + if disp_norm2 > disp_threshold and disp_norm1 < disp_threshold: + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + if disp_norm2 < disp_threshold and disp_norm1 > disp_threshold: + return translation_vec2, scale_ind, scores_hn, 'hard_negative' + if disp_norm2 > disp_threshold and disp_norm1 > disp_threshold: + return translation_vec1, scale_ind, scores_hn, 'uncertain' + + # If also the distractor is close, return with highest score + return translation_vec1, scale_ind, scores_hn, 'uncertain' + + if max_score2 > self.params.hard_negative_threshold * max_score1 and max_score2 > self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + + return translation_vec1, scale_ind, scores_hn, 'normal' + + def extract_backbone_features(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + im_patches, patch_coords = sample_patch_multiscale(im, pos, scales, sz, + mode=self.params.get('border_mode', 'replicate'), + max_scale_change=self.params.get('patch_max_scale_change', None)) + with torch.no_grad(): + backbone_feat = self.net.extract_backbone(im_patches) + return backbone_feat, patch_coords, im_patches + + def get_classification_features(self, backbone_feat): + with torch.no_grad(): + return self.net.extract_classification_feat(backbone_feat) + + def get_iou_backbone_features(self, backbone_feat): + return self.net.get_backbone_bbreg_feat(backbone_feat) + + def get_iou_features(self, backbone_feat): + with torch.no_grad(): + return self.net.bb_regressor.get_iou_feat(self.get_iou_backbone_features(backbone_feat)) + + def get_iou_modulation(self, iou_backbone_feat, target_boxes): + with torch.no_grad(): + return self.net.bb_regressor.get_modulation(iou_backbone_feat, target_boxes) + + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + """Perform data augmentation to generate initial training samples.""" + + mode = self.params.get('border_mode', 'replicate') + if mode == 'inside': + # Get new sample size if forced inside the image + im_sz = torch.Tensor([im.shape[2], im.shape[3]]) + sample_sz = self.target_scale * self.img_sample_sz + shrink_factor = (sample_sz.float() / im_sz) + if mode == 'inside': + shrink_factor = shrink_factor.max() + elif mode == 'inside_major': + shrink_factor = shrink_factor.min() + shrink_factor.clamp_(min=1, max=self.params.get('patch_max_scale_change', None)) + sample_sz = (sample_sz.float() / shrink_factor) + self.init_sample_scale = (sample_sz / self.img_sample_sz).prod().sqrt() + tl = self.pos - (sample_sz - 1) / 2 + br = self.pos + sample_sz / 2 + 1 + global_shift = - ((-tl).clamp(0) - (br - im_sz).clamp(0)) / self.init_sample_scale + else: + self.init_sample_scale = self.target_scale + global_shift = torch.zeros(2) + + self.init_sample_pos = self.pos.round() + + # Compute augmentation size + aug_expansion_factor = self.params.get('augmentation_expansion_factor', None) + aug_expansion_sz = self.img_sample_sz.clone() + aug_output_sz = None + if aug_expansion_factor is not None and aug_expansion_factor != 1: + aug_expansion_sz = (self.img_sample_sz * aug_expansion_factor).long() + aug_expansion_sz += (aug_expansion_sz - self.img_sample_sz.long()) % 2 + aug_expansion_sz = aug_expansion_sz.float() + aug_output_sz = self.img_sample_sz.long().tolist() + + # Random shift for each sample + get_rand_shift = lambda: None + random_shift_factor = self.params.get('random_shift_factor', 0) + if random_shift_factor > 0: + get_rand_shift = lambda: ((torch.rand(2) - 0.5) * self.img_sample_sz * random_shift_factor + global_shift).long().tolist() + + # Always put identity transformation first, since it is the unaugmented sample that is always used + self.transforms = [augmentation.Identity(aug_output_sz, global_shift.long().tolist())] + + augs = self.params.augmentation if self.params.get('use_augmentation', True) else {} + + # Add all augmentations + if 'shift' in augs: + self.transforms.extend([augmentation.Translation(shift, aug_output_sz, global_shift.long().tolist()) for shift in augs['shift']]) + if 'relativeshift' in augs: + get_absolute = lambda shift: (torch.Tensor(shift) * self.img_sample_sz/2).long().tolist() + self.transforms.extend([augmentation.Translation(get_absolute(shift), aug_output_sz, global_shift.long().tolist()) for shift in augs['relativeshift']]) + if 'fliplr' in augs and augs['fliplr']: + self.transforms.append(augmentation.FlipHorizontal(aug_output_sz, get_rand_shift())) + if 'blur' in augs: + self.transforms.extend([augmentation.Blur(sigma, aug_output_sz, get_rand_shift()) for sigma in augs['blur']]) + if 'scale' in augs: + self.transforms.extend([augmentation.Scale(scale_factor, aug_output_sz, get_rand_shift()) for scale_factor in augs['scale']]) + if 'rotate' in augs: + self.transforms.extend([augmentation.Rotate(angle, aug_output_sz, get_rand_shift()) for angle in augs['rotate']]) + + # Extract augmented image patches + im_patches = sample_patch_transformed(im, self.init_sample_pos, self.init_sample_scale, aug_expansion_sz, self.transforms) + + # Extract initial backbone features + with torch.no_grad(): + init_backbone_feat = self.net.extract_backbone(im_patches) + + return init_backbone_feat + + def init_target_boxes(self): + """Get the target bounding boxes for the initial augmented samples.""" + self.classifier_target_box = self.get_iounet_box(self.pos, self.target_sz, self.init_sample_pos, self.init_sample_scale) + init_target_boxes = TensorList() + for T in self.transforms: + init_target_boxes.append(self.classifier_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + init_target_boxes = torch.cat(init_target_boxes.view(1, 4), 0).to(self.params.device) + self.target_boxes = init_target_boxes.new_zeros(self.params.sample_memory_size, 4) + self.target_boxes[:init_target_boxes.shape[0],:] = init_target_boxes + return init_target_boxes + + def init_memory(self, train_x: TensorList): + # Initialize first-frame spatial training samples + self.num_init_samples = train_x.size(0) + init_sample_weights = TensorList([x.new_ones(1) / x.shape[0] for x in train_x]) + + # Sample counters and weights for spatial + self.num_stored_samples = self.num_init_samples.copy() + self.previous_replace_ind = [None] * len(self.num_stored_samples) + self.sample_weights = TensorList([x.new_zeros(self.params.sample_memory_size) for x in train_x]) + for sw, init_sw, num in zip(self.sample_weights, init_sample_weights, self.num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [x.new_zeros(self.params.sample_memory_size, x.shape[1], x.shape[2], x.shape[3]) for x in train_x]) + + for ts, x in zip(self.training_samples, train_x): + ts[:x.shape[0],...] = x + + + def update_memory(self, sample_x: TensorList, target_box, learning_rate = None): + # Update weights and get replace ind + replace_ind = self.update_sample_weights(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.num_init_samples, learning_rate) + self.previous_replace_ind = replace_ind + + # Update sample and label memory + for train_samp, x, ind in zip(self.training_samples, sample_x, replace_ind): + train_samp[ind:ind+1,...] = x + + # Update bb memory + self.target_boxes[replace_ind[0],:] = target_box + + self.num_stored_samples += 1 + + + def update_sample_weights(self, sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, learning_rate = None): + # Update weights and get index to replace + replace_ind = [] + for sw, prev_ind, num_samp, num_init in zip(sample_weights, previous_replace_ind, num_stored_samples, num_init_samples): + lr = learning_rate + if lr is None: + lr = self.params.learning_rate + + init_samp_weight = self.params.get('init_samples_minimum_weight', None) + if init_samp_weight == 0: + init_samp_weight = None + s_ind = 0 if init_samp_weight is None else num_init + + if num_samp == 0 or lr == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + if num_samp < sw.shape[0]: + r_ind = num_samp + else: + _, r_ind = torch.min(sw[s_ind:], 0) + r_ind = r_ind.item() + s_ind + + # Update weights + if prev_ind is None: + sw /= 1 - lr + sw[r_ind] = lr + else: + sw[r_ind] = sw[prev_ind] / (1 - lr) + + sw /= sw.sum() + if init_samp_weight is not None and sw[:num_init].sum() < init_samp_weight: + sw /= init_samp_weight + sw[num_init:].sum() + sw[:num_init] = init_samp_weight / num_init + + replace_ind.append(r_ind) + + return replace_ind + + def update_state(self, new_pos, new_scale = None): + # Update scale + if new_scale is not None: + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = self.params.get('target_inside_ratio', 0.2) + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + + def get_iounet_box(self, pos, sz, sample_pos, sample_scale): + """All inputs in original image coordinates. + Generates a box in the cropped image sample reference frame, in the format used by the IoUNet.""" + box_center = (pos - sample_pos) / sample_scale + (self.img_sample_sz - 1) / 2 + box_sz = sz / sample_scale + target_ul = box_center - (box_sz - 1) / 2 + return torch.cat([target_ul.flip((0,)), box_sz.flip((0,))]) + + + def init_iou_net(self, backbone_feat): + # Setup IoU net and objective + for p in self.net.bb_regressor.parameters(): + p.requires_grad = False + + # Get target boxes for the different augmentations + self.classifier_target_box = self.get_iounet_box(self.pos, self.target_sz, self.init_sample_pos, self.init_sample_scale) + target_boxes = TensorList() + if self.params.iounet_augmentation: + for T in self.transforms: + if not isinstance(T, (augmentation.Identity, augmentation.Translation, augmentation.FlipHorizontal, augmentation.FlipVertical, augmentation.Blur)): + break + target_boxes.append(self.classifier_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + else: + target_boxes.append(self.classifier_target_box + torch.Tensor([self.transforms[0].shift[1], self.transforms[0].shift[0], 0, 0])) + target_boxes = torch.cat(target_boxes.view(1,4), 0).to(self.params.device) + + # Get iou features + iou_backbone_feat = self.get_iou_backbone_features(backbone_feat) + + # Remove other augmentations such as rotation + iou_backbone_feat = TensorList([x[:target_boxes.shape[0],...] for x in iou_backbone_feat]) + + # Get modulation vector + self.iou_modulation = self.get_iou_modulation(iou_backbone_feat, target_boxes) + if torch.is_tensor(self.iou_modulation[0]): + self.iou_modulation = TensorList([x.detach().mean(0) for x in self.iou_modulation]) + + + def init_classifier(self, init_backbone_feat): + # Get classification features + x = self.get_classification_features(init_backbone_feat) + + # Overwrite some parameters in the classifier. (These are not generally changed) + self._overwrite_classifier_params(feature_dim=x.shape[-3]) + + # Add the dropout augmentation here, since it requires extraction of the classification features + if 'dropout' in self.params.augmentation and self.params.get('use_augmentation', True): + num, prob = self.params.augmentation['dropout'] + self.transforms.extend(self.transforms[:1]*num) + x = torch.cat([x, F.dropout2d(x[0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + # Set feature size and other related sizes + self.feature_sz = torch.Tensor(list(x.shape[-2:])) + ksz = self.net.classifier.filter_size + self.kernel_size = torch.Tensor([ksz, ksz] if isinstance(ksz, (int, float)) else ksz) + self.output_sz = self.feature_sz + (self.kernel_size + 1)%2 + + # Construct output window + self.output_window = None + if self.params.get('window_output', False): + if self.params.get('use_clipped_window', False): + self.output_window = dcf.hann2d_clipped(self.output_sz.long(), (self.output_sz*self.params.effective_search_area / self.params.search_area_scale).long(), centered=True).to(self.params.device) + else: + self.output_window = dcf.hann2d(self.output_sz.long(), centered=True).to(self.params.device) + self.output_window = self.output_window.squeeze(0) + + # Get target boxes for the different augmentations + target_boxes = self.init_target_boxes() + + # Set number of iterations + plot_loss = self.params.debug > 0 + num_iter = self.params.get('net_opt_iter', None) + + # Get target filter by running the discriminative model prediction module + with torch.no_grad(): + self.target_filter, _, losses = self.net.classifier.get_filter(x, target_boxes, num_iter=num_iter, + compute_losses=plot_loss) + + # Init memory + if self.params.get('update_classifier', True): + self.init_memory(TensorList([x])) + + if plot_loss: + if isinstance(losses, dict): + losses = losses['train'] + self.losses = torch.cat(losses) + if self.visdom is not None: + self.visdom.register((self.losses, torch.arange(self.losses.numel())), 'lineplot', 3, 'Training Loss' + self.id_str) + elif self.params.debug >= 3: + plot_graph(self.losses, 10, title='Training Loss' + self.id_str) + + def _overwrite_classifier_params(self, feature_dim): + # Overwrite some parameters in the classifier. (These are not generally changed) + pred_module = getattr(self.net.classifier.filter_optimizer, 'score_predictor', self.net.classifier.filter_optimizer) + if self.params.get('label_threshold', None) is not None: + self.net.classifier.filter_optimizer.label_threshold = self.params.label_threshold + if self.params.get('label_shrink', None) is not None: + self.net.classifier.filter_optimizer.label_shrink = self.params.label_shrink + if self.params.get('softmax_reg', None) is not None: + self.net.classifier.filter_optimizer.softmax_reg = self.params.softmax_reg + if self.params.get('filter_reg', None) is not None: + pred_module.filter_reg[0] = self.params.filter_reg + pred_module.min_filter_reg = self.params.filter_reg + if self.params.get('filter_init_zero', False): + self.net.classifier.filter_initializer = FilterInitializerZero(self.net.classifier.filter_size, feature_dim) + + + def update_classifier(self, train_x, target_box, learning_rate=None, scores=None): + # Set flags and learning rate + hard_negative_flag = learning_rate is not None + if learning_rate is None: + learning_rate = self.params.learning_rate + + # Update the tracker memory + if hard_negative_flag or self.frame_num % self.params.get('train_sample_interval', 1) == 0: + self.update_memory(TensorList([train_x]), target_box, learning_rate) + + # Decide the number of iterations to run + num_iter = 0 + low_score_th = self.params.get('low_score_opt_threshold', None) + if hard_negative_flag: + num_iter = self.params.get('net_opt_hn_iter', None) + elif low_score_th is not None and low_score_th > scores.max().item(): + num_iter = self.params.get('net_opt_low_iter', None) + elif (self.frame_num - 1) % self.params.train_skipping == 0: + num_iter = self.params.get('net_opt_update_iter', None) + + plot_loss = self.params.debug > 0 + + if num_iter > 0: + # Get inputs for the DiMP filter optimizer module + samples = self.training_samples[0][:self.num_stored_samples[0],...] + target_boxes = self.target_boxes[:self.num_stored_samples[0],:].clone() + sample_weights = self.sample_weights[0][:self.num_stored_samples[0]] + + # Run the filter optimizer module + with torch.no_grad(): + self.target_filter, _, losses = self.net.classifier.filter_optimizer(self.target_filter, + num_iter=num_iter, feat=samples, + bb=target_boxes, + sample_weight=sample_weights, + compute_losses=plot_loss) + + if plot_loss: + if isinstance(losses, dict): + losses = losses['train'] + self.losses = torch.cat((self.losses, torch.cat(losses))) + if self.visdom is not None: + self.visdom.register((self.losses, torch.arange(self.losses.numel())), 'lineplot', 3, 'Training Loss' + self.id_str) + elif self.params.debug >= 3: + plot_graph(self.losses, 10, title='Training Loss' + self.id_str) + + def refine_target_box(self, backbone_feat, sample_pos, sample_scale, scale_ind, update_scale = True): + """Run the ATOM IoUNet to refine the target bounding box.""" + + if hasattr(self.net.bb_regressor, 'predict_bb'): + return self.direct_box_regression(backbone_feat, sample_pos, sample_scale, scale_ind, update_scale) + + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features(backbone_feat) + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + # Generate random initial boxes + init_boxes = init_box.view(1,4).clone() + if self.params.num_init_random_boxes > 0: + square_box_sz = init_box[2:].prod().sqrt() + rand_factor = square_box_sz * torch.cat([self.params.box_jitter_pos * torch.ones(2), self.params.box_jitter_sz * torch.ones(2)]) + + minimal_edge_size = init_box[2:].min()/3 + rand_bb = (torch.rand(self.params.num_init_random_boxes, 4) - 0.5) * rand_factor + new_sz = (init_box[2:] + rand_bb[:,2:]).clamp(minimal_edge_size) + new_center = (init_box[:2] + init_box[2:]/2) + rand_bb[:,:2] + init_boxes = torch.cat([new_center - new_sz/2, new_sz], 1) + init_boxes = torch.cat([init_box.view(1,4), init_boxes]) + + # Optimize the boxes + output_boxes, output_iou = self.optimize_boxes(iou_features, init_boxes) + + # Remove weird boxes + output_boxes[:, 2:].clamp_(1) + aspect_ratio = output_boxes[:,2] / output_boxes[:,3] + keep_ind = (aspect_ratio < self.params.maximal_aspect_ratio) * (aspect_ratio > 1/self.params.maximal_aspect_ratio) + output_boxes = output_boxes[keep_ind,:] + output_iou = output_iou[keep_ind] + + # If no box found + if output_boxes.shape[0] == 0: + return + + # Predict box + k = self.params.get('iounet_k', 5) + topk = min(k, output_boxes.shape[0]) + _, inds = torch.topk(output_iou, topk) + predicted_box = output_boxes[inds, :].mean(0) + predicted_iou = output_iou.view(-1, 1)[inds, :].mean(0) + + # Get new position and size + new_pos = predicted_box[:2] + predicted_box[2:] / 2 + new_pos = (new_pos.flip((0,)) - (self.img_sample_sz - 1) / 2) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + # self.visualize_iou_pred(iou_features, predicted_box) + + + def optimize_boxes(self, iou_features, init_boxes): + box_refinement_space = self.params.get('box_refinement_space', 'default') + if box_refinement_space == 'default': + return self.optimize_boxes_default(iou_features, init_boxes) + if box_refinement_space == 'relative': + return self.optimize_boxes_relative(iou_features, init_boxes) + raise ValueError('Unknown box_refinement_space {}'.format(box_refinement_space)) + + + def optimize_boxes_default(self, iou_features, init_boxes): + """Optimize iounet boxes with the default parametrization""" + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]], device=self.params.device).view(1,1,4) + + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init = output_boxes.clone().detach() + bb_init.requires_grad = True + + outputs = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient = torch.ones_like(outputs)) + + # Update proposal + output_boxes = bb_init + step_length * bb_init.grad * bb_init[:, :, 2:].repeat(1, 1, 2) + output_boxes.detach_() + + step_length *= self.params.box_refinement_step_decay + + return output_boxes.view(-1,4).cpu(), outputs.detach().view(-1).cpu() + + + def optimize_boxes_relative(self, iou_features, init_boxes): + """Optimize iounet boxes with the relative parametrization ised in PrDiMP""" + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]]).to(self.params.device).view(1,1,4) + + sz_norm = output_boxes[:,:1,2:].clone() + output_boxes_rel = bbutils.rect_to_rel(output_boxes, sz_norm) + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init_rel = output_boxes_rel.clone().detach() + bb_init_rel.requires_grad = True + + bb_init = bbutils.rel_to_rect(bb_init_rel, sz_norm) + outputs = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient = torch.ones_like(outputs)) + + # Update proposal + output_boxes_rel = bb_init_rel + step_length * bb_init_rel.grad + output_boxes_rel.detach_() + + step_length *= self.params.box_refinement_step_decay + + # for s in outputs.view(-1): + # print('{:.2f} '.format(s.item()), end='') + # print('') + # print('') + + output_boxes = bbutils.rel_to_rect(output_boxes_rel, sz_norm) + + return output_boxes.view(-1,4).cpu(), outputs.detach().view(-1).cpu() + + def direct_box_regression(self, backbone_feat, sample_pos, sample_scale, scale_ind, update_scale = True): + """Implementation of direct bounding box regression.""" + + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features(backbone_feat) + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + # Generate random initial boxes + init_boxes = init_box.view(1, 1, 4).clone().to(self.params.device) + + # Optimize the boxes + output_boxes = self.net.bb_regressor.predict_bb(self.iou_modulation, iou_features, init_boxes).view(-1,4).cpu() + + # Remove weird boxes + output_boxes[:, 2:].clamp_(1) + + predicted_box = output_boxes[0, :] + + # Get new position and size + new_pos = predicted_box[:2] + predicted_box[2:] / 2 + new_pos = (new_pos.flip((0,)) - (self.img_sample_sz - 1) / 2) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale_bbr = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + new_scale = new_scale_bbr + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + + def visualize_iou_pred(self, iou_features, center_box): + center_box = center_box.view(1,1,4) + sz_norm = center_box[...,2:].clone() + center_box_rel = bbutils.rect_to_rel(center_box, sz_norm) + + pos_dist = 1.0 + sz_dist = math.log(3.0) + pos_step = 0.01 + sz_step = 0.01 + + pos_scale = torch.arange(-pos_dist, pos_dist+pos_step, step=pos_step) + sz_scale = torch.arange(-sz_dist, sz_dist+sz_step, step=sz_step) + + bbx = torch.zeros(1, pos_scale.numel(), 4) + bbx[0,:,0] = pos_scale.clone() + bby = torch.zeros(pos_scale.numel(), 1, 4) + bby[:,0,1] = pos_scale.clone() + bbw = torch.zeros(1, sz_scale.numel(), 4) + bbw[0,:,2] = sz_scale.clone() + bbh = torch.zeros(sz_scale.numel(), 1, 4) + bbh[:,0,3] = sz_scale.clone() + + pos_boxes = bbutils.rel_to_rect((center_box_rel + bbx) + bby, sz_norm).view(1,-1,4).to(self.params.device) + sz_boxes = bbutils.rel_to_rect((center_box_rel + bbw) + bbh, sz_norm).view(1,-1,4).to(self.params.device) + + pos_scores = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, pos_boxes).exp() + sz_scores = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, sz_boxes).exp() + + show_tensor(pos_scores.view(pos_scale.numel(),-1), title='Position scores', fig_num=21) + show_tensor(sz_scores.view(sz_scale.numel(),-1), title='Size scores', fig_num=22) + + + def visdom_draw_tracking(self, image, box, segmentation=None): + if hasattr(self, 'search_area_box'): + self.visdom.register((image, box, self.search_area_box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, box), 'Tracking', 1, 'Tracking') \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/eco/__init__.py b/Stark/external/AR/pytracking/tracker/eco/__init__.py new file mode 100755 index 0000000..26cf654 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/eco/__init__.py @@ -0,0 +1,4 @@ +from .eco import ECO + +def get_tracker_class(): + return ECO \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/eco/eco.py b/Stark/external/AR/pytracking/tracker/eco/eco.py new file mode 100755 index 0000000..25e90e6 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/eco/eco.py @@ -0,0 +1,385 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import math +from pytracking import complex, dcf, fourier, TensorList +from pytracking.libs.tensorlist import tensor_operation +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor +from pytracking.libs.optimization import GaussNewtonCG +from .optim import FilterOptim, FactorizedConvProblem +from pytracking.features import augmentation + + + +class ECO(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.features.initialize() + self.features_initialized = True + + + def initialize(self, image, info: dict) -> dict: + state = info['init_bbox'] + + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize features + self.initialize_features() + + # Chack if image is color + self.params.features.set_is_color(image.shape[2] == 3) + + # Get feature specific params + self.fparams = self.params.features.get_fparams('feature_params') + + # Get position and size + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Set search area + self.target_scale = 1.0 + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + if search_area > self.params.max_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.max_image_sample_size) + elif search_area < self.params.min_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.min_image_sample_size) + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Use odd square search area and set sizes + feat_max_stride = max(self.params.features.stride()) + self.img_sample_sz = torch.round(torch.sqrt(torch.prod(self.base_target_sz * self.params.search_area_scale))) * torch.ones(2) + self.img_sample_sz += feat_max_stride - self.img_sample_sz % (2 * feat_max_stride) + + # Set other sizes (corresponds to ECO code) + self.img_support_sz = self.img_sample_sz + self.feature_sz = self.params.features.size(self.img_sample_sz) + self.filter_sz = self.feature_sz + (self.feature_sz + 1) % 2 + self.output_sz = self.params.score_upsample_factor * self.img_support_sz # Interpolated size of the output + self.compressed_dim = self.fparams.attribute('compressed_dim') + + # Number of filters + self.num_filters = len(self.filter_sz) + + # Get window function + self.window = TensorList([dcf.hann2d(sz).to(self.params.device) for sz in self.feature_sz]) + + # Get interpolation function + self.interp_fs = TensorList([dcf.get_interp_fourier(sz, self.params.interpolation_method, + self.params.interpolation_bicubic_a, self.params.interpolation_centering, + self.params.interpolation_windowing, self.params.device) for sz in self.filter_sz]) + + # Get regularization filter + self.reg_filter = TensorList([dcf.get_reg_filter(self.img_support_sz, self.base_target_sz, fparams).to(self.params.device) + for fparams in self.fparams]) + self.reg_energy = self.reg_filter.view(-1) @ self.reg_filter.view(-1) + + # Get label function + output_sigma_factor = self.fparams.attribute('output_sigma_factor') + sigma = (self.filter_sz / self.img_support_sz) * torch.sqrt(self.base_target_sz.prod()) * output_sigma_factor + self.yf = TensorList([dcf.label_function(sz, sig).to(self.params.device) for sz, sig in zip(self.filter_sz, sigma)]) + + # Optimization options + self.params.precond_learning_rate = self.fparams.attribute('learning_rate') + if self.params.CG_forgetting_rate is None or max(self.params.precond_learning_rate) >= 1: + self.params.direction_forget_factor = 0 + else: + self.params.direction_forget_factor = (1 - max(self.params.precond_learning_rate))**self.params.CG_forgetting_rate + + + # Convert image + im = numpy_to_torch(image) + + # Setup bounds + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + x = self.generate_init_samples(im) + + # Initialize projection matrix + x_mat = TensorList([e.permute(1,0,2,3).reshape(e.shape[1], -1).clone() for e in x]) + x_mat -= x_mat.mean(dim=1, keepdim=True) + cov_x = x_mat @ x_mat.t() + self.projection_matrix = TensorList([torch.svd(C)[0][:,:cdim].clone() for C, cdim in zip(cov_x, self.compressed_dim)]) + + # Transform to get the training sample + train_xf = self.preprocess_sample(x) + + # Shift the samples back + if 'shift' in self.params.augmentation: + for xf in train_xf: + if xf.shape[0] == 1: + continue + for i, shift in enumerate(self.params.augmentation['shift']): + shift_samp = 2 * math.pi * torch.Tensor(shift) / self.img_support_sz + xf[1+i:2+i,...] = fourier.shift_fs(xf[1+i:2+i,...], shift=shift_samp) + + # Shift sample + shift_samp = 2*math.pi * (self.pos - self.pos.round()) / (self.target_scale * self.img_support_sz) + train_xf = fourier.shift_fs(train_xf, shift=shift_samp) + + # Initialize first-frame training samples + num_init_samples = train_xf.size(0) + self.init_sample_weights = TensorList([xf.new_ones(1) / xf.shape[0] for xf in train_xf]) + self.init_training_samples = train_xf.permute(2, 3, 0, 1, 4) + + + # Sample counters and weights + self.num_stored_samples = num_init_samples + self.previous_replace_ind = [None]*len(self.num_stored_samples) + self.sample_weights = TensorList([xf.new_zeros(self.params.sample_memory_size) for xf in train_xf]) + for sw, init_sw, num in zip(self.sample_weights, self.init_sample_weights, num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [xf.new_zeros(xf.shape[2], xf.shape[3], self.params.sample_memory_size, cdim, 2) for xf, cdim in zip(train_xf, self.compressed_dim)]) + + # Initialize filter + self.filter = TensorList( + [xf.new_zeros(1, cdim, xf.shape[2], xf.shape[3], 2) for xf, cdim in zip(train_xf, self.compressed_dim)]) + + # Do joint optimization + self.joint_problem = FactorizedConvProblem(self.init_training_samples, self.yf, self.reg_filter, self.projection_matrix, self.params, self.init_sample_weights) + joint_var = self.filter.concat(self.projection_matrix) + self.joint_optimizer = GaussNewtonCG(self.joint_problem, joint_var, debug=(self.params.debug>=1), visdom=self.visdom) + + if self.params.update_projection_matrix: + self.joint_optimizer.run(self.params.init_CG_iter // self.params.init_GN_iter, self.params.init_GN_iter) + + # Re-project samples with the new projection matrix + compressed_samples = complex.mtimes(self.init_training_samples, self.projection_matrix) + for train_samp, init_samp in zip(self.training_samples, compressed_samples): + train_samp[:,:,:init_samp.shape[2],:,:] = init_samp + + # Initialize optimizer + self.filter_optimizer = FilterOptim(self.params, self.reg_energy) + self.filter_optimizer.register(self.filter, self.training_samples, self.yf, self.sample_weights, self.reg_filter) + self.filter_optimizer.sample_energy = self.joint_problem.sample_energy + self.filter_optimizer.residuals = self.joint_optimizer.residuals.clone() + + if not self.params.update_projection_matrix: + self.filter_optimizer.run(self.params.init_CG_iter) + + # Post optimization + self.filter_optimizer.run(self.params.post_init_CG_iter) + + self.symmetrize_filter() + + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.pos.round() + sample_scales = self.target_scale * self.params.scale_factors + test_xf = self.extract_fourier_sample(im, self.pos, sample_scales, self.img_sample_sz) + + # Compute scores + sf = self.apply_filter(test_xf) + translation_vec, scale_ind, s = self.localize_target(sf) + scale_change_factor = self.params.scale_factors[scale_ind] + + # Update position and scale + self.update_state(sample_pos + translation_vec, self.target_scale * scale_change_factor) + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + self.debug_info['max_score'] = max_score + + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map') + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # if self.params.debug >= 3: + # for i, hf in enumerate(self.filter): + # show_tensor(fourier.sample_fs(hf).abs().mean(1), 6+i) + + + # ------- UPDATE ------- # + + # Get train sample + train_xf = TensorList([xf[scale_ind:scale_ind+1, ...] for xf in test_xf]) + + # Shift the sample + shift_samp = 2*math.pi * (self.pos - sample_pos) / (sample_scales[scale_ind] * self.img_support_sz) + train_xf = fourier.shift_fs(train_xf, shift=shift_samp) + + # Update memory + self.update_memory(train_xf) + + # Train filter + if self.frame_num % self.params.train_skipping == 1: + self.filter_optimizer.run(self.params.CG_iter, train_xf) + self.symmetrize_filter() + + # Return new state + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + out = {'target_bbox': new_state.tolist()} + return out + + + def apply_filter(self, sample_xf: TensorList) -> torch.Tensor: + return complex.mult(self.filter, sample_xf).sum(1, keepdim=True) + + def localize_target(self, sf: TensorList): + if self.params.score_fusion_strategy == 'sum': + scores = fourier.sample_fs(fourier.sum_fs(sf), self.output_sz) + elif self.params.score_fusion_strategy == 'weightedsum': + weight = self.fparams.attribute('translation_weight') + scores = fourier.sample_fs(fourier.sum_fs(weight * sf), self.output_sz) + elif self.params.score_fusion_strategy == 'transcale': + alpha = self.fparams.attribute('scale_weight') + beta = self.fparams.attribute('translation_weight') + sample_sz = torch.round(self.output_sz.view(1,-1) * self.params.scale_factors.view(-1,1)) + scores = 0 + for sfe, a, b in zip(sf, alpha, beta): + sfe = fourier.shift_fs(sfe, math.pi*torch.ones(2)) + scores_scales = [] + for sind, sz in enumerate(sample_sz): + pd = (self.output_sz-sz)/2 + scores_scales.append(F.pad(fourier.sample_fs(sfe[sind:sind+1,...], sz), + (math.floor(pd[1].item()), math.ceil(pd[1].item()), + math.floor(pd[0].item()), math.ceil(pd[0].item())))) + scores_cat = torch.cat(scores_scales) + scores = scores + (b - a) * scores_cat.mean(dim=0, keepdim=True) + a * scores_cat + else: + raise ValueError('Unknown score fusion strategy.') + + # Get maximum + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp.float().cpu() + + # Convert to displacements in the base scale + if self.params.score_fusion_strategy in ['sum', 'weightedsum']: + disp = (max_disp + self.output_sz / 2) % self.output_sz - self.output_sz / 2 + elif self.params.score_fusion_strategy == 'transcale': + disp = max_disp - self.output_sz / 2 + + # Compute translation vector and scale change factor + translation_vec = disp[scale_ind, ...].view(-1) * (self.img_support_sz / self.output_sz) * self.target_scale + if self.params.score_fusion_strategy in ['sum', 'weightedsum']: + translation_vec *= self.params.scale_factors[scale_ind] + + return translation_vec, scale_ind, scores + + + def extract_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + return self.params.features.extract(im, pos, scales, sz)[0] + + def extract_fourier_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor) -> TensorList: + x = self.extract_sample(im, pos, scales, sz) + return self.preprocess_sample(self.project_sample(x)) + + def preprocess_sample(self, x: TensorList) -> TensorList: + x *= self.window + sample_xf = fourier.cfft2(x) + return TensorList([dcf.interpolate_dft(xf, bf) for xf, bf in zip(sample_xf, self.interp_fs)]) + + def project_sample(self, x: TensorList): + @tensor_operation + def _project_sample(x: torch.Tensor, P: torch.Tensor): + if P is None: + return x + return torch.matmul(x.permute(2, 3, 0, 1), P).permute(2, 3, 0, 1) + + return _project_sample(x, self.projection_matrix) + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + # Do data augmentation + transforms = [augmentation.Identity()] + if 'shift' in self.params.augmentation: + transforms.extend([augmentation.Translation(shift) for shift in self.params.augmentation['shift']]) + if 'fliplr' in self.params.augmentation and self.params.augmentation['fliplr']: + transforms.append(augmentation.FlipHorizontal()) + if 'rotate' in self.params.augmentation: + transforms.extend([augmentation.Rotate(angle) for angle in self.params.augmentation['rotate']]) + if 'blur' in self.params.augmentation: + transforms.extend([augmentation.Blur(sigma) for sigma in self.params.augmentation['blur']]) + + init_samples = self.params.features.extract_transformed(im, self.pos, self.target_scale, self.img_sample_sz, transforms) + + # Remove augmented samples for those that shall not have + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if not use_aug: + init_samples[i] = init_samples[i][0:1, ...] + + if 'dropout' in self.params.augmentation: + num, prob = self.params.augmentation['dropout'] + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if use_aug: + init_samples[i] = torch.cat([init_samples[i], F.dropout2d(init_samples[i][0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + return init_samples + + + def update_memory(self, sample_xf: TensorList): + # Update weights and get index to replace + replace_ind = self.update_sample_weights() + for train_samp, xf, ind in zip(self.training_samples, sample_xf, replace_ind): + train_samp[:,:,ind:ind+1,:,:] = xf.permute(2, 3, 0, 1, 4) + + + def update_sample_weights(self): + replace_ind = [] + for sw, prev_ind, num_samp, fparams in zip(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.fparams): + if num_samp == 0 or fparams.learning_rate == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + _, r_ind = torch.min(sw, 0) + r_ind = r_ind.item() + + # Update weights + if prev_ind is None: + sw /= 1 - fparams.learning_rate + sw[r_ind] = fparams.learning_rate + else: + sw[r_ind] = sw[prev_ind] / (1 - fparams.learning_rate) + + sw /= sw.sum() + replace_ind.append(r_ind) + + self.previous_replace_ind = replace_ind.copy() + self.num_stored_samples += 1 + return replace_ind + + def update_state(self, new_pos, new_scale): + # Update scale + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = 0.2 + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + def symmetrize_filter(self): + for hf in self.filter: + hf[:,:,:,0,:] /= 2 + hf[:,:,:,0,:] += complex.conj(hf[:,:,:,0,:].flip((2,))) \ No newline at end of file diff --git a/Stark/external/AR/pytracking/tracker/eco/optim.py b/Stark/external/AR/pytracking/tracker/eco/optim.py new file mode 100755 index 0000000..32d9c64 --- /dev/null +++ b/Stark/external/AR/pytracking/tracker/eco/optim.py @@ -0,0 +1,208 @@ +import torch +import torch.nn.functional as F +from pytracking import complex, optimization, fourier, TensorList +from pytracking.utils.plotting import plot_graph +import math + + +class FactorizedConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, yf:TensorList, reg_filter: torch.Tensor, init_proj_mat: TensorList, params, sample_weights: torch.Tensor = None): + self.training_samples = training_samples + self.yf = complex.complex(yf).permute(2, 3, 0, 1, 4) + self.reg_filter = reg_filter + self.sample_weights_sqrt = None if sample_weights is None else sample_weights.sqrt() + self.params = params + + # Sample energy for preconditioner + compressed_samples = complex.mtimes(self.training_samples, init_proj_mat) + self.sample_energy = complex.abs_sqr(compressed_samples).mean(dim=2, keepdim=True).permute(2, 3, 0, 1) + self.reg_energy = self.reg_filter.view(-1) @ self.reg_filter.view(-1) + + # Projection energy for preconditioner + self.proj_energy = 2 * fourier.inner_prod_fs(yf, yf) / self.training_samples.size(3) + + # Filter part of preconditioner + self.diag_M = (1 - self.params.precond_reg_param) * (self.params.precond_data_param * self.sample_energy + + (1 - self.params.precond_data_param) * self.sample_energy.mean(1, keepdim=True)) + \ + self.params.precond_reg_param * self.reg_energy + self.diag_M.unsqueeze_(-1) + + # Projection matrix part of preconditioner + self.diag_M.extend(self.params.precond_proj_param * (self.proj_energy + self.params.projection_reg)) + + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters, projection_matrices] + :return: [data_terms, filter_regularizations, proj_mat_regularizations] + """ + hf = x[:len(x)//2] + P = x[len(x)//2:] + + compressed_samples = complex.mtimes(self.training_samples, P) + residuals = complex.mtimes(compressed_samples, hf.permute(2, 3, 1, 0, 4)) # (h, w, num_samp, num_filt, 2) + residuals = residuals - self.yf + + if self.sample_weights_sqrt is not None: + residuals = complex.mult(self.sample_weights_sqrt.view(1, 1, -1, 1), residuals) + + + # Add spatial regularization + for hfe, reg_filter in zip(hf, self.reg_filter): + reg_pad1 = min(reg_filter.shape[-2] - 1, hfe.shape[-3] - 1) + reg_pad2 = min(reg_filter.shape[-1] - 1, hfe.shape[-2] - 1) + + # Add part needed for convolution + if reg_pad2 > 0: + hfe_left_padd = complex.conj(hfe[...,1:reg_pad2+1,:].clone().detach().flip((2,3))) + hfe_conv = torch.cat([hfe_left_padd, hfe], -2) + else: + hfe_conv = hfe.clone() + + # Shift data to batch dimension + hfe_conv = hfe_conv.permute(0,1,4,2,3).reshape(-1, 1, hfe_conv.shape[-3], hfe_conv.shape[-2]) + + # Do first convolution + hfe_conv = F.conv2d(hfe_conv, reg_filter, padding=(reg_pad1, reg_pad2)) + + residuals.append(hfe_conv) + + # Add regularization for projection matrix + residuals.extend(math.sqrt(self.params.projection_reg) * P) + + return residuals + + + def ip_input(self, a: TensorList, b: TensorList): + num = len(a) // 2 # Number of filters + a_filter = a[:num] + b_filter = b[:num] + a_P = a[num:] + b_P = b[num:] + + # Filter inner product + ip_out = fourier.inner_prod_fs(a_filter, b_filter) + + # Add projection matrix part + ip_out += a_P.reshape(-1) @ b_P.reshape(-1) + + # Have independent inner products for each filter + return ip_out.concat(ip_out.clone()) + + + def ip_output(self, a: TensorList, b: TensorList): + num = len(a) // 3 # Number of filters + a_data = a[:num].permute(2,3,0,1,4) + b_data = b[:num].permute(2,3,0,1,4) + a_filt_reg = a[num:2*num] + b_filt_reg = b[num:2*num] + a_P_reg = a[2*num:] + b_P_reg = b[2*num:] + + ip_data = sum(fourier.inner_prod_fs(a_data, b_data)) + ip_filt_reg = ip_data.new_zeros(1) + + for ar, br, res_data, reg_filter in zip(a_filt_reg, b_filt_reg, a_data, self.reg_filter): + reg_pad2 = min(reg_filter.shape[-1] - 1, res_data.shape[-2] - 1) + arp = ar.reshape(1, -1, 2, ar.shape[2], ar.shape[3]).permute(0, 1, 3, 4, 2) + brp = br.reshape(1, -1, 2, br.shape[2], br.shape[3]).permute(0, 1, 3, 4, 2) + ip_filt_reg += fourier.inner_prod_fs(arp[:,:,:,2*reg_pad2:,:], brp[:,:,:,2*reg_pad2:,:]) + + ip_P_reg = sum(a_P_reg.view(-1) @ b_P_reg.view(-1)) + + return ip_data + ip_filt_reg + ip_P_reg + + + def M1(self, x: TensorList): + return x / self.diag_M + + +class FilterOptim(optimization.ConjugateGradientBase): + def __init__(self, params, reg_energy): + super(FilterOptim, self).__init__(params.fletcher_reeves, params.standard_alpha, params.direction_forget_factor, (params.debug >= 3)) + + # Parameters + self.params = params + + self.reg_energy = reg_energy + self.sample_energy = None + + self.residuals = torch.zeros(0) + + + def register(self, filter, training_samples, yf, sample_weights, reg_filter): + self.filter = filter + self.training_samples = training_samples # (h, w, num_samples, num_channels, 2) + self.yf = yf + self.sample_weights = sample_weights + self.reg_filter = reg_filter + + + def run(self, num_iter, new_xf: TensorList = None): + if num_iter == 0: + return + + if new_xf is not None: + new_sample_energy = complex.abs_sqr(new_xf) + if self.sample_energy is None: + self.sample_energy = new_sample_energy + else: + self.sample_energy = (1 - self.params.precond_learning_rate) * self.sample_energy + self.params.precond_learning_rate * new_sample_energy + + # Compute right hand side + self.b = complex.mtimes(self.sample_weights.view(1,1,1,-1), self.training_samples).permute(2,3,0,1,4) + self.b = complex.mult_conj(self.yf, self.b) + + self.diag_M = (1 - self.params.precond_reg_param) * (self.params.precond_data_param * self.sample_energy + + (1 - self.params.precond_data_param) * self.sample_energy.mean(1, keepdim=True)) + self.params.precond_reg_param * self.reg_energy + + _, res = self.run_CG(num_iter, self.filter) + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + plot_graph(self.residuals, 9) + + + + def A(self, hf: TensorList): + # Classify + sh = complex.mtimes(self.training_samples, hf.permute(2,3,1,0,4)) # (h, w, num_samp, num_filt, 2) + sh = complex.mult(self.sample_weights.view(1,1,-1,1), sh) + + # Multiply with transpose + hf_out = complex.mtimes(sh.permute(0,1,3,2,4), self.training_samples, conj_b=True).permute(2,3,0,1,4) + + # Add regularization + for hfe, hfe_out, reg_filter in zip(hf, hf_out, self.reg_filter): + reg_pad1 = min(reg_filter.shape[-2] - 1, hfe.shape[-3] - 1) + reg_pad2 = min(reg_filter.shape[-1] - 1, 2*hfe.shape[-2]- 2) + + # Add part needed for convolution + if reg_pad2 > 0: + hfe_conv = torch.cat([complex.conj(hfe[...,1:reg_pad2+1,:].flip((2,3))), hfe], -2) + else: + hfe_conv = hfe.clone() + + # Shift data to batch dimension + hfe_conv = hfe_conv.permute(0,1,4,2,3).reshape(-1, 1, hfe_conv.shape[-3], hfe_conv.shape[-2]) + + # Do first convolution + hfe_conv = F.conv2d(hfe_conv, reg_filter, padding=(reg_pad1, reg_pad2)) + + # Do second convolution + remove_size = min(reg_pad2, hfe.shape[-2]-1) + hfe_conv = F.conv2d(hfe_conv[...,remove_size:], reg_filter) + + # Reshape back and add + hfe_out += hfe_conv.reshape(hfe.shape[0], hfe.shape[1], 2, hfe.shape[2], hfe.shape[3]).permute(0,1,3,4,2) + + return hf_out + + + def ip(self, a: torch.Tensor, b: torch.Tensor): + return fourier.inner_prod_fs(a, b) + + + def M1(self, hf): + return complex.div(hf, self.diag_M) diff --git a/Stark/external/AR/pytracking/util_scripts/__init__.py b/Stark/external/AR/pytracking/util_scripts/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/external/AR/pytracking/util_scripts/download_results.py b/Stark/external/AR/pytracking/util_scripts/download_results.py new file mode 100755 index 0000000..879a234 --- /dev/null +++ b/Stark/external/AR/pytracking/util_scripts/download_results.py @@ -0,0 +1,173 @@ +import os +import sys +import gdown +import re +import shutil +import argparse +import tempfile + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation.environment import env_settings + +results_link_dict = { + "dimp": { + "prdimp50_003.zip": "1p13j3iwcOCubBi3ms0hLwqnP6-x0J8Mc", + "prdimp50_002.zip": "1PPKgrAepbuyM2kjfzYAozQKTL6AjcQOz", + "prdimp50_001.zip": "17NFBObEDeK6mW4Mk2vN5Ekk1SGbFvxRS", + "prdimp50_000.zip": "1r3Efq7AumML2yGQ_KV4zmf4ATKVE1bo6", + "prdimp18_004.zip": "1DF4ZJQAa4CwvN_OiT4te33AV0kpsO7JM", + "prdimp18_003.zip": "1RgwJAN4TxnzgVgsfvrHIg1OUXD1EBZkO", + "prdimp18_002.zip": "17lMllYhygCqgE81DoHX4BZar3xc3auzM", + "prdimp18_001.zip": "1Yg7DmGYOnn2k0MYtSjjKlGyzO1Uimj4G", + "prdimp18_000.zip": "1DuZJSBJ-23WJBQTOWSAaoPYSbGAJJN2Z", + "prdimp50_004.zip": "1f9bx9-dtx3B5_IvIJhjjJyp-cnXciqLO", + "dimp50_004.zip": "1Lj3p8mYCoIqxzdQXZkWFTw-MA8c6eeLa", + "dimp50_000.zip": "1LCgf5sg453Z4bY37A_W5mbXeG68U1fET", + "dimp18_000.zip": "17M7dJZ1oKrIY4-O5lL_mlQPEubUn034g", + "dimp18_001.zip": "1AsiliVgISyDTouYOQYVOXA0srj3YskhJ", + "dimp50_got_001.zip": "1EE5FcPXqMBkv_0ghfzytCMmbKxWxy04p", + "dimp18_002.zip": "1I0GrBaPnySOyPWSvItHhXH8182tFCi_Y", + "dimp50_got_002.zip": "1ALXzVkn58GZ1E0I22vrbXkEXwy5u0xOc", + "dimp18_got_000.zip": "1BxowlgGEonnuaVXwiDwiYr7VV7BRWLvr", + "dimp50_001.zip": "1XfPvwAcymW88J1rq7RlhyKmqsawJDK-K", + "dimp18_got_002.zip": "1awqXQnFRr5NwjLfI-Ngtt3zT7XmQIwzs", + "dimp18_got_001.zip": "1rr2J6NuuYJ5E4wDUw-PrxaNKjIsfgAyk", + "dimp50_got_000.zip": "1ruP8XJOu0woq-bvKdHJ9_Y9RceHDrDjm", + "dimp18_004.zip": "1EztF6bpROFwZ1PSJWgMB7bQ4G_Z08YIg", + "dimp18_003.zip": "1iuiFLv04WE7GfBjm8UkZXFq4gheG2Ru8", + "dimp50_003.zip": "1rLsgeQXyKpD6ryl9BjlIVdO3vd27ekwy", + "dimp50_002.zip": "1wj2jUwlpHgsP1hAcuxXAVriUPuEspsu4", + }, + "atom": { + "default_004.zip": "1BapnQh_8iRM44DXj862eOZV4q8zQLdmT", + "default_003.zip": "1YpfOBLBEUQQiX0fWMPA5pnW3dm0NG3E5", + "default_got_000.zip": "1uJnC0PPQhavwRbAL7VQ2Zow8YdLVzeCb", + "default_got_001.zip": "1YzJm0H31veDW-lMxwy8MYNpMULgsYHKf", + "default_000.zip": "1x6fKGZk3V839mX99Gl_pw7JUaiMaTxc5", + "default_002.zip": "1QIlQFv3p6MBTwsYdIMYmzUDBDQGxGsUC", + "default_001.zip": "1-K2--GNCURDKEgUuiEF18K4DcCLvDEVt", + "default_got_002.zip": "1qGtArxdAy0uWSd-HqFT5zmXpR6TCm4Vc", + }, +} + + +def _download_file(file_id, path): + link = 'https://drive.google.com/uc?id=' + file_id + gdown.download(link, path, quiet=True) + + +def download_results(download_path, trackers='all'): + """ + Script to automatically download tracker results for PyTracking. + + args: + download_path - Directory where the zipped results are downloaded + trackers - Tracker results which are to be downloaded. If set to 'all', all available results are downloaded. + If set to a name of a tracker (e.g. atom), all results for that tracker are downloaded. + Otherwise, it can be set to a dict, where the keys are the names of the trackers for which results are + downloaded. The value can be set to either 'all', in which case all available results for the + tracker are downloaded. Else the value should be a list of parameter file names. + """ + print('Using download path ''{}'''.format(download_path)) + + os.makedirs(download_path, exist_ok=True) + + if isinstance(trackers, str): + if trackers == 'all': + trackers = {k: 'all' for k in results_link_dict.keys()} + elif trackers in results_link_dict: + trackers = {trackers: 'all'} + else: + raise Exception('tracker_list must be set to ''all'', a tracker name, or be a dict') + elif isinstance(trackers, dict): + pass + else: + raise Exception('tracker_list must be set to ''all'', or be a dict') + + for trk, runfiles in trackers.items(): + trk_path = os.path.join(download_path, trk) + if not os.path.exists(trk_path): + os.makedirs(trk_path) + + if runfiles == 'all': + for params, fileid in results_link_dict[trk].items(): + print('Downloading: {}/{}'.format(trk, params)) + _download_file(fileid, os.path.join(trk_path, params)) + elif isinstance(runfiles, (list, tuple)): + for p in runfiles: + for params, fileid in results_link_dict[trk].items(): + if re.match(r'{}(|_(\d\d\d)).zip'.format(p), params) is not None: + print('Downloading: {}/{}'.format(trk, params)) + _download_file(fileid, os.path.join(trk_path, params)) + + else: + raise Exception('tracker_list values must either be set to ''all'', or be a list of param names') + + + +def unpack_tracking_results(download_path, output_path=None): + """ + Unpacks zipped benchmark results. The directory 'download_path' should have the following structure + - root + - tracker1 + - param1.zip + - param2.zip + . + . + - tracker2 + - param1.zip + - param2.zip + . + . + + args: + download_path - Path to the directory where the zipped results are stored + output_path - Path to the directory where the results will be unpacked. Set to env_settings().results_path + by default + """ + + if output_path is None: + output_path = env_settings().results_path + + if not os.path.exists(output_path): + os.makedirs(output_path) + + trackers = os.listdir(download_path) + + for t in trackers: + runfiles = os.listdir(os.path.join(download_path, t)) + + for r in runfiles: + save_path = os.path.join(output_path, t) + if not os.path.exists(save_path): + os.makedirs(save_path) + shutil.unpack_archive(os.path.join(download_path, t, r), os.path.join(save_path, r[:-4]), 'zip') + + +def main(): + parser = argparse.ArgumentParser(description='Download and unpack zipped results') + parser.add_argument('--tracker', type=str, default='all', + help='Name of tracker results to download, or ''all''.') + parser.add_argument('--output_path', type=str, default=None, + help='Path to the directory where the results will be unpacked.') + parser.add_argument('--temp_download_path', type=str, default=None, + help='Temporary path used for downloading the Zip files.') + parser.add_argument('--download', type=bool, default=True, + help='Whether to download results or unpack existing downloaded files.') + args = parser.parse_args() + + download_path = args.temp_download_path + if download_path is None: + download_path = '{}/pytracking_results/'.format(tempfile.gettempdir()) + + if args.download: + download_results(download_path, args.tracker) + + unpack_tracking_results(download_path, args.output_path) + + +if __name__ == '__main__': + main() diff --git a/Stark/external/AR/pytracking/util_scripts/pack_got10k_results.py b/Stark/external/AR/pytracking/util_scripts/pack_got10k_results.py new file mode 100755 index 0000000..f1c036b --- /dev/null +++ b/Stark/external/AR/pytracking/util_scripts/pack_got10k_results.py @@ -0,0 +1,42 @@ +import numpy as np +import os +import shutil +from pytracking.evaluation.environment import env_settings + + +def pack_got10k_results(tracker_name, param_name, output_name): + """ Packs got10k results into a zip folder which can be directly uploaded to the evaluation server. The packed + file is saved in the folder env_settings().got_packed_results_path + + args: + tracker_name - name of the tracker + param_name - name of the parameter file + output_name - name of the packed zip file + """ + output_path = os.path.join(env_settings().got_packed_results_path, output_name) + + if not os.path.exists(output_path): + os.makedirs(output_path) + + results_path = env_settings().results_path + for i in range(1,181): + seq_name = 'GOT-10k_Test_{:06d}'.format(i) + + seq_output_path = '{}/{}'.format(output_path, seq_name) + if not os.path.exists(seq_output_path): + os.makedirs(seq_output_path) + + for run_id in range(3): + res = np.loadtxt('{}/{}/{}_{:03d}/{}.txt'.format(results_path, tracker_name, param_name, run_id, seq_name), dtype=np.float64) + times = np.loadtxt( + '{}/{}/{}_{:03d}/{}_time.txt'.format(results_path, tracker_name, param_name, run_id, seq_name), + dtype=np.float64) + + np.savetxt('{}/{}_{:03d}.txt'.format(seq_output_path, seq_name, run_id+1), res, delimiter=',', fmt='%f') + np.savetxt('{}/{}_time.txt'.format(seq_output_path, seq_name), times, fmt='%f') + + # Generate ZIP file + shutil.make_archive(output_path, 'zip', output_path) + + # Remove raw text files + shutil.rmtree(output_path) diff --git a/Stark/external/AR/pytracking/util_scripts/pack_trackingnet_results.py b/Stark/external/AR/pytracking/util_scripts/pack_trackingnet_results.py new file mode 100755 index 0000000..40fb76a --- /dev/null +++ b/Stark/external/AR/pytracking/util_scripts/pack_trackingnet_results.py @@ -0,0 +1,50 @@ +import numpy as np +import os +import shutil +from pytracking.evaluation.environment import env_settings +from pytracking.evaluation.datasets import get_dataset + + +def pack_trackingnet_results(tracker_name, param_name, run_id=None, output_name=None): + """ Packs trackingnet results into a zip folder which can be directly uploaded to the evaluation server. The packed + file is saved in the folder env_settings().tn_packed_results_path + + args: + tracker_name - name of the tracker + param_name - name of the parameter file + run_id - run id for the tracker + output_name - name of the packed zip file + """ + + if output_name is None: + if run_id is None: + output_name = '{}_{}'.format(tracker_name, param_name) + else: + output_name = '{}_{}_{:03d}'.format(tracker_name, param_name, run_id) + + output_path = os.path.join(env_settings().tn_packed_results_path, output_name) + + if not os.path.exists(output_path): + os.makedirs(output_path) + + results_path = env_settings().results_path + + tn_dataset = get_dataset('trackingnet') + + for seq in tn_dataset: + seq_name = seq.name + + if run_id is None: + seq_results_path = '{}/{}/{}/{}.txt'.format(results_path, tracker_name, param_name, seq_name) + else: + seq_results_path = '{}/{}/{}_{:03d}/{}.txt'.format(results_path, tracker_name, param_name, run_id, seq_name) + + results = np.loadtxt(seq_results_path, dtype=np.float64) + + np.savetxt('{}/{}.txt'.format(output_path, seq_name), results, delimiter=',', fmt='%.2f') + + # Generate ZIP file + shutil.make_archive(output_path, 'zip', output_path) + + # Remove raw text files + shutil.rmtree(output_path) diff --git a/Stark/external/AR/pytracking/utils/__init__.py b/Stark/external/AR/pytracking/utils/__init__.py new file mode 100755 index 0000000..8d83e11 --- /dev/null +++ b/Stark/external/AR/pytracking/utils/__init__.py @@ -0,0 +1 @@ +from .params import TrackerParams, FeatureParams, Choice \ No newline at end of file diff --git a/Stark/external/AR/pytracking/utils/convert_vot_anno_to_rect.py b/Stark/external/AR/pytracking/utils/convert_vot_anno_to_rect.py new file mode 100755 index 0000000..e0d1c64 --- /dev/null +++ b/Stark/external/AR/pytracking/utils/convert_vot_anno_to_rect.py @@ -0,0 +1,37 @@ +import numpy as np + + +def convert_vot_anno_to_rect(vot_anno, type): + if len(vot_anno) == 4: + return vot_anno + + if type == 'union': + x1 = min(vot_anno[0::2]) + x2 = max(vot_anno[0::2]) + y1 = min(vot_anno[1::2]) + y2 = max(vot_anno[1::2]) + return [x1, y1, x2 - x1, y2 - y1] + elif type == 'preserve_area': + if len(vot_anno) != 8: + raise ValueError + + vot_anno = np.array(vot_anno) + cx = np.mean(vot_anno[0::2]) + cy = np.mean(vot_anno[1::2]) + + x1 = min(vot_anno[0::2]) + x2 = max(vot_anno[0::2]) + y1 = min(vot_anno[1::2]) + y2 = max(vot_anno[1::2]) + + A1 = np.linalg.norm(vot_anno[0:2] - vot_anno[2: 4]) * np.linalg.norm(vot_anno[2: 4] - vot_anno[4:6]) + A2 = (x2 - x1) * (y2 - y1) + s = np.sqrt(A1 / A2) + w = s * (x2 - x1) + 1 + h = s * (y2 - y1) + 1 + + x = cx - 0.5*w + y = cy - 0.5*h + return [x, y, w, h] + else: + raise ValueError diff --git a/Stark/external/AR/pytracking/utils/load_text.py b/Stark/external/AR/pytracking/utils/load_text.py new file mode 100755 index 0000000..919536c --- /dev/null +++ b/Stark/external/AR/pytracking/utils/load_text.py @@ -0,0 +1,41 @@ +import numpy as np +import pandas as pd + + +def load_text_numpy(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = np.loadtxt(path, delimiter=d, dtype=dtype) + return ground_truth_rect + except: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = np.loadtxt(path, delimiter=delimiter, dtype=dtype) + return ground_truth_rect + + +def load_text_pandas(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = pd.read_csv(path, delimiter=d, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + except Exception as e: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = pd.read_csv(path, delimiter=delimiter, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + + +def load_text(path, delimiter=' ', dtype=np.float32, backend='numpy'): + if backend == 'numpy': + return load_text_numpy(path, delimiter, dtype) + elif backend == 'pandas': + return load_text_pandas(path, delimiter, dtype) diff --git a/Stark/external/AR/pytracking/utils/loading.py b/Stark/external/AR/pytracking/utils/loading.py new file mode 100755 index 0000000..55846a7 --- /dev/null +++ b/Stark/external/AR/pytracking/utils/loading.py @@ -0,0 +1,33 @@ +import os +import ltr.admin.loading as ltr_loading +from pytracking.evaluation.environment import env_settings + + +def load_network(net_path, **kwargs): + """Load network for tracking. + args: + net_path - Path to network. If it is not an absolute path, it is relative to the network_path in the local.py. + See ltr.admin.loading.load_network for further details. + **kwargs - Additional key-word arguments that are sent to ltr.admin.loading.load_network. + """ + kwargs['backbone_pretrained'] = False + if os.path.isabs(net_path): + path_full = net_path + net, _ = ltr_loading.load_network(path_full, **kwargs) + elif isinstance(env_settings().network_path, (list, tuple)): + net = None + for p in env_settings().network_path: + path_full = os.path.join(p, net_path) + try: + net, _ = ltr_loading.load_network(path_full, **kwargs) + break + except Exception as e: + # print(e) + pass + + assert net is not None, 'Failed to load network' + else: + path_full = os.path.join(env_settings().network_path, net_path) + net, _ = ltr_loading.load_network(path_full, **kwargs) + + return net diff --git a/Stark/external/AR/pytracking/utils/params.py b/Stark/external/AR/pytracking/utils/params.py new file mode 100755 index 0000000..b3cdb04 --- /dev/null +++ b/Stark/external/AR/pytracking/utils/params.py @@ -0,0 +1,43 @@ +from pytracking import TensorList +import random + + +class TrackerParams: + """Class for tracker parameters.""" + def set_default_values(self, default_vals: dict): + for name, val in default_vals.items(): + if not hasattr(self, name): + setattr(self, name, val) + + def get(self, name: str, *default): + """Get a parameter value with the given name. If it does not exists, it return the default value given as a + second argument or returns an error if no default value is given.""" + if len(default) > 1: + raise ValueError('Can only give one default value.') + + if not default: + return getattr(self, name) + + return getattr(self, name, default[0]) + + def has(self, name: str): + """Check if there exist a parameter with the given name.""" + return hasattr(self, name) + + +class FeatureParams: + """Class for feature specific parameters""" + def __init__(self, *args, **kwargs): + if len(args) > 0: + raise ValueError + + for name, val in kwargs.items(): + if isinstance(val, list): + setattr(self, name, TensorList(val)) + else: + setattr(self, name, val) + + +def Choice(*args): + """Can be used to sample random parameter values.""" + return random.choice(args) diff --git a/Stark/external/AR/pytracking/utils/plotting.py b/Stark/external/AR/pytracking/utils/plotting.py new file mode 100755 index 0000000..47869fe --- /dev/null +++ b/Stark/external/AR/pytracking/utils/plotting.py @@ -0,0 +1,155 @@ +import matplotlib.pyplot as plt +import numpy as np +import torch +import cv2 + + +def draw_figure(fig): + fig.canvas.draw() + fig.canvas.flush_events() + plt.pause(0.001) + + +def show_tensor(a: torch.Tensor, fig_num = None, title = None, range=(None, None), ax=None): + """Display a 2D tensor. + args: + fig_num: Figure number. + title: Title of figure. + """ + a_np = a.squeeze().cpu().clone().detach().numpy() + if a_np.ndim == 3: + a_np = np.transpose(a_np, (1, 2, 0)) + + if ax is None: + fig = plt.figure(fig_num) + plt.tight_layout() + plt.cla() + plt.imshow(a_np, vmin=range[0], vmax=range[1]) + plt.axis('off') + plt.axis('equal') + if title is not None: + plt.title(title) + draw_figure(fig) + else: + ax.cla() + ax.imshow(a_np, vmin=range[0], vmax=range[1]) + ax.set_axis_off() + ax.axis('equal') + if title is not None: + ax.set_title(title) + draw_figure(plt.gcf()) + + +def plot_graph(a: torch.Tensor, fig_num = None, title = None): + """Plot graph. Data is a 1D tensor. + args: + fig_num: Figure number. + title: Title of figure. + """ + a_np = a.squeeze().cpu().clone().detach().numpy() + if a_np.ndim > 1: + raise ValueError + fig = plt.figure(fig_num) + # plt.tight_layout() + plt.cla() + plt.plot(a_np) + if title is not None: + plt.title(title) + draw_figure(fig) + + +def show_image_with_boxes(im, boxes, iou_pred=None, disp_ids=None): + im_np = im.clone().cpu().squeeze().numpy() + im_np = np.ascontiguousarray(im_np.transpose(1, 2, 0).astype(np.uint8)) + + boxes = boxes.view(-1, 4).cpu().numpy().round().astype(int) + + # Draw proposals + for i_ in range(boxes.shape[0]): + if disp_ids is None or disp_ids[i_]: + bb = boxes[i_, :] + disp_color = (i_*38 % 256, (255 - i_*97) % 256, (123 + i_*66) % 256) + cv2.rectangle(im_np, (bb[0], bb[1]), (bb[0] + bb[2], bb[1] + bb[3]), + disp_color, 1) + + if iou_pred is not None: + text_pos = (bb[0], bb[1] - 5) + cv2.putText(im_np, 'ID={} IOU = {:3.2f}'.format(i_, iou_pred[i_]), text_pos, + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, bottomLeftOrigin=False) + + im_tensor = torch.from_numpy(im_np.transpose(2, 0, 1)).float() + + return im_tensor + + + +def _pascal_color_map(N=256, normalized=False): + """ + Python implementation of the color map function for the PASCAL VOC data set. + Official Matlab version can be found in the PASCAL VOC devkit + http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html#devkit + """ + + def bitget(byteval, idx): + return (byteval & (1 << idx)) != 0 + + dtype = 'float32' if normalized else 'uint8' + cmap = np.zeros((N, 3), dtype=dtype) + for i in range(N): + r = g = b = 0 + c = i + for j in range(8): + r = r | (bitget(c, 0) << 7 - j) + g = g | (bitget(c, 1) << 7 - j) + b = b | (bitget(c, 2) << 7 - j) + c = c >> 3 + + cmap[i] = np.array([r, g, b]) + + cmap = cmap / 255 if normalized else cmap + return cmap + + +def overlay_mask(im, ann, alpha=0.5, colors=None, contour_thickness=None): + """ Overlay mask over image. + Source: https://github.com/albertomontesg/davis-interactive/blob/master/davisinteractive/utils/visualization.py + This function allows you to overlay a mask over an image with some + transparency. + # Arguments + im: Numpy Array. Array with the image. The shape must be (H, W, 3) and + the pixels must be represented as `np.uint8` data type. + ann: Numpy Array. Array with the mask. The shape must be (H, W) and the + values must be intergers + alpha: Float. Proportion of alpha to apply at the overlaid mask. + colors: Numpy Array. Optional custom colormap. It must have shape (N, 3) + being N the maximum number of colors to represent. + contour_thickness: Integer. Thickness of each object index contour draw + over the overlay. This function requires to have installed the + package `opencv-python`. + # Returns + Numpy Array: Image of the overlay with shape (H, W, 3) and data type + `np.uint8`. + """ + im, ann = np.asarray(im, dtype=np.uint8), np.asarray(ann, dtype=np.int) + if im.shape[:-1] != ann.shape: + raise ValueError('First two dimensions of `im` and `ann` must match') + if im.shape[-1] != 3: + raise ValueError('im must have three channels at the 3 dimension') + + colors = colors or _pascal_color_map() + colors = np.asarray(colors, dtype=np.uint8) + + mask = colors[ann] + fg = im * alpha + (1 - alpha) * mask + + img = im.copy() + img[ann > 0] = fg[ann > 0] + + if contour_thickness: # pragma: no cover + import cv2 + for obj_id in np.unique(ann[ann > 0]): + contours = cv2.findContours((ann == obj_id).astype( + np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:] + cv2.drawContours(img, contours[0], -1, colors[obj_id].tolist(), + contour_thickness) + return img diff --git a/Stark/external/AR/pytracking/utils/visdom.py b/Stark/external/AR/pytracking/utils/visdom.py new file mode 100755 index 0000000..72ae3b9 --- /dev/null +++ b/Stark/external/AR/pytracking/utils/visdom.py @@ -0,0 +1,428 @@ +import visdom +import visdom.server +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_image_with_boxes, overlay_mask +import cv2 +import torch +import copy +import numpy as np +from collections import OrderedDict + + +class VisBase: + def __init__(self, visdom, show_data, title): + self.visdom = visdom + self.show_data = show_data + self.title = title + self.raw_data = None + + def update(self, data, **kwargs): + self.save_data(data, **kwargs) + + if self.show_data: + self.draw_data() + + def save_data(self, data, **kwargs): + raise NotImplementedError + + def draw_data(self): + raise NotImplementedError + + def toggle_display(self, new_mode=None): + if new_mode is not None: + self.show_data = new_mode + else: + self.show_data = not self.show_data + + if self.show_data: + self.draw_data() + else: + self.visdom.close(self.title) + + +class VisImage(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + data = data.float() + self.raw_data = data + + def draw_data(self): + self.visdom.image(self.raw_data.clone(), opts={'title': self.title}, win=self.title) + + +class VisHeatmap(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + data = data.squeeze().flip(0) + self.raw_data = data + + def draw_data(self): + self.visdom.heatmap(self.raw_data.clone(), opts={'title': self.title}, win=self.title) + + +class VisFeaturemap(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.block_list = None + + def block_list_callback_handler(self, data): + self.block_list[data['propertyId']]['value'] = data['value'] + self.visdom.properties(self.block_list, opts={'title': 'Featuremap UI'}, win='featuremap_ui') + self.draw_data() + + def save_data(self, data): + data = data.view(-1, *data.shape[-2:]) + data = data.flip(1) + if self.block_list is None: + self.block_list = [] + self.draw_feat = [] + for i in range(data.shape[0]): + self.block_list.append({'type': 'checkbox', 'name': 'Channel {:04d}'.format(i), 'value': False}) + + self.visdom.properties(self.block_list, opts={'title': 'Featuremap UI'}, win='featuremap_ui') + self.visdom.register_event_handler(self.block_list_callback_handler, 'featuremap_ui') + + self.raw_data = data + + def draw_data(self): + if self.block_list is not None and self.show_data: + for i, d in enumerate(self.block_list): + if d['value']: + fig_title = '{} ch: {:04d}'.format(self.title, i) + self.visdom.heatmap(self.raw_data[i, :, :].clone(), + opts={'title': fig_title}, win=fig_title) + + +class VisCostVolume(VisBase): + def __init__(self, visdom, show_data, title, flip=False): + super().__init__(visdom, show_data, title) + self.show_slice = False + self.slice_pos = None + self.flip = flip + + def show_cost_volume(self): + data = self.raw_data.clone() + + # data_perm = data.permute(2, 0, 3, 1).contiguous() + data_perm = data.permute(0, 2, 1, 3).contiguous() + if self.flip: + data_perm = data_perm.permute(2, 3, 0, 1).contiguous() + + data_perm = data_perm.view(data_perm.shape[0] * data_perm.shape[1], -1) + self.visdom.heatmap(data_perm.flip(0), opts={'title': self.title}, win=self.title) + + def set_zoom_pos(self, slice_pos): + self.slice_pos = slice_pos + + def toggle_show_slice(self, new_mode=None): + if new_mode is not None: + self.show_slice = new_mode + else: + self.show_slice = not self.show_slice + + def show_cost_volume_slice(self): + slice_pos = self.slice_pos + + # slice_pos: [row, col] + cost_volume_data = self.raw_data.clone() + + if self.flip: + cost_volume_slice = cost_volume_data[:, :, slice_pos[0], slice_pos[1]] + else: + cost_volume_slice = cost_volume_data[slice_pos[0], slice_pos[1], :, :] + self.visdom.heatmap(cost_volume_slice.flip(0), opts={'title': self.title}, win=self.title) + + def save_data(self, data): + data = data.view(data.shape[-2], data.shape[-1], data.shape[-2], data.shape[-1]) + self.raw_data = data + + def draw_data(self): + if self.show_slice: + self.show_cost_volume_slice() + else: + self.show_cost_volume() + + +class VisCostVolumeUI(VisBase): + def cv_ui_handler(self, data): + zoom_toggled = False + if data['event_type'] == 'KeyPress': + if data['key'] == 'ArrowRight': + self.zoom_pos[1] = min(self.zoom_pos[1] + 1, self.feat_shape[1]-1) + elif data['key'] == 'ArrowLeft': + self.zoom_pos[1] = max(self.zoom_pos[1] - 1, 0) + elif data['key'] == 'ArrowUp': + self.zoom_pos[0] = max(self.zoom_pos[0] - 1, 0) + elif data['key'] == 'ArrowDown': + self.zoom_pos[0] = min(self.zoom_pos[0] + 1, self.feat_shape[0]-1) + elif data['key'] == 'Enter': + self.zoom_mode = not self.zoom_mode + zoom_toggled = True + + # Update image + self.show_image() + + # Update cost volumes + for block_title, block in self.registered_blocks.items(): + if isinstance(block, VisCostVolume): + block.set_zoom_pos(self.zoom_pos) + block.toggle_show_slice(self.zoom_mode) + + if (self.zoom_mode or zoom_toggled) and block.show_data: + block.draw_data() + + def __init__(self, visdom, show_data, title, feat_shape, registered_blocks): + super().__init__(visdom, show_data, title) + self.feat_shape = feat_shape + self.zoom_mode = False + self.zoom_pos = [int((feat_shape[0] - 1) / 2), int((feat_shape[1] - 1) / 2)] + self.registered_blocks = registered_blocks + + self.visdom.register_event_handler(self.cv_ui_handler, title) + + def draw_grid(self, data): + stride_r = int(data.shape[1] / self.feat_shape[0]) + stride_c = int(data.shape[2] / self.feat_shape[1]) + + # Draw grid + data[:, list(range(0, data.shape[1], stride_r)), :] = 0 + data[:, :, list(range(0, data.shape[2], stride_c))] = 0 + + data[0, list(range(0, data.shape[1], stride_r)), :] = 255 + data[0, :, list(range(0, data.shape[2], stride_c))] = 255 + + return data + + def shade_cell(self, data): + stride_r = int(data.shape[1] / self.feat_shape[0]) + stride_c = int(data.shape[2] / self.feat_shape[1]) + + r1 = self.zoom_pos[0]*stride_r + r2 = min((self.zoom_pos[0] + 1)*stride_r, data.shape[1]) + + c1 = self.zoom_pos[1] * stride_c + c2 = min((self.zoom_pos[1] + 1) * stride_c, data.shape[2]) + + factor = 0.8 if self.zoom_mode else 0.5 + data[:, r1:r2, c1:c2] = data[:, r1:r2, c1:c2] * (1 - factor) + torch.tensor([255.0, 0.0, 0.0]).view(3, 1, 1).to(data.device) * factor + return data + + def show_image(self, data=None): + if data is None: + data = self.raw_data.clone() + + data = self.draw_grid(data) + data = self.shade_cell(data) + self.visdom.image(data, opts={'title': self.title}, win=self.title) + + def save_data(self, data): + # Ignore feat shape + data = data[0] + data = data.float() + self.raw_data = data + + def draw_data(self): + self.show_image(self.raw_data.clone()) + + +class VisInfoDict(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.raw_data = OrderedDict() + + def generate_display_text(self, data): + display_text = '' + for key, value in data.items(): + key = key.replace('_', ' ') + if value is None: + display_text += '{}: {}
'.format(key, 'None') + elif isinstance(value, (str, int)): + display_text += '{}: {}
'.format(key, value) + else: + display_text += '{}: {:.2f}
'.format(key, value) + + return display_text + + def save_data(self, data): + for key, val in data.items(): + self.raw_data[key] = val + + def draw_data(self): + data = copy.deepcopy(self.raw_data) + display_text = self.generate_display_text(data) + self.visdom.text(display_text, opts={'title': self.title}, win=self.title) + + +class VisText(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + self.raw_data = data + + def draw_data(self): + data = copy.deepcopy(self.raw_data) + self.visdom.text(data, opts={'title': self.title}, win=self.title) + + +class VisLinePlot(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + self.raw_data = data + + def draw_data(self): + if isinstance(self.raw_data, (list, tuple)): + data_y = self.raw_data[0].clone() + data_x = self.raw_data[1].clone() + else: + data_y = self.raw_data.clone() + data_x = torch.arange(data_y.shape[0]) + + self.visdom.line(data_y, data_x, opts={'title': self.title}, win=self.title) + + +class VisTracking(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + image = data[0] + boxes_masks = data[1:] + + boxes, masks = [], [] + for bm in boxes_masks: + if bm is None: + continue + if isinstance(bm, list): + boxes.append(torch.Tensor(bm)); continue + if len(bm.shape) > 1: + # Binarize segmentation if a float tensor is provided + if bm.dtype != np.uint8: + bm = (bm > 0.5).astype(np.uint8) + masks.append(bm); continue + boxes.append(bm.float()) + + self.raw_data = [image, boxes, masks] + + def draw_data(self): + disp_image = self.raw_data[0].copy() + + resize_factor = 1 + if max(disp_image.shape) > 480: + resize_factor = 480.0 / float(max(disp_image.shape)) + disp_image = cv2.resize(disp_image, None, fx=resize_factor, fy=resize_factor) + for i, mask in enumerate(self.raw_data[2]): + self.raw_data[2][i] = cv2.resize(mask, None, fx=resize_factor, fy=resize_factor) + + boxes = [resize_factor * b.clone() for b in self.raw_data[1]] + + for i, disp_rect in enumerate(boxes): + color = ((255*((i%3)>0)), 255*((i+1)%2), (255*(i%5))//4) + cv2.rectangle(disp_image, + (int(disp_rect[0]), int(disp_rect[1])), + (int(disp_rect[0] + disp_rect[2]), int(disp_rect[1] + disp_rect[3])), color, 2) + for i, mask in enumerate(self.raw_data[2], 1): + disp_image = overlay_mask(disp_image, mask * i) + disp_image = numpy_to_torch(disp_image).squeeze(0) + disp_image = disp_image.float() + self.visdom.image(disp_image, opts={'title': self.title}, win=self.title) + + +class VisBBReg(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.block_list = [] + + def block_list_callback_handler(self, data): + self.block_list[data['propertyId']]['value'] = data['value'] + self.visdom.properties(self.block_list, opts={'title': 'BBReg Vis'}, win='bbreg_vis') + self.draw_data() + + def save_data(self, data): + self.image = data[0].float() + self.init_boxes = data[1] + self.final_boxes = data[2] + self.final_ious = data[3] + + def draw_data(self): + if len(self.block_list) == 0: + self.block_list.append({'type': 'checkbox', 'name': 'ID 0', 'value': True}) + self.block_list.append({'type': 'checkbox', 'name': 'ID 1', 'value': True}) + self.visdom.properties(self.block_list, opts={'title': 'BBReg Vis'}, win='bbreg_vis') + self.visdom.register_event_handler(self.block_list_callback_handler, 'bbreg_vis') + + disp_image = self.image + + ids = [x['value'] for x in self.block_list] + init_box_image = show_image_with_boxes(disp_image.clone(), self.init_boxes.clone(), disp_ids=ids) + final_box_image = show_image_with_boxes(disp_image.clone(), self.final_boxes.clone(), self.final_ious.clone(), disp_ids=ids) + + self.visdom.image(init_box_image, opts={'title': 'Init Boxes'}, win='Init Boxes') + self.visdom.image(final_box_image, opts={'title': 'Final Boxes'}, win='Final Boxes') + + +class Visdom: + def __init__(self, debug=0, ui_info=None, visdom_info=None): + self.debug = debug + self.visdom = visdom.Visdom(server=visdom_info.get('server', '127.0.0.1'), port=visdom_info.get('port', 8097)) + self.registered_blocks = {} + self.blocks_list = [] + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + self.visdom.register_event_handler(self.block_list_callback_handler, 'block_list') + + if ui_info is not None: + self.visdom.register_event_handler(ui_info['handler'], ui_info['win_id']) + + def block_list_callback_handler(self, data): + field_name = self.blocks_list[data['propertyId']]['name'] + + self.registered_blocks[field_name].toggle_display(data['value']) + + self.blocks_list[data['propertyId']]['value'] = data['value'] + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + + def register(self, data, mode, debug_level=0, title='Data', **kwargs): + if title not in self.registered_blocks.keys(): + show_data = self.debug >= debug_level + + if title != 'Tracking': + self.blocks_list.append({'type': 'checkbox', 'name': title, 'value': show_data}) + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + + if mode == 'image': + self.registered_blocks[title] = VisImage(self.visdom, show_data, title) + elif mode == 'heatmap': + self.registered_blocks[title] = VisHeatmap(self.visdom, show_data, title) + elif mode == 'cost_volume': + self.registered_blocks[title] = VisCostVolume(self.visdom, show_data, title) + elif mode == 'cost_volume_flip': + self.registered_blocks[title] = VisCostVolume(self.visdom, show_data, title, flip=True) + elif mode == 'cost_volume_ui': + self.registered_blocks[title] = VisCostVolumeUI(self.visdom, show_data, title, data[1], + self.registered_blocks) + elif mode == 'info_dict': + self.registered_blocks[title] = VisInfoDict(self.visdom, show_data, title) + elif mode == 'text': + self.registered_blocks[title] = VisText(self.visdom, show_data, title) + elif mode == 'lineplot': + self.registered_blocks[title] = VisLinePlot(self.visdom, show_data, title) + elif mode == 'Tracking': + self.registered_blocks[title] = VisTracking(self.visdom, show_data, title) + elif mode == 'bbreg': + self.registered_blocks[title] = VisBBReg(self.visdom, show_data, title) + elif mode == 'featmap': + self.registered_blocks[title] = VisFeaturemap(self.visdom, show_data, title) + else: + raise ValueError('Visdom Error: Unknown data mode {}'.format(mode)) + # Update + self.registered_blocks[title].update(data, **kwargs) + diff --git a/Stark/external/AR/pytracking/vot20_utils.py b/Stark/external/AR/pytracking/vot20_utils.py new file mode 100755 index 0000000..2adddf1 --- /dev/null +++ b/Stark/external/AR/pytracking/vot20_utils.py @@ -0,0 +1,60 @@ +import numpy as np + + +def make_full_size(x, output_sz): + ''' + zero-pad input x (right and down) to match output_sz + x: numpy array e.g., binary mask + output_sz: size of the output [width, height] + ''' + if x.shape[0] == output_sz[1] and x.shape[1] == output_sz[0]: + return x + pad_x = output_sz[0] - x.shape[1] + if pad_x < 0: + x = x[:, :x.shape[1] + pad_x] + # padding has to be set to zero, otherwise pad function fails + pad_x = 0 + pad_y = output_sz[1] - x.shape[0] + if pad_y < 0: + x = x[:x.shape[0] + pad_y, :] + # padding has to be set to zero, otherwise pad function fails + pad_y = 0 + return np.pad(x, ((0, pad_y), (0, pad_x)), 'constant', constant_values=0) + + +def rect_from_mask(mask): + ''' + create an axis-aligned rectangle from a given binary mask + mask in created as a minimal rectangle containing all non-zero pixels + ''' + x_ = np.sum(mask, axis=0) + y_ = np.sum(mask, axis=1) + x0 = np.min(np.nonzero(x_)) + x1 = np.max(np.nonzero(x_)) + y0 = np.min(np.nonzero(y_)) + y1 = np.max(np.nonzero(y_)) + return [x0, y0, x1 - x0 + 1, y1 - y0 + 1] + + +def mask_from_rect(rect, output_sz): + ''' + create a binary mask from a given rectangle + rect: axis-aligned rectangle [x0, y0, width, height] + output_sz: size of the output [width, height] + ''' + mask = np.zeros((output_sz[1], output_sz[0]), dtype=np.uint8) + x0 = max(int(round(rect[0])), 0) + y0 = max(int(round(rect[1])), 0) + x1 = min(int(round(rect[0] + rect[2])), output_sz[0]) + y1 = min(int(round(rect[1] + rect[3])), output_sz[1]) + mask[y0:y1, x0:x1] = 1 + return mask + + +def bbox_clip(x1, y1, x2, y2, boundary, min_sz=10): + '''boundary (H,W)''' + x1_new = max(0, min(x1, boundary[1] - min_sz)) + y1_new = max(0, min(y1, boundary[0] - min_sz)) + x2_new = max(min_sz, min(x2, boundary[1])) + y2_new = max(min_sz, min(y2, boundary[0])) + return x1_new, y1_new, x2_new, y2_new \ No newline at end of file diff --git a/Stark/external/vot20/stark_s50/config.yaml b/Stark/external/vot20/stark_s50/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_s50/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_s50/exp.sh b/Stark/external/vot20/stark_s50/exp.sh new file mode 100755 index 0000000..5b7d561 --- /dev/null +++ b/Stark/external/vot20/stark_s50/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_s50 +vot analysis --workspace . stark_s50 --format html + + diff --git a/Stark/external/vot20/stark_s50/trackers.ini b/Stark/external/vot20/stark_s50/trackers.ini new file mode 100755 index 0000000..8dc76f9 --- /dev/null +++ b/Stark/external/vot20/stark_s50/trackers.ini @@ -0,0 +1,6 @@ +[stark_s50] # +label = stark_s50 +protocol = traxpython +command = stark_s50 +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/lib/test/vot20 diff --git a/Stark/external/vot20/stark_s50_ar/config.yaml b/Stark/external/vot20/stark_s50_ar/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_s50_ar/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_s50_ar/exp.sh b/Stark/external/vot20/stark_s50_ar/exp.sh new file mode 100755 index 0000000..5b57f8d --- /dev/null +++ b/Stark/external/vot20/stark_s50_ar/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_s50_ar +vot analysis --workspace . stark_s50_ar --format html + + diff --git a/Stark/external/vot20/stark_s50_ar/trackers.ini b/Stark/external/vot20/stark_s50_ar/trackers.ini new file mode 100755 index 0000000..c84bbc8 --- /dev/null +++ b/Stark/external/vot20/stark_s50_ar/trackers.ini @@ -0,0 +1,6 @@ +[stark_s50_ar] # +label = stark_s50_ar +protocol = traxpython +command = stark_s50_ar +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP diff --git a/Stark/external/vot20/stark_st101/config.yaml b/Stark/external/vot20/stark_st101/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_st101/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_st101/exp.sh b/Stark/external/vot20/stark_st101/exp.sh new file mode 100755 index 0000000..e206581 --- /dev/null +++ b/Stark/external/vot20/stark_st101/exp.sh @@ -0,0 +1,2 @@ +vot evaluate --workspace . stark_st101 +vot analysis --workspace . stark_st101 --format html \ No newline at end of file diff --git a/Stark/external/vot20/stark_st101/trackers.ini b/Stark/external/vot20/stark_st101/trackers.ini new file mode 100755 index 0000000..f12072d --- /dev/null +++ b/Stark/external/vot20/stark_st101/trackers.ini @@ -0,0 +1,6 @@ +[stark_st101] # +label = stark_st101 +protocol = traxpython +command = stark_st101 +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/lib/test/vot20 diff --git a/Stark/external/vot20/stark_st101_ar/config.yaml b/Stark/external/vot20/stark_st101_ar/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_st101_ar/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_st101_ar/exp.sh b/Stark/external/vot20/stark_st101_ar/exp.sh new file mode 100755 index 0000000..3da2cc3 --- /dev/null +++ b/Stark/external/vot20/stark_st101_ar/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_st101_ar +vot analysis --workspace . stark_st101_ar --format html + + diff --git a/Stark/external/vot20/stark_st101_ar/trackers.ini b/Stark/external/vot20/stark_st101_ar/trackers.ini new file mode 100755 index 0000000..5d216aa --- /dev/null +++ b/Stark/external/vot20/stark_st101_ar/trackers.ini @@ -0,0 +1,6 @@ +[stark_st101_ar] # +label = stark_st101_ar +protocol = traxpython +command = stark_st101_ar +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP diff --git a/Stark/external/vot20/stark_st50/config.yaml b/Stark/external/vot20/stark_st50/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_st50/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_st50/exp.sh b/Stark/external/vot20/stark_st50/exp.sh new file mode 100755 index 0000000..809ab17 --- /dev/null +++ b/Stark/external/vot20/stark_st50/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_st50 +vot analysis --workspace . stark_st50 --format html + + diff --git a/Stark/external/vot20/stark_st50/trackers.ini b/Stark/external/vot20/stark_st50/trackers.ini new file mode 100755 index 0000000..2083e2c --- /dev/null +++ b/Stark/external/vot20/stark_st50/trackers.ini @@ -0,0 +1,6 @@ +[stark_st50] # +label = stark_st50 +protocol = traxpython +command = stark_st50 +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/lib/test/vot20 diff --git a/Stark/external/vot20/stark_st50_ar/config.yaml b/Stark/external/vot20/stark_st50_ar/config.yaml new file mode 100755 index 0000000..2ce38fe --- /dev/null +++ b/Stark/external/vot20/stark_st50_ar/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2020 diff --git a/Stark/external/vot20/stark_st50_ar/exp.sh b/Stark/external/vot20/stark_st50_ar/exp.sh new file mode 100755 index 0000000..76004cd --- /dev/null +++ b/Stark/external/vot20/stark_st50_ar/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_st50_ar +vot analysis --workspace . stark_st50_ar --format html + + diff --git a/Stark/external/vot20/stark_st50_ar/trackers.ini b/Stark/external/vot20/stark_st50_ar/trackers.ini new file mode 100755 index 0000000..e8b11d6 --- /dev/null +++ b/Stark/external/vot20/stark_st50_ar/trackers.ini @@ -0,0 +1,6 @@ +[stark_st50_ar] # +label = stark_st50_ar +protocol = traxpython +command = stark_st50_ar +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/external/AR/pytracking/VOT2020_super_only_mask_384_HP diff --git a/Stark/external/vot20_lt/stark_st101_lt/config.yaml b/Stark/external/vot20_lt/stark_st101_lt/config.yaml new file mode 100755 index 0000000..9f43771 --- /dev/null +++ b/Stark/external/vot20_lt/stark_st101_lt/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: votlt2020 diff --git a/Stark/external/vot20_lt/stark_st101_lt/exp.sh b/Stark/external/vot20_lt/stark_st101_lt/exp.sh new file mode 100755 index 0000000..da934c9 --- /dev/null +++ b/Stark/external/vot20_lt/stark_st101_lt/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_st101_lt +vot analysis --workspace . stark_st101_lt --format html + + diff --git a/Stark/external/vot20_lt/stark_st101_lt/trackers.ini b/Stark/external/vot20_lt/stark_st101_lt/trackers.ini new file mode 100755 index 0000000..bf56c8e --- /dev/null +++ b/Stark/external/vot20_lt/stark_st101_lt/trackers.ini @@ -0,0 +1,6 @@ +[stark_st101_lt] # +label = stark_st101_lt +protocol = traxpython +command = stark_st101_lt +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/lib/test/vot20 diff --git a/Stark/external/vot20_lt/stark_st50_lt/config.yaml b/Stark/external/vot20_lt/stark_st50_lt/config.yaml new file mode 100755 index 0000000..9f43771 --- /dev/null +++ b/Stark/external/vot20_lt/stark_st50_lt/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: votlt2020 diff --git a/Stark/external/vot20_lt/stark_st50_lt/exp.sh b/Stark/external/vot20_lt/stark_st50_lt/exp.sh new file mode 100755 index 0000000..eebfaee --- /dev/null +++ b/Stark/external/vot20_lt/stark_st50_lt/exp.sh @@ -0,0 +1,4 @@ +vot evaluate --workspace . stark_st50_lt +vot analysis --workspace . stark_st50_lt --format html + + diff --git a/Stark/external/vot20_lt/stark_st50_lt/trackers.ini b/Stark/external/vot20_lt/stark_st50_lt/trackers.ini new file mode 100755 index 0000000..04eeba3 --- /dev/null +++ b/Stark/external/vot20_lt/stark_st50_lt/trackers.ini @@ -0,0 +1,6 @@ +[stark_st50_lt] # +label = stark_st50_lt +protocol = traxpython +command = stark_st50_lt +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = /data/sda/v-yanbi/iccv21/MSRA/Stark/lib/test/vot20 diff --git a/Stark/install.sh b/Stark/install.sh new file mode 100755 index 0000000..be4d13e --- /dev/null +++ b/Stark/install.sh @@ -0,0 +1,87 @@ +echo "****************** Installing pytorch ******************" +conda install -y pytorch==1.5.1 torchvision==0.6.1 cudatoolkit=10.2 -c pytorch + +echo "" +echo "" +echo "****************** Installing yaml ******************" +pip install PyYAML + +echo "" +echo "" +echo "****************** Installing easydict ******************" +pip install easydict + +echo "" +echo "" +echo "****************** Installing cython ******************" +pip install cython + +echo "" +echo "" +echo "****************** Installing opencv-python ******************" +pip install opencv-python + +echo "" +echo "" +echo "****************** Installing pandas ******************" +pip install pandas + +echo "" +echo "" +echo "****************** Installing tqdm ******************" +conda install -y tqdm + +echo "" +echo "" +echo "****************** Installing coco toolkit ******************" +pip install pycocotools + +echo "" +echo "" +echo "****************** Installing jpeg4py python wrapper ******************" +apt-get install libturbojpeg +pip install jpeg4py + +echo "" +echo "" +echo "****************** Installing tensorboard ******************" +pip install tb-nightly + +echo "" +echo "" +echo "****************** Installing tikzplotlib ******************" +pip install tikzplotlib + +echo "" +echo "" +echo "****************** Installing thop tool for FLOPs and Params computing ******************" +pip install --upgrade git+https://github.com/Lyken17/pytorch-OpCounter.git + +echo "" +echo "" +echo "****************** Installing colorama ******************" +pip install colorama + +echo "" +echo "" +echo "****************** Installing lmdb ******************" +pip install lmdb + +echo "" +echo "" +echo "****************** Installing scipy ******************" +pip install scipy + +echo "" +echo "" +echo "****************** Installing visdom ******************" +pip install visdom + +echo "" +echo "" +echo "****************** Installing vot-toolkit python ******************" +pip install git+https://github.com/votchallenge/vot-toolkit-python + +echo "" +echo "" +echo "****************** Installation complete! ******************" diff --git a/Stark/lib/__init__.py b/Stark/lib/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/__pycache__/__init__.cpython-37.pyc b/Stark/lib/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..e01e2e0 Binary files /dev/null and b/Stark/lib/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/config/__init__.py b/Stark/lib/config/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/config/__pycache__/__init__.cpython-37.pyc b/Stark/lib/config/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..6c0a24e Binary files /dev/null and b/Stark/lib/config/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/config/stark_s/config.py b/Stark/lib/config/stark_s/config.py new file mode 100755 index 0000000..596385c --- /dev/null +++ b/Stark/lib/config/stark_s/config.py @@ -0,0 +1,130 @@ +from easydict import EasyDict as edict +import yaml + +""" +Add default config for STARK-S. +""" +cfg = edict() + +# MODEL +cfg.MODEL = edict() +cfg.MODEL.HEAD_TYPE = "CORNER" +cfg.MODEL.HIDDEN_DIM = 256 +cfg.MODEL.NUM_OBJECT_QUERIES = 1 +cfg.MODEL.POSITION_EMBEDDING = 'sine' # sine or learned +cfg.MODEL.PREDICT_MASK = False +# MODEL.BACKBONE +cfg.MODEL.BACKBONE = edict() +cfg.MODEL.BACKBONE.TYPE = "resnet50" # resnet50, resnext101_32x8d +cfg.MODEL.BACKBONE.OUTPUT_LAYERS = ["layer3"] +cfg.MODEL.BACKBONE.DILATION = False +# MODEL.TRANSFORMER +cfg.MODEL.TRANSFORMER = edict() +cfg.MODEL.TRANSFORMER.NHEADS = 8 +cfg.MODEL.TRANSFORMER.DROPOUT = 0.1 +cfg.MODEL.TRANSFORMER.DIM_FEEDFORWARD = 2048 +cfg.MODEL.TRANSFORMER.ENC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.DEC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.PRE_NORM = False +cfg.MODEL.TRANSFORMER.DIVIDE_NORM = False + +# TRAIN +cfg.TRAIN = edict() +cfg.TRAIN.LR = 0.0001 +cfg.TRAIN.WEIGHT_DECAY = 0.0001 +cfg.TRAIN.EPOCH = 500 +cfg.TRAIN.LR_DROP_EPOCH = 400 +cfg.TRAIN.BATCH_SIZE = 16 +cfg.TRAIN.NUM_WORKER = 8 +cfg.TRAIN.OPTIMIZER = "ADAMW" +cfg.TRAIN.BACKBONE_MULTIPLIER = 0.1 +cfg.TRAIN.GIOU_WEIGHT = 2.0 +cfg.TRAIN.L1_WEIGHT = 5.0 +cfg.TRAIN.DEEP_SUPERVISION = False +cfg.TRAIN.FREEZE_BACKBONE_BN = True +cfg.TRAIN.FREEZE_LAYERS = ['conv1', 'layer1'] +cfg.TRAIN.PRINT_INTERVAL = 50 +cfg.TRAIN.VAL_EPOCH_INTERVAL = 20 +cfg.TRAIN.GRAD_CLIP_NORM = 0.1 +# TRAIN.SCHEDULER +cfg.TRAIN.SCHEDULER = edict() +cfg.TRAIN.SCHEDULER.TYPE = "step" +cfg.TRAIN.SCHEDULER.DECAY_RATE = 0.1 + +# DATA +cfg.DATA = edict() +cfg.DATA.MEAN = [0.485, 0.456, 0.406] +cfg.DATA.STD = [0.229, 0.224, 0.225] +cfg.DATA.MAX_SAMPLE_INTERVAL = 200 +# DATA.TRAIN +cfg.DATA.TRAIN = edict() +cfg.DATA.TRAIN.DATASETS_NAME = ["LASOT", "GOT10K_vottrain"] +cfg.DATA.TRAIN.DATASETS_RATIO = [1, 1] +cfg.DATA.TRAIN.SAMPLE_PER_EPOCH = 60000 +# DATA.VAL +cfg.DATA.VAL = edict() +cfg.DATA.VAL.DATASETS_NAME = ["GOT10K_votval"] +cfg.DATA.VAL.DATASETS_RATIO = [1] +cfg.DATA.VAL.SAMPLE_PER_EPOCH = 10000 +# DATA.SEARCH +cfg.DATA.SEARCH = edict() +cfg.DATA.SEARCH.SIZE = 320 +cfg.DATA.SEARCH.FACTOR = 5.0 +cfg.DATA.SEARCH.CENTER_JITTER = 4.5 +cfg.DATA.SEARCH.SCALE_JITTER = 0.5 +# DATA.TEMPLATE +cfg.DATA.TEMPLATE = edict() +cfg.DATA.TEMPLATE.SIZE = 128 +cfg.DATA.TEMPLATE.FACTOR = 2.0 +cfg.DATA.TEMPLATE.CENTER_JITTER = 0 +cfg.DATA.TEMPLATE.SCALE_JITTER = 0 + +# TEST +cfg.TEST = edict() +cfg.TEST.TEMPLATE_FACTOR = 2.0 +cfg.TEST.TEMPLATE_SIZE = 128 +cfg.TEST.SEARCH_FACTOR = 5.0 +cfg.TEST.SEARCH_SIZE = 320 +cfg.TEST.EPOCH = 500 + + +def _edict2dict(dest_dict, src_edict): + if isinstance(dest_dict, dict) and isinstance(src_edict, dict): + for k, v in src_edict.items(): + if not isinstance(v, edict): + dest_dict[k] = v + else: + dest_dict[k] = {} + _edict2dict(dest_dict[k], v) + else: + return + + +def gen_config(config_file): + cfg_dict = {} + _edict2dict(cfg_dict, cfg) + with open(config_file, 'w') as f: + yaml.dump(cfg_dict, f, default_flow_style=False) + + +def _update_config(base_cfg, exp_cfg): + if isinstance(base_cfg, dict) and isinstance(exp_cfg, edict): + for k, v in exp_cfg.items(): + if k in base_cfg: + if not isinstance(v, dict): + base_cfg[k] = v + else: + _update_config(base_cfg[k], v) + else: + raise ValueError("{} not exist in config.py".format(k)) + else: + return + + +def update_config_from_file(filename): + exp_config = None + with open(filename) as f: + exp_config = edict(yaml.safe_load(f)) + _update_config(cfg, exp_config) + + diff --git a/Stark/lib/config/stark_st1/config.py b/Stark/lib/config/stark_st1/config.py new file mode 100755 index 0000000..0d86ec0 --- /dev/null +++ b/Stark/lib/config/stark_st1/config.py @@ -0,0 +1,128 @@ +from easydict import EasyDict as edict +import yaml + +""" +Add default config for STARK-ST Stage1. +""" +cfg = edict() + +# MODEL +cfg.MODEL = edict() +cfg.MODEL.HEAD_TYPE = "CORNER" +cfg.MODEL.NLAYER_HEAD = 3 +cfg.MODEL.HIDDEN_DIM = 256 +cfg.MODEL.NUM_OBJECT_QUERIES = 1 +cfg.MODEL.POSITION_EMBEDDING = 'sine' # sine or learned +cfg.MODEL.PREDICT_MASK = False +# MODEL.BACKBONE +cfg.MODEL.BACKBONE = edict() +cfg.MODEL.BACKBONE.TYPE = "resnet50" # resnet50, resnext101_32x8d +cfg.MODEL.BACKBONE.OUTPUT_LAYERS = ["layer3"] +cfg.MODEL.BACKBONE.STRIDE = 16 +cfg.MODEL.BACKBONE.DILATION = False +# MODEL.TRANSFORMER +cfg.MODEL.TRANSFORMER = edict() +cfg.MODEL.TRANSFORMER.NHEADS = 8 +cfg.MODEL.TRANSFORMER.DROPOUT = 0.1 +cfg.MODEL.TRANSFORMER.DIM_FEEDFORWARD = 2048 +cfg.MODEL.TRANSFORMER.ENC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.DEC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.PRE_NORM = False +cfg.MODEL.TRANSFORMER.DIVIDE_NORM = False + +# TRAIN +cfg.TRAIN = edict() +cfg.TRAIN.LR = 0.0001 +cfg.TRAIN.WEIGHT_DECAY = 0.0001 +cfg.TRAIN.EPOCH = 500 +cfg.TRAIN.LR_DROP_EPOCH = 400 +cfg.TRAIN.BATCH_SIZE = 16 +cfg.TRAIN.NUM_WORKER = 8 +cfg.TRAIN.OPTIMIZER = "ADAMW" +cfg.TRAIN.BACKBONE_MULTIPLIER = 0.1 +cfg.TRAIN.GIOU_WEIGHT = 2.0 +cfg.TRAIN.L1_WEIGHT = 5.0 +cfg.TRAIN.DEEP_SUPERVISION = False +cfg.TRAIN.FREEZE_BACKBONE_BN = True +cfg.TRAIN.FREEZE_LAYERS = ['conv1', 'layer1'] +cfg.TRAIN.PRINT_INTERVAL = 50 +cfg.TRAIN.VAL_EPOCH_INTERVAL = 20 +cfg.TRAIN.GRAD_CLIP_NORM = 0.1 +# TRAIN.SCHEDULER +cfg.TRAIN.SCHEDULER = edict() +cfg.TRAIN.SCHEDULER.TYPE = "step" +cfg.TRAIN.SCHEDULER.DECAY_RATE = 0.1 + +# DATA +cfg.DATA = edict() +cfg.DATA.SAMPLER_MODE = "trident_pro" # sampling methods +cfg.DATA.MEAN = [0.485, 0.456, 0.406] +cfg.DATA.STD = [0.229, 0.224, 0.225] +cfg.DATA.MAX_SAMPLE_INTERVAL = [200] +# DATA.TRAIN +cfg.DATA.TRAIN = edict() +cfg.DATA.TRAIN.DATASETS_NAME = ["LASOT", "GOT10K_vottrain"] +cfg.DATA.TRAIN.DATASETS_RATIO = [1, 1] +cfg.DATA.TRAIN.SAMPLE_PER_EPOCH = 60000 +# DATA.VAL +cfg.DATA.VAL = edict() +cfg.DATA.VAL.DATASETS_NAME = ["GOT10K_votval"] +cfg.DATA.VAL.DATASETS_RATIO = [1] +cfg.DATA.VAL.SAMPLE_PER_EPOCH = 10000 +# DATA.SEARCH +cfg.DATA.SEARCH = edict() +cfg.DATA.SEARCH.NUMBER = 1 # number of search frames for multiple frames training +cfg.DATA.SEARCH.SIZE = 320 +cfg.DATA.SEARCH.FACTOR = 5.0 +cfg.DATA.SEARCH.CENTER_JITTER = 4.5 +cfg.DATA.SEARCH.SCALE_JITTER = 0.5 +# DATA.TEMPLATE +cfg.DATA.TEMPLATE = edict() +cfg.DATA.TEMPLATE.NUMBER = 2 +cfg.DATA.TEMPLATE.SIZE = 128 +cfg.DATA.TEMPLATE.FACTOR = 2.0 +cfg.DATA.TEMPLATE.CENTER_JITTER = 0 +cfg.DATA.TEMPLATE.SCALE_JITTER = 0 + + + +def _edict2dict(dest_dict, src_edict): + if isinstance(dest_dict, dict) and isinstance(src_edict, dict): + for k, v in src_edict.items(): + if not isinstance(v, edict): + dest_dict[k] = v + else: + dest_dict[k] = {} + _edict2dict(dest_dict[k], v) + else: + return + + +def gen_config(config_file): + cfg_dict = {} + _edict2dict(cfg_dict, cfg) + with open(config_file, 'w') as f: + yaml.dump(cfg_dict, f, default_flow_style=False) + + +def _update_config(base_cfg, exp_cfg): + if isinstance(base_cfg, dict) and isinstance(exp_cfg, edict): + for k, v in exp_cfg.items(): + if k in base_cfg: + if not isinstance(v, dict): + base_cfg[k] = v + else: + _update_config(base_cfg[k], v) + else: + raise ValueError("{} not exist in config.py".format(k)) + else: + return + + +def update_config_from_file(filename): + exp_config = None + with open(filename) as f: + exp_config = edict(yaml.safe_load(f)) + _update_config(cfg, exp_config) + + diff --git a/Stark/lib/config/stark_st2/__pycache__/config.cpython-37.pyc b/Stark/lib/config/stark_st2/__pycache__/config.cpython-37.pyc new file mode 100755 index 0000000..8ab987e Binary files /dev/null and b/Stark/lib/config/stark_st2/__pycache__/config.cpython-37.pyc differ diff --git a/Stark/lib/config/stark_st2/config.py b/Stark/lib/config/stark_st2/config.py new file mode 100755 index 0000000..23f3095 --- /dev/null +++ b/Stark/lib/config/stark_st2/config.py @@ -0,0 +1,142 @@ +from easydict import EasyDict as edict +import yaml + +""" +Add default config for STARK-ST Stage2. +""" +cfg = edict() + +# MODEL +cfg.MODEL = edict() +cfg.MODEL.HEAD_TYPE = "CORNER" +cfg.MODEL.NLAYER_HEAD = 3 +cfg.MODEL.HIDDEN_DIM = 256 +cfg.MODEL.NUM_OBJECT_QUERIES = 1 +cfg.MODEL.POSITION_EMBEDDING = 'sine' # sine or learned +cfg.MODEL.PREDICT_MASK = False +# MODEL.BACKBONE +cfg.MODEL.BACKBONE = edict() +cfg.MODEL.BACKBONE.TYPE = "resnet50" # resnet50, resnext101_32x8d +cfg.MODEL.BACKBONE.OUTPUT_LAYERS = ["layer3"] +cfg.MODEL.BACKBONE.STRIDE = 16 +cfg.MODEL.BACKBONE.DILATION = False +# MODEL.TRANSFORMER +cfg.MODEL.TRANSFORMER = edict() +cfg.MODEL.TRANSFORMER.NHEADS = 8 +cfg.MODEL.TRANSFORMER.DROPOUT = 0.1 +cfg.MODEL.TRANSFORMER.DIM_FEEDFORWARD = 2048 +cfg.MODEL.TRANSFORMER.ENC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.DEC_LAYERS = 6 +cfg.MODEL.TRANSFORMER.PRE_NORM = False +cfg.MODEL.TRANSFORMER.DIVIDE_NORM = False + +# TRAIN +cfg.TRAIN = edict() +cfg.TRAIN.TRAIN_CLS = True +cfg.TRAIN.LR = 0.0001 +cfg.TRAIN.WEIGHT_DECAY = 0.0001 +cfg.TRAIN.EPOCH = 500 +cfg.TRAIN.LR_DROP_EPOCH = 400 +cfg.TRAIN.BATCH_SIZE = 16 +cfg.TRAIN.NUM_WORKER = 8 +cfg.TRAIN.OPTIMIZER = "ADAMW" +cfg.TRAIN.BACKBONE_MULTIPLIER = 0.1 +cfg.TRAIN.GIOU_WEIGHT = 2.0 +cfg.TRAIN.L1_WEIGHT = 5.0 +cfg.TRAIN.DEEP_SUPERVISION = False +cfg.TRAIN.FREEZE_BACKBONE_BN = True +cfg.TRAIN.FREEZE_LAYERS = ['conv1', 'layer1'] +cfg.TRAIN.PRINT_INTERVAL = 50 +cfg.TRAIN.VAL_EPOCH_INTERVAL = 20 +cfg.TRAIN.GRAD_CLIP_NORM = 0.1 +# TRAIN.SCHEDULER +cfg.TRAIN.SCHEDULER = edict() +cfg.TRAIN.SCHEDULER.TYPE = "step" +cfg.TRAIN.SCHEDULER.DECAY_RATE = 0.1 + +# DATA +cfg.DATA = edict() +cfg.DATA.SAMPLER_MODE = "trident_pro" # sampling methods +cfg.DATA.MEAN = [0.485, 0.456, 0.406] +cfg.DATA.STD = [0.229, 0.224, 0.225] +cfg.DATA.MAX_SAMPLE_INTERVAL = [200] +# DATA.TRAIN +cfg.DATA.TRAIN = edict() +cfg.DATA.TRAIN.DATASETS_NAME = ["LASOT", "GOT10K_vottrain"] +cfg.DATA.TRAIN.DATASETS_RATIO = [1, 1] +cfg.DATA.TRAIN.SAMPLE_PER_EPOCH = 60000 +# DATA.VAL +cfg.DATA.VAL = edict() +cfg.DATA.VAL.DATASETS_NAME = ["GOT10K_votval"] +cfg.DATA.VAL.DATASETS_RATIO = [1] +cfg.DATA.VAL.SAMPLE_PER_EPOCH = 10000 +# DATA.SEARCH +cfg.DATA.SEARCH = edict() +cfg.DATA.SEARCH.NUMBER = 1 # number of search frames for multiple frames training +cfg.DATA.SEARCH.SIZE = 320 +cfg.DATA.SEARCH.FACTOR = 5.0 +cfg.DATA.SEARCH.CENTER_JITTER = 4.5 +cfg.DATA.SEARCH.SCALE_JITTER = 0.5 +# DATA.TEMPLATE +cfg.DATA.TEMPLATE = edict() +cfg.DATA.TEMPLATE.NUMBER = 2 +cfg.DATA.TEMPLATE.SIZE = 128 +cfg.DATA.TEMPLATE.FACTOR = 2.0 +cfg.DATA.TEMPLATE.CENTER_JITTER = 0 +cfg.DATA.TEMPLATE.SCALE_JITTER = 0 + +# TEST +cfg.TEST = edict() +cfg.TEST.TEMPLATE_FACTOR = 2.0 +cfg.TEST.TEMPLATE_SIZE = 128 +cfg.TEST.SEARCH_FACTOR = 5.0 +cfg.TEST.SEARCH_SIZE = 320 +cfg.TEST.EPOCH = 500 +cfg.TEST.UPDATE_INTERVALS = edict() +cfg.TEST.UPDATE_INTERVALS.LASOT = [200] +cfg.TEST.UPDATE_INTERVALS.GOT10K_TEST = [200] +cfg.TEST.UPDATE_INTERVALS.TRACKINGNET = [200] +cfg.TEST.UPDATE_INTERVALS.VOT20 = [200] +cfg.TEST.UPDATE_INTERVALS.VOT20LT = [200] + + +def _edict2dict(dest_dict, src_edict): + if isinstance(dest_dict, dict) and isinstance(src_edict, dict): + for k, v in src_edict.items(): + if not isinstance(v, edict): + dest_dict[k] = v + else: + dest_dict[k] = {} + _edict2dict(dest_dict[k], v) + else: + return + + +def gen_config(config_file): + cfg_dict = {} + _edict2dict(cfg_dict, cfg) + with open(config_file, 'w') as f: + yaml.dump(cfg_dict, f, default_flow_style=False) + + +def _update_config(base_cfg, exp_cfg): + if isinstance(base_cfg, dict) and isinstance(exp_cfg, edict): + for k, v in exp_cfg.items(): + if k in base_cfg: + if not isinstance(v, dict): + base_cfg[k] = v + else: + _update_config(base_cfg[k], v) + else: + raise ValueError("{} not exist in config.py".format(k)) + else: + return + + +def update_config_from_file(filename): + exp_config = None + with open(filename) as f: + exp_config = edict(yaml.safe_load(f)) + _update_config(cfg, exp_config) + + diff --git a/Stark/lib/models/__init__.py b/Stark/lib/models/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/models/__pycache__/__init__.cpython-37.pyc b/Stark/lib/models/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..00794b1 Binary files /dev/null and b/Stark/lib/models/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__init__.py b/Stark/lib/models/stark/__init__.py new file mode 100755 index 0000000..6646e77 --- /dev/null +++ b/Stark/lib/models/stark/__init__.py @@ -0,0 +1,2 @@ +from .stark_s import build_starks +from .stark_st import build_starkst diff --git a/Stark/lib/models/stark/__pycache__/__init__.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..2cf940a Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/backbone.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/backbone.cpython-37.pyc new file mode 100755 index 0000000..aa56ba1 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/backbone.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/head.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/head.cpython-37.pyc new file mode 100755 index 0000000..1b2ed30 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/head.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/position_encoding.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/position_encoding.cpython-37.pyc new file mode 100755 index 0000000..4bf09a8 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/position_encoding.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/resnet.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/resnet.cpython-37.pyc new file mode 100755 index 0000000..4470ee6 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/resnet.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/stark_s.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/stark_s.cpython-37.pyc new file mode 100755 index 0000000..5e35f58 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/stark_s.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/stark_st.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/stark_st.cpython-37.pyc new file mode 100755 index 0000000..f9dc997 Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/stark_st.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/__pycache__/transformer.cpython-37.pyc b/Stark/lib/models/stark/__pycache__/transformer.cpython-37.pyc new file mode 100755 index 0000000..e71152b Binary files /dev/null and b/Stark/lib/models/stark/__pycache__/transformer.cpython-37.pyc differ diff --git a/Stark/lib/models/stark/backbone.py b/Stark/lib/models/stark/backbone.py new file mode 100755 index 0000000..6c0910f --- /dev/null +++ b/Stark/lib/models/stark/backbone.py @@ -0,0 +1,120 @@ +""" +Backbone modules. +""" + +import torch +import torch.nn.functional as F +from torch import nn +from torchvision.models._utils import IntermediateLayerGetter +from typing import Dict, List +from lib.utils.misc import NestedTensor, is_main_process +from .position_encoding import build_position_encoding +from lib.models.stark import resnet as resnet_module + + +class FrozenBatchNorm2d(torch.nn.Module): + """ + BatchNorm2d where the batch statistics and the affine parameters are fixed. + + Copy-paste from torchvision.misc.ops with added eps before rqsrt, + without which any other models than torchvision.models.resnet[18,34,50,101] + produce nans. + """ + + def __init__(self, n): + super(FrozenBatchNorm2d, self).__init__() + self.register_buffer("weight", torch.ones(n)) + self.register_buffer("bias", torch.zeros(n)) + self.register_buffer("running_mean", torch.zeros(n)) + self.register_buffer("running_var", torch.ones(n)) + + def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict, + missing_keys, unexpected_keys, error_msgs): + num_batches_tracked_key = prefix + 'num_batches_tracked' + if num_batches_tracked_key in state_dict: + del state_dict[num_batches_tracked_key] + + super(FrozenBatchNorm2d, self)._load_from_state_dict( + state_dict, prefix, local_metadata, strict, + missing_keys, unexpected_keys, error_msgs) + + def forward(self, x): + # move reshapes to the beginning + # to make it fuser-friendly + w = self.weight.reshape(1, -1, 1, 1) + b = self.bias.reshape(1, -1, 1, 1) + rv = self.running_var.reshape(1, -1, 1, 1) + rm = self.running_mean.reshape(1, -1, 1, 1) + eps = 1e-5 + scale = w * (rv + eps).rsqrt() # rsqrt(x): 1/sqrt(x), r: reciprocal + bias = b - rm * scale + return x * scale + bias + + +class BackboneBase(nn.Module): + + def __init__(self, backbone: nn.Module, train_backbone: bool, num_channels: int, return_interm_layers: bool): + super().__init__() + for name, parameter in backbone.named_parameters(): + if not train_backbone or 'layer2' not in name and 'layer3' not in name: + parameter.requires_grad_(False) # here should allow users to specify which layers to freeze ! + # print('freeze %s'%name) + if return_interm_layers: + return_layers = {"layer1": "0", "layer2": "1", "layer3": "2"} # stride = 4, 8, 16 + else: + return_layers = {'layer3': "0"} # stride = 16 + self.body = IntermediateLayerGetter(backbone, return_layers=return_layers) # method in torchvision + self.num_channels = num_channels + + def forward(self, tensor_list: NestedTensor): + xs = self.body(tensor_list.tensors) + out: Dict[str, NestedTensor] = {} + for name, x in xs.items(): + m = tensor_list.mask + assert m is not None + mask = F.interpolate(m[None].float(), size=x.shape[-2:]).to(torch.bool)[0] + out[name] = NestedTensor(x, mask) + return out + + +class Backbone(BackboneBase): + """ResNet backbone with frozen BatchNorm.""" + def __init__(self, name: str, + train_backbone: bool, + return_interm_layers: bool, + dilation: bool, + freeze_bn: bool): + norm_layer = FrozenBatchNorm2d if freeze_bn else nn.BatchNorm2d + # here is different from the original DETR because we use feature from block3 + backbone = getattr(resnet_module, name)( + replace_stride_with_dilation=[False, dilation, False], + pretrained=is_main_process(), norm_layer=norm_layer, last_layer='layer3') + num_channels = 256 if name in ('resnet18', 'resnet34') else 1024 + super().__init__(backbone, train_backbone, num_channels, return_interm_layers) + + +class Joiner(nn.Sequential): + def __init__(self, backbone, position_embedding): + super().__init__(backbone, position_embedding) + + def forward(self, tensor_list: NestedTensor, mode=None): + xs = self[0](tensor_list) + out: List[NestedTensor] = [] + pos = [] + for name, x in xs.items(): + out.append(x) + # position encoding + pos.append(self[1](x).to(x.tensors.dtype)) + + return out, pos + + +def build_backbone(cfg): + position_embedding = build_position_encoding(cfg) + train_backbone = cfg.TRAIN.BACKBONE_MULTIPLIER > 0 + return_interm_layers = cfg.MODEL.PREDICT_MASK + backbone = Backbone(cfg.MODEL.BACKBONE.TYPE, train_backbone, return_interm_layers, + cfg.MODEL.BACKBONE.DILATION, cfg.TRAIN.FREEZE_BACKBONE_BN) + model = Joiner(backbone, position_embedding) + model.num_channels = backbone.num_channels + return model diff --git a/Stark/lib/models/stark/head.py b/Stark/lib/models/stark/head.py new file mode 100755 index 0000000..85b3560 --- /dev/null +++ b/Stark/lib/models/stark/head.py @@ -0,0 +1,115 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +from lib.models.stark.backbone import FrozenBatchNorm2d + + +def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1, + freeze_bn=False): + if freeze_bn: + return nn.Sequential( + nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=True), + FrozenBatchNorm2d(out_planes), + nn.ReLU(inplace=True)) + else: + return nn.Sequential( + nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=True), + nn.BatchNorm2d(out_planes), + nn.ReLU(inplace=True)) + + +class Corner_Predictor(nn.Module): + """ Corner Predictor module""" + def __init__(self, inplanes=64, channel=256, feat_sz=20, stride=16, freeze_bn=False): + super(Corner_Predictor, self).__init__() + self.feat_sz = feat_sz + self.stride = stride + self.img_sz = self.feat_sz * self.stride + '''top-left corner''' + self.conv1_tl = conv(inplanes, channel, freeze_bn=freeze_bn) + self.conv2_tl = conv(channel, channel // 2, freeze_bn=freeze_bn) + self.conv3_tl = conv(channel // 2, channel // 4, freeze_bn=freeze_bn) + self.conv4_tl = conv(channel // 4, channel // 8, freeze_bn=freeze_bn) + self.conv5_tl = nn.Conv2d(channel // 8, 1, kernel_size=1) + + '''bottom-right corner''' + self.conv1_br = conv(inplanes, channel, freeze_bn=freeze_bn) + self.conv2_br = conv(channel, channel // 2, freeze_bn=freeze_bn) + self.conv3_br = conv(channel // 2, channel // 4, freeze_bn=freeze_bn) + self.conv4_br = conv(channel // 4, channel // 8, freeze_bn=freeze_bn) + self.conv5_br = nn.Conv2d(channel // 8, 1, kernel_size=1) + + '''about coordinates and indexs''' + with torch.no_grad(): + self.indice = torch.arange(0, self.feat_sz).view(-1, 1) * self.stride + # generate mesh-grid + self.coord_x = self.indice.repeat((self.feat_sz, 1)) \ + .view((self.feat_sz * self.feat_sz,)).float().cuda() + self.coord_y = self.indice.repeat((1, self.feat_sz)) \ + .view((self.feat_sz * self.feat_sz,)).float().cuda() + + def forward(self, x): + """ Forward pass with input x. """ + score_map_tl, score_map_br = self.get_score_map(x) + coorx_tl, coory_tl = self.soft_argmax(score_map_tl) + coorx_br, coory_br = self.soft_argmax(score_map_br) + return torch.stack((coorx_tl, coory_tl, coorx_br, coory_br), dim=1) / self.img_sz + + def get_score_map(self, x): + # top-left branch + x_tl1 = self.conv1_tl(x) + x_tl2 = self.conv2_tl(x_tl1) + x_tl3 = self.conv3_tl(x_tl2) + x_tl4 = self.conv4_tl(x_tl3) + score_map_tl = self.conv5_tl(x_tl4) + + # bottom-right branch + x_br1 = self.conv1_br(x) + x_br2 = self.conv2_br(x_br1) + x_br3 = self.conv3_br(x_br2) + x_br4 = self.conv4_br(x_br3) + score_map_br = self.conv5_br(x_br4) + return score_map_tl, score_map_br + + def soft_argmax(self, score_map): + """ get soft-argmax coordinate for a given heatmap """ + prob_vec = nn.functional.softmax( + score_map.view((-1, self.feat_sz * self.feat_sz)), dim=1) # (batch, feat_sz * feat_sz) + exp_x = torch.sum((self.coord_x * prob_vec), dim=1) + exp_y = torch.sum((self.coord_y * prob_vec), dim=1) + return exp_x, exp_y + + +class MLP(nn.Module): + """ Very simple multi-layer perceptron (also called FFN)""" + + def __init__(self, input_dim, hidden_dim, output_dim, num_layers): + super().__init__() + self.num_layers = num_layers + h = [hidden_dim] * (num_layers - 1) + self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim])) + + def forward(self, x): + for i, layer in enumerate(self.layers): + x = F.relu(layer(x)) if i < self.num_layers - 1 else layer(x) + return x + + +def build_box_head(cfg): + if cfg.MODEL.HEAD_TYPE == "MLP": + hidden_dim = cfg.MODEL.HIDDEN_DIM + mlp_head = MLP(hidden_dim, hidden_dim, 4, 3) # dim_in, dim_hidden, dim_out, 3 layers + return mlp_head + elif cfg.MODEL.HEAD_TYPE == "CORNER": + if cfg.MODEL.BACKBONE.DILATION is False: + stride = 16 + else: + stride = 8 + feat_sz = int(cfg.DATA.SEARCH.SIZE / stride) + corner_head = Corner_Predictor(inplanes=cfg.MODEL.HIDDEN_DIM, channel=256, + feat_sz=feat_sz, stride=stride) + return corner_head + else: + raise ValueError("HEAD TYPE %s is not supported." % cfg.MODEL.HEAD_TYPE) \ No newline at end of file diff --git a/Stark/lib/models/stark/position_encoding.py b/Stark/lib/models/stark/position_encoding.py new file mode 100755 index 0000000..e1c3c62 --- /dev/null +++ b/Stark/lib/models/stark/position_encoding.py @@ -0,0 +1,105 @@ +""" +Various positional encodings for the transformer. +""" +import math +import torch +from torch import nn + +from lib.utils.misc import NestedTensor + + +class PositionEmbeddingSine(nn.Module): + """ + This is a more standard version of the position embedding, very similar to the one + used by the Attention is all you need paper, generalized to work on images. + """ + def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None): + super().__init__() + self.num_pos_feats = num_pos_feats + self.temperature = temperature + self.normalize = normalize + if scale is not None and normalize is False: + raise ValueError("normalize should be True if scale is passed") + if scale is None: + scale = 2 * math.pi + self.scale = scale + + def forward(self, tensor_list: NestedTensor): + x = tensor_list.tensors + mask = tensor_list.mask + assert mask is not None + not_mask = ~mask # (b,h,w) + y_embed = not_mask.cumsum(1, dtype=torch.float32) # cumulative sum along axis 1 (h axis) --> (b, h, w) + x_embed = not_mask.cumsum(2, dtype=torch.float32) # cumulative sum along axis 2 (w axis) --> (b, h, w) + if self.normalize: + eps = 1e-6 + y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale # 2pi * (y / sigma(y)) + x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale # 2pi * (x / sigma(x)) + + dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device) # (0,1,2,...,d/2) + dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats) + + pos_x = x_embed[:, :, :, None] / dim_t # (b,h,w,d/2) + pos_y = y_embed[:, :, :, None] / dim_t # (b,h,w,d/2) + pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2) + pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) # (b,h,w,d/2) + pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) # (b,h,w,d) + return pos + + +class PositionEmbeddingLearned(nn.Module): + """ + Absolute pos embedding, learned. + """ + def __init__(self, num_pos_feats=256): + super().__init__() + self.row_embed = nn.Embedding(50, num_pos_feats) + self.col_embed = nn.Embedding(50, num_pos_feats) + self.reset_parameters() + + def reset_parameters(self): + nn.init.uniform_(self.row_embed.weight) + nn.init.uniform_(self.col_embed.weight) + + def forward(self, tensor_list: NestedTensor): + x = tensor_list.tensors + h, w = x.shape[-2:] + i = torch.arange(w, device=x.device) + j = torch.arange(h, device=x.device) + x_emb = self.col_embed(i) + y_emb = self.row_embed(j) + pos = torch.cat([ + x_emb.unsqueeze(0).repeat(h, 1, 1), + y_emb.unsqueeze(1).repeat(1, w, 1), + ], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(x.shape[0], 1, 1, 1) + return pos # (H,W,C) --> (C,H,W) --> (1,C,H,W) --> (B,C,H,W) + + +class PositionEmbeddingNone(nn.Module): + """ + No positional encoding. + """ + def __init__(self, num_pos_feats=256): + super().__init__() + self.n_dim = num_pos_feats * 2 + + def forward(self, tensor_list: NestedTensor): + x = tensor_list.tensors + b, _, h, w = x.size() + return torch.zeros((b, self.n_dim, h, w), device=x.device) # (B, C, H, W) + + +def build_position_encoding(cfg): + N_steps = cfg.MODEL.HIDDEN_DIM // 2 + if cfg.MODEL.POSITION_EMBEDDING in ('v2', 'sine'): + # TODO find a better way of exposing other arguments + position_embedding = PositionEmbeddingSine(N_steps, normalize=True) + elif cfg.MODEL.POSITION_EMBEDDING in ('v3', 'learned'): + position_embedding = PositionEmbeddingLearned(N_steps) + elif cfg.MODEL.POSITION_EMBEDDING in ('None', ): + print("Not using positional encoding.") + position_embedding = PositionEmbeddingNone(N_steps) + else: + raise ValueError(f"not supported {cfg.MODEL.POSITION_EMBEDDING}") + + return position_embedding diff --git a/Stark/lib/models/stark/resnet.py b/Stark/lib/models/stark/resnet.py new file mode 100755 index 0000000..17f065f --- /dev/null +++ b/Stark/lib/models/stark/resnet.py @@ -0,0 +1,276 @@ +import torch +import torch.nn as nn +from torchvision.models.utils import load_state_dict_from_url +from torchvision.models.resnet import BasicBlock, Bottleneck, conv1x1, conv3x3 +'''2021.1.5 Modified from torchvision.models.resnet +Now the +''' + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152', 'resnext50_32x4d', 'resnext101_32x8d', + 'wide_resnet50_2', 'wide_resnet101_2'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', + 'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth', + 'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth', + 'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth', + 'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth', +} + + +class ResNet(nn.Module): + + def __init__(self, block, layers, num_classes=1000, zero_init_residual=False, + groups=1, width_per_group=64, replace_stride_with_dilation=None, + norm_layer=None, last_layer=None): + super(ResNet, self).__init__() + assert last_layer in ['layer1', 'layer2', 'layer3', 'layer4', 'fc'] + self.last_layer = last_layer + if norm_layer is None: + norm_layer = nn.BatchNorm2d + self._norm_layer = norm_layer + + self.inplanes = 64 + self.dilation = 1 + if replace_stride_with_dilation is None: + # each element in the tuple indicates if we should replace + # the 2x2 stride with a dilated convolution instead + replace_stride_with_dilation = [False, False, False] + if len(replace_stride_with_dilation) != 3: + raise ValueError("replace_stride_with_dilation should be None " + "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) + self.groups = groups + self.base_width = width_per_group + self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = norm_layer(self.inplanes) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + if self.last_layer != 'layer1': + self.layer2 = self._make_layer(block, 128, layers[1], stride=2, + dilate=replace_stride_with_dilation[0]) + if self.last_layer != 'layer2': + self.layer3 = self._make_layer(block, 256, layers[2], stride=2, + dilate=replace_stride_with_dilation[1]) + if self.last_layer != 'layer3': + self.layer4 = self._make_layer(block, 512, layers[3], stride=2, + dilate=replace_stride_with_dilation[2]) + if self.last_layer != 'layer4': + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + + # Zero-initialize the last BN in each residual branch, + # so that the residual branch starts with zeros, and each residual block behaves like an identity. + # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 + if zero_init_residual: + for m in self.modules(): + if isinstance(m, Bottleneck): + nn.init.constant_(m.bn3.weight, 0) + elif isinstance(m, BasicBlock): + nn.init.constant_(m.bn2.weight, 0) + + def _make_layer(self, block, planes, blocks, stride=1, dilate=False): + norm_layer = self._norm_layer + downsample = None + previous_dilation = self.dilation + if dilate: + self.dilation *= stride + stride = 1 + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + conv1x1(self.inplanes, planes * block.expansion, stride), + norm_layer(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample, self.groups, + self.base_width, previous_dilation, norm_layer)) + self.inplanes = planes * block.expansion + for _ in range(1, blocks): + layers.append(block(self.inplanes, planes, groups=self.groups, + base_width=self.base_width, dilation=self.dilation, + norm_layer=norm_layer)) + + return nn.Sequential(*layers) + + def _forward_impl(self, x): + # See note [TorchScript super()] + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + if self.last_layer != 'layer1': + x = self.layer2(x) + if self.last_layer != 'layer2': + x = self.layer3(x) + if self.last_layer != 'layer3': + x = self.layer4(x) + if self.last_layer != 'layer4': + x = self.avgpool(x) + x = torch.flatten(x, 1) + x = self.fc(x) + + return x + + def forward(self, x): + return self._forward_impl(x) + + +def _resnet(arch, block, layers, pretrained, progress, **kwargs): + model = ResNet(block, layers, **kwargs) + if pretrained: + state_dict = load_state_dict_from_url(model_urls[arch], + progress=progress) + try: + model.load_state_dict(state_dict) + except: + # model_keys = model.state_dict().keys() + # checkpoint_keys = state_dict.keys() + # for key in model_keys: + # if key not in checkpoint_keys: + # print("key %s is not found in the checkpoint." % key) + # for key in checkpoint_keys: + # if key not in model_keys: + # print("the checkpoint contains additional key %s" % key) + model.load_state_dict(state_dict, strict=False) + return model + + +def resnet18(pretrained=False, progress=True, **kwargs): + r"""ResNet-18 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress, + **kwargs) + + +def resnet34(pretrained=False, progress=True, **kwargs): + r"""ResNet-34 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress, + **kwargs) + + +def resnet50(pretrained=False, progress=True, **kwargs): + r"""ResNet-50 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress, + **kwargs) + + +def resnet101(pretrained=False, progress=True, **kwargs): + r"""ResNet-101 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress, + **kwargs) + + +def resnet152(pretrained=False, progress=True, **kwargs): + r"""ResNet-152 model from + `"Deep Residual Learning for Image Recognition" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress, + **kwargs) + + +def resnext50_32x4d(pretrained=False, progress=True, **kwargs): + r"""ResNeXt-50 32x4d model from + `"Aggregated Residual Transformation for Deep Neural Networks" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 4 + return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3], + pretrained, progress, **kwargs) + + +def resnext101_32x8d(pretrained=False, progress=True, **kwargs): + r"""ResNeXt-101 32x8d model from + `"Aggregated Residual Transformation for Deep Neural Networks" `_ + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['groups'] = 32 + kwargs['width_per_group'] = 8 + return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3], + pretrained, progress, **kwargs) + + +def wide_resnet50_2(pretrained=False, progress=True, **kwargs): + r"""Wide ResNet-50-2 model from + `"Wide Residual Networks" `_ + + The model is the same as ResNet except for the bottleneck number of channels + which is twice larger in every block. The number of channels in outer 1x1 + convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 + channels, and in Wide ResNet-50-2 has 2048-1024-2048. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['width_per_group'] = 64 * 2 + return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3], + pretrained, progress, **kwargs) + + +def wide_resnet101_2(pretrained=False, progress=True, **kwargs): + r"""Wide ResNet-101-2 model from + `"Wide Residual Networks" `_ + + The model is the same as ResNet except for the bottleneck number of channels + which is twice larger in every block. The number of channels in outer 1x1 + convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048 + channels, and in Wide ResNet-50-2 has 2048-1024-2048. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + progress (bool): If True, displays a progress bar of the download to stderr + """ + kwargs['width_per_group'] = 64 * 2 + return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3], + pretrained, progress, **kwargs) diff --git a/Stark/lib/models/stark/stark_s.py b/Stark/lib/models/stark/stark_s.py new file mode 100755 index 0000000..c825aa7 --- /dev/null +++ b/Stark/lib/models/stark/stark_s.py @@ -0,0 +1,129 @@ +""" +Basic STARK Model (Spatial-only). +""" +import torch +from torch import nn + +from lib.utils.misc import NestedTensor + +from .backbone import build_backbone +from .transformer import build_transformer +from .head import build_box_head +from lib.utils.box_ops import box_xyxy_to_cxcywh + + +class STARKS(nn.Module): + """ This is the base class for Transformer Tracking """ + def __init__(self, backbone, transformer, box_head, num_queries, + aux_loss=False, head_type="CORNER"): + """ Initializes the model. + Parameters: + backbone: torch module of the backbone to be used. See backbone.py + transformer: torch module of the transformer architecture. See transformer.py + num_queries: number of object queries. + aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used. + """ + super().__init__() + self.backbone = backbone + self.transformer = transformer + self.box_head = box_head + self.num_queries = num_queries + hidden_dim = transformer.d_model + self.query_embed = nn.Embedding(num_queries, hidden_dim) # object queries + self.bottleneck = nn.Conv2d(backbone.num_channels, hidden_dim, kernel_size=1) # the bottleneck layer + self.aux_loss = aux_loss + self.head_type = head_type + if head_type == "CORNER": + self.feat_sz_s = int(box_head.feat_sz) + self.feat_len_s = int(box_head.feat_sz ** 2) + + def forward(self, img=None, seq_dict=None, mode="backbone", run_box_head=True, run_cls_head=False): + if mode == "backbone": + return self.forward_backbone(img) + elif mode == "transformer": + return self.forward_transformer(seq_dict, run_box_head=run_box_head, run_cls_head=run_cls_head) + else: + raise ValueError + + def forward_backbone(self, input: NestedTensor): + """The input type is NestedTensor, which consists of: + - tensor: batched images, of shape [batch_size x 3 x H x W] + - mask: a binary mask of shape [batch_size x H x W], containing 1 on padded pixels + """ + assert isinstance(input, NestedTensor) + # Forward the backbone + output_back, pos = self.backbone(input) # features & masks, position embedding for the search + # Adjust the shapes + return self.adjust(output_back, pos) + + def forward_transformer(self, seq_dict, run_box_head=True, run_cls_head=False): + if self.aux_loss: + raise ValueError("Deep supervision is not supported.") + # Forward the transformer encoder and decoder + output_embed, enc_mem = self.transformer(seq_dict["feat"], seq_dict["mask"], self.query_embed.weight, + seq_dict["pos"], return_encoder_output=True) + # Forward the corner head + out, outputs_coord = self.forward_box_head(output_embed, enc_mem) + return out, outputs_coord, output_embed + + def forward_box_head(self, hs, memory): + """ + hs: output embeddings (1, B, N, C) + memory: encoder embeddings (HW1+HW2, B, C)""" + if self.head_type == "CORNER": + # adjust shape + enc_opt = memory[-self.feat_len_s:].transpose(0, 1) # encoder output for the search region (B, HW, C) + dec_opt = hs.squeeze(0).transpose(1, 2) # (B, C, N) + att = torch.matmul(enc_opt, dec_opt) # (B, HW, N) + opt = (enc_opt.unsqueeze(-1) * att.unsqueeze(-2)).permute((0, 3, 2, 1)).contiguous() # (B, HW, C, N) --> (B, N, C, HW) + bs, Nq, C, HW = opt.size() + opt_feat = opt.view(-1, C, self.feat_sz_s, self.feat_sz_s) + # run the corner head + outputs_coord = box_xyxy_to_cxcywh(self.box_head(opt_feat)) + outputs_coord_new = outputs_coord.view(bs, Nq, 4) + out = {'pred_boxes': outputs_coord_new} + return out, outputs_coord_new + elif self.head_type == "MLP": + # Forward the class and box head + outputs_coord = self.box_head(hs).sigmoid() + out = {'pred_boxes': outputs_coord[-1]} + if self.aux_loss: + out['aux_outputs'] = self._set_aux_loss(outputs_coord) + return out, outputs_coord + + def adjust(self, output_back: list, pos_embed: list): + """ + """ + src_feat, mask = output_back[-1].decompose() + assert mask is not None + # reduce channel + feat = self.bottleneck(src_feat) # (B, C, H, W) + # adjust shapes + feat_vec = feat.flatten(2).permute(2, 0, 1) # HWxBxC + pos_embed_vec = pos_embed[-1].flatten(2).permute(2, 0, 1) # HWxBxC + mask_vec = mask.flatten(1) # BxHW + return {"feat": feat_vec, "mask": mask_vec, "pos": pos_embed_vec} + + @torch.jit.unused + def _set_aux_loss(self, outputs_coord): + # this is a workaround to make torchscript happy, as torchscript + # doesn't support dictionary with non-homogeneous values, such + # as a dict having both a Tensor and a list. + return [{'pred_boxes': b} + for b in outputs_coord[:-1]] + + +def build_starks(cfg): + backbone = build_backbone(cfg) # backbone and positional encoding are built together + transformer = build_transformer(cfg) + box_head = build_box_head(cfg) + model = STARKS( + backbone, + transformer, + box_head, + num_queries=cfg.MODEL.NUM_OBJECT_QUERIES, + aux_loss=cfg.TRAIN.DEEP_SUPERVISION, + head_type=cfg.MODEL.HEAD_TYPE + ) + + return model diff --git a/Stark/lib/models/stark/stark_st.py b/Stark/lib/models/stark/stark_st.py new file mode 100755 index 0000000..0473fbf --- /dev/null +++ b/Stark/lib/models/stark/stark_st.py @@ -0,0 +1,76 @@ +""" +STARK-ST Model (Spatio-Temporal). +""" +from .backbone import build_backbone +from .transformer import build_transformer +from .head import build_box_head, MLP +from lib.models.stark.stark_s import STARKS + + +class STARKST(STARKS): + """ This is the base class for Transformer Tracking """ + def __init__(self, backbone, transformer, box_head, num_queries, + aux_loss=False, head_type="CORNER", cls_head=None): + """ Initializes the model. + Parameters: + backbone: torch module of the backbone to be used. See backbone.py + transformer: torch module of the transformer architecture. See transformer.py + num_queries: number of object queries. + aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used. + """ + super().__init__(backbone, transformer, box_head, num_queries, + aux_loss=aux_loss, head_type=head_type) + self.cls_head = cls_head + + def forward(self, img=None, seq_dict=None, mode="backbone", run_box_head=False, run_cls_head=False): + if mode == "backbone": + return self.forward_backbone(img) + elif mode == "transformer": + return self.forward_transformer(seq_dict, run_box_head=run_box_head, run_cls_head=run_cls_head) + else: + raise ValueError + + def forward_transformer(self, seq_dict, run_box_head=False, run_cls_head=False): + if self.aux_loss: + raise ValueError("Deep supervision is not supported.") + # Forward the transformer encoder and decoder + output_embed, enc_mem = self.transformer(seq_dict["feat"], seq_dict["mask"], self.query_embed.weight, + seq_dict["pos"], return_encoder_output=True) + # Forward the corner head + out, outputs_coord = self.forward_head(output_embed, enc_mem, run_box_head=run_box_head, run_cls_head=run_cls_head) + return out, outputs_coord, output_embed + + def forward_head(self, hs, memory, run_box_head=False, run_cls_head=False): + """ + hs: output embeddings (1, B, N, C) + memory: encoder embeddings (HW1+HW2, B, C)""" + out_dict = {} + if run_cls_head: + # forward the classification head + out_dict.update({'pred_logits': self.cls_head(hs)[-1]}) + if run_box_head: + # forward the box prediction head + out_dict_box, outputs_coord = self.forward_box_head(hs, memory) + # merge results + out_dict.update(out_dict_box) + return out_dict, outputs_coord + else: + return out_dict, None + + +def build_starkst(cfg): + backbone = build_backbone(cfg) # backbone and positional encoding are built together + transformer = build_transformer(cfg) + box_head = build_box_head(cfg) + cls_head = MLP(cfg.MODEL.HIDDEN_DIM, cfg.MODEL.HIDDEN_DIM, 1, cfg.MODEL.NLAYER_HEAD) + model = STARKST( + backbone, + transformer, + box_head, + num_queries=cfg.MODEL.NUM_OBJECT_QUERIES, + aux_loss=cfg.TRAIN.DEEP_SUPERVISION, + head_type=cfg.MODEL.HEAD_TYPE, + cls_head=cls_head + ) + + return model diff --git a/Stark/lib/models/stark/transformer.py b/Stark/lib/models/stark/transformer.py new file mode 100755 index 0000000..df2bdf0 --- /dev/null +++ b/Stark/lib/models/stark/transformer.py @@ -0,0 +1,363 @@ +""" +STARK Transformer class. + +Copy-paste from torch.nn.Transformer with modifications: + * positional encodings are passed in MHattention + * extra LN at the end of encoder is removed + * decoder returns a stack of activations from all decoding layers + +2020.12.23 Split some preprocess fom the forward function +""" +import copy +from typing import Optional, List + +import torch +import torch.nn.functional as F +from torch import nn, Tensor + + +def check_inf(tensor): + return torch.isinf(tensor.detach()).any() + + +def check_nan(tensor): + return torch.isnan(tensor.detach()).any() + + +def check_valid(tensor, type_name): + if check_inf(tensor): + print("%s is inf." % type_name) + if check_nan(tensor): + print("%s is nan" % type_name) + + +class Transformer(nn.Module): + + def __init__(self, d_model=512, nhead=8, num_encoder_layers=6, + num_decoder_layers=6, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False, + return_intermediate_dec=False, divide_norm=False): + super().__init__() + + encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward, + dropout, activation, normalize_before, divide_norm=divide_norm) + encoder_norm = nn.LayerNorm(d_model) if normalize_before else None + if num_encoder_layers == 0: + self.encoder = None + else: + self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm) + + decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward, + dropout, activation, normalize_before, divide_norm=divide_norm) + decoder_norm = nn.LayerNorm(d_model) + if num_decoder_layers == 0: + self.decoder = None + else: + self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm, + return_intermediate=return_intermediate_dec) + + self._reset_parameters() + + self.d_model = d_model + self.nhead = nhead + self.d_feed = dim_feedforward + # 2021.1.7 Try dividing norm to avoid NAN + self.divide_norm = divide_norm + self.scale_factor = float(d_model // nhead) ** 0.5 + + def _reset_parameters(self): + for p in self.parameters(): + if p.dim() > 1: + nn.init.xavier_uniform_(p) + + def forward(self, feat, mask, query_embed, pos_embed, mode="all", return_encoder_output=False): + """ + + :param feat: (H1W1+H2W2, bs, C) + :param mask: (bs, H1W1+H2W2) + :param query_embed: (N, C) or (N, B, C) + :param pos_embed: (H1W1+H2W2, bs, C) + :param mode: run the whole transformer or encoder only + :param return_encoder_output: whether to return the output of encoder (together with decoder) + :return: + """ + assert mode in ["all", "encoder"] + if self.encoder is None: + memory = feat + else: + memory = self.encoder(feat, src_key_padding_mask=mask, pos=pos_embed) + if mode == "encoder": + return memory + elif mode == "all": + assert len(query_embed.size()) in [2, 3] + if len(query_embed.size()) == 2: + bs = feat.size(1) + query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1) # (N,C) --> (N,1,C) --> (N,B,C) + if self.decoder is not None: + tgt = torch.zeros_like(query_embed) + hs = self.decoder(tgt, memory, memory_key_padding_mask=mask, + pos=pos_embed, query_pos=query_embed) + else: + hs = query_embed.unsqueeze(0) + if return_encoder_output: + return hs.transpose(1, 2), memory # (1, B, N, C) + else: + return hs.transpose(1, 2) # (1, B, N, C) + + +class TransformerEncoder(nn.Module): + + def __init__(self, encoder_layer, num_layers, norm=None): + super().__init__() + self.layers = _get_clones(encoder_layer, num_layers) + self.num_layers = num_layers + self.norm = norm + + def forward(self, src, + mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + output = src + + for layer in self.layers: + output = layer(output, src_mask=mask, + src_key_padding_mask=src_key_padding_mask, pos=pos) + + if self.norm is not None: + output = self.norm(output) + + return output + + +class TransformerDecoder(nn.Module): + + def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False): + super().__init__() + self.layers = _get_clones(decoder_layer, num_layers) + self.num_layers = num_layers + self.norm = norm + self.return_intermediate = return_intermediate + + def forward(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + output = tgt + + intermediate = [] + + for layer in self.layers: + output = layer(output, memory, tgt_mask=tgt_mask, + memory_mask=memory_mask, + tgt_key_padding_mask=tgt_key_padding_mask, + memory_key_padding_mask=memory_key_padding_mask, + pos=pos, query_pos=query_pos) + if self.return_intermediate: + intermediate.append(self.norm(output)) + + if self.norm is not None: + output = self.norm(output) + if self.return_intermediate: + intermediate.pop() + intermediate.append(output) + + if self.return_intermediate: + return torch.stack(intermediate) + + return output.unsqueeze(0) + + +class TransformerEncoderLayer(nn.Module): + + def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False, divide_norm=False): + super().__init__() + self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + # Implementation of Feedforward model + self.linear1 = nn.Linear(d_model, dim_feedforward) + self.dropout = nn.Dropout(dropout) + self.linear2 = nn.Linear(dim_feedforward, d_model) + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.dropout1 = nn.Dropout(dropout) + self.dropout2 = nn.Dropout(dropout) + + self.activation = _get_activation_fn(activation) + self.normalize_before = normalize_before # first normalization, then add + + self.divide_norm = divide_norm + self.scale_factor = float(d_model // nhead) ** 0.5 + + def with_pos_embed(self, tensor, pos: Optional[Tensor]): + return tensor if pos is None else tensor + pos + + def forward_post(self, + src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + q = k = self.with_pos_embed(src, pos) # add pos to src + if self.divide_norm: + # print("encoder divide by norm") + q = q / torch.norm(q, dim=-1, keepdim=True) * self.scale_factor + k = k / torch.norm(k, dim=-1, keepdim=True) + src2 = self.self_attn(q, k, value=src, attn_mask=src_mask, + key_padding_mask=src_key_padding_mask)[0] + src = src + self.dropout1(src2) + src = self.norm1(src) + src2 = self.linear2(self.dropout(self.activation(self.linear1(src)))) + src = src + self.dropout2(src2) + src = self.norm2(src) + return src + + def forward_pre(self, src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + src2 = self.norm1(src) + q = k = self.with_pos_embed(src2, pos) + src2 = self.self_attn(q, k, value=src2, attn_mask=src_mask, + key_padding_mask=src_key_padding_mask)[0] + src = src + self.dropout1(src2) + src2 = self.norm2(src) + src2 = self.linear2(self.dropout(self.activation(self.linear1(src2)))) + src = src + self.dropout2(src2) + return src + + def forward(self, src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + if self.normalize_before: + return self.forward_pre(src, src_mask, src_key_padding_mask, pos) + return self.forward_post(src, src_mask, src_key_padding_mask, pos) + + +class TransformerDecoderLayer(nn.Module): + + def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False, divide_norm=False): + super().__init__() + self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + # Implementation of Feedforward model + self.linear1 = nn.Linear(d_model, dim_feedforward) + self.dropout = nn.Dropout(dropout) + self.linear2 = nn.Linear(dim_feedforward, d_model) + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + self.dropout1 = nn.Dropout(dropout) + self.dropout2 = nn.Dropout(dropout) + self.dropout3 = nn.Dropout(dropout) + + self.activation = _get_activation_fn(activation) + self.normalize_before = normalize_before + + self.divide_norm = divide_norm + self.scale_factor = float(d_model // nhead) ** 0.5 + + def with_pos_embed(self, tensor, pos: Optional[Tensor]): + return tensor if pos is None else tensor + pos + + def forward_post(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + # self-attention + q = k = self.with_pos_embed(tgt, query_pos) # Add object query to the query and key + if self.divide_norm: + q = q / torch.norm(q, dim=-1, keepdim=True) * self.scale_factor + k = k / torch.norm(k, dim=-1, keepdim=True) + tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask, + key_padding_mask=tgt_key_padding_mask)[0] + tgt = tgt + self.dropout1(tgt2) + tgt = self.norm1(tgt) + # mutual attention + queries, keys = self.with_pos_embed(tgt, query_pos), self.with_pos_embed(memory, pos) + if self.divide_norm: + queries = queries / torch.norm(queries, dim=-1, keepdim=True) * self.scale_factor + keys = keys / torch.norm(keys, dim=-1, keepdim=True) + tgt2 = self.multihead_attn(query=queries, + key=keys, + value=memory, attn_mask=memory_mask, + key_padding_mask=memory_key_padding_mask)[0] + tgt = tgt + self.dropout2(tgt2) + tgt = self.norm2(tgt) + tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt)))) + tgt = tgt + self.dropout3(tgt2) + tgt = self.norm3(tgt) + return tgt + + def forward_pre(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + tgt2 = self.norm1(tgt) + q = k = self.with_pos_embed(tgt2, query_pos) + tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask, + key_padding_mask=tgt_key_padding_mask)[0] + tgt = tgt + self.dropout1(tgt2) + tgt2 = self.norm2(tgt) + tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos), + key=self.with_pos_embed(memory, pos), + value=memory, attn_mask=memory_mask, + key_padding_mask=memory_key_padding_mask)[0] + tgt = tgt + self.dropout2(tgt2) + tgt2 = self.norm3(tgt) + tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2)))) + tgt = tgt + self.dropout3(tgt2) + return tgt + + def forward(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + if self.normalize_before: + return self.forward_pre(tgt, memory, tgt_mask, memory_mask, + tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) + return self.forward_post(tgt, memory, tgt_mask, memory_mask, + tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) + + +def _get_clones(module, N): + return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) + + +def build_transformer(cfg): + return Transformer( + d_model=cfg.MODEL.HIDDEN_DIM, + dropout=cfg.MODEL.TRANSFORMER.DROPOUT, + nhead=cfg.MODEL.TRANSFORMER.NHEADS, + dim_feedforward=cfg.MODEL.TRANSFORMER.DIM_FEEDFORWARD, + num_encoder_layers=cfg.MODEL.TRANSFORMER.ENC_LAYERS, + num_decoder_layers=cfg.MODEL.TRANSFORMER.DEC_LAYERS, + normalize_before=cfg.MODEL.TRANSFORMER.PRE_NORM, + return_intermediate_dec=False, # we use false to avoid DDP error, + divide_norm=cfg.MODEL.TRANSFORMER.DIVIDE_NORM + ) + + +def _get_activation_fn(activation): + """Return an activation function given a string""" + if activation == "relu": + return F.relu + if activation == "gelu": + return F.gelu + if activation == "glu": + return F.glu + raise RuntimeError(F"activation should be relu/gelu, not {activation}.") diff --git a/Stark/lib/test/__init__.py b/Stark/lib/test/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/test/__pycache__/__init__.cpython-37.pyc b/Stark/lib/test/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..6d70eae Binary files /dev/null and b/Stark/lib/test/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/test/analysis/__init__.py b/Stark/lib/test/analysis/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/test/analysis/extract_results.py b/Stark/lib/test/analysis/extract_results.py new file mode 100755 index 0000000..8110caa --- /dev/null +++ b/Stark/lib/test/analysis/extract_results.py @@ -0,0 +1,182 @@ +import os +import sys +import numpy as np +from lib.test.utils.load_text import load_text +import torch +import pickle +from tqdm import tqdm + +env_path = os.path.join(os.path.dirname(__file__), '../../..') +if env_path not in sys.path: + sys.path.append(env_path) + +from lib.test.evaluation.environment import env_settings + + +def calc_err_center(pred_bb, anno_bb, normalized=False): + pred_center = pred_bb[:, :2] + 0.5 * (pred_bb[:, 2:] - 1.0) + anno_center = anno_bb[:, :2] + 0.5 * (anno_bb[:, 2:] - 1.0) + + if normalized: + pred_center = pred_center / anno_bb[:, 2:] + anno_center = anno_center / anno_bb[:, 2:] + + err_center = ((pred_center - anno_center)**2).sum(1).sqrt() + return err_center + + +def calc_iou_overlap(pred_bb, anno_bb): + tl = torch.max(pred_bb[:, :2], anno_bb[:, :2]) + br = torch.min(pred_bb[:, :2] + pred_bb[:, 2:] - 1.0, anno_bb[:, :2] + anno_bb[:, 2:] - 1.0) + sz = (br - tl + 1.0).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = pred_bb[:, 2:].prod(dim=1) + anno_bb[:, 2:].prod(dim=1) - intersection + + return intersection / union + + +def calc_seq_err_robust(pred_bb, anno_bb, dataset, target_visible=None): + pred_bb = pred_bb.clone() + + # Check if invalid values are present + if torch.isnan(pred_bb).any() or (pred_bb[:, 2:] < 0.0).any(): + raise Exception('Error: Invalid results') + + if torch.isnan(anno_bb).any(): + if dataset == 'uav': + pass + else: + raise Exception('Warning: NaNs in annotation') + + if (pred_bb[:, 2:] == 0.0).any(): + for i in range(1, pred_bb.shape[0]): + if (pred_bb[i, 2:] == 0.0).any() and not torch.isnan(anno_bb[i, :]).any(): + pred_bb[i, :] = pred_bb[i-1, :] + + if pred_bb.shape[0] != anno_bb.shape[0]: + if dataset == 'lasot': + if pred_bb.shape[0] > anno_bb.shape[0]: + # For monkey-17, there is a mismatch for some trackers. + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + raise Exception('Mis-match in tracker prediction and GT lengths') + else: + # print('Warning: Mis-match in tracker prediction and GT lengths') + if pred_bb.shape[0] > anno_bb.shape[0]: + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + pad = torch.zeros((anno_bb.shape[0] - pred_bb.shape[0], 4)).type_as(pred_bb) + pred_bb = torch.cat((pred_bb, pad), dim=0) + + pred_bb[0, :] = anno_bb[0, :] + + if target_visible is not None: + target_visible = target_visible.bool() + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) & target_visible + else: + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) + + err_center = calc_err_center(pred_bb, anno_bb) + err_center_normalized = calc_err_center(pred_bb, anno_bb, normalized=True) + err_overlap = calc_iou_overlap(pred_bb, anno_bb) + + # handle invalid anno cases + if dataset in ['uav']: + err_center[~valid] = -1.0 + else: + err_center[~valid] = float("Inf") + err_center_normalized[~valid] = -1.0 + err_overlap[~valid] = -1.0 + + if dataset == 'lasot': + err_center_normalized[~target_visible] = float("Inf") + err_center[~target_visible] = float("Inf") + + if torch.isnan(err_overlap).any(): + raise Exception('Nans in calculated overlap') + return err_overlap, err_center, err_center_normalized, valid + + +def extract_results(trackers, dataset, report_name, skip_missing_seq=False, plot_bin_gap=0.05, + exclude_invalid_frames=False): + settings = env_settings() + eps = 1e-16 + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + if not os.path.exists(result_plot_path): + os.makedirs(result_plot_path) + + threshold_set_overlap = torch.arange(0.0, 1.0 + plot_bin_gap, plot_bin_gap, dtype=torch.float64) + threshold_set_center = torch.arange(0, 51, dtype=torch.float64) + threshold_set_center_norm = torch.arange(0, 51, dtype=torch.float64) / 100.0 + + avg_overlap_all = torch.zeros((len(dataset), len(trackers)), dtype=torch.float64) + ave_success_rate_plot_overlap = torch.zeros((len(dataset), len(trackers), threshold_set_overlap.numel()), + dtype=torch.float32) + ave_success_rate_plot_center = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + ave_success_rate_plot_center_norm = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + + valid_sequence = torch.ones(len(dataset), dtype=torch.uint8) + + for seq_id, seq in enumerate(tqdm(dataset)): + # Load anno + anno_bb = torch.tensor(seq.ground_truth_rect) + target_visible = torch.tensor(seq.target_visible, dtype=torch.uint8) if seq.target_visible is not None else None + for trk_id, trk in enumerate(trackers): + # Load results + base_results_path = '{}/{}'.format(trk.results_dir, seq.name) + results_path = '{}.txt'.format(base_results_path) + + if os.path.isfile(results_path): + pred_bb = torch.tensor(load_text(str(results_path), delimiter=('\t', ','), dtype=np.float64)) + else: + if skip_missing_seq: + valid_sequence[seq_id] = 0 + break + else: + raise Exception('Result not found. {}'.format(results_path)) + + # Calculate measures + err_overlap, err_center, err_center_normalized, valid_frame = calc_seq_err_robust( + pred_bb, anno_bb, seq.dataset, target_visible) + + avg_overlap_all[seq_id, trk_id] = err_overlap[valid_frame].mean() + + if exclude_invalid_frames: + seq_length = valid_frame.long().sum() + else: + seq_length = anno_bb.shape[0] + + if seq_length <= 0: + raise Exception('Seq length zero') + + ave_success_rate_plot_overlap[seq_id, trk_id, :] = (err_overlap.view(-1, 1) > threshold_set_overlap.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center[seq_id, trk_id, :] = (err_center.view(-1, 1) <= threshold_set_center.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center_norm[seq_id, trk_id, :] = (err_center_normalized.view(-1, 1) <= threshold_set_center_norm.view(1, -1)).sum(0).float() / seq_length + + print('\n\nComputed results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + # Prepare dictionary for saving data + seq_names = [s.name for s in dataset] + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + + eval_data = {'sequences': seq_names, 'trackers': tracker_names, + 'valid_sequence': valid_sequence.tolist(), + 'ave_success_rate_plot_overlap': ave_success_rate_plot_overlap.tolist(), + 'ave_success_rate_plot_center': ave_success_rate_plot_center.tolist(), + 'ave_success_rate_plot_center_norm': ave_success_rate_plot_center_norm.tolist(), + 'avg_overlap_all': avg_overlap_all.tolist(), + 'threshold_set_overlap': threshold_set_overlap.tolist(), + 'threshold_set_center': threshold_set_center.tolist(), + 'threshold_set_center_norm': threshold_set_center_norm.tolist()} + + with open(result_plot_path + '/eval_data.pkl', 'wb') as fh: + pickle.dump(eval_data, fh) + + return eval_data diff --git a/Stark/lib/test/analysis/plot_results.py b/Stark/lib/test/analysis/plot_results.py new file mode 100755 index 0000000..c40843a --- /dev/null +++ b/Stark/lib/test/analysis/plot_results.py @@ -0,0 +1,495 @@ +import tikzplotlib +import matplotlib +import matplotlib.pyplot as plt +import os +import torch +import pickle +import json +from lib.test.evaluation.environment import env_settings +from lib.test.analysis.extract_results import extract_results + + +def get_plot_draw_styles(): + plot_draw_style = [{'color': (1.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 1.0), 'line_style': '-'}, + {'color': (0.5, 0.5, 0.5), 'line_style': '-'}, + {'color': (136.0 / 255.0, 0.0, 21.0 / 255.0), 'line_style': '-'}, + {'color': (1.0, 127.0 / 255.0, 39.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 162.0 / 255.0, 232.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 0.5, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.5, 0.2), 'line_style': '-'}, + {'color': (0.1, 0.4, 0.0), 'line_style': '-'}, + {'color': (0.6, 0.3, 0.9), 'line_style': '-'}, + {'color': (0.4, 0.7, 0.1), 'line_style': '-'}, + {'color': (0.2, 0.1, 0.7), 'line_style': '-'}, + {'color': (0.7, 0.6, 0.2), 'line_style': '-'}] + + return plot_draw_style + + +def check_eval_data_is_valid(eval_data, trackers, dataset): + """ Checks if the pre-computed results are valid""" + seq_names = [s.name for s in dataset] + seq_names_saved = eval_data['sequences'] + + tracker_names_f = [(t.name, t.parameter_name, t.run_id) for t in trackers] + tracker_names_f_saved = [(t['name'], t['param'], t['run_id']) for t in eval_data['trackers']] + + return seq_names == seq_names_saved and tracker_names_f == tracker_names_f_saved + + +def merge_multiple_runs(eval_data): + new_tracker_names = [] + ave_success_rate_plot_overlap_merged = [] + ave_success_rate_plot_center_merged = [] + ave_success_rate_plot_center_norm_merged = [] + avg_overlap_all_merged = [] + + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) + + trackers = eval_data['trackers'] + merged = torch.zeros(len(trackers), dtype=torch.uint8) + for i in range(len(trackers)): + if merged[i]: + continue + base_tracker = trackers[i] + new_tracker_names.append(base_tracker) + + match = [t['name'] == base_tracker['name'] and t['param'] == base_tracker['param'] for t in trackers] + match = torch.tensor(match) + + ave_success_rate_plot_overlap_merged.append(ave_success_rate_plot_overlap[:, match, :].mean(1)) + ave_success_rate_plot_center_merged.append(ave_success_rate_plot_center[:, match, :].mean(1)) + ave_success_rate_plot_center_norm_merged.append(ave_success_rate_plot_center_norm[:, match, :].mean(1)) + avg_overlap_all_merged.append(avg_overlap_all[:, match].mean(1)) + + merged[match] = 1 + + ave_success_rate_plot_overlap_merged = torch.stack(ave_success_rate_plot_overlap_merged, dim=1) + ave_success_rate_plot_center_merged = torch.stack(ave_success_rate_plot_center_merged, dim=1) + ave_success_rate_plot_center_norm_merged = torch.stack(ave_success_rate_plot_center_norm_merged, dim=1) + avg_overlap_all_merged = torch.stack(avg_overlap_all_merged, dim=1) + + eval_data['trackers'] = new_tracker_names + eval_data['ave_success_rate_plot_overlap'] = ave_success_rate_plot_overlap_merged.tolist() + eval_data['ave_success_rate_plot_center'] = ave_success_rate_plot_center_merged.tolist() + eval_data['ave_success_rate_plot_center_norm'] = ave_success_rate_plot_center_norm_merged.tolist() + eval_data['avg_overlap_all'] = avg_overlap_all_merged.tolist() + + return eval_data + + +def get_tracker_display_name(tracker): + if tracker['disp_name'] is None: + if tracker['run_id'] is None: + disp_name = '{}_{}'.format(tracker['name'], tracker['param']) + else: + disp_name = '{}_{}_{:03d}'.format(tracker['name'], tracker['param'], + tracker['run_id']) + else: + disp_name = tracker['disp_name'] + + return disp_name + + +def plot_draw_save(y, x, scores, trackers, plot_draw_styles, result_plot_path, plot_opts): + plt.rcParams['text.usetex']=True + plt.rcParams["font.family"] = "Times New Roman" + # Plot settings + font_size = plot_opts.get('font_size', 20) + font_size_axis = plot_opts.get('font_size_axis', 20) + line_width = plot_opts.get('line_width', 2) + font_size_legend = plot_opts.get('font_size_legend', 20) + + plot_type = plot_opts['plot_type'] + legend_loc = plot_opts['legend_loc'] + + xlabel = plot_opts['xlabel'] + ylabel = plot_opts['ylabel'] + ylabel = "%s"%(ylabel.replace('%','\%')) + xlim = plot_opts['xlim'] + ylim = plot_opts['ylim'] + + title = r"$\bf{%s}$" %(plot_opts['title']) + + matplotlib.rcParams.update({'font.size': font_size}) + matplotlib.rcParams.update({'axes.titlesize': font_size_axis}) + matplotlib.rcParams.update({'axes.titleweight': 'black'}) + matplotlib.rcParams.update({'axes.labelsize': font_size_axis}) + + fig, ax = plt.subplots() + + index_sort = scores.argsort(descending=False) + + plotted_lines = [] + legend_text = [] + + for id, id_sort in enumerate(index_sort): + line = ax.plot(x.tolist(), y[id_sort, :].tolist(), + linewidth=line_width, + color=plot_draw_styles[index_sort.numel() - id - 1]['color'], + linestyle=plot_draw_styles[index_sort.numel() - id - 1]['line_style']) + + plotted_lines.append(line[0]) + + tracker = trackers[id_sort] + disp_name = get_tracker_display_name(tracker) + + legend_text.append('{} [{:.1f}]'.format(disp_name, scores[id_sort])) + + try: + # add bold to our method + for i in range(1,2): + legend_text[-i] = r'\textbf{%s}'%(legend_text[-i]) + + ax.legend(plotted_lines[::-1], legend_text[::-1], loc=legend_loc, fancybox=False, edgecolor='black', + fontsize=font_size_legend, framealpha=1.0) + except: + pass + + ax.set(xlabel=xlabel, + ylabel=ylabel, + xlim=xlim, ylim=ylim, + title=title) + + ax.grid(True, linestyle='-.') + fig.tight_layout() + + tikzplotlib.save('{}/{}_plot.tex'.format(result_plot_path, plot_type)) + fig.savefig('{}/{}_plot.pdf'.format(result_plot_path, plot_type), dpi=300, format='pdf', transparent=True) + plt.draw() + + +def check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation=False, **kwargs): + # Load data + settings = env_settings() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data_path = os.path.join(result_plot_path, 'eval_data.pkl') + + if os.path.isfile(eval_data_path) and not force_evaluation: + with open(eval_data_path, 'rb') as fh: + eval_data = pickle.load(fh) + else: + # print('Pre-computed evaluation data not found. Computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + + if not check_eval_data_is_valid(eval_data, trackers, dataset): + # print('Pre-computed evaluation data invalid. Re-computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + # pass + else: + # Update display names + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + eval_data['trackers'] = tracker_names + with open(eval_data_path, 'wb') as fh: + pickle.dump(eval_data, fh) + return eval_data + + +def get_auc_curve(ave_success_rate_plot_overlap, valid_sequence): + ave_success_rate_plot_overlap = ave_success_rate_plot_overlap[valid_sequence, :, :] + auc_curve = ave_success_rate_plot_overlap.mean(0) * 100.0 + auc = auc_curve.mean(-1) + + return auc_curve, auc + + +def get_prec_curve(ave_success_rate_plot_center, valid_sequence): + ave_success_rate_plot_center = ave_success_rate_plot_center[valid_sequence, :, :] + prec_curve = ave_success_rate_plot_center.mean(0) * 100.0 + prec_score = prec_curve[:, 20] + + return prec_curve, prec_score + + +def plot_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), force_evaluation=False, **kwargs): + """ + Plot results for the given trackers + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success', + 'prec' (precision), and 'norm_prec' (normalized precision) + """ + # Load data + settings = env_settings() + + plot_draw_styles = get_plot_draw_styles() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nPlotting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + print('\nGenerating plots for: {}'.format(report_name)) + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 88), 'title': 'Success'} + plot_draw_save(auc_curve, threshold_set_overlap, auc, tracker_names, plot_draw_styles, result_plot_path, success_plot_opts) + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + threshold_set_center = torch.tensor(eval_data['threshold_set_center']) + + precision_plot_opts = {'plot_type': 'precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold [pixels]', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 50), 'ylim': (0, 100), 'title': 'Precision plot'} + plot_draw_save(prec_curve, threshold_set_center, prec_score, tracker_names, plot_draw_styles, result_plot_path, + precision_plot_opts) + + # ******************************** Norm Precision Plot ************************************** + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + threshold_set_center_norm = torch.tensor(eval_data['threshold_set_center_norm']) + + norm_precision_plot_opts = {'plot_type': 'norm_precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 0.5), 'ylim': (0, 85), 'title': 'Normalized Precision'} + plot_draw_save(prec_curve, threshold_set_center_norm, prec_score, tracker_names, plot_draw_styles, result_plot_path, + norm_precision_plot_opts) + + plt.show() + + +def generate_formatted_report(row_labels, scores, table_name=''): + name_width = max([len(d) for d in row_labels] + [len(table_name)]) + 5 + min_score_width = 10 + + report_text = '\n{label: <{width}} |'.format(label=table_name, width=name_width) + + score_widths = [max(min_score_width, len(k) + 3) for k in scores.keys()] + + for s, s_w in zip(scores.keys(), score_widths): + report_text = '{prev} {s: <{width}} |'.format(prev=report_text, s=s, width=s_w) + + report_text = '{prev}\n'.format(prev=report_text) + + for trk_id, d_name in enumerate(row_labels): + # display name + report_text = '{prev}{tracker: <{width}} |'.format(prev=report_text, tracker=d_name, + width=name_width) + for (score_type, score_value), s_w in zip(scores.items(), score_widths): + report_text = '{prev} {score: <{width}} |'.format(prev=report_text, + score='{:0.2f}'.format(score_value[trk_id].item()), + width=s_w) + report_text = '{prev}\n'.format(prev=report_text) + + return report_text + + +def print_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), **kwargs): + """ Print the results for the given trackers in a formatted table + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success' (prints AUC, OP50, and OP75 scores), + 'prec' (prints precision score), and 'norm_prec' (prints normalized precision score) + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nReporting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + scores = {} + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + scores['AUC'] = auc + scores['OP50'] = auc_curve[:, threshold_set_overlap == 0.50] + scores['OP75'] = auc_curve[:, threshold_set_overlap == 0.75] + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + scores['Precision'] = prec_score + + # ******************************** Norm Precision Plot ********************************* + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + norm_prec_curve, norm_prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + scores['Norm Precision'] = norm_prec_score + + # Print + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + report_text = generate_formatted_report(tracker_disp_names, scores, table_name=report_name) + print(report_text) + + +def plot_got_success(trackers, report_name): + """ Plot success plot for GOT-10k dataset using the json reports. + Save the json reports from http://got-10k.aitestunion.com/leaderboard in the directory set to + env_settings.got_reports_path + + The tracker name in the experiment file should be set to the name of the report file for that tracker, + e.g. DiMP50_report_2019_09_02_15_44_25 if the report is name DiMP50_report_2019_09_02_15_44_25.json + + args: + trackers - List of trackers to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + """ + # Load data + settings = env_settings() + plot_draw_styles = get_plot_draw_styles() + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + auc_curve = torch.zeros((len(trackers), 101)) + scores = torch.zeros(len(trackers)) + + # Load results + tracker_names = [] + for trk_id, trk in enumerate(trackers): + json_path = '{}/{}.json'.format(settings.got_reports_path, trk.name) + + if os.path.isfile(json_path): + with open(json_path, 'r') as f: + eval_data = json.load(f) + else: + raise Exception('Report not found {}'.format(json_path)) + + if len(eval_data.keys()) > 1: + raise Exception + + # First field is the tracker name. Index it out + eval_data = eval_data[list(eval_data.keys())[0]] + if 'succ_curve' in eval_data.keys(): + curve = eval_data['succ_curve'] + ao = eval_data['ao'] + elif 'overall' in eval_data.keys() and 'succ_curve' in eval_data['overall'].keys(): + curve = eval_data['overall']['succ_curve'] + ao = eval_data['overall']['ao'] + else: + raise Exception('Invalid JSON file {}'.format(json_path)) + + auc_curve[trk_id, :] = torch.tensor(curve) * 100.0 + scores[trk_id] = ao * 100.0 + + tracker_names.append({'name': trk.name, 'param': trk.parameter_name, 'run_id': trk.run_id, + 'disp_name': trk.display_name}) + + threshold_set_overlap = torch.arange(0.0, 1.01, 0.01, dtype=torch.float64) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 100), 'title': 'Success plot'} + plot_draw_save(auc_curve, threshold_set_overlap, scores, tracker_names, plot_draw_styles, result_plot_path, + success_plot_opts) + plt.show() + + +def print_per_sequence_results(trackers, dataset, report_name, merge_results=False, + filter_criteria=None, **kwargs): + """ Print per-sequence results for the given trackers. Additionally, the sequences to list can be filtered using + the filter criteria. + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + filter_criteria - Filter sequence results which are reported. Following modes are supported + None: No filtering. Display results for all sequences in dataset + 'ao_min': Only display sequences for which the minimum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences where at least one tracker performs poorly. + 'ao_max': Only display sequences for which the maximum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences all tracker performs poorly. + 'delta_ao': Only display sequences for which the performance of different trackers vary by at + least filter_criteria['threshold'] in average overlap (AO) score. This mode can + be used to select sequences where the behaviour of the trackers greatly differ + between each other. + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + sequence_names = eval_data['sequences'] + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) * 100.0 + + # Filter sequences + if filter_criteria is not None: + if filter_criteria['mode'] == 'ao_min': + min_ao = avg_overlap_all.min(dim=1)[0] + valid_sequence = valid_sequence & (min_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'ao_max': + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & (max_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'delta_ao': + min_ao = avg_overlap_all.min(dim=1)[0] + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & ((max_ao - min_ao) > filter_criteria['threshold']) + else: + raise Exception + + avg_overlap_all = avg_overlap_all[valid_sequence, :] + sequence_names = [s + ' (ID={})'.format(i) for i, (s, v) in enumerate(zip(sequence_names, valid_sequence.tolist())) if v] + + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + + scores_per_tracker = {k: avg_overlap_all[:, i] for i, k in enumerate(tracker_disp_names)} + report_text = generate_formatted_report(sequence_names, scores_per_tracker) + + print(report_text) diff --git a/Stark/lib/test/evaluation/__init__.py b/Stark/lib/test/evaluation/__init__.py new file mode 100755 index 0000000..5947f3e --- /dev/null +++ b/Stark/lib/test/evaluation/__init__.py @@ -0,0 +1,4 @@ +from .data import Sequence +from .tracker import Tracker, trackerlist +from .datasets import get_dataset +from .environment import create_default_local_file_ITP_test \ No newline at end of file diff --git a/Stark/lib/test/evaluation/__pycache__/__init__.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..4ce9c5e Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/__pycache__/data.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/data.cpython-37.pyc new file mode 100755 index 0000000..425c95c Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/data.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/__pycache__/datasets.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/datasets.cpython-37.pyc new file mode 100755 index 0000000..fa68801 Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/datasets.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/__pycache__/environment.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/environment.cpython-37.pyc new file mode 100755 index 0000000..e3a60b6 Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/environment.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/__pycache__/local.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/local.cpython-37.pyc new file mode 100755 index 0000000..25662ed Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/local.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/__pycache__/tracker.cpython-37.pyc b/Stark/lib/test/evaluation/__pycache__/tracker.cpython-37.pyc new file mode 100755 index 0000000..8e48124 Binary files /dev/null and b/Stark/lib/test/evaluation/__pycache__/tracker.cpython-37.pyc differ diff --git a/Stark/lib/test/evaluation/data.py b/Stark/lib/test/evaluation/data.py new file mode 100755 index 0000000..52d0d28 --- /dev/null +++ b/Stark/lib/test/evaluation/data.py @@ -0,0 +1,169 @@ +import numpy as np +from lib.test.evaluation.environment import env_settings +from lib.train.data.image_loader import imread_indexed +from collections import OrderedDict + + +class BaseDataset: + """Base class for all datasets.""" + def __init__(self): + self.env_settings = env_settings() + + def __len__(self): + """Overload this function in your dataset. This should return number of sequences in the dataset.""" + raise NotImplementedError + + def get_sequence_list(self): + """Overload this in your dataset. Should return the list of sequences in the dataset.""" + raise NotImplementedError + + +class Sequence: + """Class for the sequence in an evaluation.""" + def __init__(self, name, frames, dataset, ground_truth_rect, ground_truth_seg=None, init_data=None, + object_class=None, target_visible=None, object_ids=None, multiobj_mode=False): + self.name = name + self.frames = frames + self.dataset = dataset + self.ground_truth_rect = ground_truth_rect + self.ground_truth_seg = ground_truth_seg + self.object_class = object_class + self.target_visible = target_visible + self.object_ids = object_ids + self.multiobj_mode = multiobj_mode + self.init_data = self._construct_init_data(init_data) + self._ensure_start_frame() + + def _ensure_start_frame(self): + # Ensure start frame is 0 + start_frame = min(list(self.init_data.keys())) + if start_frame > 0: + self.frames = self.frames[start_frame:] + if self.ground_truth_rect is not None: + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + for obj_id, gt in self.ground_truth_rect.items(): + self.ground_truth_rect[obj_id] = gt[start_frame:,:] + else: + self.ground_truth_rect = self.ground_truth_rect[start_frame:,:] + if self.ground_truth_seg is not None: + self.ground_truth_seg = self.ground_truth_seg[start_frame:] + assert len(self.frames) == len(self.ground_truth_seg) + + if self.target_visible is not None: + self.target_visible = self.target_visible[start_frame:] + self.init_data = {frame-start_frame: val for frame, val in self.init_data.items()} + + def _construct_init_data(self, init_data): + if init_data is not None: + if not self.multiobj_mode: + assert self.object_ids is None or len(self.object_ids) == 1 + for frame, init_val in init_data.items(): + if 'bbox' in init_val and isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = init_val['bbox'][self.object_ids[0]] + # convert to list + for frame, init_val in init_data.items(): + if 'bbox' in init_val: + if isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = OrderedDict({obj_id: list(init) for obj_id, init in init_val['bbox'].items()}) + else: + init_val['bbox'] = list(init_val['bbox']) + else: + init_data = {0: dict()} # Assume start from frame 0 + + if self.object_ids is not None: + init_data[0]['object_ids'] = self.object_ids + + if self.ground_truth_rect is not None: + if self.multiobj_mode: + assert isinstance(self.ground_truth_rect, (dict, OrderedDict)) + init_data[0]['bbox'] = OrderedDict({obj_id: list(gt[0,:]) for obj_id, gt in self.ground_truth_rect.items()}) + else: + assert self.object_ids is None or len(self.object_ids) == 1 + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + init_data[0]['bbox'] = list(self.ground_truth_rect[self.object_ids[0]][0, :]) + else: + init_data[0]['bbox'] = list(self.ground_truth_rect[0,:]) + + if self.ground_truth_seg is not None: + init_data[0]['mask'] = self.ground_truth_seg[0] + + return init_data + + def init_info(self): + info = self.frame_info(frame_num=0) + return info + + def frame_info(self, frame_num): + info = self.object_init_data(frame_num=frame_num) + return info + + def init_bbox(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_bbox') + + def init_mask(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_mask') + + def get_info(self, keys, frame_num=None): + info = dict() + for k in keys: + val = self.get(k, frame_num=frame_num) + if val is not None: + info[k] = val + return info + + def object_init_data(self, frame_num=None) -> dict: + if frame_num is None: + frame_num = 0 + if frame_num not in self.init_data: + return dict() + + init_data = dict() + for key, val in self.init_data[frame_num].items(): + if val is None: + continue + init_data['init_'+key] = val + + if 'init_mask' in init_data and init_data['init_mask'] is not None: + anno = imread_indexed(init_data['init_mask']) + if not self.multiobj_mode and self.object_ids is not None: + assert len(self.object_ids) == 1 + anno = (anno == int(self.object_ids[0])).astype(np.uint8) + init_data['init_mask'] = anno + + if self.object_ids is not None: + init_data['object_ids'] = self.object_ids + init_data['sequence_object_ids'] = self.object_ids + + return init_data + + def target_class(self, frame_num=None): + return self.object_class + + def get(self, name, frame_num=None): + return getattr(self, name)(frame_num) + + def __repr__(self): + return "{self.__class__.__name__} {self.name}, length={len} frames".format(self=self, len=len(self.frames)) + + + +class SequenceList(list): + """List of sequences. Supports the addition operator to concatenate sequence lists.""" + def __getitem__(self, item): + if isinstance(item, str): + for seq in self: + if seq.name == item: + return seq + raise IndexError('Sequence name not in the dataset.') + elif isinstance(item, int): + return super(SequenceList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return SequenceList([super(SequenceList, self).__getitem__(i) for i in item]) + else: + return SequenceList(super(SequenceList, self).__getitem__(item)) + + def __add__(self, other): + return SequenceList(super(SequenceList, self).__add__(other)) + + def copy(self): + return SequenceList(super(SequenceList, self).copy()) \ No newline at end of file diff --git a/Stark/lib/test/evaluation/datasets.py b/Stark/lib/test/evaluation/datasets.py new file mode 100755 index 0000000..b580d41 --- /dev/null +++ b/Stark/lib/test/evaluation/datasets.py @@ -0,0 +1,36 @@ +from collections import namedtuple +import importlib +from lib.test.evaluation.data import SequenceList + +DatasetInfo = namedtuple('DatasetInfo', ['module', 'class_name', 'kwargs']) + +pt = "lib.test.evaluation.%sdataset" # Useful abbreviations to reduce the clutter + +dataset_dict = dict( + trackingnet=DatasetInfo(module=pt % "trackingnet", class_name="TrackingNetDataset", kwargs=dict()), + got10k_test=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='test')), + got10k_val=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='val')), + got10k_ltrval=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='ltrval')), + lasot=DatasetInfo(module=pt % "lasot", class_name="LaSOTDataset", kwargs=dict()), + lasot_lmdb=DatasetInfo(module=pt % "lasot_lmdb", class_name="LaSOTlmdbDataset", kwargs=dict()) +) + + +def load_dataset(name: str): + """ Import and load a single dataset.""" + name = name.lower() + dset_info = dataset_dict.get(name) + if dset_info is None: + raise ValueError('Unknown dataset \'%s\'' % name) + + m = importlib.import_module(dset_info.module) + dataset = getattr(m, dset_info.class_name)(**dset_info.kwargs) # Call the constructor + return dataset.get_sequence_list() + + +def get_dataset(*args): + """ Get a single or set of datasets.""" + dset = SequenceList() + for name in args: + dset.extend(load_dataset(name)) + return dset \ No newline at end of file diff --git a/Stark/lib/test/evaluation/environment.py b/Stark/lib/test/evaluation/environment.py new file mode 100755 index 0000000..d6ad0b5 --- /dev/null +++ b/Stark/lib/test/evaluation/environment.py @@ -0,0 +1,118 @@ +import importlib +import os + + +class EnvSettings: + def __init__(self): + test_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + + self.results_path = '{}/tracking_results/'.format(test_path) + self.segmentation_path = '{}/segmentation_results/'.format(test_path) + self.network_path = '{}/networks/'.format(test_path) + self.result_plot_path = '{}/result_plots/'.format(test_path) + self.otb_path = '' + self.nfs_path = '' + self.uav_path = '' + self.tpl_path = '' + self.vot_path = '' + self.got10k_path = '' + self.lasot_path = '' + self.trackingnet_path = '' + self.davis_dir = '' + self.youtubevos_dir = '' + + self.got_packed_results_path = '' + self.got_reports_path = '' + self.tn_packed_results_path = '' + + +def create_default_local_file(): + comment = {'results_path': 'Where to store tracking results', + 'network_path': 'Where tracking networks are stored.'} + + path = os.path.join(os.path.dirname(__file__), 'local.py') + with open(path, 'w') as f: + settings = EnvSettings() + + f.write('from test.evaluation.environment import EnvSettings\n\n') + f.write('def local_env_settings():\n') + f.write(' settings = EnvSettings()\n\n') + f.write(' # Set your local paths here.\n\n') + + for attr in dir(settings): + comment_str = None + if attr in comment: + comment_str = comment[attr] + attr_val = getattr(settings, attr) + if not attr.startswith('__') and not callable(attr_val): + if comment_str is None: + f.write(' settings.{} = \'{}\'\n'.format(attr, attr_val)) + else: + f.write(' settings.{} = \'{}\' # {}\n'.format(attr, attr_val, comment_str)) + f.write('\n return settings\n\n') + + +class EnvSettings_ITP: + def __init__(self, workspace_dir, data_dir, save_dir): + self.prj_dir = workspace_dir + self.save_dir = save_dir + self.results_path = os.path.join(save_dir, 'test/tracking_results') + self.segmentation_path = os.path.join(save_dir, 'test/segmentation_results') + self.network_path = os.path.join(save_dir, 'test/networks') + self.result_plot_path = os.path.join(save_dir, 'test/result_plots') + self.otb_path = '' + self.nfs_path = '' + self.uav_path = '' + self.tpl_path = '' + self.vot_path = os.path.join(data_dir, 'VOT2019') + self.got10k_path = os.path.join(data_dir, 'got10k') + self.got10k_lmdb_path = os.path.join(data_dir, 'got10k_lmdb') + self.lasot_path = os.path.join(data_dir, 'lasot') + self.lasot_lmdb_path = os.path.join(data_dir, 'lasot_lmdb') + self.trackingnet_path = os.path.join(data_dir, 'trackingNet') + self.davis_dir = '' + self.youtubevos_dir = '' + + self.got_packed_results_path = '' + self.got_reports_path = '' + self.tn_packed_results_path = '' + + +def create_default_local_file_ITP_test(workspace_dir, data_dir, save_dir): + comment = {'results_path': 'Where to store tracking results', + 'network_path': 'Where tracking networks are stored.'} + + path = os.path.join(os.path.dirname(__file__), 'local.py') + with open(path, 'w') as f: + settings = EnvSettings_ITP(workspace_dir, data_dir, save_dir) + + f.write('from lib.test.evaluation.environment import EnvSettings\n\n') + f.write('def local_env_settings():\n') + f.write(' settings = EnvSettings()\n\n') + f.write(' # Set your local paths here.\n\n') + + for attr in dir(settings): + comment_str = None + if attr in comment: + comment_str = comment[attr] + attr_val = getattr(settings, attr) + if not attr.startswith('__') and not callable(attr_val): + if comment_str is None: + f.write(' settings.{} = \'{}\'\n'.format(attr, attr_val)) + else: + f.write(' settings.{} = \'{}\' # {}\n'.format(attr, attr_val, comment_str)) + f.write('\n return settings\n\n') + + +def env_settings(): + env_module_name = 'lib.test.evaluation.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.local_env_settings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + # Create a default file + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. ' + 'Then try to run again.'.format(env_file)) \ No newline at end of file diff --git a/Stark/lib/test/evaluation/got10kdataset.py b/Stark/lib/test/evaluation/got10kdataset.py new file mode 100755 index 0000000..5d2140d --- /dev/null +++ b/Stark/lib/test/evaluation/got10kdataset.py @@ -0,0 +1,56 @@ +import numpy as np +from lib.test.evaluation.data import Sequence, BaseDataset, SequenceList +from lib.test.utils.load_text import load_text +import os + + +class GOT10KDataset(BaseDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + def __init__(self, split): + super().__init__() + # Split can be test, val, or ltrval (a validation split consisting of videos from the official train set) + if split == 'test' or split == 'val': + self.base_path = os.path.join(self.env_settings.got10k_path, split) + else: + self.base_path = os.path.join(self.env_settings.got10k_path, 'train') + + self.sequence_list = self._get_sequence_list(split) + self.split = split + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + anno_path = '{}/{}/groundtruth.txt'.format(self.base_path, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + frames_path = '{}/{}'.format(self.base_path, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'got10k', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self, split): + with open('{}/list.txt'.format(self.base_path)) as f: + sequence_list = f.read().splitlines() + + if split == 'ltrval': + with open('{}/got10k_val_split.txt'.format(self.env_settings.dataspec_path)) as f: + seq_ids = f.read().splitlines() + + sequence_list = [sequence_list[int(x)] for x in seq_ids] + return sequence_list diff --git a/Stark/lib/test/evaluation/lasot_lmdbdataset.py b/Stark/lib/test/evaluation/lasot_lmdbdataset.py new file mode 100755 index 0000000..41e5e57 --- /dev/null +++ b/Stark/lib/test/evaluation/lasot_lmdbdataset.py @@ -0,0 +1,345 @@ +from lib.test.evaluation.data import Sequence, BaseDataset, SequenceList +from lib.utils.lmdb_utils import * + +'''2021.1.27 LaSOT dataset using lmdb data''' + + +class LaSOTlmdbDataset(BaseDataset): + """ + LaSOT test set consisting of 280 videos (see Protocol-II in the LaSOT paper) + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.lasot_lmdb_path + self.sequence_list = self._get_sequence_list() + self.clean_list = self.clean_seq_list() + + def clean_seq_list(self): + clean_lst = [] + for i in range(len(self.sequence_list)): + cls, _ = self.sequence_list[i].split('-') + clean_lst.append(cls) + return clean_lst + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + class_name = sequence_name.split('-')[0] + anno_path = str('{}/{}/groundtruth.txt'.format(class_name, sequence_name)) + # decode the groundtruth + gt_str_list = decode_str(self.base_path, anno_path).split('\n')[:-1] # the last line is empty + gt_list = [list(map(float, line.split(','))) for line in gt_str_list] + ground_truth_rect = np.array(gt_list).astype(np.float64) + # decode occlusion file + occlusion_label_path = str('{}/{}/full_occlusion.txt'.format(class_name, sequence_name)) + occ_list = list(map(int, decode_str(self.base_path, occlusion_label_path).split(','))) + full_occlusion = np.array(occ_list).astype(np.float64) + # decode out of view file + out_of_view_label_path = str('{}/{}/out_of_view.txt'.format(class_name, sequence_name)) + out_of_view_list = list(map(int, decode_str(self.base_path, out_of_view_label_path).split(','))) + out_of_view = np.array(out_of_view_list).astype(np.float64) + + target_visible = np.logical_and(full_occlusion == 0, out_of_view == 0) + + frames_path = '{}/{}/img'.format(class_name, sequence_name) + + frames_list = [[self.base_path, '{}/{:08d}.jpg'.format(frames_path, frame_number)] for frame_number in range(1, ground_truth_rect.shape[0] + 1)] + + target_class = class_name + return Sequence(sequence_name, frames_list, 'lasot', ground_truth_rect.reshape(-1, 4), + object_class=target_class, target_visible=target_visible) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list = ['airplane-1', + 'airplane-9', + 'airplane-13', + 'airplane-15', + 'basketball-1', + 'basketball-6', + 'basketball-7', + 'basketball-11', + 'bear-2', + 'bear-4', + 'bear-6', + 'bear-17', + 'bicycle-2', + 'bicycle-7', + 'bicycle-9', + 'bicycle-18', + 'bird-2', + 'bird-3', + 'bird-15', + 'bird-17', + 'boat-3', + 'boat-4', + 'boat-12', + 'boat-17', + 'book-3', + 'book-10', + 'book-11', + 'book-19', + 'bottle-1', + 'bottle-12', + 'bottle-14', + 'bottle-18', + 'bus-2', + 'bus-5', + 'bus-17', + 'bus-19', + 'car-2', + 'car-6', + 'car-9', + 'car-17', + 'cat-1', + 'cat-3', + 'cat-18', + 'cat-20', + 'cattle-2', + 'cattle-7', + 'cattle-12', + 'cattle-13', + 'spider-14', + 'spider-16', + 'spider-18', + 'spider-20', + 'coin-3', + 'coin-6', + 'coin-7', + 'coin-18', + 'crab-3', + 'crab-6', + 'crab-12', + 'crab-18', + 'surfboard-12', + 'surfboard-4', + 'surfboard-5', + 'surfboard-8', + 'cup-1', + 'cup-4', + 'cup-7', + 'cup-17', + 'deer-4', + 'deer-8', + 'deer-10', + 'deer-14', + 'dog-1', + 'dog-7', + 'dog-15', + 'dog-19', + 'guitar-3', + 'guitar-8', + 'guitar-10', + 'guitar-16', + 'person-1', + 'person-5', + 'person-10', + 'person-12', + 'pig-2', + 'pig-10', + 'pig-13', + 'pig-18', + 'rubicCube-1', + 'rubicCube-6', + 'rubicCube-14', + 'rubicCube-19', + 'swing-10', + 'swing-14', + 'swing-17', + 'swing-20', + 'drone-13', + 'drone-15', + 'drone-2', + 'drone-7', + 'pool-12', + 'pool-15', + 'pool-3', + 'pool-7', + 'rabbit-10', + 'rabbit-13', + 'rabbit-17', + 'rabbit-19', + 'racing-10', + 'racing-15', + 'racing-16', + 'racing-20', + 'robot-1', + 'robot-19', + 'robot-5', + 'robot-8', + 'sepia-13', + 'sepia-16', + 'sepia-6', + 'sepia-8', + 'sheep-3', + 'sheep-5', + 'sheep-7', + 'sheep-9', + 'skateboard-16', + 'skateboard-19', + 'skateboard-3', + 'skateboard-8', + 'tank-14', + 'tank-16', + 'tank-6', + 'tank-9', + 'tiger-12', + 'tiger-18', + 'tiger-4', + 'tiger-6', + 'train-1', + 'train-11', + 'train-20', + 'train-7', + 'truck-16', + 'truck-3', + 'truck-6', + 'truck-7', + 'turtle-16', + 'turtle-5', + 'turtle-8', + 'turtle-9', + 'umbrella-17', + 'umbrella-19', + 'umbrella-2', + 'umbrella-9', + 'yoyo-15', + 'yoyo-17', + 'yoyo-19', + 'yoyo-7', + 'zebra-10', + 'zebra-14', + 'zebra-16', + 'zebra-17', + 'elephant-1', + 'elephant-12', + 'elephant-16', + 'elephant-18', + 'goldfish-3', + 'goldfish-7', + 'goldfish-8', + 'goldfish-10', + 'hat-1', + 'hat-2', + 'hat-5', + 'hat-18', + 'kite-4', + 'kite-6', + 'kite-10', + 'kite-15', + 'motorcycle-1', + 'motorcycle-3', + 'motorcycle-9', + 'motorcycle-18', + 'mouse-1', + 'mouse-8', + 'mouse-9', + 'mouse-17', + 'flag-3', + 'flag-9', + 'flag-5', + 'flag-2', + 'frog-3', + 'frog-4', + 'frog-20', + 'frog-9', + 'gametarget-1', + 'gametarget-2', + 'gametarget-7', + 'gametarget-13', + 'hand-2', + 'hand-3', + 'hand-9', + 'hand-16', + 'helmet-5', + 'helmet-11', + 'helmet-19', + 'helmet-13', + 'licenseplate-6', + 'licenseplate-12', + 'licenseplate-13', + 'licenseplate-15', + 'electricfan-1', + 'electricfan-10', + 'electricfan-18', + 'electricfan-20', + 'chameleon-3', + 'chameleon-6', + 'chameleon-11', + 'chameleon-20', + 'crocodile-3', + 'crocodile-4', + 'crocodile-10', + 'crocodile-14', + 'gecko-1', + 'gecko-5', + 'gecko-16', + 'gecko-19', + 'fox-2', + 'fox-3', + 'fox-5', + 'fox-20', + 'giraffe-2', + 'giraffe-10', + 'giraffe-13', + 'giraffe-15', + 'gorilla-4', + 'gorilla-6', + 'gorilla-9', + 'gorilla-13', + 'hippo-1', + 'hippo-7', + 'hippo-9', + 'hippo-20', + 'horse-1', + 'horse-4', + 'horse-12', + 'horse-15', + 'kangaroo-2', + 'kangaroo-5', + 'kangaroo-11', + 'kangaroo-14', + 'leopard-1', + 'leopard-7', + 'leopard-16', + 'leopard-20', + 'lion-1', + 'lion-5', + 'lion-12', + 'lion-20', + 'lizard-1', + 'lizard-3', + 'lizard-6', + 'lizard-13', + 'microphone-2', + 'microphone-6', + 'microphone-14', + 'microphone-16', + 'monkey-3', + 'monkey-4', + 'monkey-9', + 'monkey-17', + 'shark-2', + 'shark-3', + 'shark-5', + 'shark-6', + 'squirrel-8', + 'squirrel-11', + 'squirrel-13', + 'squirrel-19', + 'volleyball-1', + 'volleyball-13', + 'volleyball-18', + 'volleyball-19'] + return sequence_list diff --git a/Stark/lib/test/evaluation/lasotdataset.py b/Stark/lib/test/evaluation/lasotdataset.py new file mode 100755 index 0000000..223be1b --- /dev/null +++ b/Stark/lib/test/evaluation/lasotdataset.py @@ -0,0 +1,342 @@ +import numpy as np +from lib.test.evaluation.data import Sequence, BaseDataset, SequenceList +from lib.test.utils.load_text import load_text + + +class LaSOTDataset(BaseDataset): + """ + LaSOT test set consisting of 280 videos (see Protocol-II in the LaSOT paper) + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.lasot_path + self.sequence_list = self._get_sequence_list() + self.clean_list = self.clean_seq_list() + + def clean_seq_list(self): + clean_lst = [] + for i in range(len(self.sequence_list)): + cls, _ = self.sequence_list[i].split('-') + clean_lst.append(cls) + return clean_lst + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + class_name = sequence_name.split('-')[0] + anno_path = '{}/{}/{}/groundtruth.txt'.format(self.base_path, class_name, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + occlusion_label_path = '{}/{}/{}/full_occlusion.txt'.format(self.base_path, class_name, sequence_name) + + # NOTE: pandas backed seems super super slow for loading occlusion/oov masks + full_occlusion = load_text(str(occlusion_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + out_of_view_label_path = '{}/{}/{}/out_of_view.txt'.format(self.base_path, class_name, sequence_name) + out_of_view = load_text(str(out_of_view_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + target_visible = np.logical_and(full_occlusion == 0, out_of_view == 0) + + frames_path = '{}/{}/{}/img'.format(self.base_path, class_name, sequence_name) + + frames_list = ['{}/{:08d}.jpg'.format(frames_path, frame_number) for frame_number in range(1, ground_truth_rect.shape[0] + 1)] + + target_class = class_name + return Sequence(sequence_name, frames_list, 'lasot', ground_truth_rect.reshape(-1, 4), + object_class=target_class, target_visible=target_visible) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list = ['airplane-1', + 'airplane-9', + 'airplane-13', + 'airplane-15', + 'basketball-1', + 'basketball-6', + 'basketball-7', + 'basketball-11', + 'bear-2', + 'bear-4', + 'bear-6', + 'bear-17', + 'bicycle-2', + 'bicycle-7', + 'bicycle-9', + 'bicycle-18', + 'bird-2', + 'bird-3', + 'bird-15', + 'bird-17', + 'boat-3', + 'boat-4', + 'boat-12', + 'boat-17', + 'book-3', + 'book-10', + 'book-11', + 'book-19', + 'bottle-1', + 'bottle-12', + 'bottle-14', + 'bottle-18', + 'bus-2', + 'bus-5', + 'bus-17', + 'bus-19', + 'car-2', + 'car-6', + 'car-9', + 'car-17', + 'cat-1', + 'cat-3', + 'cat-18', + 'cat-20', + 'cattle-2', + 'cattle-7', + 'cattle-12', + 'cattle-13', + 'spider-14', + 'spider-16', + 'spider-18', + 'spider-20', + 'coin-3', + 'coin-6', + 'coin-7', + 'coin-18', + 'crab-3', + 'crab-6', + 'crab-12', + 'crab-18', + 'surfboard-12', + 'surfboard-4', + 'surfboard-5', + 'surfboard-8', + 'cup-1', + 'cup-4', + 'cup-7', + 'cup-17', + 'deer-4', + 'deer-8', + 'deer-10', + 'deer-14', + 'dog-1', + 'dog-7', + 'dog-15', + 'dog-19', + 'guitar-3', + 'guitar-8', + 'guitar-10', + 'guitar-16', + 'person-1', + 'person-5', + 'person-10', + 'person-12', + 'pig-2', + 'pig-10', + 'pig-13', + 'pig-18', + 'rubicCube-1', + 'rubicCube-6', + 'rubicCube-14', + 'rubicCube-19', + 'swing-10', + 'swing-14', + 'swing-17', + 'swing-20', + 'drone-13', + 'drone-15', + 'drone-2', + 'drone-7', + 'pool-12', + 'pool-15', + 'pool-3', + 'pool-7', + 'rabbit-10', + 'rabbit-13', + 'rabbit-17', + 'rabbit-19', + 'racing-10', + 'racing-15', + 'racing-16', + 'racing-20', + 'robot-1', + 'robot-19', + 'robot-5', + 'robot-8', + 'sepia-13', + 'sepia-16', + 'sepia-6', + 'sepia-8', + 'sheep-3', + 'sheep-5', + 'sheep-7', + 'sheep-9', + 'skateboard-16', + 'skateboard-19', + 'skateboard-3', + 'skateboard-8', + 'tank-14', + 'tank-16', + 'tank-6', + 'tank-9', + 'tiger-12', + 'tiger-18', + 'tiger-4', + 'tiger-6', + 'train-1', + 'train-11', + 'train-20', + 'train-7', + 'truck-16', + 'truck-3', + 'truck-6', + 'truck-7', + 'turtle-16', + 'turtle-5', + 'turtle-8', + 'turtle-9', + 'umbrella-17', + 'umbrella-19', + 'umbrella-2', + 'umbrella-9', + 'yoyo-15', + 'yoyo-17', + 'yoyo-19', + 'yoyo-7', + 'zebra-10', + 'zebra-14', + 'zebra-16', + 'zebra-17', + 'elephant-1', + 'elephant-12', + 'elephant-16', + 'elephant-18', + 'goldfish-3', + 'goldfish-7', + 'goldfish-8', + 'goldfish-10', + 'hat-1', + 'hat-2', + 'hat-5', + 'hat-18', + 'kite-4', + 'kite-6', + 'kite-10', + 'kite-15', + 'motorcycle-1', + 'motorcycle-3', + 'motorcycle-9', + 'motorcycle-18', + 'mouse-1', + 'mouse-8', + 'mouse-9', + 'mouse-17', + 'flag-3', + 'flag-9', + 'flag-5', + 'flag-2', + 'frog-3', + 'frog-4', + 'frog-20', + 'frog-9', + 'gametarget-1', + 'gametarget-2', + 'gametarget-7', + 'gametarget-13', + 'hand-2', + 'hand-3', + 'hand-9', + 'hand-16', + 'helmet-5', + 'helmet-11', + 'helmet-19', + 'helmet-13', + 'licenseplate-6', + 'licenseplate-12', + 'licenseplate-13', + 'licenseplate-15', + 'electricfan-1', + 'electricfan-10', + 'electricfan-18', + 'electricfan-20', + 'chameleon-3', + 'chameleon-6', + 'chameleon-11', + 'chameleon-20', + 'crocodile-3', + 'crocodile-4', + 'crocodile-10', + 'crocodile-14', + 'gecko-1', + 'gecko-5', + 'gecko-16', + 'gecko-19', + 'fox-2', + 'fox-3', + 'fox-5', + 'fox-20', + 'giraffe-2', + 'giraffe-10', + 'giraffe-13', + 'giraffe-15', + 'gorilla-4', + 'gorilla-6', + 'gorilla-9', + 'gorilla-13', + 'hippo-1', + 'hippo-7', + 'hippo-9', + 'hippo-20', + 'horse-1', + 'horse-4', + 'horse-12', + 'horse-15', + 'kangaroo-2', + 'kangaroo-5', + 'kangaroo-11', + 'kangaroo-14', + 'leopard-1', + 'leopard-7', + 'leopard-16', + 'leopard-20', + 'lion-1', + 'lion-5', + 'lion-12', + 'lion-20', + 'lizard-1', + 'lizard-3', + 'lizard-6', + 'lizard-13', + 'microphone-2', + 'microphone-6', + 'microphone-14', + 'microphone-16', + 'monkey-3', + 'monkey-4', + 'monkey-9', + 'monkey-17', + 'shark-2', + 'shark-3', + 'shark-5', + 'shark-6', + 'squirrel-8', + 'squirrel-11', + 'squirrel-13', + 'squirrel-19', + 'volleyball-1', + 'volleyball-13', + 'volleyball-18', + 'volleyball-19'] + return sequence_list diff --git a/Stark/lib/test/evaluation/local.py b/Stark/lib/test/evaluation/local.py new file mode 100755 index 0000000..fee8779 --- /dev/null +++ b/Stark/lib/test/evaluation/local.py @@ -0,0 +1,32 @@ +import vot_path +from lib.test.evaluation.environment import EnvSettings + +def local_env_settings(): + settings = EnvSettings() + + # Set your local paths here. + + settings.davis_dir = '' + settings.got10k_lmdb_path = vot_path.base_path+'/mlpLT/Stark/data/got10k_lmdb' + settings.got10k_path = vot_path.base_path+'/mlpLT/Stark/data/got10k' + settings.got_packed_results_path = '' + settings.got_reports_path = '' + settings.lasot_lmdb_path = vot_path.base_path+'/mlpLT/Stark/data/lasot_lmdb' + settings.lasot_path = vot_path.base_path+'/mlpLT/Stark/data/lasot' + settings.network_path = vot_path.base_path+'/mlpLT/Stark/test/networks' # Where tracking networks are stored. + settings.nfs_path = '' + settings.otb_path = '' + settings.prj_dir = vot_path.base_path+'/mlpLT/Stark' + settings.result_plot_path = vot_path.base_path+'/mlpLT/Stark/test/result_plots' + settings.results_path = vot_path.base_path+'/mlpLT/Stark/test/tracking_results' # Where to store tracking results + settings.save_dir = vot_path.base_path+'/mlpLT/Stark' + settings.segmentation_path = vot_path.base_path+'/mlpLT/Stark/test/segmentation_results' + settings.tn_packed_results_path = '' + settings.tpl_path = '' + settings.trackingnet_path = vot_path.base_path+'/mlpLT/Stark/data/trackingNet' + settings.uav_path = '' + settings.vot_path = vot_path.base_path+'/mlpLT/Stark/data/VOT2019' + settings.youtubevos_dir = '' + + return settings + diff --git a/Stark/lib/test/evaluation/running.py b/Stark/lib/test/evaluation/running.py new file mode 100755 index 0000000..fa0d245 --- /dev/null +++ b/Stark/lib/test/evaluation/running.py @@ -0,0 +1,183 @@ +import numpy as np +import multiprocessing +import os +import sys +from itertools import product +from collections import OrderedDict +from lib.test.evaluation import Sequence, Tracker +import torch + + +def _save_tracker_output(seq: Sequence, tracker: Tracker, output: dict): + """Saves the output of the tracker.""" + + if not os.path.exists(tracker.results_dir): + print("create tracking result dir:", tracker.results_dir) + os.makedirs(tracker.results_dir) + if seq.dataset in ['trackingnet', 'got10k']: + if not os.path.exists(os.path.join(tracker.results_dir, seq.dataset)): + os.makedirs(os.path.join(tracker.results_dir, seq.dataset)) + '''2021.1.5 create new folder for these two datasets''' + if seq.dataset in ['trackingnet', 'got10k']: + base_results_path = os.path.join(tracker.results_dir, seq.dataset, seq.name) + else: + base_results_path = os.path.join(tracker.results_dir, seq.name) + + def save_bb(file, data): + tracked_bb = np.array(data).astype(int) + np.savetxt(file, tracked_bb, delimiter='\t', fmt='%d') + + def save_time(file, data): + exec_times = np.array(data).astype(float) + np.savetxt(file, exec_times, delimiter='\t', fmt='%f') + + def save_score(file, data): + scores = np.array(data).astype(float) + np.savetxt(file, scores, delimiter='\t', fmt='%.2f') + + def _convert_dict(input_dict): + data_dict = {} + for elem in input_dict: + for k, v in elem.items(): + if k in data_dict.keys(): + data_dict[k].append(v) + else: + data_dict[k] = [v, ] + return data_dict + + for key, data in output.items(): + # If data is empty + if not data: + continue + + if key == 'target_bbox': + if isinstance(data[0], (dict, OrderedDict)): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + bbox_file = '{}_{}.txt'.format(base_results_path, obj_id) + save_bb(bbox_file, d) + else: + # Single-object mode + bbox_file = '{}.txt'.format(base_results_path) + save_bb(bbox_file, data) + + if key == 'all_boxes': + if isinstance(data[0], (dict, OrderedDict)): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + bbox_file = '{}_{}_all_boxes.txt'.format(base_results_path, obj_id) + save_bb(bbox_file, d) + else: + # Single-object mode + bbox_file = '{}_all_boxes.txt'.format(base_results_path) + save_bb(bbox_file, data) + + if key == 'all_scores': + if isinstance(data[0], (dict, OrderedDict)): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + bbox_file = '{}_{}_all_scores.txt'.format(base_results_path, obj_id) + save_score(bbox_file, d) + else: + # Single-object mode + print("saving scores...") + bbox_file = '{}_all_scores.txt'.format(base_results_path) + save_score(bbox_file, data) + + elif key == 'time': + if isinstance(data[0], dict): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + timings_file = '{}_{}_time.txt'.format(base_results_path, obj_id) + save_time(timings_file, d) + else: + timings_file = '{}_time.txt'.format(base_results_path) + save_time(timings_file, data) + + +def run_sequence(seq: Sequence, tracker: Tracker, debug=False, num_gpu=8): + """Runs a tracker on a sequence.""" + '''2021.1.2 Add multiple gpu support''' + try: + worker_name = multiprocessing.current_process().name + worker_id = int(worker_name[worker_name.find('-') + 1:]) - 1 + gpu_id = worker_id % num_gpu + torch.cuda.set_device(gpu_id) + except: + pass + + def _results_exist(): + if seq.object_ids is None: + if seq.dataset in ['trackingnet', 'got10k']: + base_results_path = os.path.join(tracker.results_dir, seq.dataset, seq.name) + bbox_file = '{}.txt'.format(base_results_path) + else: + bbox_file = '{}/{}.txt'.format(tracker.results_dir, seq.name) + return os.path.isfile(bbox_file) + else: + bbox_files = ['{}/{}_{}.txt'.format(tracker.results_dir, seq.name, obj_id) for obj_id in seq.object_ids] + missing = [not os.path.isfile(f) for f in bbox_files] + return sum(missing) == 0 + + if _results_exist() and not debug: + print('FPS: {}'.format(-1)) + return + + print('Tracker: {} {} {} , Sequence: {}'.format(tracker.name, tracker.parameter_name, tracker.run_id, seq.name)) + + if debug: + output = tracker.run_sequence(seq, debug=debug) + else: + try: + output = tracker.run_sequence(seq, debug=debug) + except Exception as e: + print(e) + return + + sys.stdout.flush() + + if isinstance(output['time'][0], (dict, OrderedDict)): + exec_time = sum([sum(times.values()) for times in output['time']]) + num_frames = len(output['time']) + else: + exec_time = sum(output['time']) + num_frames = len(output['time']) + + print('FPS: {}'.format(num_frames / exec_time)) + + if not debug: + _save_tracker_output(seq, tracker, output) + + +def run_dataset(dataset, trackers, debug=False, threads=0, num_gpus=8): + """Runs a list of trackers on a dataset. + args: + dataset: List of Sequence instances, forming a dataset. + trackers: List of Tracker instances. + debug: Debug level. + threads: Number of threads to use (default 0). + """ + multiprocessing.set_start_method('spawn', force=True) + + print('Evaluating {:4d} trackers on {:5d} sequences'.format(len(trackers), len(dataset))) + + multiprocessing.set_start_method('spawn', force=True) + + if threads == 0: + mode = 'sequential' + else: + mode = 'parallel' + + if mode == 'sequential': + for seq in dataset: + for tracker_info in trackers: + run_sequence(seq, tracker_info, debug=debug) + elif mode == 'parallel': + param_list = [(seq, tracker_info, debug, num_gpus) for seq, tracker_info in product(dataset, trackers)] + with multiprocessing.Pool(processes=threads) as pool: + pool.starmap(run_sequence, param_list) + print('Done') diff --git a/Stark/lib/test/evaluation/tracker.py b/Stark/lib/test/evaluation/tracker.py new file mode 100755 index 0000000..11c1da7 --- /dev/null +++ b/Stark/lib/test/evaluation/tracker.py @@ -0,0 +1,168 @@ +import importlib +import os +from collections import OrderedDict +from lib.test.evaluation.environment import env_settings +import time +import cv2 as cv + +from lib.utils.lmdb_utils import decode_img + + +def trackerlist(name: str, parameter_name: str, dataset_name: str, run_ids = None, display_name: str = None, + result_only=False): + """Generate list of trackers. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_ids: A single or list of run_ids. + display_name: Name to be displayed in the result plots. + """ + if run_ids is None or isinstance(run_ids, int): + run_ids = [run_ids] + return [Tracker(name, parameter_name, dataset_name, run_id, display_name, result_only) for run_id in run_ids] + + +class Tracker: + """Wraps the tracker for evaluation and running purposes. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_id: The run id. + display_name: Name to be displayed in the result plots. + """ + + def __init__(self, name: str, parameter_name: str, dataset_name: str, run_id: int = None, display_name: str = None, + result_only=False): + assert run_id is None or isinstance(run_id, int) + + self.name = name + self.parameter_name = parameter_name + self.dataset_name = dataset_name + self.run_id = run_id + self.display_name = display_name + + env = env_settings() + #""" + if self.run_id is None: + self.results_dir = '{}/{}/{}'.format(env.results_path, self.name, self.parameter_name) + else: + self.results_dir = '{}/{}/{}_{:03d}'.format(env.results_path, self.name, self.parameter_name, self.run_id) + if result_only: + self.results_dir = '{}/{}/{}'.format(env.results_path, "LaSOT", self.name) + #""" + + tracker_module_abspath = os.path.abspath(os.path.join(os.path.dirname(__file__), + '..', 'tracker', '%s.py' % self.name)) + if os.path.isfile(tracker_module_abspath): + tracker_module = importlib.import_module('lib.test.tracker.{}'.format(self.name)) + self.tracker_class = tracker_module.get_tracker_class() + else: + self.tracker_class = None + + def create_tracker(self, params): + tracker = self.tracker_class(params, self.dataset_name) + return tracker + + def run_sequence(self, seq, debug=None): + """Run tracker on sequence. + args: + seq: Sequence to run the tracker on. + visualization: Set visualization flag (None means default value specified in the parameters). + debug: Set debug level (None means default value specified in the parameters). + multiobj_mode: Which mode to use for multiple objects. + """ + params = self.get_parameters() + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + + params.debug = debug_ + + # Get init information + init_info = seq.init_info() + + tracker = self.create_tracker(params) + + output = self._track_sequence(tracker, seq, init_info) + return output + + def _track_sequence(self, tracker, seq, init_info): + # Define outputs + # Each field in output is a list containing tracker prediction for each frame. + + # In case of single object tracking mode: + # target_bbox[i] is the predicted bounding box for frame i + # time[i] is the processing time for frame i + + # In case of multi object tracking mode: + # target_bbox[i] is an OrderedDict, where target_bbox[i][obj_id] is the predicted box for target obj_id in + # frame i + # time[i] is either the processing time for frame i, or an OrderedDict containing processing times for each + # object in frame i + + output = {'target_bbox': [], + 'time': []} + if tracker.params.save_all_boxes: + output['all_boxes'] = [] + output['all_scores'] = [] + + def _store_outputs(tracker_out: dict, defaults=None): + defaults = {} if defaults is None else defaults + for key in output.keys(): + val = tracker_out.get(key, defaults.get(key, None)) + if key in tracker_out or val is not None: + output[key].append(val) + + # Initialize + image = self._read_image(seq.frames[0]) + + start_time = time.time() + out = tracker.initialize(image, init_info) + if out is None: + out = {} + + prev_output = OrderedDict(out) + init_default = {'target_bbox': init_info.get('init_bbox'), + 'time': time.time() - start_time} + if tracker.params.save_all_boxes: + init_default['all_boxes'] = out['all_boxes'] + init_default['all_scores'] = out['all_scores'] + + _store_outputs(out, init_default) + + for frame_num, frame_path in enumerate(seq.frames[1:], start=1): + image = self._read_image(frame_path) + + start_time = time.time() + + info = seq.frame_info(frame_num) + info['previous_output'] = prev_output + + out = tracker.track(image, info) + prev_output = OrderedDict(out) + _store_outputs(out, {'time': time.time() - start_time}) + + for key in ['target_bbox', 'all_boxes', 'all_scores']: + if key in output and len(output[key]) <= 1: + output.pop(key) + + return output + + def get_parameters(self): + """Get parameters.""" + param_module = importlib.import_module('lib.test.parameter.{}'.format(self.name)) + params = param_module.parameters(self.parameter_name) + return params + + def _read_image(self, image_file: str): + if isinstance(image_file, str): + im = cv.imread(image_file) + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + elif isinstance(image_file, list) and len(image_file) == 2: + return decode_img(image_file[0], image_file[1]) + else: + raise ValueError("type of image_file should be str or list") + + + diff --git a/Stark/lib/test/evaluation/trackingnetdataset.py b/Stark/lib/test/evaluation/trackingnetdataset.py new file mode 100755 index 0000000..8dc2619 --- /dev/null +++ b/Stark/lib/test/evaluation/trackingnetdataset.py @@ -0,0 +1,58 @@ +import numpy as np +from lib.test.evaluation.data import Sequence, BaseDataset, SequenceList +import os +from lib.test.utils.load_text import load_text + + +class TrackingNetDataset(BaseDataset): + """ TrackingNet test set. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.trackingnet_path + + sets = 'TEST' + if not isinstance(sets, (list, tuple)): + if sets == 'TEST': + sets = ['TEST'] + elif sets == 'TRAIN': + sets = ['TRAIN_{}'.format(i) for i in range(5)] + + self.sequence_list = self._list_sequences(self.base_path, sets) + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(set, seq_name) for set, seq_name in self.sequence_list]) + + def _construct_sequence(self, set, sequence_name): + anno_path = '{}/{}/anno/{}.txt'.format(self.base_path, set, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64, backend='numpy') + + frames_path = '{}/{}/frames/{}'.format(self.base_path, set, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'trackingnet', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _list_sequences(self, root, set_ids): + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, s, "anno") + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + + sequence_list += sequences_cur_set + + return sequence_list diff --git a/Stark/lib/test/parameter/__init__.py b/Stark/lib/test/parameter/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/test/parameter/__pycache__/__init__.cpython-37.pyc b/Stark/lib/test/parameter/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..38ebd6f Binary files /dev/null and b/Stark/lib/test/parameter/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/test/parameter/__pycache__/stark_st.cpython-37.pyc b/Stark/lib/test/parameter/__pycache__/stark_st.cpython-37.pyc new file mode 100755 index 0000000..cb4176a Binary files /dev/null and b/Stark/lib/test/parameter/__pycache__/stark_st.cpython-37.pyc differ diff --git a/Stark/lib/test/parameter/stark_s.py b/Stark/lib/test/parameter/stark_s.py new file mode 100755 index 0000000..adef0ef --- /dev/null +++ b/Stark/lib/test/parameter/stark_s.py @@ -0,0 +1,30 @@ +from lib.test.utils import TrackerParams +import os +from lib.test.evaluation.environment import env_settings +from lib.config.stark_s.config import cfg, update_config_from_file + + +def parameters(yaml_name: str): + params = TrackerParams() + prj_dir = env_settings().prj_dir + save_dir = env_settings().save_dir + # update default config from yaml file + yaml_file = os.path.join(prj_dir, 'experiments/stark_s/%s.yaml' % yaml_name) + update_config_from_file(yaml_file) + params.cfg = cfg + print("test config: ", cfg) + + # template and search region + params.template_factor = cfg.TEST.TEMPLATE_FACTOR + params.template_size = cfg.TEST.TEMPLATE_SIZE + params.search_factor = cfg.TEST.SEARCH_FACTOR + params.search_size = cfg.TEST.SEARCH_SIZE + + # Network checkpoint path + params.checkpoint = os.path.join(save_dir, "checkpoints/train/stark_s/%s/STARKS_ep%04d.pth.tar" % + (yaml_name, cfg.TEST.EPOCH)) + + # whether to save boxes from all queries + params.save_all_boxes = False + + return params diff --git a/Stark/lib/test/parameter/stark_st.py b/Stark/lib/test/parameter/stark_st.py new file mode 100755 index 0000000..21a80c8 --- /dev/null +++ b/Stark/lib/test/parameter/stark_st.py @@ -0,0 +1,30 @@ +from lib.test.utils import TrackerParams +import os +from lib.test.evaluation.environment import env_settings +from lib.config.stark_st2.config import cfg, update_config_from_file +import vot_path + + +def parameters(yaml_name: str): + params = TrackerParams() + prj_dir = env_settings().prj_dir + save_dir = env_settings().save_dir + # update default config from yaml file + yaml_file = os.path.join(prj_dir, 'experiments/stark_st2/%s.yaml' % yaml_name) + update_config_from_file(yaml_file) + params.cfg = cfg + print("test config: ", cfg) + + # template and search region + params.template_factor = cfg.TEST.TEMPLATE_FACTOR + params.template_size = cfg.TEST.TEMPLATE_SIZE + params.search_factor = cfg.TEST.SEARCH_FACTOR + params.search_size = cfg.TEST.SEARCH_SIZE + + # Network checkpoint path + params.checkpoint = os.path.join(vot_path.base_path, "mlpLT/ckpt/STARKST_ep0050.pth.tar") #os.path.join(save_dir, "lib/test/networks/%s/STARKST_ep%04d.pth.tar" % (yaml_name, cfg.TEST.EPOCH)) + + # whether to save boxes from all queries + params.save_all_boxes = False + + return params diff --git a/Stark/lib/test/tracker/__init__.py b/Stark/lib/test/tracker/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/Stark/lib/test/tracker/__pycache__/__init__.cpython-37.pyc b/Stark/lib/test/tracker/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..1a834f3 Binary files /dev/null and b/Stark/lib/test/tracker/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/test/tracker/__pycache__/basetracker.cpython-37.pyc b/Stark/lib/test/tracker/__pycache__/basetracker.cpython-37.pyc new file mode 100755 index 0000000..dd3b06d Binary files /dev/null and b/Stark/lib/test/tracker/__pycache__/basetracker.cpython-37.pyc differ diff --git a/Stark/lib/test/tracker/__pycache__/stark_st.cpython-37.pyc b/Stark/lib/test/tracker/__pycache__/stark_st.cpython-37.pyc new file mode 100755 index 0000000..1743093 Binary files /dev/null and b/Stark/lib/test/tracker/__pycache__/stark_st.cpython-37.pyc differ diff --git a/Stark/lib/test/tracker/__pycache__/stark_utils.cpython-37.pyc b/Stark/lib/test/tracker/__pycache__/stark_utils.cpython-37.pyc new file mode 100755 index 0000000..9eade64 Binary files /dev/null and b/Stark/lib/test/tracker/__pycache__/stark_utils.cpython-37.pyc differ diff --git a/Stark/lib/test/tracker/basetracker.py b/Stark/lib/test/tracker/basetracker.py new file mode 100755 index 0000000..7224c67 --- /dev/null +++ b/Stark/lib/test/tracker/basetracker.py @@ -0,0 +1,30 @@ +from _collections import OrderedDict + + +class BaseTracker: + """Base class for all trackers.""" + + def __init__(self, params): + self.params = params + self.visdom = None + + def predicts_segmentation_mask(self): + return False + + def initialize(self, image, info: dict) -> dict: + """Overload this function in your tracker. This should initialize the model.""" + raise NotImplementedError + + def track(self, image, info: dict = None) -> dict: + """Overload this function in your tracker. This should track in the frame and update the model.""" + raise NotImplementedError + + def visdom_draw_tracking(self, image, box, segmentation=None): + if isinstance(box, OrderedDict): + box = [v for k, v in box.items()] + else: + box = (box,) + if segmentation is None: + self.visdom.register((image, *box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, *box, segmentation), 'Tracking', 1, 'Tracking') \ No newline at end of file diff --git a/Stark/lib/test/tracker/stark_s.py b/Stark/lib/test/tracker/stark_s.py new file mode 100755 index 0000000..d551349 --- /dev/null +++ b/Stark/lib/test/tracker/stark_s.py @@ -0,0 +1,103 @@ +from lib.test.tracker.basetracker import BaseTracker +import torch +from lib.train.data.processing_utils import sample_target +# for debug +import cv2 +import os +from lib.utils.merge import merge_template_search +from lib.models.stark import build_starks +from lib.test.tracker.stark_utils import Preprocessor +from lib.utils.box_ops import clip_box + + +class STARK_S(BaseTracker): + def __init__(self, params, dataset_name): + super(STARK_S, self).__init__(params) + network = build_starks(params.cfg) + network.load_state_dict(torch.load(self.params.checkpoint, map_location='cpu')['net'], strict=True) + self.cfg = params.cfg + self.network = network.cuda() + self.network.eval() + self.preprocessor = Preprocessor() + self.state = None + # for debug + self.debug = False + self.frame_id = 0 + if self.debug: + self.save_dir = "debug" + if not os.path.exists(self.save_dir): + os.makedirs(self.save_dir) + # for save boxes from all queries + self.save_all_boxes = params.save_all_boxes + self.z_dict1 = {} + + def initialize(self, image, info: dict): + # forward the template once + z_patch_arr, _, z_amask_arr = sample_target(image, info['init_bbox'], self.params.template_factor, + output_sz=self.params.template_size) + template = self.preprocessor.process(z_patch_arr, z_amask_arr) + with torch.no_grad(): + self.z_dict1 = self.network.forward_backbone(template) + # save states + self.state = info['init_bbox'] + self.frame_id = 0 + if self.save_all_boxes: + '''save all predicted boxes''' + all_boxes_save = info['init_bbox'] * self.cfg.MODEL.NUM_OBJECT_QUERIES + return {"all_boxes": all_boxes_save} + + def track(self, image, info: dict = None): + H, W, _ = image.shape + self.frame_id += 1 + x_patch_arr, resize_factor, x_amask_arr = sample_target(image, self.state, self.params.search_factor, + output_sz=self.params.search_size) # (x1, y1, w, h) + search = self.preprocessor.process(x_patch_arr, x_amask_arr) + with torch.no_grad(): + x_dict = self.network.forward_backbone(search) + # merge the template and the search + feat_dict_list = [self.z_dict1, x_dict] + seq_dict = merge_template_search(feat_dict_list) + # run the transformer + out_dict, _, _ = self.network.forward_transformer(seq_dict=seq_dict, run_box_head=True) + + pred_boxes = out_dict['pred_boxes'].view(-1, 4) + # Baseline: Take the mean of all pred boxes as the final result + pred_box = (pred_boxes.mean(dim=0) * self.params.search_size / resize_factor).tolist() # (cx, cy, w, h) [0,1] + # get the final box result + self.state = clip_box(self.map_box_back(pred_box, resize_factor), H, W, margin=10) + + # for debug + if self.debug: + x1, y1, w, h = self.state + image_BGR = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.rectangle(image_BGR, (int(x1),int(y1)), (int(x1+w),int(y1+h)), color=(0,0,255), thickness=2) + save_path = os.path.join(self.save_dir, "%04d.jpg" % self.frame_id) + cv2.imwrite(save_path, image_BGR) + if self.save_all_boxes: + '''save all predictions''' + all_boxes = self.map_box_back_batch(pred_boxes * self.params.search_size / resize_factor, resize_factor) + all_boxes_save = all_boxes.view(-1).tolist() # (4N, ) + return {"target_bbox": self.state, + "all_boxes": all_boxes_save} + else: + return {"target_bbox": self.state} + + def map_box_back(self, pred_box: list, resize_factor: float): + cx_prev, cy_prev = self.state[0] + 0.5 * self.state[2], self.state[1] + 0.5 * self.state[3] + cx, cy, w, h = pred_box + half_side = 0.5 * self.params.search_size / resize_factor + cx_real = cx + (cx_prev - half_side) + cy_real = cy + (cy_prev - half_side) + return [cx_real - 0.5 * w, cy_real - 0.5 * h, w, h] + + def map_box_back_batch(self, pred_box: torch.Tensor, resize_factor: float): + cx_prev, cy_prev = self.state[0] + 0.5 * self.state[2], self.state[1] + 0.5 * self.state[3] + cx, cy, w, h = pred_box.unbind(-1) # (N,4) --> (N,) + half_side = 0.5 * self.params.search_size / resize_factor + cx_real = cx + (cx_prev - half_side) + cy_real = cy + (cy_prev - half_side) + return torch.stack([cx_real - 0.5 * w, cy_real - 0.5 * h, w, h], dim=-1) + + +def get_tracker_class(): + return STARK_S diff --git a/Stark/lib/test/tracker/stark_st.py b/Stark/lib/test/tracker/stark_st.py new file mode 100755 index 0000000..86b2a4a --- /dev/null +++ b/Stark/lib/test/tracker/stark_st.py @@ -0,0 +1,206 @@ +from lib.test.tracker.basetracker import BaseTracker +import torch +from lib.train.data.processing_utils import sample_target +from copy import deepcopy +# for debug +import cv2 +import os +from lib.utils.merge import merge_template_search +from lib.models.stark import build_starkst +from lib.test.tracker.stark_utils import Preprocessor +from lib.utils.box_ops import clip_box + + +class STARK_ST(BaseTracker): + def __init__(self, params, dataset_name): + super(STARK_ST, self).__init__(params) + network = build_starkst(params.cfg) + network.load_state_dict(torch.load(self.params.checkpoint, map_location='cpu')['net'], strict=True) + self.cfg = params.cfg + self.network = network.cuda() + self.network.eval() + self.preprocessor = Preprocessor() + self.state = None + # for debug + self.debug = False + self.frame_id = 0 + if self.debug: + self.save_dir = "debug" + if not os.path.exists(self.save_dir): + os.makedirs(self.save_dir) + # for save boxes from all queries + self.save_all_boxes = params.save_all_boxes + # template update + self.z_dict1 = {} + self.z_dict_list = [] + # Set the update interval + DATASET_NAME = dataset_name.upper() + if hasattr(self.cfg.TEST.UPDATE_INTERVALS, DATASET_NAME): + self.update_intervals = self.cfg.TEST.UPDATE_INTERVALS[DATASET_NAME] + else: + self.update_intervals = self.cfg.DATA.MAX_SAMPLE_INTERVAL + print("Update interval is: ", self.update_intervals) + self.num_extra_template = len(self.update_intervals) + + def initialize(self, image, info: dict): + # initialize z_dict_list + self.z_dict_list = [] + # get the 1st template + z_patch_arr1, _, z_amask_arr1 = sample_target(image, info['init_bbox'], self.params.template_factor, + output_sz=self.params.template_size) + template1 = self.preprocessor.process(z_patch_arr1, z_amask_arr1) + with torch.no_grad(): + self.z_dict1 = self.network.forward_backbone(template1) + # get the complete z_dict_list + self.z_dict_list.append(self.z_dict1) + for i in range(self.num_extra_template): + self.z_dict_list.append(deepcopy(self.z_dict1)) + + # save states + self.state = info['init_bbox'] + self.frame_id = 0 + #self.update_idx = 200 + if self.save_all_boxes: + '''save all predicted boxes''' + all_boxes_save = info['init_bbox'] * self.cfg.MODEL.NUM_OBJECT_QUERIES + return {"all_boxes": all_boxes_save} + + def track(self, image, info: dict = None, detect=False): + H, W, _ = image.shape + if not detect: + self.frame_id += 1 + # get the t-th search region + x_patch_arr, resize_factor, x_amask_arr = sample_target(image, self.state, self.params.search_factor, + output_sz=self.params.search_size) # (x1, y1, w, h) + search = self.preprocessor.process(x_patch_arr, x_amask_arr) + with torch.no_grad(): + x_dict = self.network.forward_backbone(search) + # merge the template and the search + feat_dict_list = self.z_dict_list + [x_dict] + seq_dict = merge_template_search(feat_dict_list) + # run the transformer + out_dict, _, _ = self.network.forward_transformer(seq_dict=seq_dict, run_box_head=True, run_cls_head=True) + # get the final result + pred_boxes = out_dict['pred_boxes'].view(-1, 4) + # Baseline: Take the mean of all pred boxes as the final result + pred_box = (pred_boxes.mean(dim=0) * self.params.search_size / resize_factor).tolist() # (cx, cy, w, h) [0,1] + # get the final box result + self.state = clip_box(self.map_box_back(pred_box, resize_factor), H, W, margin=10) + # get confidence score (whether the search region is reliable) + conf_score = out_dict["pred_logits"].view(-1).sigmoid().item() + #conf_score = (out_dict["pred_logits"].view(-1) * 0.9).sigmoid().item() + # update template + for idx, update_i in enumerate(self.update_intervals): + if self.frame_id % update_i == 0 and conf_score > 0.5: + z_patch_arr, _, z_amask_arr = sample_target(image, self.state, self.params.template_factor, + output_sz=self.params.template_size) # (x1, y1, w, h) + template_t = self.preprocessor.process(z_patch_arr, z_amask_arr) + with torch.no_grad(): + z_dict_t = self.network.forward_backbone(template_t) + self.z_dict_list[idx+1] = z_dict_t # the 1st element of z_dict_list is template from the 1st frame + + # for debug + if self.debug: + x1, y1, w, h = self.state + image_BGR = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) + cv2.rectangle(image_BGR, (int(x1),int(y1)), (int(x1+w),int(y1+h)), color=(0,0,255), thickness=2) + save_path = os.path.join(self.save_dir, "%04d.jpg" % self.frame_id) + cv2.imwrite(save_path, image_BGR) + if self.save_all_boxes: + '''save all predictions''' + all_boxes = self.map_box_back_batch(pred_boxes * self.params.search_size / resize_factor, resize_factor) + all_boxes_save = all_boxes.view(-1).tolist() # (4N, ) + return {"target_bbox": self.state, + "all_boxes": all_boxes_save, + "conf_score": conf_score} + else: + return {"target_bbox": self.state, + "conf_score": conf_score} + + def track2(self, image, info: dict = None, detect=False): + H, W, _ = image.shape + if not detect: + self.frame_id += 1 + # get the t-th search region + x_patch_arr, resize_factor, x_amask_arr = sample_target(image, self.state, self.params.search_factor, + output_sz=self.params.search_size) # (x1, y1, w, h) + search = self.preprocessor.process(x_patch_arr, x_amask_arr) + with torch.no_grad(): + x_dict = self.network.forward_backbone(search) + # merge the template and the search + feat_dict_list = self.z_dict_list + [x_dict] + seq_dict = merge_template_search(feat_dict_list) + # run the transformer + out_dict, _, _ = self.network.forward_transformer(seq_dict=seq_dict, run_box_head=True, run_cls_head=True) + # get the final result + pred_boxes = out_dict['pred_boxes'].view(-1, 4) + # Baseline: Take the mean of all pred boxes as the final result + pred_box = (pred_boxes.mean(dim=0) * self.params.search_size / resize_factor).tolist() # (cx, cy, w, h) [0,1] + # get the final box result + self.state = clip_box(self.map_box_back(pred_box, resize_factor), H, W, margin=10) + # get confidence score (whether the search region is reliable) + conf_score = out_dict["pred_logits"].view(-1).sigmoid().item() + + return {"target_bbox": self.state, + "conf_score": conf_score} + """ + def update2(self, image, state, conf_score): + # update template + for idx, update_i in enumerate(self.update_intervals): + if self.frame_id % update_i == 0 and conf_score > 0.5: + z_patch_arr, _, z_amask_arr = sample_target(image, state, self.params.template_factor, + output_sz=self.params.template_size) # (x1, y1, w, h) + template_t = self.preprocessor.process(z_patch_arr, z_amask_arr) + with torch.no_grad(): + z_dict_t = self.network.forward_backbone(template_t) + self.z_dict_list[idx+1] = z_dict_t # the 1st element of z_dict_list is template from the 1st frame + """ + def update2(self, image, state, conf_score): + # update template + #if self.frame_id == self.update_idx and conf_score > 0.5: + if self.frame_id == self.update_idx and conf_score > 3: + z_patch_arr, _, z_amask_arr = sample_target(image, state, self.params.template_factor, + output_sz=self.params.template_size) # (x1, y1, w, h) + template_t = self.preprocessor.process(z_patch_arr, z_amask_arr) + with torch.no_grad(): + z_dict_t = self.network.forward_backbone(template_t) + self.z_dict_list[1] = z_dict_t # the 1st element of z_dict_list is template from the 1st frame + #self.update_idx += self.update_intervals[0] + self.update_idx += (self.update_intervals[0] - self.update_idx % self.update_intervals[0]) + #elif self.frame_id == self.update_idx and conf_score <= 0.5: + elif self.frame_id == self.update_idx and conf_score <= 3: + self.update_idx += 1 + else: + return + + """ + def update2(self, image, state, conf_score): + # update template + z_patch_arr, _, z_amask_arr = sample_target(image, state, self.params.template_factor, + output_sz=self.params.template_size) # (x1, y1, w, h) + template_t = self.preprocessor.process(z_patch_arr, z_amask_arr) + with torch.no_grad(): + z_dict_t = self.network.forward_backbone(template_t) + self.z_dict_list[1] = z_dict_t # the 1st element of z_dict_list is template from the 1st frame + """ + + + def map_box_back(self, pred_box: list, resize_factor: float): + cx_prev, cy_prev = self.state[0] + 0.5 * self.state[2], self.state[1] + 0.5 * self.state[3] + cx, cy, w, h = pred_box + half_side = 0.5 * self.params.search_size / resize_factor + cx_real = cx + (cx_prev - half_side) + cy_real = cy + (cy_prev - half_side) + return [cx_real - 0.5 * w, cy_real - 0.5 * h, w, h] + + def map_box_back_batch(self, pred_box: torch.Tensor, resize_factor: float): + cx_prev, cy_prev = self.state[0] + 0.5 * self.state[2], self.state[1] + 0.5 * self.state[3] + cx, cy, w, h = pred_box.unbind(-1) # (N,4) --> (N,) + half_side = 0.5 * self.params.search_size / resize_factor + cx_real = cx + (cx_prev - half_side) + cy_real = cy + (cy_prev - half_side) + return torch.stack([cx_real - 0.5 * w, cy_real - 0.5 * h, w, h], dim=-1) + + +def get_tracker_class(): + return STARK_ST diff --git a/Stark/lib/test/tracker/stark_utils.py b/Stark/lib/test/tracker/stark_utils.py new file mode 100755 index 0000000..3f98da9 --- /dev/null +++ b/Stark/lib/test/tracker/stark_utils.py @@ -0,0 +1,17 @@ +import torch +import numpy as np +from lib.utils.misc import NestedTensor + + +class Preprocessor(object): + def __init__(self): + self.mean = torch.tensor([0.485, 0.456, 0.406]).view((1, 3, 1, 1)).cuda() + self.std = torch.tensor([0.229, 0.224, 0.225]).view((1, 3, 1, 1)).cuda() + + def process(self, img_arr: np.ndarray, amask_arr: np.ndarray): + # Deal with the image patch + img_tensor = torch.tensor(img_arr).cuda().float().permute((2,0,1)).unsqueeze(dim=0) + img_tensor_norm = ((img_tensor / 255.0) - self.mean) / self.std # (1,3,H,W) + # Deal with the attention mask + amask_tensor = torch.from_numpy(amask_arr).to(torch.bool).cuda().unsqueeze(dim=0) # (1,H,W) + return NestedTensor(img_tensor_norm, amask_tensor) diff --git a/Stark/lib/test/utils/__init__.py b/Stark/lib/test/utils/__init__.py new file mode 100755 index 0000000..8d83e11 --- /dev/null +++ b/Stark/lib/test/utils/__init__.py @@ -0,0 +1 @@ +from .params import TrackerParams, FeatureParams, Choice \ No newline at end of file diff --git a/Stark/lib/test/utils/__pycache__/__init__.cpython-37.pyc b/Stark/lib/test/utils/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..c6681f0 Binary files /dev/null and b/Stark/lib/test/utils/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/test/utils/__pycache__/params.cpython-37.pyc b/Stark/lib/test/utils/__pycache__/params.cpython-37.pyc new file mode 100755 index 0000000..1f71d3f Binary files /dev/null and b/Stark/lib/test/utils/__pycache__/params.cpython-37.pyc differ diff --git a/Stark/lib/test/utils/_init_paths.py b/Stark/lib/test/utils/_init_paths.py new file mode 100755 index 0000000..0c59a91 --- /dev/null +++ b/Stark/lib/test/utils/_init_paths.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os.path as osp +import sys + + +def add_path(path): + if path not in sys.path: + sys.path.insert(0, path) + + +this_dir = osp.dirname(__file__) + +prj_path = osp.join(this_dir, '..', '..', '..') +add_path(prj_path) diff --git a/Stark/lib/test/utils/load_text.py b/Stark/lib/test/utils/load_text.py new file mode 100755 index 0000000..919536c --- /dev/null +++ b/Stark/lib/test/utils/load_text.py @@ -0,0 +1,41 @@ +import numpy as np +import pandas as pd + + +def load_text_numpy(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = np.loadtxt(path, delimiter=d, dtype=dtype) + return ground_truth_rect + except: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = np.loadtxt(path, delimiter=delimiter, dtype=dtype) + return ground_truth_rect + + +def load_text_pandas(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = pd.read_csv(path, delimiter=d, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + except Exception as e: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = pd.read_csv(path, delimiter=delimiter, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + + +def load_text(path, delimiter=' ', dtype=np.float32, backend='numpy'): + if backend == 'numpy': + return load_text_numpy(path, delimiter, dtype) + elif backend == 'pandas': + return load_text_pandas(path, delimiter, dtype) diff --git a/Stark/lib/test/utils/params.py b/Stark/lib/test/utils/params.py new file mode 100755 index 0000000..7ac43c1 --- /dev/null +++ b/Stark/lib/test/utils/params.py @@ -0,0 +1,43 @@ +from lib.utils import TensorList +import random + + +class TrackerParams: + """Class for tracker parameters.""" + def set_default_values(self, default_vals: dict): + for name, val in default_vals.items(): + if not hasattr(self, name): + setattr(self, name, val) + + def get(self, name: str, *default): + """Get a parameter value with the given name. If it does not exists, it return the default value given as a + second argument or returns an error if no default value is given.""" + if len(default) > 1: + raise ValueError('Can only give one default value.') + + if not default: + return getattr(self, name) + + return getattr(self, name, default[0]) + + def has(self, name: str): + """Check if there exist a parameter with the given name.""" + return hasattr(self, name) + + +class FeatureParams: + """Class for feature specific parameters""" + def __init__(self, *args, **kwargs): + if len(args) > 0: + raise ValueError + + for name, val in kwargs.items(): + if isinstance(val, list): + setattr(self, name, TensorList(val)) + else: + setattr(self, name, val) + + +def Choice(*args): + """Can be used to sample random parameter values.""" + return random.choice(args) diff --git a/Stark/lib/test/utils/transform_got10k.py b/Stark/lib/test/utils/transform_got10k.py new file mode 100755 index 0000000..2d35ffe --- /dev/null +++ b/Stark/lib/test/utils/transform_got10k.py @@ -0,0 +1,52 @@ +import numpy as np +import os +import shutil +import argparse +import _init_paths +from lib.test.evaluation.environment import env_settings + + +def transform_got10k(tracker_name, cfg_name): + env = env_settings() + result_dir = env.results_path + src_dir = os.path.join(result_dir, "%s/%s/got10k/" % (tracker_name, cfg_name)) + dest_dir = os.path.join(result_dir, "%s/%s/got10k_submit/" % (tracker_name, cfg_name)) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + items = os.listdir(src_dir) + for item in items: + if "all" in item: + continue + src_path = os.path.join(src_dir, item) + if "time" not in item: + seq_name = item.replace(".txt", '') + seq_dir = os.path.join(dest_dir, seq_name) + if not os.path.exists(seq_dir): + os.makedirs(seq_dir) + new_item = item.replace(".txt", '_001.txt') + dest_path = os.path.join(seq_dir, new_item) + bbox_arr = np.loadtxt(src_path, dtype=np.int, delimiter='\t') + np.savetxt(dest_path, bbox_arr, fmt='%d', delimiter=',') + else: + seq_name = item.replace("_time.txt", '') + seq_dir = os.path.join(dest_dir, seq_name) + if not os.path.exists(seq_dir): + os.makedirs(seq_dir) + dest_path = os.path.join(seq_dir, item) + os.system("cp %s %s" % (src_path, dest_path)) + # make zip archive + shutil.make_archive(src_dir, "zip", src_dir) + shutil.make_archive(dest_dir, "zip", dest_dir) + # Remove the original files + shutil.rmtree(src_dir) + shutil.rmtree(dest_dir) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='transform got10k results.') + parser.add_argument('--tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('--cfg_name', type=str, help='Name of config file.') + + args = parser.parse_args() + transform_got10k(args.tracker_name, args.cfg_name) + diff --git a/Stark/lib/test/utils/transform_trackingnet.py b/Stark/lib/test/utils/transform_trackingnet.py new file mode 100755 index 0000000..9146941 --- /dev/null +++ b/Stark/lib/test/utils/transform_trackingnet.py @@ -0,0 +1,39 @@ +import numpy as np +import os +import shutil +import argparse +import _init_paths +from lib.test.evaluation.environment import env_settings + + +def transform_trackingnet(tracker_name, cfg_name): + env = env_settings() + result_dir = env.results_path + src_dir = os.path.join(result_dir, "%s/%s/trackingnet/" % (tracker_name, cfg_name)) + dest_dir = os.path.join(result_dir, "%s/%s/trackingnet_submit/" % (tracker_name, cfg_name)) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + items = os.listdir(src_dir) + for item in items: + if "all" in item: + continue + if "time" not in item: + src_path = os.path.join(src_dir, item) + dest_path = os.path.join(dest_dir, item) + bbox_arr = np.loadtxt(src_path, dtype=np.int, delimiter='\t') + np.savetxt(dest_path, bbox_arr, fmt='%d', delimiter=',') + # make zip archive + shutil.make_archive(src_dir, "zip", src_dir) + shutil.make_archive(dest_dir, "zip", dest_dir) + # Remove the original files + shutil.rmtree(src_dir) + shutil.rmtree(dest_dir) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='transform trackingnet results.') + parser.add_argument('--tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('--cfg_name', type=str, help='Name of config file.') + + args = parser.parse_args() + transform_trackingnet(args.tracker_name, args.cfg_name) diff --git a/Stark/lib/test/vot20/__pycache__/stark_vot20lt.cpython-37.pyc b/Stark/lib/test/vot20/__pycache__/stark_vot20lt.cpython-37.pyc new file mode 100755 index 0000000..1693ede Binary files /dev/null and b/Stark/lib/test/vot20/__pycache__/stark_vot20lt.cpython-37.pyc differ diff --git a/Stark/lib/test/vot20/__pycache__/vot20_utils.cpython-37.pyc b/Stark/lib/test/vot20/__pycache__/vot20_utils.cpython-37.pyc new file mode 100755 index 0000000..70ea7f5 Binary files /dev/null and b/Stark/lib/test/vot20/__pycache__/vot20_utils.cpython-37.pyc differ diff --git a/Stark/lib/test/vot20/stark_s50.py b/Stark/lib/test/vot20/stark_s50.py new file mode 100755 index 0000000..fe550eb --- /dev/null +++ b/Stark/lib/test/vot20/stark_s50.py @@ -0,0 +1,4 @@ +from lib.test.vot20.stark_vot20 import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '0' +run_vot_exp('stark_s', 'baseline', vis=False) diff --git a/Stark/lib/test/vot20/stark_st101.py b/Stark/lib/test/vot20/stark_st101.py new file mode 100755 index 0000000..78b236e --- /dev/null +++ b/Stark/lib/test/vot20/stark_st101.py @@ -0,0 +1,4 @@ +from lib.test.vot20.stark_vot20 import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '5' +run_vot_exp('stark_st', 'baseline_R101', vis=False) diff --git a/Stark/lib/test/vot20/stark_st101_lt.py b/Stark/lib/test/vot20/stark_st101_lt.py new file mode 100755 index 0000000..39be064 --- /dev/null +++ b/Stark/lib/test/vot20/stark_st101_lt.py @@ -0,0 +1,4 @@ +from lib.test.vot20.stark_vot20lt import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '7' +run_vot_exp('stark_st', 'baseline_R101', vis=False) diff --git a/Stark/lib/test/vot20/stark_st50.py b/Stark/lib/test/vot20/stark_st50.py new file mode 100755 index 0000000..79af0f0 --- /dev/null +++ b/Stark/lib/test/vot20/stark_st50.py @@ -0,0 +1,4 @@ +from lib.test.vot20.stark_vot20 import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '4' +run_vot_exp('stark_st', 'baseline', vis=False) diff --git a/Stark/lib/test/vot20/stark_st50_lt.py b/Stark/lib/test/vot20/stark_st50_lt.py new file mode 100755 index 0000000..ba06c03 --- /dev/null +++ b/Stark/lib/test/vot20/stark_st50_lt.py @@ -0,0 +1,4 @@ +from lib.test.vot20.stark_vot20lt import run_vot_exp +import os +os.environ['CUDA_VISIBLE_DEVICES'] = '6' +run_vot_exp('stark_st', 'baseline', vis=False) diff --git a/Stark/lib/test/vot20/stark_vot20.py b/Stark/lib/test/vot20/stark_vot20.py new file mode 100755 index 0000000..0e80cd5 --- /dev/null +++ b/Stark/lib/test/vot20/stark_vot20.py @@ -0,0 +1,101 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + +import cv2 +import torch +import vot +import sys +import time +import os +from lib.test.evaluation import Tracker +from lib.test.vot20.vot20_utils import * + +'''stark_vot20 class''' + + +class stark_vot20(object): + def __init__(self, tracker_name='stark_st', para_name='baseline'): + # create tracker + tracker_info = Tracker(tracker_name, para_name, "vot20", None) + params = tracker_info.get_parameters() + params.visualization = False + params.debug = False + self.tracker = tracker_info.create_tracker(params) + + def initialize(self, img_rgb, mask): + # init on the 1st frame + region = rect_from_mask(mask) + self.H, self.W, _ = img_rgb.shape + init_info = {'init_bbox': region} + _ = self.tracker.initialize(img_rgb, init_info) + + def track(self, img_rgb): + # track + outputs = self.tracker.track(img_rgb) + pred_bbox = outputs['target_bbox'] + final_mask = mask_from_rect(pred_bbox, (self.W, self.H)) + return pred_bbox, final_mask + + +def run_vot_exp(tracker_name, para_name, vis=False): + + torch.set_num_threads(1) + save_root = os.path.join('/data/sda/v-yanbi/iccv21/LittleBoy/vot20_debug', para_name) + if vis and (not os.path.exists(save_root)): + os.mkdir(save_root) + tracker = stark_vot20(tracker_name=tracker_name, para_name=para_name) + handle = vot.VOT("mask") + selection = handle.region() + imagefile = handle.frame() + if not imagefile: + sys.exit(0) + if vis: + '''for vis''' + seq_name = imagefile.split('/')[-3] + save_v_dir = os.path.join(save_root,seq_name) + if not os.path.exists(save_v_dir): + os.mkdir(save_v_dir) + cur_time = int(time.time() % 10000) + save_dir = os.path.join(save_v_dir, str(cur_time)) + if not os.path.exists(save_dir): + os.makedirs(save_dir) + + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + # mask given by the toolkit ends with the target (zero-padding to the right and down is needed) + mask = make_full_size(selection, (image.shape[1], image.shape[0])) + tracker.initialize(image, mask) + + while True: + imagefile = handle.frame() + if not imagefile: + break + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + b1, m = tracker.track(image) + handle.report(m) + if vis: + '''Visualization''' + # original image + image_ori = image[:,:,::-1].copy() # RGB --> BGR + image_name = imagefile.split('/')[-1] + save_path = os.path.join(save_dir, image_name) + cv2.imwrite(save_path, image_ori) + # tracker box + image_b = image_ori.copy() + cv2.rectangle(image_b, (int(b1[0]), int(b1[1])), + (int(b1[0] + b1[2]), int(b1[1] + b1[3])), (0, 0, 255), 2) + image_b_name = image_name.replace('.jpg','_bbox.jpg') + save_path = os.path.join(save_dir, image_b_name) + cv2.imwrite(save_path, image_b) + # original image + mask + image_m = image_ori.copy().astype(np.float32) + image_m[:, :, 1] += 127.0 * m + image_m[:, :, 2] += 127.0 * m + contours, _ = cv2.findContours(m, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) + image_m = cv2.drawContours(image_m, contours, -1, (0, 255, 255), 2) + image_m = image_m.clip(0, 255).astype(np.uint8) + image_mask_name_m = image_name.replace('.jpg', '_mask.jpg') + save_path = os.path.join(save_dir, image_mask_name_m) + cv2.imwrite(save_path, image_m) diff --git a/Stark/lib/test/vot20/stark_vot20lt.py b/Stark/lib/test/vot20/stark_vot20lt.py new file mode 100755 index 0000000..f725753 --- /dev/null +++ b/Stark/lib/test/vot20/stark_vot20lt.py @@ -0,0 +1,104 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + + +import vot_path +import cv2 +import torch +import vot +import sys +import time +import os +#sys.path.append('/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/') +sys.path.append(vot_path.base_path + 'mlpLT/Stark/') +from lib.test.evaluation import Tracker +from lib.test.vot20.vot20_utils import * + +'''stark_vot20_lt class''' + + +class stark_vot20_lt(object): + def __init__(self, tracker_name='stark_st', para_name='baseline'): + # create tracker + tracker_info = Tracker(tracker_name, para_name, "vot20lt", None) + params = tracker_info.get_parameters() + params.visualization = False + params.debug = False + self.tracker = tracker_info.create_tracker(params) + + def initialize(self, img_rgb, box): + # init on the 1st frame + self.H, self.W, _ = img_rgb.shape + init_info = {'init_bbox': box} + _ = self.tracker.initialize(img_rgb, init_info) + + def track(self, img_rgb, detect=False): + # track + outputs = self.tracker.track(img_rgb, detect=detect) + pred_bbox = outputs['target_bbox'] + conf_score = outputs["conf_score"] + return pred_bbox, conf_score + + def track2(self, img_rgb, detect=False): + # track + outputs = self.tracker.track2(img_rgb, detect=detect) + pred_bbox = outputs['target_bbox'] + conf_score = outputs["conf_score"] + return pred_bbox, conf_score + + def update2(self, img_rgb, state, conf_score): + # update + outputs = self.tracker.update2(img_rgb, state, conf_score) + + +def run_vot_exp(tracker_name, para_name, vis=False): + + torch.set_num_threads(1) + save_root = os.path.join('/data/sda/v-yanbi/iccv21/LittleBoy/vot20_lt_debug', para_name) + if vis and (not os.path.exists(save_root)): + os.makedirs(save_root) + tracker = stark_vot20_lt(tracker_name=tracker_name, para_name=para_name) + handle = vot.VOT("rectangle") + selection = handle.region() + imagefile = handle.frame() + init_box = [selection.x, selection.y, selection.width, selection.height] + if not imagefile: + sys.exit(0) + if vis: + '''for vis''' + seq_name = imagefile.split('/')[-3] + save_v_dir = os.path.join(save_root,seq_name) + if not os.path.exists(save_v_dir): + os.mkdir(save_v_dir) + cur_time = int(time.time() % 10000) + save_dir = os.path.join(save_v_dir, str(cur_time)) + if not os.path.exists(save_dir): + os.makedirs(save_dir) + + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + tracker.initialize(image, init_box) + + while True: + imagefile = handle.frame() + if not imagefile: + break + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) # Right + b1, conf = tracker.track(image) + x1, y1, w, h = b1 + handle.report(vot.Rectangle(x1, y1, w, h), conf) + if vis: + '''Visualization''' + # original image + image_ori = image[:,:,::-1].copy() # RGB --> BGR + image_name = imagefile.split('/')[-1] + save_path = os.path.join(save_dir, image_name) + cv2.imwrite(save_path, image_ori) + # tracker box + image_b = image_ori.copy() + cv2.rectangle(image_b, (int(b1[0]), int(b1[1])), + (int(b1[0] + b1[2]), int(b1[1] + b1[3])), (0, 0, 255), 2) + image_b_name = image_name.replace('.jpg','_bbox.jpg') + save_path = os.path.join(save_dir, image_b_name) + cv2.imwrite(save_path, image_b) diff --git a/Stark/lib/test/vot20/vot.py b/Stark/lib/test/vot20/vot.py new file mode 100755 index 0000000..53e5a1f --- /dev/null +++ b/Stark/lib/test/vot20/vot.py @@ -0,0 +1,113 @@ +""" +\file vot.py +@brief Python utility functions for VOT integration +@author Luka Cehovin, Alessio Dore +@date 2016 +""" + +import sys +import copy +import collections +import numpy as np + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON, trax.Region.MASK]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels, customMetadata=dict(vot="python")) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + elif isinstance(request.region, trax.Mask): + self._region = request.region.array(True) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [x.path() for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + Arguments: + region: region for the frame + """ + assert(isinstance(region, (Rectangle, Polygon, np.ndarray))) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + elif isinstance(region, np.ndarray): + tregion = trax.Mask.create(region) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + image = [x.path() for k, x in request.image.items()] + if len(image) == 1: + return image[0] + return image + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() diff --git a/Stark/lib/test/vot20/vot20_utils.py b/Stark/lib/test/vot20/vot20_utils.py new file mode 100755 index 0000000..2adddf1 --- /dev/null +++ b/Stark/lib/test/vot20/vot20_utils.py @@ -0,0 +1,60 @@ +import numpy as np + + +def make_full_size(x, output_sz): + ''' + zero-pad input x (right and down) to match output_sz + x: numpy array e.g., binary mask + output_sz: size of the output [width, height] + ''' + if x.shape[0] == output_sz[1] and x.shape[1] == output_sz[0]: + return x + pad_x = output_sz[0] - x.shape[1] + if pad_x < 0: + x = x[:, :x.shape[1] + pad_x] + # padding has to be set to zero, otherwise pad function fails + pad_x = 0 + pad_y = output_sz[1] - x.shape[0] + if pad_y < 0: + x = x[:x.shape[0] + pad_y, :] + # padding has to be set to zero, otherwise pad function fails + pad_y = 0 + return np.pad(x, ((0, pad_y), (0, pad_x)), 'constant', constant_values=0) + + +def rect_from_mask(mask): + ''' + create an axis-aligned rectangle from a given binary mask + mask in created as a minimal rectangle containing all non-zero pixels + ''' + x_ = np.sum(mask, axis=0) + y_ = np.sum(mask, axis=1) + x0 = np.min(np.nonzero(x_)) + x1 = np.max(np.nonzero(x_)) + y0 = np.min(np.nonzero(y_)) + y1 = np.max(np.nonzero(y_)) + return [x0, y0, x1 - x0 + 1, y1 - y0 + 1] + + +def mask_from_rect(rect, output_sz): + ''' + create a binary mask from a given rectangle + rect: axis-aligned rectangle [x0, y0, width, height] + output_sz: size of the output [width, height] + ''' + mask = np.zeros((output_sz[1], output_sz[0]), dtype=np.uint8) + x0 = max(int(round(rect[0])), 0) + y0 = max(int(round(rect[1])), 0) + x1 = min(int(round(rect[0] + rect[2])), output_sz[0]) + y1 = min(int(round(rect[1] + rect[3])), output_sz[1]) + mask[y0:y1, x0:x1] = 1 + return mask + + +def bbox_clip(x1, y1, x2, y2, boundary, min_sz=10): + '''boundary (H,W)''' + x1_new = max(0, min(x1, boundary[1] - min_sz)) + y1_new = max(0, min(y1, boundary[0] - min_sz)) + x2_new = max(min_sz, min(x2, boundary[1])) + y2_new = max(min_sz, min(y2, boundary[0])) + return x1_new, y1_new, x2_new, y2_new \ No newline at end of file diff --git a/Stark/lib/train/__init__.py b/Stark/lib/train/__init__.py new file mode 100755 index 0000000..bef8ff0 --- /dev/null +++ b/Stark/lib/train/__init__.py @@ -0,0 +1 @@ +from .admin.multigpu import MultiGPU diff --git a/Stark/lib/train/__pycache__/__init__.cpython-37.pyc b/Stark/lib/train/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..180c2b2 Binary files /dev/null and b/Stark/lib/train/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/train/_init_paths.py b/Stark/lib/train/_init_paths.py new file mode 100755 index 0000000..3c61361 --- /dev/null +++ b/Stark/lib/train/_init_paths.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os.path as osp +import sys + + +def add_path(path): + if path not in sys.path: + sys.path.insert(0, path) + + +this_dir = osp.dirname(__file__) + +prj_path = osp.join(this_dir, '../..') +add_path(prj_path) diff --git a/Stark/lib/train/actors/__init__.py b/Stark/lib/train/actors/__init__.py new file mode 100755 index 0000000..80ba0c0 --- /dev/null +++ b/Stark/lib/train/actors/__init__.py @@ -0,0 +1,3 @@ +from .base_actor import BaseActor +from .stark_s import STARKSActor +from .stark_st import STARKSTActor diff --git a/Stark/lib/train/actors/base_actor.py b/Stark/lib/train/actors/base_actor.py new file mode 100755 index 0000000..013b077 --- /dev/null +++ b/Stark/lib/train/actors/base_actor.py @@ -0,0 +1,44 @@ +from lib.utils import TensorDict + + +class BaseActor: + """ Base class for actor. The actor class handles the passing of the data through the network + and calculation the loss""" + def __init__(self, net, objective): + """ + args: + net - The network to train + objective - The loss function + """ + self.net = net + self.objective = objective + + def __call__(self, data: TensorDict): + """ Called in each training iteration. Should pass in input data through the network, calculate the loss, and + return the training stats for the input data + args: + data - A TensorDict containing all the necessary data blocks. + + returns: + loss - loss for the input data + stats - a dict containing detailed losses + """ + raise NotImplementedError + + def to(self, device): + """ Move the network to device + args: + device - device to use. 'cpu' or 'cuda' + """ + self.net.to(device) + + def train(self, mode=True): + """ Set whether the network is in train mode. + args: + mode (True) - Bool specifying whether in training mode. + """ + self.net.train(mode) + + def eval(self): + """ Set network to eval mode""" + self.train(False) \ No newline at end of file diff --git a/Stark/lib/train/actors/stark_s.py b/Stark/lib/train/actors/stark_s.py new file mode 100755 index 0000000..dee0f98 --- /dev/null +++ b/Stark/lib/train/actors/stark_s.py @@ -0,0 +1,82 @@ +from . import BaseActor +from lib.utils.misc import NestedTensor +from lib.utils.box_ops import box_cxcywh_to_xyxy, box_xywh_to_xyxy +import torch +from lib.utils.merge import merge_template_search + + +class STARKSActor(BaseActor): + """ Actor for training the STARK-S and STARK-ST(Stage1)""" + def __init__(self, net, objective, loss_weight, settings): + super().__init__(net, objective) + self.loss_weight = loss_weight + self.settings = settings + self.bs = self.settings.batchsize # batch size + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'template', 'search', 'gt_bbox'. + template_images: (N_t, batch, 3, H, W) + search_images: (N_s, batch, 3, H, W) + returns: + loss - the training loss + status - dict containing detailed losses + """ + # forward pass + out_dict = self.forward_pass(data, run_box_head=True, run_cls_head=False) + + # process the groundtruth + gt_bboxes = data['search_anno'] # (Ns, batch, 4) (x1,y1,w,h) + + # compute losses + loss, status = self.compute_losses(out_dict, gt_bboxes[0]) + + return loss, status + + def forward_pass(self, data, run_box_head, run_cls_head): + feat_dict_list = [] + # process the templates + for i in range(self.settings.num_template): + template_img_i = data['template_images'][i].view(-1, *data['template_images'].shape[2:]) # (batch, 3, 128, 128) + template_att_i = data['template_att'][i].view(-1, *data['template_att'].shape[2:]) # (batch, 128, 128) + feat_dict_list.append(self.net(img=NestedTensor(template_img_i, template_att_i), mode='backbone')) + + # process the search regions (t-th frame) + search_img = data['search_images'].view(-1, *data['search_images'].shape[2:]) # (batch, 3, 320, 320) + search_att = data['search_att'].view(-1, *data['search_att'].shape[2:]) # (batch, 320, 320) + feat_dict_list.append(self.net(img=NestedTensor(search_img, search_att), mode='backbone')) + + # run the transformer and compute losses + seq_dict = merge_template_search(feat_dict_list) + out_dict, _, _ = self.net(seq_dict=seq_dict, mode="transformer", run_box_head=run_box_head, run_cls_head=run_cls_head) + # out_dict: (B, N, C), outputs_coord: (1, B, N, C), target_query: (1, B, N, C) + return out_dict + + def compute_losses(self, pred_dict, gt_bbox, return_status=True): + # Get boxes + pred_boxes = pred_dict['pred_boxes'] + if torch.isnan(pred_boxes).any(): + raise ValueError("Network outputs is NAN! Stop Training") + num_queries = pred_boxes.size(1) + pred_boxes_vec = box_cxcywh_to_xyxy(pred_boxes).view(-1, 4) # (B,N,4) --> (BN,4) (x1,y1,x2,y2) + gt_boxes_vec = box_xywh_to_xyxy(gt_bbox)[:, None, :].repeat((1, num_queries, 1)).view(-1, 4).clamp(min=0.0, max=1.0) # (B,4) --> (B,1,4) --> (B,N,4) + # compute giou and iou + try: + giou_loss, iou = self.objective['giou'](pred_boxes_vec, gt_boxes_vec) # (BN,4) (BN,4) + except: + giou_loss, iou = torch.tensor(0.0).cuda(), torch.tensor(0.0).cuda() + # compute l1 loss + l1_loss = self.objective['l1'](pred_boxes_vec, gt_boxes_vec) # (BN,4) (BN,4) + # weighted sum + loss = self.loss_weight['giou'] * giou_loss + self.loss_weight['l1'] * l1_loss + if return_status: + # status for log + mean_iou = iou.detach().mean() + status = {"Loss/total": loss.item(), + "Loss/giou": giou_loss.item(), + "Loss/l1": l1_loss.item(), + "IoU": mean_iou.item()} + return loss, status + else: + return loss diff --git a/Stark/lib/train/actors/stark_st.py b/Stark/lib/train/actors/stark_st.py new file mode 100755 index 0000000..096536e --- /dev/null +++ b/Stark/lib/train/actors/stark_st.py @@ -0,0 +1,40 @@ +from . import STARKSActor + + +class STARKSTActor(STARKSActor): + """ Actor for training the STARK-ST(Stage2)""" + def __init__(self, net, objective, loss_weight, settings): + super().__init__(net, objective, loss_weight, settings) + self.loss_weight = loss_weight + self.settings = settings + self.bs = self.settings.batchsize # batch size + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'template', 'search', 'gt_bbox'. + template_images: (N_t, batch, 3, H, W) + search_images: (N_s, batch, 3, H, W) + returns: + loss - the training loss + status - dict containing detailed losses + """ + # forward pass + out_dict = self.forward_pass(data, run_box_head=False, run_cls_head=True) + + # process the groundtruth label + labels = data['label'].view(-1) # (batch, ) 0 or 1 + + loss, status = self.compute_losses(out_dict, labels) + + return loss, status + + def compute_losses(self, pred_dict, labels, return_status=True): + loss = self.loss_weight["cls"] * self.objective['cls'](pred_dict["pred_logits"].view(-1), labels) + if return_status: + # status for log + status = { + "cls_loss": loss.item()} + return loss, status + else: + return loss diff --git a/Stark/lib/train/admin/__init__.py b/Stark/lib/train/admin/__init__.py new file mode 100755 index 0000000..971c258 --- /dev/null +++ b/Stark/lib/train/admin/__init__.py @@ -0,0 +1,3 @@ +from .environment import env_settings, create_default_local_file_ITP_train +from .stats import AverageMeter, StatValue +from .tensorboard import TensorboardWriter diff --git a/Stark/lib/train/admin/__pycache__/__init__.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..d6f70ee Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/environment.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/environment.cpython-37.pyc new file mode 100755 index 0000000..d269359 Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/environment.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/local.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/local.cpython-37.pyc new file mode 100755 index 0000000..60b56ff Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/local.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/multigpu.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/multigpu.cpython-37.pyc new file mode 100755 index 0000000..00117bd Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/multigpu.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/settings.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/settings.cpython-37.pyc new file mode 100755 index 0000000..f5ebfac Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/settings.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/stats.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/stats.cpython-37.pyc new file mode 100755 index 0000000..d407cd4 Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/stats.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/__pycache__/tensorboard.cpython-37.pyc b/Stark/lib/train/admin/__pycache__/tensorboard.cpython-37.pyc new file mode 100755 index 0000000..3009606 Binary files /dev/null and b/Stark/lib/train/admin/__pycache__/tensorboard.cpython-37.pyc differ diff --git a/Stark/lib/train/admin/environment.py b/Stark/lib/train/admin/environment.py new file mode 100755 index 0000000..8373725 --- /dev/null +++ b/Stark/lib/train/admin/environment.py @@ -0,0 +1,101 @@ +import importlib +import os +from collections import OrderedDict + + +def create_default_local_file(): + path = os.path.join(os.path.dirname(__file__), 'local.py') + + empty_str = '\'\'' + default_settings = OrderedDict({ + 'workspace_dir': empty_str, + 'tensorboard_dir': 'self.workspace_dir + \'/tensorboard/\'', + 'pretrained_networks': 'self.workspace_dir + \'/pretrained_networks/\'', + 'lasot_dir': empty_str, + 'got10k_dir': empty_str, + 'trackingnet_dir': empty_str, + 'coco_dir': empty_str, + 'lvis_dir': empty_str, + 'sbd_dir': empty_str, + 'imagenet_dir': empty_str, + 'imagenetdet_dir': empty_str, + 'ecssd_dir': empty_str, + 'hkuis_dir': empty_str, + 'msra10k_dir': empty_str, + 'davis_dir': empty_str, + 'youtubevos_dir': empty_str}) + + comment = {'workspace_dir': 'Base directory for saving network checkpoints.', + 'tensorboard_dir': 'Directory for tensorboard files.'} + + with open(path, 'w') as f: + f.write('class EnvironmentSettings:\n') + f.write(' def __init__(self):\n') + + for attr, attr_val in default_settings.items(): + comment_str = None + if attr in comment: + comment_str = comment[attr] + if comment_str is None: + f.write(' self.{} = {}\n'.format(attr, attr_val)) + else: + f.write(' self.{} = {} # {}\n'.format(attr, attr_val, comment_str)) + + +def create_default_local_file_ITP_train(workspace_dir, data_dir): + path = os.path.join(os.path.dirname(__file__), 'local.py') + + empty_str = '\'\'' + default_settings = OrderedDict({ + 'workspace_dir': workspace_dir, + 'tensorboard_dir': os.path.join(workspace_dir, 'tensorboard'), # Directory for tensorboard files. + 'pretrained_networks': os.path.join(workspace_dir, 'pretrained_networks'), + 'lasot_dir': os.path.join(data_dir, 'lasot'), + 'got10k_dir': os.path.join(data_dir, 'got10k'), + 'lasot_lmdb_dir': os.path.join(data_dir, 'lasot_lmdb'), + 'got10k_lmdb_dir': os.path.join(data_dir, 'got10k_lmdb'), + 'trackingnet_dir': os.path.join(data_dir, 'trackingnet'), + 'trackingnet_lmdb_dir': os.path.join(data_dir, 'trackingnet_lmdb'), + 'coco_dir': os.path.join(data_dir, 'coco'), + 'coco_lmdb_dir': os.path.join(data_dir, 'coco_lmdb'), + 'lvis_dir': empty_str, + 'sbd_dir': empty_str, + 'imagenet_dir': os.path.join(data_dir, 'vid'), + 'imagenet_lmdb_dir': os.path.join(data_dir, 'vid_lmdb'), + 'imagenetdet_dir': empty_str, + 'ecssd_dir': empty_str, + 'hkuis_dir': empty_str, + 'msra10k_dir': empty_str, + 'davis_dir': empty_str, + 'youtubevos_dir': empty_str}) + + comment = {'workspace_dir': 'Base directory for saving network checkpoints.', + 'tensorboard_dir': 'Directory for tensorboard files.'} + + with open(path, 'w') as f: + f.write('class EnvironmentSettings:\n') + f.write(' def __init__(self):\n') + + for attr, attr_val in default_settings.items(): + comment_str = None + if attr in comment: + comment_str = comment[attr] + if comment_str is None: + if attr_val == empty_str: + f.write(' self.{} = {}\n'.format(attr, attr_val)) + else: + f.write(' self.{} = \'{}\'\n'.format(attr, attr_val)) + else: + f.write(' self.{} = \'{}\' # {}\n'.format(attr, attr_val, comment_str)) + + +def env_settings(): + env_module_name = 'lib.train.admin.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.EnvironmentSettings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. Then try to run again.'.format(env_file)) diff --git a/Stark/lib/train/admin/local.py b/Stark/lib/train/admin/local.py new file mode 100755 index 0000000..b8ec2b8 --- /dev/null +++ b/Stark/lib/train/admin/local.py @@ -0,0 +1,23 @@ +class EnvironmentSettings: + def __init__(self): + self.workspace_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark' # Base directory for saving network checkpoints. + self.tensorboard_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/tensorboard' # Directory for tensorboard files. + self.pretrained_networks = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/pretrained_networks' + self.lasot_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/lasot' + self.got10k_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/got10k' + self.lasot_lmdb_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/lasot_lmdb' + self.got10k_lmdb_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/got10k_lmdb' + self.trackingnet_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/trackingnet' + self.trackingnet_lmdb_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/trackingnet_lmdb' + self.coco_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/coco' + self.coco_lmdb_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/coco_lmdb' + self.lvis_dir = '' + self.sbd_dir = '' + self.imagenet_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/vid' + self.imagenet_lmdb_dir = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/Stark/data/vid_lmdb' + self.imagenetdet_dir = '' + self.ecssd_dir = '' + self.hkuis_dir = '' + self.msra10k_dir = '' + self.davis_dir = '' + self.youtubevos_dir = '' diff --git a/Stark/lib/train/admin/multigpu.py b/Stark/lib/train/admin/multigpu.py new file mode 100755 index 0000000..097aacd --- /dev/null +++ b/Stark/lib/train/admin/multigpu.py @@ -0,0 +1,15 @@ +import torch.nn as nn +# Here we use DistributedDataParallel(DDP) rather than DataParallel(DP) for multiple GPUs training + + +def is_multi_gpu(net): + return isinstance(net, (MultiGPU, nn.parallel.distributed.DistributedDataParallel)) + + +class MultiGPU(nn.parallel.distributed.DistributedDataParallel): + def __getattr__(self, item): + try: + return super().__getattr__(item) + except: + pass + return getattr(self.module, item) diff --git a/Stark/lib/train/admin/settings.py b/Stark/lib/train/admin/settings.py new file mode 100755 index 0000000..f4c8fb8 --- /dev/null +++ b/Stark/lib/train/admin/settings.py @@ -0,0 +1,13 @@ +from lib.train.admin.environment import env_settings + + +class Settings: + """ Training settings, e.g. the paths to datasets and networks.""" + def __init__(self): + self.set_default() + + def set_default(self): + self.env = env_settings() + self.use_gpu = True + + diff --git a/Stark/lib/train/admin/stats.py b/Stark/lib/train/admin/stats.py new file mode 100755 index 0000000..34887fc --- /dev/null +++ b/Stark/lib/train/admin/stats.py @@ -0,0 +1,71 @@ + + +class StatValue: + def __init__(self): + self.clear() + + def reset(self): + self.val = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val): + self.val = val + self.history.append(self.val) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self): + self.clear() + self.has_new_data = False + + def reset(self): + self.avg = 0 + self.val = 0 + self.sum = 0 + self.count = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def new_epoch(self): + if self.count > 0: + self.history.append(self.avg) + self.reset() + self.has_new_data = True + else: + self.has_new_data = False + + +def topk_accuracy(output, target, topk=(1,)): + """Computes the precision@k for the specified values of k""" + single_input = not isinstance(topk, (tuple, list)) + if single_input: + topk = (topk,) + + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)[0] + res.append(correct_k * 100.0 / batch_size) + + if single_input: + return res[0] + + return res diff --git a/Stark/lib/train/admin/tensorboard.py b/Stark/lib/train/admin/tensorboard.py new file mode 100755 index 0000000..83b206e --- /dev/null +++ b/Stark/lib/train/admin/tensorboard.py @@ -0,0 +1,27 @@ +import os +from collections import OrderedDict +try: + from torch.utils.tensorboard import SummaryWriter +except: + print('WARNING: You are using tensorboardX instead sis you have a too old pytorch version.') + from tensorboardX import SummaryWriter + + +class TensorboardWriter: + def __init__(self, directory, loader_names): + self.directory = directory + self.writer = OrderedDict({name: SummaryWriter(os.path.join(self.directory, name)) for name in loader_names}) + + def write_info(self, script_name, description): + tb_info_writer = SummaryWriter(os.path.join(self.directory, 'info')) + tb_info_writer.add_text('Script_name', script_name) + tb_info_writer.add_text('Description', description) + tb_info_writer.close() + + def write_epoch(self, stats: OrderedDict, epoch: int, ind=-1): + for loader_name, loader_stats in stats.items(): + if loader_stats is None: + continue + for var_name, val in loader_stats.items(): + if hasattr(val, 'history') and getattr(val, 'has_new_data', True): + self.writer[loader_name].add_scalar(var_name, val.history[ind], epoch) \ No newline at end of file diff --git a/Stark/lib/train/base_functions.py b/Stark/lib/train/base_functions.py new file mode 100755 index 0000000..6d528e6 --- /dev/null +++ b/Stark/lib/train/base_functions.py @@ -0,0 +1,180 @@ +import torch +from torch.utils.data.distributed import DistributedSampler +# datasets related +from lib.train.dataset import Lasot, Got10k, MSCOCOSeq, ImagenetVID, TrackingNet +from lib.train.dataset import Lasot_lmdb, Got10k_lmdb, MSCOCOSeq_lmdb, ImagenetVID_lmdb, TrackingNet_lmdb +from lib.train.data import sampler, opencv_loader, processing, LTRLoader +import lib.train.data.transforms as tfm + + +def update_settings(settings, cfg): + settings.print_interval = cfg.TRAIN.PRINT_INTERVAL + settings.search_area_factor = {'template': cfg.DATA.TEMPLATE.FACTOR, + 'search': cfg.DATA.SEARCH.FACTOR} + settings.output_sz = {'template': cfg.DATA.TEMPLATE.SIZE, + 'search': cfg.DATA.SEARCH.SIZE} + settings.center_jitter_factor = {'template': cfg.DATA.TEMPLATE.CENTER_JITTER, + 'search': cfg.DATA.SEARCH.CENTER_JITTER} + settings.scale_jitter_factor = {'template': cfg.DATA.TEMPLATE.SCALE_JITTER, + 'search': cfg.DATA.SEARCH.SCALE_JITTER} + settings.grad_clip_norm = cfg.TRAIN.GRAD_CLIP_NORM + settings.print_stats = None + settings.batchsize = cfg.TRAIN.BATCH_SIZE + settings.scheduler_type = cfg.TRAIN.SCHEDULER.TYPE + + +def names2datasets(name_list: list, settings, image_loader): + assert isinstance(name_list, list) + datasets = [] + for name in name_list: + assert name in ["LASOT", "GOT10K_vottrain", "GOT10K_votval", "GOT10K_train_full", "COCO17", "VID", "TRACKINGNET"] + if name == "LASOT": + if settings.use_lmdb: + print("Building lasot dataset from lmdb") + datasets.append(Lasot_lmdb(settings.env.lasot_lmdb_dir, split='train', image_loader=image_loader)) + else: + datasets.append(Lasot(settings.env.lasot_dir, split='train', image_loader=image_loader)) + if name == "GOT10K_vottrain": + if settings.use_lmdb: + print("Building got10k from lmdb") + datasets.append(Got10k_lmdb(settings.env.got10k_lmdb_dir, split='vottrain', image_loader=image_loader)) + else: + datasets.append(Got10k(settings.env.got10k_dir, split='vottrain', image_loader=image_loader)) + if name == "GOT10K_train_full": + if settings.use_lmdb: + print("Building got10k_train_full from lmdb") + datasets.append(Got10k_lmdb(settings.env.got10k_lmdb_dir, split='train_full', image_loader=image_loader)) + else: + datasets.append(Got10k(settings.env.got10k_dir, split='train_full', image_loader=image_loader)) + if name == "GOT10K_votval": + if settings.use_lmdb: + print("Building got10k from lmdb") + datasets.append(Got10k_lmdb(settings.env.got10k_lmdb_dir, split='votval', image_loader=image_loader)) + else: + datasets.append(Got10k(settings.env.got10k_dir, split='votval', image_loader=image_loader)) + if name == "COCO17": + if settings.use_lmdb: + print("Building COCO2017 from lmdb") + datasets.append(MSCOCOSeq_lmdb(settings.env.coco_lmdb_dir, version="2017", image_loader=image_loader)) + else: + datasets.append(MSCOCOSeq(settings.env.coco_dir, version="2017", image_loader=image_loader)) + if name == "VID": + if settings.use_lmdb: + print("Building VID from lmdb") + datasets.append(ImagenetVID_lmdb(settings.env.imagenet_lmdb_dir, image_loader=image_loader)) + else: + datasets.append(ImagenetVID(settings.env.imagenet_dir, image_loader=image_loader)) + if name == "TRACKINGNET": + if settings.use_lmdb: + print("Building TrackingNet from lmdb") + datasets.append(TrackingNet_lmdb(settings.env.trackingnet_lmdb_dir, image_loader=image_loader)) + else: + # raise ValueError("NOW WE CAN ONLY USE TRACKINGNET FROM LMDB") + datasets.append(TrackingNet(settings.env.trackingnet_dir, image_loader=image_loader)) + return datasets + + +def build_dataloaders(cfg, settings): + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05), + tfm.RandomHorizontalFlip(probability=0.5)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.RandomHorizontalFlip_Norm(probability=0.5), + tfm.Normalize(mean=cfg.DATA.MEAN, std=cfg.DATA.STD)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=cfg.DATA.MEAN, std=cfg.DATA.STD)) + + # The tracking pairs processing module + output_sz = settings.output_sz + search_area_factor = settings.search_area_factor + + data_processing_train = processing.STARKProcessing(search_area_factor=search_area_factor, + output_sz=output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + transform=transform_train, + joint_transform=transform_joint, + settings=settings) + + data_processing_val = processing.STARKProcessing(search_area_factor=search_area_factor, + output_sz=output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + transform=transform_val, + joint_transform=transform_joint, + settings=settings) + + # Train sampler and loader + settings.num_template = getattr(cfg.DATA.TEMPLATE, "NUMBER", 1) + settings.num_search = getattr(cfg.DATA.SEARCH, "NUMBER", 1) + sampler_mode = getattr(cfg.DATA, "SAMPLER_MODE", "causal") + train_cls = getattr(cfg.TRAIN, "TRAIN_CLS", False) + print("sampler_mode", sampler_mode) + dataset_train = sampler.TrackingSampler(datasets=names2datasets(cfg.DATA.TRAIN.DATASETS_NAME, settings, opencv_loader), + p_datasets=cfg.DATA.TRAIN.DATASETS_RATIO, + samples_per_epoch=cfg.DATA.TRAIN.SAMPLE_PER_EPOCH, + max_gap=cfg.DATA.MAX_SAMPLE_INTERVAL, num_search_frames=settings.num_search, + num_template_frames=settings.num_template, processing=data_processing_train, + frame_sample_mode=sampler_mode, train_cls=train_cls) + + train_sampler = DistributedSampler(dataset_train) if settings.local_rank != -1 else None + shuffle = False if settings.local_rank != -1 else True + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=cfg.TRAIN.BATCH_SIZE, shuffle=shuffle, + num_workers=cfg.TRAIN.NUM_WORKER, drop_last=True, stack_dim=1, sampler=train_sampler) + + # Validation samplers and loaders + dataset_val = sampler.TrackingSampler(datasets=names2datasets(cfg.DATA.VAL.DATASETS_NAME, settings, opencv_loader), + p_datasets=cfg.DATA.VAL.DATASETS_RATIO, + samples_per_epoch=cfg.DATA.VAL.SAMPLE_PER_EPOCH, + max_gap=cfg.DATA.MAX_SAMPLE_INTERVAL, num_search_frames=settings.num_search, + num_template_frames=settings.num_template, processing=data_processing_val, + frame_sample_mode=sampler_mode, train_cls=train_cls) + val_sampler = DistributedSampler(dataset_val) if settings.local_rank != -1 else None + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=cfg.TRAIN.BATCH_SIZE, + num_workers=cfg.TRAIN.NUM_WORKER, drop_last=True, stack_dim=1, sampler=val_sampler, + epoch_interval=cfg.TRAIN.VAL_EPOCH_INTERVAL) + + return loader_train, loader_val + + +def get_optimizer_scheduler(net, cfg): + train_cls = getattr(cfg.TRAIN, "TRAIN_CLS", False) + if train_cls: + print("Only training classification head. Learnable parameters are shown below.") + param_dicts = [ + {"params": [p for n, p in net.named_parameters() if "cls_head" in n and p.requires_grad]} + ] + + for n, p in net.named_parameters(): + if "cls_head" not in n: + p.requires_grad = False + else: + print(n) + else: + param_dicts = [ + {"params": [p for n, p in net.named_parameters() if "backbone" not in n and p.requires_grad]}, + { + "params": [p for n, p in net.named_parameters() if "backbone" in n and p.requires_grad], + "lr": cfg.TRAIN.LR * cfg.TRAIN.BACKBONE_MULTIPLIER, + }, + ] + + if cfg.TRAIN.OPTIMIZER == "ADAMW": + optimizer = torch.optim.AdamW(param_dicts, lr=cfg.TRAIN.LR, + weight_decay=cfg.TRAIN.WEIGHT_DECAY) + else: + raise ValueError("Unsupported Optimizer") + if cfg.TRAIN.SCHEDULER.TYPE == 'step': + lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, cfg.TRAIN.LR_DROP_EPOCH) + elif cfg.TRAIN.SCHEDULER.TYPE == "Mstep": + lr_scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, + milestones=cfg.TRAIN.SCHEDULER.MILESTONES, + gamma=cfg.TRAIN.SCHEDULER.GAMMA) + else: + raise ValueError("Unsupported scheduler") + return optimizer, lr_scheduler diff --git a/Stark/lib/train/data/__init__.py b/Stark/lib/train/data/__init__.py new file mode 100755 index 0000000..a5de2f3 --- /dev/null +++ b/Stark/lib/train/data/__init__.py @@ -0,0 +1,2 @@ +from .loader import LTRLoader +from .image_loader import jpeg4py_loader, opencv_loader, jpeg4py_loader_w_failsafe, default_image_loader diff --git a/Stark/lib/train/data/__pycache__/__init__.cpython-37.pyc b/Stark/lib/train/data/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..fd02c10 Binary files /dev/null and b/Stark/lib/train/data/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/train/data/__pycache__/image_loader.cpython-37.pyc b/Stark/lib/train/data/__pycache__/image_loader.cpython-37.pyc new file mode 100755 index 0000000..faee7da Binary files /dev/null and b/Stark/lib/train/data/__pycache__/image_loader.cpython-37.pyc differ diff --git a/Stark/lib/train/data/__pycache__/loader.cpython-37.pyc b/Stark/lib/train/data/__pycache__/loader.cpython-37.pyc new file mode 100755 index 0000000..03e7b88 Binary files /dev/null and b/Stark/lib/train/data/__pycache__/loader.cpython-37.pyc differ diff --git a/Stark/lib/train/data/__pycache__/processing_utils.cpython-37.pyc b/Stark/lib/train/data/__pycache__/processing_utils.cpython-37.pyc new file mode 100755 index 0000000..7f12bd5 Binary files /dev/null and b/Stark/lib/train/data/__pycache__/processing_utils.cpython-37.pyc differ diff --git a/Stark/lib/train/data/bounding_box_utils.py b/Stark/lib/train/data/bounding_box_utils.py new file mode 100755 index 0000000..df0c31a --- /dev/null +++ b/Stark/lib/train/data/bounding_box_utils.py @@ -0,0 +1,94 @@ +import torch + + +def rect_to_rel(bb, sz_norm=None): + """Convert standard rectangular parametrization of the bounding box [x, y, w, h] + to relative parametrization [cx/sw, cy/sh, log(w), log(h)], where [cx, cy] is the center coordinate. + args: + bb - N x 4 tensor of boxes. + sz_norm - [N] x 2 tensor of value of [sw, sh] (optional). sw=w and sh=h if not given. + """ + + c = bb[...,:2] + 0.5 * bb[...,2:] + if sz_norm is None: + c_rel = c / bb[...,2:] + else: + c_rel = c / sz_norm + sz_rel = torch.log(bb[...,2:]) + return torch.cat((c_rel, sz_rel), dim=-1) + + +def rel_to_rect(bb, sz_norm=None): + """Inverts the effect of rect_to_rel. See above.""" + + sz = torch.exp(bb[...,2:]) + if sz_norm is None: + c = bb[...,:2] * sz + else: + c = bb[...,:2] * sz_norm + tl = c - 0.5 * sz + return torch.cat((tl, sz), dim=-1) + + +def masks_to_bboxes(mask, fmt='c'): + + """ Convert a mask tensor to one or more bounding boxes. + Note: This function is a bit new, make sure it does what it says. /Andreas + :param mask: Tensor of masks, shape = (..., H, W) + :param fmt: bbox layout. 'c' => "center + size" or (x_center, y_center, width, height) + 't' => "top left + size" or (x_left, y_top, width, height) + 'v' => "vertices" or (x_left, y_top, x_right, y_bottom) + :return: tensor containing a batch of bounding boxes, shape = (..., 4) + """ + batch_shape = mask.shape[:-2] + mask = mask.reshape((-1, *mask.shape[-2:])) + bboxes = [] + + for m in mask: + mx = m.sum(dim=-2).nonzero() + my = m.sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + bboxes.append(bb) + + bboxes = torch.tensor(bboxes, dtype=torch.float32, device=mask.device) + bboxes = bboxes.reshape(batch_shape + (4,)) + + if fmt == 'v': + return bboxes + + x1 = bboxes[..., :2] + s = bboxes[..., 2:] - x1 + 1 + + if fmt == 'c': + return torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + return torch.cat((x1, s), dim=-1) + + raise ValueError("Undefined bounding box layout '%s'" % fmt) + + +def masks_to_bboxes_multi(mask, ids, fmt='c'): + assert mask.dim() == 2 + bboxes = [] + + for id in ids: + mx = (mask == id).sum(dim=-2).nonzero() + my = (mask == id).float().sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + + bb = torch.tensor(bb, dtype=torch.float32, device=mask.device) + + x1 = bb[:2] + s = bb[2:] - x1 + 1 + + if fmt == 'v': + pass + elif fmt == 'c': + bb = torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + bb = torch.cat((x1, s), dim=-1) + else: + raise ValueError("Undefined bounding box layout '%s'" % fmt) + bboxes.append(bb) + + return bboxes diff --git a/Stark/lib/train/data/image_loader.py b/Stark/lib/train/data/image_loader.py new file mode 100755 index 0000000..636ec0a --- /dev/null +++ b/Stark/lib/train/data/image_loader.py @@ -0,0 +1,103 @@ +import jpeg4py +import cv2 as cv +from PIL import Image +import numpy as np + +davis_palette = np.repeat(np.expand_dims(np.arange(0,256), 1), 3, 1).astype(np.uint8) +davis_palette[:22, :] = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], + [0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128], + [64, 0, 0], [191, 0, 0], [64, 128, 0], [191, 128, 0], + [64, 0, 128], [191, 0, 128], [64, 128, 128], [191, 128, 128], + [0, 64, 0], [128, 64, 0], [0, 191, 0], [128, 191, 0], + [0, 64, 128], [128, 64, 128]] + + +def default_image_loader(path): + """The default image loader, reads the image from the given path. It first tries to use the jpeg4py_loader, + but reverts to the opencv_loader if the former is not available.""" + if default_image_loader.use_jpeg4py is None: + # Try using jpeg4py + im = jpeg4py_loader(path) + if im is None: + default_image_loader.use_jpeg4py = False + print('Using opencv_loader instead.') + else: + default_image_loader.use_jpeg4py = True + return im + if default_image_loader.use_jpeg4py: + return jpeg4py_loader(path) + return opencv_loader(path) + +default_image_loader.use_jpeg4py = None + + +def jpeg4py_loader(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_loader(path): + """ Read image using opencv's imread function and returns it in rgb format""" + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def jpeg4py_loader_w_failsafe(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except: + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_seg_loader(path): + """ Read segmentation annotation using opencv's imread function""" + try: + return cv.imread(path) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def imread_indexed(filename): + """ Load indexed image with given filename. Used to read segmentation annotations.""" + + im = Image.open(filename) + + annotation = np.atleast_3d(im)[...,0] + return annotation + + +def imwrite_indexed(filename, array, color_palette=None): + """ Save indexed image as png. Used to save segmentation annotation.""" + + if color_palette is None: + color_palette = davis_palette + + if np.atleast_3d(array).shape[2] != 1: + raise Exception("Saving indexed PNGs requires 2D array.") + + im = Image.fromarray(array) + im.putpalette(color_palette.ravel()) + im.save(filename, format='PNG') \ No newline at end of file diff --git a/Stark/lib/train/data/loader.py b/Stark/lib/train/data/loader.py new file mode 100755 index 0000000..62b97b6 --- /dev/null +++ b/Stark/lib/train/data/loader.py @@ -0,0 +1,190 @@ +import torch +import torch.utils.data.dataloader +import importlib +import collections +from torch._six import string_classes, int_classes +from lib.utils import TensorDict, TensorList + + +def _check_use_shared_memory(): + if hasattr(torch.utils.data.dataloader, '_use_shared_memory'): + return getattr(torch.utils.data.dataloader, '_use_shared_memory') + collate_lib = importlib.import_module('torch.utils.data._utils.collate') + if hasattr(collate_lib, '_use_shared_memory'): + return getattr(collate_lib, '_use_shared_memory') + return torch.utils.data.get_worker_info() is not None + + +def ltr_collate(batch): + """Puts each data field into a tensor with outer dimension batch size""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 0, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 0) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +def ltr_collate_stack1(batch): + """Puts each data field into a tensor. The tensors are stacked at dim=1 to form the batch""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 1, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 1) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate_stack1(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate_stack1(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +class LTRLoader(torch.utils.data.dataloader.DataLoader): + """ + Data loader. Combines a dataset and a sampler, and provides + single- or multi-process iterators over the dataset. + + Note: The only difference with default pytorch DataLoader is that an additional option stack_dim is available to + select along which dimension the data should be stacked to form a batch. + + Arguments: + dataset (Dataset): dataset from which to load the data. + batch_size (int, optional): how many samples per batch to load + (default: 1). + shuffle (bool, optional): set to ``True`` to have the data reshuffled + at every epoch (default: False). + sampler (Sampler, optional): defines the strategy to draw samples from + the dataset. If specified, ``shuffle`` must be False. + batch_sampler (Sampler, optional): like sampler, but returns a batch of + indices at a time. Mutually exclusive with batch_size, shuffle, + sampler, and drop_last. + num_workers (int, optional): how many subprocesses to use for data + loading. 0 means that the data will be loaded in the main process. + (default: 0) + collate_fn (callable, optional): merges a list of samples to form a mini-batch. + stack_dim (int): Dimension along which to stack to form the batch. (default: 0) + pin_memory (bool, optional): If ``True``, the data loader will copy tensors + into CUDA pinned memory before returning them. + drop_last (bool, optional): set to ``True`` to drop the last incomplete batch, + if the dataset size is not divisible by the batch size. If ``False`` and + the size of dataset is not divisible by the batch size, then the last batch + will be smaller. (default: False) + timeout (numeric, optional): if positive, the timeout value for collecting a batch + from workers. Should always be non-negative. (default: 0) + worker_init_fn (callable, optional): If not None, this will be called on each + worker subprocess with the worker id (an int in ``[0, num_workers - 1]``) as + input, after seeding and before data loading. (default: None) + + .. note:: By default, each worker will have its PyTorch seed set to + ``base_seed + worker_id``, where ``base_seed`` is a long generated + by main process using its RNG. However, seeds for other libraries + may be duplicated upon initializing workers (w.g., NumPy), causing + each worker to return identical random numbers. (See + :ref:`dataloader-workers-random-seed` section in FAQ.) You may + use ``torch.initial_seed()`` to access the PyTorch seed for each + worker in :attr:`worker_init_fn`, and use it to set other seeds + before data loading. + + .. warning:: If ``spawn`` start method is used, :attr:`worker_init_fn` cannot be an + unpicklable object, e.g., a lambda function. + """ + + __initialized = False + + def __init__(self, name, dataset, training=True, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, + num_workers=0, epoch_interval=1, collate_fn=None, stack_dim=0, pin_memory=False, drop_last=False, + timeout=0, worker_init_fn=None): + if collate_fn is None: + if stack_dim == 0: + collate_fn = ltr_collate + elif stack_dim == 1: + collate_fn = ltr_collate_stack1 + else: + raise ValueError('Stack dim no supported. Must be 0 or 1.') + + super(LTRLoader, self).__init__(dataset, batch_size, shuffle, sampler, batch_sampler, + num_workers, collate_fn, pin_memory, drop_last, + timeout, worker_init_fn) + + self.name = name + self.training = training + self.epoch_interval = epoch_interval + self.stack_dim = stack_dim diff --git a/Stark/lib/train/data/processing.py b/Stark/lib/train/data/processing.py new file mode 100755 index 0000000..3accc9e --- /dev/null +++ b/Stark/lib/train/data/processing.py @@ -0,0 +1,154 @@ +import torch +import torchvision.transforms as transforms +from lib.utils import TensorDict +import lib.train.data.processing_utils as prutils +import torch.nn.functional as F + + +def stack_tensors(x): + if isinstance(x, (list, tuple)) and isinstance(x[0], torch.Tensor): + return torch.stack(x) + return x + + +class BaseProcessing: + """ Base class for Processing. Processing class is used to process the data returned by a dataset, before passing it + through the network. For example, it can be used to crop a search region around the object, apply various data + augmentations, etc.""" + def __init__(self, transform=transforms.ToTensor(), template_transform=None, search_transform=None, joint_transform=None): + """ + args: + transform - The set of transformations to be applied on the images. Used only if template_transform or + search_transform is None. + template_transform - The set of transformations to be applied on the template images. If None, the 'transform' + argument is used instead. + search_transform - The set of transformations to be applied on the search images. If None, the 'transform' + argument is used instead. + joint_transform - The set of transformations to be applied 'jointly' on the template and search images. For + example, it can be used to convert both template and search images to grayscale. + """ + self.transform = {'template': transform if template_transform is None else template_transform, + 'search': transform if search_transform is None else search_transform, + 'joint': joint_transform} + + def __call__(self, data: TensorDict): + raise NotImplementedError + + +class STARKProcessing(BaseProcessing): + """ The processing class used for training LittleBoy. The images are processed in the following way. + First, the target bounding box is jittered by adding some noise. Next, a square region (called search region ) + centered at the jittered target center, and of area search_area_factor^2 times the area of the jittered box is + cropped from the image. The reason for jittering the target box is to avoid learning the bias that the target is + always at the center of the search region. The search region is then resized to a fixed size given by the + argument output_sz. + + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, + mode='pair', settings=None, *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.mode = mode + self.settings = settings + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'template' or 'search' indicating template or search data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'template_images', search_images', 'template_anno', 'search_anno' + returns: + TensorDict - output data block with following fields: + 'template_images', 'search_images', 'template_anno', 'search_anno', 'test_proposals', 'proposal_iou' + """ + # Apply joint transforms + if self.transform['joint'] is not None: + data['template_images'], data['template_anno'], data['template_masks'] = self.transform['joint']( + image=data['template_images'], bbox=data['template_anno'], mask=data['template_masks']) + data['search_images'], data['search_anno'], data['search_masks'] = self.transform['joint']( + image=data['search_images'], bbox=data['search_anno'], mask=data['search_masks'], new_roll=False) + + for s in ['template', 'search']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # 2021.1.9 Check whether data is valid. Avoid too small bounding boxes + w, h = torch.stack(jittered_anno, dim=0)[:, 2], torch.stack(jittered_anno, dim=0)[:, 3] + + crop_sz = torch.ceil(torch.sqrt(w * h) * self.search_area_factor[s]) + if (crop_sz < 1).any(): + data['valid'] = False + # print("Too small box is found. Replace it with new data.") + return data + + # Crop image region centered at jittered_anno box and get the attention mask + crops, boxes, att_mask, mask_crops = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, + data[s + '_anno'], self.search_area_factor[s], + self.output_sz[s], masks=data[s + '_masks']) + # Apply transforms + data[s + '_images'], data[s + '_anno'], data[s + '_att'], data[s + '_masks'] = self.transform[s]( + image=crops, bbox=boxes, att=att_mask, mask=mask_crops, joint=False) + + # 2021.1.9 Check whether elements in data[s + '_att'] is all 1 + # Note that type of data[s + '_att'] is tuple, type of ele is torch.tensor + for ele in data[s + '_att']: + if (ele == 1).all(): + data['valid'] = False + # print("Values of original attention mask are all one. Replace it with new data.") + return data + # 2021.1.10 more strict conditions: require the donwsampled masks not to be all 1 + for ele in data[s + '_att']: + feat_size = self.output_sz[s] // 16 # 16 is the backbone stride + # (1,1,128,128) (1,1,256,256) --> (1,1,8,8) (1,1,16,16) + mask_down = F.interpolate(ele[None, None].float(), size=feat_size).to(torch.bool)[0] + if (mask_down == 1).all(): + data['valid'] = False + # print("Values of down-sampled attention mask are all one. " + # "Replace it with new data.") + return data + + data['valid'] = True + # if we use copy-and-paste augmentation + if data["template_masks"] is None or data["search_masks"] is None: + data["template_masks"] = torch.zeros((1, self.output_sz["template"], self.output_sz["template"])) + data["search_masks"] = torch.zeros((1, self.output_sz["search"], self.output_sz["search"])) + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data diff --git a/Stark/lib/train/data/processing_utils.py b/Stark/lib/train/data/processing_utils.py new file mode 100755 index 0000000..394a10b --- /dev/null +++ b/Stark/lib/train/data/processing_utils.py @@ -0,0 +1,168 @@ +import torch +import math +import cv2 as cv +import torch.nn.functional as F +import numpy as np + +'''modified from the original test implementation +Replace cv.BORDER_REPLICATE with cv.BORDER_CONSTANT +Add a variable called att_mask for computing attention and positional encoding later''' + + +def sample_target(im, target_bb, search_area_factor, output_sz=None, mask=None): + """ Extracts a square crop centered at target_bb box, of area search_area_factor^2 times target_bb area + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + float - the factor by which the crop has been resized to make the crop size equal output_size + """ + if not isinstance(target_bb, list): + x, y, w, h = target_bb.tolist() + else: + x, y, w, h = target_bb + # Crop image + crop_sz = math.ceil(math.sqrt(w * h) * search_area_factor) + + if crop_sz < 1: + raise Exception('Too small bounding box.') + + x1 = round(x + 0.5 * w - crop_sz * 0.5) + x2 = x1 + crop_sz + + y1 = round(y + 0.5 * h - crop_sz * 0.5) + y2 = y1 + crop_sz + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_CONSTANT) + # deal with attention mask + H, W, _ = im_crop_padded.shape + att_mask = np.ones((H,W)) + end_x, end_y = -x2_pad, -y2_pad + if y2_pad == 0: + end_y = None + if x2_pad == 0: + end_x = None + att_mask[y1_pad:end_y, x1_pad:end_x] = 0 + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + if output_sz is not None: + resize_factor = output_sz / crop_sz + im_crop_padded = cv.resize(im_crop_padded, (output_sz, output_sz)) + att_mask = cv.resize(att_mask, (output_sz, output_sz)).astype(np.bool_) + if mask is None: + return im_crop_padded, resize_factor, att_mask + mask_crop_padded = \ + F.interpolate(mask_crop_padded[None, None], (output_sz, output_sz), mode='bilinear', align_corners=False)[0, 0] + return im_crop_padded, resize_factor, att_mask, mask_crop_padded + + else: + if mask is None: + return im_crop_padded, att_mask.astype(np.bool_), 1.0 + return im_crop_padded, 1.0, att_mask.astype(np.bool_), mask_crop_padded + + +def transform_image_to_crop(box_in: torch.Tensor, box_extract: torch.Tensor, resize_factor: float, + crop_sz: torch.Tensor, normalize=False) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box_in - the box for which the co-ordinates are to be transformed + box_extract - the box about which the image crop has been extracted. + resize_factor - the ratio between the original image scale and the scale of the image crop + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + box_extract_center = box_extract[0:2] + 0.5 * box_extract[2:4] + + box_in_center = box_in[0:2] + 0.5 * box_in[2:4] + + box_out_center = (crop_sz - 1) / 2 + (box_in_center - box_extract_center) * resize_factor + box_out_wh = box_in[2:4] * resize_factor + + box_out = torch.cat((box_out_center - 0.5 * box_out_wh, box_out_wh)) + if normalize: + return box_out / crop_sz[0] + else: + return box_out + + +def jittered_center_crop(frames, box_extract, box_gt, search_area_factor, output_sz, masks=None): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. The extracted crops are then resized to output_sz. Further, the co-ordinates of the box + box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if masks is None: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz) + for f, a in zip(frames, box_extract)] + frames_crop, resize_factors, att_mask = zip(*crops_resize_factors) + masks_crop = None + else: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz, m) + for f, a, m in zip(frames, box_extract, masks)] + frames_crop, resize_factors, att_mask, masks_crop = zip(*crops_resize_factors) + # frames_crop: tuple of ndarray (128,128,3), att_mask: tuple of ndarray (128,128) + crop_sz = torch.Tensor([output_sz, output_sz]) + + # find the bb location in the crop + '''Note that here we use normalized coord''' + box_crop = [transform_image_to_crop(a_gt, a_ex, rf, crop_sz, normalize=True) + for a_gt, a_ex, rf in zip(box_gt, box_extract, resize_factors)] # (x1,y1,w,h) list of tensors + + return frames_crop, box_crop, att_mask, masks_crop + + +def transform_box_to_crop(box: torch.Tensor, crop_box: torch.Tensor, crop_sz: torch.Tensor, normalize=False) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box - the box for which the co-ordinates are to be transformed + crop_box - bounding box defining the crop in the original image + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + + box_out = box.clone() + box_out[:2] -= crop_box[:2] + + scale_factor = crop_sz / crop_box[2:] + + box_out[:2] *= scale_factor + box_out[2:] *= scale_factor + if normalize: + return box_out / crop_sz[0] + else: + return box_out + diff --git a/Stark/lib/train/data/sampler.py b/Stark/lib/train/data/sampler.py new file mode 100755 index 0000000..b355c87 --- /dev/null +++ b/Stark/lib/train/data/sampler.py @@ -0,0 +1,314 @@ +import random +import torch.utils.data +from lib.utils import TensorDict +import numpy as np + + +def no_processing(data): + return data + + +class TrackingSampler(torch.utils.data.Dataset): + """ Class responsible for sampling frames from training sequences to form batches. + + The sampling is done in the following ways. First a dataset is selected at random. Next, a sequence is selected + from that dataset. A base frame is then sampled randomly from the sequence. Next, a set of 'train frames' and + 'test frames' are sampled from the sequence from the range [base_frame_id - max_gap, base_frame_id] and + (base_frame_id, base_frame_id + max_gap] respectively. Only the frames in which the target is visible are sampled. + If enough visible frames are not found, the 'max_gap' is increased gradually till enough frames are found. + + The sampled frames are then passed through the input 'processing' function for the necessary processing- + """ + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_search_frames, num_template_frames=1, processing=no_processing, frame_sample_mode='causal', + train_cls=False, pos_prob=0.5): + """ + args: + datasets - List of datasets to be used for training + p_datasets - List containing the probabilities by which each dataset will be sampled + samples_per_epoch - Number of training samples per epoch + max_gap - Maximum gap, in frame numbers, between the train frames and the test frames. + num_search_frames - Number of search frames to sample. + num_template_frames - Number of template frames to sample. + processing - An instance of Processing class which performs the necessary processing of the data. + frame_sample_mode - Either 'causal' or 'interval'. If 'causal', then the test frames are sampled in a causally, + otherwise randomly within the interval. + """ + self.datasets = datasets + self.train_cls = train_cls # whether we are training classification + self.pos_prob = pos_prob # probability of sampling positive class when making classification + + # If p not provided, sample uniformly from all videos + if p_datasets is None: + p_datasets = [len(d) for d in self.datasets] + + # Normalize + p_total = sum(p_datasets) + self.p_datasets = [x / p_total for x in p_datasets] + + self.samples_per_epoch = samples_per_epoch + self.max_gap = max_gap + self.num_search_frames = num_search_frames + self.num_template_frames = num_template_frames + self.processing = processing + self.frame_sample_mode = frame_sample_mode + + def __len__(self): + return self.samples_per_epoch + + def _sample_visible_ids(self, visible, num_ids=1, min_id=None, max_id=None, + allow_invisible=False, force_invisible=False): + """ Samples num_ids frames between min_id and max_id for which target is visible + + args: + visible - 1d Tensor indicating whether target is visible for each frame + num_ids - number of frames to be samples + min_id - Minimum allowed frame number + max_id - Maximum allowed frame number + + returns: + list - List of sampled frame numbers. None if not sufficient visible frames could be found. + """ + if num_ids == 0: + return [] + if min_id is None or min_id < 0: + min_id = 0 + if max_id is None or max_id > len(visible): + max_id = len(visible) + # get valid ids + if force_invisible: + valid_ids = [i for i in range(min_id, max_id) if not visible[i]] + else: + if allow_invisible: + valid_ids = [i for i in range(min_id, max_id)] + else: + valid_ids = [i for i in range(min_id, max_id) if visible[i]] + + # No visible ids + if len(valid_ids) == 0: + return None + + return random.choices(valid_ids, k=num_ids) + + def __getitem__(self, index): + if self.train_cls: + return self.getitem_cls() + else: + return self.getitem() + + def getitem(self): + """ + returns: + TensorDict - dict containing all the data blocks + """ + valid = False + while not valid: + # Select a dataset + dataset = random.choices(self.datasets, self.p_datasets)[0] + + is_video_dataset = dataset.is_video_sequence() + + # sample a sequence from the given dataset + seq_id, visible, seq_info_dict = self.sample_seq_from_dataset(dataset, is_video_dataset) + + if is_video_dataset: + template_frame_ids = None + search_frame_ids = None + gap_increase = 0 + + if self.frame_sample_mode == 'causal': + # Sample test and train frames in a causal manner, i.e. search_frame_ids > template_frame_ids + while search_frame_ids is None: + base_frame_id = self._sample_visible_ids(visible, num_ids=1, min_id=self.num_template_frames - 1, + max_id=len(visible) - self.num_search_frames) + prev_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_template_frames - 1, + min_id=base_frame_id[0] - self.max_gap - gap_increase, + max_id=base_frame_id[0]) + if prev_frame_ids is None: + gap_increase += 5 + continue + template_frame_ids = base_frame_id + prev_frame_ids + search_frame_ids = self._sample_visible_ids(visible, min_id=template_frame_ids[0] + 1, + max_id=template_frame_ids[0] + self.max_gap + gap_increase, + num_ids=self.num_search_frames) + # Increase gap until a frame is found + gap_increase += 5 + + elif self.frame_sample_mode == "trident" or self.frame_sample_mode == "trident_pro": + template_frame_ids, search_frame_ids = self.get_frame_ids_trident(visible) + else: + # In case of image dataset, just repeat the image to generate synthetic video + template_frame_ids = [1] * self.num_template_frames + search_frame_ids = [1] * self.num_search_frames + try: + template_frames, template_anno, meta_obj_train = dataset.get_frames(seq_id, template_frame_ids, seq_info_dict) + search_frames, search_anno, meta_obj_test = dataset.get_frames(seq_id, search_frame_ids, seq_info_dict) + + H, W, _ = template_frames[0].shape + template_masks = template_anno['mask'] if 'mask' in template_anno else [torch.zeros((H, W))] * self.num_template_frames + search_masks = search_anno['mask'] if 'mask' in search_anno else [torch.zeros((H, W))] * self.num_search_frames + + data = TensorDict({'template_images': template_frames, + 'template_anno': template_anno['bbox'], + 'template_masks': template_masks, + 'search_images': search_frames, + 'search_anno': search_anno['bbox'], + 'search_masks': search_masks, + 'dataset': dataset.get_name(), + 'test_class': meta_obj_test.get('object_class_name')}) + # make data augmentation + data = self.processing(data) + + # check whether data is valid + valid = data['valid'] + except: + valid = False + + return data + + def getitem_cls(self): + # get data for classification + """ + args: + index (int): Index (Ignored since we sample randomly) + aux (bool): whether the current data is for auxiliary use (e.g. copy-and-paste) + + returns: + TensorDict - dict containing all the data blocks + """ + valid = False + label = None + while not valid: + # Select a dataset + dataset = random.choices(self.datasets, self.p_datasets)[0] + + is_video_dataset = dataset.is_video_sequence() + + # sample a sequence from the given dataset + seq_id, visible, seq_info_dict = self.sample_seq_from_dataset(dataset, is_video_dataset) + # sample template and search frame ids + if is_video_dataset: + assert self.frame_sample_mode == "trident" or self.frame_sample_mode == "trident_pro" + template_frame_ids, search_frame_ids = self.get_frame_ids_trident(visible) + else: + # In case of image dataset, just repeat the image to generate synthetic video + template_frame_ids = [1] * self.num_template_frames + search_frame_ids = [1] * self.num_search_frames + try: + # "try" is used to handle trackingnet data failure + # get images and bounding boxes (for templates) + template_frames, template_anno, meta_obj_train = dataset.get_frames(seq_id, template_frame_ids, + seq_info_dict) + H, W, _ = template_frames[0].shape + template_masks = template_anno['mask'] if 'mask' in template_anno else [torch.zeros( + (H, W))] * self.num_template_frames + # get images and bounding boxes (for searches) + # positive samples + if random.random() < self.pos_prob: + label = torch.ones(1,) + search_frames, search_anno, meta_obj_test = dataset.get_frames(seq_id, search_frame_ids, seq_info_dict) + search_masks = search_anno['mask'] if 'mask' in search_anno else [torch.zeros( + (H, W))] * self.num_search_frames + # negative samples + else: + label = torch.zeros(1,) + if is_video_dataset: + search_frame_ids = self._sample_visible_ids(visible, num_ids=1, force_invisible=True) + if search_frame_ids is None: + search_frames, search_anno, meta_obj_test = self.get_one_search() + else: + search_frames, search_anno, meta_obj_test = dataset.get_frames(seq_id, search_frame_ids, + seq_info_dict) + search_anno["bbox"] = [self.get_center_box(H, W)] + else: + search_frames, search_anno, meta_obj_test = self.get_one_search() + H, W, _ = search_frames[0].shape + search_masks = search_anno['mask'] if 'mask' in search_anno else [torch.zeros( + (H, W))] * self.num_search_frames + + data = TensorDict({'template_images': template_frames, + 'template_anno': template_anno['bbox'], + 'template_masks': template_masks, + 'search_images': search_frames, + 'search_anno': search_anno['bbox'], + 'search_masks': search_masks, + 'dataset': dataset.get_name(), + 'test_class': meta_obj_test.get('object_class_name')}) + + # make data augmentation + data = self.processing(data) + # add classification label + data["label"] = label + # check whether data is valid + valid = data['valid'] + except: + valid = False + + return data + + def get_center_box(self, H, W, ratio=1/8): + cx, cy, w, h = W/2, H/2, W * ratio, H * ratio + return torch.tensor([int(cx-w/2), int(cy-h/2), int(w), int(h)]) + + def sample_seq_from_dataset(self, dataset, is_video_dataset): + + # Sample a sequence with enough visible frames + enough_visible_frames = False + while not enough_visible_frames: + # Sample a sequence + seq_id = random.randint(0, dataset.get_num_sequences() - 1) + + # Sample frames + seq_info_dict = dataset.get_sequence_info(seq_id) + visible = seq_info_dict['visible'] + + enough_visible_frames = visible.type(torch.int64).sum().item() > 2 * ( + self.num_search_frames + self.num_template_frames) and len(visible) >= 20 + + enough_visible_frames = enough_visible_frames or not is_video_dataset + return seq_id, visible, seq_info_dict + + def get_one_search(self): + # Select a dataset + dataset = random.choices(self.datasets, self.p_datasets)[0] + + is_video_dataset = dataset.is_video_sequence() + # sample a sequence + seq_id, visible, seq_info_dict = self.sample_seq_from_dataset(dataset, is_video_dataset) + # sample a frame + if is_video_dataset: + search_frame_ids = self._sample_visible_ids(visible, num_ids=1, allow_invisible=True) + else: + search_frame_ids = [1] + # get the image, bounding box and other info + search_frames, search_anno, meta_obj_test = dataset.get_frames(seq_id, search_frame_ids, seq_info_dict) + + return search_frames, search_anno, meta_obj_test + + def get_frame_ids_trident(self, visible): + # get template and search ids in a 'trident' manner + template_frame_ids_extra = [] + while None in template_frame_ids_extra or len(template_frame_ids_extra) == 0: + template_frame_ids_extra = [] + # first randomly sample two frames from a video + template_frame_id1 = self._sample_visible_ids(visible, num_ids=1) # the initial template id + search_frame_ids = self._sample_visible_ids(visible, num_ids=1) # the search region id + # get the dynamic template id + for max_gap in self.max_gap: + if template_frame_id1[0] >= search_frame_ids[0]: + min_id, max_id = search_frame_ids[0], search_frame_ids[0] + max_gap + else: + min_id, max_id = search_frame_ids[0] - max_gap, search_frame_ids[0] + if self.frame_sample_mode == "trident_pro": + f_id = self._sample_visible_ids(visible, num_ids=1, min_id=min_id, max_id=max_id, + allow_invisible=True) + else: + f_id = self._sample_visible_ids(visible, num_ids=1, min_id=min_id, max_id=max_id) + if f_id is None: + template_frame_ids_extra += [None] + else: + template_frame_ids_extra += f_id + + template_frame_ids = template_frame_id1 + template_frame_ids_extra + return template_frame_ids, search_frame_ids \ No newline at end of file diff --git a/Stark/lib/train/data/transforms.py b/Stark/lib/train/data/transforms.py new file mode 100755 index 0000000..7f66a1d --- /dev/null +++ b/Stark/lib/train/data/transforms.py @@ -0,0 +1,335 @@ +import random +import numpy as np +import math +import cv2 as cv +import torch +import torch.nn.functional as F +import torchvision.transforms.functional as tvisf + + +class Transform: + """A set of transformations, used for e.g. data augmentation. + Args of constructor: + transforms: An arbitrary number of transformations, derived from the TransformBase class. + They are applied in the order they are given. + + The Transform object can jointly transform images, bounding boxes and segmentation masks. + This is done by calling the object with the following key-word arguments (all are optional). + + The following arguments are inputs to be transformed. They are either supplied as a single instance, or a list of instances. + image - Image + coords - 2xN dimensional Tensor of 2D image coordinates [y, x] + bbox - Bounding box on the form [x, y, w, h] + mask - Segmentation mask with discrete classes + + The following parameters can be supplied with calling the transform object: + joint [Bool] - If True then transform all images/coords/bbox/mask in the list jointly using the same transformation. + Otherwise each tuple (images, coords, bbox, mask) will be transformed independently using + different random rolls. Default: True. + new_roll [Bool] - If False, then no new random roll is performed, and the saved result from the previous roll + is used instead. Default: True. + + Check the DiMPProcessing class for examples. + """ + + def __init__(self, *transforms): + if len(transforms) == 1 and isinstance(transforms[0], (list, tuple)): + transforms = transforms[0] + self.transforms = transforms + self._valid_inputs = ['image', 'coords', 'bbox', 'mask', 'att'] + self._valid_args = ['joint', 'new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + + def __call__(self, **inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + for v in inputs.keys(): + if v not in self._valid_all: + raise ValueError('Incorrect input \"{}\" to transform. Only supports inputs {} and arguments {}.'.format(v, self._valid_inputs, self._valid_args)) + + joint_mode = inputs.get('joint', True) + new_roll = inputs.get('new_roll', True) + + if not joint_mode: + out = zip(*[self(**inp) for inp in self._split_inputs(inputs)]) + return tuple(list(o) for o in out) + + out = {k: v for k, v in inputs.items() if k in self._valid_inputs} + + for t in self.transforms: + out = t(**out, joint=joint_mode, new_roll=new_roll) + if len(var_names) == 1: + return out[var_names[0]] + # Make sure order is correct + return tuple(out[v] for v in var_names) + + def _split_inputs(self, inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + split_inputs = [{k: v for k, v in zip(var_names, vals)} for vals in zip(*[inputs[vn] for vn in var_names])] + for arg_name, arg_val in filter(lambda it: it[0]!='joint' and it[0] in self._valid_args, inputs.items()): + if isinstance(arg_val, list): + for inp, av in zip(split_inputs, arg_val): + inp[arg_name] = av + else: + for inp in split_inputs: + inp[arg_name] = arg_val + return split_inputs + + def __repr__(self): + format_string = self.__class__.__name__ + '(' + for t in self.transforms: + format_string += '\n' + format_string += ' {0}'.format(t) + format_string += '\n)' + return format_string + + +class TransformBase: + """Base class for transformation objects. See the Transform class for details.""" + def __init__(self): + """2020.12.24 Add 'att' to valid inputs""" + self._valid_inputs = ['image', 'coords', 'bbox', 'mask', 'att'] + self._valid_args = ['new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + self._rand_params = None + + def __call__(self, **inputs): + # Split input + input_vars = {k: v for k, v in inputs.items() if k in self._valid_inputs} + input_args = {k: v for k, v in inputs.items() if k in self._valid_args} + + # Roll random parameters for the transform + if input_args.get('new_roll', True): + rand_params = self.roll() + if rand_params is None: + rand_params = () + elif not isinstance(rand_params, tuple): + rand_params = (rand_params,) + self._rand_params = rand_params + + outputs = dict() + for var_name, var in input_vars.items(): + if var is not None: + transform_func = getattr(self, 'transform_' + var_name) + if var_name in ['coords', 'bbox']: + params = (self._get_image_size(input_vars),) + self._rand_params + else: + params = self._rand_params + if isinstance(var, (list, tuple)): + outputs[var_name] = [transform_func(x, *params) for x in var] + else: + outputs[var_name] = transform_func(var, *params) + return outputs + + def _get_image_size(self, inputs): + im = None + for var_name in ['image', 'mask']: + if inputs.get(var_name) is not None: + im = inputs[var_name] + break + if im is None: + return None + if isinstance(im, (list, tuple)): + im = im[0] + if isinstance(im, np.ndarray): + return im.shape[:2] + if torch.is_tensor(im): + return (im.shape[-2], im.shape[-1]) + raise Exception('Unknown image type') + + def roll(self): + return None + + def transform_image(self, image, *rand_params): + """Must be deterministic""" + return image + + def transform_coords(self, coords, image_shape, *rand_params): + """Must be deterministic""" + return coords + + def transform_bbox(self, bbox, image_shape, *rand_params): + """Assumes [x, y, w, h]""" + # Check if not overloaded + if self.transform_coords.__code__ == TransformBase.transform_coords.__code__: + return bbox + + coord = bbox.clone().view(-1,2).t().flip(0) + + x1 = coord[1, 0] + x2 = coord[1, 0] + coord[1, 1] + + y1 = coord[0, 0] + y2 = coord[0, 0] + coord[0, 1] + + coord_all = torch.tensor([[y1, y1, y2, y2], [x1, x2, x2, x1]]) + + coord_transf = self.transform_coords(coord_all, image_shape, *rand_params).flip(0) + tl = torch.min(coord_transf, dim=1)[0] + sz = torch.max(coord_transf, dim=1)[0] - tl + bbox_out = torch.cat((tl, sz), dim=-1).reshape(bbox.shape) + return bbox_out + + def transform_mask(self, mask, *rand_params): + """Must be deterministic""" + return mask + + def transform_att(self, att, *rand_params): + """2020.12.24 Added to deal with attention masks""" + return att + + +class ToTensor(TransformBase): + """Convert to a Tensor""" + + def transform_image(self, image): + # handle numpy array + if image.ndim == 2: + image = image[:, :, None] + + image = torch.from_numpy(image.transpose((2, 0, 1))) + # backward compatibility + if isinstance(image, torch.ByteTensor): + return image.float().div(255) + else: + return image + + def transfrom_mask(self, mask): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + + def transform_att(self, att): + if isinstance(att, np.ndarray): + return torch.from_numpy(att).to(torch.bool) + elif isinstance(att, torch.Tensor): + return att.to(torch.bool) + else: + raise ValueError ("dtype must be np.ndarray or torch.Tensor") + + +class ToTensorAndJitter(TransformBase): + """Convert to a Tensor and jitter brightness""" + def __init__(self, brightness_jitter=0.0, normalize=True): + super().__init__() + self.brightness_jitter = brightness_jitter + self.normalize = normalize + + def roll(self): + return np.random.uniform(max(0, 1 - self.brightness_jitter), 1 + self.brightness_jitter) + + def transform_image(self, image, brightness_factor): + # handle numpy array + image = torch.from_numpy(image.transpose((2, 0, 1))) + + # backward compatibility + if self.normalize: + return image.float().mul(brightness_factor/255.0).clamp(0.0, 1.0) + else: + return image.float().mul(brightness_factor).clamp(0.0, 255.0) + + def transform_mask(self, mask, brightness_factor): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + else: + return mask + def transform_att(self, att, brightness_factor): + if isinstance(att, np.ndarray): + return torch.from_numpy(att).to(torch.bool) + elif isinstance(att, torch.Tensor): + return att.to(torch.bool) + else: + raise ValueError ("dtype must be np.ndarray or torch.Tensor") + + +class Normalize(TransformBase): + """Normalize image""" + def __init__(self, mean, std, inplace=False): + super().__init__() + self.mean = mean + self.std = std + self.inplace = inplace + + def transform_image(self, image): + return tvisf.normalize(image, self.mean, self.std, self.inplace) + + +class ToGrayscale(TransformBase): + """Converts image to grayscale with probability""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + self.color_weights = np.array([0.2989, 0.5870, 0.1140], dtype=np.float32) + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_grayscale): + if do_grayscale: + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) + return np.stack([img_gray, img_gray, img_gray], axis=2) + # return np.repeat(np.sum(img * self.color_weights, axis=2, keepdims=True).astype(np.uint8), 3, axis=2) + return image + + +class ToBGR(TransformBase): + """Converts image to BGR""" + def transform_image(self, image): + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_bgr = cv.cvtColor(image, cv.COLOR_RGB2BGR) + return img_bgr + + +class RandomHorizontalFlip(TransformBase): + """Horizontally flip image randomly with a probability p.""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_flip): + if do_flip: + if torch.is_tensor(image): + return image.flip((2,)) + return np.fliplr(image).copy() + return image + + def transform_coords(self, coords, image_shape, do_flip): + if do_flip: + coords_flip = coords.clone() + coords_flip[1,:] = (image_shape[1] - 1) - coords[1,:] + return coords_flip + return coords + + def transform_mask(self, mask, do_flip): + if do_flip: + if torch.is_tensor(mask): + return mask.flip((-1,)) + return np.fliplr(mask).copy() + return mask + + def transform_att(self, att, do_flip): + if do_flip: + if torch.is_tensor(att): + return att.flip((-1,)) + return np.fliplr(att).copy() + return att + + +class RandomHorizontalFlip_Norm(RandomHorizontalFlip): + """Horizontally flip image randomly with a probability p. + The difference is that the coord is normalized to [0,1]""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + + def transform_coords(self, coords, image_shape, do_flip): + """we should use 1 rather than image_shape""" + if do_flip: + coords_flip = coords.clone() + coords_flip[1,:] = 1 - coords[1,:] + return coords_flip + return coords diff --git a/Stark/lib/train/data_specs/got10k_train_full_split.txt b/Stark/lib/train/data_specs/got10k_train_full_split.txt new file mode 100755 index 0000000..2369cfe --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_train_full_split.txt @@ -0,0 +1,9335 @@ +3784 +8998 +3906 +1631 +8277 +8358 +2338 +7938 +2988 +8302 +2662 +2663 +2825 +7447 +4781 +2218 +6348 +5860 +4517 +2819 +8075 +5391 +116 +3606 +7976 +7941 +1024 +4519 +1970 +557 +8579 +6908 +993 +7204 +1991 +3674 +8781 +6840 +5 +3225 +3763 +8688 +6778 +5777 +4794 +2744 +8126 +3864 +1733 +2923 +6829 +701 +683 +2081 +1831 +2404 +1459 +2741 +5972 +3618 +7462 +2654 +103 +2174 +6224 +2989 +2506 +2766 +5912 +2699 +3295 +3986 +609 +4895 +6673 +801 +1098 +1602 +2490 +3129 +8476 +3186 +7355 +4784 +4270 +1812 +4226 +2267 +8873 +6544 +6112 +2381 +4752 +753 +3776 +6511 +6016 +731 +2559 +7369 +5866 +563 +7731 +1105 +5603 +50 +4238 +2208 +8725 +4994 +4719 +1444 +8807 +7298 +8139 +8760 +8173 +2332 +4131 +5207 +1065 +8562 +3992 +4024 +2188 +9095 +6765 +1707 +6105 +6922 +5362 +1486 +7898 +4135 +6574 +1551 +998 +6565 +8127 +8927 +2544 +4365 +510 +768 +3535 +3875 +6808 +2931 +487 +1088 +4451 +368 +2470 +8111 +3493 +7338 +8281 +6390 +1271 +4373 +3667 +3494 +3757 +2966 +3756 +7840 +6315 +7827 +3300 +6261 +4163 +2217 +6549 +94 +7236 +9136 +1857 +6691 +3470 +6271 +807 +516 +9311 +6098 +3144 +8420 +5425 +5694 +2643 +6696 +6072 +7285 +3781 +903 +8522 +6092 +5979 +2622 +2529 +855 +3420 +3261 +8953 +7866 +2492 +3157 +359 +1520 +2642 +7452 +759 +36 +8931 +1744 +4350 +1089 +9199 +4295 +1889 +1908 +4868 +4498 +1968 +9103 +3273 +8723 +7413 +4114 +5584 +4874 +1427 +5211 +7618 +1542 +1353 +8158 +4168 +3200 +6345 +8560 +5619 +5953 +3158 +8849 +5831 +1411 +7294 +8103 +6539 +7397 +1006 +5450 +3119 +4274 +5352 +4571 +2319 +4217 +4976 +902 +1814 +2651 +3299 +3398 +982 +2428 +5793 +1346 +7057 +3737 +7329 +4449 +2110 +7405 +1773 +958 +3901 +4127 +8234 +2994 +7066 +1289 +2995 +5871 +3556 +9085 +846 +2366 +585 +7032 +5516 +5230 +3481 +2732 +6658 +7423 +1855 +6384 +3554 +5823 +4948 +7058 +4667 +5377 +2503 +7694 +9191 +9144 +655 +3409 +62 +8019 +8970 +5523 +7403 +3379 +2323 +4833 +5750 +3178 +6548 +8891 +7501 +3280 +7404 +343 +2171 +8397 +1367 +8611 +6118 +6603 +3729 +7182 +9048 +7733 +5642 +7141 +3335 +4845 +5449 +3467 +6250 +163 +5168 +2040 +5339 +3609 +8352 +3426 +8567 +769 +187 +6151 +6437 +7028 +8507 +3970 +9146 +2068 +5028 +7492 +1661 +2815 +2469 +2563 +3814 +8430 +4305 +3479 +5678 +9115 +4132 +1211 +5459 +4814 +545 +4556 +238 +4296 +2724 +1260 +2581 +6087 +4632 +4313 +380 +1209 +5447 +3032 +7942 +8943 +806 +2432 +6130 +4314 +2131 +9045 +6531 +5706 +6747 +7724 +2017 +3292 +5469 +2743 +424 +4233 +7643 +8619 +5192 +4516 +9324 +3537 +9152 +8058 +7526 +8711 +1949 +5982 +1732 +6702 +7027 +6388 +7012 +328 +2130 +452 +306 +7669 +3134 +5761 +3703 +44 +4189 +695 +7672 +5224 +9215 +5644 +3143 +3704 +5443 +2348 +7177 +2328 +4725 +354 +1418 +7810 +7746 +9002 +5759 +7226 +4535 +9160 +4385 +5397 +7249 +2936 +3204 +6287 +385 +2371 +2738 +3636 +9033 +2246 +2680 +6940 +4310 +2054 +9250 +9080 +4568 +5586 +4469 +2038 +3410 +7900 +4332 +6108 +678 +3319 +9079 +1054 +4048 +4751 +1320 +6890 +7931 +1398 +4349 +5299 +5025 +7932 +5738 +7787 +4590 +4020 +1274 +2488 +8497 +3372 +8965 +3219 +799 +3664 +6500 +7093 +4362 +6205 +4244 +4652 +1964 +5945 +6434 +2031 +2684 +6632 +4588 +8271 +3232 +5782 +2904 +6789 +5636 +7200 +3632 +5435 +8203 +3480 +4786 +7579 +3351 +1921 +798 +3646 +3094 +4359 +1654 +5975 +376 +5965 +780 +7821 +9224 +6738 +3185 +2133 +6248 +5996 +2834 +531 +5688 +2448 +7925 +7974 +5924 +6401 +5778 +6594 +5442 +8336 +4522 +3770 +6340 +6328 +4946 +4161 +2954 +2588 +8465 +2885 +1606 +5787 +3407 +3121 +7310 +1413 +1932 +4787 +2579 +3325 +508 +5610 +6480 +4290 +479 +3792 +6628 +2545 +6717 +6972 +2665 +6730 +3547 +6845 +5929 +3540 +4356 +8993 +1052 +2235 +8356 +3403 +8818 +8260 +572 +4159 +1180 +5348 +941 +7948 +2676 +3539 +4866 +6422 +8365 +3217 +1310 +2059 +9177 +1419 +2283 +8892 +8162 +1212 +6277 +3725 +7806 +6149 +7874 +718 +6888 +7118 +277 +656 +8763 +8289 +4759 +5854 +8659 +7710 +3145 +5981 +1881 +5799 +6947 +1609 +6396 +2631 +2887 +318 +2550 +6132 +1736 +2907 +7816 +48 +4304 +8133 +6698 +2760 +7779 +7732 +7642 +1154 +7242 +711 +9262 +539 +8033 +7440 +1913 +5480 +5570 +8594 +8772 +4654 +8974 +6128 +6183 +1071 +8449 +2142 +2298 +524 +1695 +820 +4053 +8241 +1856 +8641 +3981 +217 +1063 +9286 +3152 +221 +5461 +1270 +2006 +7164 +1199 +6951 +5604 +5400 +5309 +3498 +6407 +6661 +7097 +8165 +5169 +3852 +7070 +5702 +4344 +6648 +6904 +3272 +7119 +5795 +2365 +2659 +353 +5444 +6968 +2755 +1924 +2098 +2972 +6006 +5865 +8740 +2418 +3401 +7856 +5841 +598 +836 +1147 +931 +8897 +0 +6049 +1837 +865 +1871 +6116 +6831 +5773 +3587 +303 +1883 +2163 +3070 +1308 +7953 +6300 +6909 +853 +7301 +3279 +123 +7186 +3194 +5553 +5133 +1931 +4622 +6075 +4891 +5722 +5693 +8 +2339 +6596 +71 +379 +4506 +4370 +1238 +2707 +3344 +4254 +8767 +1726 +325 +4148 +5438 +5357 +548 +1332 +6824 +2290 +2335 +3146 +2594 +2315 +3389 +3885 +2621 +4116 +5389 +7412 +7222 +4894 +8595 +2000 +4978 +4721 +6444 +3796 +9321 +2236 +6409 +1523 +1468 +9249 +8270 +2341 +2874 +174 +4757 +4502 +4703 +9034 +9108 +5451 +2619 +5022 +9158 +490 +6540 +1466 +2962 +8771 +3036 +2712 +4539 +1581 +5638 +9246 +4308 +4363 +4647 +4470 +1636 +2511 +1311 +6560 +7519 +8027 +9217 +6464 +6364 +3779 +4822 +3563 +3982 +5896 +5510 +6655 +1524 +2846 +3137 +621 +141 +1887 +6567 +8921 +4671 +6052 +8445 +8699 +7349 +3553 +2117 +7651 +5034 +5383 +649 +3818 +9022 +8414 +1012 +8159 +5081 +8571 +4765 +9135 +4361 +4073 +9142 +727 +2835 +8229 +3989 +4490 +4923 +5477 +1638 +3643 +712 +9044 +2230 +499 +7166 +96 +3172 +8431 +8401 +1470 +6356 +8817 +927 +4212 +2152 +1795 +3812 +4949 +1219 +1538 +3029 +6481 +9042 +7775 +7742 +423 +2085 +7715 +4541 +9061 +5916 +3950 +7420 +4878 +7406 +7046 +7808 +4911 +8804 +6927 +8820 +3264 +300 +8670 +2979 +252 +4407 +3383 +4688 +8504 +6723 +26 +3837 +2489 +4137 +8209 +229 +6490 +2364 +9016 +1763 +1728 +338 +8335 +9063 +5280 +2791 +641 +5454 +4581 +5420 +4548 +2840 +8508 +3463 +7231 +7619 +2560 +1755 +6201 +165 +1471 +6279 +5806 +6867 +5890 +2396 +3416 +1981 +6073 +5872 +3045 +4182 +7607 +3318 +4414 +2998 +6553 +7139 +5624 +2123 +3666 +723 +5110 +6932 +8200 +2222 +8399 +1041 +4138 +1594 +3569 +9253 +393 +7940 +8004 +1475 +6759 +5393 +1107 +2597 +878 +9309 +7576 +5250 +1759 +3142 +2015 +571 +3921 +1255 +7080 +893 +2160 +1355 +82 +1562 +9153 +8583 +4085 +4644 +7196 +9165 +3558 +4550 +6374 +7826 +8602 +4146 +9257 +6083 +874 +8383 +3731 +3374 +3653 +8222 +7344 +470 +1813 +4478 +6871 +7245 +6866 +3998 +7433 +276 +1915 +1988 +8168 +2518 +2686 +831 +6143 +5205 +8718 +1703 +7729 +2077 +7983 +8450 +1195 +9232 +507 +7989 +6974 +4054 +5828 +8655 +6679 +5245 +7783 +5886 +9098 +6491 +8782 +3525 +6542 +131 +8110 +9186 +9074 +4933 +9035 +2607 +4 +2057 +6273 +2711 +5829 +3382 +2696 +3043 +2048 +619 +2499 +5295 +1162 +7807 +3694 +2194 +3149 +1940 +7934 +840 +3592 +8237 +4731 +1324 +8486 +8726 +8573 +2928 +9078 +2272 +2564 +1370 +5911 +7434 +8026 +407 +7546 +2004 +5849 +3034 +7887 +3425 +1118 +926 +3430 +1544 +5902 +2282 +1124 +2334 +129 +1372 +4842 +6473 +4382 +1028 +415 +8269 +8073 +6910 +2796 +3038 +5735 +5080 +2852 +6306 +8842 +9188 +3637 +1066 +532 +928 +5485 +2838 +6753 +9008 +7984 +2816 +8819 +7103 +5977 +5044 +2064 +2599 +4973 +382 +3249 +6446 +6638 +852 +1724 +3368 +892 +3250 +8258 +7962 +4300 +1616 +167 +8855 +2090 +4424 +879 +5136 +5350 +2635 +7828 +8506 +63 +3004 +3847 +3676 +1184 +1705 +6745 +1263 +5020 +746 +1888 +7036 +1033 +3914 +5433 +3905 +4641 +8909 +228 +4801 +3766 +8085 +643 +6914 +9280 +3013 +5657 +3696 +1590 +2920 +8282 +2403 +416 +911 +3849 +4215 +1120 +5490 +296 +2306 +3140 +3742 +4819 +6153 +6414 +760 +3000 +7498 +7108 +6429 +3031 +5314 +751 +3357 +5808 +7505 +98 +7652 +4027 +6257 +3943 +1799 +8577 +5577 +4969 +9163 +2025 +6061 +4026 +5732 +588 +7017 +1415 +4961 +4940 +7152 +538 +706 +2802 +8983 +3375 +1246 +6593 +5837 +1789 +7939 +4997 +5939 +2411 +6133 +199 +7593 +1702 +5406 +6082 +2359 +2912 +6109 +100 +8149 +5470 +2807 +3384 +6413 +3362 +5621 +6019 +9241 +9268 +7703 +4111 +7967 +5458 +7181 +5492 +1112 +6729 +4577 +106 +8853 +3774 +979 +7082 +4610 +1853 +9003 +9292 +2867 +6262 +2245 +3460 +1557 +767 +4796 +8147 +2658 +5769 +6985 +7065 +421 +7990 +3289 +1540 +9316 +2251 +6896 +5947 +4965 +2652 +4480 +963 +9047 +7168 +7824 +3976 +6210 +7018 +7179 +5016 +7789 +6102 +6828 +7659 +9109 +9071 +8115 +7628 +7110 +16 +7513 +835 +939 +4078 +2351 +2322 +3881 +4945 +560 +6837 +6094 +6475 +7901 +3 +771 +8029 +3135 +8044 +7127 +3741 +5156 +7030 +4906 +113 +3747 +7042 +5232 +5225 +3002 +4747 +6879 +5379 +4886 +7192 +4184 +1896 +1834 +8689 +3665 +2957 +6913 +8009 +4851 +6420 +7987 +828 +3003 +8884 +8815 +3198 +8008 +194 +6251 +3303 +3934 +395 +1285 +4169 +1648 +1347 +3600 +4631 +509 +211 +6230 +7241 +8250 +2219 +2582 +8353 +7790 +7583 +4462 +3904 +9004 +6942 +1704 +5686 +8051 +2981 +5511 +6182 +7088 +1699 +1222 +3455 +6189 +1528 +5197 +6221 +7893 +3283 +2837 +7773 +8766 +2942 +8021 +614 +4102 +7362 +1786 +400 +133 +556 +3127 +5237 +3727 +1440 +3873 +6322 +8448 +6285 +8696 +8800 +4009 +3386 +454 +4847 +5685 +9093 +246 +1314 +5895 +6863 +4302 +4260 +8405 +8417 +7116 +255 +3223 +4737 +7852 +6337 +814 +710 +1094 +6103 +5809 +5882 +6336 +4974 +1499 +2806 +3744 +2664 +2436 +4482 +8665 +8918 +1076 +8676 +5725 +9248 +4755 +1447 +9328 +5500 +78 +2653 +792 +6854 +6093 +6172 +3378 +4492 +5529 +5476 +3846 +1391 +383 +4289 +3883 +2648 +3265 +2525 +5402 +4599 +6870 +6877 +4413 +2464 +8519 +2521 +1839 +5822 +5664 +7257 +5375 +6852 +6764 +5182 +8914 +3015 +8509 +3080 +4562 +8979 +6215 +6643 +8601 +6096 +4812 +5246 +7862 +527 +7849 +6737 +12 +2468 +7961 +275 +27 +5932 +3840 +7341 +4996 +8564 +2154 +3788 +6138 +7831 +4442 +757 +4464 +1170 +2568 +19 +323 +6584 +7675 +3441 +2067 +9027 +2486 +4379 +4744 +1737 +7563 +301 +3907 +4742 +6857 +1221 +9284 +8458 +8236 +2897 +4004 +1526 +5345 +4423 +6246 +8578 +1057 +3711 +4986 +4785 +3997 +7311 +4788 +107 +8387 +2041 +2608 +8628 +5830 +6031 +783 +6817 +3293 +541 +773 +8473 +2501 +7247 +5667 +804 +483 +1639 +696 +6060 +5429 +5762 +1527 +7342 +1329 +6225 +7895 +381 +8030 +8520 +8362 +4734 +3526 +9273 +2039 +4142 +5084 +875 +6905 +8968 +5275 +3052 +650 +7509 +232 +2595 +3631 +1810 +4355 +8315 +8908 +1777 +4834 +3164 +2336 +1543 +6212 +8346 +3024 +3719 +1242 +6265 +8101 +3133 +6150 +6358 +3316 +4089 +1647 +4629 +7117 +2596 +5366 +1225 +6371 +624 +2209 +1428 +1158 +7648 +466 +8765 +802 +153 +4639 +3657 +6482 +9320 +2693 +6591 +3294 +2617 +5052 +6305 +3227 +8784 +7170 +93 +5868 +6716 +1671 +178 +2703 +954 +3254 +2262 +5046 +5743 +8647 +6393 +7706 +6604 +3728 +6978 +7489 +7474 +8754 +2740 +2233 +6038 +1491 +8814 +2080 +2358 +5944 +5653 +1164 +9259 +4518 +7343 +5748 +3897 +923 +5967 +2677 +3503 +1202 +4966 +1836 +1863 +6634 +1962 +9096 +9064 +977 +4049 +1464 +658 +536 +3402 +8064 +1309 +259 +7999 +8122 +910 +224 +6152 +7142 +6070 +7523 +8411 +2408 +6766 +9214 +9312 +8325 +6192 +626 +6025 +6240 +8708 +4630 +6777 +1075 +8906 +408 +9269 +6236 +9067 +2514 +8568 +2324 +156 +3136 +3530 +7878 +7308 +4335 +2065 +3845 +4453 +3356 +1450 +371 +7219 +5171 +201 +8642 +2099 +477 +1603 +8339 +7430 +3061 +235 +8291 +1133 +8474 +7035 +8653 +989 +4569 +9092 +8347 +3102 +1743 +9086 +5140 +7438 +1530 +4342 +2460 +7646 +5047 +5071 +5430 +6944 +610 +2803 +1448 +4696 +6156 +4386 +4248 +4256 +994 +2112 +805 +8011 +8276 +8999 +4956 +1712 +2795 +7553 +6436 +2158 +9083 +3184 +5784 +4428 +612 +5288 +6222 +1365 +5074 +6848 +575 +5213 +2175 +4240 +351 +2086 +2656 +5150 +9255 +8189 +7735 +1261 +1344 +4097 +8674 +2984 +4235 +5998 +6488 +537 +1267 +7486 +7124 +6245 +7955 +7337 +5436 +1194 +8226 +209 +1710 +7906 +4357 +4139 +5679 +2584 +2854 +1004 +8246 +8586 +5087 +1878 +4926 +6637 +3197 +7757 +8249 +4055 +6502 +1248 +990 +3928 +2770 +2751 +1020 +6426 +4190 +6839 +2671 +884 +3871 +9212 +4179 +3394 +10 +5861 +5316 +6869 +2985 +8905 +8559 +4457 +2480 +2313 +4100 +4395 +6835 +7799 +7890 +2785 +5468 +7302 +5862 +1803 +6376 +3171 +8591 +717 +7053 +1655 +4489 +2522 +2921 +8555 +1984 +895 +8949 +1305 +738 +7606 +112 +3042 +1325 +437 +3167 +3340 +511 +3689 +5813 +8982 +69 +4421 +7150 +550 +8829 +8685 +3147 +8956 +3166 +7023 +8633 +3308 +2014 +3573 +3880 +4045 +2069 +6051 +4950 +702 +6664 +8418 +2454 +6181 +4853 +4166 +7022 +7418 +3605 +9181 +7172 +5031 +4589 +7858 +6586 +6351 +8334 +7504 +634 +3759 +1890 +890 +6959 +5085 +4919 +2161 +1191 +256 +3610 +7079 +3427 +4071 +7323 +2982 +7263 +7444 +4251 +5846 +4864 +3649 +4311 +7461 +8120 +4582 +6373 +2805 +4872 +4869 +5493 +5867 +2670 +7099 +30 +8933 +930 +7919 +501 +7261 +5289 +7449 +7772 +3613 +7848 +3196 +474 +205 +841 +2611 +6185 +3088 +409 +7239 +5938 +7871 +1343 +6705 +1027 +5596 +2199 +9113 +5471 +6134 +838 +2345 +8359 +4061 +1474 +3229 +270 +4245 +1979 +5995 +1517 +8652 +4006 +4880 +6137 +4693 +2528 +6996 +2926 +5798 +2477 +2549 +1128 +3341 +6014 +4479 +2861 +4208 +5175 +5174 +5118 +3736 +5463 +1588 +2327 +8380 +7982 +1514 +1058 +4586 +6608 +7985 +3044 +1822 +3628 +6851 +549 +1811 +2184 +2601 +4608 +8922 +2540 +6659 +3859 +307 +3650 +3767 +8167 +505 +4366 +4824 +5520 +461 +1933 +2401 +8106 +2055 +7844 +8544 +8838 +4797 +7419 +6686 +7670 +6039 +5672 +5141 +6543 +206 +5252 +4718 +888 +1601 +3218 +5114 +713 +4022 +4419 +6708 +397 +425 +6612 +5057 +1729 +6573 +4729 +4080 +1034 +2961 +534 +8194 +5598 +9218 +2424 +329 +4154 +1597 +922 +109 +8823 +3578 +9038 +8437 +3307 +128 +8032 +1412 +7333 +8762 +8851 +8865 +3056 +468 +3808 +3064 +8798 +7052 +7767 +9231 +1086 +2162 +6566 +2109 +3439 +6122 +3642 +7696 +8610 +5279 +1808 +8687 +8377 +817 +8714 +6066 +4008 +3640 +6015 +1021 +7601 +4855 +6017 +87 +7071 +2730 +7268 +3614 +6084 +6117 +6924 +9102 +2829 +375 +8724 +2095 +22 +1541 +2970 +633 +139 +451 +4521 +179 +1396 +3876 +5824 +8020 +426 +4982 +4172 +1157 +190 +4859 +1455 +3110 +3323 +9104 +858 +6719 +6428 +4495 +8551 +2141 +3984 +3066 +67 +4299 +5821 +8444 +6581 +6097 +7090 +7781 +8944 +3085 +8606 +2114 +5355 +8901 +1461 +3301 +422 +7000 +4820 +5790 +1379 +7536 +4199 +8736 +8991 +5241 +1698 +1294 +1753 +196 +2987 +8680 +4658 +4144 +8639 +6441 +8255 +8156 +3677 +6385 +6520 +7700 +3760 +6001 +1144 +5478 +7394 +8057 +5018 +4232 +5235 +6844 +3111 +8802 +867 +949 +7843 +573 +2278 +6801 +7629 +2714 +5105 +6946 +2697 +5315 +1571 +8677 +2537 +4374 +3833 +7820 +3750 +2033 +6526 +3884 +8706 +7195 +417 +3603 +3001 +6284 +5873 +5718 +8576 +8457 +3589 +5839 +459 +3626 +6342 +8729 +6933 +607 +6053 +8228 +3773 +1805 +6365 +5142 +6069 +1389 +9026 +570 +4614 +5712 +5533 +9222 +2821 +1897 +819 +766 +4060 +4902 +5905 +6842 +5446 +1277 +4303 +2836 +934 +1014 +7822 +7494 +3466 +665 +1047 +5881 +3328 +4664 +315 +1315 +1462 +8616 +7725 +2756 +5749 +1730 +8184 +4567 +5065 +7499 +8867 +1304 +3669 +9192 +410 +8177 +6710 +1210 +2329 +8443 +3911 +1899 +7686 +3315 +7190 +6180 +3116 +5341 +4394 +8337 +9182 +6969 +5715 +2172 +1742 +2782 +3715 +9195 +7960 +2517 +4890 +8294 +2337 +8014 +3353 +7475 +2193 +4843 +8831 +4200 +4653 +6196 +6957 +3063 +2996 +8959 +8973 +6529 +3457 +5274 +8002 +6823 +6154 +5561 +1780 +9318 +7657 +1758 +6503 +7678 +3274 +1625 +4327 +3236 +8575 +3155 +4707 +4331 +1494 +8756 +3174 +1074 +8116 +8295 +8311 +3048 +3752 +6050 +6483 +8003 +9175 +4674 +1642 +2556 +6166 +7165 +8441 +5413 +3990 +1640 +1778 +7500 +8304 +1395 +4315 +5949 +3364 +242 +5763 +1036 +249 +2430 +7426 +8131 +411 +6267 +2045 +6606 +899 +8065 +9052 +7507 +5779 +5616 +2107 +5408 +2980 +6310 +5776 +4328 +821 +3251 +2354 +7076 +1700 +5313 +6736 +79 +8212 +3959 +5677 +7545 +160 +6790 +6859 +3659 +6770 +1106 +8846 +956 +7472 +2050 +8099 +4795 +8053 +9293 +7037 +1646 +9307 +1069 +5322 +5332 +2708 +8977 +917 +2419 +184 +2105 +1578 +3923 +5780 +1903 +2512 +429 +5582 +493 +4972 +445 +8286 +555 +320 +8300 +322 +617 +3413 +4459 +525 +5631 +6314 +5157 +5300 +8545 +182 +1031 +4429 +2495 +7586 +1534 +3099 +3916 +3738 +1919 +535 +2119 +1299 +177 +1838 +2159 +4099 +8285 +5172 +8540 +6020 +7683 +3073 +3115 +1673 +3087 +3488 +2416 +1894 +5942 +3597 +5834 +2007 +43 +1779 +4174 +2023 +2546 +2429 +9006 +436 +4214 +4536 +3693 +5426 +6767 +5903 +4368 +2170 +5051 +7490 +7882 +2859 +5035 +7835 +5372 +7122 +925 +3253 +6338 +8393 +4093 +5848 +7588 +2683 +8049 +5403 +5894 +8745 +8550 +2941 +3484 +9029 +4461 +8022 +725 +2355 +1619 +3030 +1975 +5623 +2415 +1957 +6141 +9278 +3226 +3062 +5670 +7326 +8759 +8496 +6619 +8187 +8262 +6199 +951 +7183 +668 +2388 +4698 +5681 +8240 +2851 +871 +4988 +9084 +9089 +3162 +1167 +8244 +5227 +6461 +2831 +776 +5010 +5770 +5282 +3574 +5102 +1278 +2281 +5455 +305 +4628 +4663 +9119 +7487 +8746 +4889 +6569 +1175 +102 +2386 +8940 +2479 +5566 +53 +8833 +1918 +8001 +321 +6786 +6861 +4358 +2771 +7467 +975 +4777 +605 +3543 +2600 +7584 +9299 +4530 +6477 +7364 +7328 +183 +4761 +7543 +304 +1196 +4623 +7839 +2139 +5519 +1953 +533 +5989 +7590 +7428 +6346 +6162 +1091 +1946 +6260 +4405 +5676 +8924 +7171 +8409 +1866 +6379 +3411 +2387 +3051 +7398 +154 +1185 +6442 +6004 +1611 +2165 +9018 +8323 +616 +3995 +8952 +1533 +7853 +4194 +213 +789 +4991 +3675 +7456 +5752 +175 +7556 +4195 +907 +2248 +9057 +8467 +4594 +1017 +7968 +880 +7446 +3304 +1666 +4942 +3867 +4802 +9156 +6357 +4621 +887 +6213 +5261 +1336 +521 +8928 +1818 +7864 +4792 +6742 +157 +1593 +823 +7235 +5303 +5633 +1100 +1692 +8047 +5993 +1460 +6714 +1630 +6440 +6307 +3608 +292 +212 +401 +5974 +7107 +8301 +8342 +2720 +4583 +2757 +7315 +833 +4466 +4236 +1282 +5273 +2149 +287 +8484 +2380 +8119 +7167 +737 +5076 +6598 +3596 +5382 +2650 +8980 +3421 +1356 +1954 +7823 +1172 +2226 +1941 +6136 +7274 +2256 +4928 +324 +1407 +4410 +4579 +1061 +7113 +486 +862 +3435 +6956 +2873 +1465 +6113 +8225 +8512 +6806 +272 +6008 +1241 +88 +5662 +3555 +689 +8733 +2812 +7453 +6282 +420 +2471 +4477 +7495 +1445 +594 +6939 +1564 +8704 +8590 +7992 +7374 +5796 +9298 +4213 +5713 +5864 +326 +5513 +402 +464 +608 +1951 +8640 +8180 +3347 +3459 +4162 +2690 +7478 +5856 +5240 +2389 +3022 +602 +5547 +1798 +1345 +9276 +599 +3673 +3277 +1635 +8625 +1567 +5928 +636 +5671 +2896 +3477 +412 +7575 +4201 +685 +4760 +1229 +4275 +8960 +3123 +4471 +5941 +3355 +3999 +7157 +6354 +7741 +6850 +8783 +1943 +6769 +7330 +8721 +8477 +1381 +848 +778 +6408 +2644 +5817 +1441 +1723 +2144 +2776 +2368 +120 +367 +8839 +8749 +5353 +4158 +3148 +9114 +1233 +9228 +8857 +2895 +1286 +200 +6755 +5125 +5857 +1657 +7658 +5097 +5000 +942 +7020 +586 +784 +7078 +6194 +8658 +8957 +9325 +1851 +8911 +4862 +7004 +1186 +8824 +1651 +2999 +561 +7639 +4316 +5086 +3187 +7912 +2624 +9183 +8487 +5089 +8475 +7554 +4031 +6297 +6059 +5329 +115 +2058 +7650 +7634 +7121 +2485 +7805 +2241 +7713 +4352 +2409 +1026 +2745 +4549 +6474 +5124 +5201 +6556 +6617 +9091 +3945 +8402 +5648 +5257 +2192 +4901 +7750 +6131 +6027 +6352 +4625 +1254 +5498 +3720 +8261 +3939 +5576 +3685 +6713 +8472 +991 +8354 +8068 +5655 +5997 +1029 +7506 +6740 +2575 +2990 +4898 +583 +7402 +3290 +5388 +6715 +8235 +5361 +4970 +1363 +3338 +5731 +9014 +5358 +2216 +2856 +635 +1193 +3705 +6334 +7666 +5270 +1384 +6368 +8604 +3564 +1937 +2481 +1341 +721 +2100 +3958 +6551 +3813 +2592 +7980 +5385 +319 +2357 +8761 +8910 +8693 +1204 +489 +4827 +8024 +7832 +6427 +3895 +89 +9068 +8067 +1708 +1111 +8963 +1902 +9251 +5719 +9143 +5537 +9169 +77 +5365 +1840 +485 +4456 +2841 +1169 +3271 +7144 +6886 +9140 +7173 +6003 +1659 +1807 +8371 +2439 +274 +4660 +3448 +6623 +347 +2103 +3400 +2106 +9073 +8169 +3687 +3305 +4416 +8454 +6635 +332 +2433 +2909 +3839 +4063 +1944 +6509 +1296 +7770 +1880 +6610 +4075 +9331 +4484 +302 +418 +4219 +1333 +2350 +6498 +8424 +4694 +4883 +5269 +6580 +5007 +6722 +1669 +8470 +2571 +513 +3810 +7049 +6332 +7363 +3532 +8456 +2097 +297 +8841 +7180 +714 +1587 +5234 +4268 +2320 +7372 +660 +8503 +1668 +8847 +1101 +7275 +3336 +6460 +722 +7782 +3947 +502 +4258 +2132 +1835 +181 +3841 +427 +3446 +2551 +8324 +6963 +4284 +7297 +7577 +3399 +9148 +8213 +5656 +8440 +851 +657 +2446 +4292 +6992 +976 +1108 +2681 +3237 +8582 +377 +5969 +5287 +9209 +8523 +7178 +7833 +6175 +2126 +3023 +5090 +7491 +6640 +6077 +2221 +2780 +1694 +4094 +144 +6161 +3203 +7123 +749 +3625 +3848 +980 +2270 +7819 +3672 +7689 +7203 +2718 +1714 +2884 +3474 +3802 +3851 +4224 +7237 +5415 +7998 +7207 +4106 +9036 +1046 +8731 +5070 +6818 +4592 +6056 +693 +1328 +3309 +5791 +2629 +2736 +202 +388 +7886 +4417 +8786 +8822 +4035 +7718 +8492 +5505 +1192 +4388 +8941 +5019 +7538 +6732 +7296 +6389 +5923 +1405 +3278 +3917 +1688 +8374 +443 +4037 +9099 +5190 +6402 +4177 +9310 +7747 +4348 +7197 +4844 +4998 +5609 +4345 +29 +3332 +8648 +4107 +346 +2577 +3941 +1215 +3782 +8252 +4706 +2675 +3790 +7459 +6164 +7316 +1149 +6687 +582 +3139 +5040 +7645 +3882 +7322 +4034 +1861 +4701 +8757 +3208 +8801 +6349 +8907 +1823 +4528 +4789 +143 +4746 +9234 +3866 +9245 +1911 +1366 +4393 +2061 +859 +1959 +6967 +3138 +7382 +9031 +6237 +845 +80 +6911 +7163 +5229 +4736 +8738 +33 +8543 +357 +3193 +7262 +4448 +6796 +6793 +3321 +7569 +6411 +7692 +7340 +1417 +5847 +3836 +2678 +1188 +8727 +223 +8615 +7417 +5771 +3170 +8061 +2935 +8263 +8257 +6883 +1276 +1239 +812 +6258 +3922 +7525 +8117 +3039 +603 +8554 +7573 +2787 +3445 +5115 +3478 +962 +3961 +6570 +7722 +216 +2797 +5154 +2530 +4904 +2405 +7542 +4021 +3252 +5370 +9302 +236 +4532 +1361 +3373 +1716 +2183 +1583 +3783 +868 +1687 +8925 +1433 +6198 +8208 +6367 +7603 +882 +3469 +1645 +7654 +1176 +4231 +150 +7997 +5456 +7031 +4375 +8840 +5634 +6945 +705 +3442 +4774 +3822 +7148 +1922 +8459 +6249 +8713 +6197 +8599 +6071 +6756 +1634 +950 +5640 +7749 +5920 +6622 +4783 +7837 +7479 +7229 +3919 +1797 +5272 +8945 +4908 +5439 +6903 +5833 +6930 +8197 +9261 +1711 +5483 +6046 +4285 +8852 +7409 +8971 +8278 +7534 +7792 +2444 +7496 +8063 +1665 +248 +3894 +4585 +1982 +66 +6651 +4850 +1240 +7511 +7524 +9258 +2075 +3979 +4714 +7592 +965 +2919 +8239 +1842 +8013 +4750 +2344 +6155 +3468 +31 +2087 +1599 +1573 +5883 +7613 +195 +3749 +644 +2189 +8779 +8743 +9005 +8081 +1040 +7785 +5820 +8830 +5495 +4867 +2710 +3843 +491 +7153 +6217 +1148 +4741 +1761 +5484 +3423 +5474 +6916 +5876 +7252 +1739 +8930 +6647 +5198 +4903 +8488 +7366 +2774 +2726 +2385 +7625 +3179 +2211 +8845 +6600 +399 +6810 +3447 +6684 +4915 +8368 +1867 +2325 +2101 +1335 +7734 +3722 +7437 +3716 +7025 +4000 +6897 +1408 +7154 +5013 +2204 +9233 +4225 +3817 +1877 +9161 +2197 +6991 +3390 +280 +1892 +1612 +7753 +2801 +7246 +7909 +6229 +9314 +8407 +1436 +3879 +6432 +6849 +5326 +5327 +8535 +7910 +7745 +5545 +7916 +207 +1783 +6158 +8517 +7361 +8070 +6430 +119 +6146 +4183 +1083 +7385 +4497 +9133 +1686 +3765 +5099 +595 +8046 +4418 +4043 +2361 +7915 +9149 +1717 +1141 +6375 +1018 +5602 +1262 +7485 +9178 +6629 +3339 +8934 +4648 +7988 +6252 +3440 +864 +5418 +3874 +7280 +6191 +8388 +4323 +6792 +4324 +2232 +7228 +8684 +7813 +6187 +6678 +3177 +3534 +4953 +4402 +7739 +6319 +2414 +8700 +5946 +8238 +4533 +6917 +4167 +4618 +2115 +2268 +3081 +1247 +4001 +8580 +7636 +3101 +2195 +1559 +3714 +2484 +7188 +6028 +7530 +2828 +1977 +3238 +6496 +2340 +110 +3247 +7532 +7541 +924 +1632 +484 +4487 +4439 +6447 +1319 +4944 +6347 +1791 +2285 +8087 +5452 +91 +1166 +162 +5185 +7933 +4743 +1627 +7259 +8620 +8525 +8207 +5845 +9011 +5525 +4269 +4700 +1824 +8186 +8872 +8299 +3957 +8242 +4558 +6439 +2666 +5943 +6958 +8112 +5121 +8806 +6170 +7688 +3486 +2082 +7436 +2778 +1096 +786 +2206 +5170 +1443 +6030 +3312 +9151 +8485 +6404 +8498 +2883 +8961 +2280 +8341 +9137 +4337 +2809 +2445 +809 +8298 +8643 +8316 +4951 +6853 +1572 +3215 +3938 +2249 +6515 +1337 +8328 +7712 +1429 +4117 +5441 +3230 +4152 +7225 +3513 +6953 +1507 +348 +3639 +5739 +2673 +1550 +6301 +1652 +8453 +204 +6833 +8056 +2200 +5217 +1854 +4711 +7368 +4572 +4032 +7531 +1013 +3634 +2875 +6058 +8307 +7609 +1766 +904 +667 +5410 +6578 +3601 +1664 +3233 +7390 +8178 +4486 +4952 +4427 +4876 +9166 +3107 +2772 +6295 +5001 +5296 +3371 +6518 +6327 +854 +1615 +8288 +1912 +5927 +6202 +5814 +9032 +1059 +3214 +6547 +7038 +5781 +6926 +4390 +6114 +1622 +4318 +5803 +5984 +736 +3561 +6554 +5045 +4277 +7386 +9081 +8462 +2034 +4955 +2701 +932 +1298 +7758 +7176 +9205 +2276 +3077 +3803 +3562 +8054 +7946 +295 +1843 +7728 +1629 +7768 +3663 +6363 +2971 +431 +9285 +2513 +1116 +3656 +4529 +6366 +5758 +6339 +8398 +816 +4153 +648 +2536 +1826 +7870 +8113 +7730 +7101 +6555 +9256 +6774 +1072 +4578 +2598 +3604 +5880 +861 +8273 +3350 +3117 +4685 +9219 +4334 +5165 +2035 +7224 +4066 +4253 +4447 +3815 +5038 +253 +3658 +2252 +330 +3967 +6443 +2143 +7336 +6135 +593 +2734 +8390 +4655 +7800 +1399 +1173 +5618 +2822 +7905 +7503 +4431 +2443 +1568 +3909 +1974 +2496 +4772 +5164 +4105 +2138 +2864 +3799 +3924 +4882 +8245 +1585 +5528 +5692 +5730 +5832 +137 +3175 +2894 +2062 +3899 +2752 +4028 +2113 +5411 +293 +2647 +730 +3758 +1667 +8879 +9303 +6653 +3698 +3968 +3053 +503 +2150 +4645 +2257 +4627 +8303 +7966 +8742 +4692 +5901 +8547 +2277 +5546 +986 +370 +4697 +8712 +4804 +4881 +1182 +6650 +7290 +3487 +2814 +5668 +7567 +5333 +3724 +4164 +3084 +8896 +3888 +6537 +17 +6882 +3531 +704 +1037 +8866 +5263 +6758 +3762 +1393 +3824 +5575 +5112 +214 +1439 +5700 +8932 +1306 +5011 +6928 +5173 +4098 +1132 +7352 +4778 +7723 +1368 +2390 +670 +2685 +5855 +1772 +6380 +3853 +940 +5424 +6091 +1748 +6193 +5297 +6572 +8877 +6874 +430 +5041 +5267 +1145 +7448 +620 +9112 +4294 +1432 +72 +130 +2393 +7920 +4597 +6614 +8889 +3697 +1895 +3462 +2616 +3978 +4791 +7846 +7780 +8372 +428 +6559 +8326 +9211 +2363 +1525 +5980 +7888 +3331 +8118 +7899 +615 +7377 +791 +5930 +6627 +8322 +1138 +770 +8460 +5100 +8274 +8350 +6316 +2893 +7594 +9236 +5082 +8150 +1986 +1909 +8902 +2145 +3617 +3501 +7 +2426 +5056 +8016 +2702 +5360 +8135 +8385 +8378 +8018 +8574 +720 +8893 +3021 +1978 +4782 +1816 +2083 +4051 +1446 +5870 +971 +9097 +8006 +4222 +8287 +686 +1377 +611 +8153 +4920 +4808 +1536 +679 +4096 +3891 +4884 +432 +4615 +8988 +5560 +3451 +5589 +3514 +6169 +1414 +3244 +1490 +7100 +3588 +690 +7317 +4171 +2266 +6800 +108 +2793 +5151 +6977 +2587 +8188 +8752 +6318 +5815 +5116 +263 +3311 +5191 +5689 +289 +3392 +5755 +1022 +5548 +9319 +8937 +6011 +7632 +5328 +4993 +4141 +5407 +1865 +520 +7305 +7208 +526 +3645 +1859 +2520 +3523 +8629 +7304 +8881 +3076 +4005 +8329 +2205 +2214 +6925 +8691 +4136 +8883 +974 +7873 +7952 +3965 +5887 +7964 +7189 +2406 +2783 +8086 +405 +6568 +5147 +2021 +4727 +4826 +7674 +1600 +5078 +2949 +6624 +6541 +8986 +5740 +4679 +8500 +3591 +4434 +398 +983 +7544 +1478 +4570 +6012 +465 +9330 +7206 +808 +8737 +2356 +4959 +8812 +6955 +3599 +2168 +1420 +1721 +1794 +5897 +8422 +2 +4023 +2739 +3619 +8797 +5496 +8951 +8181 +6893 +9254 +1809 +5682 +4309 +6929 +2742 +5988 +3363 +4493 +8434 +4210 +1503 +1876 +5094 +4600 +4936 +4798 +3933 +5216 +646 +7660 +3098 +8773 +4076 +1576 +5335 +3746 +3327 +47 +4602 +8636 +4129 +363 +6417 +7416 +9025 +4377 +4766 +2779 +4151 +9046 +7860 +3154 +3476 +7620 +966 +2052 +8344 +1752 +7199 +4412 +8895 +8882 +2463 +339 +56 +5390 +4821 +7555 +6558 +1905 +5258 +8880 +4205 +3580 +6735 +1023 +4511 +3850 +161 +7395 +2532 +3349 +7055 +7387 +758 +1907 +872 +3006 +659 +815 +1961 +6902 +7668 +4708 +1904 +4433 +5159 +6816 +8664 +6918 +1016 +6513 +7314 +5364 +7480 +9313 +716 +3395 +6843 +2292 +918 +4329 +1035 +6344 +8593 +3404 +5212 +837 +480 +8524 +1342 +3690 +6797 +7414 +288 +8863 +3352 +1628 +24 +135 +3314 +2181 +8650 +5915 +8078 +6812 +1375 +6040 +906 +5635 +7126 +1387 +7458 +6119 +5591 +3795 +1531 +95 +1960 +7522 +3033 +898 +4607 +4921 +3913 +2623 +4430 +6268 +7063 +1326 +9075 +2505 +7400 +1284 +2951 +747 +6466 +1357 +6493 +7320 +5892 +576 +5107 +5559 +97 +2583 +6361 +8843 +3509 +7892 +6086 +1476 +4612 +7427 +4267 +9094 +7050 +6048 +8455 +8382 +2227 +284 +2898 +3221 +2353 +2157 +5990 +5810 +3581 +7279 +6188 +7859 +3549 +5539 +7918 +2022 +9066 +630 +2500 +5111 +6561 +5127 +8095 +5569 +6123 +1338 +8605 +3491 +4187 +8220 +7334 +9213 +3067 +6997 +2853 +4735 +4372 +1489 +5954 +6662 +2207 +973 +3361 +960 +6350 +4170 +7431 +8076 +1129 +750 +7559 +7194 +2261 +2300 +6590 +5893 +6889 +3125 +8788 +334 +7286 +3472 +8164 +7693 +1469 +1181 +669 +7515 +5563 +4773 +3210 +6324 +3113 +9070 +3638 +7551 +2541 +3506 +5138 +4069 +7198 +7560 +3306 +6100 +2932 +4473 +1741 +14 +4672 +7564 +8748 +8874 +3804 +3678 +2240 +2610 +2862 +1358 +5716 +42 +5176 +9326 +8464 +1038 +2993 +3017 +9072 +32 +4809 +4364 +2808 +4125 +448 +152 +7299 +5431 +6178 +793 +3444 +9120 +8410 +4963 +772 +5457 +6954 +3014 +6881 +286 +553 +1948 +6398 +6255 +3057 +8646 +6176 +2700 +7106 +5663 +6683 +1281 +6013 +8799 +7635 +9289 +1885 +442 +2225 +6294 +5054 +2674 +7884 +8730 +8216 +4203 +1488 +7111 +4013 +3623 +7950 +1971 +1966 +3248 +2900 +1553 +472 +3865 +7796 +6937 +4591 +8098 +5208 +294 +5627 +5691 +5687 +7149 +4879 +3624 +7005 +2773 +3112 +9185 +1633 +7830 +5101 +8707 +8469 +4678 +4860 +700 +5527 +9194 +2794 +5068 +2639 +1177 +4282 +6492 +8128 +5859 +5029 +5123 +2877 +522 +5048 +7230 +2104 +6642 +6731 +2717 +5149 +2043 +9059 +5277 +844 +1394 +3262 +5515 +6706 +3651 +9105 +7671 +2880 +3607 +6410 +2508 +8463 +2394 +1916 +1125 +5343 +3322 +5307 +4547 +1589 +8478 +8899 +2955 +8028 +7293 +4619 +4058 +2781 +8715 +1272 +5734 +4474 +4863 +4367 +49 +8844 +5605 +8671 +6743 +4281 +7077 +1874 +2626 +2516 +258 +5249 +6186 +7958 +5432 +3801 +6288 +4732 +9121 +7558 +2527 +4661 +6819 +3835 +7508 +584 +215 +5036 +4261 +8978 +5228 +647 +4657 +2591 +5931 +5088 +9204 +929 +4381 +5421 +2965 +5050 +6495 +5033 +4799 +959 +6115 +3520 +1232 +5811 +317 +8976 +7705 +3842 +2178 +7187 +1373 +7112 +2694 +8627 +8493 +3991 +7441 +6308 +2589 +6462 +3406 +7673 +8660 +2902 +752 +1025 +849 +7682 +6982 +6652 +3612 +298 +5148 +4873 +3414 +1693 +1458 +327 +2016 +5002 +6768 +7016 +5583 +3270 +857 +8232 +7158 +7981 +4676 +4675 +2164 +8360 +6709 +8143 +365 +4062 +4527 +7928 +9009 +6228 +5818 +2533 +9305 +8887 +55 +2507 +8870 +6649 +5158 +76 +5595 +6693 +5306 +8666 +3020 +7527 +3082 +6304 +1591 +6145 +6868 +7205 +9107 +1165 +6773 +172 +1993 +4176 +8400 +4611 +7589 +8702 +5386 +6095 +6335 +1561 +8805 +5963 +7393 +3681 +2037 +4968 +7451 +3360 +7466 +8361 +4455 +4064 +5422 +1689 +3977 +7269 +362 +4178 +4145 +6127 +5162 +2399 +9225 +7068 +1650 +794 +3007 +1348 +7736 +444 +6081 +5298 +2026 +2543 +9087 +3593 +7425 +3730 +8468 +2641 +7529 +1720 +6377 +8732 +5851 +7956 +3150 +3785 +6485 +3611 +2869 +8510 +4775 +4463 +1251 +9124 +6873 +3391 +6505 +4118 +1617 +8837 +7051 +3213 +3668 +5347 +8452 +6289 +5840 +478 +3522 +453 +3376 +6190 +3342 +2237 +2870 +5178 +5567 +5952 +6919 +3005 +134 +3397 +7443 +8539 +6822 +5264 +3288 +5962 +8421 +6744 +8608 +4656 +1802 +2073 +4271 +1043 +2922 +8211 +2196 +5260 +3789 +7211 +7571 +7834 +5680 +2047 +5502 +3369 +3437 +3286 +5517 +3912 +8386 +1442 +6961 +2191 +2417 +9088 +5155 +6813 +4520 +7375 +1224 +811 +1891 +3748 +4123 +2789 +5305 +8419 +7248 +9237 +992 +4038 +4499 +2060 +5538 +850 +2669 +7612 +104 +9290 +2526 +1287 +4160 +4633 +7125 +742 +744 +4534 +2407 +7714 +4555 +8764 +7661 +4722 +7721 +3205 +6657 +1214 +3754 +6080 +4593 +3018 +8792 +2294 +4450 +7701 +9301 +127 +7069 +4513 +6243 +8025 +4010 +8632 +4715 +5284 +4574 +726 +4252 +4561 +7354 +299 +6088 +1090 +5012 +5684 +3489 +5639 +4888 +1584 +1969 +4846 +2915 +6804 +2775 +7306 +6506 +9306 +5231 +7740 +4283 +953 +6725 +458 +8290 +1504 +1539 +8885 +138 +3764 +1256 +257 +335 +1011 +7060 +5986 +9323 +4740 +8994 +4140 +6807 +8254 +3963 +9297 +2102 +2964 +9207 +4910 +8709 +4411 +1672 +457 +5852 +8037 +4932 +3679 +8794 +2362 +8592 +495 +8432 +1608 +2155 +7411 +2881 +9244 +37 +6535 +8219 +4505 +8635 +1928 +8384 +2570 +8996 +7610 +2128 +8728 +6656 +8935 +6681 +2070 +176 +9062 +972 +514 +1796 +4039 +6838 +2462 +230 +569 +5521 +4637 +4939 +4420 +2863 +672 +4995 +3807 +447 +1656 +2005 +5113 +3297 +8858 +2118 +6309 +1926 +481 +1156 +1509 +1228 +1787 +5978 +8678 +3951 +2929 +4980 +5039 +4713 +7002 +151 +5536 +8148 +3823 +4709 +2299 +142 +7067 +2372 +3761 +9 +2265 +5747 +2764 +724 +2913 +3151 +4525 +6370 +4247 +9329 +5494 +3721 +629 +3621 +7371 +59 +1999 +6704 +3734 +2698 +4691 +6938 +9117 +8415 +6353 +6750 +9077 +2679 +7623 +2478 +7321 +6611 +4007 +2076 +5772 +6416 +2264 +8348 +2672 +6546 +754 +6934 +7908 +8546 +4404 +592 +4748 +6625 +2129 +7944 +2377 +6 +8929 +8275 +3515 +4524 +3660 +8710 +419 +6878 +170 +8313 +7460 +8753 +2917 +6891 +6663 +4918 +7129 +396 +7256 +3500 +631 +5585 +8343 +2695 +6168 +6292 +3176 +5092 +5160 +3701 +9021 +7221 +7825 +1216 +1438 +3471 +2318 +8923 +6223 +2182 +7621 +8514 +9010 +8987 +1252 +1972 +1872 +1715 +8205 +6463 +8138 +8989 +5661 +2890 +565 +2427 +8946 +1303 +3718 +6000 +3620 +1560 +5276 +8089 +9260 +1467 +6173 +7641 +7520 +5061 +4677 +5757 +4400 +2620 +2719 +8995 +2079 +6644 +1683 +8141 +7754 +5744 +2952 +7568 +654 +7457 +5368 +3310 +1510 +4440 +1513 +3072 +8034 +1456 +9164 +3163 +3035 +6111 +5042 +7161 +1401 +1084 +8000 +6672 +8531 +5404 +6550 +8379 +9141 +8681 +7752 +6394 +7011 +3739 +8253 +978 +4771 +6024 +4828 +7959 +1649 +1727 +7073 +8349 +6952 +661 +7283 +3159 +2590 +3496 +8741 +3969 +2956 +4565 +920 +1830 +8558 +1930 +6677 +6825 +8256 +7454 +7521 +4710 +1768 +3753 +6459 +5606 +5292 +1397 +240 +2733 +946 +6711 +3242 +2627 +4929 +5006 +3202 +132 +2295 +2746 +1293 +2124 +5405 +4065 +818 +7464 +1820 +4398 +1312 +6994 +6920 +261 +987 +6120 +3109 +331 +2986 +4338 +7774 +5122 +8396 +1364 +8969 +6712 +8161 +7083 +7595 +5940 +1566 +6419 +8634 +4432 +6047 +4749 +6076 +1161 +8217 +674 +8494 +3688 +2447 +4704 +969 +7477 +1160 +3243 +3173 +4979 +9288 +6860 +1662 +6171 +225 +5143 +313 +8327 +3275 +3385 +7626 +3103 +4401 +6794 +5600 +5043 +7664 +933 +6830 +4452 +3980 +1604 +5875 +6633 +4635 +5756 +3329 +1751 +8108 +4817 +1989 +1237 +1893 +2848 +9334 +51 +8875 +4981 +5417 +4134 +877 +6688 +3545 +4943 +5615 +2476 +1684 +3652 +7396 +1769 +1171 +6563 +3415 +3644 +340 +6630 +8284 +3256 +7240 +5371 +3405 +2108 +6360 +1734 +5612 +8638 +2343 +1103 +7803 +6809 +3055 +188 +8031 +3124 +3683 +4537 +988 +2297 +4893 +6499 +3396 +839 +4467 +5195 +4041 +6457 +4441 +6378 +6472 +6195 +4912 +6884 +5922 +7014 +1660 +38 +1595 +6752 +4554 +1292 +2709 +3800 +6057 +1980 +8775 +6587 +6392 +6263 +7214 +5219 +282 +309 +6685 +2253 +6311 +4092 +18 +7570 +5543 +4081 +2515 +6278 +8690 +5294 +6184 +5215 +9130 +6720 +250 +7250 +4983 +639 +3567 +7841 +2636 +4067 +8446 +5703 +8609 +2586 +7695 +1253 +6701 +7930 +6317 +5921 +7719 +8501 +7312 +4110 +6219 +4552 +5059 +4088 +7975 +9132 +6054 +692 +3412 +4079 +6754 +6950 +5281 +3028 +8321 +3877 +7614 +8939 +4188 +2223 +239 +4745 +6875 +7096 +5571 +4403 +2640 +5556 +1845 +6690 +1825 +4157 +314 +4682 +8825 +1003 +6206 +8093 +7215 +6465 +99 +8077 +6631 +4206 +2523 +366 +1208 +6043 +4640 +1457 +5475 +4985 +1351 +3090 +5625 +7307 +8466 +2003 +8854 +218 +1500 +4476 +2293 +1847 +5032 +2147 +866 +3710 +2552 +1749 +6692 +3926 +4112 +6458 +735 +9171 +60 +9304 +6726 +2630 +2882 +1178 +1151 +4922 +4662 +173 +7233 +1776 +6533 +4113 +2423 +2425 +4343 +5800 +970 +6372 +1009 +6607 +3068 +8435 +6423 +3126 +4813 +1709 +1201 +7104 +5620 +3932 +5701 +5724 +3366 +8050 +4984 +5023 +9203 +5079 +627 +290 +779 +5572 +5233 +1392 +4975 +8534 +8210 +2269 +1143 +2475 +2562 +905 +4546 +267 +3536 +8538 +449 +101 +7367 +2722 +4605 +7356 +6781 +8537 +8697 +6820 +8340 +8926 +3821 +2349 +2259 +6545 +8100 +8395 +2258 +2911 +5108 +3946 +1406 +8683 +8296 +5579 +2177 +8264 +1425 +3940 +957 +3647 +515 +5342 +8363 +2449 +3108 +1001 +2937 +3452 +5574 +4319 +9184 +8381 +945 +6876 +600 +5714 +4871 +8532 +1852 +8856 +392 +2018 +8878 +369 +5711 +9230 +5304 +7266 +1681 +7829 +2309 +4683 +8938 +2255 +6159 +3207 +4651 +2029 +4341 +5106 +5794 +9024 +4712 +2434 +7151 +7359 +6431 +1290 +5918 +8705 +3438 +5554 +8876 +7415 +6290 +5373 +3805 +2950 +2331 +6772 +8997 +6576 +2307 +8515 +4033 +3428 +6487 +6595 +45 +5792 +333 +762 +2383 +3388 +666 +2166 +460 +943 +364 +6980 +8223 +8221 +637 +6218 +4108 +5381 +4649 +5096 +1614 +8768 +5095 +3809 +5030 +984 +3538 +5120 +2498 +5222 +5613 +5486 +5119 +241 +5707 +9227 +544 +4109 +7771 +728 +3671 +9327 +1230 +9270 +1070 +8565 +4769 +7056 +5654 +7965 +1793 +5956 +7883 +1362 +5479 +8769 +8821 +8320 +1901 +1994 +2461 +5552 +389 +2839 +6467 +2762 +4763 +3499 +1487 +7599 +4488 +3241 +8272 +1131 +4496 +7006 +7265 +4897 +2747 +6618 +5291 +4563 +5146 +1939 +6369 +8548 +6163 +5526 +4068 +9030 +5349 +8433 +748 +1477 +4265 +9200 +3878 +462 +6846 +9040 +4806 +3519 +6798 +5464 +5179 +546 +6044 +8114 +7216 +6276 +1495 +494 +8146 +5434 +856 +8403 +8071 +3972 +5544 +3337 +6855 +1546 +2824 +1718 +6009 +2042 +251 +9076 +3330 +5004 +192 +4717 +3797 +1146 +394 +7814 +7699 +4659 +4689 +4156 +7903 +9054 +7332 +7811 +1119 +5531 +6782 +5210 +8412 +2633 +7924 +4624 +8314 +5666 +3240 +2310 +4262 +8160 +4553 +8196 +2661 +7213 +7455 +7399 +870 +6126 +1227 +1226 +781 +937 +6343 +2578 +2892 +4124 +2792 +5696 +6865 +6455 +8312 +5193 +6026 +5251 +3787 +4460 +4687 +7923 +1140 +9106 +796 +2482 +9170 +8695 +2749 +6734 +4825 +114 +8319 +827 +4175 +390 +7611 +7484 +1249 +7727 +955 +579 +3629 +8915 +2958 +885 +7227 +1424 +4810 +4604 +1535 +774 +7518 +5428 +1955 +8233 +2645 +2167 +6484 +3855 +1502 +4861 +2333 +2973 +4829 +1906 +3966 +476 +9023 +6960 +3483 +2748 +5891 +8174 +7702 +8948 +5324 +4396 +1605 +2823 +7348 +7347 +5933 +310 +9082 +916 +4255 +203 +4239 +5976 +6200 +6435 +4425 +787 +1121 +6034 +13 +39 +3104 +5961 +5507 +5785 +1463 +7339 +1575 +7801 +5445 +8283 +5951 +6995 +999 +5163 +6023 +3786 +6536 +5850 +3524 +3528 +4508 +6674 +2939 +8227 +4598 +7550 +8495 +8622 +1152 +4538 +4003 +1318 +739 +3296 +8202 +1552 +6204 +5236 +3576 +4699 +9238 +1879 +488 +2274 +433 +5587 +1678 +9282 +7914 +8552 +6445 +7971 +8331 +6880 +7476 +7282 +1570 +7271 +3827 +6489 +8091 +9287 +7351 +1765 +5286 +6921 +542 +1762 +8553 +4987 +894 +3622 +7855 +92 +3131 +4811 +3590 +6517 +4510 +733 +4954 +1360 +5669 +2842 +8107 +5646 +5968 +1618 +1827 +7709 +8521 +5807 +5321 +9239 +5501 +3745 +4437 +1586 +7273 +5265 +6605 +7917 +1607 +6074 +4668 +7061 +1580 +8694 +8461 +4573 +618 +9173 +5243 +435 +8770 +2421 +7450 +3870 +8308 +2605 +2934 +9240 +6887 +4512 +1198 +7585 +7691 +7738 +2843 +8423 +7929 +6971 +7854 +86 +9128 +4298 +622 +790 +9155 +6579 +2203 +7716 +1265 +8645 +3834 +1174 +7380 +623 +8936 +4306 +8082 +4312 +8661 +5753 +7243 +2768 +8155 +85 +4143 +3047 +8479 +7809 +2833 +5555 +7578 +1637 +1936 +8130 +5549 +8062 +7143 +5522 +8966 +5614 +8105 +8719 +7655 +7502 +8268 +5760 +6695 +5565 +7615 +9226 +4870 +4507 +3160 +4835 +1598 +2465 +4422 +5248 +7867 +1078 +5015 +6660 +1676 +5354 +6391 +5351 +7184 +6280 +5936 +6124 +1327 +2906 +269 +8292 +2466 +8809 +5167 +8142 +8204 +2713 +1910 +2930 +2494 +5592 +7384 +7726 +5727 +625 +1735 +5710 +5518 +2491 +1410 +4989 +5183 +8777 +6562 +4947 +3692 +6129 +384 +1097 +2084 +5209 +3723 +7272 +6895 +2459 +543 +8621 +5394 +6211 +2074 +1511 +2524 +7776 +5055 +7191 +6207 +7922 +281 +8436 +2918 +3141 +4800 +6323 +7631 +8903 +2716 +3735 +3012 +5301 +3975 +2800 +7963 +105 +1920 +7391 +4909 +1754 +4816 +5488 +5145 +5098 +5139 +5268 +9317 +8631 +4346 +7318 +136 +3993 +1220 +2151 +308 +7483 +7582 +3071 +1339 +3777 +8191 +5378 +7087 +1056 +7465 +5608 +6564 +512 +2754 +2687 +1596 +5376 +1512 +566 +6382 +7360 +1757 +8035 +2296 +4264 +3551 +1053 +4716 +1537 +8518 +254 +6253 +7132 +8557 +3490 +9267 +5473 +2412 +7539 +7136 +6670 +3974 +891 +1323 +5958 +1217 +2879 +9118 +1259 +2317 +7033 +2467 +6665 +6244 +2180 +2140 +7098 +5126 +6395 +4150 +547 +4120 +4307 +1725 +2737 +8549 +8195 +1245 +6286 +935 +1756 +1701 +1626 +7379 +3492 +3717 +5802 +2817 +1234 +1005 +4101 +21 +2576 +4650 +3381 +1030 +2844 +1641 +936 +2729 +6469 +8913 +8369 +5994 +341 +81 +4083 +1685 +5152 +3380 +8739 +6615 +3829 +164 +7927 +4779 +829 +4216 +8528 +3641 +4606 +2769 +6970 +1545 +8850 +4971 +5489 +2008 +4564 +8682 +7784 +5768 +9252 +901 +438 +3577 +2765 +5904 +664 +3348 +6298 +3602 +2502 +8617 +7684 +4293 +5166 +5805 +4126 +2451 +6906 +7234 +9243 +3778 +2940 +1087 +9053 +5026 +2504 +5283 +2820 +4242 +797 +3925 +1383 +8750 +7861 +1403 +6973 +7617 +968 +3065 +5395 +4347 +8144 +2688 +6527 +8597 +8673 +7327 +6331 +1422 +7115 +244 +7013 +2092 +54 +7970 +5742 +3464 +4823 +8588 +2938 +3060 +6406 +4149 +2375 +6616 +8803 +1555 +4369 +1380 +3011 +6144 +3367 +4990 +7370 +7131 +1995 +2602 +985 +8785 +8480 +9125 +1927 +3269 +3771 +1032 +7378 +6900 +5726 +2731 +2020 +4503 +3313 +6727 +8793 +2304 +523 +6036 +58 +7993 +5512 +5049 +2721 +8482 +673 +7937 +1168 +4472 +8247 +7287 +9017 +6421 +9190 +3584 +1819 +1792 +2810 +6033 +638 +6749 +7677 +981 +7160 +4726 +1886 +7845 +7911 +6975 +568 +7422 +4613 +4501 +2569 +4263 +3206 +4133 +2420 +3706 +8894 +2263 +5774 +4925 +9180 +8888 +2945 +2091 +1873 +6303 +729 +6728 +2156 +3267 +1860 +6597 +1374 +4930 +5253 +938 +580 +5825 +4839 +166 +8198 +6892 +8701 +74 +7094 +7284 +8954 +3156 +6140 +4279 +5594 +2229 +7535 +5466 +8413 +7105 +8192 +2632 +7638 +9308 +8530 +832 +4643 +2201 +3268 +4322 +6510 +2967 +262 +403 +7973 +1258 +8828 +4036 +5838 +9263 +8529 +2788 +4202 +237 +3838 +1291 +2305 +4056 +5628 +7281 +1430 +6476 +7935 +2850 +6041 +2013 +4016 +4576 +5312 +6827 +6321 +8669 +8439 +830 +1942 +1519 +2750 +6106 +6993 +6235 +5899 +7313 +5331 +4371 +7086 +4399 +8600 +2660 +5409 +3465 +5499 +6231 +5745 +1801 +5337 +4468 +1451 +4192 +1275 +8230 +2302 +1114 +4960 +8860 +3900 +6468 +5058 +1505 +8868 +5588 +3858 +1947 +2565 +1472 +8499 +243 +8442 +6583 +7085 +5374 +2250 +4291 +4426 +492 +2311 +8305 +3662 +5338 +8780 +7488 +3890 +5005 +2442 +4680 +7358 +9116 +4397 +5999 +587 +7902 +83 +3566 +2134 +8942 +4767 +6601 +2456 +1745 +5736 +5254 +8017 +4015 +7690 +3798 +8947 +1067 +2116 +7945 +590 +2547 +2535 +64 +2053 +5359 +2493 +6669 +4351 +6412 +7473 +6147 +7175 +6983 +5196 +745 +2657 +3497 +697 +3161 +7528 +2239 +5991 +3201 +7681 +2440 +5189 +2959 +2044 +8917 +2046 +6313 +6333 +5318 +2763 +4301 +2555 +2213 +2933 +4121 +1340 +3903 +4392 +7889 +5323 +1055 +707 +3857 +518 +6078 +5134 +6645 +9138 +1592 +680 +4446 +7943 +3461 +3887 +5601 +2321 +6621 +558 +4914 +913 +5637 +6453 +8511 +4531 +1218 +5508 +2603 +6802 +8426 +8297 +2947 +5971 +6552 +5262 +5935 +782 +7435 +8357 +6139 +1136 +1473 +5008 +3585 +3627 +2914 +5356 +2997 +2347 +881 +5652 +4849 +8808 +8351 +4017 +2010 +6836 +7616 +4391 +3630 +3712 +6099 +2969 +5238 +4333 +2301 +4406 +1236 +1050 +1864 +1104 +8408 +8251 +8795 +5879 +3365 +7481 +8206 +2452 +1767 +8859 +124 +3948 +4444 +8962 +4438 +5003 +1740 +8428 +3105 +5117 +1095 +1480 +8755 +7881 +3097 +4877 +155 +1917 +2455 +6042 +337 +6724 +6045 +8483 +7135 +2242 +4566 +1679 +834 +1746 +795 +3548 +2314 +2036 +4046 +9129 +6979 +7084 +5091 +2413 +8170 +5775 +1817 +529 +7220 +813 +2916 +5130 +8972 +126 +1243 +2370 +4831 +9122 +3010 +5104 +2613 +6761 +7482 +909 +2146 +4595 +5340 +3512 +6283 +2346 +653 +6121 +2615 +7421 +1869 +1002 +8834 +2991 +8992 +632 +1093 +4543 +645 +2352 +4115 +373 +1483 +6966 +8598 +3896 +3434 +5987 +8318 +1815 +1223 +1548 +6885 +5073 +6330 +2573 +1369 +4095 +1431 +2185 +5766 +1301 +7258 +8048 +7598 +2847 +1996 +2378 +8561 +743 +6381 +271 +1956 +7439 +7596 +7134 +6636 +5804 +1858 +6214 +4730 +8536 +1203 +3118 +9202 +1875 +5885 +8975 +168 +5898 +4014 +4186 +3346 +3041 +5558 +9296 +8157 +4339 +3234 +1738 +2604 +6803 +5387 +5590 +125 +2173 +8012 +8005 +4858 +3069 +651 +372 +378 +8366 +6299 +1449 +7793 +8541 +3235 +8043 +3086 +3983 +6949 +4690 +2176 +6494 +7637 +8406 +3856 +7408 +350 +7021 +8224 +7044 +7662 +6697 +7679 +169 +528 +7029 +2790 +7138 +7432 +7602 +8333 +1582 +1378 +519 +482 +9279 +8015 +6592 +4514 +3542 +2612 +628 +5053 +6699 +6227 +2094 +1621 +847 +3598 +2728 +8490 +7276 +6620 +8345 +9216 +4278 +4059 +9058 +5063 +5816 +4173 +8134 +1997 +3182 +3224 +8129 +5109 +4494 +189 +7640 +8243 +180 +2963 +1123 +5593 +3263 +4185 +7140 +8990 +6320 +9275 +4601 +4854 +5907 +1135 +8083 +5964 +7788 +1992 +8069 +9174 +6160 +35 +8572 +2865 +46 +3952 +6418 +2510 +5783 +20 +3816 +2715 +3930 +2548 +5204 +4122 +4103 +708 +7756 +3825 +777 +3550 +8502 +3929 +5440 +6751 +7764 +4070 +7331 +3743 +9131 +9206 +3828 +23 +41 +4197 +234 +5723 +7622 +8832 +4626 +2169 +5599 +2976 +5266 +1967 +1150 +5334 +90 +822 +2538 +3169 +6771 +7442 +498 +4967 +5580 +7581 +7680 +4728 +1115 +4040 +1064 +3106 +6266 +4415 +9294 +5597 +7059 +197 +7218 +6948 +5690 +4234 +1653 +4485 +4019 +3370 +919 +1330 +6085 +2078 +3768 +5427 +4545 +2435 +8862 +3633 +8145 +5221 +1388 +5913 +8140 +7471 +7156 +6989 +1190 +6832 +2830 +4387 +3454 +7469 +2910 +4526 +5187 +2410 +9223 +6247 +6912 +4681 +1300 +7407 +8612 +6523 +3616 +6894 +7253 +4515 +5874 +5448 +7137 +7957 +1130 +3092 +7054 +3516 +5797 +1000 +2727 +4336 +9090 +6403 +7255 +8919 +6522 +6760 +8898 +4803 +1938 +374 +8686 +9150 +3985 +7045 +3475 +6065 +7991 +1409 +7851 +6671 +6090 +5826 +7857 +1155 +8964 +1117 +7072 +6064 +2497 +4899 +2397 +3189 +2369 +15 +5027 +5754 +8950 +5617 +8391 +914 +6264 +279 +6174 +5184 +3733 +7392 +5278 +2924 +567 +7994 +352 +8084 +2148 +2723 +3359 +70 +1870 +7708 +220 +3994 +9013 +3191 +9220 +4155 +5717 +1110 +2198 +9179 +785 +5325 +4770 +4250 +52 +4634 +5072 +9037 +601 +8036 +7996 +2483 +7232 +8675 +8836 +1279 +5346 +7676 +6104 +1515 +4603 +5607 +7894 +5144 +2628 +68 +440 +3586 +3083 +4830 +4378 +7762 +1134 +4542 +7850 +6296 +2866 +4011 +8751 +4776 +7954 +7102 +5697 +2032 +5729 +5017 +6962 +2051 +1092 +764 +9019 +2759 +8581 +1484 +8618 +912 +2382 +4892 +8447 +8176 +5491 +5695 +5504 +1060 +7064 +709 +578 +4320 +2379 +7649 +8416 +1613 +5344 +7512 +7865 +3037 +6689 +6557 +1569 +5955 +3707 +9168 +8566 +1775 +5950 +6943 +7804 +434 +6179 +9300 +1142 +7947 +6456 +6291 +5789 +6538 +9134 +3049 +5075 +5399 +5161 +1623 +948 +6302 +6063 +7516 +117 +506 +3302 +7146 +355 +3854 +1081 +2827 +1496 +2574 +6167 +3183 +4287 +5482 +1722 +7319 +7277 +3860 +3443 +3298 +8364 +3826 +7254 +2360 +5093 +7039 +6325 +4230 +2567 +6241 +4443 +559 +2625 +4228 +8967 +6405 +1674 +3936 +4475 +8556 +8585 +896 +3713 +6259 +4297 +6718 +2392 +2279 +4927 +1283 +2374 +2860 +7665 +663 +596 +6293 +6805 +2811 +7383 +8306 +8330 +3153 +2153 +2618 +2441 +3615 +8092 +552 +5285 +5255 +8124 +9247 +5530 +8175 +6242 +5660 +3433 +1610 +1832 +3892 +3862 +640 +2127 +2474 +4196 +3495 +7217 +5206 +4836 +7759 +4376 +800 +4227 +3699 +9055 +5665 +6826 +7463 +9065 +4720 +5069 +3245 +3453 +3358 +6532 +5970 +7921 +4087 +1547 +3424 +8040 +7995 +6787 +9069 +8716 +2561 +8199 +1479 +2767 +7818 +7145 +604 +7597 +4896 +9281 +4666 +185 +8171 +7978 +3059 +9196 +9221 +2135 +1800 +2974 +1529 +5948 +446 +4436 +8672 +3508 +6208 +5673 +6998 +5203 +278 +7041 +9110 +5853 +8121 +1764 +3046 +2400 +6575 +4738 +2228 +7761 +9322 +7019 +6931 +6383 +6762 +283 +3935 +2534 +7717 +6785 +471 +8214 +231 +4241 +5310 +3844 +5746 +2011 +7209 +336 +6433 +756 +9167 +6741 +3345 +7685 +4018 +6682 +9147 +4790 +5836 +5906 +8747 +676 +3964 +6362 +3510 +7510 +2308 +1806 +5917 +1189 +4012 +3387 +1331 +5319 +5423 +8900 +147 +3780 +1696 +9111 +6783 +6497 +4104 +1898 +3987 +260 +4616 +2121 +9283 +1400 +2437 +4670 +2735 +1163 +2096 +6521 +1423 +4523 +2243 +6667 +6990 +3944 +6915 +6763 +5611 +404 +2691 +1015 +7092 +7562 +8624 +2291 +4193 +5934 +5503 +2326 +4408 +2960 +842 +1963 +3354 +5568 +9050 +3806 +439 +9154 +6055 +6451 +2190 +7633 +688 +4354 +8890 +2813 +2872 +8102 +8317 +6609 +1497 +8389 +6449 +1682 +3594 +5103 +5812 +863 +268 +3054 +8079 +2260 +2027 +3091 +7687 +6703 +3557 +2019 +8427 +2799 +8182 +6641 +3168 +2284 +1934 +4865 +1077 +6507 +1658 +3811 +1774 +7897 +2238 +2943 +191 +3869 +3246 +4057 +3188 +414 +8072 +7838 +1382 +4962 +6010 +5363 +4042 +1983 +4077 +7429 +1833 +3583 +4044 +1109 +1295 +386 +5481 +3927 +311 +1349 +5651 +5878 +562 +2202 +8904 +765 +1501 +8654 +2975 +2689 +3680 +5180 +1900 +7707 +4723 +8912 +4029 +3579 +869 +2888 +8657 +6599 +741 +4288 +2244 +7357 +5704 +8791 +208 +8587 +7969 +4805 +8526 +4887 +8871 +7468 +3343 +886 +7794 +5764 +2646 +6454 +6101 +7885 +7744 +1297 +4119 +4856 +122 +2286 +2925 +5131 +3570 +5843 +3027 +5320 +5626 +540 +1862 +5401 +7335 +699 +7760 +9198 +3259 +7345 +8698 +1280 +6479 +3100 +3988 +1322 +5737 +1268 +3257 +6791 +3326 +4815 +7644 +1082 +2826 +6821 +8984 +2553 +5290 +5909 +4762 +9242 +8096 +8066 +4325 +6666 +7193 +7114 +8060 +2376 +7872 +6788 +3544 +5460 +3507 +2509 +6626 +3429 +5542 +4220 +2968 +5271 +4249 +3863 +1868 +5581 +2012 +6270 +8038 +4050 +121 +2845 +1565 +1998 +2275 +5524 +6068 +7624 +4913 +9277 +1506 +803 +8848 +5925 +2450 +2072 +8190 +4753 +9162 +1923 +825 +7303 +9028 +2088 +8516 +1556 +5937 +7847 +2367 +7549 +1049 +1521 +4739 +3931 +8958 +4130 +7877 +7876 +897 +5985 +7346 +7537 +111 +3700 +1126 +7896 +1288 +3419 +4673 +1051 +5720 +1068 +3458 +146 +291 +6256 +5514 +2857 +4580 +6239 +6525 +8717 +391 +4841 +6676 +4360 +1453 +4211 +73 +1675 +1987 +4025 +1321 +662 +8265 +6424 +2758 +7765 +7656 +3209 +7497 +7600 +9039 +7697 +5177 +2983 +5622 +9295 +1200 +3284 +964 +2024 +1269 +4551 +8088 +5659 +2212 +5199 +5551 +8607 +5573 +2247 +5200 +6341 +7951 +8429 +7720 +5919 +1273 +3529 +6707 +9176 +7552 +3255 +5649 +6110 +9235 +1137 +9272 +775 +788 +5786 +5186 +6746 +2667 +9145 +7630 +3953 +1828 +8827 +6471 +4702 +7815 +467 +6387 +3195 +6238 +6508 +2373 +5983 +4931 +2948 +921 +2438 +517 +3949 +2137 +3216 +5683 +3695 +1719 +4837 +9159 +6981 +860 +7410 +5497 +1770 +5557 +8810 +5194 +4857 +9100 +6329 +2609 +1925 +3686 +9041 +4924 +349 +9187 +3393 +3661 +7120 +6858 +4587 +3831 +3130 +5396 +5060 +6486 +3937 +8023 +824 +5398 +1354 +8861 +5534 +7292 +4389 +6029 +6226 +3505 +4326 +7445 +581 +6089 +3450 +7324 +6516 +6775 +1207 +4575 +5135 +9265 +3918 +9020 +3473 +3898 +7812 +6571 +6757 +6639 +2557 +1206 +6148 +7325 +8790 +4938 +7026 +4383 +8041 +1250 +7267 +1952 +7561 +8811 +4941 +8373 +4848 +6602 +8355 +8104 +5214 +6654 +4330 +995 +3181 +3422 +456 +1782 +3408 +6530 +719 +7587 +5910 +3058 +740 +2009 +4207 +5336 +2798 +9229 +8668 +2473 +4221 +1493 +3281 +171 +9157 +9139 +7766 +6220 +9127 +3324 +5308 +3708 +2431 +8080 +2093 +2585 +406 +7040 +5064 +5247 +4758 +6512 +2953 +4257 +4935 +2705 +2572 +3436 +8513 +5884 +1385 +4852 +2637 +7091 +2761 +6007 +8332 +6694 +2422 +4917 +2186 +6898 +1390 +6965 +3132 +7698 +475 +2002 +2692 +5024 +7365 +7373 +4091 +1731 +947 +3962 +8692 +1788 +8734 +8656 +6862 +6856 +1950 +1914 +5658 +3635 +1620 +4780 +2580 +1454 +2786 +687 +7238 +3648 +6452 +1197 +3190 +5900 +9043 +4958 +1935 +1821 +1187 +1153 +7737 +7223 +3820 +7169 +7350 +5674 +6254 +3025 +6680 +1690 +2899 +3893 +1577 +5728 +9189 +5077 +34 +3560 +2179 +5462 +1402 +3654 +1376 +7936 +4246 +5506 +1179 +5647 +4686 +8644 +1352 +2855 +6079 +2254 +2668 +2287 +2457 +3418 +7264 +677 +3074 +2655 +1042 +2210 +4504 +7089 +8309 +4209 +4280 +3258 +2977 +84 +4705 +1244 +3511 +6355 +8813 +3228 +9266 +1122 +613 +732 +5202 +8425 +2638 +6470 +2886 +3541 +8132 +2063 +8201 +5129 +2818 +7949 +6936 +8090 +4465 +7295 +5239 +7009 +9271 +8563 +2832 +952 +8136 +6776 +3565 +5188 +7288 +6999 +285 +5487 +7763 +7608 +8584 +2071 +7868 +2804 +3655 +7048 +6847 +3276 +4082 +4272 +3910 +3709 +1574 +4559 +7580 +7081 +5014 +7769 +8183 +6386 +7574 +356 +4937 +2487 +9315 +7572 +3040 +671 +2682 +8626 +3868 +8623 +387 +8679 +4074 +1481 +3527 +3595 +4754 +2453 +1579 +4638 +9123 +1829 +316 +3009 +3691 +763 +4875 +3572 +4642 +3128 +4273 +2777 +6032 +4793 +233 +7147 +996 +3199 +8835 +3517 +7210 +6125 +6037 +3684 +8589 +3915 +3095 +8310 +3180 +7043 +4458 +2889 +57 +4483 +7667 +8375 +1434 +7493 +6986 +4733 +8471 +5827 +2111 +1313 +7986 +3075 +2614 +7547 +4977 +8527 +3212 +7300 +5842 +5244 +3291 +597 +1007 +2030 +227 +3830 +5540 +247 +5643 +9333 +1958 +3096 +1371 +5220 +7926 +2927 +1516 +7130 +193 +1522 +6165 +6923 +3794 +4223 +5535 +2472 +8630 +3971 +9101 +2946 +222 +4609 +7291 +8542 +6501 +7548 +4557 +6274 +1010 +5226 +7309 +1317 +9056 +6275 +1624 +1099 +4191 +4030 +7270 +5392 +2316 +3819 +1670 +8154 +8045 +4807 +8864 +2391 +5908 +8338 +8218 +6400 +9193 +3165 +843 +6613 +6941 +4380 +9332 +5629 +7557 +4321 +3702 +681 +734 +1159 +4665 +5959 +1697 +5509 +8774 +7389 +3832 +3751 +8637 +3079 +1680 +6841 +703 +684 +8293 +3682 +5733 +4818 +3231 +3078 +5562 +9001 +3889 +7024 +2519 +1713 +3287 +219 +6021 +8776 +2289 +7212 +4832 +4684 +4617 +4237 +2649 +8185 +6326 +3568 +551 +1426 +4181 +8869 +312 +2905 +4165 +8248 +2558 +900 +1044 +8613 +7743 +5437 +7604 +3122 +5708 +8649 +2878 +4695 +4491 +1929 +7533 +5223 +7711 +915 +1844 +5751 +3008 +8055 +961 +6142 +4636 +61 +198 +2271 +5698 +4596 +4500 +5709 +5819 +7972 +2992 +1643 +1048 +6281 +8886 +360 +4198 +1841 +6814 +3960 +2606 +7001 +5888 +450 +7133 +7015 +7034 +5153 +8920 +5066 +469 +1302 +8816 +463 +8651 +5869 +8193 +6582 +5578 +1231 +9274 +7260 +7751 +8052 +6799 +2089 +2342 +8451 +3260 +5550 +7795 +2288 +1205 +40 +496 +8367 +7836 +5973 +3908 +5242 +5062 +2706 +997 +6514 +5419 +9201 +1965 +6062 +3050 +5302 +8735 +358 +2398 +7470 +1644 +8179 +7047 +1549 +5414 +2539 +7381 +589 +8166 +8505 +6035 +3956 +4540 +6721 +8074 +1062 +2384 +2531 +7159 +3502 +3902 +4584 +2554 +264 +8720 +2849 +4916 +5218 +7202 +883 +4560 +1677 +4317 +7863 +4509 +6577 +2903 +1452 +1416 +5369 +473 +6233 +6359 +5992 +4934 +8059 +6834 +4907 +3320 +8267 +8280 +2066 +2402 +1485 +3772 +3732 +4764 +9126 +3575 +5564 +4768 +5641 +1884 +2330 +1804 +344 +698 +3089 +1532 +4454 +761 +7289 +8094 +3432 +1747 +6811 +8722 +8826 +4646 +3222 +8614 +2901 +7003 +652 +8663 +4266 +413 +810 +75 +3334 +4905 +6438 +4756 +5137 +6528 +6534 +6988 +6177 +8533 +889 +5384 +7201 +5132 +7802 +6864 +3973 +873 +4840 +1482 +8376 +3769 +5858 +6675 +4286 +2593 +5863 +4353 +7817 +7540 +4999 +4838 +2303 +6002 +7913 +1508 +5317 +7755 +2784 +4964 +3431 +6209 +3755 +6022 +6399 +6232 +3954 +455 +5416 +6448 +1558 +7591 +245 +140 +9210 +6585 +4084 +967 +7798 +6795 +7095 +6733 +3861 +9264 +361 +1045 +755 +8042 +7074 +7778 +6415 +4724 +6450 +2049 +1563 +1307 +3485 +1790 +7869 +3282 +6907 +3920 +2868 +5801 +5632 +1079 +5009 +3955 +7517 +5128 +3417 +3019 +2725 +1784 +2312 +2753 +6976 +342 +8266 +1849 +2273 +5037 +7880 +3793 +7401 +5412 +8279 +1257 +3670 +9049 +3266 +8955 +6519 +8916 +2858 +694 +5650 +1019 +4669 +1785 +3533 +5877 +2704 +8603 +3726 +6668 +497 +1085 +6815 +6157 +6646 +6964 +186 +8097 +5645 +8481 +8215 +3775 +2542 +7514 +5699 +4072 +3518 +5767 +3239 +3740 +1404 +8981 +4086 +6397 +6984 +4204 +6899 +682 +6589 +3317 +2944 +3456 +4340 +7424 +9208 +6504 +4409 +1 +145 +1882 +4620 +2634 +4992 +5453 +4481 +3377 +266 +7875 +530 +1235 +7605 +504 +1771 +8489 +345 +7353 +7797 +7174 +5914 +2871 +5721 +6067 +3582 +7653 +5467 +6234 +691 +8758 +2122 +1213 +2908 +1492 +1437 +2187 +1266 +2395 +7278 +8491 +5256 +1554 +8163 +5966 +7128 +7904 +1691 +6272 +1264 +3996 +1706 +1334 +1316 +6478 +6935 +1518 +6700 +8703 +8744 +8152 +8778 +5367 +4218 +9007 +6312 +606 +7565 +5293 +2891 +675 +2125 +2120 +826 +7008 +5705 +7748 +8010 +1498 +5330 +5472 +2215 +7627 +3016 +6588 +1850 +4128 +8569 +6987 +7566 +148 +8151 +8789 +7907 +8596 +715 +6018 +9060 +3872 +1750 +5889 +4047 +5960 +3120 +3449 +1421 +1102 +3333 +9197 +8796 +8123 +8007 +2028 +8404 +1945 +1985 +8109 +5380 +8438 +3504 +6739 +4180 +5835 +4243 +25 +4002 +1976 +3482 +8392 +158 +5181 +4885 +8985 +11 +6872 +6425 +5926 +7062 +5083 +8394 +4259 +5844 +1990 +3942 +5532 +2220 +28 +5957 +149 +6748 +1663 +3559 +7647 +2566 +1359 +8787 +5259 +7010 +554 +8231 +4229 +6005 +8172 +8125 +1350 +3571 +9051 +1973 +1386 +1781 +5788 +159 +7007 +3220 +1846 +3093 +4445 +2056 +8370 +3211 +1113 +4384 +2231 +273 +4276 +642 +7663 +5311 +265 +226 +9012 +7879 +118 +7109 +7251 +1760 +8667 +2876 +7162 +3552 +6901 +6779 +5021 +6524 +4957 +3114 +4544 +441 +1848 +2136 +2458 +8662 +1127 +5541 +3026 +1080 +6780 +2224 +8259 +1073 +9000 +7244 +7977 +500 +4435 +7376 +7979 +1435 +9291 +7704 +3791 +3521 +210 +7388 +1039 +6269 +4052 +8570 +3285 +564 +8039 +3546 +6203 +1183 +6107 +4147 +6216 +2234 +7185 +3192 +7155 +2001 +7777 +876 +944 +908 +7791 +5465 +6784 +65 +9172 +5675 +7075 +3886 +7891 +2978 +1008 +5630 +591 +5067 +1139 +577 +9015 +574 +8137 +7786 +5765 +4900 +4090 +7842 +5741 diff --git a/Stark/lib/train/data_specs/got10k_train_split.txt b/Stark/lib/train/data_specs/got10k_train_split.txt new file mode 100755 index 0000000..7dde8f7 --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_train_split.txt @@ -0,0 +1,7934 @@ +3784 +8998 +3906 +1631 +8277 +8358 +2338 +7938 +2988 +8302 +2662 +2663 +2825 +7447 +4781 +2218 +6348 +5860 +4517 +2819 +8075 +5391 +116 +3606 +7976 +7941 +1024 +4519 +1970 +557 +8579 +6908 +993 +7204 +1991 +3674 +8781 +6840 +5 +3225 +3763 +8688 +6778 +5777 +4794 +2744 +8126 +3864 +1733 +2923 +6829 +701 +683 +2081 +1831 +2404 +1459 +2741 +5972 +3618 +7462 +2654 +103 +2174 +6224 +2989 +2506 +2766 +5912 +2699 +3295 +3986 +609 +4895 +6673 +801 +1098 +1602 +2490 +3129 +8476 +3186 +7355 +4784 +4270 +1812 +4226 +2267 +8873 +6544 +6112 +2381 +4752 +753 +3776 +6511 +6016 +731 +2559 +7369 +5866 +563 +7731 +1105 +5603 +50 +4238 +2208 +8725 +4994 +4719 +1444 +8807 +7298 +8139 +8760 +8173 +2332 +4131 +5207 +1065 +8562 +3992 +4024 +2188 +9095 +6765 +1707 +6105 +6922 +5362 +1486 +7898 +4135 +6574 +1551 +998 +6565 +8127 +8927 +2544 +4365 +510 +768 +3535 +3875 +6808 +2931 +487 +1088 +4451 +368 +2470 +8111 +3493 +7338 +8281 +6390 +1271 +4373 +3667 +3494 +3757 +2966 +3756 +7840 +6315 +7827 +3300 +6261 +4163 +2217 +6549 +94 +7236 +9136 +1857 +6691 +3470 +6271 +807 +516 +9311 +6098 +3144 +8420 +5425 +5694 +2643 +6696 +6072 +7285 +3781 +903 +8522 +6092 +5979 +2622 +2529 +855 +3420 +3261 +8953 +7866 +2492 +3157 +359 +1520 +2642 +7452 +759 +36 +8931 +1744 +4350 +1089 +9199 +4295 +1889 +1908 +4868 +4498 +1968 +9103 +3273 +8723 +7413 +4114 +5584 +4874 +1427 +5211 +7618 +1542 +1353 +8158 +4168 +3200 +6345 +8560 +5619 +5953 +3158 +8849 +5831 +1411 +7294 +8103 +6539 +7397 +1006 +5450 +3119 +4274 +5352 +4571 +2319 +4217 +4976 +902 +1814 +2651 +3299 +3398 +982 +2428 +5793 +1346 +7057 +3737 +7329 +4449 +2110 +7405 +1773 +958 +3901 +4127 +8234 +2994 +7066 +1289 +2995 +5871 +3556 +9085 +846 +2366 +585 +7032 +5516 +5230 +3481 +2732 +6658 +7423 +1855 +6384 +3554 +5823 +4948 +7058 +4667 +5377 +2503 +7694 +9191 +9144 +655 +3409 +62 +8019 +8970 +5523 +7403 +3379 +2323 +4833 +5750 +3178 +6548 +8891 +7501 +3280 +7404 +343 +2171 +8397 +1367 +8611 +6118 +6603 +3729 +7182 +9048 +7733 +5642 +7141 +3335 +4845 +5449 +3467 +6250 +163 +5168 +2040 +5339 +3609 +8352 +3426 +8567 +769 +187 +6151 +6437 +7028 +8507 +3970 +9146 +2068 +5028 +7492 +1661 +2815 +2469 +2563 +3814 +8430 +4305 +3479 +5678 +9115 +4132 +1211 +5459 +4814 +545 +4556 +238 +4296 +2724 +1260 +2581 +6087 +4632 +4313 +380 +1209 +5447 +3032 +7942 +8943 +806 +2432 +6130 +4314 +2131 +9045 +6531 +5706 +6747 +7724 +2017 +3292 +5469 +2743 +424 +4233 +7643 +8619 +5192 +4516 +9324 +3537 +9152 +8058 +7526 +8711 +1949 +5982 +1732 +6702 +7027 +6388 +7012 +328 +2130 +452 +306 +7669 +3134 +5761 +3703 +44 +4189 +695 +7672 +5224 +9215 +5644 +3143 +3704 +5443 +2348 +7177 +2328 +4725 +354 +1418 +7810 +7746 +9002 +5759 +7226 +4535 +9160 +4385 +5397 +7249 +2936 +3204 +6287 +385 +2371 +2738 +3636 +9033 +2246 +2680 +6940 +4310 +2054 +9250 +9080 +4568 +5586 +4469 +2038 +3410 +7900 +4332 +6108 +678 +3319 +9079 +1054 +4048 +4751 +1320 +6890 +7931 +1398 +4349 +5299 +5025 +7932 +5738 +7787 +4590 +4020 +1274 +2488 +8497 +3372 +8965 +3219 +799 +3664 +6500 +7093 +4362 +6205 +4244 +4652 +1964 +5945 +6434 +2031 +2684 +6632 +4588 +8271 +3232 +5782 +2904 +6789 +5636 +7200 +3632 +5435 +8203 +3480 +4786 +7579 +3351 +1921 +798 +3646 +3094 +4359 +1654 +5975 +376 +5965 +780 +7821 +9224 +6738 +3185 +2133 +6248 +5996 +2834 +531 +5688 +2448 +7925 +7974 +5924 +6401 +5778 +6594 +5442 +8336 +4522 +3770 +6340 +6328 +4946 +4161 +2954 +2588 +8465 +2885 +1606 +5787 +3407 +3121 +7310 +1413 +1932 +4787 +2579 +3325 +508 +5610 +6480 +4290 +479 +3792 +6628 +2545 +6717 +6972 +2665 +6730 +3547 +6845 +5929 +3540 +4356 +8993 +1052 +2235 +8356 +3403 +8818 +8260 +572 +4159 +1180 +5348 +941 +7948 +2676 +3539 +4866 +6422 +8365 +3217 +1310 +2059 +9177 +1419 +2283 +8892 +8162 +1212 +6277 +3725 +7806 +6149 +7874 +718 +6888 +7118 +277 +656 +8763 +8289 +4759 +5854 +8659 +7710 +3145 +5981 +1881 +5799 +6947 +1609 +6396 +2631 +2887 +318 +2550 +6132 +1736 +2907 +7816 +48 +4304 +8133 +6698 +2760 +7779 +7732 +7642 +1154 +7242 +711 +9262 +539 +8033 +7440 +1913 +5480 +5570 +8594 +8772 +4654 +8974 +6128 +6183 +1071 +8449 +2142 +2298 +524 +1695 +820 +4053 +8241 +1856 +8641 +3981 +217 +1063 +9286 +3152 +221 +5461 +1270 +2006 +7164 +1199 +6951 +5604 +5400 +5309 +3498 +6407 +6661 +7097 +8165 +5169 +3852 +7070 +5702 +4344 +6648 +6904 +3272 +7119 +5795 +2365 +2659 +353 +5444 +6968 +2755 +1924 +2098 +2972 +6006 +5865 +8740 +2418 +3401 +7856 +5841 +598 +836 +1147 +931 +8897 +0 +6049 +1837 +865 +1871 +6116 +6831 +5773 +3587 +303 +1883 +2163 +3070 +1308 +7953 +6300 +6909 +853 +7301 +3279 +123 +7186 +3194 +5553 +5133 +1931 +4622 +6075 +4891 +5722 +5693 +8 +2339 +6596 +71 +379 +4506 +4370 +1238 +2707 +3344 +4254 +8767 +1726 +325 +4148 +5438 +5357 +548 +1332 +6824 +2290 +2335 +3146 +2594 +2315 +3389 +3885 +2621 +4116 +5389 +7412 +7222 +4894 +8595 +2000 +4978 +4721 +6444 +3796 +9321 +2236 +6409 +1523 +1468 +9249 +8270 +2341 +2874 +174 +4757 +4502 +4703 +9034 +9108 +5451 +2619 +5022 +9158 +490 +6540 +1466 +2962 +8771 +3036 +2712 +4539 +1581 +5638 +9246 +4308 +4363 +4647 +4470 +1636 +2511 +1311 +6560 +7519 +8027 +9217 +6464 +6364 +3779 +4822 +3563 +3982 +5896 +5510 +6655 +1524 +2846 +3137 +621 +141 +1887 +6567 +8921 +4671 +6052 +8445 +8699 +7349 +3553 +2117 +7651 +5034 +5383 +649 +3818 +9022 +8414 +1012 +8159 +5081 +8571 +4765 +9135 +4361 +4073 +9142 +727 +2835 +8229 +3989 +4490 +4923 +5477 +1638 +3643 +712 +9044 +2230 +499 +7166 +96 +3172 +8431 +8401 +1470 +6356 +8817 +927 +4212 +2152 +1795 +3812 +4949 +1219 +1538 +3029 +6481 +9042 +7775 +7742 +423 +2085 +7715 +4541 +9061 +5916 +3950 +7420 +4878 +7406 +7046 +7808 +4911 +8804 +6927 +8820 +3264 +300 +8670 +2979 +252 +4407 +3383 +4688 +8504 +6723 +26 +3837 +2489 +4137 +8209 +229 +6490 +2364 +9016 +1763 +1728 +338 +8335 +9063 +5280 +2791 +641 +5454 +4581 +5420 +4548 +2840 +8508 +3463 +7231 +7619 +2560 +1755 +6201 +165 +1471 +6279 +5806 +6867 +5890 +2396 +3416 +1981 +6073 +5872 +3045 +4182 +7607 +3318 +4414 +2998 +6553 +7139 +5624 +2123 +3666 +723 +5110 +6932 +8200 +2222 +8399 +1041 +4138 +1594 +3569 +9253 +393 +7940 +8004 +1475 +6759 +5393 +1107 +2597 +878 +9309 +7576 +5250 +1759 +3142 +2015 +571 +3921 +1255 +7080 +893 +2160 +1355 +82 +1562 +9153 +8583 +4085 +4644 +7196 +9165 +3558 +4550 +6374 +7826 +8602 +4146 +9257 +6083 +874 +8383 +3731 +3374 +3653 +8222 +7344 +470 +1813 +4478 +6871 +7245 +6866 +3998 +7433 +276 +1915 +1988 +8168 +2518 +2686 +831 +6143 +5205 +8718 +1703 +7729 +2077 +7983 +8450 +1195 +9232 +507 +7989 +6974 +4054 +5828 +8655 +6679 +5245 +7783 +5886 +9098 +6491 +8782 +3525 +6542 +131 +8110 +9186 +9074 +4933 +9035 +2607 +4 +2057 +6273 +2711 +5829 +3382 +2696 +3043 +2048 +619 +2499 +5295 +1162 +7807 +3694 +2194 +3149 +1940 +7934 +840 +3592 +8237 +4731 +1324 +8486 +8726 +8573 +2928 +9078 +2272 +2564 +1370 +5911 +7434 +8026 +407 +7546 +2004 +5849 +3034 +7887 +3425 +1118 +926 +3430 +1544 +5902 +2282 +1124 +2334 +129 +1372 +4842 +6473 +4382 +1028 +415 +8269 +8073 +6910 +2796 +3038 +5735 +5080 +2852 +6306 +8842 +9188 +3637 +1066 +532 +928 +5485 +2838 +6753 +9008 +7984 +2816 +8819 +7103 +5977 +5044 +2064 +2599 +4973 +382 +3249 +6446 +6638 +852 +1724 +3368 +892 +3250 +8258 +7962 +4300 +1616 +167 +8855 +2090 +4424 +879 +5136 +5350 +2635 +7828 +8506 +63 +3004 +3847 +3676 +1184 +1705 +6745 +1263 +5020 +746 +1888 +7036 +1033 +3914 +5433 +3905 +4641 +8909 +228 +4801 +3766 +8085 +643 +6914 +9280 +3013 +5657 +3696 +1590 +2920 +8282 +2403 +416 +911 +3849 +4215 +1120 +5490 +296 +2306 +3140 +3742 +4819 +6153 +6414 +760 +3000 +7498 +7108 +6429 +3031 +5314 +751 +3357 +5808 +7505 +98 +7652 +4027 +6257 +3943 +1799 +8577 +5577 +4969 +9163 +2025 +6061 +4026 +5732 +588 +7017 +1415 +4961 +4940 +7152 +538 +706 +2802 +8983 +3375 +1246 +6593 +5837 +1789 +7939 +4997 +5939 +2411 +6133 +199 +7593 +1702 +5406 +6082 +2359 +2912 +6109 +100 +8149 +5470 +2807 +3384 +6413 +3362 +5621 +6019 +9241 +9268 +7703 +4111 +7967 +5458 +7181 +5492 +1112 +6729 +4577 +106 +8853 +3774 +979 +7082 +4610 +1853 +9003 +9292 +2867 +6262 +2245 +3460 +1557 +767 +4796 +8147 +2658 +5769 +6985 +7065 +421 +7990 +3289 +1540 +9316 +2251 +6896 +5947 +4965 +2652 +4480 +963 +9047 +7168 +7824 +3976 +6210 +7018 +7179 +5016 +7789 +6102 +6828 +7659 +9109 +9071 +8115 +7628 +7110 +16 +7513 +835 +939 +4078 +2351 +2322 +3881 +4945 +560 +6837 +6094 +6475 +7901 +3 +771 +8029 +3135 +8044 +7127 +3741 +5156 +7030 +4906 +113 +3747 +7042 +5232 +5225 +3002 +4747 +6879 +5379 +4886 +7192 +4184 +1896 +1834 +8689 +3665 +2957 +6913 +8009 +4851 +6420 +7987 +828 +3003 +8884 +8815 +3198 +8008 +194 +6251 +3303 +3934 +395 +1285 +4169 +1648 +1347 +3600 +4631 +509 +211 +6230 +7241 +8250 +2219 +2582 +8353 +7790 +7583 +4462 +3904 +9004 +6942 +1704 +5686 +8051 +2981 +5511 +6182 +7088 +1699 +1222 +3455 +6189 +1528 +5197 +6221 +7893 +3283 +2837 +7773 +8766 +2942 +8021 +614 +4102 +7362 +1786 +400 +133 +556 +3127 +5237 +3727 +1440 +3873 +6322 +8448 +6285 +8696 +8800 +4009 +3386 +454 +4847 +5685 +9093 +246 +1314 +5895 +6863 +4302 +4260 +8405 +8417 +7116 +255 +3223 +4737 +7852 +6337 +814 +710 +1094 +6103 +5809 +5882 +6336 +4974 +1499 +2806 +3744 +2664 +2436 +4482 +8665 +8918 +1076 +8676 +5725 +9248 +4755 +1447 +9328 +5500 +78 +2653 +792 +6854 +6093 +6172 +3378 +4492 +5529 +5476 +3846 +1391 +383 +4289 +3883 +2648 +3265 +2525 +5402 +4599 +6870 +6877 +4413 +2464 +8519 +2521 +1839 +5822 +5664 +7257 +5375 +6852 +6764 +5182 +8914 +3015 +8509 +3080 +4562 +8979 +6215 +6643 +8601 +6096 +4812 +5246 +7862 +527 +7849 +6737 +12 +2468 +7961 +275 +27 +5932 +3840 +7341 +4996 +8564 +2154 +3788 +6138 +7831 +4442 +757 +4464 +1170 +2568 +19 +323 +6584 +7675 +3441 +2067 +9027 +2486 +4379 +4744 +1737 +7563 +301 +3907 +4742 +6857 +1221 +9284 +8458 +8236 +2897 +4004 +1526 +5345 +4423 +6246 +8578 +1057 +3711 +4986 +4785 +3997 +7311 +4788 +107 +8387 +2041 +2608 +8628 +5830 +6031 +783 +6817 +3293 +541 +773 +8473 +2501 +7247 +5667 +804 +483 +1639 +696 +6060 +5429 +5762 +1527 +7342 +1329 +6225 +7895 +381 +8030 +8520 +8362 +4734 +3526 +9273 +2039 +4142 +5084 +875 +6905 +8968 +5275 +3052 +650 +7509 +232 +2595 +3631 +1810 +4355 +8315 +8908 +1777 +4834 +3164 +2336 +1543 +6212 +8346 +3024 +3719 +1242 +6265 +8101 +3133 +6150 +6358 +3316 +4089 +1647 +4629 +7117 +2596 +5366 +1225 +6371 +624 +2209 +1428 +1158 +7648 +466 +8765 +802 +153 +4639 +3657 +6482 +9320 +2693 +6591 +3294 +2617 +5052 +6305 +3227 +8784 +7170 +93 +5868 +6716 +1671 +178 +2703 +954 +3254 +2262 +5046 +5743 +8647 +6393 +7706 +6604 +3728 +6978 +7489 +7474 +8754 +2740 +2233 +6038 +1491 +8814 +2080 +2358 +5944 +5653 +1164 +9259 +4518 +7343 +5748 +3897 +923 +5967 +2677 +3503 +1202 +4966 +1836 +1863 +6634 +1962 +9096 +9064 +977 +4049 +1464 +658 +536 +3402 +8064 +1309 +259 +7999 +8122 +910 +224 +6152 +7142 +6070 +7523 +8411 +2408 +6766 +9214 +9312 +8325 +6192 +626 +6025 +6240 +8708 +4630 +6777 +1075 +8906 +408 +9269 +6236 +9067 +2514 +8568 +2324 +156 +3136 +3530 +7878 +7308 +4335 +2065 +3845 +4453 +3356 +1450 +371 +7219 +5171 +201 +8642 +2099 +477 +1603 +8339 +7430 +3061 +235 +8291 +1133 +8474 +7035 +8653 +989 +4569 +9092 +8347 +3102 +1743 +9086 +5140 +7438 +1530 +4342 +2460 +7646 +5047 +5071 +5430 +6944 +610 +2803 +1448 +4696 +6156 +4386 +4248 +4256 +994 +2112 +805 +8011 +8276 +8999 +4956 +1712 +2795 +7553 +6436 +2158 +9083 +3184 +5784 +4428 +612 +5288 +6222 +1365 +5074 +6848 +575 +5213 +2175 +4240 +351 +2086 +2656 +5150 +9255 +8189 +7735 +1261 +1344 +4097 +8674 +2984 +4235 +5998 +6488 +537 +1267 +7486 +7124 +6245 +7955 +7337 +5436 +1194 +8226 +209 +1710 +7906 +4357 +4139 +5679 +2584 +2854 +1004 +8246 +8586 +5087 +1878 +4926 +6637 +3197 +7757 +8249 +4055 +6502 +1248 +990 +3928 +2770 +2751 +1020 +6426 +4190 +6839 +2671 +884 +3871 +9212 +4179 +3394 +10 +5861 +5316 +6869 +2985 +8905 +8559 +4457 +2480 +2313 +4100 +4395 +6835 +7799 +7890 +2785 +5468 +7302 +5862 +1803 +6376 +3171 +8591 +717 +7053 +1655 +4489 +2522 +2921 +8555 +1984 +895 +8949 +1305 +738 +7606 +112 +3042 +1325 +437 +3167 +3340 +511 +3689 +5813 +8982 +69 +4421 +7150 +550 +8829 +8685 +3147 +8956 +3166 +7023 +8633 +3308 +2014 +3573 +3880 +4045 +2069 +6051 +4950 +702 +6664 +8418 +2454 +6181 +4853 +4166 +7022 +7418 +3605 +9181 +7172 +5031 +4589 +7858 +6586 +6351 +8334 +7504 +634 +3759 +1890 +890 +6959 +5085 +4919 +2161 +1191 +256 +3610 +7079 +3427 +4071 +7323 +2982 +7263 +7444 +4251 +5846 +4864 +3649 +4311 +7461 +8120 +4582 +6373 +2805 +4872 +4869 +5493 +5867 +2670 +7099 +30 +8933 +930 +7919 +501 +7261 +5289 +7449 +7772 +3613 +7848 +3196 +474 +205 +841 +2611 +6185 +3088 +409 +7239 +5938 +7871 +1343 +6705 +1027 +5596 +2199 +9113 +5471 +6134 +838 +2345 +8359 +4061 +1474 +3229 +270 +4245 +1979 +5995 +1517 +8652 +4006 +4880 +6137 +4693 +2528 +6996 +2926 +5798 +2477 +2549 +1128 +3341 +6014 +4479 +2861 +4208 +5175 +5174 +5118 +3736 +5463 +1588 +2327 +8380 +7982 +1514 +1058 +4586 +6608 +7985 +3044 +1822 +3628 +6851 +549 +1811 +2184 +2601 +4608 +8922 +2540 +6659 +3859 +307 +3650 +3767 +8167 +505 +4366 +4824 +5520 +461 +1933 +2401 +8106 +2055 +7844 +8544 +8838 +4797 +7419 +6686 +7670 +6039 +5672 +5141 +6543 +206 +5252 +4718 +888 +1601 +3218 +5114 +713 +4022 +4419 +6708 +397 +425 +6612 +5057 +1729 +6573 +4729 +4080 +1034 +2961 +534 +8194 +5598 +9218 +2424 +329 +4154 +1597 +922 +109 +8823 +3578 +9038 +8437 +3307 +128 +8032 +1412 +7333 +8762 +8851 +8865 +3056 +468 +3808 +3064 +8798 +7052 +7767 +9231 +1086 +2162 +6566 +2109 +3439 +6122 +3642 +7696 +8610 +5279 +1808 +8687 +8377 +817 +8714 +6066 +4008 +3640 +6015 +1021 +7601 +4855 +6017 +87 +7071 +2730 +7268 +3614 +6084 +6117 +6924 +9102 +2829 +375 +8724 +2095 +22 +1541 +2970 +633 +139 +451 +4521 +179 +1396 +3876 +5824 +8020 +426 +4982 +4172 +1157 +190 +4859 +1455 +3110 +3323 +9104 +858 +6719 +6428 +4495 +8551 +2141 +3984 +3066 +67 +4299 +5821 +8444 +6581 +6097 +7090 +7781 +8944 +3085 +8606 +2114 +5355 +8901 +1461 +3301 +422 +7000 +4820 +5790 +1379 +7536 +4199 +8736 +8991 +5241 +1698 +1294 +1753 +196 +2987 +8680 +4658 +4144 +8639 +6441 +8255 +8156 +3677 +6385 +6520 +7700 +3760 +6001 +1144 +5478 +7394 +8057 +5018 +4232 +5235 +6844 +3111 +8802 +867 +949 +7843 +573 +2278 +6801 +7629 +2714 +5105 +6946 +2697 +5315 +1571 +8677 +2537 +4374 +3833 +7820 +3750 +2033 +6526 +3884 +8706 +7195 +417 +3603 +3001 +6284 +5873 +5718 +8576 +8457 +3589 +5839 +459 +3626 +6342 +8729 +6933 +607 +6053 +8228 +3773 +1805 +6365 +5142 +6069 +1389 +9026 +570 +4614 +5712 +5533 +9222 +2821 +1897 +819 +766 +4060 +4902 +5905 +6842 +5446 +1277 +4303 +2836 +934 +1014 +7822 +7494 +3466 +665 +1047 +5881 +3328 +4664 +315 +1315 +1462 +8616 +7725 +2756 +5749 +1730 +8184 +4567 +5065 +7499 +8867 +1304 +3669 +9192 +410 +8177 +6710 +1210 +2329 +8443 +3911 +1899 +7686 +3315 +7190 +6180 +3116 +5341 +4394 +8337 +9182 +6969 +5715 +2172 +1742 +2782 +3715 +9195 +7960 +2517 +4890 +8294 +2337 +8014 +3353 +7475 +2193 +4843 +8831 +4200 +4653 +6196 +6957 +3063 +2996 +8959 +8973 +6529 +3457 +5274 +8002 +6823 +6154 +5561 +1780 +9318 +7657 +1758 +6503 +7678 +3274 +1625 +4327 +3236 +8575 +3155 +4707 +4331 +1494 +8756 +3174 +1074 +8116 +8295 +8311 +3048 +3752 +6050 +6483 +8003 +9175 +4674 +1642 +2556 +6166 +7165 +8441 +5413 +3990 +1640 +1778 +7500 +8304 +1395 +4315 +5949 +3364 +242 +5763 +1036 +249 +2430 +7426 +8131 +411 +6267 +2045 +6606 +899 +8065 +9052 +7507 +5779 +5616 +2107 +5408 +2980 +6310 +5776 +4328 +821 +3251 +2354 +7076 +1700 +5313 +6736 +79 +8212 +3959 +5677 +7545 +160 +6790 +6859 +3659 +6770 +1106 +8846 +956 +7472 +2050 +8099 +4795 +8053 +9293 +7037 +1646 +9307 +1069 +5322 +5332 +2708 +8977 +917 +2419 +184 +2105 +1578 +3923 +5780 +1903 +2512 +429 +5582 +493 +4972 +445 +8286 +555 +320 +8300 +322 +617 +3413 +4459 +525 +5631 +6314 +5157 +5300 +8545 +182 +1031 +4429 +2495 +7586 +1534 +3099 +3916 +3738 +1919 +535 +2119 +1299 +177 +1838 +2159 +4099 +8285 +5172 +8540 +6020 +7683 +3073 +3115 +1673 +3087 +3488 +2416 +1894 +5942 +3597 +5834 +2007 +43 +1779 +4174 +2023 +2546 +2429 +9006 +436 +4214 +4536 +3693 +5426 +6767 +5903 +4368 +2170 +5051 +7490 +7882 +2859 +5035 +7835 +5372 +7122 +925 +3253 +6338 +8393 +4093 +5848 +7588 +2683 +8049 +5403 +5894 +8745 +8550 +2941 +3484 +9029 +4461 +8022 +725 +2355 +1619 +3030 +1975 +5623 +2415 +1957 +6141 +9278 +3226 +3062 +5670 +7326 +8759 +8496 +6619 +8187 +8262 +6199 +951 +7183 +668 +2388 +4698 +5681 +8240 +2851 +871 +4988 +9084 +9089 +3162 +1167 +8244 +5227 +6461 +2831 +776 +5010 +5770 +5282 +3574 +5102 +1278 +2281 +5455 +305 +4628 +4663 +9119 +7487 +8746 +4889 +6569 +1175 +102 +2386 +8940 +2479 +5566 +53 +8833 +1918 +8001 +321 +6786 +6861 +4358 +2771 +7467 +975 +4777 +605 +3543 +2600 +7584 +9299 +4530 +6477 +7364 +7328 +183 +4761 +7543 +304 +1196 +4623 +7839 +2139 +5519 +1953 +533 +5989 +7590 +7428 +6346 +6162 +1091 +1946 +6260 +4405 +5676 +8924 +7171 +8409 +1866 +6379 +3411 +2387 +3051 +7398 +154 +1185 +6442 +6004 +1611 +2165 +9018 +8323 +616 +3995 +8952 +1533 +7853 +4194 +213 +789 +4991 +3675 +7456 +5752 +175 +7556 +4195 +907 +2248 +9057 +8467 +4594 +1017 +7968 +880 +7446 +3304 +1666 +4942 +3867 +4802 +9156 +6357 +4621 +887 +6213 +5261 +1336 +521 +8928 +1818 +7864 +4792 +6742 +157 +1593 +823 +7235 +5303 +5633 +1100 +1692 +8047 +5993 +1460 +6714 +1630 +6440 +6307 +3608 +292 +212 +401 +5974 +7107 +8301 +8342 +2720 +4583 +2757 +7315 +833 +4466 +4236 +1282 +5273 +2149 +287 +8484 +2380 +8119 +7167 +737 +5076 +6598 +3596 +5382 +2650 +8980 +3421 +1356 +1954 +7823 +1172 +2226 +1941 +6136 +7274 +2256 +4928 +324 +1407 +4410 +4579 +1061 +7113 +486 +862 +3435 +6956 +2873 +1465 +6113 +8225 +8512 +6806 +272 +6008 +1241 +88 +5662 +3555 +689 +8733 +2812 +7453 +6282 +420 +2471 +4477 +7495 +1445 +594 +6939 +1564 +8704 +8590 +7992 +7374 +5796 +9298 +4213 +5713 +5864 +326 +5513 +402 +464 +608 +1951 +8640 +8180 +3347 +3459 +4162 +2690 +7478 +5856 +5240 +2389 +3022 +602 +5547 +1798 +1345 +9276 +599 +3673 +3277 +1635 +8625 +1567 +5928 +636 +5671 +2896 +3477 +412 +7575 +4201 +685 +4760 +1229 +4275 +8960 +3123 +4471 +5941 +3355 +3999 +7157 +6354 +7741 +6850 +8783 +1943 +6769 +7330 +8721 +8477 +1381 +848 +778 +6408 +2644 +5817 +1441 +1723 +2144 +2776 +2368 +120 +367 +8839 +8749 +5353 +4158 +3148 +9114 +1233 +9228 +8857 +2895 +1286 +200 +6755 +5125 +5857 +1657 +7658 +5097 +5000 +942 +7020 +586 +784 +7078 +6194 +8658 +8957 +9325 +1851 +8911 +4862 +7004 +1186 +8824 +1651 +2999 +561 +7639 +4316 +5086 +3187 +7912 +2624 +9183 +8487 +5089 +8475 +7554 +4031 +6297 +6059 +5329 +115 +2058 +7650 +7634 +7121 +2485 +7805 +2241 +7713 +4352 +2409 +1026 +2745 +4549 +6474 +5124 +5201 +6556 +6617 +9091 +3945 +8402 +5648 +5257 +2192 +4901 +7750 +6131 +6027 +6352 +4625 +1254 +5498 +3720 +8261 +3939 +5576 +3685 +6713 +8472 +991 +8354 +8068 +5655 +5997 +1029 +7506 +6740 +2575 +2990 +4898 +583 +7402 +3290 +5388 +6715 +8235 +5361 +4970 +1363 +3338 +5731 +9014 +5358 +2216 +2856 +635 +1193 +3705 +6334 +7666 +5270 +1384 +6368 +8604 +3564 +1937 +2481 +1341 +721 +2100 +3958 +6551 +3813 +2592 +7980 +5385 +319 +2357 +8761 +8910 +8693 +1204 +489 +4827 +8024 +7832 +6427 +3895 +89 +9068 +8067 +1708 +1111 +8963 +1902 +9251 +5719 +9143 +5537 +9169 +77 +5365 +1840 +485 +4456 +2841 +1169 +3271 +7144 +6886 +9140 +7173 +6003 +1659 +1807 +8371 +2439 +274 +4660 +3448 +6623 +347 +2103 +3400 +2106 +9073 +8169 +3687 +3305 +4416 +8454 +6635 +332 +2433 +2909 +3839 +4063 +1944 +6509 +1296 +7770 +1880 +6610 +4075 +9331 +4484 +302 +418 +4219 +1333 +2350 +6498 +8424 +4694 +4883 +5269 +6580 +5007 +6722 +1669 +8470 +2571 +513 +3810 +7049 +6332 +7363 +3532 +8456 +2097 +297 +8841 +7180 +714 +1587 +5234 +4268 +2320 +7372 +660 +8503 +1668 +8847 +1101 +7275 +3336 +6460 +722 +7782 +3947 +502 +4258 +2132 +1835 +181 +3841 +427 +3446 +2551 +8324 +6963 +4284 +7297 +7577 +3399 +9148 +8213 +5656 +8440 +851 +657 +2446 +4292 +6992 +976 +1108 +2681 +3237 +8582 +377 +5969 +5287 +9209 +8523 +7178 +7833 +6175 +2126 +3023 +5090 +7491 +6640 +6077 +2221 +2780 +1694 +4094 +144 +6161 +3203 +7123 +749 +3625 +3848 +980 +2270 +7819 +3672 +7689 +7203 +2718 +1714 +2884 +3474 +3802 +3851 +4224 +7237 +5415 +7998 +7207 +4106 +9036 +1046 +8731 +5070 +6818 +4592 +6056 +693 +1328 +3309 +5791 +2629 +2736 +202 +388 +7886 +4417 +8786 +8822 +4035 +7718 +8492 +5505 +1192 +4388 +8941 +5019 +7538 +6732 +7296 +6389 +5923 +1405 +3278 +3917 +1688 +8374 +443 +4037 +9099 +5190 +6402 +4177 +9310 +7747 +4348 +7197 +4844 +4998 +5609 +4345 +29 +3332 +8648 +4107 +346 +2577 +3941 +1215 +3782 +8252 +4706 +2675 +3790 +7459 +6164 +7316 +1149 +6687 +582 +3139 +5040 +7645 +3882 +7322 +4034 +1861 +4701 +8757 +3208 +8801 +6349 +8907 +1823 +4528 +4789 +143 +4746 +9234 +3866 +9245 +1911 +1366 +4393 +2061 +859 +1959 +6967 +3138 +7382 +9031 +6237 +845 +80 +6911 +7163 +5229 +4736 +8738 +33 +8543 +357 +3193 +7262 +4448 +6796 +6793 +3321 +7569 +6411 +7692 +7340 +1417 +5847 +3836 +2678 +1188 +8727 +223 +8615 +7417 +5771 +3170 +8061 +2935 +8263 +8257 +6883 +1276 +1239 +812 +6258 +3922 +7525 +8117 +3039 +603 +8554 +7573 +2787 +3445 +5115 +3478 +962 +3961 +6570 +7722 +216 +2797 +5154 +2530 +4904 +2405 +7542 +4021 +3252 +5370 +9302 +236 +4532 +1361 +3373 +1716 +2183 +1583 +3783 +868 +1687 +8925 +1433 +6198 +8208 +6367 +7603 +882 +3469 +1645 +7654 +1176 +4231 +150 +7997 +5456 +7031 +4375 +8840 +5634 +6945 +705 +3442 +4774 +3822 +7148 +1922 +8459 +6249 +8713 +6197 +8599 +6071 +6756 +1634 +950 +5640 +7749 +5920 +6622 +4783 +7837 +7479 +7229 +3919 +1797 +5272 +8945 +4908 +5439 +6903 +5833 +6930 +8197 +9261 +1711 +5483 +6046 +4285 +8852 +7409 +8971 +8278 +7534 +7792 +2444 +7496 +8063 +1665 +248 +3894 +4585 +1982 +66 +6651 +4850 +1240 +7511 +7524 +9258 +2075 +3979 +4714 +7592 +965 +2919 +8239 +1842 +8013 +4750 +2344 +6155 +3468 +31 +2087 +1599 +1573 +5883 +7613 +195 +3749 +644 +2189 +8779 +8743 +9005 +8081 +1040 +7785 +5820 +8830 +5495 +4867 +2710 +3843 +491 +7153 +6217 +1148 +4741 +1761 +5484 +3423 +5474 +6916 +5876 +7252 +1739 +8930 +6647 +5198 +4903 +8488 +7366 +2774 +2726 +2385 +7625 +3179 +2211 +8845 +6600 +399 +6810 +3447 +6684 +4915 +8368 +1867 +2325 +2101 +1335 +7734 +3722 +7437 +3716 +7025 +4000 +6897 +1408 +7154 +5013 +2204 +9233 +4225 +3817 +1877 +9161 +2197 +6991 +3390 +280 +1892 +1612 +7753 +2801 +7246 +7909 +6229 +9314 +8407 +1436 +3879 +6432 +6849 +5326 +5327 +8535 +7910 +7745 +5545 +7916 +207 +1783 +6158 +8517 +7361 +8070 +6430 +119 +6146 +4183 +1083 +7385 +4497 +9133 +1686 +3765 +5099 +595 +8046 +4418 +4043 +2361 +7915 +9149 +1717 +1141 +6375 +1018 +5602 +1262 +7485 +9178 +6629 +3339 +8934 +4648 +7988 +6252 +3440 +864 +5418 +3874 +7280 +6191 +8388 +4323 +6792 +4324 +2232 +7228 +8684 +7813 +6187 +6678 +3177 +3534 +4953 +4402 +7739 +6319 +2414 +8700 +5946 +8238 +4533 +6917 +4167 +4618 +2115 +2268 +3081 +1247 +4001 +8580 +7636 +3101 +2195 +1559 +3714 +2484 +7188 +6028 +7530 +2828 +1977 +3238 +6496 +2340 +110 +3247 +7532 +7541 +924 +1632 +484 +4487 +4439 +6447 +1319 +4944 +6347 +1791 +2285 +8087 +5452 +91 +1166 +162 +5185 +7933 +4743 +1627 +7259 +8620 +8525 +8207 +5845 +9011 +5525 +4269 +4700 +1824 +8186 +8872 +8299 +3957 +8242 +4558 +6439 +2666 +5943 +6958 +8112 +5121 +8806 +6170 +7688 +3486 +2082 +7436 +2778 +1096 +786 +2206 +5170 +1443 +6030 +3312 +9151 +8485 +6404 +8498 +2883 +8961 +2280 +8341 +9137 +4337 +2809 +2445 +809 +8298 +8643 +8316 +4951 +6853 +1572 +3215 +3938 +2249 +6515 +1337 +8328 +7712 +1429 +4117 +5441 +3230 +4152 +7225 +3513 +6953 +1507 +348 +3639 +5739 +2673 +1550 +6301 +1652 +8453 +204 +6833 +8056 +2200 +5217 +1854 +4711 +7368 +4572 +4032 +7531 +1013 +3634 +2875 +6058 +8307 +7609 +1766 +904 +667 +5410 +6578 +3601 +1664 +3233 +7390 +8178 +4486 +4952 +4427 +4876 +9166 +3107 +2772 +6295 +5001 +5296 +3371 +6518 +6327 +854 +1615 +8288 +1912 +5927 +6202 +5814 +9032 +1059 +3214 +6547 +7038 +5781 +6926 +4390 +6114 +1622 +4318 +5803 +5984 +736 +3561 +6554 +5045 +4277 +7386 +9081 +8462 +2034 +4955 +2701 +932 +1298 +7758 +7176 +9205 +2276 +3077 +3803 +3562 +8054 +7946 +295 +1843 +7728 +1629 +7768 +3663 +6363 +2971 +431 +9285 +2513 +1116 +3656 +4529 +6366 +5758 +6339 +8398 +816 +4153 +648 +2536 +1826 +7870 +8113 +7730 +7101 +6555 +9256 +6774 +1072 +4578 +2598 +3604 +5880 +861 +8273 +3350 +3117 +4685 +9219 +4334 +5165 +2035 +7224 +4066 +4253 +4447 +3815 +5038 +253 +3658 +2252 +330 +3967 +6443 +2143 +7336 +6135 +593 +2734 +8390 +4655 +7800 +1399 +1173 +5618 +2822 +7905 +7503 +4431 +2443 +1568 +3909 +1974 +2496 +4772 +5164 +4105 +2138 +2864 +3799 +3924 +4882 +8245 +1585 +5528 +5692 +5730 +5832 +137 +3175 +2894 +2062 +3899 +2752 +4028 +2113 +5411 +293 +2647 +730 +3758 +1667 +8879 +9303 +6653 +3698 +3968 +3053 +503 +2150 +4645 +2257 +4627 +8303 +7966 +8742 +4692 +5901 +8547 +2277 +5546 +986 +370 +4697 +8712 +4804 +4881 +1182 +6650 +7290 +3487 +2814 +5668 +7567 +5333 +3724 +4164 +3084 +8896 +3888 +6537 +17 +6882 +3531 +704 +1037 +8866 +5263 +6758 +3762 +1393 +3824 +5575 +5112 +214 +1439 +5700 +8932 +1306 +5011 +6928 +5173 +4098 +1132 +7352 +4778 +7723 +1368 +2390 +670 +2685 +5855 +1772 +6380 +3853 +940 +5424 +6091 +1748 +6193 +5297 +6572 +8877 +6874 +430 +5041 +5267 +1145 +7448 +620 +9112 +4294 +1432 +72 +130 +2393 +7920 +4597 +6614 +8889 +3697 +1895 +3462 +2616 +3978 +4791 +7846 +7780 +8372 +428 +6559 +8326 +9211 +2363 +1525 +5980 +7888 +3331 +8118 +7899 +615 +7377 +791 +5930 +6627 +8322 +1138 +770 +8460 +5100 +8274 +8350 +6316 +2893 +7594 +9236 +5082 +8150 +1986 +1909 +8902 +2145 +3617 +3501 +7 +2426 +5056 +8016 +2702 +5360 +8135 +8385 +8378 +8018 +8574 +720 +8893 +3021 +1978 +4782 +1816 +2083 +4051 +1446 +5870 +971 +9097 +8006 +4222 +8287 +686 +1377 +611 +8153 +4920 +4808 +1536 +679 +4096 +3891 +4884 +432 +4615 +8988 +5560 +3451 +5589 +3514 +6169 +1414 +3244 +1490 +7100 +3588 +690 +7317 +4171 +2266 +6800 +108 +2793 +5151 +6977 +2587 +8188 +8752 +6318 +5815 +5116 +263 +3311 +5191 +5689 +289 +3392 +5755 +1022 +5548 +9319 +8937 +6011 +7632 +5328 +4993 +4141 +5407 +1865 +520 +7305 +7208 +526 +3645 +1859 +2520 +3523 +8629 +7304 +8881 +3076 +4005 +8329 +2205 +2214 +6925 +8691 +4136 +8883 +974 +7873 +7952 +3965 +5887 +7964 +7189 +2406 +2783 +8086 +405 +6568 +5147 +2021 +4727 +4826 +7674 +1600 +5078 +2949 +6624 +6541 +8986 +5740 +4679 +8500 +3591 +4434 +398 +983 +7544 +1478 +4570 +6012 +465 +9330 +7206 +808 +8737 +2356 +4959 +8812 +6955 +3599 +2168 +1420 +1721 +1794 +5897 +8422 +2 +4023 +2739 +3619 +8797 +5496 +8951 +8181 +6893 +9254 +1809 +5682 +4309 +6929 +2742 +5988 +3363 +4493 +8434 +4210 +1503 +1876 +5094 +4600 +4936 +4798 +3933 +5216 +646 +7660 +3098 +8773 +4076 +1576 +5335 +3746 +3327 +47 +4602 +8636 +4129 +363 +6417 +7416 +9025 +4377 +4766 +2779 +4151 +9046 +7860 +3154 +3476 +7620 +966 +2052 +8344 +1752 +7199 +4412 +8895 +8882 +2463 +339 +56 +5390 +4821 +7555 +6558 +1905 +5258 +8880 +4205 +3580 +6735 +1023 +4511 +3850 +161 +7395 +2532 +3349 +7055 +7387 +758 +1907 +872 +3006 +659 +815 +1961 +6902 +7668 +4708 +1904 +4433 +5159 +6816 +8664 +6918 +1016 +6513 +7314 +5364 +7480 +9313 +716 +3395 +6843 +2292 +918 +4329 +1035 +6344 +8593 +3404 +5212 +837 +480 +8524 +1342 +3690 +6797 +7414 +288 +8863 +3352 +1628 +24 +135 +3314 +2181 +8650 +5915 +8078 +6812 +1375 +6040 +906 +5635 +7126 +1387 +7458 +6119 +5591 +3795 +1531 +95 +1960 +7522 +3033 +898 +4607 +4921 +3913 +2623 +4430 +6268 +7063 +1326 +9075 +2505 +7400 +1284 +2951 +747 +6466 +1357 +6493 +7320 +5892 +576 +5107 +5559 +97 +2583 +6361 +8843 +3509 +7892 +6086 +1476 +4612 +7427 +4267 +9094 +7050 +6048 +8455 +8382 +2227 +284 +2898 +3221 +2353 +2157 +5990 +5810 +3581 +7279 +6188 +7859 +3549 +5539 +7918 +2022 +9066 +630 +2500 +5111 +6561 +5127 +8095 +5569 +6123 +1338 +8605 +3491 +4187 +8220 +7334 +9213 +3067 +6997 +2853 +4735 +4372 +1489 +5954 +6662 +2207 +973 +3361 +960 +6350 +4170 +7431 +8076 +1129 +750 +7559 +7194 +2261 +2300 +6590 +5893 +6889 +3125 +8788 +334 +7286 +3472 +8164 +7693 +1469 +1181 +669 +7515 +5563 +4773 +3210 +6324 +3113 +9070 +3638 +7551 +2541 +3506 +5138 +4069 +7198 +7560 +3306 +6100 +2932 +4473 +1741 +14 +4672 +7564 +8748 +8874 +3804 +3678 +2240 +2610 +2862 +1358 +5716 +42 +5176 +9326 +8464 +1038 +2993 +3017 +9072 +32 +4809 +4364 +2808 +4125 +448 +152 +7299 +5431 +6178 +793 +3444 +9120 +8410 +4963 +772 +5457 +6954 +3014 +6881 +286 +553 +1948 +6398 +6255 +3057 +8646 +6176 +2700 +7106 +5663 +6683 +1281 +6013 +8799 +7635 +9289 +1885 +442 +2225 +6294 +5054 +2674 +7884 +8730 +8216 +4203 +1488 +7111 +4013 +3623 +7950 +1971 +1966 +3248 +2900 +1553 +472 +3865 +7796 +6937 +4591 +8098 +5208 +294 +5627 +5691 +5687 +7149 +4879 +3624 +7005 +2773 +3112 +9185 +1633 +7830 +5101 +8707 +8469 +4678 +4860 +700 +5527 +9194 +2794 +5068 +2639 +1177 +4282 +6492 +8128 +5859 +5029 +5123 +2877 +522 +5048 +7230 +2104 +6642 +6731 +2717 +5149 +2043 +9059 +5277 +844 +1394 +3262 +5515 +6706 +3651 +9105 +7671 +2880 +3607 +6410 +2508 +8463 +2394 +1916 +1125 +5343 +3322 +5307 +4547 +1589 +8478 +8899 +2955 +8028 +7293 +4619 +4058 +2781 +8715 +1272 +5734 +4474 +4863 +4367 +49 +8844 +5605 +8671 +6743 +4281 +7077 +1874 +2626 +2516 +258 +5249 +6186 +7958 +5432 +3801 +6288 +4732 +9121 +7558 +2527 +4661 +6819 +3835 +7508 +584 +215 +5036 +4261 +8978 +5228 +647 +4657 +2591 +5931 +5088 +9204 +929 +4381 +5421 +2965 +5050 +6495 +5033 +4799 +959 +6115 +3520 +1232 +5811 +317 +8976 +7705 +3842 +2178 +7187 +1373 +7112 +2694 +8627 +8493 +3991 +7441 +6308 +2589 +6462 +3406 +7673 +8660 +2902 +752 +1025 +849 +7682 +6982 +6652 +3612 +298 +5148 +4873 +3414 +1693 +1458 +327 +2016 +5002 +6768 +7016 +5583 +3270 +857 +8232 +7158 +7981 +4676 +4675 +2164 +8360 +6709 +8143 +365 +4062 +4527 +7928 +9009 +6228 +5818 +2533 +9305 +8887 +55 +2507 +8870 +6649 +5158 +76 +5595 +6693 +5306 +8666 +3020 +7527 +3082 +6304 +1591 +6145 +6868 +7205 +9107 +1165 +6773 +172 +1993 +4176 +8400 +4611 +7589 +8702 +5386 +6095 +6335 +1561 +8805 +5963 +7393 +3681 +2037 +4968 +7451 +3360 +7466 +8361 +4455 +4064 +5422 +1689 +3977 +7269 +362 +4178 +4145 +6127 +5162 +2399 +9225 +7068 +1650 +794 +3007 +1348 +7736 +444 +6081 +5298 +2026 +2543 +9087 +3593 +7425 +3730 +8468 +2641 +7529 +1720 +6377 +8732 +5851 +7956 +3150 +3785 +6485 +3611 +2869 +8510 +4775 +4463 +1251 +9124 +6873 +3391 +6505 +4118 +1617 +8837 +7051 +3213 +3668 +5347 +8452 +6289 +5840 +478 +3522 +453 +3376 +6190 +3342 +2237 +2870 +5178 +5567 +5952 +6919 +3005 +134 +3397 +7443 +8539 +6822 +5264 +3288 +5962 +8421 +6744 +8608 +4656 +1802 +2073 +4271 +1043 +2922 +8211 +2196 +5260 +3789 +7211 +7571 +7834 +5680 +2047 +5502 +3369 +3437 +3286 +5517 +3912 +8386 +1442 +6961 +2191 +2417 +9088 +5155 +6813 +4520 +7375 +1224 +811 +1891 +3748 +4123 +2789 +5305 +8419 +7248 +9237 +992 +4038 +4499 +2060 +5538 +850 +2669 +7612 +104 +9290 +2526 +1287 +4160 +4633 +7125 +742 +744 +4534 +2407 +7714 +4555 +8764 +7661 +4722 +7721 +3205 +6657 +1214 +3754 +6080 +4593 +3018 +8792 +2294 +4450 +7701 +9301 +127 +7069 +4513 +6243 +8025 +4010 +8632 +4715 +5284 +4574 +726 +4252 +4561 +7354 +299 +6088 +1090 +5012 +5684 +3489 +5639 +4888 +1584 +1969 +4846 +2915 +6804 +2775 +7306 +6506 +9306 +5231 +7740 +4283 +953 +6725 +458 +8290 +1504 +1539 +8885 +138 +3764 +1256 +257 +335 +1011 +7060 +5986 +9323 +4740 +8994 +4140 +6807 +8254 +3963 +9297 +2102 +2964 +9207 +4910 +8709 +4411 +1672 +457 +5852 +8037 +4932 +3679 +8794 +2362 +8592 +495 +8432 +1608 +2155 +7411 +2881 +9244 +37 +6535 +8219 +4505 +8635 +1928 +8384 +2570 +8996 +7610 +2128 +8728 +6656 +8935 +6681 +2070 +176 +9062 +972 +514 +1796 +4039 +6838 +2462 +230 +569 +5521 +4637 +4939 +4420 +2863 +672 +4995 +3807 +447 +1656 +2005 +5113 +3297 +8858 +2118 +6309 +1926 +481 +1156 +1509 +1228 +1787 +5978 +8678 +3951 +2929 +4980 +5039 +4713 +7002 +151 +5536 +8148 +3823 +4709 +2299 +142 +7067 +2372 +3761 +9 +2265 +5747 +2764 +724 +2913 +3151 +4525 +6370 +4247 +9329 +5494 +3721 +629 +3621 +7371 +59 +1999 +6704 +3734 +2698 +4691 +6938 +9117 +8415 +6353 +6750 +9077 +2679 +7623 +2478 +7321 +6611 +4007 +2076 +5772 +6416 +2264 +8348 +2672 +6546 +754 +6934 +7908 +8546 +4404 +592 +4748 +6625 +2129 +7944 +2377 +6 +8929 +8275 +3515 +4524 +3660 +8710 +419 +6878 +170 +8313 +7460 +8753 +2917 +6891 +6663 +4918 +7129 +396 +7256 +3500 +631 +5585 +8343 +2695 +6168 +6292 +3176 +5092 +5160 +3701 +9021 +7221 +7825 +1216 +1438 +3471 +2318 +8923 +6223 +2182 +7621 +8514 +9010 +8987 +1252 +1972 +1872 +1715 +8205 +6463 +8138 +8989 +5661 +2890 +565 +2427 +8946 +1303 +3718 +6000 +3620 +1560 +5276 +8089 +9260 +1467 +6173 +7641 +7520 +5061 +4677 +5757 +4400 +2620 +2719 +8995 +2079 +6644 +1683 +8141 +7754 +5744 +2952 +7568 +654 +7457 +5368 +3310 +1510 +4440 +1513 +3072 +8034 +1456 +9164 +3163 +3035 +6111 +5042 +7161 +1401 +1084 +8000 +6672 +8531 +5404 +6550 +8379 +9141 +8681 +7752 +6394 +7011 +3739 +8253 +978 +4771 +6024 +4828 +7959 +1649 +1727 +7073 +8349 +6952 +661 +7283 +3159 +2590 +3496 +8741 +3969 +2956 +4565 +920 +1830 +8558 +1930 +6677 +6825 +8256 +7454 +7521 +4710 +1768 +3753 +6459 +5606 +5292 +1397 +240 +2733 +946 +6711 +3242 +2627 +4929 +5006 +3202 +132 +2295 +2746 +1293 +2124 +5405 +4065 +818 +7464 +1820 +4398 +1312 +6994 +6920 +261 +987 +6120 +3109 +331 +2986 +4338 +7774 +5122 +8396 +1364 +8969 +6712 +8161 +7083 +7595 +5940 +1566 +6419 +8634 +4432 +6047 +4749 +6076 +1161 +8217 +674 +8494 +3688 +2447 +4704 +969 +7477 +1160 +3243 +3173 +4979 +9288 +6860 +1662 +6171 +225 +5143 +313 +8327 +3275 +3385 +7626 +3103 +4401 +6794 +5600 +5043 +7664 +933 +6830 +4452 +3980 +1604 +5875 +6633 +4635 +5756 +3329 +1751 +8108 +4817 +1989 +1237 +1893 +2848 +9334 +51 +8875 +4981 +5417 +4134 +877 +6688 +3545 +4943 +5615 +2476 +1684 +3652 +7396 +1769 +1171 +6563 +3415 +3644 +340 +6630 +8284 +3256 +7240 +5371 +3405 +2108 +6360 +1734 +5612 +8638 +2343 +1103 +7803 +6809 +3055 +188 +8031 +3124 +3683 +4537 +988 +2297 +4893 +6499 +3396 +839 +4467 +5195 +4041 +6457 +4441 +6378 +6472 +6195 +4912 +6884 +5922 +7014 +1660 +38 +1595 +6752 +4554 +1292 +2709 +3800 +6057 +1980 +8775 +6587 +6392 +6263 +7214 +5219 +282 +309 +6685 +2253 +6311 +4092 +18 +7570 +5543 +4081 +2515 +6278 +8690 +5294 +6184 +5215 +9130 +6720 +250 +7250 +4983 +639 +3567 +7841 +2636 +4067 +8446 +5703 +8609 +2586 +7695 +1253 +6701 +7930 +6317 +5921 +7719 +8501 +7312 +4110 +6219 +4552 +5059 +4088 +7975 +9132 +6054 +692 +3412 +4079 +6754 +6950 +5281 +3028 +8321 +3877 +7614 +8939 +4188 +2223 +239 +4745 +6875 +7096 +5571 +4403 +2640 +5556 +1845 +6690 +1825 +4157 +314 +4682 +8825 +1003 +6206 +8093 +7215 +6465 +99 +8077 +6631 +4206 +2523 +366 +1208 +6043 +4640 +1457 +5475 +4985 +1351 +3090 +5625 +7307 +8466 +2003 +8854 +218 +1500 +4476 +2293 +1847 +5032 +2147 +866 +3710 +2552 +1749 +6692 +3926 +4112 +6458 +735 +9171 +60 +9304 +6726 +2630 +2882 +1178 +1151 +4922 +4662 +173 +7233 +1776 +6533 +4113 +2423 +2425 +4343 +5800 +970 +6372 +1009 +6607 +3068 +8435 +6423 +3126 +4813 +1709 +1201 +7104 +5620 +3932 +5701 +5724 +3366 +8050 +4984 +5023 +9203 +5079 +627 +290 +779 +5572 +5233 +1392 +4975 +8534 +8210 +2269 +1143 +2475 +2562 +905 +4546 +267 +3536 +8538 +449 +101 +7367 +2722 +4605 +7356 +6781 +8537 +8697 +6820 +8340 +8926 +3821 +2349 +2259 +6545 +8100 +8395 +2258 +2911 +5108 +3946 +1406 +8683 +8296 +5579 +2177 +8264 +1425 +3940 +957 +3647 +515 +5342 +8363 +2449 +3108 +1001 +2937 +3452 +5574 +4319 +9184 +8381 +945 +6876 +600 +5714 +4871 +8532 +1852 +8856 +392 +2018 +8878 +369 +5711 +9230 +5304 +7266 +1681 +7829 +2309 +4683 +8938 +2255 +6159 +3207 +4651 +2029 +4341 +5106 +5794 +9024 +4712 +2434 +7151 +7359 +6431 +1290 +5918 +8705 +3438 +5554 +8876 +7415 +6290 +5373 +3805 +2950 +2331 +6772 +8997 +6576 +2307 +8515 +4033 +3428 +6487 +6595 +45 +5792 +333 +762 +2383 +3388 +666 +2166 +460 +943 +364 +6980 +8223 +8221 +637 +6218 +4108 +5381 +4649 +5096 +1614 +8768 +5095 +3809 +5030 +984 +3538 +5120 +2498 +5222 +5613 +5486 +5119 +241 +5707 +9227 +544 +4109 +7771 +728 +3671 +9327 +1230 +9270 +1070 +8565 +4769 +7056 +5654 +7965 +1793 +5956 +7883 +1362 +5479 +8769 +8821 +8320 +1901 +1994 +2461 +5552 +389 +2839 +6467 +2762 +4763 +3499 +1487 +7599 +4488 +3241 +8272 +1131 +4496 +7006 +7265 +4897 +2747 +6618 +5291 +4563 +5146 +1939 +6369 +8548 +6163 +5526 +4068 +9030 +5349 +8433 +748 +1477 +4265 +9200 +3878 +462 +6846 +9040 +4806 +3519 +6798 +5464 +5179 +546 +6044 +8114 +7216 +6276 +1495 +494 +8146 +5434 +856 +8403 +8071 +3972 +5544 +3337 +6855 +1546 +2824 +1718 +6009 +2042 +251 +9076 +3330 +5004 +192 +4717 +3797 +1146 +394 +7814 +7699 +4659 +4689 +4156 +7903 +9054 +7332 +7811 +1119 +5531 +6782 +5210 +8412 +2633 +7924 +4624 +8314 +5666 +3240 +2310 +4262 +8160 +4553 +8196 +2661 +7213 +7455 +7399 +870 +6126 +1227 +1226 +781 +937 +6343 +2578 +2892 +4124 +2792 +5696 +6865 +6455 +8312 +5193 +6026 +5251 +3787 +4460 +4687 +7923 +1140 +9106 +796 +2482 +9170 +8695 +2749 +6734 +4825 +114 +8319 +827 +4175 +390 +7611 +7484 +1249 +7727 +955 +579 +3629 +8915 +2958 +885 +7227 +1424 +4810 +4604 +1535 +774 +7518 +5428 +1955 +8233 +2645 +2167 +6484 +3855 +1502 +4861 +2333 +2973 +4829 +1906 +3966 +476 +9023 +6960 +3483 +2748 +5891 +8174 +7702 +8948 +5324 +4396 +1605 +2823 +7348 +7347 +5933 +310 +9082 +916 +4255 +203 +4239 +5976 +6200 +6435 +4425 +787 +1121 +6034 +13 +39 +3104 +5961 +5507 +5785 +1463 +7339 +1575 +7801 +5445 +8283 +5951 +6995 +999 +5163 +6023 +3786 +6536 +5850 +3524 +3528 +4508 +6674 +2939 +8227 +4598 +7550 +8495 +8622 +1152 +4538 +4003 +1318 +739 +3296 +8202 +1552 +6204 +5236 +3576 +4699 +9238 +1879 +488 +2274 +433 +5587 +1678 +9282 +7914 +8552 +6445 +7971 +8331 +6880 +7476 +7282 +1570 +7271 +3827 +6489 +8091 +9287 +7351 +1765 +5286 +6921 +542 +1762 +8553 +4987 +894 +3622 +7855 +92 +3131 +4811 +3590 +6517 +4510 +733 +4954 +1360 +5669 +2842 +8107 +5646 +5968 +1618 +1827 +7709 +8521 +5807 +5321 +9239 +5501 +3745 +4437 +1586 +7273 +5265 +6605 +7917 +1607 +6074 +4668 +7061 +1580 +8694 +8461 +4573 +618 +9173 +5243 +435 +8770 +2421 +7450 +3870 +8308 +2605 +2934 +9240 +6887 +4512 +1198 +7585 +7691 +7738 +2843 +8423 +7929 +6971 +7854 +86 +9128 +4298 +622 +790 +9155 +6579 +2203 +7716 +1265 +8645 +3834 +1174 +7380 +623 +8936 +4306 +8082 +4312 +8661 +5753 +7243 +2768 +8155 +85 +4143 +3047 +8479 +7809 +2833 +5555 +7578 +1637 +1936 +8130 +5549 +8062 +7143 +5522 +8966 +5614 +8105 +8719 +7655 +7502 +8268 +5760 +6695 +5565 +7615 +9226 +4870 +4507 +3160 +4835 +1598 +2465 +4422 +5248 +7867 +1078 +5015 +6660 +1676 +5354 +6391 +5351 +7184 +6280 +5936 +6124 +1327 +2906 +269 +8292 +2466 +8809 +5167 +8142 +8204 +2713 +1910 +2930 +2494 +5592 +7384 +7726 +5727 +625 +1735 +5710 +5518 +2491 +1410 +4989 +5183 +8777 +6562 +4947 +3692 +6129 +384 +1097 +2084 +5209 +3723 +7272 +6895 +2459 +543 +8621 +5394 +6211 +2074 +1511 +2524 +7776 +5055 +7191 +6207 +7922 +281 +8436 +2918 +3141 +4800 +6323 +7631 +8903 +2716 +3735 +3012 +5301 +3975 +2800 +7963 +105 +1920 +7391 +4909 +1754 +4816 +5488 +5145 +5098 +5139 +5268 +9317 +8631 +4346 +7318 +136 +3993 +1220 +2151 +308 +7483 +7582 +3071 +1339 +3777 +8191 +5378 +7087 +1056 +7465 +5608 +6564 +512 +2754 +2687 +1596 +5376 +1512 +566 +6382 +7360 +1757 +8035 +2296 +4264 +3551 +1053 +4716 +1537 +8518 +254 +6253 +7132 +8557 +3490 +9267 +5473 +2412 +7539 +7136 +6670 +3974 +891 +1323 +5958 +1217 +2879 +9118 +1259 +2317 +7033 +2467 +6665 +6244 +2180 +2140 +7098 +5126 +6395 +4150 +547 +4120 +4307 +1725 +2737 +8549 +8195 +1245 +6286 +935 +1756 +1701 +1626 +7379 +3492 +3717 +5802 +2817 +1234 +1005 +4101 +21 +2576 +4650 +3381 +1030 +2844 +1641 +936 +2729 +6469 +8913 +8369 +5994 +341 +81 +4083 +1685 +5152 +3380 +8739 +6615 +3829 +164 +7927 +4779 +829 +4216 +8528 +3641 +4606 +2769 +6970 +1545 +8850 +4971 +5489 +2008 +4564 +8682 +7784 +5768 +9252 +901 +438 +3577 +2765 +5904 +664 +3348 +6298 +3602 +2502 +8617 +7684 +4293 +5166 +5805 +4126 +2451 +6906 +7234 +9243 +3778 +2940 +1087 +9053 +5026 +2504 +5283 +2820 +4242 +797 +3925 +1383 +8750 +7861 +1403 +6973 +7617 +968 +3065 +5395 +4347 +8144 +2688 +6527 +8597 +8673 +7327 +6331 +1422 +7115 +244 +7013 +2092 +54 +7970 +5742 +3464 +4823 +8588 +2938 +3060 +6406 +4149 +2375 +6616 +8803 +1555 +4369 +1380 +3011 +6144 +3367 +4990 +7370 +7131 +1995 +2602 +985 +8785 +8480 +9125 +1927 +3269 +3771 +1032 +7378 +6900 +5726 +2731 +2020 +4503 +3313 +6727 +8793 +2304 +523 +6036 +58 +7993 +5512 +5049 +2721 +8482 +673 +7937 +1168 +4472 +8247 +7287 +9017 +6421 +9190 +3584 +1819 +1792 +2810 +6033 +638 +6749 +7677 +981 +7160 +4726 +1886 +7845 +7911 +6975 +568 +7422 +4613 +4501 +2569 +4263 +3206 +4133 +2420 +3706 +8894 +2263 +5774 +4925 +9180 +8888 +2945 +2091 +1873 +6303 +729 +6728 +2156 +3267 +1860 +6597 +1374 +4930 +5253 +938 +580 +5825 +4839 +166 +8198 +6892 +8701 +74 +7094 +7284 +8954 +3156 +6140 +4279 +5594 +2229 +7535 +5466 +8413 +7105 +8192 +2632 +7638 +9308 +8530 +832 +4643 +2201 +3268 +4322 +6510 +2967 +262 +403 +7973 +1258 +8828 +4036 +5838 +9263 +8529 +2788 +4202 +237 +3838 +1291 +2305 +4056 +5628 +7281 +1430 +6476 +7935 +2850 +6041 +2013 +4016 +4576 +5312 +6827 +6321 +8669 +8439 +830 +1942 +1519 +2750 +6106 +6993 +6235 +5899 +7313 +5331 +4371 +7086 +4399 +8600 +2660 +5409 +3465 +5499 +6231 +5745 +1801 +5337 +4468 +1451 +4192 +1275 +8230 +2302 +1114 +4960 +8860 +3900 +6468 +5058 +1505 +8868 +5588 +3858 +1947 +2565 +1472 +8499 +243 +8442 +6583 +7085 +5374 +2250 +4291 +4426 +492 +2311 +8305 +3662 +5338 +8780 +7488 +3890 +5005 +2442 +4680 +7358 +9116 +4397 +5999 +587 +7902 +83 +3566 +2134 +8942 +4767 +6601 +2456 +1745 +5736 +5254 +8017 +4015 +7690 +3798 +8947 +1067 +2116 +7945 +590 +2547 +2535 +64 +2053 +5359 +2493 +6669 +4351 +6412 +7473 +6147 +7175 +6983 +5196 +745 +2657 +3497 +697 +3161 +7528 +2239 +5991 +3201 +7681 +2440 +5189 +2959 +2044 +8917 +2046 +6313 +6333 +5318 +2763 +4301 +2555 +2213 +2933 +4121 +1340 +3903 +4392 +7889 +5323 +1055 +707 +3857 +518 +6078 +5134 +6645 +9138 +1592 +680 +4446 +7943 +3461 +3887 +5601 +2321 +6621 +558 +4914 +913 +5637 +6453 +8511 +4531 +1218 +5508 +2603 +6802 +8426 +8297 +2947 +5971 +6552 +5262 +5935 +782 +7435 +8357 +6139 +1136 +1473 +5008 +3585 +3627 +2914 +5356 +2997 +2347 +881 +5652 +4849 +8808 +8351 +4017 +2010 +6836 +7616 +4391 +3630 +3712 +6099 +2969 +5238 +4333 +2301 +4406 +1236 +1050 +1864 +1104 +8408 +8251 +8795 +5879 +3365 +7481 +8206 +2452 +1767 +8859 +124 +3948 +4444 +8962 +4438 +5003 +1740 +8428 +3105 +5117 +1095 +1480 +8755 +7881 +3097 +4877 +155 +1917 +2455 +6042 +337 +6724 +6045 +8483 +7135 +2242 +4566 +1679 +834 +1746 +795 +3548 +2314 +2036 +4046 +9129 +6979 +7084 +5091 +2413 +8170 +5775 +1817 +529 +7220 +813 +2916 +5130 +8972 +126 +1243 +2370 +4831 +9122 +3010 +5104 +2613 +6761 +7482 +909 +2146 +4595 +5340 +3512 +6283 +2346 +653 +6121 +2615 +7421 +1869 +1002 +8834 +2991 +8992 +632 +1093 +4543 +645 +2352 +4115 +373 +1483 +6966 +8598 +3896 +3434 +5987 +8318 +1815 +1223 +1548 +6885 +5073 +6330 +2573 +1369 +4095 +1431 +2185 +5766 +1301 +7258 +8048 +7598 +2847 +1996 +2378 +8561 +743 +6381 +271 +1956 +7439 +7596 +7134 +6636 +5804 +1858 +6214 +4730 +8536 +1203 +3118 +9202 +1875 +5885 +8975 +168 +5898 +4014 +4186 +3346 +3041 +5558 +9296 +8157 +4339 +3234 +1738 +2604 +6803 +5387 +5590 +125 +2173 +8012 +8005 +4858 +3069 +651 +372 +378 +8366 +6299 +1449 +7793 +8541 +3235 +8043 +3086 +3983 +6949 +4690 +2176 +6494 +7637 +8406 +3856 +7408 +350 +7021 +8224 +7044 +7662 +6697 +7679 +169 +528 +7029 +2790 +7138 +7432 +7602 +8333 +1582 +1378 +519 +482 +9279 +8015 +6592 +4514 +3542 +2612 +628 +5053 +6699 +6227 +2094 +1621 +847 +3598 +2728 +8490 +7276 +6620 +8345 +9216 +4278 +4059 +9058 +5063 +5816 +4173 +8134 +1997 +3182 +3224 +8129 +5109 +4494 +189 +7640 +8243 +180 +2963 +1123 +5593 +3263 +4185 +7140 +8990 +6320 +9275 +4601 +4854 +5907 +1135 +8083 +5964 +7788 +1992 +8069 +9174 +6160 +35 +8572 +2865 +46 +3952 +6418 +2510 +5783 +20 +3816 +2715 +3930 +2548 +5204 +4122 +4103 +708 +7756 +3825 +777 +3550 +8502 +3929 +5440 +6751 +7764 +4070 +7331 +3743 +9131 +9206 +3828 +23 +41 +4197 +234 +5723 +7622 +8832 +4626 +2169 +5599 +2976 +5266 +1967 +1150 +5334 +90 +822 +2538 +3169 +6771 +7442 +498 +4967 +5580 +7581 +7680 +4728 +1115 +4040 +1064 +3106 +6266 +4415 +9294 +5597 +7059 +197 +7218 +6948 +5690 +4234 +1653 +4485 +4019 +3370 +919 +1330 +6085 +2078 +3768 +5427 +4545 +2435 +8862 +3633 +8145 +5221 +1388 +5913 +8140 +7471 +7156 +6989 +1190 +6832 +2830 +4387 +3454 +7469 +2910 +4526 +5187 +2410 +9223 +6247 +6912 +4681 +1300 +7407 +8612 +6523 +3616 +6894 +7253 +4515 +5874 +5448 +7137 +7957 +1130 +3092 +7054 +3516 +5797 +1000 +2727 +4336 +9090 +6403 +7255 +8919 +6522 +6760 +8898 +4803 +1938 +374 +8686 +9150 +3985 +7045 +3475 +6065 +7991 +1409 +7851 +6671 +6090 +5826 +7857 +1155 +8964 +1117 +7072 +6064 +2497 +4899 +2397 +3189 +2369 +15 +5027 +5754 +8950 +5617 +8391 +914 +6264 +279 +6174 +5184 +3733 +7392 +5278 +2924 +567 +7994 +352 +8084 +2148 +2723 +3359 +70 +1870 +7708 +220 +3994 +9013 +3191 +9220 +4155 +5717 +1110 +2198 +9179 +785 +5325 +4770 +4250 +52 +4634 +5072 +9037 +601 +8036 +7996 +2483 +7232 +8675 +8836 +1279 +5346 +7676 +6104 +1515 +4603 +5607 +7894 +5144 +2628 +68 +440 +3586 +3083 +4830 +4378 +7762 +1134 +4542 +7850 +6296 +2866 +4011 +8751 +4776 +7954 +7102 +5697 +2032 +5729 +5017 +6962 +2051 +1092 +764 +9019 +2759 +8581 +1484 +8618 +912 +2382 +4892 +8447 +8176 +5491 +5695 +5504 +1060 +7064 +709 +578 +4320 +2379 +7649 +8416 +1613 +5344 +7512 +7865 +3037 +6689 +6557 +1569 +5955 +3707 +9168 +8566 +1775 +5950 +6943 +7804 +434 +6179 +9300 +1142 +7947 +6456 +6291 +5789 +6538 +9134 +3049 +5075 +5399 +5161 +1623 +948 +6302 +6063 +7516 +117 +506 +3302 +7146 +355 +3854 +1081 +2827 +1496 +2574 +6167 +3183 +4287 +5482 +1722 +7319 +7277 +3860 +3443 +3298 +8364 +3826 +7254 +2360 +5093 +7039 +6325 +4230 +2567 +6241 +4443 +559 +2625 +4228 +8967 +6405 +1674 +3936 +4475 +8556 +8585 +896 +3713 +6259 +4297 +6718 +2392 +2279 +4927 +1283 +2374 +2860 +7665 +663 +596 +6293 +6805 +2811 +7383 +8306 +8330 +3153 +2153 +2618 +2441 +3615 +8092 +552 +5285 +5255 +8124 +9247 +5530 +8175 +6242 +5660 +3433 +1610 +1832 +3892 +3862 +640 +2127 +2474 +4196 +3495 +7217 +5206 +4836 +7759 +4376 +800 +4227 +3699 +9055 +5665 +6826 +7463 +9065 +4720 +5069 +3245 +3453 +3358 +6532 +5970 +7921 +4087 +1547 +3424 +8040 +7995 +6787 +9069 +8716 +2561 +8199 +1479 +2767 +7818 +7145 +604 +7597 +4896 +9281 +4666 +185 +8171 +7978 +3059 +9196 +9221 +2135 +1800 +2974 +1529 +5948 +446 +4436 +8672 +3508 +6208 +5673 +6998 +5203 +278 +7041 +9110 +5853 +8121 +1764 +3046 +2400 +6575 +4738 +2228 +7761 +9322 +7019 +6931 +6383 +6762 +283 +3935 +2534 +7717 +6785 +471 +8214 +231 +4241 +5310 +3844 +5746 +2011 +7209 +336 +6433 +756 +9167 +6741 +3345 +7685 +4018 +6682 +9147 +4790 +5836 +5906 +8747 +676 +3964 +6362 +3510 +7510 +2308 +1806 +5917 +1189 +4012 +3387 +1331 +5319 +5423 +8900 +147 +3780 +1696 +9111 +6783 +6497 +4104 +1898 +3987 +260 +4616 +2121 +9283 +1400 +2437 +4670 +2735 +1163 +2096 +6521 +1423 +4523 +2243 +6667 +6990 +3944 +6915 +6763 +5611 +404 +2691 +1015 +7092 +7562 +8624 +2291 +4193 +5934 +5503 +2326 +4408 +2960 +842 +1963 +3354 +5568 +9050 +3806 +439 +9154 +6055 +6451 +2190 +7633 +688 +4354 +8890 +2813 +2872 +8102 +8317 +6609 +1497 +8389 +6449 +1682 +3594 +5103 +5812 +863 +268 +3054 +8079 +2260 +2027 +3091 +7687 +6703 +3557 +2019 +8427 +2799 +8182 +6641 +3168 +2284 +1934 +4865 +1077 +6507 +1658 +3811 +1774 +7897 +2238 +2943 +191 +3869 +3246 +4057 +3188 +414 +8072 +7838 +1382 +4962 +6010 +5363 +4042 +1983 +4077 +7429 +1833 +3583 +4044 +1109 +1295 +386 +5481 +3927 +311 diff --git a/Stark/lib/train/data_specs/got10k_val_split.txt b/Stark/lib/train/data_specs/got10k_val_split.txt new file mode 100755 index 0000000..340e286 --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_val_split.txt @@ -0,0 +1,1401 @@ +1349 +5651 +5878 +562 +2202 +8904 +765 +1501 +8654 +2975 +2689 +3680 +5180 +1900 +7707 +4723 +8912 +4029 +3579 +869 +2888 +8657 +6599 +741 +4288 +2244 +7357 +5704 +8791 +208 +8587 +7969 +4805 +8526 +4887 +8871 +7468 +3343 +886 +7794 +5764 +2646 +6454 +6101 +7885 +7744 +1297 +4119 +4856 +122 +2286 +2925 +5131 +3570 +5843 +3027 +5320 +5626 +540 +1862 +5401 +7335 +699 +7760 +9198 +3259 +7345 +8698 +1280 +6479 +3100 +3988 +1322 +5737 +1268 +3257 +6791 +3326 +4815 +7644 +1082 +2826 +6821 +8984 +2553 +5290 +5909 +4762 +9242 +8096 +8066 +4325 +6666 +7193 +7114 +8060 +2376 +7872 +6788 +3544 +5460 +3507 +2509 +6626 +3429 +5542 +4220 +2968 +5271 +4249 +3863 +1868 +5581 +2012 +6270 +8038 +4050 +121 +2845 +1565 +1998 +2275 +5524 +6068 +7624 +4913 +9277 +1506 +803 +8848 +5925 +2450 +2072 +8190 +4753 +9162 +1923 +825 +7303 +9028 +2088 +8516 +1556 +5937 +7847 +2367 +7549 +1049 +1521 +4739 +3931 +8958 +4130 +7877 +7876 +897 +5985 +7346 +7537 +111 +3700 +1126 +7896 +1288 +3419 +4673 +1051 +5720 +1068 +3458 +146 +291 +6256 +5514 +2857 +4580 +6239 +6525 +8717 +391 +4841 +6676 +4360 +1453 +4211 +73 +1675 +1987 +4025 +1321 +662 +8265 +6424 +2758 +7765 +7656 +3209 +7497 +7600 +9039 +7697 +5177 +2983 +5622 +9295 +1200 +3284 +964 +2024 +1269 +4551 +8088 +5659 +2212 +5199 +5551 +8607 +5573 +2247 +5200 +6341 +7951 +8429 +7720 +5919 +1273 +3529 +6707 +9176 +7552 +3255 +5649 +6110 +9235 +1137 +9272 +775 +788 +5786 +5186 +6746 +2667 +9145 +7630 +3953 +1828 +8827 +6471 +4702 +7815 +467 +6387 +3195 +6238 +6508 +2373 +5983 +4931 +2948 +921 +2438 +517 +3949 +2137 +3216 +5683 +3695 +1719 +4837 +9159 +6981 +860 +7410 +5497 +1770 +5557 +8810 +5194 +4857 +9100 +6329 +2609 +1925 +3686 +9041 +4924 +349 +9187 +3393 +3661 +7120 +6858 +4587 +3831 +3130 +5396 +5060 +6486 +3937 +8023 +824 +5398 +1354 +8861 +5534 +7292 +4389 +6029 +6226 +3505 +4326 +7445 +581 +6089 +3450 +7324 +6516 +6775 +1207 +4575 +5135 +9265 +3918 +9020 +3473 +3898 +7812 +6571 +6757 +6639 +2557 +1206 +6148 +7325 +8790 +4938 +7026 +4383 +8041 +1250 +7267 +1952 +7561 +8811 +4941 +8373 +4848 +6602 +8355 +8104 +5214 +6654 +4330 +995 +3181 +3422 +456 +1782 +3408 +6530 +719 +7587 +5910 +3058 +740 +2009 +4207 +5336 +2798 +9229 +8668 +2473 +4221 +1493 +3281 +171 +9157 +9139 +7766 +6220 +9127 +3324 +5308 +3708 +2431 +8080 +2093 +2585 +406 +7040 +5064 +5247 +4758 +6512 +2953 +4257 +4935 +2705 +2572 +3436 +8513 +5884 +1385 +4852 +2637 +7091 +2761 +6007 +8332 +6694 +2422 +4917 +2186 +6898 +1390 +6965 +3132 +7698 +475 +2002 +2692 +5024 +7365 +7373 +4091 +1731 +947 +3962 +8692 +1788 +8734 +8656 +6862 +6856 +1950 +1914 +5658 +3635 +1620 +4780 +2580 +1454 +2786 +687 +7238 +3648 +6452 +1197 +3190 +5900 +9043 +4958 +1935 +1821 +1187 +1153 +7737 +7223 +3820 +7169 +7350 +5674 +6254 +3025 +6680 +1690 +2899 +3893 +1577 +5728 +9189 +5077 +34 +3560 +2179 +5462 +1402 +3654 +1376 +7936 +4246 +5506 +1179 +5647 +4686 +8644 +1352 +2855 +6079 +2254 +2668 +2287 +2457 +3418 +7264 +677 +3074 +2655 +1042 +2210 +4504 +7089 +8309 +4209 +4280 +3258 +2977 +84 +4705 +1244 +3511 +6355 +8813 +3228 +9266 +1122 +613 +732 +5202 +8425 +2638 +6470 +2886 +3541 +8132 +2063 +8201 +5129 +2818 +7949 +6936 +8090 +4465 +7295 +5239 +7009 +9271 +8563 +2832 +952 +8136 +6776 +3565 +5188 +7288 +6999 +285 +5487 +7763 +7608 +8584 +2071 +7868 +2804 +3655 +7048 +6847 +3276 +4082 +4272 +3910 +3709 +1574 +4559 +7580 +7081 +5014 +7769 +8183 +6386 +7574 +356 +4937 +2487 +9315 +7572 +3040 +671 +2682 +8626 +3868 +8623 +387 +8679 +4074 +1481 +3527 +3595 +4754 +2453 +1579 +4638 +9123 +1829 +316 +3009 +3691 +763 +4875 +3572 +4642 +3128 +4273 +2777 +6032 +4793 +233 +7147 +996 +3199 +8835 +3517 +7210 +6125 +6037 +3684 +8589 +3915 +3095 +8310 +3180 +7043 +4458 +2889 +57 +4483 +7667 +8375 +1434 +7493 +6986 +4733 +8471 +5827 +2111 +1313 +7986 +3075 +2614 +7547 +4977 +8527 +3212 +7300 +5842 +5244 +3291 +597 +1007 +2030 +227 +3830 +5540 +247 +5643 +9333 +1958 +3096 +1371 +5220 +7926 +2927 +1516 +7130 +193 +1522 +6165 +6923 +3794 +4223 +5535 +2472 +8630 +3971 +9101 +2946 +222 +4609 +7291 +8542 +6501 +7548 +4557 +6274 +1010 +5226 +7309 +1317 +9056 +6275 +1624 +1099 +4191 +4030 +7270 +5392 +2316 +3819 +1670 +8154 +8045 +4807 +8864 +2391 +5908 +8338 +8218 +6400 +9193 +3165 +843 +6613 +6941 +4380 +9332 +5629 +7557 +4321 +3702 +681 +734 +1159 +4665 +5959 +1697 +5509 +8774 +7389 +3832 +3751 +8637 +3079 +1680 +6841 +703 +684 +8293 +3682 +5733 +4818 +3231 +3078 +5562 +9001 +3889 +7024 +2519 +1713 +3287 +219 +6021 +8776 +2289 +7212 +4832 +4684 +4617 +4237 +2649 +8185 +6326 +3568 +551 +1426 +4181 +8869 +312 +2905 +4165 +8248 +2558 +900 +1044 +8613 +7743 +5437 +7604 +3122 +5708 +8649 +2878 +4695 +4491 +1929 +7533 +5223 +7711 +915 +1844 +5751 +3008 +8055 +961 +6142 +4636 +61 +198 +2271 +5698 +4596 +4500 +5709 +5819 +7972 +2992 +1643 +1048 +6281 +8886 +360 +4198 +1841 +6814 +3960 +2606 +7001 +5888 +450 +7133 +7015 +7034 +5153 +8920 +5066 +469 +1302 +8816 +463 +8651 +5869 +8193 +6582 +5578 +1231 +9274 +7260 +7751 +8052 +6799 +2089 +2342 +8451 +3260 +5550 +7795 +2288 +1205 +40 +496 +8367 +7836 +5973 +3908 +5242 +5062 +2706 +997 +6514 +5419 +9201 +1965 +6062 +3050 +5302 +8735 +358 +2398 +7470 +1644 +8179 +7047 +1549 +5414 +2539 +7381 +589 +8166 +8505 +6035 +3956 +4540 +6721 +8074 +1062 +2384 +2531 +7159 +3502 +3902 +4584 +2554 +264 +8720 +2849 +4916 +5218 +7202 +883 +4560 +1677 +4317 +7863 +4509 +6577 +2903 +1452 +1416 +5369 +473 +6233 +6359 +5992 +4934 +8059 +6834 +4907 +3320 +8267 +8280 +2066 +2402 +1485 +3772 +3732 +4764 +9126 +3575 +5564 +4768 +5641 +1884 +2330 +1804 +344 +698 +3089 +1532 +4454 +761 +7289 +8094 +3432 +1747 +6811 +8722 +8826 +4646 +3222 +8614 +2901 +7003 +652 +8663 +4266 +413 +810 +75 +3334 +4905 +6438 +4756 +5137 +6528 +6534 +6988 +6177 +8533 +889 +5384 +7201 +5132 +7802 +6864 +3973 +873 +4840 +1482 +8376 +3769 +5858 +6675 +4286 +2593 +5863 +4353 +7817 +7540 +4999 +4838 +2303 +6002 +7913 +1508 +5317 +7755 +2784 +4964 +3431 +6209 +3755 +6022 +6399 +6232 +3954 +455 +5416 +6448 +1558 +7591 +245 +140 +9210 +6585 +4084 +967 +7798 +6795 +7095 +6733 +3861 +9264 +361 +1045 +755 +8042 +7074 +7778 +6415 +4724 +6450 +2049 +1563 +1307 +3485 +1790 +7869 +3282 +6907 +3920 +2868 +5801 +5632 +1079 +5009 +3955 +7517 +5128 +3417 +3019 +2725 +1784 +2312 +2753 +6976 +342 +8266 +1849 +2273 +5037 +7880 +3793 +7401 +5412 +8279 +1257 +3670 +9049 +3266 +8955 +6519 +8916 +2858 +694 +5650 +1019 +4669 +1785 +3533 +5877 +2704 +8603 +3726 +6668 +497 +1085 +6815 +6157 +6646 +6964 +186 +8097 +5645 +8481 +8215 +3775 +2542 +7514 +5699 +4072 +3518 +5767 +3239 +3740 +1404 +8981 +4086 +6397 +6984 +4204 +6899 +682 +6589 +3317 +2944 +3456 +4340 +7424 +9208 +6504 +4409 +1 +145 +1882 +4620 +2634 +4992 +5453 +4481 +3377 +266 +7875 +530 +1235 +7605 +504 +1771 +8489 +345 +7353 +7797 +7174 +5914 +2871 +5721 +6067 +3582 +7653 +5467 +6234 +691 +8758 +2122 +1213 +2908 +1492 +1437 +2187 +1266 +2395 +7278 +8491 +5256 +1554 +8163 +5966 +7128 +7904 +1691 +6272 +1264 +3996 +1706 +1334 +1316 +6478 +6935 +1518 +6700 +8703 +8744 +8152 +8778 +5367 +4218 +9007 +6312 +606 +7565 +5293 +2891 +675 +2125 +2120 +826 +7008 +5705 +7748 +8010 +1498 +5330 +5472 +2215 +7627 +3016 +6588 +1850 +4128 +8569 +6987 +7566 +148 +8151 +8789 +7907 +8596 +715 +6018 +9060 +3872 +1750 +5889 +4047 +5960 +3120 +3449 +1421 +1102 +3333 +9197 +8796 +8123 +8007 +2028 +8404 +1945 +1985 +8109 +5380 +8438 +3504 +6739 +4180 +5835 +4243 +25 +4002 +1976 +3482 +8392 +158 +5181 +4885 +8985 +11 +6872 +6425 +5926 +7062 +5083 +8394 +4259 +5844 +1990 +3942 +5532 +2220 +28 +5957 +149 +6748 +1663 +3559 +7647 +2566 +1359 +8787 +5259 +7010 +554 +8231 +4229 +6005 +8172 +8125 +1350 +3571 +9051 +1973 +1386 +1781 +5788 +159 +7007 +3220 +1846 +3093 +4445 +2056 +8370 +3211 +1113 +4384 +2231 +273 +4276 +642 +7663 +5311 +265 +226 +9012 +7879 +118 +7109 +7251 +1760 +8667 +2876 +7162 +3552 +6901 +6779 +5021 +6524 +4957 +3114 +4544 +441 +1848 +2136 +2458 +8662 +1127 +5541 +3026 +1080 +6780 +2224 +8259 +1073 +9000 +7244 +7977 +500 +4435 +7376 +7979 +1435 +9291 +7704 +3791 +3521 +210 +7388 +1039 +6269 +4052 +8570 +3285 +564 +8039 +3546 +6203 +1183 +6107 +4147 +6216 +2234 +7185 +3192 +7155 +2001 +7777 +876 +944 +908 +7791 +5465 +6784 +65 +9172 +5675 +7075 +3886 +7891 +2978 +1008 +5630 +591 +5067 +1139 +577 +9015 +574 +8137 +7786 +5765 +4900 +4090 +7842 +5741 diff --git a/Stark/lib/train/data_specs/got10k_vot_exclude.txt b/Stark/lib/train/data_specs/got10k_vot_exclude.txt new file mode 100755 index 0000000..7e7291a --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_vot_exclude.txt @@ -0,0 +1,1000 @@ +GOT-10k_Train_000004 +GOT-10k_Train_000013 +GOT-10k_Train_000015 +GOT-10k_Train_000020 +GOT-10k_Train_000024 +GOT-10k_Train_000034 +GOT-10k_Train_000038 +GOT-10k_Train_000048 +GOT-10k_Train_000051 +GOT-10k_Train_000059 +GOT-10k_Train_000077 +GOT-10k_Train_000081 +GOT-10k_Train_000089 +GOT-10k_Train_000093 +GOT-10k_Train_000094 +GOT-10k_Train_000096 +GOT-10k_Train_000104 +GOT-10k_Train_000107 +GOT-10k_Train_000108 +GOT-10k_Train_000120 +GOT-10k_Train_000132 +GOT-10k_Train_000170 +GOT-10k_Train_000186 +GOT-10k_Train_000212 +GOT-10k_Train_000213 +GOT-10k_Train_000222 +GOT-10k_Train_000223 +GOT-10k_Train_000240 +GOT-10k_Train_000246 +GOT-10k_Train_000249 +GOT-10k_Train_000266 +GOT-10k_Train_000268 +GOT-10k_Train_000287 +GOT-10k_Train_000293 +GOT-10k_Train_000305 +GOT-10k_Train_000316 +GOT-10k_Train_000319 +GOT-10k_Train_000322 +GOT-10k_Train_000331 +GOT-10k_Train_000334 +GOT-10k_Train_000354 +GOT-10k_Train_000361 +GOT-10k_Train_000368 +GOT-10k_Train_000382 +GOT-10k_Train_000401 +GOT-10k_Train_000417 +GOT-10k_Train_000448 +GOT-10k_Train_000454 +GOT-10k_Train_000458 +GOT-10k_Train_000466 +GOT-10k_Train_000475 +GOT-10k_Train_000484 +GOT-10k_Train_000488 +GOT-10k_Train_000501 +GOT-10k_Train_000510 +GOT-10k_Train_000512 +GOT-10k_Train_000519 +GOT-10k_Train_000539 +GOT-10k_Train_000544 +GOT-10k_Train_000555 +GOT-10k_Train_000564 +GOT-10k_Train_000568 +GOT-10k_Train_000583 +GOT-10k_Train_000587 +GOT-10k_Train_000593 +GOT-10k_Train_000621 +GOT-10k_Train_000624 +GOT-10k_Train_000625 +GOT-10k_Train_000638 +GOT-10k_Train_000648 +GOT-10k_Train_000654 +GOT-10k_Train_000669 +GOT-10k_Train_000701 +GOT-10k_Train_000709 +GOT-10k_Train_000712 +GOT-10k_Train_000731 +GOT-10k_Train_000734 +GOT-10k_Train_000737 +GOT-10k_Train_000744 +GOT-10k_Train_000746 +GOT-10k_Train_000748 +GOT-10k_Train_000762 +GOT-10k_Train_000764 +GOT-10k_Train_000765 +GOT-10k_Train_000766 +GOT-10k_Train_000767 +GOT-10k_Train_000775 +GOT-10k_Train_000783 +GOT-10k_Train_000790 +GOT-10k_Train_000829 +GOT-10k_Train_000857 +GOT-10k_Train_000859 +GOT-10k_Train_000867 +GOT-10k_Train_000872 +GOT-10k_Train_000880 +GOT-10k_Train_000884 +GOT-10k_Train_000909 +GOT-10k_Train_000915 +GOT-10k_Train_000922 +GOT-10k_Train_000928 +GOT-10k_Train_000933 +GOT-10k_Train_000941 +GOT-10k_Train_000961 +GOT-10k_Train_000966 +GOT-10k_Train_000968 +GOT-10k_Train_000971 +GOT-10k_Train_000972 +GOT-10k_Train_000995 +GOT-10k_Train_001003 +GOT-10k_Train_001010 +GOT-10k_Train_001011 +GOT-10k_Train_001019 +GOT-10k_Train_001021 +GOT-10k_Train_001035 +GOT-10k_Train_001039 +GOT-10k_Train_001047 +GOT-10k_Train_001057 +GOT-10k_Train_001069 +GOT-10k_Train_001077 +GOT-10k_Train_001079 +GOT-10k_Train_001085 +GOT-10k_Train_001088 +GOT-10k_Train_001091 +GOT-10k_Train_001104 +GOT-10k_Train_001112 +GOT-10k_Train_001113 +GOT-10k_Train_001124 +GOT-10k_Train_001128 +GOT-10k_Train_001143 +GOT-10k_Train_001145 +GOT-10k_Train_001146 +GOT-10k_Train_001148 +GOT-10k_Train_001150 +GOT-10k_Train_001154 +GOT-10k_Train_001156 +GOT-10k_Train_001157 +GOT-10k_Train_001163 +GOT-10k_Train_001181 +GOT-10k_Train_001184 +GOT-10k_Train_001189 +GOT-10k_Train_001200 +GOT-10k_Train_001225 +GOT-10k_Train_001264 +GOT-10k_Train_001288 +GOT-10k_Train_001296 +GOT-10k_Train_001298 +GOT-10k_Train_001299 +GOT-10k_Train_001314 +GOT-10k_Train_001319 +GOT-10k_Train_001329 +GOT-10k_Train_001331 +GOT-10k_Train_001340 +GOT-10k_Train_001374 +GOT-10k_Train_001384 +GOT-10k_Train_001394 +GOT-10k_Train_001407 +GOT-10k_Train_001415 +GOT-10k_Train_001430 +GOT-10k_Train_001433 +GOT-10k_Train_001453 +GOT-10k_Train_001457 +GOT-10k_Train_001471 +GOT-10k_Train_001473 +GOT-10k_Train_001480 +GOT-10k_Train_001484 +GOT-10k_Train_001489 +GOT-10k_Train_001514 +GOT-10k_Train_001537 +GOT-10k_Train_001544 +GOT-10k_Train_001545 +GOT-10k_Train_001551 +GOT-10k_Train_001558 +GOT-10k_Train_001560 +GOT-10k_Train_001562 +GOT-10k_Train_001563 +GOT-10k_Train_001570 +GOT-10k_Train_001576 +GOT-10k_Train_001604 +GOT-10k_Train_001615 +GOT-10k_Train_001617 +GOT-10k_Train_001618 +GOT-10k_Train_001619 +GOT-10k_Train_001624 +GOT-10k_Train_001650 +GOT-10k_Train_001651 +GOT-10k_Train_001663 +GOT-10k_Train_001673 +GOT-10k_Train_001685 +GOT-10k_Train_001692 +GOT-10k_Train_001700 +GOT-10k_Train_001722 +GOT-10k_Train_001731 +GOT-10k_Train_001732 +GOT-10k_Train_001738 +GOT-10k_Train_001740 +GOT-10k_Train_001742 +GOT-10k_Train_001747 +GOT-10k_Train_001759 +GOT-10k_Train_001769 +GOT-10k_Train_001781 +GOT-10k_Train_001791 +GOT-10k_Train_001794 +GOT-10k_Train_001795 +GOT-10k_Train_001818 +GOT-10k_Train_001833 +GOT-10k_Train_001836 +GOT-10k_Train_001841 +GOT-10k_Train_001852 +GOT-10k_Train_001863 +GOT-10k_Train_001865 +GOT-10k_Train_001878 +GOT-10k_Train_001898 +GOT-10k_Train_001919 +GOT-10k_Train_001923 +GOT-10k_Train_001929 +GOT-10k_Train_001935 +GOT-10k_Train_001938 +GOT-10k_Train_001942 +GOT-10k_Train_001955 +GOT-10k_Train_001964 +GOT-10k_Train_001966 +GOT-10k_Train_001982 +GOT-10k_Train_002005 +GOT-10k_Train_002009 +GOT-10k_Train_002035 +GOT-10k_Train_002068 +GOT-10k_Train_002073 +GOT-10k_Train_002076 +GOT-10k_Train_002084 +GOT-10k_Train_002112 +GOT-10k_Train_002115 +GOT-10k_Train_002116 +GOT-10k_Train_002123 +GOT-10k_Train_002125 +GOT-10k_Train_002129 +GOT-10k_Train_002139 +GOT-10k_Train_002146 +GOT-10k_Train_002166 +GOT-10k_Train_002168 +GOT-10k_Train_002176 +GOT-10k_Train_002184 +GOT-10k_Train_002190 +GOT-10k_Train_002192 +GOT-10k_Train_002211 +GOT-10k_Train_002216 +GOT-10k_Train_002233 +GOT-10k_Train_002240 +GOT-10k_Train_002247 +GOT-10k_Train_002250 +GOT-10k_Train_002252 +GOT-10k_Train_002253 +GOT-10k_Train_002261 +GOT-10k_Train_002274 +GOT-10k_Train_002276 +GOT-10k_Train_002292 +GOT-10k_Train_002302 +GOT-10k_Train_002304 +GOT-10k_Train_002305 +GOT-10k_Train_002320 +GOT-10k_Train_002345 +GOT-10k_Train_002355 +GOT-10k_Train_002359 +GOT-10k_Train_002363 +GOT-10k_Train_002374 +GOT-10k_Train_002376 +GOT-10k_Train_002389 +GOT-10k_Train_002393 +GOT-10k_Train_002400 +GOT-10k_Train_002408 +GOT-10k_Train_002418 +GOT-10k_Train_002437 +GOT-10k_Train_002440 +GOT-10k_Train_002442 +GOT-10k_Train_002454 +GOT-10k_Train_002456 +GOT-10k_Train_002465 +GOT-10k_Train_002466 +GOT-10k_Train_002474 +GOT-10k_Train_002479 +GOT-10k_Train_002484 +GOT-10k_Train_002511 +GOT-10k_Train_002514 +GOT-10k_Train_002517 +GOT-10k_Train_002523 +GOT-10k_Train_002527 +GOT-10k_Train_002534 +GOT-10k_Train_002555 +GOT-10k_Train_002587 +GOT-10k_Train_002589 +GOT-10k_Train_002612 +GOT-10k_Train_002627 +GOT-10k_Train_002639 +GOT-10k_Train_002652 +GOT-10k_Train_002693 +GOT-10k_Train_002699 +GOT-10k_Train_002716 +GOT-10k_Train_002725 +GOT-10k_Train_002727 +GOT-10k_Train_002730 +GOT-10k_Train_002755 +GOT-10k_Train_002756 +GOT-10k_Train_002760 +GOT-10k_Train_002763 +GOT-10k_Train_002837 +GOT-10k_Train_002841 +GOT-10k_Train_002856 +GOT-10k_Train_002862 +GOT-10k_Train_002863 +GOT-10k_Train_002866 +GOT-10k_Train_002877 +GOT-10k_Train_002884 +GOT-10k_Train_002886 +GOT-10k_Train_002887 +GOT-10k_Train_002907 +GOT-10k_Train_002908 +GOT-10k_Train_002909 +GOT-10k_Train_002914 +GOT-10k_Train_002920 +GOT-10k_Train_002922 +GOT-10k_Train_002936 +GOT-10k_Train_002940 +GOT-10k_Train_002944 +GOT-10k_Train_002953 +GOT-10k_Train_002961 +GOT-10k_Train_002964 +GOT-10k_Train_002996 +GOT-10k_Train_003003 +GOT-10k_Train_003004 +GOT-10k_Train_003007 +GOT-10k_Train_003012 +GOT-10k_Train_003027 +GOT-10k_Train_003028 +GOT-10k_Train_003033 +GOT-10k_Train_003034 +GOT-10k_Train_003036 +GOT-10k_Train_003044 +GOT-10k_Train_003056 +GOT-10k_Train_003069 +GOT-10k_Train_003078 +GOT-10k_Train_003079 +GOT-10k_Train_003095 +GOT-10k_Train_003096 +GOT-10k_Train_003107 +GOT-10k_Train_003108 +GOT-10k_Train_003127 +GOT-10k_Train_003128 +GOT-10k_Train_003129 +GOT-10k_Train_003132 +GOT-10k_Train_003146 +GOT-10k_Train_003155 +GOT-10k_Train_003173 +GOT-10k_Train_003208 +GOT-10k_Train_003239 +GOT-10k_Train_003245 +GOT-10k_Train_003246 +GOT-10k_Train_003262 +GOT-10k_Train_003275 +GOT-10k_Train_003283 +GOT-10k_Train_003296 +GOT-10k_Train_003308 +GOT-10k_Train_003310 +GOT-10k_Train_003313 +GOT-10k_Train_003317 +GOT-10k_Train_003318 +GOT-10k_Train_003354 +GOT-10k_Train_003379 +GOT-10k_Train_003384 +GOT-10k_Train_003396 +GOT-10k_Train_003401 +GOT-10k_Train_003423 +GOT-10k_Train_003435 +GOT-10k_Train_003438 +GOT-10k_Train_003442 +GOT-10k_Train_003444 +GOT-10k_Train_003455 +GOT-10k_Train_003456 +GOT-10k_Train_003464 +GOT-10k_Train_003466 +GOT-10k_Train_003474 +GOT-10k_Train_003482 +GOT-10k_Train_003488 +GOT-10k_Train_003502 +GOT-10k_Train_003515 +GOT-10k_Train_003520 +GOT-10k_Train_003530 +GOT-10k_Train_003551 +GOT-10k_Train_003570 +GOT-10k_Train_003571 +GOT-10k_Train_003578 +GOT-10k_Train_003583 +GOT-10k_Train_003590 +GOT-10k_Train_003593 +GOT-10k_Train_003618 +GOT-10k_Train_003626 +GOT-10k_Train_003650 +GOT-10k_Train_003652 +GOT-10k_Train_003663 +GOT-10k_Train_003690 +GOT-10k_Train_003704 +GOT-10k_Train_003709 +GOT-10k_Train_003716 +GOT-10k_Train_003721 +GOT-10k_Train_003722 +GOT-10k_Train_003724 +GOT-10k_Train_003729 +GOT-10k_Train_003756 +GOT-10k_Train_003768 +GOT-10k_Train_003782 +GOT-10k_Train_003786 +GOT-10k_Train_003788 +GOT-10k_Train_003791 +GOT-10k_Train_003820 +GOT-10k_Train_003821 +GOT-10k_Train_003827 +GOT-10k_Train_003834 +GOT-10k_Train_003835 +GOT-10k_Train_003839 +GOT-10k_Train_003843 +GOT-10k_Train_003854 +GOT-10k_Train_003856 +GOT-10k_Train_003881 +GOT-10k_Train_003899 +GOT-10k_Train_003904 +GOT-10k_Train_003906 +GOT-10k_Train_003913 +GOT-10k_Train_003937 +GOT-10k_Train_003940 +GOT-10k_Train_003943 +GOT-10k_Train_003950 +GOT-10k_Train_003972 +GOT-10k_Train_003974 +GOT-10k_Train_003978 +GOT-10k_Train_003981 +GOT-10k_Train_003982 +GOT-10k_Train_004003 +GOT-10k_Train_004004 +GOT-10k_Train_004008 +GOT-10k_Train_004012 +GOT-10k_Train_004013 +GOT-10k_Train_004030 +GOT-10k_Train_004036 +GOT-10k_Train_004040 +GOT-10k_Train_004052 +GOT-10k_Train_004054 +GOT-10k_Train_004055 +GOT-10k_Train_004057 +GOT-10k_Train_004063 +GOT-10k_Train_004068 +GOT-10k_Train_004072 +GOT-10k_Train_004075 +GOT-10k_Train_004078 +GOT-10k_Train_004082 +GOT-10k_Train_004102 +GOT-10k_Train_004103 +GOT-10k_Train_004105 +GOT-10k_Train_004111 +GOT-10k_Train_004120 +GOT-10k_Train_004122 +GOT-10k_Train_004124 +GOT-10k_Train_004142 +GOT-10k_Train_004158 +GOT-10k_Train_004170 +GOT-10k_Train_004175 +GOT-10k_Train_004181 +GOT-10k_Train_004190 +GOT-10k_Train_004193 +GOT-10k_Train_004194 +GOT-10k_Train_004199 +GOT-10k_Train_004202 +GOT-10k_Train_004217 +GOT-10k_Train_004225 +GOT-10k_Train_004229 +GOT-10k_Train_004230 +GOT-10k_Train_004234 +GOT-10k_Train_004241 +GOT-10k_Train_004246 +GOT-10k_Train_004249 +GOT-10k_Train_004255 +GOT-10k_Train_004268 +GOT-10k_Train_004276 +GOT-10k_Train_004292 +GOT-10k_Train_004293 +GOT-10k_Train_004295 +GOT-10k_Train_004296 +GOT-10k_Train_004302 +GOT-10k_Train_004324 +GOT-10k_Train_004337 +GOT-10k_Train_004342 +GOT-10k_Train_004351 +GOT-10k_Train_004356 +GOT-10k_Train_004376 +GOT-10k_Train_004380 +GOT-10k_Train_004395 +GOT-10k_Train_004398 +GOT-10k_Train_004399 +GOT-10k_Train_004408 +GOT-10k_Train_004430 +GOT-10k_Train_004439 +GOT-10k_Train_004440 +GOT-10k_Train_004462 +GOT-10k_Train_004473 +GOT-10k_Train_004476 +GOT-10k_Train_004478 +GOT-10k_Train_004481 +GOT-10k_Train_004483 +GOT-10k_Train_004484 +GOT-10k_Train_004503 +GOT-10k_Train_004513 +GOT-10k_Train_004517 +GOT-10k_Train_004533 +GOT-10k_Train_004536 +GOT-10k_Train_004594 +GOT-10k_Train_004595 +GOT-10k_Train_004607 +GOT-10k_Train_004619 +GOT-10k_Train_004626 +GOT-10k_Train_004642 +GOT-10k_Train_004646 +GOT-10k_Train_004652 +GOT-10k_Train_004658 +GOT-10k_Train_004660 +GOT-10k_Train_004661 +GOT-10k_Train_004668 +GOT-10k_Train_004673 +GOT-10k_Train_004679 +GOT-10k_Train_004694 +GOT-10k_Train_004702 +GOT-10k_Train_004709 +GOT-10k_Train_004717 +GOT-10k_Train_004757 +GOT-10k_Train_004768 +GOT-10k_Train_004824 +GOT-10k_Train_004826 +GOT-10k_Train_004833 +GOT-10k_Train_004839 +GOT-10k_Train_004843 +GOT-10k_Train_004852 +GOT-10k_Train_004862 +GOT-10k_Train_004865 +GOT-10k_Train_004878 +GOT-10k_Train_004880 +GOT-10k_Train_004881 +GOT-10k_Train_004902 +GOT-10k_Train_004906 +GOT-10k_Train_004920 +GOT-10k_Train_004950 +GOT-10k_Train_004951 +GOT-10k_Train_004952 +GOT-10k_Train_004973 +GOT-10k_Train_004983 +GOT-10k_Train_004984 +GOT-10k_Train_004990 +GOT-10k_Train_004993 +GOT-10k_Train_004995 +GOT-10k_Train_005004 +GOT-10k_Train_005007 +GOT-10k_Train_005022 +GOT-10k_Train_005024 +GOT-10k_Train_005040 +GOT-10k_Train_005046 +GOT-10k_Train_005047 +GOT-10k_Train_005058 +GOT-10k_Train_005063 +GOT-10k_Train_005072 +GOT-10k_Train_005097 +GOT-10k_Train_005098 +GOT-10k_Train_005099 +GOT-10k_Train_005108 +GOT-10k_Train_005113 +GOT-10k_Train_005119 +GOT-10k_Train_005126 +GOT-10k_Train_005146 +GOT-10k_Train_005166 +GOT-10k_Train_005191 +GOT-10k_Train_005207 +GOT-10k_Train_005255 +GOT-10k_Train_005269 +GOT-10k_Train_005280 +GOT-10k_Train_005310 +GOT-10k_Train_005317 +GOT-10k_Train_005319 +GOT-10k_Train_005334 +GOT-10k_Train_005338 +GOT-10k_Train_005339 +GOT-10k_Train_005354 +GOT-10k_Train_005364 +GOT-10k_Train_005382 +GOT-10k_Train_005385 +GOT-10k_Train_005389 +GOT-10k_Train_005390 +GOT-10k_Train_005396 +GOT-10k_Train_005398 +GOT-10k_Train_005399 +GOT-10k_Train_005401 +GOT-10k_Train_005413 +GOT-10k_Train_005415 +GOT-10k_Train_005420 +GOT-10k_Train_005457 +GOT-10k_Train_005465 +GOT-10k_Train_005488 +GOT-10k_Train_005493 +GOT-10k_Train_005510 +GOT-10k_Train_005523 +GOT-10k_Train_005538 +GOT-10k_Train_005553 +GOT-10k_Train_005556 +GOT-10k_Train_005575 +GOT-10k_Train_005577 +GOT-10k_Train_005582 +GOT-10k_Train_005594 +GOT-10k_Train_005606 +GOT-10k_Train_005611 +GOT-10k_Train_005636 +GOT-10k_Train_005639 +GOT-10k_Train_005642 +GOT-10k_Train_005651 +GOT-10k_Train_005652 +GOT-10k_Train_005653 +GOT-10k_Train_005681 +GOT-10k_Train_005686 +GOT-10k_Train_005689 +GOT-10k_Train_005701 +GOT-10k_Train_005712 +GOT-10k_Train_005716 +GOT-10k_Train_005724 +GOT-10k_Train_005731 +GOT-10k_Train_005732 +GOT-10k_Train_005734 +GOT-10k_Train_005741 +GOT-10k_Train_005764 +GOT-10k_Train_005767 +GOT-10k_Train_005788 +GOT-10k_Train_005791 +GOT-10k_Train_005800 +GOT-10k_Train_005813 +GOT-10k_Train_005816 +GOT-10k_Train_005830 +GOT-10k_Train_005852 +GOT-10k_Train_005876 +GOT-10k_Train_005877 +GOT-10k_Train_005884 +GOT-10k_Train_005910 +GOT-10k_Train_005929 +GOT-10k_Train_005943 +GOT-10k_Train_005958 +GOT-10k_Train_005995 +GOT-10k_Train_006002 +GOT-10k_Train_006010 +GOT-10k_Train_006018 +GOT-10k_Train_006021 +GOT-10k_Train_006022 +GOT-10k_Train_006040 +GOT-10k_Train_006046 +GOT-10k_Train_006057 +GOT-10k_Train_006075 +GOT-10k_Train_006087 +GOT-10k_Train_006099 +GOT-10k_Train_006115 +GOT-10k_Train_006126 +GOT-10k_Train_006129 +GOT-10k_Train_006142 +GOT-10k_Train_006161 +GOT-10k_Train_006163 +GOT-10k_Train_006193 +GOT-10k_Train_006195 +GOT-10k_Train_006204 +GOT-10k_Train_006206 +GOT-10k_Train_006215 +GOT-10k_Train_006216 +GOT-10k_Train_006220 +GOT-10k_Train_006224 +GOT-10k_Train_006232 +GOT-10k_Train_006241 +GOT-10k_Train_006247 +GOT-10k_Train_006287 +GOT-10k_Train_006300 +GOT-10k_Train_006315 +GOT-10k_Train_006318 +GOT-10k_Train_006322 +GOT-10k_Train_006337 +GOT-10k_Train_006341 +GOT-10k_Train_006344 +GOT-10k_Train_006348 +GOT-10k_Train_006349 +GOT-10k_Train_006363 +GOT-10k_Train_006366 +GOT-10k_Train_006376 +GOT-10k_Train_006378 +GOT-10k_Train_006395 +GOT-10k_Train_006402 +GOT-10k_Train_006406 +GOT-10k_Train_006412 +GOT-10k_Train_006413 +GOT-10k_Train_006427 +GOT-10k_Train_006448 +GOT-10k_Train_006459 +GOT-10k_Train_006464 +GOT-10k_Train_006474 +GOT-10k_Train_006477 +GOT-10k_Train_006482 +GOT-10k_Train_006483 +GOT-10k_Train_006496 +GOT-10k_Train_006498 +GOT-10k_Train_006499 +GOT-10k_Train_006505 +GOT-10k_Train_006506 +GOT-10k_Train_006514 +GOT-10k_Train_006533 +GOT-10k_Train_006563 +GOT-10k_Train_006569 +GOT-10k_Train_006573 +GOT-10k_Train_006584 +GOT-10k_Train_006585 +GOT-10k_Train_006587 +GOT-10k_Train_006591 +GOT-10k_Train_006592 +GOT-10k_Train_006598 +GOT-10k_Train_006605 +GOT-10k_Train_006631 +GOT-10k_Train_006633 +GOT-10k_Train_006644 +GOT-10k_Train_006651 +GOT-10k_Train_006654 +GOT-10k_Train_006672 +GOT-10k_Train_006717 +GOT-10k_Train_006728 +GOT-10k_Train_006736 +GOT-10k_Train_006740 +GOT-10k_Train_006746 +GOT-10k_Train_006754 +GOT-10k_Train_006759 +GOT-10k_Train_006766 +GOT-10k_Train_006789 +GOT-10k_Train_006796 +GOT-10k_Train_006797 +GOT-10k_Train_006817 +GOT-10k_Train_006818 +GOT-10k_Train_006849 +GOT-10k_Train_006851 +GOT-10k_Train_006855 +GOT-10k_Train_006872 +GOT-10k_Train_006879 +GOT-10k_Train_006900 +GOT-10k_Train_006912 +GOT-10k_Train_006926 +GOT-10k_Train_006936 +GOT-10k_Train_006955 +GOT-10k_Train_006968 +GOT-10k_Train_006969 +GOT-10k_Train_006979 +GOT-10k_Train_006980 +GOT-10k_Train_006984 +GOT-10k_Train_006986 +GOT-10k_Train_006991 +GOT-10k_Train_007017 +GOT-10k_Train_007032 +GOT-10k_Train_007035 +GOT-10k_Train_007048 +GOT-10k_Train_007064 +GOT-10k_Train_007065 +GOT-10k_Train_007075 +GOT-10k_Train_007077 +GOT-10k_Train_007081 +GOT-10k_Train_007083 +GOT-10k_Train_007089 +GOT-10k_Train_007106 +GOT-10k_Train_007107 +GOT-10k_Train_007131 +GOT-10k_Train_007138 +GOT-10k_Train_007144 +GOT-10k_Train_007150 +GOT-10k_Train_007168 +GOT-10k_Train_007170 +GOT-10k_Train_007177 +GOT-10k_Train_007181 +GOT-10k_Train_007183 +GOT-10k_Train_007190 +GOT-10k_Train_007208 +GOT-10k_Train_007220 +GOT-10k_Train_007223 +GOT-10k_Train_007247 +GOT-10k_Train_007273 +GOT-10k_Train_007284 +GOT-10k_Train_007289 +GOT-10k_Train_007293 +GOT-10k_Train_007294 +GOT-10k_Train_007296 +GOT-10k_Train_007316 +GOT-10k_Train_007322 +GOT-10k_Train_007355 +GOT-10k_Train_007360 +GOT-10k_Train_007362 +GOT-10k_Train_007364 +GOT-10k_Train_007388 +GOT-10k_Train_007392 +GOT-10k_Train_007403 +GOT-10k_Train_007404 +GOT-10k_Train_007426 +GOT-10k_Train_007427 +GOT-10k_Train_007443 +GOT-10k_Train_007446 +GOT-10k_Train_007461 +GOT-10k_Train_007482 +GOT-10k_Train_007489 +GOT-10k_Train_007499 +GOT-10k_Train_007503 +GOT-10k_Train_007507 +GOT-10k_Train_007515 +GOT-10k_Train_007521 +GOT-10k_Train_007523 +GOT-10k_Train_007525 +GOT-10k_Train_007535 +GOT-10k_Train_007559 +GOT-10k_Train_007566 +GOT-10k_Train_007582 +GOT-10k_Train_007586 +GOT-10k_Train_007596 +GOT-10k_Train_007616 +GOT-10k_Train_007623 +GOT-10k_Train_007634 +GOT-10k_Train_007637 +GOT-10k_Train_007643 +GOT-10k_Train_007645 +GOT-10k_Train_007653 +GOT-10k_Train_007660 +GOT-10k_Train_007661 +GOT-10k_Train_007663 +GOT-10k_Train_007672 +GOT-10k_Train_007700 +GOT-10k_Train_007710 +GOT-10k_Train_007714 +GOT-10k_Train_007717 +GOT-10k_Train_007718 +GOT-10k_Train_007737 +GOT-10k_Train_007741 +GOT-10k_Train_007746 +GOT-10k_Train_007763 +GOT-10k_Train_007769 +GOT-10k_Train_007780 +GOT-10k_Train_007803 +GOT-10k_Train_007821 +GOT-10k_Train_007825 +GOT-10k_Train_007839 +GOT-10k_Train_007848 +GOT-10k_Train_007873 +GOT-10k_Train_007877 +GOT-10k_Train_007882 +GOT-10k_Train_007894 +GOT-10k_Train_007905 +GOT-10k_Train_007908 +GOT-10k_Train_007911 +GOT-10k_Train_007914 +GOT-10k_Train_007918 +GOT-10k_Train_007929 +GOT-10k_Train_007936 +GOT-10k_Train_007938 +GOT-10k_Train_007965 +GOT-10k_Train_007969 +GOT-10k_Train_007973 +GOT-10k_Train_007987 +GOT-10k_Train_007999 +GOT-10k_Train_008001 +GOT-10k_Train_008034 +GOT-10k_Train_008050 +GOT-10k_Train_008056 +GOT-10k_Train_008068 +GOT-10k_Train_008073 +GOT-10k_Train_008089 +GOT-10k_Train_008095 +GOT-10k_Train_008101 +GOT-10k_Train_008128 +GOT-10k_Train_008139 +GOT-10k_Train_008147 +GOT-10k_Train_008154 +GOT-10k_Train_008171 +GOT-10k_Train_008180 +GOT-10k_Train_008193 +GOT-10k_Train_008194 +GOT-10k_Train_008201 +GOT-10k_Train_008212 +GOT-10k_Train_008226 +GOT-10k_Train_008230 +GOT-10k_Train_008231 +GOT-10k_Train_008236 +GOT-10k_Train_008239 +GOT-10k_Train_008241 +GOT-10k_Train_008243 +GOT-10k_Train_008249 +GOT-10k_Train_008250 +GOT-10k_Train_008273 +GOT-10k_Train_008278 +GOT-10k_Train_008291 +GOT-10k_Train_008310 +GOT-10k_Train_008311 +GOT-10k_Train_008317 +GOT-10k_Train_008319 +GOT-10k_Train_008331 +GOT-10k_Train_008332 +GOT-10k_Train_008344 +GOT-10k_Train_008369 +GOT-10k_Train_008377 +GOT-10k_Train_008386 +GOT-10k_Train_008392 +GOT-10k_Train_008396 +GOT-10k_Train_008432 +GOT-10k_Train_008438 +GOT-10k_Train_008439 +GOT-10k_Train_008440 +GOT-10k_Train_008442 +GOT-10k_Train_008443 +GOT-10k_Train_008455 +GOT-10k_Train_008471 +GOT-10k_Train_008484 +GOT-10k_Train_008490 +GOT-10k_Train_008492 +GOT-10k_Train_008499 +GOT-10k_Train_008502 +GOT-10k_Train_008507 +GOT-10k_Train_008520 +GOT-10k_Train_008525 +GOT-10k_Train_008568 +GOT-10k_Train_008587 +GOT-10k_Train_008589 +GOT-10k_Train_008591 +GOT-10k_Train_008606 +GOT-10k_Train_008612 +GOT-10k_Train_008623 +GOT-10k_Train_008628 +GOT-10k_Train_008633 +GOT-10k_Train_008634 +GOT-10k_Train_008645 +GOT-10k_Train_008656 +GOT-10k_Train_008668 +GOT-10k_Train_008670 +GOT-10k_Train_008702 +GOT-10k_Train_008714 +GOT-10k_Train_008723 +GOT-10k_Train_008731 +GOT-10k_Train_008732 +GOT-10k_Train_008734 +GOT-10k_Train_008747 +GOT-10k_Train_008787 +GOT-10k_Train_008794 +GOT-10k_Train_008805 +GOT-10k_Train_008829 +GOT-10k_Train_008837 +GOT-10k_Train_008838 +GOT-10k_Train_008853 +GOT-10k_Train_008878 +GOT-10k_Train_008879 +GOT-10k_Train_008880 +GOT-10k_Train_008891 +GOT-10k_Train_008895 +GOT-10k_Train_008907 +GOT-10k_Train_008909 +GOT-10k_Train_008922 +GOT-10k_Train_008935 +GOT-10k_Train_008939 +GOT-10k_Train_008972 +GOT-10k_Train_008975 +GOT-10k_Train_008976 +GOT-10k_Train_009002 +GOT-10k_Train_009031 +GOT-10k_Train_009040 +GOT-10k_Train_009052 +GOT-10k_Train_009056 +GOT-10k_Train_009057 +GOT-10k_Train_009066 +GOT-10k_Train_009076 +GOT-10k_Train_009103 +GOT-10k_Train_009115 +GOT-10k_Train_009117 +GOT-10k_Train_009127 +GOT-10k_Train_009137 +GOT-10k_Train_009145 +GOT-10k_Train_009150 +GOT-10k_Train_009155 +GOT-10k_Train_009156 +GOT-10k_Train_009160 +GOT-10k_Train_009179 +GOT-10k_Train_009181 +GOT-10k_Train_009196 +GOT-10k_Train_009203 +GOT-10k_Train_009216 +GOT-10k_Train_009219 +GOT-10k_Train_009222 +GOT-10k_Train_009224 +GOT-10k_Train_009229 +GOT-10k_Train_009231 +GOT-10k_Train_009235 +GOT-10k_Train_009242 +GOT-10k_Train_009263 +GOT-10k_Train_009265 +GOT-10k_Train_009280 +GOT-10k_Train_009282 +GOT-10k_Train_009300 +GOT-10k_Train_009301 +GOT-10k_Train_009329 +GOT-10k_Train_009332 +GOT-10k_Train_009334 \ No newline at end of file diff --git a/Stark/lib/train/data_specs/got10k_vot_train_split.txt b/Stark/lib/train/data_specs/got10k_vot_train_split.txt new file mode 100755 index 0000000..f84e045 --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_vot_train_split.txt @@ -0,0 +1,7086 @@ +3784 +8998 +1631 +8277 +8358 +2338 +2988 +8302 +2662 +2663 +2825 +7447 +4781 +2218 +5860 +2819 +8075 +5391 +116 +3606 +7976 +7941 +1024 +4519 +1970 +557 +8579 +6908 +993 +7204 +1991 +3674 +8781 +6840 +5 +3225 +3763 +8688 +6778 +5777 +4794 +2744 +8126 +3864 +1733 +2923 +6829 +683 +2081 +1831 +2404 +1459 +2741 +5972 +7462 +2654 +103 +2174 +2989 +2506 +2766 +5912 +3295 +3986 +609 +4895 +6673 +801 +1098 +1602 +2490 +8476 +3186 +4784 +4270 +1812 +4226 +2267 +8873 +6544 +6112 +2381 +4752 +753 +3776 +6511 +6016 +2559 +7369 +5866 +563 +7731 +1105 +5603 +50 +4238 +2208 +8725 +4994 +4719 +1444 +8807 +7298 +8760 +8173 +2332 +4131 +1065 +8562 +3992 +4024 +2188 +9095 +6765 +1707 +6105 +6922 +5362 +1486 +7898 +4135 +6574 +998 +6565 +8127 +8927 +2544 +4365 +768 +3535 +3875 +6808 +2931 +487 +4451 +2470 +8111 +3493 +7338 +8281 +6390 +1271 +4373 +3667 +3494 +3757 +2966 +7840 +7827 +3300 +6261 +4163 +2217 +6549 +7236 +9136 +1857 +6691 +3470 +6271 +807 +516 +9311 +6098 +3144 +8420 +5425 +5694 +2643 +6696 +6072 +7285 +3781 +903 +8522 +6092 +5979 +2622 +2529 +855 +3420 +3261 +8953 +7866 +2492 +3157 +359 +1520 +2642 +7452 +759 +36 +8931 +1744 +4350 +1089 +9199 +1889 +1908 +4868 +4498 +1968 +3273 +7413 +4114 +5584 +4874 +1427 +5211 +7618 +1542 +1353 +8158 +4168 +3200 +6345 +8560 +5619 +5953 +3158 +8849 +5831 +1411 +8103 +6539 +7397 +1006 +5450 +3119 +4274 +5352 +4571 +2319 +4976 +902 +1814 +2651 +3299 +3398 +982 +2428 +5793 +1346 +7057 +3737 +7329 +4449 +2110 +7405 +1773 +958 +3901 +4127 +8234 +2994 +7066 +1289 +2995 +5871 +3556 +9085 +846 +2366 +585 +5516 +5230 +3481 +2732 +6658 +7423 +1855 +6384 +3554 +5823 +4948 +7058 +4667 +5377 +2503 +7694 +9191 +9144 +655 +3409 +62 +8019 +8970 +2323 +5750 +3178 +6548 +7501 +3280 +343 +2171 +8397 +1367 +8611 +6118 +6603 +7182 +9048 +7733 +7141 +3335 +4845 +5449 +3467 +6250 +163 +5168 +2040 +3609 +8352 +3426 +8567 +769 +187 +6151 +6437 +7028 +3970 +9146 +5028 +7492 +1661 +2815 +2469 +2563 +3814 +8430 +4305 +3479 +5678 +4132 +1211 +5459 +4814 +545 +4556 +238 +2724 +1260 +2581 +4632 +4313 +380 +1209 +5447 +3032 +7942 +8943 +806 +2432 +6130 +4314 +2131 +9045 +6531 +5706 +6747 +7724 +2017 +3292 +5469 +2743 +424 +4233 +8619 +5192 +4516 +9324 +3537 +9152 +8058 +7526 +8711 +1949 +5982 +6702 +7027 +6388 +7012 +328 +2130 +452 +306 +7669 +3134 +5761 +3703 +44 +4189 +695 +5224 +9215 +5644 +3143 +5443 +2348 +2328 +4725 +1418 +7810 +5759 +7226 +4535 +4385 +5397 +7249 +3204 +385 +2371 +2738 +3636 +9033 +2246 +2680 +6940 +4310 +2054 +9250 +9080 +4568 +5586 +4469 +2038 +3410 +7900 +4332 +6108 +678 +3319 +9079 +1054 +4048 +4751 +1320 +6890 +7931 +1398 +4349 +5299 +5025 +7932 +5738 +7787 +4590 +4020 +1274 +2488 +8497 +3372 +8965 +3219 +799 +3664 +6500 +7093 +4362 +6205 +4244 +5945 +6434 +2031 +2684 +6632 +4588 +8271 +3232 +5782 +2904 +7200 +3632 +5435 +8203 +3480 +4786 +7579 +3351 +1921 +798 +3646 +3094 +4359 +1654 +5975 +376 +5965 +780 +6738 +3185 +2133 +6248 +5996 +2834 +531 +5688 +2448 +7925 +7974 +5924 +6401 +5778 +6594 +5442 +8336 +4522 +3770 +6340 +6328 +4946 +4161 +2954 +2588 +8465 +2885 +1606 +5787 +3407 +3121 +7310 +1413 +1932 +4787 +2579 +3325 +508 +5610 +6480 +4290 +479 +3792 +6628 +2545 +6972 +2665 +6730 +3547 +6845 +3540 +8993 +1052 +2235 +8356 +3403 +8818 +8260 +572 +4159 +1180 +5348 +7948 +2676 +3539 +4866 +6422 +8365 +3217 +1310 +2059 +9177 +1419 +2283 +8892 +8162 +1212 +6277 +3725 +7806 +6149 +7874 +718 +6888 +7118 +277 +656 +8763 +8289 +4759 +5854 +8659 +3145 +5981 +1881 +5799 +6947 +1609 +6396 +2631 +318 +2550 +6132 +1736 +7816 +4304 +8133 +6698 +7779 +7732 +7642 +7242 +711 +9262 +8033 +7440 +1913 +5480 +5570 +8594 +8772 +4654 +8974 +6128 +6183 +1071 +8449 +2142 +2298 +524 +1695 +820 +4053 +1856 +8641 +217 +1063 +9286 +3152 +221 +5461 +1270 +2006 +7164 +1199 +6951 +5604 +5400 +5309 +3498 +6407 +6661 +7097 +8165 +5169 +3852 +7070 +5702 +4344 +6648 +6904 +3272 +7119 +5795 +2365 +2659 +353 +5444 +1924 +2098 +2972 +6006 +5865 +8740 +7856 +5841 +598 +836 +1147 +931 +8897 +0 +6049 +1837 +865 +1871 +6116 +6831 +5773 +3587 +303 +1883 +2163 +3070 +1308 +7953 +6909 +853 +7301 +3279 +123 +7186 +3194 +5133 +1931 +4622 +4891 +5722 +5693 +8 +2339 +6596 +71 +379 +4506 +4370 +1238 +2707 +3344 +4254 +8767 +1726 +325 +4148 +5438 +5357 +548 +1332 +6824 +2290 +2335 +2594 +2315 +3389 +3885 +2621 +4116 +7412 +7222 +4894 +8595 +2000 +4978 +4721 +6444 +3796 +9321 +2236 +6409 +1523 +1468 +9249 +8270 +2341 +2874 +174 +4502 +4703 +9034 +9108 +5451 +2619 +9158 +490 +6540 +1466 +2962 +8771 +2712 +4539 +1581 +5638 +9246 +4308 +4363 +4647 +4470 +1636 +1311 +6560 +7519 +8027 +9217 +6364 +3779 +4822 +3563 +5896 +6655 +1524 +2846 +3137 +141 +1887 +6567 +8921 +4671 +6052 +8445 +8699 +7349 +3553 +2117 +7651 +5034 +5383 +649 +3818 +9022 +8414 +1012 +8159 +5081 +8571 +4765 +9135 +4361 +4073 +9142 +727 +2835 +8229 +3989 +4490 +4923 +5477 +1638 +3643 +9044 +2230 +499 +7166 +3172 +8431 +8401 +1470 +6356 +8817 +927 +4212 +2152 +3812 +4949 +1219 +1538 +3029 +6481 +9042 +7775 +7742 +423 +2085 +7715 +4541 +9061 +5916 +7420 +7406 +7046 +7808 +4911 +8804 +6927 +8820 +3264 +300 +2979 +252 +4407 +3383 +4688 +8504 +6723 +26 +3837 +2489 +4137 +8209 +229 +6490 +2364 +9016 +1763 +1728 +338 +8335 +9063 +2791 +641 +5454 +4581 +4548 +2840 +8508 +3463 +7231 +7619 +2560 +1755 +6201 +165 +6279 +5806 +6867 +5890 +2396 +3416 +1981 +6073 +5872 +3045 +4182 +7607 +4414 +2998 +6553 +7139 +5624 +3666 +723 +5110 +6932 +8200 +2222 +8399 +1041 +4138 +1594 +3569 +9253 +393 +7940 +8004 +1475 +5393 +1107 +2597 +878 +9309 +7576 +5250 +3142 +2015 +571 +3921 +1255 +7080 +893 +2160 +1355 +82 +9153 +8583 +4085 +4644 +7196 +9165 +3558 +4550 +6374 +7826 +8602 +4146 +9257 +6083 +874 +8383 +3731 +3374 +3653 +8222 +7344 +470 +1813 +6871 +7245 +6866 +3998 +7433 +276 +1915 +1988 +8168 +2518 +2686 +831 +6143 +5205 +8718 +1703 +7729 +2077 +7983 +8450 +1195 +9232 +507 +7989 +6974 +5828 +8655 +6679 +5245 +7783 +5886 +9098 +6491 +8782 +3525 +6542 +131 +8110 +9186 +9074 +4933 +9035 +2607 +2057 +6273 +2711 +5829 +3382 +2696 +3043 +2048 +619 +2499 +5295 +1162 +7807 +3694 +2194 +3149 +1940 +7934 +840 +3592 +8237 +4731 +1324 +8486 +8726 +8573 +2928 +9078 +2272 +2564 +1370 +5911 +7434 +8026 +407 +7546 +2004 +5849 +7887 +3425 +1118 +926 +3430 +5902 +2282 +2334 +129 +1372 +4842 +6473 +4382 +1028 +415 +8269 +6910 +2796 +3038 +5735 +5080 +2852 +6306 +8842 +9188 +3637 +1066 +532 +5485 +2838 +6753 +9008 +7984 +2816 +8819 +7103 +5977 +5044 +2064 +2599 +3249 +6446 +6638 +852 +1724 +3368 +892 +3250 +8258 +7962 +4300 +1616 +167 +8855 +2090 +4424 +879 +5136 +5350 +2635 +7828 +8506 +63 +3847 +3676 +1705 +6745 +1263 +5020 +1888 +7036 +1033 +3914 +5433 +3905 +4641 +228 +4801 +3766 +8085 +643 +6914 +3013 +5657 +3696 +1590 +8282 +2403 +416 +911 +3849 +4215 +1120 +5490 +296 +2306 +3140 +3742 +4819 +6153 +6414 +760 +3000 +7498 +7108 +6429 +3031 +5314 +751 +3357 +5808 +7505 +98 +7652 +4027 +6257 +1799 +8577 +4969 +9163 +2025 +6061 +4026 +588 +4961 +4940 +7152 +538 +706 +2802 +8983 +3375 +1246 +6593 +5837 +1789 +7939 +4997 +5939 +2411 +6133 +199 +7593 +1702 +5406 +6082 +2912 +6109 +100 +8149 +5470 +2807 +3362 +5621 +6019 +9241 +9268 +7703 +7967 +5458 +5492 +6729 +4577 +106 +3774 +979 +7082 +4610 +1853 +9003 +9292 +2867 +6262 +2245 +3460 +1557 +4796 +2658 +5769 +6985 +421 +7990 +3289 +1540 +9316 +2251 +6896 +5947 +4965 +4480 +963 +9047 +7824 +3976 +6210 +7018 +7179 +5016 +7789 +6102 +6828 +7659 +9109 +9071 +8115 +7628 +7110 +16 +7513 +835 +939 +2351 +2322 +4945 +560 +6837 +6094 +6475 +7901 +3 +771 +8029 +3135 +8044 +7127 +3741 +5156 +7030 +113 +3747 +7042 +5232 +5225 +3002 +4747 +5379 +4886 +7192 +4184 +1896 +1834 +8689 +3665 +2957 +6913 +8009 +4851 +6420 +828 +8884 +8815 +3198 +8008 +194 +6251 +3303 +3934 +395 +1285 +4169 +1648 +1347 +3600 +4631 +509 +211 +6230 +7241 +2219 +2582 +8353 +7790 +7583 +9004 +6942 +1704 +8051 +2981 +5511 +6182 +7088 +1699 +1222 +6189 +1528 +5197 +6221 +7893 +7773 +8766 +2942 +8021 +614 +1786 +400 +133 +556 +5237 +3727 +1440 +3873 +8448 +6285 +8696 +8800 +4009 +3386 +4847 +5685 +9093 +5895 +6863 +4260 +8405 +8417 +7116 +255 +3223 +4737 +7852 +814 +710 +1094 +6103 +5809 +5882 +6336 +4974 +1499 +2806 +3744 +2664 +2436 +4482 +8665 +8918 +1076 +8676 +5725 +9248 +4755 +1447 +9328 +5500 +78 +2653 +792 +6854 +6093 +6172 +3378 +4492 +5529 +5476 +3846 +1391 +383 +4289 +3883 +2648 +3265 +2525 +5402 +4599 +6870 +6877 +4413 +2464 +8519 +2521 +1839 +5822 +5664 +7257 +5375 +6852 +6764 +5182 +8914 +3015 +8509 +3080 +4562 +8979 +6643 +8601 +6096 +4812 +5246 +7862 +527 +7849 +6737 +12 +2468 +7961 +275 +27 +5932 +3840 +7341 +4996 +8564 +2154 +6138 +7831 +4442 +757 +4464 +1170 +2568 +19 +323 +7675 +3441 +2067 +9027 +2486 +4379 +4744 +1737 +7563 +301 +3907 +4742 +6857 +1221 +9284 +8458 +2897 +1526 +5345 +4423 +6246 +8578 +3711 +4986 +4785 +3997 +7311 +4788 +8387 +2041 +2608 +6031 +3293 +541 +773 +8473 +2501 +5667 +804 +483 +1639 +696 +6060 +5429 +5762 +1527 +7342 +6225 +7895 +381 +8030 +8362 +4734 +3526 +9273 +2039 +5084 +875 +6905 +8968 +5275 +3052 +650 +7509 +232 +2595 +3631 +1810 +4355 +8315 +8908 +1777 +4834 +3164 +2336 +1543 +6212 +8346 +3024 +3719 +1242 +6265 +3133 +6150 +6358 +3316 +4089 +1647 +4629 +7117 +2596 +5366 +6371 +2209 +1428 +1158 +7648 +8765 +802 +153 +4639 +3657 +9320 +3294 +2617 +5052 +6305 +3227 +8784 +5868 +6716 +1671 +178 +2703 +954 +3254 +2262 +5743 +8647 +6393 +7706 +6604 +3728 +6978 +7474 +8754 +2740 +6038 +1491 +8814 +2080 +2358 +5944 +1164 +9259 +4518 +7343 +5748 +3897 +923 +5967 +2677 +3503 +1202 +4966 +6634 +1962 +9096 +9064 +977 +4049 +1464 +658 +536 +3402 +8064 +1309 +259 +8122 +910 +224 +6152 +7142 +6070 +8411 +9214 +9312 +8325 +6192 +626 +6025 +6240 +8708 +4630 +6777 +1075 +8906 +408 +9269 +6236 +9067 +2324 +156 +3136 +7878 +7308 +4335 +2065 +3845 +4453 +3356 +1450 +371 +7219 +5171 +201 +8642 +2099 +477 +1603 +8339 +7430 +3061 +235 +1133 +8474 +8653 +989 +4569 +9092 +8347 +3102 +1743 +9086 +5140 +7438 +1530 +2460 +7646 +5071 +5430 +6944 +610 +2803 +1448 +4696 +6156 +4386 +4248 +4256 +994 +805 +8011 +8276 +8999 +4956 +1712 +2795 +7553 +6436 +2158 +9083 +3184 +5784 +4428 +612 +5288 +6222 +1365 +5074 +6848 +575 +5213 +2175 +4240 +351 +2086 +2656 +5150 +9255 +8189 +7735 +1261 +1344 +4097 +8674 +2984 +4235 +5998 +6488 +537 +1267 +7486 +7124 +6245 +7955 +7337 +5436 +1194 +209 +1710 +7906 +4357 +4139 +5679 +2584 +2854 +1004 +8246 +8586 +5087 +4926 +6637 +3197 +7757 +6502 +1248 +990 +3928 +2770 +2751 +1020 +6426 +6839 +2671 +3871 +9212 +4179 +3394 +10 +5861 +5316 +6869 +2985 +8905 +8559 +4457 +2480 +2313 +4100 +6835 +7799 +7890 +2785 +5468 +7302 +5862 +1803 +3171 +717 +7053 +1655 +4489 +2522 +2921 +8555 +1984 +895 +8949 +1305 +738 +7606 +112 +3042 +1325 +437 +3167 +3340 +511 +3689 +8982 +69 +4421 +550 +8685 +3147 +8956 +3166 +7023 +2014 +3573 +3880 +4045 +2069 +6051 +702 +6664 +8418 +6181 +4853 +4166 +7022 +7418 +3605 +7172 +5031 +4589 +7858 +6586 +6351 +8334 +7504 +634 +3759 +1890 +890 +6959 +5085 +4919 +2161 +1191 +256 +3610 +7079 +3427 +4071 +7323 +2982 +7263 +7444 +4251 +5846 +4864 +3649 +4311 +8120 +4582 +6373 +2805 +4872 +4869 +5867 +2670 +7099 +30 +8933 +930 +7919 +7261 +5289 +7449 +7772 +3613 +3196 +474 +205 +841 +2611 +6185 +3088 +409 +7239 +5938 +7871 +1343 +6705 +1027 +5596 +2199 +9113 +5471 +6134 +838 +8359 +4061 +1474 +3229 +270 +4245 +1979 +1517 +8652 +4006 +6137 +4693 +2528 +6996 +2926 +5798 +2477 +2549 +3341 +6014 +4479 +2861 +4208 +5175 +5174 +5118 +3736 +5463 +1588 +2327 +8380 +7982 +1058 +4586 +6608 +7985 +1822 +3628 +549 +1811 +2601 +4608 +2540 +6659 +3859 +307 +3767 +8167 +505 +4366 +5520 +461 +1933 +2401 +8106 +2055 +7844 +8544 +4797 +7419 +6686 +7670 +6039 +5672 +5141 +6543 +206 +5252 +4718 +888 +1601 +3218 +5114 +713 +4022 +4419 +6708 +397 +425 +6612 +5057 +1729 +4729 +4080 +1034 +534 +5598 +9218 +2424 +329 +4154 +1597 +109 +8823 +9038 +8437 +3307 +128 +8032 +1412 +7333 +8762 +8851 +8865 +468 +3808 +3064 +8798 +7052 +7767 +1086 +2162 +6566 +2109 +3439 +6122 +3642 +7696 +8610 +5279 +1808 +8687 +817 +6066 +3640 +6015 +7601 +4855 +6017 +87 +7071 +7268 +3614 +6084 +6117 +6924 +9102 +2829 +375 +8724 +2095 +22 +1541 +2970 +633 +139 +451 +4521 +179 +1396 +3876 +5824 +8020 +426 +4982 +4172 +190 +4859 +1455 +3110 +3323 +9104 +858 +6719 +6428 +4495 +8551 +2141 +3984 +3066 +67 +4299 +5821 +8444 +6581 +6097 +7090 +7781 +8944 +3085 +2114 +5355 +8901 +1461 +3301 +422 +7000 +4820 +5790 +1379 +7536 +8736 +8991 +5241 +1698 +1294 +1753 +196 +2987 +8680 +4144 +8639 +6441 +8255 +8156 +3677 +6385 +6520 +3760 +6001 +1144 +5478 +7394 +8057 +5018 +4232 +5235 +6844 +3111 +8802 +949 +7843 +573 +2278 +6801 +7629 +2714 +5105 +6946 +2697 +5315 +1571 +8677 +2537 +4374 +3833 +7820 +3750 +2033 +6526 +3884 +8706 +7195 +3603 +3001 +6284 +5873 +5718 +8576 +8457 +3589 +5839 +459 +6342 +8729 +6933 +607 +6053 +8228 +3773 +1805 +6365 +5142 +6069 +1389 +9026 +570 +4614 +5533 +2821 +1897 +819 +4060 +5905 +6842 +5446 +1277 +4303 +2836 +934 +1014 +7822 +7494 +665 +5881 +3328 +4664 +315 +1315 +1462 +8616 +7725 +5749 +1730 +8184 +4567 +5065 +8867 +1304 +3669 +9192 +410 +8177 +6710 +1210 +2329 +3911 +1899 +7686 +3315 +6180 +3116 +5341 +4394 +8337 +9182 +5715 +2172 +2782 +3715 +9195 +7960 +4890 +8294 +2337 +8014 +3353 +7475 +2193 +8831 +4200 +4653 +6196 +6957 +3063 +8959 +8973 +6529 +3457 +5274 +8002 +6823 +6154 +5561 +1780 +9318 +7657 +1758 +6503 +7678 +3274 +1625 +4327 +3236 +8575 +4707 +4331 +1494 +8756 +3174 +1074 +8116 +8295 +3048 +3752 +6050 +8003 +9175 +4674 +1642 +2556 +6166 +7165 +8441 +3990 +1640 +1778 +7500 +8304 +1395 +4315 +5949 +3364 +242 +5763 +1036 +2430 +8131 +411 +6267 +2045 +6606 +899 +8065 +5779 +5616 +2107 +5408 +2980 +6310 +5776 +4328 +821 +3251 +2354 +7076 +5313 +79 +3959 +5677 +7545 +160 +6790 +6859 +3659 +6770 +1106 +8846 +956 +7472 +2050 +8099 +4795 +8053 +9293 +7037 +1646 +9307 +5322 +5332 +2708 +8977 +917 +2419 +184 +2105 +1578 +3923 +5780 +1903 +2512 +429 +493 +4972 +445 +8286 +320 +8300 +617 +3413 +4459 +525 +5631 +6314 +5157 +5300 +8545 +182 +1031 +4429 +2495 +1534 +3099 +3916 +3738 +535 +2119 +177 +1838 +2159 +4099 +8285 +5172 +8540 +6020 +7683 +3073 +3115 +3087 +2416 +1894 +5942 +3597 +5834 +2007 +43 +1779 +4174 +2023 +2546 +2429 +9006 +436 +4214 +3693 +5426 +6767 +5903 +4368 +2170 +5051 +7490 +2859 +5035 +7835 +5372 +7122 +925 +3253 +6338 +8393 +4093 +5848 +7588 +2683 +8049 +5403 +5894 +8745 +8550 +2941 +3484 +9029 +4461 +8022 +725 +3030 +1975 +5623 +2415 +1957 +6141 +9278 +3226 +3062 +5670 +7326 +8759 +8496 +6619 +8187 +8262 +6199 +951 +668 +2388 +4698 +8240 +2851 +871 +4988 +9084 +9089 +3162 +1167 +8244 +5227 +6461 +2831 +776 +5010 +5770 +5282 +3574 +5102 +1278 +2281 +5455 +4628 +4663 +9119 +7487 +8746 +4889 +1175 +102 +2386 +8940 +5566 +53 +8833 +1918 +321 +6786 +6861 +4358 +2771 +7467 +975 +4777 +605 +3543 +2600 +7584 +9299 +4530 +7328 +183 +4761 +7543 +304 +1196 +4623 +5519 +1953 +533 +5989 +7590 +7428 +6346 +6162 +1946 +6260 +4405 +5676 +8924 +7171 +8409 +1866 +6379 +3411 +2387 +3051 +7398 +154 +1185 +6442 +6004 +1611 +2165 +9018 +8323 +616 +3995 +8952 +1533 +7853 +789 +4991 +3675 +7456 +5752 +175 +7556 +4195 +907 +2248 +8467 +1017 +7968 +3304 +1666 +4942 +3867 +4802 +6357 +4621 +887 +6213 +5261 +1336 +521 +8928 +7864 +4792 +6742 +157 +1593 +823 +7235 +5303 +5633 +1100 +8047 +5993 +1460 +6714 +1630 +6440 +6307 +3608 +292 +5974 +8301 +8342 +2720 +4583 +2757 +7315 +833 +4466 +4236 +1282 +5273 +2149 +2380 +8119 +7167 +5076 +3596 +2650 +8980 +3421 +1356 +1954 +7823 +1172 +2226 +1941 +6136 +7274 +2256 +4928 +324 +4410 +4579 +1061 +7113 +486 +862 +6956 +2873 +1465 +6113 +8225 +8512 +6806 +272 +6008 +1241 +88 +5662 +3555 +689 +8733 +2812 +7453 +6282 +420 +2471 +4477 +7495 +1445 +594 +6939 +1564 +8704 +8590 +7992 +7374 +5796 +9298 +4213 +5713 +5864 +326 +5513 +402 +464 +608 +1951 +8640 +3347 +3459 +4162 +2690 +7478 +5856 +5240 +3022 +602 +5547 +1798 +1345 +9276 +599 +3673 +3277 +1635 +8625 +1567 +5928 +636 +5671 +2896 +3477 +412 +7575 +4201 +685 +4760 +1229 +4275 +8960 +3123 +4471 +5941 +3355 +3999 +7157 +6354 +6850 +8783 +1943 +6769 +7330 +8721 +8477 +1381 +848 +778 +6408 +2644 +5817 +1441 +1723 +2144 +2776 +2368 +367 +8839 +8749 +5353 +3148 +9114 +1233 +9228 +8857 +2895 +1286 +200 +6755 +5125 +5857 +1657 +7658 +5000 +942 +7020 +586 +784 +7078 +6194 +8658 +8957 +9325 +1851 +8911 +7004 +1186 +8824 +2999 +561 +7639 +4316 +5086 +3187 +7912 +2624 +9183 +8487 +5089 +8475 +7554 +4031 +6297 +6059 +5329 +115 +2058 +7650 +7121 +2485 +7805 +2241 +7713 +4352 +2409 +1026 +2745 +4549 +5124 +5201 +6556 +6617 +9091 +3945 +8402 +5648 +5257 +4901 +7750 +6131 +6027 +6352 +4625 +1254 +5498 +3720 +8261 +3939 +5576 +3685 +6713 +8472 +991 +8354 +5655 +5997 +1029 +7506 +2575 +2990 +4898 +7402 +3290 +5388 +6715 +8235 +5361 +4970 +1363 +3338 +9014 +5358 +635 +1193 +3705 +6334 +7666 +5270 +6368 +8604 +3564 +1937 +2481 +1341 +721 +2100 +3958 +6551 +3813 +2592 +7980 +2357 +8761 +8910 +8693 +1204 +489 +4827 +8024 +7832 +3895 +9068 +8067 +1708 +1111 +8963 +1902 +9251 +5719 +9143 +5537 +9169 +5365 +1840 +485 +4456 +1169 +3271 +6886 +9140 +7173 +6003 +1659 +1807 +8371 +2439 +274 +3448 +6623 +347 +2103 +3400 +2106 +9073 +8169 +3687 +3305 +4416 +8454 +6635 +332 +2433 +1944 +6509 +7770 +1880 +6610 +9331 +302 +418 +4219 +1333 +2350 +8424 +4883 +6580 +6722 +1669 +8470 +2571 +513 +3810 +7049 +6332 +7363 +3532 +8456 +2097 +297 +8841 +7180 +714 +1587 +5234 +7372 +660 +8503 +1668 +8847 +1101 +7275 +3336 +6460 +722 +7782 +3947 +502 +4258 +2132 +1835 +181 +3841 +427 +3446 +2551 +8324 +6963 +4284 +7297 +7577 +3399 +9148 +8213 +5656 +851 +657 +2446 +6992 +976 +1108 +2681 +3237 +8582 +377 +5969 +5287 +9209 +8523 +7178 +7833 +6175 +2126 +3023 +5090 +7491 +6640 +6077 +2221 +2780 +1694 +4094 +144 +3203 +7123 +749 +3625 +3848 +980 +2270 +7819 +3672 +7689 +7203 +2718 +1714 +3802 +3851 +4224 +7237 +7998 +7207 +4106 +9036 +1046 +5070 +4592 +6056 +693 +1328 +3309 +2629 +2736 +202 +388 +7886 +4417 +8786 +8822 +4035 +5505 +1192 +4388 +8941 +5019 +7538 +6732 +6389 +5923 +1405 +3278 +3917 +1688 +8374 +443 +4037 +9099 +5190 +4177 +9310 +7747 +4348 +7197 +4844 +4998 +5609 +4345 +29 +3332 +8648 +4107 +346 +2577 +3941 +1215 +8252 +4706 +2675 +3790 +7459 +6164 +1149 +6687 +582 +3139 +3882 +4034 +1861 +4701 +8757 +8801 +1823 +4528 +4789 +143 +4746 +9234 +3866 +9245 +1911 +1366 +4393 +2061 +1959 +6967 +3138 +7382 +6237 +845 +80 +6911 +7163 +5229 +4736 +8738 +33 +8543 +357 +3193 +7262 +4448 +6793 +3321 +7569 +6411 +7692 +7340 +1417 +5847 +3836 +2678 +1188 +8727 +8615 +7417 +5771 +3170 +8061 +2935 +8263 +8257 +6883 +1276 +1239 +812 +6258 +3922 +8117 +3039 +603 +8554 +7573 +2787 +3445 +5115 +3478 +962 +3961 +6570 +7722 +216 +2797 +5154 +2530 +4904 +2405 +7542 +4021 +3252 +5370 +9302 +236 +4532 +1361 +3373 +1716 +2183 +1583 +3783 +868 +1687 +8925 +6198 +8208 +6367 +7603 +882 +3469 +1645 +7654 +1176 +4231 +150 +7997 +5456 +7031 +4375 +8840 +5634 +6945 +705 +4774 +3822 +7148 +1922 +8459 +6249 +8713 +6197 +8599 +6071 +6756 +1634 +950 +5640 +7749 +5920 +6622 +4783 +7837 +7479 +7229 +3919 +1797 +5272 +8945 +4908 +5439 +6903 +5833 +6930 +8197 +9261 +1711 +5483 +4285 +8852 +7409 +8971 +7534 +7792 +2444 +7496 +8063 +1665 +248 +3894 +4585 +66 +4850 +1240 +7511 +7524 +9258 +2075 +3979 +4714 +7592 +965 +2919 +1842 +8013 +4750 +2344 +6155 +3468 +31 +2087 +1599 +1573 +5883 +7613 +195 +3749 +644 +2189 +8779 +8743 +9005 +8081 +1040 +7785 +5820 +8830 +5495 +4867 +2710 +491 +7153 +6217 +4741 +1761 +5484 +5474 +6916 +7252 +1739 +8930 +6647 +5198 +4903 +8488 +7366 +2774 +2726 +2385 +7625 +3179 +8845 +6600 +399 +6810 +3447 +6684 +4915 +8368 +1867 +2325 +2101 +1335 +7734 +7437 +7025 +4000 +6897 +1408 +7154 +5013 +2204 +9233 +3817 +1877 +9161 +2197 +3390 +280 +1892 +1612 +7753 +2801 +7246 +7909 +6229 +9314 +8407 +1436 +3879 +6432 +5326 +5327 +8535 +7910 +7745 +5545 +7916 +207 +1783 +6158 +8517 +7361 +8070 +6430 +119 +6146 +4183 +1083 +7385 +4497 +9133 +1686 +3765 +595 +8046 +4418 +4043 +2361 +7915 +9149 +1717 +1141 +6375 +1018 +5602 +1262 +7485 +9178 +6629 +3339 +8934 +4648 +7988 +6252 +3440 +864 +5418 +3874 +7280 +6191 +8388 +4323 +6792 +2232 +7228 +8684 +7813 +6187 +6678 +3177 +3534 +4953 +4402 +7739 +6319 +2414 +8700 +5946 +8238 +6917 +4167 +4618 +2268 +3081 +1247 +4001 +8580 +7636 +3101 +2195 +1559 +3714 +7188 +6028 +7530 +2828 +1977 +3238 +2340 +110 +3247 +7532 +7541 +924 +1632 +4487 +6447 +4944 +6347 +2285 +8087 +5452 +91 +1166 +162 +5185 +7933 +4743 +1627 +7259 +8620 +8207 +5845 +9011 +5525 +4269 +4700 +1824 +8186 +8872 +8299 +3957 +8242 +4558 +6439 +2666 +6958 +8112 +5121 +8806 +6170 +7688 +3486 +2082 +7436 +2778 +1096 +786 +2206 +5170 +1443 +6030 +3312 +9151 +8485 +6404 +8498 +2883 +8961 +2280 +8341 +2809 +2445 +809 +8298 +8643 +8316 +6853 +1572 +3215 +3938 +2249 +6515 +1337 +8328 +7712 +1429 +4117 +5441 +3230 +4152 +7225 +3513 +6953 +1507 +348 +3639 +5739 +2673 +1550 +6301 +1652 +8453 +204 +6833 +2200 +5217 +1854 +4711 +7368 +4572 +4032 +7531 +1013 +3634 +2875 +6058 +8307 +7609 +1766 +904 +667 +5410 +6578 +3601 +1664 +3233 +7390 +8178 +4486 +4427 +4876 +9166 +2772 +6295 +5001 +5296 +3371 +6518 +6327 +854 +8288 +1912 +5927 +6202 +5814 +9032 +1059 +3214 +6547 +7038 +5781 +4390 +6114 +1622 +4318 +5803 +5984 +736 +3561 +6554 +5045 +4277 +7386 +9081 +8462 +2034 +4955 +2701 +932 +7758 +7176 +9205 +3077 +3803 +3562 +8054 +7946 +295 +1843 +7728 +1629 +7768 +2971 +431 +9285 +2513 +1116 +3656 +4529 +5758 +6339 +8398 +816 +4153 +2536 +1826 +7870 +8113 +7730 +7101 +6555 +9256 +6774 +1072 +4578 +2598 +3604 +5880 +861 +3350 +3117 +4685 +4334 +5165 +7224 +4066 +4253 +4447 +3815 +5038 +253 +3658 +330 +3967 +6443 +2143 +7336 +6135 +2734 +8390 +4655 +7800 +1399 +1173 +5618 +2822 +4431 +2443 +1568 +3909 +1974 +2496 +4772 +5164 +2138 +2864 +3799 +3924 +4882 +8245 +1585 +5528 +5692 +5730 +5832 +137 +3175 +2894 +2062 +2752 +4028 +2113 +5411 +2647 +730 +3758 +1667 +9303 +6653 +3698 +3968 +3053 +503 +2150 +4645 +2257 +4627 +8303 +7966 +8742 +4692 +5901 +8547 +2277 +5546 +986 +370 +4697 +8712 +4804 +1182 +6650 +7290 +3487 +2814 +5668 +7567 +5333 +4164 +3084 +8896 +3888 +6537 +17 +6882 +3531 +704 +1037 +8866 +5263 +6758 +3762 +1393 +3824 +5112 +214 +1439 +5700 +8932 +1306 +5011 +6928 +5173 +4098 +1132 +7352 +4778 +7723 +1368 +2390 +670 +2685 +5855 +1772 +6380 +3853 +940 +5424 +6091 +1748 +5297 +6572 +8877 +6874 +430 +5041 +5267 +7448 +620 +9112 +4294 +1432 +72 +130 +7920 +4597 +6614 +8889 +3697 +1895 +3462 +2616 +4791 +7846 +8372 +428 +6559 +8326 +9211 +1525 +5980 +7888 +3331 +8118 +7899 +615 +7377 +791 +5930 +6627 +8322 +1138 +770 +8460 +5100 +8274 +8350 +6316 +2893 +7594 +9236 +5082 +8150 +1986 +1909 +8902 +2145 +3617 +3501 +7 +2426 +5056 +8016 +2702 +5360 +8135 +8385 +8378 +8018 +8574 +720 +8893 +3021 +1978 +4782 +1816 +2083 +4051 +1446 +5870 +9097 +8006 +4222 +8287 +686 +1377 +611 +8153 +4808 +1536 +679 +4096 +3891 +4884 +432 +4615 +8988 +5560 +3451 +5589 +3514 +6169 +1414 +3244 +1490 +7100 +3588 +690 +7317 +4171 +2266 +6800 +2793 +5151 +6977 +8188 +8752 +5815 +5116 +263 +3311 +289 +3392 +5755 +1022 +5548 +9319 +8937 +6011 +7632 +5328 +4141 +5407 +520 +7305 +526 +3645 +1859 +2520 +3523 +8629 +7304 +8881 +3076 +4005 +8329 +2205 +2214 +6925 +8691 +4136 +8883 +974 +7952 +3965 +5887 +7964 +7189 +2406 +2783 +8086 +405 +6568 +5147 +2021 +4727 +7674 +1600 +5078 +2949 +6624 +6541 +8986 +5740 +8500 +3591 +4434 +398 +983 +7544 +1478 +4570 +6012 +465 +9330 +7206 +808 +8737 +2356 +4959 +8812 +3599 +1420 +1721 +5897 +8422 +2 +4023 +2739 +3619 +8797 +5496 +8951 +8181 +6893 +9254 +1809 +5682 +4309 +6929 +2742 +5988 +3363 +4493 +8434 +4210 +1503 +1876 +5094 +4600 +4936 +4798 +3933 +5216 +646 +3098 +8773 +4076 +5335 +3746 +3327 +47 +4602 +8636 +4129 +363 +6417 +7416 +9025 +4377 +4766 +2779 +4151 +9046 +7860 +3154 +3476 +7620 +2052 +1752 +7199 +4412 +8882 +2463 +339 +56 +4821 +7555 +6558 +1905 +5258 +4205 +3580 +6735 +1023 +4511 +3850 +161 +7395 +2532 +3349 +7055 +7387 +758 +1907 +3006 +659 +815 +1961 +6902 +7668 +4708 +1904 +4433 +5159 +6816 +8664 +6918 +1016 +6513 +7314 +7480 +9313 +716 +3395 +6843 +918 +4329 +8593 +3404 +5212 +837 +480 +8524 +1342 +7414 +288 +8863 +3352 +1628 +135 +3314 +2181 +8650 +5915 +8078 +6812 +1375 +906 +5635 +7126 +1387 +7458 +6119 +5591 +3795 +1531 +95 +1960 +7522 +898 +4921 +2623 +6268 +7063 +1326 +9075 +2505 +7400 +1284 +2951 +747 +6466 +1357 +6493 +7320 +5892 +576 +5107 +5559 +97 +2583 +6361 +8843 +3509 +7892 +6086 +1476 +4612 +4267 +9094 +7050 +6048 +8382 +2227 +284 +2898 +3221 +2353 +2157 +5990 +5810 +3581 +7279 +6188 +7859 +3549 +5539 +2022 +630 +2500 +5111 +6561 +5127 +5569 +6123 +1338 +8605 +3491 +4187 +8220 +7334 +9213 +3067 +6997 +2853 +4735 +4372 +5954 +6662 +2207 +973 +3361 +960 +6350 +7431 +8076 +1129 +750 +7194 +2300 +6590 +5893 +6889 +3125 +8788 +7286 +3472 +8164 +7693 +1469 +5563 +4773 +3210 +6324 +3113 +9070 +3638 +7551 +2541 +3506 +5138 +4069 +7198 +7560 +3306 +6100 +2932 +1741 +14 +4672 +7564 +8748 +8874 +3804 +3678 +2610 +1358 +42 +5176 +9326 +8464 +1038 +2993 +3017 +9072 +32 +4809 +4364 +2808 +4125 +152 +7299 +5431 +6178 +793 +9120 +8410 +4963 +772 +6954 +3014 +6881 +286 +553 +1948 +6398 +6255 +3057 +8646 +6176 +2700 +5663 +6683 +1281 +6013 +8799 +7635 +9289 +1885 +442 +2225 +6294 +5054 +2674 +7884 +8730 +8216 +4203 +1488 +7111 +3623 +7950 +1971 +3248 +2900 +1553 +472 +3865 +7796 +6937 +4591 +8098 +5208 +294 +5627 +5691 +5687 +7149 +4879 +3624 +7005 +2773 +3112 +9185 +1633 +7830 +5101 +8707 +8469 +4678 +4860 +700 +5527 +9194 +2794 +5068 +1177 +4282 +6492 +5859 +5029 +5123 +522 +5048 +7230 +2104 +6642 +6731 +2717 +5149 +2043 +9059 +5277 +844 +5515 +6706 +3651 +9105 +7671 +2880 +3607 +6410 +2508 +8463 +2394 +1916 +1125 +5343 +3322 +5307 +4547 +1589 +8478 +8899 +2955 +8028 +4058 +2781 +8715 +1272 +4474 +4863 +4367 +49 +8844 +5605 +8671 +6743 +4281 +1874 +2626 +2516 +258 +5249 +6186 +7958 +5432 +3801 +6288 +4732 +9121 +7558 +6819 +7508 +584 +215 +5036 +4261 +8978 +5228 +647 +4657 +2591 +5931 +5088 +9204 +929 +4381 +5421 +2965 +5050 +6495 +5033 +4799 +959 +1232 +5811 +317 +7705 +3842 +2178 +7187 +1373 +7112 +2694 +8627 +8493 +3991 +7441 +6308 +6462 +3406 +7673 +8660 +2902 +752 +1025 +849 +7682 +6982 +6652 +3612 +298 +5148 +4873 +3414 +1693 +1458 +327 +2016 +5002 +6768 +7016 +5583 +3270 +8232 +7158 +7981 +4676 +4675 +2164 +8360 +6709 +8143 +365 +4062 +4527 +7928 +9009 +6228 +5818 +2533 +9305 +8887 +55 +2507 +8870 +6649 +5158 +76 +5595 +6693 +5306 +8666 +3020 +7527 +3082 +6304 +1591 +6145 +6868 +7205 +9107 +1165 +6773 +172 +1993 +4176 +8400 +4611 +7589 +5386 +6095 +6335 +1561 +5963 +7393 +3681 +2037 +4968 +7451 +3360 +7466 +8361 +4455 +4064 +5422 +1689 +3977 +7269 +362 +4178 +4145 +6127 +5162 +2399 +9225 +7068 +794 +1348 +7736 +444 +6081 +5298 +2026 +2543 +9087 +7425 +3730 +8468 +2641 +7529 +1720 +6377 +5851 +7956 +3150 +3785 +6485 +3611 +2869 +8510 +4775 +4463 +1251 +9124 +6873 +3391 +4118 +7051 +3213 +3668 +5347 +8452 +6289 +5840 +478 +3522 +453 +3376 +6190 +3342 +2237 +2870 +5178 +5567 +5952 +6919 +3005 +134 +3397 +8539 +6822 +5264 +3288 +5962 +8421 +6744 +8608 +4656 +1802 +4271 +1043 +8211 +2196 +5260 +3789 +7211 +7571 +7834 +5680 +2047 +5502 +3369 +3437 +3286 +5517 +3912 +1442 +6961 +2191 +2417 +9088 +5155 +6813 +4520 +7375 +1224 +811 +1891 +3748 +4123 +2789 +5305 +8419 +7248 +9237 +992 +4038 +4499 +2060 +850 +2669 +7612 +9290 +2526 +1287 +4160 +4633 +7125 +742 +4534 +2407 +4555 +8764 +4722 +7721 +3205 +6657 +1214 +3754 +6080 +4593 +3018 +8792 +2294 +4450 +7701 +127 +7069 +6243 +8025 +4010 +8632 +4715 +5284 +4574 +726 +4252 +4561 +7354 +299 +6088 +1090 +5012 +5684 +3489 +4888 +1584 +1969 +4846 +2915 +6804 +2775 +7306 +9306 +5231 +7740 +4283 +953 +6725 +8290 +1504 +1539 +8885 +138 +3764 +1256 +257 +335 +7060 +5986 +9323 +4740 +8994 +4140 +6807 +8254 +3963 +9297 +2102 +9207 +4910 +8709 +4411 +1672 +457 +8037 +4932 +3679 +2362 +8592 +495 +1608 +2155 +7411 +2881 +9244 +37 +6535 +8219 +4505 +8635 +1928 +8384 +2570 +8996 +7610 +2128 +8728 +6656 +6681 +2070 +176 +9062 +514 +1796 +4039 +6838 +2462 +230 +569 +5521 +4637 +4939 +4420 +672 +3807 +447 +1656 +3297 +8858 +2118 +6309 +1926 +481 +1509 +1228 +1787 +5978 +8678 +3951 +2929 +4980 +5039 +4713 +7002 +151 +5536 +8148 +3823 +2299 +142 +7067 +2372 +3761 +9 +2265 +5747 +2764 +724 +2913 +3151 +4525 +6370 +4247 +5494 +629 +3621 +7371 +1999 +6704 +3734 +2698 +4691 +6938 +8415 +6353 +6750 +9077 +2679 +2478 +7321 +6611 +4007 +5772 +6416 +2264 +8348 +2672 +6546 +754 +6934 +8546 +4404 +592 +4748 +6625 +7944 +2377 +6 +8929 +8275 +4524 +3660 +8710 +419 +6878 +8313 +7460 +8753 +2917 +6891 +6663 +4918 +7129 +396 +7256 +3500 +631 +5585 +8343 +2695 +6168 +6292 +3176 +5092 +5160 +3701 +9021 +7221 +1216 +1438 +3471 +2318 +8923 +6223 +2182 +7621 +8514 +9010 +8987 +1252 +1972 +1872 +1715 +8205 +6463 +8138 +8989 +5661 +2890 +565 +2427 +8946 +1303 +3718 +6000 +3620 +5276 +9260 +1467 +6173 +7641 +7520 +5061 +4677 +5757 +4400 +2620 +2719 +8995 +2079 +1683 +8141 +7754 +5744 +2952 +7568 +7457 +5368 +1510 +1513 +3072 +1456 +9164 +3163 +3035 +6111 +5042 +7161 +1401 +1084 +8000 +8531 +5404 +6550 +8379 +9141 +8681 +7752 +6394 +7011 +3739 +8253 +978 +4771 +6024 +4828 +7959 +1649 +1727 +7073 +8349 +6952 +661 +7283 +3159 +2590 +3496 +8741 +3969 +2956 +4565 +920 +1830 +8558 +1930 +6677 +6825 +8256 +7454 +4710 +1768 +3753 +5292 +1397 +2733 +946 +6711 +3242 +4929 +5006 +3202 +2295 +2746 +1293 +2124 +5405 +4065 +818 +7464 +1820 +1312 +6994 +6920 +261 +987 +6120 +3109 +2986 +4338 +7774 +5122 +1364 +8969 +6712 +8161 +7595 +5940 +1566 +6419 +4432 +6047 +4749 +6076 +1161 +8217 +674 +8494 +3688 +2447 +4704 +969 +7477 +1160 +3243 +4979 +9288 +6860 +1662 +6171 +225 +5143 +313 +8327 +3385 +7626 +3103 +4401 +6794 +5600 +5043 +7664 +6830 +4452 +3980 +5875 +4635 +5756 +3329 +1751 +8108 +4817 +1989 +1237 +1893 +2848 +8875 +4981 +5417 +4134 +877 +6688 +3545 +4943 +5615 +2476 +1684 +7396 +1171 +3415 +3644 +340 +6630 +8284 +3256 +7240 +5371 +3405 +2108 +6360 +1734 +5612 +8638 +2343 +1103 +6809 +3055 +188 +8031 +3124 +3683 +4537 +988 +2297 +4893 +839 +4467 +5195 +4041 +6457 +4441 +6472 +4912 +6884 +5922 +7014 +1660 +1595 +6752 +4554 +1292 +2709 +3800 +1980 +8775 +6392 +6263 +7214 +5219 +282 +309 +6685 +6311 +4092 +18 +7570 +5543 +4081 +2515 +6278 +8690 +5294 +6184 +5215 +9130 +6720 +250 +7250 +639 +3567 +7841 +2636 +4067 +8446 +5703 +8609 +2586 +7695 +1253 +6701 +7930 +6317 +5921 +7719 +8501 +7312 +4110 +6219 +4552 +5059 +4088 +7975 +9132 +6054 +692 +3412 +4079 +6950 +5281 +8321 +3877 +7614 +4188 +2223 +239 +4745 +6875 +7096 +5571 +4403 +2640 +1845 +6690 +1825 +4157 +314 +4682 +8825 +8093 +7215 +6465 +99 +8077 +4206 +366 +1208 +6043 +4640 +5475 +4985 +1351 +3090 +5625 +7307 +8466 +2003 +8854 +218 +1500 +2293 +1847 +5032 +2147 +866 +3710 +2552 +1749 +6692 +3926 +4112 +6458 +735 +9171 +60 +9304 +6726 +2630 +2882 +1178 +1151 +4922 +4662 +173 +7233 +1776 +4113 +2423 +2425 +4343 +970 +6372 +1009 +6607 +3068 +8435 +6423 +3126 +4813 +1709 +1201 +7104 +5620 +3932 +3366 +5023 +5079 +627 +290 +779 +5572 +5233 +1392 +4975 +8534 +8210 +2269 +2475 +2562 +905 +4546 +267 +3536 +8538 +449 +101 +7367 +2722 +4605 +7356 +6781 +8537 +8697 +6820 +8340 +8926 +2349 +2259 +6545 +8100 +8395 +2258 +2911 +3946 +1406 +8683 +8296 +5579 +2177 +8264 +1425 +957 +3647 +515 +5342 +8363 +2449 +1001 +2937 +3452 +5574 +4319 +9184 +8381 +945 +6876 +600 +5714 +4871 +8532 +8856 +392 +2018 +369 +5711 +9230 +5304 +7266 +1681 +7829 +2309 +4683 +8938 +2255 +6159 +3207 +4651 +2029 +4341 +5106 +5794 +9024 +4712 +2434 +7151 +7359 +6431 +1290 +5918 +8705 +5554 +8876 +7415 +6290 +5373 +3805 +2950 +2331 +6772 +8997 +6576 +2307 +8515 +4033 +3428 +6487 +6595 +45 +5792 +333 +2383 +3388 +666 +460 +943 +364 +8223 +8221 +637 +6218 +4108 +5381 +4649 +5096 +1614 +8768 +5095 +3809 +5030 +984 +3538 +5120 +2498 +5222 +5613 +5486 +241 +5707 +9227 +4109 +7771 +728 +3671 +9327 +1230 +9270 +1070 +8565 +4769 +7056 +5654 +1793 +5956 +7883 +1362 +5479 +8769 +8821 +8320 +1901 +1994 +2461 +5552 +389 +2839 +6467 +2762 +4763 +3499 +1487 +7599 +4488 +3241 +8272 +1131 +4496 +7006 +7265 +4897 +2747 +6618 +5291 +4563 +1939 +6369 +8548 +5526 +9030 +5349 +8433 +1477 +4265 +9200 +3878 +462 +6846 +4806 +3519 +6798 +5464 +5179 +546 +6044 +8114 +7216 +6276 +1495 +494 +8146 +5434 +856 +8403 +8071 +5544 +3337 +1546 +2824 +1718 +6009 +2042 +251 +3330 +192 +3797 +394 +7814 +7699 +4659 +4689 +4156 +7903 +9054 +7332 +7811 +1119 +5531 +6782 +5210 +8412 +2633 +7924 +4624 +8314 +5666 +3240 +2310 +4262 +8160 +4553 +8196 +2661 +7213 +7455 +7399 +870 +1227 +1226 +781 +937 +6343 +2578 +2892 +2792 +5696 +6865 +6455 +8312 +5193 +6026 +5251 +3787 +4460 +4687 +7923 +1140 +9106 +796 +2482 +9170 +8695 +2749 +6734 +4825 +114 +827 +390 +7611 +7484 +1249 +7727 +955 +579 +3629 +8915 +2958 +885 +7227 +1424 +4810 +4604 +1535 +774 +7518 +5428 +8233 +2645 +2167 +6484 +3855 +1502 +4861 +2333 +2973 +4829 +1906 +3966 +476 +9023 +6960 +3483 +2748 +5891 +8174 +7702 +8948 +5324 +4396 +1605 +2823 +7348 +7347 +5933 +310 +9082 +916 +203 +4239 +5976 +6200 +6435 +4425 +787 +1121 +6034 +39 +3104 +5961 +5507 +5785 +1463 +7339 +1575 +7801 +5445 +8283 +5951 +6995 +999 +5163 +6023 +6536 +5850 +3524 +3528 +4508 +6674 +2939 +8227 +4598 +7550 +8495 +8622 +1152 +4538 +1318 +739 +8202 +1552 +5236 +3576 +4699 +9238 +1879 +433 +5587 +1678 +8552 +6445 +7971 +6880 +7476 +7282 +7271 +6489 +8091 +9287 +7351 +1765 +5286 +6921 +542 +1762 +8553 +4987 +894 +3622 +7855 +92 +3131 +4811 +6517 +4510 +733 +4954 +1360 +5669 +2842 +8107 +5646 +5968 +1827 +7709 +8521 +5807 +5321 +9239 +5501 +3745 +4437 +1586 +5265 +7917 +1607 +6074 +7061 +1580 +8694 +8461 +4573 +618 +9173 +5243 +435 +8770 +2421 +7450 +3870 +8308 +2605 +2934 +9240 +6887 +4512 +1198 +7585 +7691 +7738 +2843 +8423 +6971 +7854 +86 +9128 +4298 +622 +6579 +2203 +7716 +1265 +1174 +7380 +623 +8936 +4306 +8082 +4312 +8661 +5753 +7243 +2768 +8155 +85 +4143 +3047 +8479 +7809 +2833 +5555 +7578 +1637 +1936 +8130 +5549 +8062 +7143 +5522 +8966 +5614 +8105 +8719 +7655 +7502 +8268 +5760 +6695 +5565 +7615 +9226 +4870 +4507 +3160 +4835 +1598 +4422 +5248 +7867 +1078 +5015 +6660 +1676 +6391 +5351 +7184 +6280 +5936 +6124 +1327 +2906 +269 +8292 +8809 +5167 +8142 +8204 +2713 +1910 +2930 +2494 +5592 +7384 +7726 +5727 +1735 +5710 +5518 +2491 +1410 +4989 +5183 +8777 +6562 +4947 +3692 +384 +1097 +5209 +3723 +7272 +6895 +2459 +543 +8621 +5394 +6211 +2074 +1511 +2524 +7776 +5055 +7191 +6207 +7922 +281 +8436 +2918 +3141 +4800 +6323 +7631 +8903 +3735 +5301 +3975 +2800 +7963 +105 +1920 +7391 +4909 +1754 +4816 +5145 +5139 +5268 +9317 +8631 +4346 +7318 +136 +3993 +1220 +2151 +308 +7483 +3071 +1339 +3777 +8191 +5378 +7087 +1056 +7465 +5608 +6564 +2754 +2687 +1596 +5376 +1512 +566 +6382 +1757 +8035 +2296 +4264 +1053 +4716 +8518 +254 +6253 +7132 +8557 +3490 +9267 +5473 +2412 +7539 +7136 +6670 +891 +1323 +1217 +2879 +9118 +1259 +2317 +7033 +2467 +6665 +6244 +2180 +2140 +7098 +4150 +547 +4307 +1725 +2737 +8549 +8195 +1245 +6286 +935 +1756 +1701 +1626 +7379 +3492 +3717 +5802 +2817 +1234 +1005 +4101 +21 +2576 +4650 +3381 +1030 +2844 +1641 +936 +2729 +6469 +8913 +5994 +341 +4083 +5152 +3380 +8739 +6615 +3829 +164 +7927 +4779 +4216 +8528 +3641 +4606 +2769 +6970 +8850 +4971 +5489 +2008 +4564 +8682 +7784 +5768 +9252 +901 +438 +3577 +2765 +5904 +664 +3348 +6298 +3602 +2502 +8617 +7684 +5805 +4126 +2451 +6906 +7234 +9243 +3778 +1087 +9053 +5026 +2504 +5283 +2820 +4242 +797 +3925 +1383 +8750 +7861 +1403 +6973 +7617 +3065 +5395 +4347 +8144 +2688 +6527 +8597 +8673 +7327 +6331 +1422 +7115 +244 +7013 +2092 +54 +7970 +5742 +4823 +8588 +2938 +3060 +4149 +2375 +6616 +8803 +1555 +4369 +1380 +3011 +6144 +3367 +7370 +1995 +2602 +985 +8785 +8480 +9125 +1927 +3269 +3771 +1032 +7378 +5726 +2731 +2020 +6727 +8793 +523 +6036 +58 +7993 +5512 +5049 +2721 +8482 +673 +7937 +1168 +4472 +8247 +7287 +9017 +6421 +9190 +3584 +1819 +1792 +2810 +6033 +6749 +7677 +981 +7160 +4726 +1886 +7845 +6975 +7422 +4613 +4501 +2569 +4263 +3206 +4133 +2420 +3706 +8894 +2263 +5774 +4925 +9180 +8888 +2945 +2091 +1873 +6303 +729 +2156 +3267 +1860 +6597 +4930 +5253 +938 +580 +5825 +166 +8198 +6892 +8701 +74 +7094 +8954 +3156 +6140 +4279 +2229 +5466 +8413 +7105 +8192 +2632 +7638 +9308 +8530 +832 +4643 +2201 +3268 +4322 +6510 +2967 +262 +403 +1258 +8828 +5838 +8529 +2788 +237 +3838 +1291 +4056 +5628 +7281 +6476 +7935 +2850 +6041 +2013 +4016 +4576 +5312 +6827 +6321 +8669 +830 +1519 +2750 +6106 +6993 +6235 +5899 +7313 +5331 +4371 +7086 +8600 +2660 +5409 +3465 +5499 +6231 +5745 +1801 +5337 +4468 +1451 +4192 +1275 +1114 +4960 +8860 +3900 +6468 +1505 +8868 +5588 +3858 +1947 +2565 +1472 +243 +6583 +7085 +5374 +4291 +4426 +492 +2311 +8305 +3662 +8780 +7488 +3890 +5005 +4680 +7358 +9116 +4397 +5999 +7902 +83 +3566 +2134 +8942 +4767 +6601 +1745 +5736 +5254 +8017 +4015 +7690 +3798 +8947 +1067 +7945 +590 +2547 +2535 +64 +2053 +5359 +2493 +6669 +7473 +6147 +7175 +6983 +5196 +745 +2657 +3497 +697 +3161 +7528 +2239 +5991 +3201 +7681 +5189 +2959 +2044 +8917 +2046 +6313 +6333 +5318 +4301 +2213 +2933 +4121 +3903 +4392 +7889 +5323 +1055 +707 +3857 +518 +6078 +5134 +6645 +9138 +1592 +680 +4446 +7943 +3461 +3887 +5601 +2321 +6621 +558 +4914 +913 +5637 +6453 +8511 +4531 +1218 +5508 +2603 +6802 +8426 +8297 +2947 +5971 +6552 +5262 +5935 +782 +7435 +8357 +6139 +1136 +5008 +3585 +3627 +5356 +2997 +2347 +881 +4849 +8808 +8351 +4017 +2010 +6836 +4391 +3630 +3712 +2969 +5238 +4333 +2301 +4406 +1236 +1050 +1864 +8408 +8251 +8795 +5879 +3365 +7481 +8206 +2452 +1767 +8859 +124 +3948 +4444 +8962 +4438 +5003 +8428 +3105 +5117 +1095 +8755 +7881 +3097 +4877 +155 +1917 +2455 +6042 +337 +6724 +6045 +8483 +7135 +2242 +4566 +1679 +834 +1746 +795 +3548 +2314 +2036 +4046 +9129 +7084 +5091 +2413 +8170 +5775 +1817 +529 +813 +2916 +5130 +126 +1243 +2370 +4831 +9122 +3010 +5104 +2613 +6761 +5340 +3512 +6283 +2346 +653 +6121 +2615 +7421 +1869 +1002 +8834 +2991 +8992 +632 +1093 +4543 +645 +2352 +4115 +373 +1483 +6966 +8598 +3896 +3434 +5987 +8318 +1815 +1223 +1548 +6885 +5073 +6330 +2573 +1369 +4095 +1431 +2185 +5766 +1301 +7258 +8048 +7598 +2847 +1996 +2378 +8561 +743 +6381 +271 +1956 +7439 +7134 +6636 +5804 +1858 +6214 +4730 +8536 +1203 +3118 +9202 +1875 +5885 +168 +5898 +4014 +4186 +3346 +3041 +5558 +9296 +8157 +4339 +3234 +2604 +6803 +5387 +5590 +125 +2173 +8012 +8005 +4858 +651 +372 +378 +8366 +6299 +1449 +7793 +8541 +3235 +8043 +3086 +3983 +6949 +4690 +6494 +8406 +7408 +350 +7021 +8224 +7044 +7662 +6697 +7679 +169 +528 +7029 +2790 +7432 +7602 +8333 +1582 +1378 +482 +9279 +8015 +4514 +3542 +628 +5053 +6699 +6227 +2094 +1621 +847 +3598 +2728 +7276 +6620 +8345 +4278 +4059 +9058 +4173 +8134 +1997 +3182 +3224 +8129 +5109 +4494 +189 +7640 +180 +2963 +1123 +5593 +3263 +4185 +7140 +8990 +6320 +9275 +4601 +4854 +5907 +1135 +8083 +5964 +7788 +1992 +8069 +9174 +6160 +35 +8572 +2865 +46 +3952 +6418 +2510 +5783 +3816 +2715 +3930 +2548 +5204 +708 +7756 +3825 +777 +3550 +3929 +5440 +6751 +7764 +4070 +7331 +3743 +9131 +9206 +3828 +23 +41 +4197 +234 +5723 +7622 +8832 +2169 +5599 +2976 +5266 +1967 +90 +822 +2538 +3169 +6771 +7442 +498 +4967 +5580 +7581 +7680 +4728 +1115 +1064 +3106 +6266 +4415 +9294 +5597 +7059 +197 +7218 +6948 +5690 +1653 +4485 +4019 +3370 +919 +1330 +6085 +2078 +5427 +4545 +2435 +8862 +3633 +8145 +5221 +1388 +5913 +8140 +7471 +7156 +6989 +1190 +6832 +2830 +4387 +3454 +7469 +2910 +4526 +5187 +2410 +9223 +4681 +1300 +7407 +6523 +3616 +6894 +7253 +4515 +5874 +5448 +7137 +7957 +1130 +3092 +7054 +3516 +5797 +1000 +4336 +9090 +6403 +7255 +8919 +6522 +6760 +8898 +4803 +374 +8686 +3985 +7045 +3475 +6065 +7991 +1409 +7851 +6671 +6090 +5826 +7857 +1155 +8964 +1117 +7072 +6064 +2497 +4899 +2397 +3189 +2369 +5027 +5754 +8950 +5617 +8391 +914 +6264 +279 +6174 +5184 +3733 +5278 +2924 +567 +7994 +352 +8084 +2148 +2723 +3359 +70 +1870 +7708 +220 +3994 +9013 +3191 +9220 +4155 +5717 +1110 +2198 +785 +5325 +4770 +4250 +52 +4634 +9037 +601 +8036 +7996 +2483 +7232 +8675 +8836 +1279 +5346 +7676 +6104 +1515 +4603 +5607 +5144 +2628 +68 +440 +3586 +3083 +4830 +4378 +7762 +1134 +4542 +7850 +6296 +4011 +8751 +4776 +7954 +7102 +5697 +2032 +5729 +5017 +6962 +2051 +1092 +9019 +2759 +8581 +8618 +912 +2382 +4892 +8447 +8176 +5491 +5695 +5504 +1060 +578 +4320 +2379 +7649 +8416 +1613 +5344 +7512 +7865 +3037 +6689 +6557 +1569 +5955 +3707 +9168 +8566 +1775 +5950 +6943 +7804 +434 +6179 +1142 +7947 +6456 +6291 +5789 +6538 +9134 +3049 +5075 +5161 +1623 +948 +6302 +6063 +7516 +117 +506 +3302 +7146 +355 +1081 +2827 +1496 +2574 +6167 +3183 +4287 +5482 +7319 +7277 +3860 +3443 +3298 +8364 +3826 +7254 +2360 +5093 +7039 +6325 +2567 +4443 +559 +2625 +4228 +8967 +6405 +1674 +3936 +4475 +8556 +8585 +896 +3713 +6259 +4297 +6718 +2392 +2279 +4927 +1283 +2860 +7665 +663 +596 +6293 +6805 +2811 +7383 +8306 +8330 +3153 +2153 +2618 +2441 +3615 +8092 +552 +5285 +8124 +9247 +5530 +8175 +6242 +5660 +3433 +1610 +1832 +3892 +3862 +640 +2127 +4196 +3495 +7217 +5206 +4836 +7759 +800 +4227 +3699 +9055 +5665 +6826 +7463 +9065 +4720 +5069 +3453 +3358 +6532 +5970 +7921 +4087 +1547 +3424 +8040 +7995 +6787 +9069 +8716 +2561 +8199 +1479 +2767 +7818 +7145 +604 +7597 +4896 +9281 +4666 +185 +7978 +3059 +9221 +2135 +1800 +2974 +1529 +5948 +446 +4436 +8672 +3508 +6208 +5673 +6998 +5203 +278 +7041 +9110 +5853 +8121 +1764 +3046 +6575 +4738 +2228 +7761 +9322 +7019 +6931 +6383 +6762 +283 +3935 +6785 +471 +8214 +231 +3844 +5746 +2011 +7209 +336 +6433 +756 +9167 +6741 +3345 +7685 +4018 +6682 +9147 +4790 +5836 +5906 +676 +3964 +6362 +3510 +7510 +2308 +1806 +5917 +3387 +5423 +8900 +147 +3780 +1696 +9111 +6783 +6497 +4104 +3987 +260 +4616 +2121 +9283 +1400 +4670 +2735 +2096 +6521 +1423 +4523 +2243 +6667 +6990 +3944 +6915 +6763 +404 +2691 +1015 +7092 +7562 +8624 +2291 +5934 +5503 +2326 +2960 +842 +1963 +5568 +9050 +3806 +439 +9154 +6055 +6451 +7633 +688 +4354 +8890 +2813 +2872 +8102 +6609 +1497 +8389 +6449 +1682 +3594 +5103 +5812 +863 +3054 +8079 +2260 +2027 +3091 +7687 +6703 +3557 +2019 +8427 +2799 +8182 +6641 +3168 +2284 +1934 +6507 +1658 +3811 +1774 +7897 +2238 +2943 +191 +3869 +3188 +414 +8072 +7838 +1382 +4962 +5363 +4042 +1983 +4077 +7429 +4044 +1109 +1295 +386 +5481 +3927 +311 diff --git a/Stark/lib/train/data_specs/got10k_vot_val_split.txt b/Stark/lib/train/data_specs/got10k_vot_val_split.txt new file mode 100755 index 0000000..734a9da --- /dev/null +++ b/Stark/lib/train/data_specs/got10k_vot_val_split.txt @@ -0,0 +1,1249 @@ +1349 +5878 +562 +2202 +8904 +1501 +8654 +2975 +2689 +3680 +5180 +1900 +7707 +4723 +8912 +4029 +3579 +869 +2888 +8657 +6599 +741 +4288 +2244 +7357 +5704 +8791 +208 +4805 +8526 +4887 +8871 +7468 +3343 +886 +7794 +2646 +6454 +6101 +7885 +7744 +1297 +4119 +4856 +122 +2286 +2925 +5131 +5843 +5320 +5626 +540 +1862 +7335 +699 +7760 +9198 +3259 +7345 +8698 +1280 +6479 +3100 +3988 +1322 +5737 +1268 +3257 +6791 +3326 +4815 +7644 +1082 +2826 +6821 +8984 +2553 +5290 +5909 +4762 +8096 +8066 +4325 +6666 +7193 +7114 +8060 +7872 +6788 +3544 +5460 +3507 +2509 +6626 +3429 +5542 +4220 +2968 +5271 +3863 +1868 +5581 +2012 +6270 +8038 +4050 +121 +2845 +1565 +1998 +2275 +5524 +6068 +7624 +4913 +9277 +1506 +803 +8848 +5925 +2450 +2072 +8190 +4753 +9162 +825 +7303 +9028 +2088 +8516 +1556 +5937 +7847 +2367 +7549 +1049 +1521 +4739 +3931 +8958 +4130 +7876 +897 +5985 +7346 +7537 +111 +3700 +1126 +7896 +3419 +1051 +5720 +1068 +3458 +146 +291 +6256 +5514 +2857 +4580 +6239 +6525 +8717 +391 +4841 +6676 +4360 +4211 +73 +1675 +1987 +4025 +1321 +662 +8265 +6424 +2758 +7765 +7656 +3209 +7497 +7600 +9039 +7697 +5177 +2983 +5622 +9295 +3284 +964 +2024 +1269 +4551 +8088 +5659 +2212 +5199 +5551 +8607 +5573 +5200 +7951 +8429 +7720 +5919 +1273 +3529 +6707 +9176 +7552 +3255 +5649 +6110 +1137 +9272 +788 +5786 +5186 +2667 +7630 +3953 +1828 +8827 +6471 +7815 +467 +6387 +3195 +6238 +6508 +2373 +5983 +4931 +2948 +921 +2438 +517 +3949 +2137 +3216 +5683 +3695 +1719 +4837 +9159 +6981 +860 +7410 +5497 +1770 +5557 +8810 +5194 +4857 +9100 +6329 +2609 +1925 +3686 +9041 +4924 +349 +9187 +3393 +3661 +7120 +6858 +4587 +3831 +3130 +5060 +6486 +8023 +824 +1354 +8861 +5534 +7292 +4389 +6029 +6226 +3505 +4326 +7445 +581 +6089 +3450 +7324 +6516 +6775 +1207 +4575 +5135 +3918 +9020 +3473 +3898 +7812 +6571 +6757 +6639 +2557 +1206 +6148 +7325 +8790 +4938 +7026 +4383 +8041 +1250 +7267 +1952 +7561 +8811 +4941 +8373 +4848 +6602 +8355 +8104 +5214 +4330 +3181 +3422 +456 +1782 +3408 +6530 +719 +7587 +3058 +740 +4207 +5336 +2798 +2473 +4221 +1493 +3281 +171 +9157 +9139 +7766 +3324 +5308 +3708 +2431 +8080 +2093 +2585 +406 +7040 +5064 +5247 +4758 +6512 +4257 +4935 +2705 +2572 +3436 +8513 +1385 +2637 +7091 +2761 +6007 +6694 +2422 +4917 +2186 +6898 +1390 +6965 +7698 +2002 +2692 +7365 +7373 +4091 +947 +3962 +8692 +1788 +6862 +6856 +1950 +1914 +5658 +3635 +1620 +4780 +2580 +1454 +2786 +687 +7238 +3648 +6452 +1197 +3190 +5900 +9043 +4958 +1821 +1187 +1153 +7169 +7350 +5674 +6254 +3025 +6680 +1690 +2899 +3893 +1577 +5728 +9189 +5077 +3560 +2179 +5462 +1402 +3654 +1376 +5506 +1179 +5647 +4686 +8644 +1352 +2855 +6079 +2254 +2668 +2287 +2457 +3418 +7264 +677 +3074 +2655 +1042 +2210 +4504 +8309 +4209 +4280 +3258 +2977 +84 +4705 +1244 +3511 +6355 +8813 +3228 +9266 +1122 +613 +732 +5202 +8425 +2638 +6470 +3541 +8132 +2063 +5129 +2818 +7949 +8090 +4465 +7295 +5239 +7009 +9271 +8563 +2832 +952 +8136 +6776 +3565 +5188 +7288 +6999 +285 +5487 +7608 +8584 +2071 +7868 +2804 +3655 +6847 +3276 +4272 +3910 +1574 +4559 +7580 +5014 +8183 +6386 +7574 +356 +4937 +2487 +9315 +7572 +3040 +671 +2682 +8626 +3868 +387 +8679 +4074 +1481 +3527 +3595 +4754 +2453 +1579 +4638 +9123 +1829 +3009 +3691 +763 +4875 +3572 +4273 +2777 +6032 +4793 +233 +7147 +996 +3199 +8835 +3517 +7210 +6125 +6037 +3684 +3915 +3180 +7043 +4458 +2889 +57 +7667 +8375 +1434 +7493 +4733 +5827 +2111 +1313 +7986 +3075 +2614 +7547 +4977 +8527 +3212 +7300 +5842 +5244 +3291 +597 +1007 +2030 +227 +3830 +5540 +247 +5643 +9333 +1958 +1371 +5220 +7926 +2927 +1516 +7130 +193 +1522 +6165 +6923 +3794 +4223 +5535 +2472 +8630 +3971 +9101 +2946 +4609 +7291 +8542 +6501 +7548 +4557 +6274 +5226 +7309 +1317 +6275 +1099 +4191 +7270 +5392 +2316 +3819 +1670 +8045 +4807 +8864 +2391 +5908 +8338 +8218 +6400 +9193 +3165 +843 +6613 +6941 +5629 +7557 +4321 +3702 +681 +1159 +4665 +5959 +1697 +5509 +8774 +7389 +3832 +3751 +8637 +1680 +6841 +703 +684 +8293 +3682 +5733 +4818 +3231 +5562 +9001 +3889 +7024 +2519 +1713 +3287 +219 +8776 +2289 +7212 +4832 +4684 +4617 +4237 +2649 +8185 +6326 +3568 +551 +1426 +8869 +312 +2905 +4165 +8248 +2558 +900 +1044 +8613 +7743 +5437 +7604 +3122 +5708 +8649 +2878 +4695 +4491 +7533 +5223 +7711 +1844 +5751 +3008 +8055 +4636 +61 +198 +2271 +5698 +4596 +4500 +5709 +5819 +7972 +2992 +1643 +1048 +6281 +8886 +360 +4198 +6814 +3960 +2606 +7001 +5888 +450 +7133 +7015 +7034 +5153 +8920 +5066 +469 +1302 +8816 +463 +8651 +5869 +6582 +5578 +1231 +9274 +7260 +7751 +8052 +6799 +2089 +2342 +8451 +3260 +5550 +7795 +2288 +1205 +40 +496 +8367 +7836 +5973 +3908 +5242 +5062 +2706 +997 +5419 +9201 +1965 +6062 +3050 +5302 +8735 +358 +2398 +7470 +1644 +8179 +7047 +1549 +5414 +2539 +7381 +589 +8166 +8505 +6035 +3956 +4540 +6721 +8074 +1062 +2384 +2531 +7159 +3902 +4584 +2554 +264 +8720 +2849 +4916 +5218 +7202 +883 +4560 +1677 +4317 +7863 +4509 +6577 +2903 +1452 +1416 +5369 +473 +6233 +6359 +5992 +4934 +8059 +6834 +4907 +3320 +8267 +8280 +2066 +2402 +1485 +3772 +3732 +4764 +9126 +3575 +5564 +5641 +1884 +2330 +1804 +344 +698 +3089 +1532 +4454 +761 +8094 +3432 +6811 +8722 +8826 +3222 +8614 +2901 +7003 +652 +8663 +4266 +413 +810 +75 +3334 +4905 +6438 +4756 +5137 +6528 +6534 +6988 +6177 +8533 +889 +5384 +7201 +5132 +7802 +6864 +3973 +873 +4840 +1482 +8376 +3769 +5858 +6675 +4286 +2593 +5863 +4353 +7817 +7540 +4999 +4838 +2303 +7913 +1508 +7755 +2784 +4964 +3431 +6209 +3755 +6399 +3954 +455 +5416 +7591 +245 +140 +9210 +4084 +967 +7798 +6795 +7095 +6733 +3861 +9264 +1045 +755 +8042 +7074 +7778 +6415 +4724 +6450 +2049 +1307 +3485 +1790 +7869 +3282 +6907 +3920 +2868 +5801 +5632 +5009 +3955 +7517 +5128 +3417 +3019 +1784 +2312 +2753 +6976 +342 +8266 +1849 +2273 +5037 +7880 +3793 +7401 +5412 +8279 +1257 +3670 +9049 +3266 +8955 +6519 +8916 +2858 +694 +5650 +4669 +1785 +3533 +2704 +8603 +3726 +6668 +497 +6815 +6157 +6646 +6964 +8097 +5645 +8481 +8215 +3775 +2542 +7514 +5699 +3518 +3740 +1404 +8981 +4086 +6397 +4204 +6899 +682 +6589 +4340 +7424 +9208 +6504 +4409 +1 +145 +1882 +4620 +2634 +4992 +5453 +3377 +7875 +530 +1235 +7605 +504 +1771 +8489 +345 +7353 +7797 +7174 +5914 +2871 +5721 +6067 +3582 +5467 +6234 +691 +8758 +2122 +1213 +1492 +1437 +2187 +1266 +2395 +7278 +8491 +5256 +1554 +8163 +5966 +7128 +7904 +1691 +6272 +3996 +1706 +1334 +1316 +6478 +6935 +1518 +6700 +8703 +8744 +8152 +8778 +5367 +4218 +9007 +6312 +606 +7565 +5293 +2891 +675 +2120 +826 +7008 +5705 +7748 +8010 +1498 +5330 +5472 +2215 +7627 +3016 +6588 +1850 +4128 +8569 +6987 +148 +8151 +8789 +7907 +8596 +715 +9060 +3872 +1750 +5889 +4047 +5960 +3120 +3449 +1421 +1102 +3333 +9197 +8796 +8123 +8007 +2028 +8404 +1945 +1985 +8109 +5380 +3504 +6739 +4180 +5835 +4243 +25 +4002 +1976 +158 +5181 +4885 +8985 +11 +6425 +5926 +7062 +5083 +8394 +4259 +5844 +1990 +3942 +5532 +2220 +28 +5957 +149 +6748 +3559 +7647 +2566 +1359 +5259 +7010 +554 +6005 +8172 +8125 +1350 +9051 +1973 +1386 +159 +7007 +3220 +1846 +3093 +4445 +2056 +8370 +3211 +4384 +2231 +273 +642 +5311 +265 +226 +9012 +7879 +118 +7109 +7251 +1760 +8667 +2876 +7162 +3552 +6901 +6779 +5021 +6524 +4957 +3114 +4544 +441 +1848 +2136 +2458 +8662 +1127 +5541 +3026 +1080 +6780 +2224 +8259 +1073 +9000 +7244 +7977 +500 +4435 +7376 +7979 +1435 +9291 +7704 +3521 +210 +6269 +8570 +3285 +8039 +3546 +6203 +1183 +6107 +4147 +2234 +7185 +3192 +7155 +2001 +7777 +876 +944 +908 +7791 +6784 +65 +9172 +5675 +3886 +7891 +2978 +1008 +5630 +591 +5067 +1139 +577 +9015 +574 +8137 +7786 +5765 +4900 +4090 +7842 diff --git a/Stark/lib/train/data_specs/lasot_train_split.txt b/Stark/lib/train/data_specs/lasot_train_split.txt new file mode 100755 index 0000000..ffa2be4 --- /dev/null +++ b/Stark/lib/train/data_specs/lasot_train_split.txt @@ -0,0 +1,1120 @@ +airplane-10 +airplane-11 +airplane-12 +airplane-14 +airplane-16 +airplane-17 +airplane-18 +airplane-19 +airplane-2 +airplane-20 +airplane-3 +airplane-4 +airplane-5 +airplane-6 +airplane-7 +airplane-8 +basketball-10 +basketball-12 +basketball-13 +basketball-14 +basketball-15 +basketball-16 +basketball-17 +basketball-18 +basketball-19 +basketball-2 +basketball-20 +basketball-3 +basketball-4 +basketball-5 +basketball-8 +basketball-9 +bear-1 +bear-10 +bear-11 +bear-12 +bear-13 +bear-14 +bear-15 +bear-16 +bear-18 +bear-19 +bear-20 +bear-3 +bear-5 +bear-7 +bear-8 +bear-9 +bicycle-1 +bicycle-10 +bicycle-11 +bicycle-12 +bicycle-13 +bicycle-14 +bicycle-15 +bicycle-16 +bicycle-17 +bicycle-19 +bicycle-20 +bicycle-3 +bicycle-4 +bicycle-5 +bicycle-6 +bicycle-8 +bird-1 +bird-10 +bird-11 +bird-12 +bird-13 +bird-14 +bird-16 +bird-18 +bird-19 +bird-20 +bird-4 +bird-5 +bird-6 +bird-7 +bird-8 +bird-9 +boat-1 +boat-10 +boat-11 +boat-13 +boat-14 +boat-15 +boat-16 +boat-18 +boat-19 +boat-2 +boat-20 +boat-5 +boat-6 +boat-7 +boat-8 +boat-9 +book-1 +book-12 +book-13 +book-14 +book-15 +book-16 +book-17 +book-18 +book-2 +book-20 +book-4 +book-5 +book-6 +book-7 +book-8 +book-9 +bottle-10 +bottle-11 +bottle-13 +bottle-15 +bottle-16 +bottle-17 +bottle-19 +bottle-2 +bottle-20 +bottle-3 +bottle-4 +bottle-5 +bottle-6 +bottle-7 +bottle-8 +bottle-9 +bus-1 +bus-10 +bus-11 +bus-12 +bus-13 +bus-14 +bus-15 +bus-16 +bus-18 +bus-20 +bus-3 +bus-4 +bus-6 +bus-7 +bus-8 +bus-9 +car-1 +car-10 +car-11 +car-12 +car-13 +car-14 +car-15 +car-16 +car-18 +car-19 +car-20 +car-3 +car-4 +car-5 +car-7 +car-8 +cat-10 +cat-11 +cat-12 +cat-13 +cat-14 +cat-15 +cat-16 +cat-17 +cat-19 +cat-2 +cat-4 +cat-5 +cat-6 +cat-7 +cat-8 +cat-9 +cattle-1 +cattle-10 +cattle-11 +cattle-14 +cattle-15 +cattle-16 +cattle-17 +cattle-18 +cattle-19 +cattle-20 +cattle-3 +cattle-4 +cattle-5 +cattle-6 +cattle-8 +cattle-9 +chameleon-1 +chameleon-10 +chameleon-12 +chameleon-13 +chameleon-14 +chameleon-15 +chameleon-16 +chameleon-17 +chameleon-18 +chameleon-19 +chameleon-2 +chameleon-4 +chameleon-5 +chameleon-7 +chameleon-8 +chameleon-9 +coin-1 +coin-10 +coin-11 +coin-12 +coin-13 +coin-14 +coin-15 +coin-16 +coin-17 +coin-19 +coin-2 +coin-20 +coin-4 +coin-5 +coin-8 +coin-9 +crab-1 +crab-10 +crab-11 +crab-13 +crab-14 +crab-15 +crab-16 +crab-17 +crab-19 +crab-2 +crab-20 +crab-4 +crab-5 +crab-7 +crab-8 +crab-9 +crocodile-1 +crocodile-11 +crocodile-12 +crocodile-13 +crocodile-15 +crocodile-16 +crocodile-17 +crocodile-18 +crocodile-19 +crocodile-2 +crocodile-20 +crocodile-5 +crocodile-6 +crocodile-7 +crocodile-8 +crocodile-9 +cup-10 +cup-11 +cup-12 +cup-13 +cup-14 +cup-15 +cup-16 +cup-18 +cup-19 +cup-2 +cup-20 +cup-3 +cup-5 +cup-6 +cup-8 +cup-9 +deer-1 +deer-11 +deer-12 +deer-13 +deer-15 +deer-16 +deer-17 +deer-18 +deer-19 +deer-2 +deer-20 +deer-3 +deer-5 +deer-6 +deer-7 +deer-9 +dog-10 +dog-11 +dog-12 +dog-13 +dog-14 +dog-16 +dog-17 +dog-18 +dog-2 +dog-20 +dog-3 +dog-4 +dog-5 +dog-6 +dog-8 +dog-9 +drone-1 +drone-10 +drone-11 +drone-12 +drone-14 +drone-16 +drone-17 +drone-18 +drone-19 +drone-20 +drone-3 +drone-4 +drone-5 +drone-6 +drone-8 +drone-9 +electricfan-11 +electricfan-12 +electricfan-13 +electricfan-14 +electricfan-15 +electricfan-16 +electricfan-17 +electricfan-19 +electricfan-2 +electricfan-3 +electricfan-4 +electricfan-5 +electricfan-6 +electricfan-7 +electricfan-8 +electricfan-9 +elephant-10 +elephant-11 +elephant-13 +elephant-14 +elephant-15 +elephant-17 +elephant-19 +elephant-2 +elephant-20 +elephant-3 +elephant-4 +elephant-5 +elephant-6 +elephant-7 +elephant-8 +elephant-9 +flag-1 +flag-10 +flag-11 +flag-12 +flag-13 +flag-14 +flag-15 +flag-16 +flag-17 +flag-18 +flag-19 +flag-20 +flag-4 +flag-6 +flag-7 +flag-8 +fox-1 +fox-10 +fox-11 +fox-12 +fox-13 +fox-14 +fox-15 +fox-16 +fox-17 +fox-18 +fox-19 +fox-4 +fox-6 +fox-7 +fox-8 +fox-9 +frog-1 +frog-10 +frog-11 +frog-12 +frog-13 +frog-14 +frog-15 +frog-16 +frog-17 +frog-18 +frog-19 +frog-2 +frog-5 +frog-6 +frog-7 +frog-8 +gametarget-10 +gametarget-11 +gametarget-12 +gametarget-14 +gametarget-15 +gametarget-16 +gametarget-17 +gametarget-18 +gametarget-19 +gametarget-20 +gametarget-3 +gametarget-4 +gametarget-5 +gametarget-6 +gametarget-8 +gametarget-9 +gecko-10 +gecko-11 +gecko-12 +gecko-13 +gecko-14 +gecko-15 +gecko-17 +gecko-18 +gecko-2 +gecko-20 +gecko-3 +gecko-4 +gecko-6 +gecko-7 +gecko-8 +gecko-9 +giraffe-1 +giraffe-11 +giraffe-12 +giraffe-14 +giraffe-16 +giraffe-17 +giraffe-18 +giraffe-19 +giraffe-20 +giraffe-3 +giraffe-4 +giraffe-5 +giraffe-6 +giraffe-7 +giraffe-8 +giraffe-9 +goldfish-1 +goldfish-11 +goldfish-12 +goldfish-13 +goldfish-14 +goldfish-15 +goldfish-16 +goldfish-17 +goldfish-18 +goldfish-19 +goldfish-2 +goldfish-20 +goldfish-4 +goldfish-5 +goldfish-6 +goldfish-9 +gorilla-1 +gorilla-10 +gorilla-11 +gorilla-12 +gorilla-14 +gorilla-15 +gorilla-16 +gorilla-17 +gorilla-18 +gorilla-19 +gorilla-2 +gorilla-20 +gorilla-3 +gorilla-5 +gorilla-7 +gorilla-8 +guitar-1 +guitar-11 +guitar-12 +guitar-13 +guitar-14 +guitar-15 +guitar-17 +guitar-18 +guitar-19 +guitar-2 +guitar-20 +guitar-4 +guitar-5 +guitar-6 +guitar-7 +guitar-9 +hand-1 +hand-10 +hand-11 +hand-12 +hand-13 +hand-14 +hand-15 +hand-17 +hand-18 +hand-19 +hand-20 +hand-4 +hand-5 +hand-6 +hand-7 +hand-8 +hat-10 +hat-11 +hat-12 +hat-13 +hat-14 +hat-15 +hat-16 +hat-17 +hat-19 +hat-20 +hat-3 +hat-4 +hat-6 +hat-7 +hat-8 +hat-9 +helmet-1 +helmet-10 +helmet-12 +helmet-14 +helmet-15 +helmet-16 +helmet-17 +helmet-18 +helmet-2 +helmet-20 +helmet-3 +helmet-4 +helmet-6 +helmet-7 +helmet-8 +helmet-9 +hippo-10 +hippo-11 +hippo-12 +hippo-13 +hippo-14 +hippo-15 +hippo-16 +hippo-17 +hippo-18 +hippo-19 +hippo-2 +hippo-3 +hippo-4 +hippo-5 +hippo-6 +hippo-8 +horse-10 +horse-11 +horse-13 +horse-14 +horse-16 +horse-17 +horse-18 +horse-19 +horse-2 +horse-20 +horse-3 +horse-5 +horse-6 +horse-7 +horse-8 +horse-9 +kangaroo-1 +kangaroo-10 +kangaroo-12 +kangaroo-13 +kangaroo-15 +kangaroo-16 +kangaroo-17 +kangaroo-18 +kangaroo-19 +kangaroo-20 +kangaroo-3 +kangaroo-4 +kangaroo-6 +kangaroo-7 +kangaroo-8 +kangaroo-9 +kite-1 +kite-11 +kite-12 +kite-13 +kite-14 +kite-16 +kite-17 +kite-18 +kite-19 +kite-2 +kite-20 +kite-3 +kite-5 +kite-7 +kite-8 +kite-9 +leopard-10 +leopard-11 +leopard-12 +leopard-13 +leopard-14 +leopard-15 +leopard-17 +leopard-18 +leopard-19 +leopard-2 +leopard-3 +leopard-4 +leopard-5 +leopard-6 +leopard-8 +leopard-9 +licenseplate-1 +licenseplate-10 +licenseplate-11 +licenseplate-14 +licenseplate-16 +licenseplate-17 +licenseplate-18 +licenseplate-19 +licenseplate-2 +licenseplate-20 +licenseplate-3 +licenseplate-4 +licenseplate-5 +licenseplate-7 +licenseplate-8 +licenseplate-9 +lion-10 +lion-11 +lion-13 +lion-14 +lion-15 +lion-16 +lion-17 +lion-18 +lion-19 +lion-2 +lion-3 +lion-4 +lion-6 +lion-7 +lion-8 +lion-9 +lizard-10 +lizard-11 +lizard-12 +lizard-14 +lizard-15 +lizard-16 +lizard-17 +lizard-18 +lizard-19 +lizard-2 +lizard-20 +lizard-4 +lizard-5 +lizard-7 +lizard-8 +lizard-9 +microphone-1 +microphone-10 +microphone-11 +microphone-12 +microphone-13 +microphone-15 +microphone-17 +microphone-18 +microphone-19 +microphone-20 +microphone-3 +microphone-4 +microphone-5 +microphone-7 +microphone-8 +microphone-9 +monkey-1 +monkey-10 +monkey-11 +monkey-12 +monkey-13 +monkey-14 +monkey-15 +monkey-16 +monkey-18 +monkey-19 +monkey-2 +monkey-20 +monkey-5 +monkey-6 +monkey-7 +monkey-8 +motorcycle-10 +motorcycle-11 +motorcycle-12 +motorcycle-13 +motorcycle-14 +motorcycle-15 +motorcycle-16 +motorcycle-17 +motorcycle-19 +motorcycle-2 +motorcycle-20 +motorcycle-4 +motorcycle-5 +motorcycle-6 +motorcycle-7 +motorcycle-8 +mouse-10 +mouse-11 +mouse-12 +mouse-13 +mouse-14 +mouse-15 +mouse-16 +mouse-18 +mouse-19 +mouse-2 +mouse-20 +mouse-3 +mouse-4 +mouse-5 +mouse-6 +mouse-7 +person-11 +person-13 +person-14 +person-15 +person-16 +person-17 +person-18 +person-19 +person-2 +person-20 +person-3 +person-4 +person-6 +person-7 +person-8 +person-9 +pig-1 +pig-11 +pig-12 +pig-14 +pig-15 +pig-16 +pig-17 +pig-19 +pig-20 +pig-3 +pig-4 +pig-5 +pig-6 +pig-7 +pig-8 +pig-9 +pool-1 +pool-10 +pool-11 +pool-13 +pool-14 +pool-16 +pool-17 +pool-18 +pool-19 +pool-2 +pool-20 +pool-4 +pool-5 +pool-6 +pool-8 +pool-9 +rabbit-1 +rabbit-11 +rabbit-12 +rabbit-14 +rabbit-15 +rabbit-16 +rabbit-18 +rabbit-2 +rabbit-20 +rabbit-3 +rabbit-4 +rabbit-5 +rabbit-6 +rabbit-7 +rabbit-8 +rabbit-9 +racing-1 +racing-11 +racing-12 +racing-13 +racing-14 +racing-17 +racing-18 +racing-19 +racing-2 +racing-3 +racing-4 +racing-5 +racing-6 +racing-7 +racing-8 +racing-9 +robot-10 +robot-11 +robot-12 +robot-13 +robot-14 +robot-15 +robot-16 +robot-17 +robot-18 +robot-2 +robot-20 +robot-3 +robot-4 +robot-6 +robot-7 +robot-9 +rubicCube-10 +rubicCube-11 +rubicCube-12 +rubicCube-13 +rubicCube-15 +rubicCube-16 +rubicCube-17 +rubicCube-18 +rubicCube-2 +rubicCube-20 +rubicCube-3 +rubicCube-4 +rubicCube-5 +rubicCube-7 +rubicCube-8 +rubicCube-9 +sepia-1 +sepia-10 +sepia-11 +sepia-12 +sepia-14 +sepia-15 +sepia-17 +sepia-18 +sepia-19 +sepia-2 +sepia-20 +sepia-3 +sepia-4 +sepia-5 +sepia-7 +sepia-9 +shark-1 +shark-10 +shark-11 +shark-12 +shark-13 +shark-14 +shark-15 +shark-16 +shark-17 +shark-18 +shark-19 +shark-20 +shark-4 +shark-7 +shark-8 +shark-9 +sheep-1 +sheep-10 +sheep-11 +sheep-12 +sheep-13 +sheep-14 +sheep-15 +sheep-16 +sheep-17 +sheep-18 +sheep-19 +sheep-2 +sheep-20 +sheep-4 +sheep-6 +sheep-8 +skateboard-1 +skateboard-10 +skateboard-11 +skateboard-12 +skateboard-13 +skateboard-14 +skateboard-15 +skateboard-17 +skateboard-18 +skateboard-2 +skateboard-20 +skateboard-4 +skateboard-5 +skateboard-6 +skateboard-7 +skateboard-9 +spider-1 +spider-10 +spider-11 +spider-12 +spider-13 +spider-15 +spider-17 +spider-19 +spider-2 +spider-3 +spider-4 +spider-5 +spider-6 +spider-7 +spider-8 +spider-9 +squirrel-1 +squirrel-10 +squirrel-12 +squirrel-14 +squirrel-15 +squirrel-16 +squirrel-17 +squirrel-18 +squirrel-2 +squirrel-20 +squirrel-3 +squirrel-4 +squirrel-5 +squirrel-6 +squirrel-7 +squirrel-9 +surfboard-1 +surfboard-10 +surfboard-11 +surfboard-13 +surfboard-14 +surfboard-15 +surfboard-16 +surfboard-17 +surfboard-18 +surfboard-19 +surfboard-2 +surfboard-20 +surfboard-3 +surfboard-6 +surfboard-7 +surfboard-9 +swing-1 +swing-11 +swing-12 +swing-13 +swing-15 +swing-16 +swing-18 +swing-19 +swing-2 +swing-3 +swing-4 +swing-5 +swing-6 +swing-7 +swing-8 +swing-9 +tank-1 +tank-10 +tank-11 +tank-12 +tank-13 +tank-15 +tank-17 +tank-18 +tank-19 +tank-2 +tank-20 +tank-3 +tank-4 +tank-5 +tank-7 +tank-8 +tiger-1 +tiger-10 +tiger-11 +tiger-13 +tiger-14 +tiger-15 +tiger-16 +tiger-17 +tiger-19 +tiger-2 +tiger-20 +tiger-3 +tiger-5 +tiger-7 +tiger-8 +tiger-9 +train-10 +train-12 +train-13 +train-14 +train-15 +train-16 +train-17 +train-18 +train-19 +train-2 +train-3 +train-4 +train-5 +train-6 +train-8 +train-9 +truck-1 +truck-10 +truck-11 +truck-12 +truck-13 +truck-14 +truck-15 +truck-17 +truck-18 +truck-19 +truck-2 +truck-20 +truck-4 +truck-5 +truck-8 +truck-9 +turtle-1 +turtle-10 +turtle-11 +turtle-12 +turtle-13 +turtle-14 +turtle-15 +turtle-17 +turtle-18 +turtle-19 +turtle-2 +turtle-20 +turtle-3 +turtle-4 +turtle-6 +turtle-7 +umbrella-1 +umbrella-10 +umbrella-11 +umbrella-12 +umbrella-13 +umbrella-14 +umbrella-15 +umbrella-16 +umbrella-18 +umbrella-20 +umbrella-3 +umbrella-4 +umbrella-5 +umbrella-6 +umbrella-7 +umbrella-8 +volleyball-10 +volleyball-11 +volleyball-12 +volleyball-14 +volleyball-15 +volleyball-16 +volleyball-17 +volleyball-2 +volleyball-20 +volleyball-3 +volleyball-4 +volleyball-5 +volleyball-6 +volleyball-7 +volleyball-8 +volleyball-9 +yoyo-1 +yoyo-10 +yoyo-11 +yoyo-12 +yoyo-13 +yoyo-14 +yoyo-16 +yoyo-18 +yoyo-2 +yoyo-20 +yoyo-3 +yoyo-4 +yoyo-5 +yoyo-6 +yoyo-8 +yoyo-9 +zebra-1 +zebra-11 +zebra-12 +zebra-13 +zebra-15 +zebra-18 +zebra-19 +zebra-2 +zebra-20 +zebra-3 +zebra-4 +zebra-5 +zebra-6 +zebra-7 +zebra-8 +zebra-9 diff --git a/Stark/lib/train/data_specs/trackingnet_classmap.txt b/Stark/lib/train/data_specs/trackingnet_classmap.txt new file mode 100755 index 0000000..cfbfec4 --- /dev/null +++ b/Stark/lib/train/data_specs/trackingnet_classmap.txt @@ -0,0 +1,30134 @@ +Nf1aqv5Fg5o_0 airplane +AAB6lO-XiKE_0 person +AACM71csS-Q_0 person +AACM71csS-Q_1 person +AARNQeeGCeM_1 person +AARldOxX9Qc_0 bird +AATSbTthMRo_1 person +AAVQ--F7Bk8_7 bird +AAVQ--F7Bk8_2 bird +AAVQ--F7Bk8_8 bird +AAWK6esRYaE_0 person +AAWK6esRYaE_1 person +AAjY2Ci68z8_0 person +AA19zjGEPvg_1 bear +AA28Bcp5cJ4_0 train +ABBGULxaufw_0 person +ABF8Qzi1y6k_1 bear +ABIlEiPfEC4_0 bird +ABJ_agLToOw_0 bird +ABZMoeeFyek_0 bicycle +ABny-jw1_S0_0 elephant +ABrhnT3LRWs_2 cat +ABxlnMGfo5c_0 umbrella +AByCCGnybVU_1 person +AB2MjrpRiEQ_0 horse +AB-q-hxh9XQ_4 bus +AB-q-hxh9XQ_1 bus +AB-q-hxh9XQ_3 bus +ACDuy9fWQCs_1 umbrella +ACFxVnoXE2k_1 horse +ACMvGMt8Neo_0 person +ACM6PJWHfcM_0 person +ACOGOPL4ZH0_1 person +ACOGOPL4ZH0_0 person +ACS5TtaAdG8_0 truck +ACarEC5tuT8_0 truck +ACiNZsAvVTE_0 person +ACkYaVC9f9M_1 umbrella +ACnQKLobnGE_4 airplane +ACnQKLobnGE_5 airplane +AC0Z4yw1hf0_0 person +AC0Z4yw1hf0_1 person +AC-10OYYnLM_1 person +AC-10OYYnLM_0 person +ADHNPU5iB_4_0 cat +ADWpC6kDWFU_0 person +ADiIG2D8pds_2 motorcycle +ADiIG2D8pds_0 motorcycle +ADi674XOuRY_0 dog +ADn8ZdVYOcc_0 train +ADn8ZdVYOcc_2 train +AD1cVG81mpA_0 person +AD4EACfWAIM_0 horse +AD4EACfWAIM_1 horse +AD531xkux4k_0 person +AD7A6_o0Las_0 horse +AEQT6XxEeT0_0 person +AEQT6XxEeT0_1 person +AESfphazWKA_0 person +AESfphazWKA_1 person +AEokTVMPd4A_0 person +AEtwwIR9UkI_0 dog +AE2TrzJHr2s_1 motorcycle +AE3t_VNk3eo_0 person +AE6G6W2CL9M_1 person +AE7tEK8S9pk_0 bird +AE7tEK8S9pk_3 bird +AE-k9jcdaJk_1 giraffe +AFLrK88FzTI_0 motorcycle +AFOjy-9Kf-8_0 person +AFSTw_O6inE_0 person +AFSTw_O6inE_1 person +AFT64SYoPTo_1 person +AFeRUltwvNE_0 knife +AFeRUltwvNE_2 knife +AFf9I30fB6U_0 person +AFkSCsJ_jeg_0 person +AFkSCsJ_jeg_1 person +AFnPp9mvoJs_0 horse +AFpVfranYCA_1 knife +AFrLubifeb4_0 airplane +AFrLubifeb4_2 airplane +AFsmSsZBS6I_1 person +AFsmSsZBS6I_0 person +AF0FDnfdpro_0 train +AF0-2lDeBME_1 bird +AF2bYjH_Q8c_0 person +AF4nO1MeUis_1 train +AGV9gZ6ePKk_0 airplane +AGXVFK896Os_0 cow +AGYehDNUqx0_1 airplane +AGYehDNUqx0_0 airplane +AGdqwMVGRoU_0 horse +AGfcGfMXHPM_3 elephant +AGsg2IV8FME_1 skateboard +ZBPURFcpqDM_0 motorcycle +ZBXAMWkamQk_2 knife +ZBXAMWkamQk_1 knife +ZBcCcSynS3Y_1 car +ZBcTSnaCcqE_1 person +ZBcTSnaCcqE_0 person +ZBcjhADZaUk_0 bear +ZBdz7fg01uE_0 umbrella +ZBp5ICCzoK8_0 person +ZBriZpPQR6Q_0 cat +ZBvEIHeKcKg_2 zebra +ZBvEIHeKcKg_9 zebra +ZBvEIHeKcKg_0 zebra +ZBvEIHeKcKg_1 zebra +ZBvEIHeKcKg_3 zebra +ZBvEIHeKcKg_4 zebra +ZBvEIHeKcKg_5 zebra +ZBvEIHeKcKg_6 zebra +ZBvEIHeKcKg_7 zebra +ZBvEIHeKcKg_8 zebra +ZB0EfmbWfng_0 horse +ZB0kV8Ni0e8_0 person +ZB_pe6v1lVI_0 person +ZB_pe6v1lVI_2 person +ZCAOpABRfTI_10 elephant +ZCAOpABRfTI_0 elephant +ZCAOpABRfTI_3 elephant +ZCAOpABRfTI_4 elephant +ZCAOpABRfTI_6 elephant +ZCAOpABRfTI_7 elephant +ZCAOpABRfTI_8 elephant +ZCFCltdIjeg_1 person +ZCFCltdIjeg_0 person +ZCGB4r_lWmY_0 horse +ZCS_eyAufDo_0 person +ZCTwXcewINc_0 cow +ZCfqT4CDOYA_1 bird +ZCgDbEHLsIg_0 person +ZClABNZVqqw_1 person +ZCmoG6WgVO4_1 person +ZCmoG6WgVO4_0 person +ZCnJ6weWtz8_1 person +ZCnJ6weWtz8_0 person +ZCnJ6weWtz8_2 person +ZCzrSOZhkx8_1 person +ZCzrSOZhkx8_2 person +ZC3Y42jSG_0_0 person +ZC5Jtr93Fc0_0 cat +ZDDtjYsFrzY_0 motorcycle +ZDMLHna_uZU_1 skateboard +ZDMSLfnIpw0_0 person +ZDS-TQTDheA_0 person +ZDWUEeCoa0c_0 person +ZDfRsMjEWrU_0 person +ZDucdx9SldA_0 bicycle +ZDwG7VWIZ2E_0 motorcycle +ZDw-tgE8yQw_0 person +ZEA5lDwY3hY_0 person +ZERPmLuCNr0_1 skateboard +ZEYyXBrvcIU_0 person +ZEbxfeAOLec_1 motorcycle +ZEdGptkowmk_2 cow +ZEdsROg2ZAk_2 horse +ZEgcTqeZxOk_1 person +ZEiW5hvCQyM_0 bird +ZE16Mis16oE_0 bus +ZE3Vro7d4pA_0 cat +ZE415SbIjYI_7 bird +ZE5h8vmL_Vw_0 boat +ZE6oeN8ZzDA_1 person +ZE6oeN8ZzDA_0 person +ZFKQ9r76HHU_1 elephant +ZFKYTz9Jkhw_0 umbrella +ZFSspVdQ_1M_0 person +ZFSspVdQ_1M_1 person +ZFe5vGzmYgY_0 bear +ZFe5vGzmYgY_4 bear +ZFfH8M8dMH8_5 bird +ZFk9b7tQz1g_0 person +ZFn422HSENU_2 airplane +ZFw7fJO3h3U_0 motorcycle +ZF2yE0Tm8D0_0 cow +ZF5yV-qvHfg_0 bicycle +ZF8rySXBivY_0 person +ZF_u1UFqAvg_0 person +ZGHtP6pLosk_0 person +ZGT9Ky1jJ0E_0 horse +ZGWqLNy2PDM_2 bird +ZGeWYNFOH7U_0 person +ZGhdqsb3kNA_0 car +ZGhdqsb3kNA_3 car +ZGhdqsb3kNA_1 car +ZGkmBkelEBU_0 person +ZGpMZT1HUiw_0 horse +ZGsHiz0oPuw_0 bus +ZGvfU-Fgk40_1 person +ZGyWFwMmdbs_0 person +ZG9dVnPGocw_0 person +ZHDkDNgRSz0_0 train +ZHFPykjdFAY_1 person +ZHPeB20mRyI_0 cow +ZHPeB20mRyI_1 cow +ZHX1xXuU_Jw_0 person +ZHlb-NoDPiE_1 elephant +ZHlb-NoDPiE_2 elephant +ZHlb-NoDPiE_4 elephant +ZHl7b8RItn0_0 horse +ZHnW6ge8wBc_0 cat +ZHodaPFcFYU_0 person +ZHovXJVH8xk_0 truck +ZHpZ3CGHl44_0 person +ZHrrW673jzQ_1 person +ZHrrW673jzQ_0 person +ZHrsTuxP7aI_1 horse +ZHu6CNOlw3g_0 cow +ZHu6CNOlw3g_1 cow +ZHxx4jT0QY8_0 person +ZH1tP4KBq4c_0 giraffe +ZH5HXdNA_Vg_0 person +ZH-X6nu5grI_33 horse +ZH-X6nu5grI_2 horse +ZH-X6nu5grI_3 horse +ZH-X6nu5grI_6 horse +ZH-X6nu5grI_7 horse +ZH-X6nu5grI_8 horse +ZH_6GNzE7AE_0 person +ZIAnd6kIMac_0 bird +ZIAnd6kIMac_1 bird +ZICz-o8kLz0_0 skateboard +AGx9YQ6C-6o_7 car +AG1KXUn4YG0_0 person +AG_bCNeWGbQ_0 elephant +AHARpIfT490_0 dog +AHIF--VOeQs_0 person +AHJcPNPqKmI_0 horse +AHKFqtjfRZA_2 bear +AHLL47_EdEA_1 person +AHLL47_EdEA_0 person +AHNC2jifaeA_1 airplane +AHQLEaBATbw_0 person +AHQW1ru8IzY_0 airplane +AHQrFFp5yq4_0 airplane +AHiwgwMi8HU_0 dog +AHjEWaIP4Us_0 cow +AHkvSb7kMDQ_0 person +AHn7KxEbpSw_0 person +AHvhccaU6e0_0 bus +AHx-m9m2WSM_0 person +AIAtwCnT8D0_1 person +AIBVp_3pm4U_1 person +AIBVp_3pm4U_0 person +AIFwUvUUIAU_1 person +AIPKb-NMVjk_0 airplane +AIPKb-NMVjk_3 airplane +AIVpT8BRXaQ_1 horse +AIYDjtWzamM_0 bear +AIYDjtWzamM_1 bear +AIZGolX95Do_0 person +AIbvvs9Mppk_0 person +AIduTWoo-tY_0 skateboard +AIeFzUH7L38_1 train +AIkHZuaZGZc_1 elephant +AIkHZuaZGZc_2 elephant +AIpwAHaTBsI_0 train +AI00Hva5A8g_0 person +AI38cuNcfsE_0 knife +AI73dwp8OlI_1 train +AJAy74dPvNA_0 person +AJCXZxF7mEU_1 skateboard +AJDMiWpRbdY_0 person +AJILdTCo1mA_0 dog +AJKXpUsj3I0_0 bird +AJRdbCnFyVo_0 elephant +AJTfeXepoNQ_0 bus +AJZ65x_ashE_0 airplane +AJaOK6nLWLU_0 person +AJaOK6nLWLU_1 person +AJaOK6nLWLU_2 person +AJh6EhObuEU_0 person +AJiQZJH_ZsU_0 bird +AJiYw7-oCvA_1 knife +AJiYw7-oCvA_2 knife +AJiYw7-oCvA_0 knife +AJkWw2b2Qjg_0 horse +AJor90pfjM8_0 cow +AJtuQLfNvSs_0 cat +AKBoEjrtQwE_1 train +AKDi2KVrR1Q_0 skateboard +AKIcyYzL9C0_0 cat +AKMl62ZFICw_3 bus +AKMl62ZFICw_1 bus +AKN6nvHB7P0_2 airplane +AKN6nvHB7P0_3 airplane +AKPDvaUNx94_1 horse +AKPDvaUNx94_2 horse +AKVUSpeg9Jk_0 knife +AKxpzCrmsi8_0 bus +AK4AJfDZfEo_0 cat +AK64udGI1BA_0 umbrella +AK8imx-InYk_1 horse +AK8imx-InYk_2 horse +AK_J57sNeeo_1 elephant +AK_0-KHw9wc_1 horse +ALCj6V-0pU8_0 person +ALKBlOms7sk_0 truck +ALLYkPepYRc_0 train +ALRR_HHP500_0 person +ALRzJ2FzEoY_0 person +ALYKJChPG6k_0 knife +ALjxXEqJFTg_0 train +ALpnjTPWIN4_0 bird +AL73oE_aovA_2 bicycle +AL73oE_aovA_3 bicycle +AMDjY36EpsU_0 truck +AMEZhZVe7hk_0 person +AMEZhZVe7hk_1 person +AMI4Xu1mmNw_0 elephant +AMZeyszxY78_0 knife +AMn7aithVV8_0 car +AMz8PhUkmpM_0 horse +AMz8PhUkmpM_3 horse +AMz8PhUkmpM_7 horse +AMz8PhUkmpM_2 horse +AMz8PhUkmpM_5 horse +AM5_HQ705r4_1 giraffe +AM6sweCILPU_0 airplane +ANHdxFi36CM_1 bird +ANNbcEcj8Do_0 person +ANQZ1MB6gI4_0 skateboard +ANVkluf6XZA_0 cat +ANWtZTJoYYc_0 dog +ANZDRJnX_Os_0 person +ANlhuKqnObE_1 person +ANlhuKqnObE_0 person +ANmJ_3l01rw_2 horse +ANmJ_3l01rw_3 horse +ANmkxc2V7qQ_0 person +ANufFQ7Fqao_0 car +ANufFQ7Fqao_1 car +ANvWNG7bZj0_0 person +ANwXehjlmOU_0 giraffe +ANwXehjlmOU_2 giraffe +ANwXehjlmOU_6 giraffe +ANwXehjlmOU_7 giraffe +AOFbvqQZz1M_0 person +AOJiO3o1Pgw_0 person +AONi1Rhl0VI_2 person +AONi1Rhl0VI_1 person +AOmvm3OOZZQ_0 person +AOn9I3GEHoU_0 person +AOo1qXfZWsc_0 bus +AOq0zSQhX1E_0 person +AOq0zSQhX1E_1 person +AO9zthhr-og_0 person +AO9zthhr-og_1 person +APAgxsDsZqs_0 person +APCppiM1SL4_0 person +APEd6F66jXU_1 airplane +APHhGoshqFo_0 umbrella +APIrIPchQwg_1 person +APIrIPchQwg_0 person +APJ4_CEV8HQ_0 bus +APLJsXaOe1c_0 person +APQ99QCF6pA_0 person +APRuUBgcBZc_1 person +APYAGnOjUQQ_0 person +APa_Xoa9qgg_1 motorcycle +APcliMIvBe4_2 person +APcliMIvBe4_0 person +APcliMIvBe4_1 person +APp-0CsKxpY_1 person +APp-0CsKxpY_0 person +APqdtMhtWlU_0 motorcycle +APtqUIS_Hyo_0 person +APwqoNNZyaA_0 person +APyVeEcEt1U_0 airplane +APyxRCm1XlY_0 person +AP5QrGcnGoU_0 cow +AP_vNEBzhqM_0 person +AQALHMjkeh0_1 giraffe +AQKHDJ9HKck_0 dog +AQNEkyvgbeA_1 cow +AQRKvHpsUk8_0 person +AQTk87BXkxk_0 person +AQVhyDD8GEk_0 person +AQVthZjIETQ_0 truck +AQcg3TVkW1s_0 person +AQcg3TVkW1s_1 person +AQi0YSJ74cw_0 person +AQj3enGQQeE_0 boat +AQminPRA2W8_0 person +AQtIgG8RHRY_0 person +AQvltP0EarU_0 person +AQy7gL42wfo_0 airplane +AQzJp7Qi_yA_2 elephant +AQzJp7Qi_yA_13 elephant +AQ2bfY90nuU_0 person +AQ7YDkmwB4M_0 dog +ARAX6-JmsNQ_0 zebra +ARAX6-JmsNQ_2 zebra +ARFd2qxDhpQ_0 airplane +ARNkmINZamQ_0 cow +ARNkmINZamQ_1 cow +AROrQJq2sWY_0 person +ARRADkl3-30_0 person +ARW5DipSrBo_0 dog +ARmfFWE2ruc_0 person +ARmsnBnMyPc_0 person +ARnGZQm8zOM_0 truck +ARqQUEVhu24_0 person +ARrbFDLoy0Q_1 person +ARtGNhHj2NU_0 cat +ARyGQdkbuyM_0 person +ARyGQdkbuyM_1 person +ASBgE1svBKQ_0 person +ASD516fNs3g_0 person +ASExrIzixaM_0 truck +ASc0m6oxXVI_0 person +ASc0m6oxXVI_1 person +ASm_mkHCybA_0 cat +AS1xCm7MYs8_0 person +AS1xCm7MYs8_1 person +AS2tsNB9LBI_1 knife +AS5hg_3pOXM_0 person +AS9kBpj7qvE_0 person +ATKytgCulZM_0 umbrella +ATakdxmz3qU_0 car +ATkJNKtd8yo_0 person +ATk9e0fbxBk_0 horse +ATk9e0fbxBk_1 horse +ATk9e0fbxBk_2 horse +AT1zSxV6stw_0 cat +AT5urL0Fr0c_0 bird +AUGQ4XFEkGY_3 knife +AUI-RsDtk4s_0 person +AUMHV6JiwU0_0 bird +AUZevw68t_s_0 bear +AUcOQ1L4Nj0_0 train +AUfaVvy5QxU_0 train +AUguk_8JO_U_0 skateboard +AUgw-t2MrtU_0 person +AUzge-cBHfM_0 bear +AU0RtWdAXcU_0 person +AU114x-Qif4_0 person +AU3mKa0Npq4_0 person +AU8GXMxyP9U_0 person +AVHVVt5Srow_0 bear +ZIGThAlQuUU_1 truck +ZIGkCx4o3G0_0 person +ZIMLdoIIFbg_0 person +ZIWkcVTlaRU_1 person +ZIamYwe-hJ8_0 car +ZIawXDt6JH4_0 cat +ZIlyoSrDQQ8_0 person +ZImLYekhFBQ_3 bus +ZI6J2WSiZy0_0 giraffe +ZI7DX2OSzzQ_0 airplane +ZJCSQFa1W3M_0 person +ZJDAzZZQ38k_1 knife +ZJDAzZZQ38k_0 knife +ZJEQHkA9NLw_1 truck +ZJHeFXEtwNE_0 knife +ZJJoit687Tc_0 person +ZJJpIPciUts_2 skateboard +ZJL9WONxDB8_0 person +ZJMJBrWq8-o_0 person +ZJOVhmSGVMM_0 person +ZJXuyIEaSc4_0 horse +ZJYXcUOxNRc_1 person +ZJdKrkzHR94_0 person +ZJdKrkzHR94_1 motorcycle +ZJe2QoJwNa0_0 horse +ZJimYyH6VUI_0 car +ZJoQRLyRs8o_0 person +ZJpozi2Piqc_0 motorcycle +ZJwWllfPFjo_0 person +ZJyDrvmQwY8_0 elephant +ZJyDrvmQwY8_1 elephant +ZJ5n1Y-yXqM_0 person +ZKF4kfqyu6U_0 person +ZKIuqz6GDSA_0 horse +ZKJuI7-4560_0 cat +ZKKalWR8MBM_0 boat +ZKSF-y6kC1I_0 elephant +ZKSF-y6kC1I_1 elephant +ZKTseP8JqIw_0 person +ZKk703iOFmY_0 horse +ZKrJdHuvvR8_0 person +ZKy67yESvjM_0 person +ZK1zKp1iJY4_5 elephant +ZK1zKp1iJY4_2 elephant +ZK3-Em8w4HE_0 horse +ZK6pkPtSd_4_0 cow +ZK_BL_TGwo0_1 train +ZLFXKnOp0LM_1 knife +ZLH6HbQ5Miw_0 person +ZLSqYLLWQLc_1 cow +ZLSqYLLWQLc_2 cow +ZLcGyr4ZfJU_1 airplane +ZLdb8-YkoiY_0 person +ZLm8Hen6OFM_1 bicycle +ZLm8Hen6OFM_2 bicycle +ZLnf4vSxfgo_1 umbrella +ZLqSGXI7FdM_3 knife +ZLuY9hS-wd4_0 bus +ZLuY9hS-wd4_1 bus +ZLuY9hS-wd4_2 bus +ZLupIiWNPOY_0 person +ZL18xmfIKH4_1 motorcycle +ZL18xmfIKH4_3 motorcycle +ZL18xmfIKH4_2 motorcycle +ZL3DgidLXjw_0 person +ZL5SCZpZWtA_1 horse +ZL-60We4drw_0 dog +ZMDe7QMaLa8_0 person +ZMD2tP69gaU_1 person +ZMKFhrS_QnY_0 cow +ZML6VoRZ_Tk_0 person +ZMMDA6nYXZs_0 bird +ZMPdl-1FCMQ_0 person +ZMZU_V7d3-I_1 umbrella +ZMa0bYeg_NE_0 dog +ZMdAlm9Zx_A_1 car +ZMeQ1Vc3HZk_0 person +ZMuwZKOfK1s_0 motorcycle +ZMvdpTH-1Ug_9 airplane +ZMxu4wRDuqU_1 person +ZMyEEXdgJeA_0 person +ZM1xadWQqKQ_0 bus +ZM2SMTrxUr0_0 train +ZM3QVkm1izg_0 person +ZM5-iyB8rFk_1 dog +ZM_TO-0UDp4_0 person +ZNJ8aytwo1E_0 person +ZNP23sy27W0_0 person +ZNTqZ3wERJE_0 person +ZNUBh1ppeyo_0 skateboard +ZNXCWGzmxK8_0 person +ZNZx7hTxCQE_0 airplane +ZNaTV3nGl6M_0 person +ZNcUW5m7eRw_0 giraffe +ZNg9OZgsMqc_0 bear +ZNoQrAOf3Ns_0 truck +ZNqpyPcacjY_0 motorcycle +ZNv_LrEIljc_0 umbrella +ZNxw9kVCouU_0 bus +ZNzeI_r7GT4_0 truck +ZN2bt7wkvH0_1 bear +ZN5ukEMKLY4_0 cow +ZN_gFe4IzxE_0 truck +ZODUj9lsCzk_0 horse +ZOEa1JGwnwE_0 person +ZOEa1JGwnwE_1 person +ZOGP8-XsFYc_0 person +ZOIuTsiGyRY_0 bird +ZOJSvR5KOsE_0 dog +ZOMPRnYycak_2 cow +ZOMnEZ4dWMk_0 elephant +ZOStUYUIEdA_0 skateboard +ZOTSBcRwdRA_0 person +ZOX1xH7rOus_0 train +ZOthVGHUcjo_3 cow +ZOwhFlp5EiA_0 person +ZOxDsYnvl0M_0 person +ZOymkqw58fw_0 person +ZOzQfVh1LN8_1 motorcycle +ZO_5hZ2ex6Y_0 person +ZPKaBLqoKvQ_0 person +ZPNr3zZg6jk_1 person +ZPNr3zZg6jk_0 person +ZPNr3zZg6jk_2 person +ZPQ0lqiH9uw_0 train +ZPQ0lqiH9uw_1 train +ZPQ3tbJp33I_0 train +ZPVOrRypdRM_0 horse +ZPZjgecd6OQ_1 boat +ZPaWYb_4S8Y_0 person +ZPeRU9CLLew_0 person +ZPgUlFmZyP4_0 person +ZPjN0Rp_1ZA_0 horse +ZPkO4x8HPaI_1 person +ZPqs3xJ8sMY_0 person +ZPqs3xJ8sMY_1 person +ZPq9qgTZ4XI_0 truck +ZPyxQD17Fq4_2 person +ZPyxQD17Fq4_4 person +ZP7SN9kW5kg_0 person +ZP7sET2Y9dU_0 person +ZP8YaHDM_qE_0 horse +ZQCFPzE41bg_0 cow +ZQDoAEWZCQk_0 person +ZQG5CpZ3fLM_0 person +ZQRzkpfy378_0 bus +ZQZRNVrE9hk_0 person +ZQarE1lLDl4_0 person +ZQdhjMVGJrk_0 person +ZQdhjMVGJrk_1 person +ZQmTc5C-h8w_0 person +ZQrMMWQidx0_0 person +ZQuVUoqiT_I_0 giraffe +ZQuVUoqiT_I_1 giraffe +ZQ3LAYCIDf8_3 bear +ZQ8X2cqYANs_0 train +ZQ9G0UkTR1c_1 person +ZQ_vGl5xbKY_0 cat +ZRFMzM7kxuI_3 cow +ZRFMzM7kxuI_0 cow +ZRFMzM7kxuI_1 cow +ZRFMzM7kxuI_2 cow +ZRLkkoSR8o8_0 knife +ZRMOgw0VYRI_0 person +ZRNQrzQlVwA_0 person +ZRNgdckx504_0 person +ZRQug2qT1tc_0 person +ZRSRBBpyBG8_0 person +ZRXjiNMKvis_0 airplane +ZRc8GDK_9hc_1 umbrella +ZRkHgC0EAz8_0 person +ZRmkeBogj-U_0 person +ZRoz_bGkPaE_0 person +ZRuQ3ipcK3o_0 bus +ZRzOWgIAwe8_0 bird +ZRzOWgIAwe8_3 bird +ZR0Qj5P8snw_1 bear +ZR4yO1ASDwo_2 person +ZR_VWPjxLTU_0 dog +ZSDCxbSs-Hs_0 person +ZSFzv92w5z4_0 motorcycle +ZSGJwERlcvM_0 person +ZSXoUfKY7t8_0 person +ZSdzUC2BB8Q_0 train +ZSdzUC2BB8Q_1 train +ZSkkNWgXm6E_0 skateboard +ZSkkNWgXm6E_1 skateboard +ZSn4gRAJToo_0 cat +ZSoJT194AtI_1 skateboard +ZSoJT194AtI_0 skateboard +ZSruK26cGuI_0 dog +ZSs6Knma-Q0_0 cow +ZSs6Knma-Q0_1 cow +ZSu3GocMJzI_0 car +ZS29l3t9vK8_0 person +ZS6NQXztroI_0 person +ZS_wuZnVzbw_0 person +ZTLDJDjvSuQ_0 truck +ZTPTnzEs_Lc_0 person +ZTcRmNM1n8M_0 person +ZTjOZ-dZDEg_1 car +ZTmHHCmX7aw_0 skateboard +ZTnEKCqMNHs_0 person +ZTo33r_63Wg_0 knife +ZTw6Dkp-LPU_7 elephant +ZTw6Dkp-LPU_0 elephant +ZTw6Dkp-LPU_4 elephant +ZTw6Dkp-LPU_5 elephant +ZTw6Dkp-LPU_6 elephant +ZT5iwG3vEhM_0 umbrella +ZUCf2cVBY08_0 person +ZUWSpLaJj4M_0 bird +ZUYtIKrcaKo_0 person +ZUaHjAaQqF0_0 bus +ZUdCQl7WU_U_1 person +ZUdCQl7WU_U_0 person +ZUd0IAbilBA_0 elephant +ZUoFqGf_ijs_0 elephant +ZUoJFmQ6ro4_0 person +ZUwniKcHERQ_0 horse +ZU0WSpOWSak_1 bear +ZU0_sT3EbVY_0 zebra +ZU9LGiLzKJg_0 motorcycle +ZU-ZhVyhBpA_1 bicycle +ZVAHreexSa0_0 person +ZVBjo5HM0Do_0 knife +ZVD-ea5SjMg_0 person +ZVJpmiue5IA_0 truck +ZVKyUsgomW4_0 person +ZVOMkt8TORM_0 train +ZVQo_9tFZGY_0 bus +ZVY_873YYQY_0 skateboard +ZVZJRbJ2h1A_0 cat +ZViLnbCdjZM_1 person +ZVlOetMc3m4_0 person +ZVl8So4V1Ss_0 cat +ZVnaHf8vAhA_0 zebra +ZVtPRAs8Za0_0 person +ZV8NIO3XuLQ_0 person +ZV9eJe2grq4_1 bear +ZWIPlBvd1DI_0 person +ZWIPlBvd1DI_1 person +ZWJv_-wAdws_1 skateboard +ZWKHlq-W7_8_9 train +ZWKHlq-W7_8_14 train +ZWKHlq-W7_8_0 train +ZWKHlq-W7_8_1 train +ZWKHlq-W7_8_4 train +ZWKHlq-W7_8_7 train +ZWKHlq-W7_8_10 train +ZWKHlq-W7_8_11 train +ZWKHlq-W7_8_12 train +ZWKHlq-W7_8_13 train +ZWNe-zcl-IY_0 boat +ZWNjUm5Uzh0_1 bicycle +ZWNjUm5Uzh0_5 bicycle +ZWXE7IAaWrg_0 person +ZWXSnELtawA_1 knife +ZWXSnELtawA_3 knife +ZWX1cGhJG98_0 bicycle +ZWlTD6EbOTo_0 person +ZWqzdCz6UvY_0 bird +ZWr6RECjqV0_1 horse +ZWr6ZU_-ir4_1 person +ZWthtO1iGtQ_0 person +ZWwlzozPAk8_0 person +ZWxn8yT0bXo_0 cow +ZW0HC4IRa64_0 person +ZW3CWoXzrn4_0 bicycle +ZW3CWoXzrn4_1 bicycle +ZW5VkDNSfWA_0 cat +ZXMqiFE6KOE_0 airplane +ZXRcWIcok2I_0 person +ZXgYAh2AWyk_0 horse +ZXp6jOe8DUE_0 person +ZXyJafbGcBM_0 horse +ZXzno8CjUyM_0 elephant +ZYB9yzoJ6jc_0 person +ZYG83auB9Lk_0 train +ZYIgTdUmOWk_0 elephant +ZYKlgXftesk_0 cow +ZYM0_4YzeeQ_0 person +ZYRgw5rNhE4_0 person +ZYS7WVlJbuU_0 person +ZYX53PWsBdk_0 person +ZYY8vkvB1zU_0 person +ZYkIkq9kfLc_0 dog +ZYlANECCXnI_0 person +ZYocOIOyuqs_0 person +ZYsifQxv94s_1 motorcycle +ZYs7rbZt8Zw_0 airplane +ZYs7rbZt8Zw_1 airplane +ZYs7rbZt8Zw_2 airplane +ZYtk2iVNC90_2 airplane +ZYtk2iVNC90_0 airplane +ZYxn9wmzRI4_0 bicycle +ZYxn9wmzRI4_1 bicycle +ZYzeKMdP2SE_0 person +ZYz6B5dwXcE_0 person +ZY_urkqeQLM_0 bicycle +ZZANjG2Z5Jk_0 person +ZZFzCaL48sE_0 cow +ZZNRG-ux4fw_0 person +ZZQDFjbEcHQ_1 bird +ZZQDFjbEcHQ_2 bird +ZZQSDwoLZ00_4 knife +ZZSFKq4WH78_0 cat +ZZVPKuh-2v8_0 person +ZZVx_IT4voA_0 person +ZZlf3LtDpH8_1 bear +ZZpLkBcXUgs_1 person +ZZpLkBcXUgs_2 person +ZZxMtMlV-MM_0 cow +ZZyW-2jZcIo_0 horse +ZZyW-2jZcIo_1 horse +ZZ20JXRExdg_0 person +ZZ8OuI39UTM_1 person +ZZ85EAvnAGU_0 person +ZZ85EAvnAGU_1 person +ZaDVUoq6h5o_1 person +ZaD5V9_Vw2w_0 person +ZaJb3JTan7Q_0 person +ZaLqPrH_aVo_0 train +ZaLqPrH_aVo_1 train +ZaNZV-lM-3o_0 person +ZaNZV-lM-3o_1 person +ZaPC288yVBg_1 bicycle +ZaPC288yVBg_5 bicycle +ZaPC288yVBg_7 bicycle +ZaPltFe0S_o_1 truck +Zabt7ElK3jM_0 person +ZacHdhX9F9M_2 dog +ZadGgAG3PzE_0 person +Zaew_bHz-PQ_11 umbrella +Zaflj5gSZEw_0 person +ZanT0hXyJhk_0 bird +ZavCWamLatc_2 person +ZavCWamLatc_1 person +Za4BYhhaFFQ_1 zebra +Za6oX4aQR34_0 airplane +ZbB-tdDvITQ_0 motorcycle +ZbDu8V7ppZE_0 motorcycle +ZbHt1sn7oTI_0 person +ZbJvtTVTTV8_0 knife +ZbQXzueqj4Y_0 horse +Zbgfg8usx-k_0 person +Zbgfg8usx-k_1 person +Zbm5_qB8fEs_0 person +ZbrJHC_mHlo_1 person +ZbrJHC_mHlo_2 person +ZbrJHC_mHlo_0 person +ZbrqZYGiMvE_1 cow +Zb2Vz655gh4_2 horse +Zb755JeGMpU_2 person +Zb-JKfQ5emU_1 person +Zb-JKfQ5emU_2 person +Zb-JKfQ5emU_0 person +ZcJPap_gVyo_0 person +ZcXA6CyQBi8_0 cat +ZchU4DxP5A8_0 person +Zcw7wSfd2JM_0 person +Zcw7wSfd2JM_1 person +ZdElKzM-US0_0 umbrella +ZdKO1sC4o60_0 person +ZdMbx0IXDzs_0 person +ZdMm6j__cQM_8 bicycle +ZdTZrRX0dv4_0 truck +ZdXrQlOU7iw_1 bicycle +ZdaFXJzLLUs_0 person +ZdaFXJzLLUs_1 person +ZdeTj7nyN-s_0 boat +Zdevf1MbY8U_0 train +Zdevf1MbY8U_1 train +Zdevf1MbY8U_2 train +ZdirtQF_sjE_0 person +ZdlnVpHrDcg_0 giraffe +ZdlnVpHrDcg_2 giraffe +Zdq2csZeJr8_2 person +Zdrk4yHmMXA_0 person +ZdtUPHscS-s_0 person +ZdxD4gqVioQ_0 cat +ZdxHWwaivLc_0 cow +ZdyBZtlMq-M_2 bear +Zd3j0bQV6NI_0 person +ZeHLf0q4Z1Q_0 person +ZeZAZbMg1zY_0 person +ZeaoaXZDhPw_0 person +ZemOY1F1bVo_0 truck +ZemOY1F1bVo_3 truck +ZemOY1F1bVo_1 truck +ZerHfx3SLxU_0 person +ZerYXYTyhoc_0 person +ZetcbIDyydg_1 car +ZetcbIDyydg_0 car +ZeuqVhpsVu0_0 horse +Ze6GIOUVxZU_0 person +Ze8W47hBrrE_2 skateboard +ZfAFALQjUwI_2 person +ZfAFALQjUwI_1 person +ZfAM39o5Cbc_0 bird +ZfDkxwMowSk_4 elephant +ZfF5Z0hrOQw_0 person +ZfHSyDaLaw0_0 airplane +ZfHSyDaLaw0_2 airplane +ZfHSyDaLaw0_1 airplane +ZfJvZeaN7Ro_1 person +ZfTTW39iHJQ_0 person +Zflcz9EKz4g_4 elephant +Zflcz9EKz4g_1 elephant +Zflcz9EKz4g_2 elephant +Zfmwrq2aghI_0 person +Zf86HoPHmBs_1 bird +Zf86HoPHmBs_0 bird +Zf-rSx5ZNB8_0 person +ZgK0Y4PgWSM_0 person +ZgOr7facaIw_0 skateboard +ZgP7q-rIhs0_1 person +ZgTDthFY-aI_0 bird +ZgZ18HIfCGc_1 motorcycle +ZggirLBvHSw_0 dog +ZgjspuwgTAc_0 person +ZgtG8Zy63UQ_0 person +Zg18GZ5OFWw_1 person +Zg2YrzGNuZs_0 person +Zg4f2iY8_zo_1 cat +Zg4f2iY8_zo_0 cat +Zg5MdsCXRWM_1 cow +Zg5MdsCXRWM_0 cow +ZhLB-laOg_g_9 bicycle +ZhLB-laOg_g_3 bicycle +ZhLB-laOg_g_5 bicycle +ZhLB-laOg_g_6 bicycle +ZhLB-laOg_g_10 bicycle +ZhLB-laOg_g_12 bicycle +ZhPafr5WTEs_0 person +ZhtgT8q5Gm4_0 person +Zhtr_XhO6_4_0 train +Zhtr_XhO6_4_1 train +Zh6QWGGQ9dU_0 person +ZiJFOBVGah4_0 horse +ZiPO1UcM3IY_0 dog +ZiP2ydBHuPs_2 person +ZiSl_Dy1ZB4_0 person +Zibk3bXvHCY_0 cat +Zig1VrVbQc0_0 horse +ZimvCFcji0A_0 person +ZisoM7y_CS4_0 person +ZitUYI22J54_1 knife +ZitUYI22J54_0 knife +Zi1etYbSUmQ_1 person +ZjCbmE2jLo4_0 person +ZjFb1VLHvyg_1 horse +ZjPmZ4grIFA_0 person +ZjPmZ4grIFA_1 person +ZjQqfJ1Docg_0 person +ZjQ9lIlCehk_0 skateboard +ZjSloqSrfWU_1 airplane +ZjSloqSrfWU_3 airplane +ZjWBw4tZUO4_0 train +ZjWBw4tZUO4_1 train +ZjWBw4tZUO4_2 train +ZjWBw4tZUO4_3 train +ZjWBw4tZUO4_4 train +ZjWBw4tZUO4_5 train +ZjWBw4tZUO4_6 train +ZjbhM1ZiKW8_0 person +ZjbhM1ZiKW8_2 person +ZjcEfOHRyLQ_0 truck +ZjcevqmMJvY_0 person +ZjgTSjb7Vh4_1 car +ZjnaerD1MHM_0 elephant +Zjn6uD43ewg_4 airplane +Zjn6uD43ewg_5 airplane +Zjn6uD43ewg_1 airplane +Zjn6uD43ewg_2 airplane +ZjpmS5k09Ug_1 person +Zjpzw1n9Lvc_0 skateboard +ZjsEX7nNYdQ_0 person +ZjxiHzcXOAs_0 person +ZjxiHzcXOAs_1 person +Zj2HBun9kBY_0 person +AVW26zY72Ns_0 person +AVXWb0s5LZw_0 person +AVqCe7X9Pp4_0 cow +AVragVmWr8M_0 motorcycle +AVvnZ-Ky-ew_0 person +AV9y4LnUV84_0 dog +AWAQTemnBJc_0 person +AWCUoghX20A_0 cow +AWD_KAfvb0U_0 skateboard +AWOhJ9RZReg_0 person +AWOhJ9RZReg_1 person +AWPNd7zPJzg_0 person +AWPNd7zPJzg_1 person +AWZt9EdU3BU_3 zebra +AWdKXFitdJI_0 boat +AWh2S4rI6kc_0 person +AW1SjuoheU8_0 cat +AW2cvkaExG4_0 cow +AW8munaOGqw_0 person +AW--f4fsLFY_0 train +AXB4hYQKqUw_0 person +AXB4hYQKqUw_2 person +AXQlwoC_K0g_1 truck +AXX66Oq_RkU_0 person +AXhx8hncZvA_0 boat +AXm0KvcIchQ_0 train +AXtXzxTXTqI_0 elephant +AX2rS0bpAmM_0 horse +AX4Hsfdm-Fo_0 elephant +AX8WoOXfJDA_0 person +AX-xVtjP42Q_0 person +AYLoR7L3CMs_3 bird +AYLoR7L3CMs_1 bird +AYUGoWokN_0_0 person +AYYdBxTI_54_1 train +AYakvLR8aVM_0 person +AYe6Wf0URgo_0 truck +AYgbgSVClN4_0 person +AYg1V2ol96s_0 dog +AYj70IRvvwI_2 airplane +AYj70IRvvwI_3 airplane +AYn-qtOy_nc_0 person +AY7foLy1uok_0 elephant +AY7foLy1uok_1 elephant +AY-AbrJPyY0_0 train +AZHYXkv5rMk_0 bird +AZJsII37MPY_0 bird +AZMW1TyN6Z4_0 person +AZQjsUm-CXk_1 person +AZhH2ej_x_g_0 person +AZjZ1ZSyCeE_0 person +AZk4MAu-j90_0 person +AZleWF5zAxc_1 bear +AZl3Emy9K3A_0 horse +AZouBTtQrtM_0 person +AZpAuvQryZo_0 person +AZpAuvQryZo_1 person +AZ9SW8bxD3E_0 bicycle +AaGwVQ6UjOE_0 person +AaRVwgGBmWU_0 person +AaTW4oc5bBU_0 person +AaZsdPwg9qg_3 bus +Aac18k-eLZI_0 person +Aac18k-eLZI_1 person +Aac18k-eLZI_2 person +AakpjcyvFSo_0 person +AalaqaXsEbs_3 umbrella +AalaqaXsEbs_0 umbrella +AalaqaXsEbs_1 umbrella +AalaqaXsEbs_2 umbrella +AaoK6DPQKII_0 bus +AaotWWHg4eU_0 truck +AaotWWHg4eU_1 truck +AaotWWHg4eU_2 truck +AasksRmCk1g_0 person +AatNkWo2ryE_0 person +Aa0FU2EIMZ4_0 bird +Aa-wzDtjCGc_0 person +Aa_biYfYp08_0 person +AbEsU9EX9XQ_0 elephant +AbEsU9EX9XQ_2 elephant +AbO_VrlyQ8I_0 umbrella +AbTxhwSueZw_0 person +Abd7Vn-Nyt8_1 truck +AbeOAFhMXBY_1 bird +AbeOAFhMXBY_2 bird +AblKd4XIjqk_0 person +AbmnNkzkXFg_0 elephant +AbmnNkzkXFg_1 elephant +AbuMVYzS0mw_0 skateboard +AbvoOuTpLtA_0 dog +AbwI4m0H9Hk_2 train +Abx126RTs10_1 elephant +Ab9zgKJnr9Y_1 person +Ab-vGS2mqFQ_0 cow +Ab-vGS2mqFQ_1 cow +AcCU5YAWXlw_0 dog +AcReGpoHOZI_0 person +AcSmnBYhEsg_0 person +AcTgPRNars0_1 truck +AcUEWZRPoGA_0 umbrella +AcZNiBe0Fgo_0 person +AcZukbBG7tI_0 boat +Acc1yTFpH2c_0 dog +AcpBKywfL4o_1 cat +AcpOxyI_YPI_0 person +AcprJcYvkbY_0 person +AdDiiRHwZ2E_0 cat +AdEH-oHs1Qo_3 train +AdEiQT7Nm0o_1 motorcycle +AdE2jnpk6AM_0 boat +AdbsyVjq_Xs_0 cow +AddL-M622TI_0 knife +AdgTVbi_kus_0 person +AdsPsjswSGQ_0 motorcycle +Ad044xbRhE8_0 person +Ad2TSmaLvX8_0 person +AeDfdgrccVw_0 person +AeHbZ3U8S8U_2 train +AeWBkNuJmEA_0 truck +AeWBkNuJmEA_3 truck +AeWBkNuJmEA_4 truck +AeWBkNuJmEA_5 truck +AeakbNNwcW0_0 train +Aec4uweTSes_2 skateboard +AeflYi3Sxss_0 person +AegDGWXkWNw_0 person +AenVUPH1ils_0 bird +AendE1XHSps_0 bicycle +AerUXP3Mmks_0 person +Ae5qWkNt6RU_2 car +Ae7ucKj40mw_0 dog +Ae9Zd3lP7bg_0 person +AfHkdkvxhNs_0 elephant +AfNCSPijpao_0 person +AfNGR5iEpvU_0 cat +AfNtKiB_rD8_1 motorcycle +AfWHElsVCyM_0 cow +AfWfexnwsHg_0 person +AfWfexnwsHg_1 person +AfkKO6j4jWc_0 person +AfmMpft13ZU_0 person +AfnQoNimSjc_0 person +AfynslRqwxI_0 car +Afz2VDV4UHg_1 person +Afz2VDV4UHg_0 person +Af2MGhdZAn8_0 person +Af2VyQEZtfk_0 person +Af6Ve26JUOg_0 person +AgBaUhTbzxA_0 airplane +AgBaUhTbzxA_4 airplane +AgBaUhTbzxA_5 airplane +AgBaUhTbzxA_3 airplane +AgBaZRmz8IY_0 skateboard +AgJCf77qxsY_0 person +AgP2HoU83S4_4 knife +AgYhFemsFag_0 person +AgZ2iflIKWc_1 person +AgaetfTOzc8_0 person +AgdrEW8jmw4_0 truck +AgqmhFD0R94_2 elephant +AgqmhFD0R94_3 elephant +AgqmhFD0R94_1 elephant +AgrKeQXSU2M_0 elephant +AgrKeQXSU2M_1 elephant +AgrKeQXSU2M_2 elephant +AgtCW50wfig_0 person +AgvxdVNj5Oc_0 skateboard +Agw5t7YSQbE_0 skateboard +AhAW4UKPzz0_0 giraffe +AhE2vDF6Gbc_0 horse +AhE2vDF6Gbc_1 horse +AhjsDq9fEzQ_0 person +Ahv2jhPqRPg_0 person +AhwGPZWtf3E_0 person +Ahxq6Rtu3lc_0 person +Ahx3IZujXDw_0 bus +Ah0AGjta1qg_5 bird +Ah04VeRs2hg_0 truck +Ah4x4EfR3BY_0 motorcycle +Ah4x4EfR3BY_1 motorcycle +AiIc8FW3q98_0 car +AiL_iCJ8HZI_1 person +AiNLvzwt3_w_1 bird +AiNLvzwt3_w_2 bird +AiP7EOvTpK4_0 motorcycle +AiP7EOvTpK4_2 motorcycle +AiU_T3DZI2w_1 bus +AiU_T3DZI2w_2 bus +AieRY99VkmE_0 person +AieVzbENJv0_3 bicycle +AiieCerOKpc_0 person +Aik2hirrxEo_3 airplane +Aik2hirrxEo_0 airplane +Aik2hirrxEo_1 airplane +Aim6_lZQi4g_0 person +AiqqXxqnPPM_1 cow +AiqqXxqnPPM_0 cow +AittR1dd2SI_0 train +AittR1dd2SI_1 train +Aiv3XHMuVq8_0 train +Aiyfw0Zh38k_0 person +Ai29fDmklxM_1 person +Ai29fDmklxM_0 person +Ai3S7n1Aofs_0 elephant +Ai-487iZv0E_0 person +AjFhyF1XZw4_0 person +AjJHvamHoMU_0 horse +AjPBAy1xgrY_0 person +AjVe8d0vc1E_0 person +AjamPk2Geuw_1 bus +Ajg7q9zxJUo_0 person +AjroIzI2OW8_1 truck +AjroIzI2OW8_2 truck +Ajsu2bGngDw_1 person +Ajs4qdBK7Jk_0 elephant +ZkD_WAxZB3o_0 cow +ZkHPsjy-YUQ_1 knife +Zkbav-Qoxds_0 horse +Zkbav-Qoxds_2 horse +Zkbav-Qoxds_1 horse +ZkidaaVx2VU_1 bus +ZknqgRL504A_4 bear +ZkqA2kLudwE_4 train +ZkqA2kLudwE_0 train +ZkqA2kLudwE_3 train +Zku9JAotBZ0_0 boat +ZkzM2jvV2AY_0 person +ZlBfF2yK2vg_1 person +ZlBfF2yK2vg_2 person +ZlBfF2yK2vg_0 person +ZlDsSDEHEzY_1 cow +ZlDsSDEHEzY_0 cow +ZlDsSDEHEzY_2 cow +ZlFElBglnHA_0 cat +ZlP8tmFYeyY_5 bird +ZlfyrRfHDoc_0 cow +Zljx0icnRa8_0 person +Zljx0icnRa8_1 person +Zlmsqen0qZo_0 person +Zln667JkWo8_0 person +ZmHKBIsSjQA_0 horse +ZmHKBIsSjQA_1 horse +ZmVLw9-fLDo_0 car +ZmbXlevaX2U_1 boat +ZmgJjFt3JU4_0 skateboard +ZmhKe4_d5Ag_0 person +ZmiCqFxUJSw_1 airplane +ZmkKOYN1dRw_0 person +ZmrCaB8p3IM_0 bear +ZmuzvhzN6EI_0 cow +Zm3AU4TEpEw_0 person +Zm5VvBaQUwU_0 bird +ZnRgQ1VBIGE_1 person +ZnWAM5ju8NM_0 person +Zne4XpVG2YQ_1 person +Zne4XpVG2YQ_0 person +Znr-Uiobo-k_0 person +ZntDSf8cCPI_0 person +ZnvLWU_PCZ0_0 motorcycle +Zn-r14oEJwM_0 airplane +ZoC1knYO0Tg_0 cow +ZoJIup20AGU_0 person +ZoKfc3OL0JY_0 person +ZoK4wKRoZjY_0 person +ZoN4k6UNw6I_1 horse +ZoOvu218D6M_0 person +ZoR1yoQzsbM_0 person +ZouHgocvjDI_0 bird +Zo-8G7N2DXU_0 person +ZpAlbL-YE0E_0 bus +ZpCrRb_a9QI_0 person +ZpCuVDLXQSw_1 horse +ZpCuVDLXQSw_0 horse +ZpSzmFLEm0c_1 car +ZpURI0wRgws_0 person +ZpXJ-0dv6Us_1 cat +ZppFK22HdIk_0 person +ZpqXtZfe-3w_0 cat +Zp1nQXN7dyg_0 horse +Zp2CuvTAZLw_1 person +Zp740cgCPPE_0 person +Zp8GHxi_5l0_0 knife +Zp8GHxi_5l0_1 knife +ZqM9VL5DJ28_1 person +ZqOcOhiAI6k_0 cow +ZqS1PqS3iT0_0 truck +ZqW027iDkCI_0 person +ZqXFvdeNrYI_1 person +Zqa0-AUnl9s_0 person +Zqm8A3wpeJQ_0 person +ZqtVs5joekw_0 cow +Zq018zZzx1c_0 person +Zq1u84GLCHI_0 motorcycle +Zq5nK49UZ_o_2 elephant +Zq5nK49UZ_o_3 elephant +Zq5r3BwLg_c_0 skateboard +Zq-RNCVoZFs_0 person +ZrA0NE09ipc_0 dog +ZrDoGqu-A5A_0 train +ZrI4ruv6B3o_0 bird +ZrKpKmp29_o_1 bird +ZrKpKmp29_o_3 bird +ZrKpKmp29_o_6 bird +ZrK5JKg83qU_0 person +ZrUx83OGIOk_0 person +ZrW7Si0hJKI_0 person +ZrbVa__ne-0_0 person +ZrfPtqkS_MY_0 airplane +ZrfPtqkS_MY_1 airplane +ZrfPtqkS_MY_5 airplane +ZrfPtqkS_MY_6 airplane +ZrfPtqkS_MY_7 airplane +ZrgMnk8f_TA_0 person +ZrgMnk8f_TA_1 person +ZruJ2hhn9z0_1 person +ZrvWeRZ_dyU_1 cow +ZrvWeRZ_dyU_0 cow +ZrwXUWAxjIM_0 giraffe +ZrzdqF_ePkM_0 horse +ZrzdqF_ePkM_2 horse +Zr5eAtkuxQ0_0 bear +Zr_AAxouNfg_0 cow +ZsCaDsfPNec_0 cow +ZsDDOO-bpFA_0 person +ZsDDOO-bpFA_1 person +ZsESx0nIYqI_0 elephant +ZsESx0nIYqI_6 elephant +ZsESx0nIYqI_7 elephant +ZsJCwiPEvkI_0 person +ZsLDBiZ0o14_0 skateboard +ZsPVRik6m_c_1 bear +ZsSkZhL-HOM_2 bicycle +Zsb2ucv_mAg_0 person +Zsdv_3EWODM_0 person +ZsyMk67bjIM_0 dog +Zs0j_1tuTDo_0 person +Zs1ltKMvRec_0 person +Zs1ltKMvRec_1 person +Zs79wUXMpx8_0 bear +ZtA8n6dsH-w_4 car +ZtA8n6dsH-w_1 car +ZtA8n6dsH-w_2 car +ZtA8n6dsH-w_3 car +ZtDUifuLGrM_2 bird +ZtEDTuHcM9U_0 person +ZtM6JRtVtpU_0 motorcycle +ZtToUMIMdYE_0 person +ZtlDJ70ap8Q_1 bear +ZtlJcLPPjsg_0 person +ZtsGzhfZg9g_0 person +ZttTri7sEK4_0 train +Ztyep9o6CLE_4 bus +Ztyep9o6CLE_6 bus +Ztyep9o6CLE_7 bus +Zt9qKAA_xyA_0 person +ZuC0Jr3Y3s8_0 car +ZuGpcHtPLLA_0 person +ZuWlzE4F84c_0 truck +ZuhmoYvtP40_1 person +Zuicm6_fX9I_1 bicycle +Zunjyc7DIP4_2 train +ZuoBIQ-Kq74_0 person +ZuqXxaMAufU_1 person +ZuuL_Yi4FZQ_1 dog +ZuuL_Yi4FZQ_0 dog +Zuy59kV2M-0_1 person +Zu-vh46IwiU_0 cow +Zu_dXJvDHdo_0 person +Zu_f8xuOweg_3 elephant +Zu_f8xuOweg_1 elephant +Zu_f8xuOweg_2 elephant +ZvDo2WbWL4g_1 person +ZvDo2WbWL4g_0 person +ZvJItzBdO04_1 person +ZvJrqHsPVL0_0 bus +ZvSN_Y6vK3c_0 person +ZvV5mqJgbcQ_0 cow +ZvfCrJvE1Tg_0 horse +ZvfIYK-AWCw_0 person +Zvlx8vSlAPs_0 bicycle +ZvtGPgtfhE8_0 person +ZvtuffxB5EY_0 person +ZvyOzgxu-4Y_0 truck +ZvzVi9irgvw_0 bear +Zv6DWiKAux4_1 person +Zv9e9Vm6Vis_0 motorcycle +ZwDqCxCFpF4_0 bicycle +ZwDqCxCFpF4_3 bicycle +ZwH5xnh6Thw_0 person +ZwW6ybIP8ys_0 bus +ZwdSYMz9ioo_0 person +ZwmRodW5wgg_0 horse +ZwrtmR7ewc4_0 person +Zw7a69yU7f0_0 motorcycle +ZxAlVbDwlCc_2 bird +ZxAuwcxhXxc_0 person +ZxE5MjV6i4w_0 skateboard +ZxOVw-Lc-NI_0 person +ZxStkYy-wgo_0 motorcycle +ZxUKijmOWJc_0 person +ZxitXAY6Xsc_1 knife +ZxqbwwO81Xc_0 train +Zxv2BRQIWm0_4 airplane +Zxv2BRQIWm0_5 airplane +Zxv2BRQIWm0_7 airplane +Zxv2BRQIWm0_8 airplane +Aj7HWiU0iQg_0 skateboard +Aj_E-ObfzoE_1 person +AkGYKkcRyPM_0 dog +AkHT5Oo22rQ_0 person +AkMpnm9JrLU_0 person +AkWcVIeIx34_0 boat +AkaR-XgClv0_0 person +AkaR-XgClv0_1 person +AkeAdeJpbpg_0 train +AkeAdeJpbpg_3 train +AkeAdeJpbpg_1 train +Akh0VNTS6G4_0 person +Akh0VNTS6G4_1 person +Akh0VNTS6G4_2 person +Akh0VNTS6G4_3 person +AkkNBGH82Ic_0 horse +AknHhsIpRqc_0 airplane +AkxKeaxEnvQ_0 dog +Ak3XQg9z8XQ_0 person +Ak8ygMb5ykk_0 person +Ak8y7dALcJI_0 person +AlAUJSBL-e4_0 dog +AlNCPdpo1gg_2 bicycle +AlNCPdpo1gg_5 bicycle +AlNCPdpo1gg_6 bicycle +AlNCPdpo1gg_0 bicycle +AlNCPdpo1gg_3 bicycle +AlNCPdpo1gg_4 bicycle +AlPZeADzCKc_0 person +AlPZeADzCKc_1 person +AlXlVnkucyU_3 train +AlXlVnkucyU_1 train +AldX05MqOs0_0 person +AleuxLN7VcU_1 bird +AlfbdsgKBAc_1 person +AlhjN5qz_WI_0 train +AlikgfDMckk_0 person +AlnIWAFamHE_0 bear +AltA5vQ7Icw_0 bus +AlzB8mXDcYc_0 horse +Al2hm71ia6E_0 person +Al9l6-4QDz0_0 horse +Al9wCTPpSWM_0 skateboard +AmPe5gTOCTo_2 person +AmPe5gTOCTo_0 person +AmPe5gTOCTo_1 person +AmQ_UrwLf3g_0 person +AmRyW4hmSjw_0 person +AmcAzvpvDRg_0 bear +AmeaTbvmKvo_0 car +Amt8BGudD0w_0 skateboard +Amt8BGudD0w_2 skateboard +AmuX-Lv7OeM_2 cow +AmwvLxALyCw_0 person +Am2wElVETcw_0 cat +AnD6ijSktyM_0 person +AnEC6v3fXrE_0 cow +AnOwuTW7DKk_0 cow +AnOwuTW7DKk_1 cow +AnQ2ZY1JxAY_2 person +AnWClR8yyu8_0 person +AnZKri0xn-c_1 cow +AnZKri0xn-c_2 cow +Anb2IyxcJbk_0 horse +Anevw4PbqTo_0 person +AnkgvW70F5E_0 person +AnkgvW70F5E_1 person +An342tYqi5g_0 person +AoI1hSI0PSI_2 car +AoKs5jwMuHc_0 person +AoP-So0vjIc_0 cat +AoSwFyY0f_A_0 person +AoXHZgatpco_1 horse +AoXHZgatpco_2 horse +AoXHZgatpco_3 horse +AoXHZgatpco_4 horse +Aof87CGS8NQ_1 skateboard +AoiCmKM8xz0_1 truck +AojgueRMVCY_0 person +AolLjcEFv5o_0 person +AopGnIjKuEk_0 motorcycle +Ao0EDmBMIQk_0 person +Ao0EDmBMIQk_1 person +Ao7Iys-_lZs_0 skateboard +Ao_b43xexzA_0 person +ApJMiJjCxCY_1 car +ApJMiJjCxCY_4 car +ApJMiJjCxCY_5 car +ApP4eoyM72g_1 skateboard +ApWIa9pt-vk_0 person +ApilCZCROGI_0 motorcycle +ApjCOCv29N8_0 person +AppgdYQTII8_0 truck +Ap1gZJZynL4_0 person +Ap-iaHj5SLk_4 elephant +Ap-iaHj5SLk_5 elephant +Ap-3HonA5go_0 person +AqBYSr4wmpQ_0 person +AqKP0V3Xj7E_0 cow +AqOxDunFl08_0 airplane +AqOxDunFl08_1 airplane +AqSP11-eje8_0 boat +AqUxRBRS-n0_0 skateboard +AqZhKjLLG70_2 boat +AqdAnSsQLI8_1 person +AqdAnSsQLI8_0 person +AqlHHwyJypE_0 bird +AqmXAZYmPJc_0 person +AqmXAZYmPJc_1 person +Aqo5yZkzz8I_4 truck +AqpinwPH8gM_1 person +AqpinwPH8gM_0 person +Aqqs8XxA8gM_1 horse +Aqqs8XxA8gM_0 horse +Aqqs8XxA8gM_2 horse +AqqvZzLy3IE_0 motorcycle +AqsuBaW1L0Q_0 person +AqxTv7XRAH0_0 person +Aq_n86sub5o_2 bicycle +Aq_n86sub5o_3 bicycle +ArJNEsuLzDc_0 person +ArJaHKwfOEo_0 person +ArM6GXi6YnI_1 dog +ArbpF1NIm-s_0 car +ArbpF1NIm-s_1 car +ArfeHbvYvKY_0 motorcycle +AriIdq0ZPfE_1 elephant +AroxRXjr3po_3 bear +ArrB-hbOgf8_1 elephant +ArvYqb1hJSk_0 person +AryOE3od43M_0 person +Ar7WaiToztg_0 person +Ar8Wk3m0uZ0_1 person +Ar8Wk3m0uZ0_0 person +Ar-vOeN30bM_0 cat +AsJt3MHLGiM_0 person +AsKUm364aHg_0 person +AsNy8gmdVec_0 person +AsWWfQtZSHA_0 person +AsY1dt4QojM_0 person +AsZa3il8cZQ_0 person +AsfAcK_laZA_2 horse +Asix5lGmXlg_0 airplane +AskNHLhn1t0_0 cow +As_a3CyN-kQ_0 bicycle +As_a3CyN-kQ_2 bicycle +As_a3CyN-kQ_7 bicycle +As_a3CyN-kQ_8 bicycle +As_a3CyN-kQ_10 bicycle +AtFOIFqxLKs_0 person +AtG98YoPQyg_0 bird +AtKUkiMSzfs_2 elephant +AtKieG766oI_0 person +AtawrCflbrM_0 person +AtfXsIpaSgQ_0 person +AtmVV-8Pjsg_0 person +AtmVV-8Pjsg_1 person +At0-VpJyfBY_0 skateboard +At81P33v_z8_0 person +AuA4_FjCMvo_0 person +AuJLIGyAoj4_1 horse +AuJalbdpJP8_0 train +AuLw9iNhPvw_0 bird +AuQYS5w13co_0 bus +AucK5ZDM060_1 airplane +AuchGbKLdmk_0 person +Aucxkj3w3nc_0 person +AugnPC3tdso_0 motorcycle +AunfkfLwN1w_0 bear +AunfkfLwN1w_3 bear +AunfkfLwN1w_2 bear +AutsbWiMLoY_0 person +AuuZLhOpxcI_1 elephant +AuuZLhOpxcI_6 elephant +AvGLANxpJ-Y_1 person +AvJexx39uCE_0 person +AvOpMSLKXTM_1 person +AvOpMSLKXTM_0 person +AvP_DY8SuU4_0 person +AvQgdEmyoFA_0 airplane +AvVBLLWgeWo_0 horse +AvdUsPyX5lE_0 person +AvdgweWTeeg_0 cat +AvgusAC7DUU_0 bird +Avlg_B60Z0E_0 bear +Avlg_B60Z0E_4 bear +Avp80BzoG9Y_1 person +Avp80BzoG9Y_0 person +Avr6FKguO2o_4 skateboard +Avr6FKguO2o_1 skateboard +AvvWfbj5x88_0 person +Av78r-lWmCs_0 horse +Av8Hkyi1fdc_1 knife +Av8k98IyQhs_0 person +AwAX85eLJH4_0 cow +AwDIxdZSWKQ_0 person +AwECiro8_h4_1 elephant +AwEtKHnfKJ8_1 cow +AwEtKHnfKJ8_2 cow +AwFA2LuUWN8_0 person +AwM3QWX5Jsc_0 person +AwOJkAFe8Xs_0 bicycle +AwZ6nHwMMuA_0 dog +AwqZ_9G0pWg_0 person +AwsAA0Xk1J8_0 person +Aw-D6USSthk_0 bear +AxAIZDsViZw_0 person +AxAIZDsViZw_1 person +AxAkf4tRXbI_0 person +AxLiwCy5umU_0 person +AxUFYNgnIq4_0 person +Axg0nab1SDc_0 person +AxvrCidcYqM_1 person +Ax2iIXU4Gyc_0 person +Ax5dd2_2sFA_1 car +Ax5dd2_2sFA_0 car +AyAAL3Rd_Rg_3 bicycle +AyAAL3Rd_Rg_5 bicycle +AyAA5q5B-84_0 person +AyAA5q5B-84_1 person +AyH0zvW0ndQ_1 bird +AyKf0Ufaa_o_0 person +Ayfmwf4oW_k_0 person +AyhXfIgl4Kk_0 knife +Ayo9w6aKSY0_0 person +AyqiYJuONPs_0 airplane +AyqvDNKC1CQ_0 person +Ay2VXLYZW50_1 person +AzFaa7gRy0k_0 person +AzMHek-Oow0_0 cat +AzNf4dneWFU_1 person +AzVMbaXM_QM_1 boat +AzVoOWc-ueY_0 person +AzaUz9OpHMI_0 truck +AzeA4K-S0CI_1 person +Azew3w3WZfI_5 skateboard +Azew3w3WZfI_1 skateboard +Azew3w3WZfI_3 skateboard +Aze0ijK2t2M_0 person +Aze_lfqL6mw_0 cow +AzhTPVtwJVk_0 person +Azh82KkzMVs_0 bird +Azh82KkzMVs_1 bird +Az0Hr5pa_Pw_0 person +Az5vE5ssYxk_0 person +Az5vE5ssYxk_1 person +Az7glF28oOw_0 person +Az_5XR0RSv0_1 person +Az_5XR0RSv0_2 person +A0JB0OdZ2NE_1 knife +A0L6M_8fDyM_0 person +A0Nx4JbdXO0_0 person +A0PQ6Si3nOU_0 airplane +A0XGvY-NO00_5 airplane +A0jhzA4HvrY_0 umbrella +A0n7dLEgCjo_0 cow +A02wb1V5W0A_1 person +A02wb1V5W0A_0 person +A08TTc4NLik_0 person +A1Hvxm2NCpk_1 airplane +A1H8wrYSPlQ_0 bicycle +A1NBheOGWNE_0 bird +A1fdw6WBO_w_0 cat +A1oQZf9EXPg_0 person +A1oQZf9EXPg_1 person +A1oQZf9EXPg_2 person +A1r3FpgoeP0_0 elephant +A1unjHSiYuk_0 skateboard +A1w5Z9ryeJI_0 elephant +A1w5Z9ryeJI_2 elephant +A1w5Z9ryeJI_1 elephant +A11L_7hymDI_0 train +A2ODL8T477o_0 umbrella +A2UiM17u3Ao_0 bear +A2Vhzr_2AAY_0 person +A2WfZtUfAy4_1 person +A2gisYdnTi0_0 bird +A2iD7VC-A9g_1 cow +A2p7Z_Ia9Ak_0 person +A2p7Z_Ia9Ak_1 person +A2rOJWkWoRo_0 person +A23nZy9maYk_1 person +A23nZy9maYk_0 person +A29DgqMHeEQ_0 person +A3EcM1p8r14_0 person +A3FTEFw2Bo0_3 horse +A3JmvJSIxeU_0 person +A3Lmb8E3Ovw_0 person +A3L2pdrSYdE_0 person +A3MpR785VH8_0 person +A3MpR785VH8_1 person +A3UoQh4P1_o_0 person +A3ZIKfh-QPo_0 person +A3b1bCXjWWE_1 knife +A3eocVVFaX8_0 person +A3vXSLx3blY_0 person +A4BVLpu2EQI_1 cow +A4CYcvyDGec_0 person +A4P_7hjid7Q_0 person +A4gw9TbmL54_0 train +A4ijVvmthCQ_0 person +A4oNmb9PiYQ_0 person +A4t4imYj0tA_1 dog +A4u61iOuzr0_0 person +A4u61iOuzr0_1 person +A4u61iOuzr0_2 person +A4wLmZZODQU_1 person +A4zzoIg6-W4_0 skateboard +A42uEePHr8c_0 person +A438LRj4MN0_0 horse +A5Ho_qla_bQ_0 skateboard +A5Kii0lU4h4_0 person +A5ZAKa7xw_I_0 person +A5ciZloGW2o_2 horse +A5nuZ-mKcBE_4 airplane +A5nuZ-mKcBE_7 airplane +A5-RNkQ5yzU_0 person +A5-yfb7-1NM_1 person +A6DfgaqbLDM_0 person +A6GND629_dg_0 person +A6IIHamstQo_0 person +A6KXKalaC7M_0 train +A6KXKalaC7M_1 train +A6LmIR6_mtk_1 truck +A6L7XcS8oF4_0 person +A6MkQdxLBSI_1 bicycle +A6MkQdxLBSI_6 bicycle +A6SipDli3dE_0 person +A6Tx9smTdyo_0 boat +A6Zbpn5hd6Q_0 person +A6jEv9bIawA_1 bus +A6rxrML8vyk_0 horse +A66pUkVBt_M_0 person +A7GxuMCyr50_0 cat +A7KLi_xOQFc_0 person +A7SDQoaalEY_0 person +A7SIvy9srFU_0 person +A7Zz2ESO-PM_2 bear +A7aEqy5QRJ4_0 cat +A7cjjAkLjfQ_1 person +A7cjjAkLjfQ_0 person +A7coVhNQrSs_0 cow +A7c_1Wcr5hM_0 cow +A7ltojA7WTk_0 person +A729VkZvy_s_0 person +A7_WDIFj23s_0 cow +A7_hPlvWyGc_0 cow +A8F5UnJOU5A_0 boat +A8MGPGEOAWk_0 train +A8PGaHrBO-g_0 bus +A8PlfHNTHVQ_0 person +A8RztgyPvCE_1 horse +A8U5HWirVCk_0 person +A8gL-e9dRa8_2 bear +A8oMFSrcteU_0 bicycle +A80V1BVUvf4_0 airplane +A89eQvkZ4go_1 car +A89eQvkZ4go_0 car +A89tFE_-szI_0 person +A9ACfqLHRIM_0 person +A9ACfqLHRIM_1 person +A9LEZHrMOh8_0 person +A9Mw5uHZ7WM_0 dog +A9UlOqoTO3A_0 car +A9WAS-oLC8Q_1 train +A9WAS-oLC8Q_2 train +A9etwHCHkQM_0 person +A9fblLjEn7E_1 person +A9fblLjEn7E_0 person +A9f0bktW-uM_0 train +A9sznaQipiM_1 person +A9sznaQipiM_3 person +A9tOXINxUeA_2 person +A-BcgCHWiLE_1 knife +A-JRl34Jmok_0 elephant +A-JRl34Jmok_1 elephant +A-JRl34Jmok_2 elephant +A-JRl34Jmok_3 elephant +A-MMqq_FLXo_0 person +A-R5A0HMT3w_0 boat +A-SdlQGGdZg_1 person +A-Vo3GQZrd8_0 skateboard +A-gQnulNzVo_0 person +A-gZpG3OWNM_0 person +A-jGPkEGCdo_0 person +A-qT3DcitzM_0 skateboard +A-0o6fFroLk_3 bird +A-1_sR8c39g_0 skateboard +A-1_sR8c39g_3 skateboard +A-37XpNHfQw_0 cow +A_AbA6K8Ouc_0 person +A_AbA6K8Ouc_1 person +A_B83i3dvWQ_0 person +A_CDsn7za4c_1 person +A_CDsn7za4c_0 person +A_DqzmxTyPQ_0 dog +A_Eaoo5O71M_0 skateboard +A_Eaoo5O71M_3 skateboard +A_Nb1jSK7vY_0 person +A_RHSgWC24U_0 elephant +A_R7iK_MLgM_0 elephant +A_Z7Cj10nKA_0 truck +A_aN9LUuMY8_0 person +A_g6G7vBr8I_1 person +A_qnLTG_VBg_0 person +A_uC3UuAVQE_0 cow +A_uxGLJDf9I_0 person +A_xtvYH_7vg_0 person +A__fHCZfwtM_0 person +BACWpC6GdxY_5 airplane +BACWpC6GdxY_3 airplane +BANdhsMHpw0_0 person +BANdhsMHpw0_1 person +BANdhsMHpw0_2 person +BAOR6YBIb8U_1 skateboard +BAO0Uce3vXA_0 cat +BARELTt_9Ko_0 elephant +BAWN6Xpw7sg_0 person +Zx3x1-cBu7I_0 person +Zx3x1-cBu7I_1 person +Zx8LkdyJzG8_0 person +ZyDqefuyQfU_1 cat +ZyDqefuyQfU_2 cat +ZyNwfXl7s2w_0 motorcycle +ZyQL8Ugiq4Y_0 person +ZyQxolWsw2o_0 cat +ZyQ_gFztNXU_0 train +ZyQ_gFztNXU_2 train +ZyqvHk5Ugjk_0 bird +ZyrTKvb3Uq4_0 person +ZyuoNtTPexE_0 person +ZywGdneFaWs_0 dog +Zyw6pIArS1g_0 train +Zy04v73t_oU_0 person +Zy4s6kQgRAs_0 person +Zy7a1FYT_2I_0 person +Zy9BXzUqORk_0 horse +ZzAgbPU4qoA_0 person +ZzBP5IPOX7Q_0 person +ZzBP5IPOX7Q_1 person +ZzFvfG2mfRU_0 cow +ZzIeftZXBMw_0 person +ZzPUlKXnUgE_0 person +ZzRMRSyCzzU_0 person +ZzS_a0D4AhE_1 skateboard +ZzWMnTc1LBY_0 person +Zzdl60FMu48_0 person +ZzeCPtqruzg_0 person +ZzgU7APbNfs_0 person +Zzgoobk2eIA_0 person +Zzgoobk2eIA_1 motorcycle +ZzhCWdZJAQY_0 person +Zzic21J3Ea8_0 person +ZznEoJsdkVI_0 person +ZzpccfyFyL0_0 person +ZzpccfyFyL0_1 person +Zzq_S3HujTo_0 person +ZztD-tmxwyc_0 person +ZzwlUbCfscM_1 dog +ZzxRC2pLBVA_0 person +Zz2oIdSVB6Q_0 person +Zz5GwCMuMj0_0 person +Z0D6uKz7v5Q_0 person +Z0m37r4St5Q_3 truck +Z0pLWU6Wg-o_0 dog +Z0stjlmfTpU_0 cat +Z0xYA5PwrjI_0 person +Z02r-T2hINk_0 elephant +Z04k6LBSuRk_1 person +Z1G9pYdQwCY_0 person +Z1HK6zDIJhg_0 person +Z1MvNM4bmxs_0 person +Z1SML4zVPik_0 person +Z1U7Wnf_WiA_0 cat +Z1XafO8l8gs_0 person +Z1aU1CigISE_0 person +Z1a8Tqg-yjE_0 person +Z1e-5FLWf6I_0 cat +Z1gxFkBk4EY_0 horse +Z1j81keSb9Q_0 motorcycle +Z1j81keSb9Q_1 motorcycle +Z1nr46t7EVk_0 airplane +Z1pv5a0as9c_0 train +Z1rB_fu2lKY_0 dog +Z1x8sEeQIuI_1 motorcycle +Z13O2uGP1nE_0 car +Z14p6heAJRc_2 person +Z14p6heAJRc_0 person +Z14p6heAJRc_1 person +Z15QqHX1Z6M_1 train +Z2HF5_tyxR4_0 bus +Z2K03YbfcGg_0 elephant +Z2QWOKCHkM8_0 cow +Z2QWOKCHkM8_2 cow +Z2QWOKCHkM8_1 cow +Z2SljfwK58g_0 skateboard +Z2SljfwK58g_1 skateboard +Z2VI7eM7BB0_0 bear +Z2acpS-e_cg_0 person +Z2cvYI55Dps_0 skateboard +Z2dab1zmqv8_0 horse +Z2gvlPrX5HA_5 elephant +Z2gvlPrX5HA_6 elephant +Z2kcVxTMZtM_0 person +Z2n2a39MxJQ_7 bicycle +Z2n2a39MxJQ_1 bicycle +Z2n2a39MxJQ_2 bicycle +Z2n2a39MxJQ_3 bicycle +Z2n2a39MxJQ_4 bicycle +Z2n2a39MxJQ_6 bicycle +Z21DONVXY1Q_2 zebra +Z23Gg06mNj8_0 person +Z236ql8Tpvg_0 person +Z23_3K28VSI_1 giraffe +Z3AHrAB9qhw_0 cat +Z3AplkSO6kA_1 car +Z3KMX_N6WSg_0 person +Z3KMX_N6WSg_1 person +Z3KMX_N6WSg_2 person +Z3PzgfwbjLk_0 truck +Z3i5sys0boU_0 person +Z3i5sys0boU_1 person +Z3sRLCOCxMY_0 cat +Z37dIpwPIqI_3 bicycle +Z4DQoYcs5mM_2 person +Z4DQoYcs5mM_0 person +Z4DQoYcs5mM_1 person +Z4XLmQjbg7Y_0 person +Z4XLmQjbg7Y_1 person +Z4ZKg0KbSm4_0 bicycle +Z4ZPyzSGdRU_0 dog +Z4bO8cpjQZI_0 person +Z4bO8cpjQZI_1 person +Z4bW8HHeYP8_0 car +Z4mYWGPFVkw_0 person +Z4n5ieSA6cM_0 cow +Z4tOSluXWnE_1 umbrella +Z4u3PPkCYOs_0 person +Z4u4zasFeAw_1 bird +Z4u4zasFeAw_0 bird +Z4vRtZE1WjQ_0 dog +Z4voZ3h_Dyk_1 person +Z4xVMaYAqJ4_1 bicycle +Z446P08C8vE_0 person +Z5KGx49qaAE_3 bird +Z5KGx49qaAE_5 bird +Z5KGx49qaAE_6 bird +Z5Qo8xdb8os_0 elephant +Z5RKMhlNHEE_0 person +Z5ZBRI0sc4Q_0 bicycle +Z5iJRTvm-Kw_1 person +Z5iV683VDk0_0 person +Z5ls93B1bBk_0 person +Z5mQ_0ttu74_1 elephant +Z5mQ_0ttu74_2 elephant +Z5yNMm-TIjI_0 bus +Z5zGHZ82r9A_0 person +Z53B8-gR640_0 person +Z6BVtmEMfkI_0 person +Z6FikDWrKkA_0 person +Z6MfvYa9hCs_2 car +Z6MfvYa9hCs_3 car +Z6PyYboRq5c_0 dog +Z6Q3LdMwgi4_0 cat +Z6WrlM4ZZKA_0 person +Z6j-7La25S4_0 person +Z6j-7La25S4_1 person +Z6j-7La25S4_2 person +Z6k1unwmsfA_1 person +Z6sd800eFC4_0 person +Z6tGpP8q53A_9 elephant +Z6tGpP8q53A_2 elephant +Z6tGpP8q53A_4 elephant +Z6vCDHs6NrM_0 person +Z6yNyxXPPOw_0 elephant +Z60iXtKpGMQ_0 bus +Z61B0fShfbs_1 cow +Z7AqkWEBwV8_0 person +Z7DGMMQP79U_0 cat +Z7I8r1AqMhU_0 person +Z7JHCdt48hA_0 airplane +Z7KEzuE_7hQ_0 person +Z7LfnFm4OHs_0 person +Z7WaJYiX_1o_0 person +Z7WaJYiX_1o_1 person +Z7bMdjLGiAo_0 person +Z7eGCBjkKrU_0 dog +Z7gxE6ZSQXI_0 airplane +Z7iq45DtCTM_4 horse +Z7iq45DtCTM_5 horse +Z7zeXJ5lJRY_1 person +Z7zeXJ5lJRY_0 person +Z72sIqrQAF4_0 skateboard +Z74EGXvFjFM_0 person +Z76Y_PNOgK4_1 person +Z76Y_PNOgK4_0 person +Z78P87kjtu4_0 person +Z8CXvEObu4c_0 dog +Z8NfZN7WDKw_0 person +Z8Oi5HJEyS4_0 skateboard +Z8k0TTq5BC8_0 horse +Z8s-Kg1PuSg_0 horse +Z86E7eIS9t8_1 airplane +Z89mG68LE2k_0 person +Z8942_IPiTo_0 bicycle +Z8942_IPiTo_2 bicycle +Z9SwanypLJM_0 bear +Z9SwanypLJM_1 bear +Z9XS4cvVVy4_2 person +Z9awHnw5J4o_0 truck +Z9bt3xT5dCc_0 cat +Z9f--QLEQqI_1 motorcycle +Z9jDpr533Cg_0 cat +Z9o5BEm1UeI_0 person +Z9pHCguAO5c_0 person +Z9wO9tftNG0_0 bus +Z9x_cPvKErA_0 person +Z98EscJ1IG8_0 person +Z98GFnZo-LA_0 person +Z-I0S45eRT0_0 person +Z-J0UQfvb5M_0 person +Z-MvTXpMdm4_0 truck +Z-PMnTjqAS8_0 person +Z-QO3lrbh7c_1 skateboard +Z-VVWO3Ovgs_0 person +Z-djkrj-5Cs_0 horse +Z-glDeBd2xA_0 boat +Z-lrIzXr9ck_0 train +Z-mTl_ipVa4_0 umbrella +Z-mXYrvubn8_0 dog +Z-zy-BzjLT0_0 motorcycle +Z-zy-BzjLT0_1 motorcycle +Z-7W_lh96xg_1 airplane +Z_JXyC6v_-s_0 person +Z_KItWz0mTI_0 elephant +Z_PViIzihe8_0 person +Z_QVuM8wEmQ_0 person +Z_QVuM8wEmQ_1 person +Z_kPrUEqYXE_0 bird +Z_p4gYNjwG0_0 person +Z_85vV3FHUg_0 person +Z_85vV3FHUg_1 person +aACqXYewohQ_0 person +aAI7SN5_3CY_4 bus +BAhHrnCKvcM_2 boat +BAhHrnCKvcM_3 boat +BAhHrnCKvcM_5 boat +BAmy5TQke7w_0 person +BAnfbsB8rIY_0 bear +BAnn4L-iNLE_0 person +BAq_fnyQ6z4_0 person +BA4ZGv8flRA_0 person +BBCBbdz3Qvs_0 dog +BBCBbdz3Qvs_1 dog +BBLAyHVLHh8_0 person +BBOd-YBAUgw_0 bicycle +BBPlqTbAphY_1 person +BBQ2xu9OehQ_1 dog +BBS5owVJaTU_1 skateboard +BBS5owVJaTU_0 person +BBVPb5z0x7k_0 cat +BBXs1J4j2mA_0 skateboard +BBdA1qc9H-g_0 skateboard +BBk7ZnOEjMA_0 person +BBopEl_n3Fc_0 person +BBpFu8j2fBc_0 bus +BBpFu8j2fBc_1 bus +BBqTHwpYeEc_0 train +BBrfgTTduuI_0 person +BB9l_znmPls_0 umbrella +BCBCK2k2Bdw_0 person +BCBgjRWuOcA_0 person +BCGB6zaBDpg_1 person +BCGB6zaBDpg_0 person +BCI91i3aEek_0 motorcycle +BCJbf6um28s_1 airplane +BCKVauIBDFM_2 bear +BCin0MjzM8Y_0 cow +BCoTKGNhMVw_0 dog +BCoTKGNhMVw_1 dog +BCo8e6n2dYQ_1 dog +BCqYnyGIols_1 bicycle +BCsmPvRqaNk_0 person +BCuzA73UTl4_0 person +BCwAdqAouFU_0 boat +BCwyoTwckSE_0 truck +BDFBV8JbIF8_0 person +BDFVkc87amI_0 person +BDHUAJn9nnc_0 person +BDHsXkbkS-w_0 skateboard +BDOemJGz04I_1 person +BDcTOMebCHs_0 person +BDcTOMebCHs_2 person +BDcTOMebCHs_1 person +BDdIKtFwnjA_1 train +BDdbk3ZQrP0_0 cat +BDdhenNSY9o_0 person +BDk-BklqSdI_0 person +BDroGke9Ogg_0 horse +BDroGke9Ogg_2 horse +BDtGFVFexaU_0 person +BDzXi4ukhN0_1 person +BDzXi4ukhN0_0 elephant +BD30MTvTuYU_0 person +BD7TQWBytfQ_0 knife +BEArUGKSB-Y_0 train +BEArUGKSB-Y_1 train +BEKMcritl6M_1 person +BEMcwkY2beQ_0 person +BERvmKL4Glc_0 person +BESdHwoIDsA_0 dog +BEUB64a3AIY_0 elephant +BEUB64a3AIY_1 elephant +BEYy-ZRSWSk_0 skateboard +BEa_8wp0528_0 cow +BEqG56tHTEI_2 bus +BEqPniAgjaY_0 cat +BErty5GnulU_0 person +BEuXjB1zLeE_1 car +BExSp8l17GY_0 person +BExlFv0scM0_0 person +BE10HJUHUHw_1 person +BE8KS4PZH54_0 elephant +BE-crlUXSSE_0 dog +BFC3DWxOces_2 airplane +BFC3DWxOces_1 airplane +BFC3DWxOces_3 airplane +BFC3DWxOces_4 airplane +BFC3DWxOces_5 airplane +BFJ4v-XlKAg_0 skateboard +BFPQCoJqTRk_0 person +BFeIwErwdS8_0 person +BFeIwErwdS8_1 person +BFggPKKt6wk_0 person +BFggPKKt6wk_1 person +BFhh8z0Fmk0_0 person +BFponHgVsdA_0 person +BFs239KuGa8_1 person +BFxUyTrqZhU_2 horse +BFxUyTrqZhU_4 horse +BF4YTMGtDs8_1 skateboard +BGAQlsAiJ_0_0 airplane +BGAQlsAiJ_0_1 airplane +BGAQlsAiJ_0_2 airplane +BGAQlsAiJ_0_3 airplane +BGAQlsAiJ_0_4 airplane +BGAQlsAiJ_0_5 airplane +BGAQlsAiJ_0_6 airplane +BGLM4yl_Ka4_2 horse +BGO3DBbNozc_0 skateboard +BGR1gMrCTpA_0 person +BGT-p0CgoFg_1 person +BGW9SDHTWKY_1 person +BGW9SDHTWKY_0 person +BGee3Ar-Fbg_0 airplane +BGpx9Xow9Ew_0 cat +BGqNnzNtWkc_0 person +BGq6TeZHkLU_0 elephant +BGshZfVDb5w_0 person +BG4QyYPKYvg_0 person +BG4QyYPKYvg_1 person +BG_x-4YUtFE_0 dog +BHA5UUg4lCw_2 train +BHH2sTfHwks_0 person +BHH2sTfHwks_1 person +BHPSyq8L5S8_1 person +BHQkdwmXrtI_1 skateboard +BHQkdwmXrtI_2 skateboard +BHYrJ1yaM-w_0 car +BHdbqcxv3Vw_0 truck +BHfXgxJCcrw_0 boat +BH5fxWFpHvE_0 airplane +BH5npOcPlY0_0 car +BH6nqU68dWo_0 person +BH74QV_0vtc_0 bird +BH9Ob6Uiw1w_1 person +BH_SlBCiQ_8_0 person +BIETPRRGGgY_4 elephant +BIETPRRGGgY_5 elephant +BIIU36E15Vo_0 person +BIMggdk7AHQ_0 cat +BIQeL2o_Ogg_0 person +BIUQ935UkDo_0 cow +BIVLmUTNYbk_0 person +BIV-1bNQ7pI_0 skateboard +BIfqcruNiic_0 person +BIkDAHYmcFw_0 person +BIkDAHYmcFw_1 person +BInC--gFqHM_0 person +BIvTK9qvP1w_0 skateboard +BIxCP9ck4-8_0 cat +BI5i3aDb_FQ_1 person +BI-kr0tFSDg_0 person +BJIZYdOZHzg_0 umbrella +BJK_SXpLtnI_0 bird +BJMP05du3Eg_0 person +BJQstPOa8Wk_0 person +BJS2YLbErJg_1 person +BJfRrRcfmF4_0 skateboard +BJf9nFjqLvg_1 bird +BJlcWhfsg_g_0 person +BJriJT6zJl8_1 skateboard +BJwoZcHbBK0_0 umbrella +BJ05o1_UKzw_0 dog +BJ44CIPaDf8_0 person +BKAo6GZ_kNs_0 train +BKTCaKgjiag_2 person +BKUKi0vTt0A_0 person +BKdSO_PNJ4U_1 person +BKdSO_PNJ4U_2 person +BKdSO_PNJ4U_0 person +BKl0wLRzoD8_0 person +BKw9UQxZ3a8_1 horse +BK-rIrwen6U_1 motorcycle +BLB0F-XD8IA_1 person +BLB0F-XD8IA_0 person +BLEdcnrUmEo_0 cat +BLE9cZ8L3a0_1 skateboard +BLFYe-dU9ZU_0 airplane +BLO7KJUu8t4_0 elephant +BLSwwE9mtTQ_1 knife +BLcOGv-0-dc_1 dog +BLfmgLou27o_0 cat +BLvowRU6z7s_0 bird +BLxsg2_sjDM_1 person +BLy6RcifNl0_0 bus +BLy6RcifNl0_1 bus +BLy6RcifNl0_3 bus +BL6tcorHrT4_0 bicycle +BMH2ReDeKuc_0 person +BMUnKa8FUGQ_0 person +BMUnKa8FUGQ_1 person +BMavrQABR1Y_0 person +BMa4xJ1U3Zk_0 person +BMbZc-jxEfo_0 person +BMbZc-jxEfo_1 person +BMfsf9tDz8o_0 cow +BMfsf9tDz8o_1 cow +BMhy1f7EuXM_0 elephant +BMptIGI1Il8_0 car +BMuO2fjJoOw_0 car +BMweJTmvCBg_0 person +BMweJTmvCBg_1 person +BMypDovEOEE_0 person +BMypDovEOEE_1 person +BM0QiiStqd8_1 skateboard +BM6XrBQQ7NE_0 person +BM6609PpfO0_1 person +BM6609PpfO0_0 person +BNGDM8sFM8Y_0 person +BNIVhG5pZh8_1 dog +BNJwAx3eUKc_0 person +BNK68rC7RdI_0 umbrella +BNTS3OPHAP4_0 horse +BNXKRPSr66c_0 person +BNXKRPSr66c_3 person +BNXKRPSr66c_1 person +BNXKRPSr66c_2 person +BNbPQGMLs2w_0 person +BNbPQGMLs2w_1 person +BNbSUPI8feg_0 person +BNcj3161E9o_0 person +BNeWUyqXAC0_1 airplane +BNmMB68b1PA_0 person +BNnVfaIfBx0_0 airplane +BNnVfaIfBx0_1 airplane +BNyK_4tt2fg_0 car +BNybc47kPjg_0 person +BN1HT0FOOhI_0 dog +BN7YfmbYuVs_0 elephant +BOE82LEqzWw_0 cow +BOF3tFvEu0o_0 person +BOHE8JNUcQc_0 boat +BOMeyjZNH5k_0 bicycle +BOQiuL9QlIo_1 person +BOUcPea33eY_2 skateboard +BOfgzvAgVQw_0 bus +aAMhdGuR5DE_0 cat +aARa5-CLhG8_0 person +aAVaqjgY1m8_1 person +aAZ2fVjhcIE_0 person +aAj0EN1Rnc0_0 bird +aAj0EN1Rnc0_1 bird +aAlTiBaLr8M_0 person +aAmVIu8X7p4_1 person +aAma36YlaAo_0 zebra +aAsr-Rf6rEE_0 person +aAsr-Rf6rEE_1 person +aAuz7EfR_fU_0 cow +aAyTLM_PmzA_0 skateboard +aAzpA1iK_bE_0 person +aA0FrWtkjXk_0 person +aA3okCsYx6Y_0 bird +aA5DYzky6o4_0 cow +aA8Tz4nZ99g_0 person +aBBtHXQoEtM_2 person +aBBtHXQoEtM_1 person +aBQm5kN1TfY_0 cat +aBexNnNkORk_0 airplane +aBq4NF1upak_0 person +aBvvXrP1BJs_0 person +aB-tGXFmyFU_0 person +aCQAel27T4o_2 person +aCSzhpU1heQ_0 cow +aCXfvvg8CF8_0 airplane +aCiDDC9KFS8_0 motorcycle +aClye1Ctc9E_3 truck +aCl98J6O9Hk_1 person +aCuXZ3LmfSo_0 person +aDGpg2xtDk8_1 person +aDRE08tF2Wc_1 bus +aDTQRnSeu_E_0 skateboard +aDTTYd0Z5Vk_1 person +aDjhOS5Xa9Q_0 boat +aDmLwCb_o30_0 dog +aDtJSv7XR90_0 car +aDte-e70l7U_0 cow +aDte-e70l7U_2 cow +aDte-e70l7U_3 cow +aDt4Puik-kU_0 horse +aDwTy9yiOms_0 umbrella +aDxRlCI40wo_0 person +aD2q00X0-eg_0 person +aD2q00X0-eg_1 person +aEJy28mvKPk_0 person +aEJy28mvKPk_1 person +aEMPa2NvIl4_0 horse +aERed6pg_h8_0 person +aER-VrHLWwY_0 person +aER-VrHLWwY_1 person +aEZ9vBpXNKU_0 person +aEw_vtKlegE_0 elephant +aExRtJpfZEs_0 knife +aE1veVneq04_0 person +aFC2Zy2-0dY_0 person +aFFKeUdtPcQ_4 knife +aFL2V522q9A_0 person +aFZ03eEOZFE_0 bird +aFbVlCimys8_0 bird +aFdPuo5xB-c_0 person +aFhKp8gVZSE_0 person +aF86vrld8V4_0 person +aF-CmWo8ooM_0 person +aF-CmWo8ooM_1 person +aGAB6WQFklc_0 person +aGE8AphnkNU_0 knife +aGGiVuwB1p8_0 bear +aGY3LCiYRnQ_0 motorcycle +aGgnovv6T3U_0 dog +aGgxdwCpAN0_1 horse +aGhNzJSHCOU_1 knife +aGmxZatPe60_0 person +aGmxZatPe60_1 person +aGuWVv6XS8Q_0 person +aGuWVv6XS8Q_1 person +aGwPRbsru-4_0 cat +aGxOl5SXjtM_0 person +aG1c8x5Dl-w_3 bicycle +aG1c8x5Dl-w_2 bicycle +aG1c8x5Dl-w_4 bicycle +aG20iwkTd_o_0 person +aG6D_te6V3s_0 person +aHEFx7Zz6E4_0 person +aHb4yEpCinw_0 truck +aHiGSUMMfBQ_0 person +aHnMWEvjLzI_0 car +aHrTcxckS-A_0 person +aHrTcxckS-A_1 person +aHsgQAyd8ss_0 person +aH2ZxImdwaU_1 motorcycle +aH2ZxImdwaU_2 motorcycle +aH5Cd20kdJw_0 elephant +aILjXrLJpHw_0 umbrella +aIQf8LQ5QPU_0 person +aISEbZGZH68_1 car +aITryMUZ2b8_0 person +aIUYT8pblHs_0 truck +aIU5E5tHvdc_1 person +aIVWVNBI-n0_0 elephant +aIcFi8LMv0w_0 airplane +aIjLf6T_K3o_1 bear +aIoZO3mu_tQ_0 person +aI311E3BWwI_0 elephant +aI7axTZFW4A_0 truck +aI80ysvYFG4_0 person +aJChqX9Ki8A_6 airplane +aJChqX9Ki8A_1 airplane +aJChqX9Ki8A_2 airplane +aJChqX9Ki8A_5 airplane +aJN9lRsvUv8_0 person +aJQ9scZQmz8_0 person +aJTABCCQtK4_0 horse +aJYmkpuijrk_0 motorcycle +aJYurtxV0Og_0 train +aJYurtxV0Og_1 train +aJcPyWppCcI_0 motorcycle +aJgpAyFnpeI_0 cat +aJ0dUcEIE_U_0 person +aJ1SzcgNcxI_0 cat +aJ8w4L7E368_0 person +aKLf2yC2diM_0 car +aKMqeCkIJSg_0 person +aKOMIxz2RsM_0 person +aKOMIxz2RsM_1 person +aKiwOUy71Lo_1 person +aKiwOUy71Lo_0 person +aKqrwq-Sigg_0 skateboard +aKtBD-3wFMA_2 bear +aKtBD-3wFMA_1 bear +aKu-1-TFl1g_0 knife +aK-rgio7orw_2 bus +aLDq7roX-SU_0 cat +aLFDqtBMblI_0 cat +aLFxGnCM1zs_0 person +aLIa7x90hQc_0 person +aLUSnANtUlE_0 airplane +aLX9cIe12C8_0 skateboard +aLZAMgiWcXk_0 bird +aLZ0lbLzg8Y_0 person +aLZ0wCY2j2s_1 person +aLeeoZ1uVcc_0 boat +aLjomcNk9fc_0 person +aLj4N9Tp6C0_0 skateboard +aLj4N9Tp6C0_1 skateboard +aLo-gekX9j0_0 person +aLo-gekX9j0_1 person +aLuNNRUC09A_1 bus +aLuNNRUC09A_6 bus +aLvCIWJQJbY_0 car +aLvg1CWrY0Q_0 truck +aLxJ8T4CFuM_0 person +aLzL_Gldhzk_1 person +aLzhO0EqNcc_3 horse +aL6H2Jatw0k_0 cat +aL70_drPJtA_0 train +aL8hELYDnTc_0 person +aMAKznXul5M_2 knife +aMAYLrcEnZY_0 bus +aMAeSegIdJg_0 person +aMAeSegIdJg_1 person +aMHtvIvWTBU_0 bear +aMNbQ1Cl5GY_0 motorcycle +aMRtQFBcLNM_0 person +aMX0jhSq6UY_0 person +aMb78Ixlbfw_0 skateboard +aMqHsdXJ7UU_0 person +aMzZxN9uvMc_2 horse +aNB5rIhRL7g_0 airplane +aNEpBEnAUhw_0 motorcycle +aNF18KgxGHA_0 skateboard +aNJuTWrnIfo_0 person +aNJuTWrnIfo_1 person +aNKleFpxS4M_0 person +aNKleFpxS4M_1 person +aNNWNDoOM_4_0 person +aNNWNDoOM_4_1 person +aNOXvvKZ3qU_0 person +aNZMe4tov6w_0 cow +aNdJrRu4imo_0 person +aNjs-khPjiU_0 person +aNj1xwowXYU_0 person +aNqkQnGfWEc_2 skateboard +aNqkQnGfWEc_0 skateboard +aNwIHwPqFPc_0 car +aN4Na3OaY4I_0 bicycle +aN4NmH-GafU_0 person +aN770kOQCD8_0 person +aN82X1hXgEE_0 person +aN82X1hXgEE_1 person +aN9XAd7-rzE_0 person +aN9XAd7-rzE_1 person +aN_3Pwk-7oY_0 person +aOHPVt_93RE_0 bicycle +aON6RKmi-YQ_2 train +aOPbvY62dMQ_0 airplane +aOQ-8RoQYEU_0 person +aOQ-8RoQYEU_1 person +aOQ-8RoQYEU_2 person +aOW81s5KlyA_0 person +aOcGv3kcyhg_0 bear +aOcGv3kcyhg_3 bear +aOjjUIWuG6Q_1 elephant +aOp2NlwNeoY_0 cat +aOz0l6mLHmA_1 dog +BOlBcGufEU8_0 person +BOlBcGufEU8_1 person +BOmgqlRxGlM_1 person +BOmgqlRxGlM_0 person +BOnvGIZd58M_0 person +BOowRuwiNhU_0 person +BOowRuwiNhU_1 person +BOr7CffDWEU_0 person +BOsNz8L3PXI_0 person +BOtfIOm5kag_0 dog +BO1T_-iFGdM_5 bird +BO1T_-iFGdM_2 bird +BO1T_-iFGdM_3 bird +BO3UKxe7nyo_0 person +BO5EdP_PO9M_0 person +BO7sWBaaL7g_0 person +BO7sWBaaL7g_1 person +BO-3uvHhUdI_0 person +BO-3uvHhUdI_1 person +BPBBMIdFoiE_0 person +BPEwUVhfaOk_1 knife +BPVpq7UrI-k_0 person +BPX5EquoyCU_0 motorcycle +BPX5EquoyCU_3 motorcycle +BPX5EquoyCU_1 motorcycle +BPX5EquoyCU_2 motorcycle +BPiWTYUA7eI_0 person +BPjkQ-lEqcw_0 person +BPrrZpiDdo4_0 cow +BPsTDg4C4o0_1 person +BPsTDg4C4o0_0 person +BPxPfFzwlQA_0 truck +BP-GGAbCOhE_1 bus +BQDxNNWRtas_0 car +BQDxNNWRtas_1 car +BQEzj9pP1SU_0 person +BQIO94PF6RE_0 person +BQIO94PF6RE_1 person +BQVcvMWyWpU_1 person +BQZGptzIdjE_0 cow +BQgPk0vRreM_0 bird +BQgPk0vRreM_1 bird +BQgPk0vRreM_3 bird +BQgPk0vRreM_6 bird +BQgPk0vRreM_9 bird +BQh5Ib9nynM_0 truck +BQtDUi4BxRg_0 person +BQwLGv7fgQg_0 person +BQxCcefrjSk_0 cat +BQyowuIZqFQ_0 person +BQzzKQ9ejzw_1 knife +BRCb183ELe0_0 person +BRHPsi_0nTg_0 motorcycle +BRQiSnowTss_0 horse +BRVNuDR5WzI_0 cow +BRcQS0dQqEU_0 car +BRfegSv5VEk_0 person +BRfegSv5VEk_1 person +BRi_AMaK3kc_0 dog +BRjvUtQdukg_0 horse +BRlWBt4WHdU_1 horse +BRnsmPzoEsM_0 skateboard +BRtCCpXG_N8_1 elephant +BRt1o8xqxFs_0 person +BRt5hLASRMU_0 bird +BRxrw0-skYM_0 elephant +BR0SGq2ioqU_2 train +BR0SGq2ioqU_7 train +BR1gOlJPEdk_2 elephant +BR8cOV8KYX4_0 person +BR-XwELzLV0_1 dog +BSDy_dzOSS4_0 cow +BSHg9I0V6Yc_2 bus +BSJgV2iO0jc_0 person +BSOCno_3bfI_0 person +BSSyaPq1EoM_0 train +BSWNCcyXeR4_1 horse +BSWpwtIPQ9U_0 elephant +BSWpwtIPQ9U_1 elephant +BSWpwtIPQ9U_2 elephant +BSWpwtIPQ9U_3 elephant +BSqz3i60KPw_4 bicycle +BSqz3i60KPw_1 bicycle +BSqz3i60KPw_2 bicycle +BSutEBx3H4A_0 truck +BSvCnoryvn4_0 elephant +BSyxB7X9SH0_5 truck +BSyxB7X9SH0_7 truck +BS1lexD0ugY_1 person +BS1lexD0ugY_0 person +BS5mJ0Y7Rys_0 person +BS-S0nYSwkQ_0 person +BS-S0nYSwkQ_1 person +BTBmlFGHK-8_2 person +BTBmlFGHK-8_0 person +BTBmlFGHK-8_1 person +BTKLizyvgcA_0 person +BTR83oP1vpo_0 person +BTlwglCdzOk_0 elephant +BTpBteZfK7Q_0 cat +BTxSuijXVPY_0 person +BTywlpNCABw_0 cow +BTzWqg8vHQI_0 car +BT9sKGDb0Qw_0 train +BT9sKGDb0Qw_1 train +BUF45g7KGB8_0 motorcycle +BUX8raEGFZk_0 dog +BUX8raEGFZk_2 dog +BUX8raEGFZk_3 dog +BUY-_l8_v9s_0 person +BUZ7x7JaQ1k_0 person +BUrMlyUBryI_0 horse +BU4SnrK9UiY_0 horse +BU4SnrK9UiY_2 horse +BU4yiA6qKAQ_0 bicycle +BU5PaU-UTss_0 person +BVAi_zqhIeg_1 person +BVCe2emxuTQ_0 horse +BVFYmsvoNTA_0 cow +BVS5Q8eBmRs_0 person +BVWEvs3lq0Y_0 person +BVWEvs3lq0Y_1 person +BVXMpcHTg80_2 motorcycle +BVm9KRW0iu8_0 motorcycle +BVo3XdFnAJM_0 horse +BVxr6TGFsMQ_1 person +BV5tXmVwddI_1 person +BV-UtDJNS2w_1 motorcycle +BWA5eWlt6Lg_0 car +BWFYpOE-8yo_0 person +BWcaU8lR4rM_0 person +BWdhK5cwgt0_0 bus +BWjRZ-aKRX4_1 person +BWlnPrI8FLk_0 person +BWnFU-Li_8E_0 person +BWn3QGOyZJc_0 elephant +BWn7EPWkJ2I_1 bear +BWp2oVJMG1A_0 person +BWqYVuIKaNA_0 person +BW5r0Kv6h2U_0 boat +BW56O_QhBmc_0 person +BW7uP0jcst8_0 horse +BXA3uMFAA9M_0 cow +BXCd65rDsk4_0 dog +BXCrD4eGGWw_0 person +BXHktSPnW24_0 person +BXTGSkuESqU_0 person +BXUL3aLVZM4_0 person +BXWXLNGacmc_1 motorcycle +BXWXLNGacmc_0 motorcycle +BXdMv9s3Rtw_0 person +BXiQhR0Zj70_0 person +BXrwbMjK_ZU_0 train +BX8AJD8uL3U_2 person +BX-SAZsC6yc_2 knife +BX-SAZsC6yc_4 knife +BYQfvvAP9rY_0 person +BYRNeh3RRZs_0 person +BYS-DmtMpWE_0 cat +BYVhHLCSZ_M_1 dog +BYYakMVK6Ko_0 person +BYi8dYVDYak_0 person +BYkytpBqzHQ_0 airplane +BYq45niURL8_1 truck +BYq45niURL8_0 truck +BYud6fy8t8A_1 knife +BYud6fy8t8A_0 knife +BYud6fy8t8A_2 knife +BYud6fy8t8A_3 knife +BYxg5sQjvQ4_0 person +BYyATiWsxZs_2 car +BYyATiWsxZs_0 car +BYyATiWsxZs_1 car +BYyrXwDFF5U_0 person +BY0XhpATtuI_0 umbrella +BY2Fs4KDDbU_0 motorcycle +BY7KYQ_Qf3Y_0 cow +BY8mmPl_K_A_0 person +BY-5sA1BbFE_0 dog +BY-5sA1BbFE_2 dog +BZDa7e9EFvI_0 knife +BZERyxrpvg4_1 person +BZIzw3XdAgI_1 person +BZI3ovXxotQ_0 knife +BZeIe9Nkb1E_0 cat +BZgZ1H4t3hQ_0 person +BZgxjWSM7Vc_0 bicycle +BZhfYzqKuu8_0 person +BZkYWI_qxz4_1 bird +BZldivEoOo8_0 person +BZli_iMMV8k_0 bear +BZli_iMMV8k_7 bear +BZ94WX4wHn0_0 skateboard +BaDQg_CCQpU_0 person +BaDQg_CCQpU_2 person +BaHS1WcgbbE_0 bird +BaHS1WcgbbE_1 bird +BaJTQLa-vuU_0 person +BaOQYsYuC6A_1 elephant +BaRsW_taGVY_0 cat +BaWQb_lSjYs_0 train +BaYLeM_yk_Q_1 skateboard +BafH7BetIyk_0 person +BakCr5HeDNE_2 boat +BakCr5HeDNE_0 boat +BauKE-faLzM_1 person +BavQVUFfmBU_1 person +BavQVUFfmBU_0 person +BavoG7kb0wo_0 car +Baxc5TW06FU_1 knife +Ba1sC-X1OF8_0 person +Ba1sC-X1OF8_1 person +Ba2T3joy6BQ_0 person +Ba3CWVKFpBE_0 boat +Ba5BO-nvDnE_1 horse +Ba-SiAqH09k_2 truck +BbAdBjyFFEA_0 bird +BbAdBjyFFEA_1 bird +BbAdBjyFFEA_2 bird +BbEfZ9mUKOY_0 cat +BbOabnT5V-E_0 person +BbQyfmZx-2Y_2 bear +BbRarKH6D_Q_0 horse +BbYZ7Ee3Ixs_0 person +BbYqjT1OzLY_0 person +BbYqjT1OzLY_1 person +BbfOXQD21Ac_1 motorcycle +BbnSU5sRdBs_0 person +BbnxzNL5tMk_0 person +Bbq8h83cFE8_0 person +Bbu_YM_GBG4_3 bird +Bbu_YM_GBG4_0 bird +Bbv9Y9Goufk_5 elephant +Bbv9Y9Goufk_0 elephant +Bbv9Y9Goufk_1 elephant +Bbv9Y9Goufk_2 elephant +Bb4uwSjmtKk_2 bird +BcHl4OuJLT4_0 person +BcHl4OuJLT4_1 person +BcSXX5O_YDw_0 bicycle +BcVn38vI_Zk_0 person +BcV5QdDIrMg_0 person +Bcg-TsdpO-Q_0 person +BcjVHV-6WWM_0 person +BcjZaclf1m0_3 bird +aO4uLNN4Gt0_0 bear +aPCEyodWBU4_0 person +aPPUf7JUJRo_0 person +aPf5SoOgmhQ_0 motorcycle +aPheJtUTSps_1 boat +aPm89i_7aKs_0 train +aPm89i_7aKs_1 train +aPswSvCaFDQ_0 elephant +aPvqWgeR03U_0 person +aQAieL0LKIo_0 horse +aQB2gAnqQi0_1 person +aQGQKDLwRqM_0 person +aQVn7fJi_l4_0 cat +aQaKnTZ4hDg_0 person +aQfQqr5W5uI_1 truck +aQfQqr5W5uI_2 truck +aQfQqr5W5uI_4 truck +aQlLjT95Hgs_3 horse +aQub6VGWKzQ_0 car +aQzKS5Sn9u0_0 person +aQ1c75hfANo_0 person +aQ6larydXgI_4 elephant +aQ6larydXgI_0 elephant +aRBWB79BIIg_1 umbrella +aRHGn50eToQ_0 bear +aRQQ75s9Ni4_0 boat +aRRUAfurxVU_0 person +aRcw_PTSf4o_0 person +aRdAN9jVvqQ_1 dog +aRnJ4lIPIL4_0 bus +aRueDRgWEOs_0 truck +aRzwrPXsTRI_0 truck +aR6P3PtMIZc_0 person +aSDuIU0pzYY_0 person +aSH88cb0kww_0 person +aSMzQpOjAc8_0 train +aSUtY_pSN0k_0 bird +aSWGbO-Nfcg_0 train +aSWGbO-Nfcg_1 train +aSb-LY3vBsg_0 giraffe +aSkBoJ55w2Y_0 person +aSqwAZJaQIk_0 bus +aSqwAZJaQIk_2 bus +aSsjyvISV94_0 train +aSw1yhbXHuA_0 elephant +aS2Zw7-j7p4_0 car +aTBr31jkThQ_3 bus +aTOn74Inw24_0 bird +aTR3FylgTkA_1 person +aTR3FylgTkA_2 person +aTS8hur_yyo_0 person +aTcDiEXEhhk_1 horse +aTdIOtWasSE_0 person +aTeFjqoG9fM_0 person +aTeFjqoG9fM_1 person +aTj38bNIsQo_0 cow +aTvgsqSb5aA_0 person +aTvoRXrEvG4_0 bicycle +aTvoRXrEvG4_2 bicycle +aT3idINTybY_0 umbrella +aUFHlj5AVrU_0 person +aUNlQPWMFHo_0 car +aUQh47P34C0_0 person +aUQh47P34C0_1 person +aUX-HZraWQs_3 zebra +aUh41vv5vdE_3 train +aUh41vv5vdE_0 train +aUh41vv5vdE_2 train +aUv4LjbJxLs_0 bus +aU5AZMYHZ2o_0 dog +aU5tePXE5qE_1 elephant +aVFbcdQrobU_0 person +aVGtibXVt40_0 train +aVMpwmT7ojA_0 truck +aVPIHMyNEw8_0 truck +aVZJ8qaxG3s_0 person +aVif6Qc9Prw_0 cow +aVknWcQimJA_0 bus +aVm9jp_ttsk_0 elephant +aVm9jp_ttsk_1 elephant +aVm9jp_ttsk_4 elephant +aVm9jp_ttsk_5 elephant +aVm9jp_ttsk_6 elephant +aVm9jp_ttsk_7 elephant +aVm9jp_ttsk_8 elephant +aVo-jvGoUGs_1 boat +aVo-jvGoUGs_0 boat +aVq4ezzbcTc_0 bird +aVvuGEexwy0_1 person +aVy9mhLlo5U_0 umbrella +aV2_0JBmw8o_1 person +aV7mSkydynI_4 bicycle +aV7mSkydynI_1 bicycle +aV7mSkydynI_2 bicycle +aWCNGGW4Qew_0 person +aWDtrDYqivs_0 person +aWQxqFyyzng_0 cow +aWQxqFyyzng_1 cow +aWWMT0webCY_0 person +aWWtWhgt_V0_0 cow +aWYoUCAev64_2 bicycle +aWYoUCAev64_0 bicycle +aWcaF85RIM8_3 elephant +aWgSKxQO5Ps_0 cat +aWi51gAEIkY_0 person +aWma4eTtHv0_0 person +aWqBSBc-XpU_2 knife +aWt13fGkYuA_0 cow +aW9D5rT3GCo_0 bear +aXFFLOGR_yI_0 person +aXFgCWZLFj8_0 horse +aXFgCWZLFj8_5 horse +aXFgCWZLFj8_1 horse +aXKbkyjRqkU_8 bear +aXKbkyjRqkU_0 bear +aXKbkyjRqkU_7 bear +aXOPdDTpvxc_0 person +aXWkAKNw0Dg_0 bird +aXXfrIsIqi0_0 person +aXhd5BhT4hs_0 cow +aXhd5BhT4hs_1 cow +aXml5kCJyDY_0 skateboard +aXml5kCJyDY_2 skateboard +aXn1cwN8vng_0 airplane +aXn1cwN8vng_1 airplane +aXxKLf5m61g_1 person +aXxKLf5m61g_0 person +aXxPxBeZjQI_0 person +aX0JOJY-BDc_0 person +aX0JOJY-BDc_2 person +aYCA7dz0nbI_0 person +aYJzxhE8-Rs_5 knife +aYPCTMucy6A_0 person +aYgA8AxT0V4_0 giraffe +aY1i2TADX0c_0 person +aY1i2TADX0c_1 person +aY1i2TADX0c_2 person +aY4dOYabpbs_0 cow +aY6lI7qO6kI_0 person +aZF83PK7HKU_0 person +aZF83PK7HKU_1 person +aZGZbrCAFl4_0 person +aZGZbrCAFl4_1 person +aZHznZSD2uE_0 person +aZJ_vArnOC0_0 cow +aZL_n-gon0U_0 boat +aZT_v5WnLio_0 person +aZVtxAF_Imw_0 dog +aZZcXyRJwyI_0 person +aZ4tzgju18s_1 train +aZ-3jypmJiY_0 person +aaAAXDB7ml4_0 elephant +aaAAXDB7ml4_1 elephant +aaA_qcyN3eM_1 cow +aaBf3fxpR7E_1 person +aaQjh2_8aVw_1 motorcycle +aaQjh2_8aVw_0 motorcycle +aaUXN-xWi1c_0 person +aaWV0TEIbhM_0 skateboard +aaWV0TEIbhM_2 skateboard +aacFWGARp08_0 person +aacLCDo8Zus_0 umbrella +aacZc8VUtxg_0 bird +aaoYsiVAFDY_0 airplane +aas39xgvbfg_0 cat +aatdoixvb4w_0 dog +aazC6OJV2GY_0 person +aa0jo00Yxz0_2 boat +aa-J6xg9RH4_0 person +abCu1bwDisA_0 umbrella +abHvXnWduQQ_0 person +abQ7YCx3QQM_0 train +abbympAEM_k_0 cow +ablCJGTLCow_1 elephant +ablCJGTLCow_3 elephant +ablCJGTLCow_4 elephant +ablCJGTLCow_0 elephant +able--ZWvkg_1 person +abnCzyC9R28_0 person +abpyt2p-uMg_1 bird +abrKRGgLV0o_0 dog +abrKRGgLV0o_1 dog +abxcR1X4UIo_1 bird +abxuxX4aHFI_1 horse +abxuxX4aHFI_2 horse +ab1RpuefUA0_3 bicycle +ab2b2WA-fQs_1 person +ab2b2WA-fQs_0 person +ab2b2WA-fQs_2 person +acDY2Ono9WA_0 dog +acL58vxHnnc_0 person +acOdf26jldk_0 person +acYxvpS0b7s_2 airplane +acZFDZif1ww_0 train +aciCzrBQsM0_0 person +acnOEnTXwJY_0 cow +acnOEnTXwJY_1 cow +ac4feYMso4k_0 train +ac6NdTBtc6U_1 person +adAkRe99CDA_0 truck +adE0Nk3CKyI_0 car +adKIteGSOIM_1 skateboard +adY8EtfOO_w_0 train +adcv2A70AoA_0 person +adiBUyRiBfo_1 person +adiBUyRiBfo_0 person +adskAqVAdFQ_1 elephant +ad2C17MGAEo_0 bus +ad94BZD75ck_1 cow +aeAjL4rCjIM_1 truck +aeAjL4rCjIM_0 truck +aeIzIOSHZek_0 person +aeJKW7m42xo_2 airplane +aeJKW7m42xo_0 airplane +aeKckIdL0io_0 bird +aeUVIIEtwdw_1 motorcycle +aeUVIIEtwdw_2 motorcycle +aeUVIIEtwdw_3 motorcycle +aeUVIIEtwdw_4 motorcycle +aeboOU_vdjo_0 person +aeboOU_vdjo_1 person +Bc2pPI9s8bM_2 horse +Bc26F0eEyBg_0 person +Bc5QvTVd-04_0 person +Bc64C5jdZDg_0 person +Bc7NXuSycR4_0 skateboard +Bc-b4WhkWxw_0 person +BdBZuvI8oak_0 truck +BdBZuvI8oak_8 truck +BdBZuvI8oak_1 truck +BdBZuvI8oak_2 truck +BdBZuvI8oak_3 truck +BdBZuvI8oak_4 truck +BdBZuvI8oak_7 truck +BdB6NgtqioE_1 bear +BdCnusBWLuw_0 bicycle +BdC5wdGWMCw_0 person +BdLMnBBX7rc_0 person +BdQ8AC4jpkk_0 person +BdR02myBXHY_0 person +BdTRTQRbNqI_1 skateboard +BdT2u0kYx90_0 bicycle +BdT2u0kYx90_1 bicycle +BdT2u0kYx90_2 bicycle +BdT2u0kYx90_4 bicycle +BdZOawocL-c_0 person +BddRmrmaI6M_0 person +Bd0JDJL6yXk_0 airplane +Bd21KrWCyCg_0 cat +Bd-WW1Hs9kk_1 train +BeAD9m4Yu_U_0 person +BeCQkxXRRww_1 person +BeCQkxXRRww_0 person +BeCmkGB-RCw_0 horse +BeQWoctTF5I_0 bear +BeQWoctTF5I_2 bear +BeQupBkL2y8_0 train +BeTu3Ag6XIw_4 bicycle +BeTu3Ag6XIw_1 bicycle +BeVqWRYzPkY_0 knife +Bebzr4dP1Ug_2 person +Bebzr4dP1Ug_0 person +BedgXkpLAOs_0 person +BefMC4f6Z3s_0 person +BefMC4f6Z3s_1 person +Befq3kL0E7o_0 person +Begwn2Da_j8_0 person +BepRWdKn0QA_0 cat +BetAKo6E3rw_0 person +BezlbA5t77I_1 person +Be4NCK9GwQU_0 person +Be4V9lpSpJw_0 knife +BfIBlw1RkXc_1 truck +BfJUkGEnxvE_0 person +BfOXYUOsSf8_0 airplane +BfSxTA9yZak_0 person +BfT3bVAeXLU_2 boat +BfWpLwfDFbc_0 person +BffFognyZOA_1 skateboard +BffFognyZOA_0 skateboard +BfkXvdTkYF4_0 person +BfkXvdTkYF4_1 person +BfwHmAlZdKA_0 person +Bf1cF3BfY18_0 person +BgBDqhuoTr0_0 dog +BgHvkS4H7w0_0 person +BgamGCKlzTI_0 person +BgbxYgCIde8_0 cow +BggPqcJz12g_1 elephant +BgjdCfaJfsE_0 elephant +BglxBESIjlE_0 person +BgsTkbznAjI_0 person +BgwZN0Ui-Q8_0 person +Bg0_DcQLOys_1 knife +Bg3Zox43xGI_0 skateboard +Bg4NtG5QkwM_0 person +Bg_cKljiGGE_2 person +Bg_cKljiGGE_0 person +BhA7KMeJYAE_0 skateboard +BhL184lkUcw_0 person +BhPyQcTHRmg_0 boat +BhXpOqm8Q5o_0 bird +BhZl6ZTtKDo_0 person +Bha-PhOr-bU_0 bird +BhdcIu_nQYs_0 bus +BhqZrCcQpD4_0 elephant +Bh4QFujTqIo_0 train +Bh5wIL7IE9A_0 person +Bh5wIL7IE9A_1 person +BiGYFhnDhMI_0 airplane +BiQ4cYnaGPo_0 person +BiYzQbOwhWY_1 train +BiYzQbOwhWY_2 train +BipPdxUV2PY_3 boat +BirMOPf7k0I_0 knife +BizSBnzOzy0_0 person +BizSBnzOzy0_1 person +Bi1KsDpJT8w_0 person +Bi1KsDpJT8w_1 person +BjGhd-Eq5ig_1 car +BjGhd-Eq5ig_7 car +BjJSECIrsd0_0 dog +BjLJqIPSyUM_0 bicycle +BjQO2ipch-w_1 dog +BjRyA1cPxA4_0 cow +BjZ9JRI_WkM_0 person +BjbCdEHhCjI_0 person +BjfwCDsBoeg_2 bicycle +BjhITTFavAk_0 person +BjiJ7HAaOj8_0 person +Bjj4KdIbDBY_0 person +Bjk2IA4thIE_0 bear +BjogwheL3BI_0 horse +BjpX2nla914_1 car +BjqdFABBqxA_0 person +BjqdFABBqxA_1 person +BjraW0bXW-0_0 person +Bj8lO8Jag3Y_0 person +Bj9wPwHXNQo_1 horse +Bj9wPwHXNQo_2 horse +Bj9wPwHXNQo_3 horse +Bj_fS2abD9o_1 bird +BkFws1J8IM0_0 bird +BkMb48QM-zQ_0 person +Bkco3wJWvp0_0 person +BkdBnU65i7Y_0 person +BkdWJT3sWro_3 airplane +BkdWJT3sWro_4 airplane +BkfKa-zgphc_1 airplane +BklBU6Epydc_4 horse +BklBU6Epydc_1 horse +BkoQ8_W4drM_0 umbrella +BkteTGu81tQ_0 bus +BkwpJBHM_DM_0 dog +Bk3VbRagAwg_0 dog +BlXhR1rRct8_0 bicycle +BlfVNiQZtko_1 cow +BlfVNiQZtko_0 cow +BlhT8WFfI54_0 person +Blj4FY__L6Y_0 person +BllnWV-BIDo_0 bird +BlqsGIq2hNg_0 person +BlqsGIq2hNg_1 person +BlzUBgB6BEc_0 person +Bl-1081HLyM_0 motorcycle +Bl--N1EQpuA_5 airplane +BmCAiO-WNmE_0 skateboard +BmG7dEBuS6s_0 cow +BmHShiZ1Xus_3 airplane +BmNwfiFBeRo_0 person +BmNzw5vNQNI_0 skateboard +BmRZWeMzQLg_3 bicycle +BmRZWeMzQLg_0 bicycle +BmSBpZrrEt8_0 cat +BmXdIzhVZ0Q_2 bear +BmZN0ljGa84_2 motorcycle +BmfHrAPEMrk_2 person +BmfHrAPEMrk_0 person +BmfHrAPEMrk_1 person +BmjBM58PfZE_0 cow +BmjEEjKDJVI_0 person +BmjLZgp38NI_0 cat +Bm3l_RLjYpo_0 motorcycle +Bm3wZ63Ymvo_2 motorcycle +Bm7e-qOAcKQ_0 person +Bm8qAGd91Gg_0 train +BnADRMlWOsM_0 airplane +BnNJUP6xfG8_0 bear +BniJFr7IJRo_1 person +BniJFr7IJRo_0 person +BniJr-iCh9M_1 truck +BnkIFwVPh8w_0 horse +BnkIFwVPh8w_2 horse +BnkIFwVPh8w_4 horse +BnkU89Dq2IQ_0 person +BoA6CUl4t70_0 cow +BoGAxXRzHWs_0 cow +BoLSvTrm3d8_3 cow +BoNtUpvusGM_3 motorcycle +BoNtUpvusGM_4 motorcycle +BoNtUpvusGM_0 motorcycle +BoNtUpvusGM_1 motorcycle +BoNtUpvusGM_2 motorcycle +BoOANS5_U9I_0 motorcycle +BoPj2W_G2Qg_0 airplane +BoYvNfndu60_0 skateboard +BoZ3ZvdEZ4o_0 car +BoZ3ZvdEZ4o_1 car +BoiPpDeQ2mQ_0 airplane +BomNEWAGolQ_0 person +BomVU8_LL_Y_2 dog +Bowyw_fhWZ8_0 person +Boy5toMvMwo_0 giraffe +Bo2qsQNYATk_3 skateboard +Bo5bT8QP_Og_0 person +BpDLFqS9EAE_0 person +BpVyiSvjk4o_1 dog +BpdZmCkSHco_0 giraffe +BpjdKB7AJ8U_0 skateboard +BpkMUQLoJUM_0 person +BpoWgamMMro_0 cow +Bp1zluIhHzc_0 person +Bp4vXfVIVxA_0 skateboard +BqBkvlijWKg_1 person +BqDnDPIE18k_3 horse +BqPcqKW3uAM_0 dog +BqoRxXUz7q4_2 truck +BqpA7iBOQ_s_0 person +BqqPm3F1F_w_0 person +Bq4id5zA48c_2 bear +Bq_emgXftMI_0 person +BrDdbgxB7qI_1 bird +BrHDj1biLlA_0 airplane +BrHDj1biLlA_1 airplane +BrJiBbRF25U_0 person +BrKgWUQnUWI_0 cow +BrQNhzCKfxs_0 person +aelph1Y8yPk_0 skateboard +ae161Zq0QBg_0 skateboard +afCYMTTgbMw_1 dog +afD_y2ZEHn4_0 skateboard +afLO-CD48TI_0 motorcycle +afLO-CD48TI_1 motorcycle +afWl3lTglsw_0 person +afbS6cTlE5Q_0 person +afu5-raaJEc_1 elephant +af9Z_LR-L7M_0 person +af-MtTvmPic_0 person +agFlIZmS0zU_0 person +agF_eyIgF3g_0 person +agGuxSx4UdI_0 motorcycle +agIme93Q6WA_0 person +agMdtESL5kE_2 cow +agSpfpV4EsQ_0 person +agVHBb-qLAw_1 bus +agWS48KnYWk_0 motorcycle +agXPzkjMl4c_0 bird +agYR35aJ1no_0 person +ag1ohTMq9Iw_0 car +ag5Gy7ZNbfw_2 knife +ag5Gy7ZNbfw_3 knife +ag6NY6nrTvw_0 bear +ahE37MgcoUs_0 person +ahMgOG4Bpcw_0 car +ahQD9PpYoqE_1 train +ahYD0J4XzC0_0 cat +aheVwPx1egw_0 truck +ahiO1CwoaY4_0 person +ahnbyNWfvpM_1 cow +ahsHWgQGPNI_0 person +ahv6_xBxvmg_0 person +ah03BOnPUqs_0 cow +ah-2yN1cKOg_0 bus +aiINQVIMx5o_0 person +aiNcNIUbY3E_1 dog +aiX8ymgR1g0_0 boat +aiX8ymgR1g0_3 boat +aierZPItkn8_0 bicycle +aierZPItkn8_1 bicycle +aiiN3X-f5Ss_0 person +aiklFoEJX1Q_0 person +ainWSZibSIM_1 bicycle +aio5SboRXGU_0 person +aio5SboRXGU_1 person +aizJI68M2SY_2 truck +aizJI68M2SY_1 truck +ai1CTuarr50_0 bus +ai3xYb_xvFA_0 person +ai7WTyMnl1g_2 horse +ai7WTyMnl1g_3 person +ai7WTyMnl1g_0 horse +ai7WTyMnl1g_1 horse +ai9-_EMwk4U_0 skateboard +ai_jmsLJTR0_0 person +ajAuKSOFBKQ_2 bus +ajAuKSOFBKQ_3 bus +ajB-QUVDyXI_0 cat +ajO4xx5beuE_1 bicycle +ajPP5EY_nAo_0 person +ajPP5EY_nAo_1 person +ajPY1htweXM_0 person +ajPY1htweXM_1 person +ajtvjEY9TPA_0 airplane +ajxcj5ovYdw_0 skateboard +aj0Ll84jtZs_0 person +aj0Ll84jtZs_1 person +aj3UwQNtZPo_0 train +aj6sqeG0k54_0 umbrella +akH9ouIrOds_0 skateboard +akIlFKpZAtk_0 person +akOLIpAsxqc_1 person +akQU-s0RCWE_1 bus +akoVZ50spRM_0 person +ak6iAVUNU7c_0 dog +ak6iAVUNU7c_2 dog +ak6iAVUNU7c_1 dog +ak89dpHVmHc_1 person +alAFNWeSJts_0 skateboard +alDkqPNUFLU_0 person +alDkqPNUFLU_1 person +alKgZTVxcV4_0 motorcycle +alX9MOY80Aw_0 person +aluZTs_Ys8I_0 car +alvKKzlOBKM_0 person +alzWhOivD0E_0 person +al2Vh0In4HU_0 bear +al2Vh0In4HU_2 bear +al2Vh0In4HU_3 bear +al8Of2FWy80_0 cat +al8vzWgNDbs_2 bicycle +al8vzWgNDbs_7 bicycle +al8vzWgNDbs_8 bicycle +amIvXQ6aZkE_0 cow +amL9Dar_hp0_0 person +amTcWqrgBBg_3 airplane +amjpcHzuYb4_0 person +ams9MCDF15I_1 person +ams9MCDF15I_0 person +amvLPTONS1U_0 cow +am-3XKJkCqg_0 train +anAXVexurxo_2 dog +anJbsuTwShw_0 person +anLTttUpag0_0 skateboard +anR9cuXRv6Q_0 person +anWxwjzPRBA_0 person +anYy3XNTTGw_0 person +anZ9lxr24eY_0 person +angay7OmUwA_0 truck +aniCxSPm8Uc_0 car +anlydfnmv7g_0 person +annQpJsk6NI_0 bus +anpsTMr_HIo_0 cat +anrBShdHOz4_0 person +anvk-OdKLBE_0 person +anvngue8Qh8_0 cat +anzrRzyYAAc_0 dog +an-QcnhNhL4_0 person +an-mFuTYuCk_0 person +an_FRcZ669c_0 person +aoBqV2Guvso_0 person +aoDJu0KrrQs_0 motorcycle +aoOJR-0sPM0_0 person +aoSWWKtf8mU_0 person +aohLKKJxjIM_0 person +aoizdynEVYU_0 dog +aoqMoScEfqE_1 horse +aotBl0tvpFs_0 train +aotBl0tvpFs_1 train +ao9uUinn2WY_1 truck +apKAwFA4oP0_0 bird +apQKmVEucLQ_0 person +apZAEWvk8XY_0 person +apcgot45Ql0_0 person +apdP6_tCdls_0 person +apfZjUpoTy0_0 skateboard +apfZjUpoTy0_1 skateboard +apprUmnQTcI_2 cow +aqGKBg0azPA_0 cow +aqGp6tCGLOU_0 motorcycle +aqKiwfY3Oqc_6 bus +aqKiwfY3Oqc_5 bus +aqKiwfY3Oqc_7 bus +aqNz8TCica4_0 zebra +aqUHuS5ALXE_0 cow +aqWN-Q0wDHI_0 person +aqWN-Q0wDHI_1 person +aqZfqhHJPLo_0 person +aqdSuLpYlwQ_0 person +aqe_mdIg6k0_0 person +aqmie50AFwE_0 dog +aq2UMxzwliQ_0 person +aq50xKvuSFg_0 skateboard +aq59B_-6ilw_0 person +aq9Sfxn9vMg_5 knife +aq-QzG14KJ4_0 person +arFKRc7lAo0_0 person +arFKRc7lAo0_1 person +arPGoY7uh4E_0 person +arS7aqpkAU0_0 motorcycle +arT4jZLX8pg_1 knife +arW0ZUPkah8_0 person +arZ_mIhaJMo_0 cat +are5LvOB2nQ_1 skateboard +are9NykT9FM_0 truck +arn0j0l_IWI_0 person +artWKQTC7CQ_0 person +artcASpzYrU_0 person +arwZ6ZPJuN4_0 cat +ar7TRjurXMY_0 person +ar-fzXT8Juc_0 truck +asT-GJNeJok_0 person +aseOdDcbIRE_2 person +aseOdDcbIRE_0 person +aseOdDcbIRE_1 person +ashHnkqFz7g_0 bicycle +ashHnkqFz7g_3 bicycle +asl-XTE0jsE_0 person +asrDocOfGQE_0 car +asrDocOfGQE_1 car +asrDocOfGQE_3 car +asrDocOfGQE_4 car +asrDocOfGQE_5 car +asrDocOfGQE_6 car +astLiScyoaQ_0 person +asx2CkH0O6I_0 elephant +as1twjKe3Cw_0 skateboard +as6Y3-EaaCg_0 person +as6Y3-EaaCg_1 person +BrgRnN_LBGk_1 person +BrgRnN_LBGk_0 person +BrhMkJ6n-hQ_1 train +BrnBTne3NBw_0 bear +BrnBTne3NBw_1 bear +BroiAN_qtCI_0 person +BrpRmX410DU_0 person +BrrAlsmwDnk_1 person +BrrAlsmwDnk_0 person +Brrlyds8g1A_0 person +BrwABvccCWs_0 person +BrzEfM8nWCw_0 cow +Br3M-xsvXFQ_0 person +Br9CVteHFEc_0 person +BsCH_ABy0WE_0 person +BsRC5xbG6uY_0 person +BsXphFpnOxE_0 bird +BsXwLsR6dm8_0 person +Bsv8dNYzPkY_0 bear +Bs1rRAtP7bw_1 bear +Bs3BPJZMD9E_0 person +Bs94h8vMmwg_0 person +Bs_9E_Rq524_0 person +Bs_9E_Rq524_1 person +BtFwcgeJjsY_0 person +BtKVAhU1LdI_0 knife +BtKl-iqkgoY_0 cat +BtN0FlaISuY_0 person +Bt19SM8BenY_0 person +Bt41QF0ze6E_1 person +Bt7B7nkGO_4_0 truck +Bt7B7nkGO_4_1 truck +BuFYI1vYj1k_1 person +BuH65mVX5yM_0 person +BuPWtDPEJ-0_0 person +BuXvxclES0s_0 bird +Buco16wWyFA_1 motorcycle +Buco16wWyFA_2 motorcycle +Buco16wWyFA_3 motorcycle +Buco16wWyFA_0 motorcycle +BufY7NdKUlM_2 motorcycle +BufY7NdKUlM_4 motorcycle +BunvBFXoGPg_0 bus +BuqljdjPWWc_0 knife +BuqljdjPWWc_1 knife +Buumm7rgDPY_0 person +Bu0gJwoDkRw_0 cat +Bu5Bgr9asUU_0 person +Bu_HdLSyLSI_0 person +Bu_3ep-qAi0_0 person +BvEAIc3hmkk_0 motorcycle +BvHzGHjR6rk_0 person +BvLCgNWIHfA_0 person +BvLJZAhIR3A_1 truck +BvTLdUcIH5I_1 person +BvTbuvBeunI_0 airplane +BvTjf9mG5MU_0 person +BvZ8DqslB-U_1 airplane +BvZ8DqslB-U_2 airplane +BviGbtAujq0_0 truck +BvrORC4d2yg_0 train +BvrORC4d2yg_1 train +Bv4rjfW9RsM_0 dog +Bv9IXbrDYLk_0 bird +BwDccOS7_vw_0 person +BwIoxW7Ee8M_4 train +BwUYR-ZnpX8_0 horse +BwW4Fs1eTRg_0 airplane +BwW4Fs1eTRg_1 airplane +BwergWBqOOs_2 train +BwgJmjOzlRk_0 person +BwoTsoC3hvQ_3 horse +Bwo1MaJvxRs_0 person +Bwrh4q5KLVg_1 dog +BwsHsSpS0dQ_0 bird +Bw2RhmesY5g_0 person +Bw5iwcbP4eM_0 giraffe +Bw6f2OXYtSo_0 cow +BxHIRvoGZMM_0 person +BxMoEE7XwL8_0 person +BxNE34BGZ-4_0 person +BxQp3-SCUGs_0 person +BxQp3-SCUGs_1 person +BxWs9aINEEI_0 person +BxWs9aINEEI_2 person +BxWs9aINEEI_1 person +BxYdU6vB2YQ_1 motorcycle +BxaEaD7zeX4_0 person +BxhktnvjtLA_0 truck +BxmeqCev3Kw_2 boat +BxmeqCev3Kw_3 boat +Bxm3EvRZAI0_0 skateboard +BxvlWueS9vA_0 motorcycle +BxwmNnxcI7o_1 person +BxzVlf9-SLc_14 bicycle +BxzVlf9-SLc_4 bicycle +BxzVlf9-SLc_6 bicycle +BxzVlf9-SLc_8 bicycle +Bx2YQSFETcw_1 person +Bx4ELKBw9PU_0 cow +Bx4ngxnRjvM_0 motorcycle +Bx-is-dL1ko_0 person +Bx_z_4bt8O4_0 person +Bx_z_4bt8O4_1 skateboard +ByBWtiJJNqk_0 person +ByBWtiJJNqk_1 person +ByFCiUvKd4E_0 cow +ByFCiUvKd4E_1 cow +ByFCiUvKd4E_2 cow +ByJNGLp-Q1Q_0 boat +ByRne1VtDow_1 person +ByfeHjkm0NA_0 bus +ByhpLi9sRUs_4 train +ByhpLi9sRUs_5 train +ByhpLi9sRUs_0 train +Byn2Qo7ghaQ_1 person +ByvWskJDMGg_0 airplane +ByvW2VADH6w_0 motorcycle +By1cSo8DcUw_0 bicycle +By8jq7bVrkw_0 person +BzKADkfj5sM_0 cow +BzNlO4ccRRY_0 person +BzOo01dGJkw_0 person +BzT8xDTB14c_2 truck +BzWiQPw-vQc_0 person +BzX2DmrGvp0_0 train +BzeW7KdQ818_0 skateboard +BzeW7KdQ818_1 skateboard +Bzehenf5vSI_0 airplane +BzgqI8VBlSE_0 person +BzpY-JMNW4c_0 person +BzrM5QG9q2o_0 train +Bzr3gVS8SzI_1 boat +Bz5rpBZ1dzs_0 person +Bz7A9QxD1nY_0 knife +Bz9MqNlU7KM_0 person +B0AazXeFQIU_0 person +B0BXcxFMgrk_0 knife +B0EZ9LIObGc_1 motorcycle +B0FupWyYbG8_1 person +B0NJSrhuWwA_1 person +B0NJSrhuWwA_0 person +B0QFrtXczzE_0 person +B0SYog80Y78_0 person +B0WaLst2GGg_1 person +B0YrdZ7s3UY_1 person +B0YrdZ7s3UY_2 person +B0aFuZP3nYE_0 person +B0aFuZP3nYE_1 person +B01lwUoyl90_0 person +B03gLj0lJrk_0 horse +B0-L6VbxLcU_0 cat +B0-lAJ4tBN4_0 train +B0-lAJ4tBN4_1 train +B1IQyTNE7eg_0 skateboard +B1Ojfucympw_0 person +B1Ojfucympw_1 person +B1YzUGPZQWo_0 train +B1hkAet1OQI_0 person +B1isEeljBFI_0 person +B1pC6hfF_Do_0 person +B1qSE-7JgXE_0 person +B1yiSrv4Ocw_1 horse +B1zPD20nhTg_0 person +B12C84by_eA_0 person +B12C84by_eA_3 elephant +B12C84by_eA_1 person +B12C84by_eA_2 person +B12C84by_eA_4 person +B12C84by_eA_5 person +B12C84by_eA_7 person +B12C84by_eA_10 person +B12C84by_eA_11 person +B2EMVGU5pNA_4 train +B2VryVb5p54_0 horse +B2VryVb5p54_2 cow +B2V7kk7fqSc_0 person +B2X9JzMNZb0_0 person +B2ZpqEJpVX0_0 person +B2fTIk9eCNc_1 elephant +B2gJVve4I58_0 person +B2hKNbDmBtM_0 cat +B2lAxi3jIR0_0 person +B2lAxi3jIR0_1 person +B2lAxi3jIR0_2 person +B2xcdU4Qoz8_0 bicycle +B2xcdU4Qoz8_12 bicycle +B23TpirETNE_0 horse +B26AQtx7Xic_0 person +B3HZSrALQYc_0 skateboard +B3IjPORG3_w_1 bird +B3J2umsYK7E_0 person +B3QykPv8TnI_0 person +B3X5wDENAUw_0 cat +B3kTu0B4OjM_0 person +B32uNSxqzgs_0 cow +B33seWCiea4_1 person +B33seWCiea4_0 person +B4Q6pRC_mZ8_0 bicycle +B4Q6pRC_mZ8_1 bicycle +B4Srj2O1AWQ_0 cow +B4dFepwxEOU_0 person +B4iP6lAoNYo_0 person +B4jbThMFW00_0 person +B4mWkc8-_6A_0 bird +B4oO-miJ6VU_0 umbrella +B4vM2iKb8cs_0 person +B4_mRuPC7o0_0 person +B5BNEoIaQL4_0 person +B5GwJoM3aX8_0 person +B5NgN9mocgI_0 person +B5PHI2HVtuc_0 person +B5fv91yB4Gw_0 bicycle +B5qSvRpXLS8_0 cat +as7rVUFzyzg_0 skateboard +as_Rz9F3slw_0 cat +atA-Cgv2XHY_0 person +atE1O6J4Wls_0 person +atLGWZUbEuM_1 train +atMjLEIbsBI_0 cow +atxnLL4Vjuo_0 person +at2dmAEDdmg_1 person +at4pXKjEDic_0 person +at4pXKjEDic_1 person +at5edW3lMVA_0 person +auA-q9fWwn4_0 elephant +auDJ1xtxFlw_0 person +auDJ1xtxFlw_1 person +auFLAZb-gD8_4 truck +auGyhsy8iLA_0 cow +auNciV4eLVo_0 bus +auOl1mbGUlk_0 bicycle +auOo1Lg_wvU_0 dog +aubLDLbxxsk_0 person +aueT5WO4e_c_0 giraffe +aueT5WO4e_c_1 giraffe +augKp60fa5Q_1 car +auiPa0HNOEQ_0 person +auu_tYb3G1Y_0 person +auzy4oPzM5Q_0 motorcycle +avCqOSeS7WU_0 person +avC67gaD1NM_0 cat +avHbY1Q3vyw_1 elephant +avLxYBedm_c_1 elephant +avT7Q6Wibdg_0 person +avl9d-bL57Q_0 airplane +avl9d-bL57Q_1 airplane +avob12vGzmU_0 horse +avonCFmxPyg_0 person +avonCFmxPyg_1 person +avpWY3czerE_1 car +avpf9VVT6CU_0 motorcycle +avvQ5wNPiew_1 person +av475qBV4QY_0 skateboard +awC9zxAeP54_0 person +awQ1n9aQEco_0 person +awVBieSP5Zw_0 person +awVa7pqR9DU_0 horse +awfg9NsCVQ0_0 person +awjHSQ5uPi4_0 bus +awkpYVN-fJw_1 horse +awmHGFkxxlw_0 person +awwWMuOKe3c_0 person +aw059qHbVm0_0 bus +aw2lOvXUAPg_0 truck +aw5C9nQgLcA_0 person +axB1Gk85UtQ_0 person +axEK7nZ8W3I_0 person +axJZ92uWnkA_0 person +axXs2oUd4ow_0 bear +axcDoOd0G0s_0 truck +axjSgDsN6t8_0 horse +axltu5Qf6ok_0 skateboard +axn6QuPBPqA_0 person +axulii3UXSQ_1 person +axulii3UXSQ_0 person +ax4YUE-PcF8_0 airplane +ax4YUE-PcF8_2 airplane +ayD3RJIjplM_0 dog +ayRmnUb2LAI_0 airplane +ayax5k3PJMs_0 person +aybdlOdul0U_1 person +aybdlOdul0U_0 person +aydxF0r6n9s_0 person +aydxF0r6n9s_1 person +ayg0x1glF2s_2 horse +ayg0x1glF2s_0 horse +ayg0x1glF2s_1 horse +aylBB_8cv60_0 umbrella +aysqPEtZvsg_0 person +ayuF_8chcKM_0 person +aywW_Wvo49w_0 person +ayzzG8M0fzo_1 person +ay1d8NBbrl0_2 bird +ay1d8NBbrl0_3 bird +ay5RnrQple4_0 train +ay5tx1Rovwk_0 cat +ay7LLDO9Ecc_0 dog +azC7-_wC8N8_0 bus +azDn4DU7cGA_0 person +azKKcIb4Ufw_1 boat +azOInI_CMHM_0 bus +azbls7-iaEU_0 person +azbls7-iaEU_1 person +azbls7-iaEU_2 person +azfLb8VvI-4_0 person +azfLb8VvI-4_1 person +azfLb8VvI-4_2 person +azlRI_Jydpw_4 cow +azmZDijLihI_0 person +azmZDijLihI_1 person +a0FDxoXtFyM_1 airplane +a0NOwUio_n8_1 person +a0NOwUio_n8_2 person +a0NdjlW5H_U_0 cow +a0N_vetshbg_0 person +a0N_vetshbg_1 person +a0OjB7xzRx4_0 person +a0RusP9ATfw_0 person +a0dHPtoBS3U_0 person +a0hRgBpppWs_0 person +a0jpiOFS7eM_0 bear +a0oeBV6-20U_0 person +a0uoJdAwobA_0 person +a085oeXd0RE_0 person +a0-Pmmyi8js_1 person +a1ADw1megCI_1 airplane +a1Fzn7iUHO8_1 motorcycle +a1RVXQl4rlY_1 cat +a1RinDI9Hgw_2 knife +a1SaKvoO2Og_0 cow +a1U6U_pntMo_0 person +a1XDxiP1hNA_0 person +a1ctjjNUZ-4_0 dog +a1kLNA-KACs_1 bicycle +a1lQwuhicQI_0 person +a1lQwuhicQI_1 person +a14VlgxHS3M_0 person +a2AT0Xo7uLY_0 person +a2Osa5aleJ0_1 bus +a2Qp2Grx3_8_0 person +a2XMK6mjiZg_0 dog +a2XvXs2guuE_1 person +a2XvXs2guuE_0 person +a2fEq8oS3M8_0 bus +a2gYRtJhP1E_0 horse +a2gYRtJhP1E_1 horse +a2hv4szlq-Q_0 train +a2kH2_9zoWU_0 airplane +a2o_-GSpXXk_0 cat +a2qmS6AhUYk_0 motorcycle +a2vx_F1NOas_0 person +a26mRIQUPoU_0 dog +a26mRIQUPoU_1 dog +a26mRIQUPoU_2 dog +a27UC8vu1hI_1 truck +a29AS00WJrY_0 cow +a3AIwQnG0Ek_0 cow +a3FLLhQu768_0 person +a3THrQYDkqw_1 bird +a3UCtF8nZIY_1 skateboard +a3dbdHben-o_0 elephant +a3dbdHben-o_3 elephant +a3dbdHben-o_9 elephant +a3dbdHben-o_1 elephant +a3dbdHben-o_2 elephant +a3dbdHben-o_4 elephant +a3dbdHben-o_6 elephant +a3rGEI8MdMs_0 cow +a3uvEIsI1no_2 person +a32oJ0GsAYw_0 person +a35UuVw16Ks_0 person +a37D3FoqIJA_1 knife +a3-oi7T-Lw0_1 zebra +a3-tURw95Xo_2 person +a4IU4va7hp0_1 truck +a4LYVAPbEwI_0 motorcycle +a4LaeeZXIc0_2 skateboard +a4Nt5QxFqmY_1 boat +a4PwZfJZVPA_2 bear +a4arqJgXHDA_0 person +a4pR_YBd4yY_1 bicycle +a4uNoGpllg4_3 bear +a4v1ptMpyi0_0 cow +a4v1ptMpyi0_3 cow +a41TZwhyyP0_0 cow +a46BqT5Mo5I_0 cow +a5HZnFcvdyA_1 horse +a5P8pVrcSRk_0 motorcycle +a5brvs-fct0_0 person +a5tSaF5GCKE_1 cat +a5ye5BUJFlY_1 person +a5znd3aNwLk_3 bicycle +a58tMy0mhIk_0 person +a6G_DBEFdFA_0 horse +a6ZXi7Qqls0_0 person +a6fBYYEgBvs_0 dog +a6jDeIJbF7Q_0 person +a6uyjrBkkXs_0 boat +a61piN6ffE4_0 person +a67zz0CSEpk_0 person +a67zz0CSEpk_1 person +a7B81Zeqgfw_2 truck +a7HKuyv2qLQ_0 elephant +a7HKuyv2qLQ_1 elephant +a7Q6eb6feT8_0 person +a7S9rFNKVMI_7 motorcycle +a7Zr0-1LIPc_1 dog +a7hwm4TORvY_0 person +a7pC7IjO2ik_0 truck +a7peWR4xJwQ_1 cow +a7ygZsaDMis_0 person +B5_Hyk-p7kE_0 cat +B6E15pe4UR8_0 horse +B6LGwD1E9SQ_1 person +B6P8B8BO-6U_0 giraffe +B6SaDYczlDQ_1 person +B6U92N9hh6k_2 horse +B6V4xqX67OA_0 truck +B6bDVhRNw00_0 airplane +B6cEdaWTjeU_0 person +B6dBkoOhfBU_0 car +B6lU93wtaDA_1 boat +B6mP9KsnQPc_1 bear +B6mngUQtFJ4_0 cow +B6nlTJYtmws_0 cow +B6pXMjH4geU_3 boat +B6qshzfLYzs_0 person +B6x2dNbgPjM_0 cow +B6y439-imys_0 person +B6z7eCsgfM0_0 bear +B61Wf8NFvcU_0 airplane +B645r0hkdmg_0 person +B645r0hkdmg_1 person +B67FwwZfIEA_0 person +B6_IcyhOHpE_0 person +B7BjhnnQ2K4_0 person +B7GRNv2opSY_0 bird +B7MHQOUO4f8_0 umbrella +B7Z9UV6aQuM_0 bird +B7a8WkaWmH4_0 person +B7a8WkaWmH4_1 person +B7cXCz7jJKQ_0 cow +B7gX18_mDyQ_0 person +B7hmqrwe88o_1 elephant +B7hmqrwe88o_2 elephant +B7iAvi5riV8_0 motorcycle +B7nwfSMbEL8_0 cow +B7pEEUJ-J1g_1 motorcycle +B7rCxgg3F_s_0 train +B8Bp9yKWV9c_0 person +B8D4fPARFvo_0 person +B8HQglK444U_2 airplane +B8HQglK444U_0 airplane +B8HQglK444U_4 airplane +B8LGL1Tt_wg_0 person +B8MxJKDkvkE_0 person +B8eeoykmq1E_1 person +B8eeoykmq1E_2 person +B8f7NnYq5sg_0 person +B8f7NnYq5sg_1 person +B8sWL2syyA8_0 person +B8uIyRkm9YA_0 airplane +B8zGkBkQw4c_0 person +B87W__RIE-E_0 person +B8_Z7m50I_E_0 motorcycle +B9AXF91pIUs_0 airplane +B9Ed_vAN9mc_0 dog +B9Y_LrDVbg4_0 person +B9aqDsvGy5Q_0 person +B9aqDsvGy5Q_1 person +B9j233QxEuQ_0 person +B9oJSA_NJ2s_0 bicycle +B9z17FOPd5A_0 person +B99mIPKaChY_3 cow +B-CR7vl67W8_0 person +B-QiQvJcSVk_0 person +B-T1YNe09SU_4 bear +B-T1YNe09SU_3 bear +B-bDxAN93a4_0 airplane +B-dlnlRKA5s_2 airplane +B-dlnlRKA5s_7 airplane +B-tukWZbXp8_0 person +B-wJpt4zl0c_0 person +B-x2pu-ux3w_0 horse +B-z1uE4iuz4_0 truck +B-0WNs2QYPk_1 elephant +B-48lEXzIS8_0 umbrella +B-7cqxw95Ro_0 person +B_BqrY2eeCY_0 motorcycle +B_Gjc7J18qg_1 person +B_Gjc7J18qg_0 person +B_M6X41emhY_0 person +B_O8idmfoCQ_0 person +B_Tj79jaRXs_1 person +B_Tmq51dx1g_0 person +B_jGC2tlhRo_0 person +B_k6vEEPHK0_0 person +B_lEJv31TlI_1 person +B_lEJv31TlI_2 person +B_nZdcreecE_0 person +B_wWPH9kbxM_0 person +B_ylVg-TN2Q_0 skateboard +B_4Kfa8_9ms_0 person +B_4eJYakoRY_0 motorcycle +CAEqRvJLY-M_1 motorcycle +CAe1SZKZ9T0_1 car +CAq4CxCpeQE_0 cat +CA4UqnJCs58_0 motorcycle +CA9SLI7TOKQ_0 person +CBASqWyp4yk_0 person +CBJQ5dL6Df8_2 horse +CBNqNe7G-QQ_0 person +CBnYDFRfYgo_1 bus +CBqyVKttAwU_0 cow +CBtgGOzZtLQ_0 person +CBz3ZOrTAjI_0 elephant +CBz3ZOrTAjI_2 elephant +CCAsEc2oRAM_0 elephant +CCGg17i4vMU_0 person +CCHay2RSnJI_0 skateboard +CCHay2RSnJI_1 skateboard +CCLRdGNDgdc_0 cat +CCoGim--jEg_0 train +CCp6NLBil8k_0 bicycle +CCwovjgEx1k_0 person +CCwovjgEx1k_1 person +CC0aX78fQFo_0 cat +CC-qoxEyocI_0 person +CDCLLCkr87I_0 cow +CDY4TXCreQ0_0 person +CDbWYF89944_0 person +CDb6uyrYrZA_0 car +CDfjcWI7iBQ_0 boat +CDgBHxiVkFw_0 truck +CDnrG74PXbI_0 person +CDpQZEjohRc_1 cow +CDpQZEjohRc_0 cow +CDrU-q6QdEs_0 person +CD0cWR7d9yI_0 person +CD4SGfIdfSg_3 elephant +CEDTshbJOaI_0 person +CEJoHSbb4gg_0 person +CEJoHSbb4gg_1 person +CEMCCDAYzQs_0 person +CENd4xI4dnY_0 person +CETUG_G0I4k_0 cow +CETUG_G0I4k_1 cow +CETUG_G0I4k_2 cow +CEUjuyvgrB0_0 person +CEUqqi8y4sg_0 cat +CEVHrP5OzJ0_1 knife +CEafe_JTk8g_0 knife +CEqA0cqMfzg_1 cow +CEsjzJHOUBw_0 dog +CEzWiyTQOMA_0 truck +CE1gHqc8aqU_0 person +CE3KdY0X0QE_1 person +CFD0NOl12CA_1 train +CFD6d4OweGQ_3 motorcycle +CFD6d4OweGQ_1 motorcycle +CFD6d4OweGQ_2 motorcycle +CFD-UQW1aQU_1 car +CFD-UQW1aQU_2 car +CFRsGLeMJKc_0 person +CFXkKgig7Io_0 person +CFee6F2rbjc_1 bird +CFxObg2ebKQ_0 airplane +CFxObg2ebKQ_1 airplane +CF0JmXACTww_0 person +CF01UBuV76Q_0 person +CF7DZCaSqIg_0 bird +CF7DZCaSqIg_1 bird +CF7KYbTChlg_0 person +CF71f3YLQ9U_1 person +CF-cX0etaAw_1 cat +CF_NSKkrwjg_0 person +CGCNTZsml7Y_0 cow +CGQoaYTzfaU_0 train +CGQoaYTzfaU_5 train +CGQoaYTzfaU_7 train +CGgxp3ycSWs_0 elephant +CGoqd4n_qJg_0 person +CGsUTzKzV4U_1 train +CGwrXZ2fUqg_0 person +CGy0nn1MCqY_0 person +CGy0nn1MCqY_1 person +CG1sXlDy2Yg_4 horse +CG1sXlDy2Yg_5 horse +CHH1SlvOzfI_0 person +CHIVYSnFst8_1 bear +CHJFpAcH8NM_8 bicycle +CHMzSMq0ui4_0 skateboard +CHZU6sP-loU_0 person +CHZU6sP-loU_1 person +CHbhzxurZNM_1 person +CHbhzxurZNM_0 person +CHnWGkGAnos_0 person +CHo3jSv3HIA_0 train +CHwNoZ55z6c_0 cat +CH6ptLNxppU_0 person +CH8zCsamj44_0 person +CH-_pvq3am4_0 person +CIJ-q_X_y7E_0 person +CIKrCLz06-4_0 cat +CIQLvytEu6E_0 person +CIQz5we_nHI_0 person +CITgpk4GyMA_0 bear +CITgpk4GyMA_9 bear +CIV_VaLTf5c_0 motorcycle +CIc1KbOeijU_0 person +CIgzZOf3uA0_0 person +CIgzZOf3uA0_1 person +CIlb5C929mc_0 knife +CImmRnndBuo_0 person +CItr4F49wO4_0 person +CIxs-77bPrM_1 person +CI2GrLRwQR4_0 person +CI3rFXxUPtI_0 bird +CI6fYr7IJJM_0 person +CI_9TEXzQE8_0 person +CJD7b_dMrVE_0 person +CJG8ou9QuY0_0 person +CJIpdb7wZEc_0 person +CJNAMf-R_J4_0 truck +CJNj2wqp8QU_0 bear +CJOJBhvHmCE_0 person +a79_ETe4ego_0 person +a7_ixAbhsRI_0 elephant +a8MHgXPiRZU_0 person +a8as0DkifS0_0 person +a8eQTqlG-6o_0 person +a8insUA82jQ_1 dog +a8insUA82jQ_2 dog +a8insUA82jQ_3 dog +a8r9Xss8Es0_0 person +a8wT4T21reQ_0 person +a8z4RhTT02c_0 horse +a82uXl_fE7A_2 cow +a82uXl_fE7A_3 cow +a892r_pD5PM_0 person +a9FI5hfZsG0_0 boat +a9GBRb_g82o_1 bicycle +a9GBRb_g82o_2 bicycle +a9YciDJw4wo_0 dog +a9Y2Jm4-FDM_0 person +a9ZvcKL6lEg_0 person +a9fG2p2YO7k_0 bus +a9fG2p2YO7k_2 bus +a9g4dt8Lszw_0 person +a9g4dt8Lszw_1 person +a9riNB4_uhk_0 horse +a90AssqciQk_1 elephant +a90AssqciQk_2 elephant +a-EIC5v0X4o_0 dog +a-EIC5v0X4o_1 dog +a-MNXAJ2mZo_0 person +a-NocjWzZtY_2 person +a-QTXZfMMT4_0 person +a-ZWAMyDG3o_0 person +a-iJ2J3oI-A_0 person +a-lm-MyKchM_0 cow +a-s461-Ddxc_0 skateboard +a-u5tm8bZnc_0 horse +a-yRjCC5TTM_0 horse +a-1bMCU5aj8_0 motorcycle +a-8RK3OMAOo_0 skateboard +a-8RK3OMAOo_1 skateboard +a_KVzTF1RIA_0 person +a_KZ5mevNfs_0 bear +a_OkB8q7LMc_1 person +a_SryCna8Rk_0 person +a_UjbYab9UM_0 train +a_YIQ1VvpcU_0 person +a_YIQ1VvpcU_1 person +a_gLFD5d04A_0 person +a_wdiSqtOK4_0 airplane +a_xkGO87GsU_0 skateboard +a_1zKb6B-bs_0 person +a_6uxh_4kb8_0 person +a_-WUUfn_l4_0 person +a__R_Y49D54_0 person +bALr5X95BQ8_1 person +bAMbXytHB7Y_0 person +bAMbXytHB7Y_1 person +bAdtKFYWQcE_0 person +bAfpD53Vjic_0 horse +bAinSo2I3HI_0 person +bAinSo2I3HI_1 person +bAp653-8UZI_0 person +bAtWugkhW88_0 bus +bAutb-z3rvw_0 cow +bAwVg4MVWds_1 elephant +bAwVg4MVWds_0 elephant +bAwVg4MVWds_5 elephant +bAwVg4MVWds_9 elephant +bAwVg4MVWds_10 elephant +bAwVg4MVWds_11 elephant +bA2bnjEnbus_0 person +bA4v5gLC700_0 person +bA5elX54rTQ_0 cat +bA6JRlAu2yE_0 person +bA8lz4kTY-0_0 bicycle +bA8lz4kTY-0_3 bicycle +bA8lz4kTY-0_5 bicycle +bA8lz4kTY-0_6 bicycle +bA_NwRpP6Tw_0 person +bA_6OElyKFo_0 train +bBPPJNf59kQ_0 umbrella +bBT4o_qtgWU_0 person +bBgRYIPlqAQ_0 person +bBm9VYnMO9g_0 bird +bBt5A6pwnxY_0 person +bB1rIuXXQFA_1 bus +bB4Xm1LS9CI_0 dog +bB6PWM19eMo_0 person +bCB5mMgiGnk_0 person +bCRN4AZbr6o_0 train +bCbqiJ6Ales_0 person +bCuWk5NSB0k_0 person +bCuWk5NSB0k_1 person +bCuuL9wxM7E_0 person +bCuuL9wxM7E_1 person +bCvbst3iM94_0 motorcycle +bCwUgQIL5cE_0 knife +bCx54wbopXs_1 horse +bDBjT69DcT4_0 cow +bDEPo_ZJ8BY_0 truck +bDJyFQqK69A_0 person +bDOeksOYoHc_0 truck +bDOeksOYoHc_1 truck +bDOeksOYoHc_2 truck +bDOeksOYoHc_3 truck +bDO5jSIN9C4_0 person +bDZrANNzYZY_0 skateboard +bDaTeoyWI4g_0 train +bDcapf9qqwU_0 person +bDjiXPhFyUA_0 person +bDu9DwJEoHs_0 cow +bDu9DwJEoHs_1 cow +bDu9DwJEoHs_2 cow +bDxvHkJLr2M_0 bus +bD9LGwYECDw_0 cat +bD-NwifgK0w_1 skateboard +bEDI6tCMZXU_0 person +bEIh6sX-Tl4_0 person +bEKdkY9RBEY_0 person +bEM1_c0lvzs_0 bear +bEOBKFTwR2Q_0 giraffe +bETxZfOvyHY_3 bear +bEUZ0kW5UxE_1 person +bEawSJKPt-Q_0 person +bEhFibV8au4_0 person +bEqXwB3xaWk_0 person +bErIbiSkE10_0 skateboard +bEwALd1GaT4_0 bicycle +bEzk1Y4QUKs_0 bus +bE2p5KejqaA_0 person +bE54N9ho-us_0 elephant +bE9RuKWeuuo_0 person +bE--xARlZGI_1 bird +bFA9McooYzo_0 car +bFCSt5rQdmU_0 person +bFEO4MHzBto_0 person +bFIAwyZ6uuE_2 person +bFIAwyZ6uuE_0 person +bFIAwyZ6uuE_1 person +bFNUtoXNMlQ_0 bus +bFORQXIUbxA_0 person +bFXutLP--Cw_0 cow +bFXutLP--Cw_1 cow +bFXutLP--Cw_2 cow +bFXutLP--Cw_3 cow +bFYfbtcZvsM_1 horse +bFe5fer15nk_1 bus +bFm95kiEE_Q_0 bicycle +bFnZbMhDMQ8_0 person +bFrVmI5XvFw_0 person +bF2D0pMJqLQ_1 knife +bF65L0Tc9w8_0 person +bF8lUYDQNgc_0 person +bGCRyP03o54_1 skateboard +bGFqTDkSuTA_1 bird +bGMKF81Sy6c_0 person +bGcugFPOZ98_0 person +bGeFOznVAdA_0 elephant +bGmggiJ7Hrk_2 boat +bGpuuVQyMOY_0 person +bGsY4wldptk_1 horse +bGsY4wldptk_0 horse +bGyLNR-ZWRY_1 cat +bG7btkvllWc_0 skateboard +bG9Q1zv6YZ4_1 person +bG-X3irBEO0_0 person +bHALJVsPIWo_0 person +bHBuapxTSS0_0 person +bHB5zkcU4DY_0 person +bHO746jxL2Y_0 skateboard +bHP9bh7-qNQ_0 truck +bHWmtSkc1qY_0 person +bHWmtSkc1qY_1 person +bHbgFvCFkb0_0 horse +bHcNLuPTrTk_0 person +bHcbcNIxs_o_0 knife +bHdxB4LnmGY_2 motorcycle +bHdxB4LnmGY_0 motorcycle +bHdypdEXRYY_0 skateboard +bHim6VG9R7E_1 boat +bHoVPJGd7EU_1 truck +bHoVPJGd7EU_2 truck +bHoVPJGd7EU_3 truck +bHvVd9-u80E_0 person +bH5d5crxmiw_0 cat +bIFUXEvQb_4_0 truck +bIFUXEvQb_4_1 truck +bIV7YZEPqTo_0 person +bIiV4e5w280_0 person +bInwFKVbP2c_0 person +bIqcbjzOQ0Y_0 car +bIslKUiw6YQ_4 airplane +bIslKUiw6YQ_0 airplane +bIyfjvesRuY_0 boat +bIzzvd9q2po_0 cow +bI19pnS1D7Q_0 motorcycle +bI8htXUqQkI_0 cat +bJADjJacbIY_1 person +bJAxqtGR-MY_0 person +bJBnGIqBiuw_0 horse +bJDJ5yePi6M_0 person +bJITjrxz5Ns_0 person +bJI1844s-tU_0 horse +bJKrgOW0nMk_0 person +bJMS4sT7XRo_5 horse +bJMS4sT7XRo_6 horse +bJMS4sT7XRo_8 horse +bJMS4sT7XRo_9 horse +bJMS4sT7XRo_0 horse +bJMS4sT7XRo_1 horse +bJWTtXkyZHg_0 person +bJcrA1AOfI4_2 train +bJcrA1AOfI4_3 train +bJfHVvueTbo_0 person +bJh3iPv6jYc_0 cow +bJqhWaDN0hQ_1 dog +bJ0SdP6bjnQ_0 person +bJ24-WqB1xs_0 person +bJ6hIJWstDo_0 truck +bJ6-RBgHmRU_0 person +bJ8k9v22vJA_0 person +bKBLXhOMUi8_0 dog +bKCfbZIUSZI_0 person +bKCjZrT7jIY_0 truck +CJfXDO8EqQ4_0 person +CJfXDO8EqQ4_1 person +CJm40KxFN5E_1 person +CJm40KxFN5E_0 person +CJqFjtBvN9Y_0 skateboard +CJqHpmU9iSk_2 person +CJqHpmU9iSk_0 person +CJrxPkQa2GE_1 train +CJ0sXsga9bM_0 bus +CJ35smVDZW0_0 person +CJ4qgeMiaOQ_0 airplane +CJ6n8mmO1b4_0 cat +CKB_--5AbfU_0 train +CKC6BopJKyk_0 person +CKGpdOkI6P4_0 person +CKNmSha1fz0_0 person +CKQHLTDcKyk_1 bird +CKSN1SlM9ug_0 cat +CKZ1xRX4dh8_4 knife +CKcBs841bV0_0 person +CKhADB_ssaI_0 elephant +CKjQxzl__Fw_0 bicycle +CKkp1wLGtks_0 person +CKmTbQn6J9U_1 person +CKsvfQdlYfo_0 person +CKuBMM3fZ84_0 airplane +CKxmvXSrPIg_0 bicycle +CKzh_WuJFng_0 person +CK29cIxMNP0_0 person +CK39c3vr6gc_0 skateboard +CLAjvvAM-K4_0 person +CLB6UiAOkP0_1 bus +CLMUcOgZdNQ_2 cow +CLQOTITDBeo_0 person +CLXlbsB7sLY_0 person +CLdyznsISW8_2 car +CLosaFzMFeI_1 person +CLzV3TNXkFo_0 person +CL1Bt58elWc_1 person +CL1Bt58elWc_0 person +CL1z2IBwWkA_0 person +CL1z2IBwWkA_1 person +CL4fc23TpVo_0 person +CL5zmQikk-A_0 person +CMBw6j8-QzY_0 person +CMBw6j8-QzY_1 person +CMIMzbsGXk8_0 bus +CMLOYaDEQ9g_0 person +CMMGX4SFyIs_2 person +CMOEwqoxxwo_0 person +CMP-dHylUas_1 person +CMlE5HjD19w_0 truck +CMlNU8W7Lsk_0 cow +CMrJ3Hog9z4_0 elephant +CMrJ3Hog9z4_1 elephant +CMrJ3Hog9z4_2 elephant +CMsMnTwn9o8_1 truck +CMwy_JpVNwc_3 bird +CMwy_JpVNwc_1 bird +CMwy_JpVNwc_2 bird +CNDd5De0h98_0 person +CNEdjudh1lE_0 person +CNID7GMZCtU_1 horse +CNiuz-9TxDo_0 person +CNqKVUmynPk_0 airplane +CNt_itMBqgs_0 person +CNua3gOk0oM_0 bus +CNwRXN4wSAk_0 knife +CN6-VQgDfe4_0 person +CN8AktLgwN8_0 giraffe +CN8AktLgwN8_6 elephant +COAed-b3LTY_0 person +COFcQrVSFcc_0 person +COTylrR16zU_1 boat +COc8fmI9wQ4_0 horse +COh7aoqTWjY_0 elephant +COj_p56dMLI_0 motorcycle +COksm121JZ0_0 train +COxq73j4_rY_0 person +COyU6vUfxXQ_1 person +COyU6vUfxXQ_0 person +CO2cK7r8MNQ_0 person +CO33VpWw45s_0 skateboard +CO_0l5Z12kw_0 cat +CPManZ0i9vw_0 truck +CPN9sc_XrbM_0 elephant +CPOp_zZsQJk_0 cow +CPQXOFjv2LM_0 person +CPXyJXYL8yY_0 motorcycle +CPXyJXYL8yY_4 motorcycle +CPYxpWVVj_M_0 cow +CPZSesZALiI_1 cat +CPuy90LHgrc_0 bus +CP3cZfEx36E_2 bear +CP3u7XjYteQ_1 person +CP3u7XjYteQ_0 person +CQEjDKzTc3Y_2 person +CQE_vEzLzMQ_0 person +CQPAMu_3qwY_0 bear +CQUUCXr0Idg_0 person +CQU9LkJ1PlA_0 person +CQU9LkJ1PlA_1 person +CQbUivUBlJ8_1 bear +CQbUivUBlJ8_3 bear +CQihoSP1KLM_0 person +CQite5jXihw_2 person +CQlL5sCIaM4_2 train +CQlL5sCIaM4_0 train +CQlL5sCIaM4_1 train +CQmCFDEszdc_0 cat +CQyxRGB9-_o_1 elephant +CQzQkumb_iw_0 person +CQ0hdku_Mu0_3 elephant +CQ0hdku_Mu0_4 elephant +CQ0hdku_Mu0_6 elephant +CQ0hdku_Mu0_8 elephant +CQ0hdku_Mu0_11 elephant +CQ2pa82Muc4_0 person +CRGhEOLOPLw_0 bus +CRHfpplogUY_2 car +CRHfpplogUY_1 car +CRPfcUOT10Q_0 train +CRQ8kzUgpGE_0 cat +CRS3P9ePDug_8 train +CRS3P9ePDug_0 train +CRS3P9ePDug_4 train +CRS3P9ePDug_7 train +CRS3P9ePDug_9 train +CRS3P9ePDug_1 train +CRYLa0UnCJY_0 dog +CRZQQc-7Cr4_0 person +CRZQQc-7Cr4_1 person +CRcL9sc8Z_Q_0 person +CRihNgUldQg_0 person +CRpG5Auclh4_0 train +CRscoQhOT24_0 elephant +CRteSMMhdfo_1 person +CR2Qbth78ug_0 person +CR7gNMR7aFk_0 person +CSBnYbN-fwQ_0 person +CSBnYbN-fwQ_1 person +CSCN35ZL4gk_0 person +CSCmLaLpgec_1 train +CSGkGWkJnIo_0 person +CSKOzx-8MRM_0 person +CSKhQtYbLiY_0 person +CSTEfDaVq_w_3 horse +CSgIyZrF2Xw_6 bear +CShE1WLp4V4_0 person +CSlYtyS3ekI_0 cat +CStjlkpuH8I_0 knife +CSwiprmAnWk_0 person +CS4LhFaTdRc_1 person +CS4TVHuh-OI_1 person +CS4TVHuh-OI_0 person +CTBCSXpoCNw_0 knife +CTGjM7vaWkc_0 car +CTNN0vCWthk_0 cow +CTOTTFDvM9g_0 elephant +CTOTTFDvM9g_1 elephant +CTpK5Ywqj4E_0 person +CTtActqncZs_1 person +CTtActqncZs_0 person +CTty0Fesx4k_1 elephant +CTty0Fesx4k_2 elephant +CT6O84zfmoY_0 person +CT8VKdB074U_0 dog +CUB_Y4U0gNU_0 person +CUE1Oj2b7oo_0 person +CUIv9zU0_7M_2 dog +CUQZtS7SlyM_0 truck +CUVQtlpfthI_0 person +CUVqn-7LP_k_0 cat +CUjEVN0BT58_0 person +CUjbAz30mdA_0 person +CUvi-gOiEak_0 airplane +CUvi-gOiEak_1 airplane +CUzrNlKejnA_0 person +CU-5HeXnZag_0 person +CU_cxu2KrzY_1 cow +CU_4MsJSWGw_0 horse +CVCPdF3TevY_0 car +CVJEcVS63rM_0 person +CVJu9kpxa0o_0 skateboard +CVQq3Lnsmb8_0 skateboard +CVRQkAzvHOI_0 cat +CVXbWRarjGI_3 bicycle +CVa-tmxG3G8_0 bus +CVfXcK9LvU4_0 cat +CVnQzQjIfdo_0 person +CVnQzQjIfdo_1 person +CVtUo7t1tg4_0 knife +CVtdQUWrMFo_0 person +CV1gdpxyUvQ_0 umbrella +CV7yBA-RY-s_0 person +CV9Mv-Z5ywo_1 knife +CV9_qaQ3bOc_0 dog +CWNPg3hbbCc_0 person +CWRUw47fnHQ_0 dog +CWcpGIObSb4_0 person +CWcpGIObSb4_1 person +CWhtecFS3Ps_0 person +CWh66yU69HI_1 person +CWq2nbpnjkw_0 person +CWsgkyp-Wv8_1 person +CWsgkyp-Wv8_0 person +CWu6nT2qW2Q_0 person +CWydCxGJyck_0 cat +CW0GVWegie4_0 person +CXEi_k33z08_0 person +CXF-MNV21Uw_1 person +CXF-MNV21Uw_2 person +CXF-MNV21Uw_0 person +bKIEzYSD9LU_0 bird +bKM4LmiXX5k_3 knife +bKM4LmiXX5k_0 knife +bKQQdBiIraA_0 dog +bKT6s25xsS4_0 person +bKh8FyKvOq8_0 umbrella +bKic74m-XKg_0 horse +bKnsY1ytgqc_0 person +bK0HzQHKqhg_0 motorcycle +bK0HzQHKqhg_1 motorcycle +bK0IN2qoSjQ_1 person +bK7Wo0UxDyQ_0 person +bLBmIVS2T-0_0 person +bLLFtAMqoF0_0 person +bLOW53I2oWw_0 knife +bLU0G55kWgs_0 car +bLU0G55kWgs_1 car +bLYGpYiiF7Q_0 person +bLg0SdwRkKc_0 person +bLneVyHWwdk_0 person +bLoyRVgQcTk_0 cat +bLoyRVgQcTk_1 cat +bLoyRVgQcTk_2 cat +bLs4dUFZzcQ_0 person +bLs4dUFZzcQ_1 person +bMEbcFBdRsA_0 airplane +bMM1OZMZ_WY_0 person +bMNzE6F4WK4_0 truck +bMPPnTHvu8c_1 cow +bMQlfzj9vCE_0 person +bMZPcnVc1K0_0 person +bMakr2vwfqQ_0 person +bMdfLBSo6jw_0 bicycle +bMfQw6tBALo_0 cow +bMgWjlwilqA_0 bicycle +bMk8JyTyvUo_0 skateboard +bMojajeogfY_0 person +bMphaUsZuqU_2 elephant +bMrDB2JI0QM_0 elephant +bMuSXdxvaWY_0 bicycle +bMumJTM0f28_0 person +bM3OcevX9F4_0 person +bM6fRimkPZg_0 cow +bM6peJ4lQyU_0 elephant +bNGoGllCEj0_0 car +bNGoGllCEj0_1 car +bNJ5ygVB-GI_0 person +bNPtMp-AuhY_5 train +bNPtMp-AuhY_4 train +bNR89JLsh7Q_0 motorcycle +bNZe9vwuE8E_0 car +bNcTCIgwqNY_0 boat +bNinDD5s0LQ_0 person +bNo2RseLYYs_0 person +bNqXgNLQX3s_0 person +bNtivYIWtQE_0 person +bNtivYIWtQE_1 person +bNtivYIWtQE_2 person +bNyyHqBZnmQ_0 airplane +bN4vggzwxWI_0 person +bN-epcJfRJ8_0 person +bOPvxhSlnZI_0 truck +bORQv_d22gA_0 bear +bOTYFfq_264_0 person +bOXM6ibmbG0_0 truck +bOarvmUMdLs_0 person +bOarvmUMdLs_1 person +bOb4k6pTF-k_0 motorcycle +bOeUzXPOIWw_0 motorcycle +bOfrPHjROWI_0 dog +bOm9Qgnl2KI_1 umbrella +bOor15z5M5Y_1 truck +bOuuxRt7ugE_0 bear +bOwOVcqeajs_1 boat +bPAO0nyCO8Y_2 cow +bPLKx5uJaZY_0 bear +bPTTPAsH7v8_0 airplane +bPZdC3oRr1c_0 dog +bPanGwtU82U_0 airplane +bPavgNJxZnI_0 horse +bPavgNJxZnI_4 horse +bPcXQrlHs60_0 zebra +bPddyJH2fm4_0 cow +bPeFwxV66_s_1 cow +bPfaS8RIHVw_1 train +bPjZsDes9ck_0 bird +bPvvA8Wm5Ts_0 person +bPw91vtx0rY_0 dog +bP17881jyH4_0 elephant +bP17881jyH4_2 elephant +bP17881jyH4_1 elephant +bP6QvQUfZSI_0 person +bP7ZU4wl_xs_1 person +bP7lN2WyBTg_2 bird +bP7lN2WyBTg_0 bird +bP7pux4nQa4_0 person +bQJQKEfdctc_1 person +bQKuVB3YmRI_1 knife +bQNLK-43XKM_0 person +bQNXrSVq4r4_0 person +bQQS-amRhxU_0 person +bQQr8FzMTHE_0 person +bQR6KxB4qjg_1 train +bQWO4r5DLWY_7 bicycle +bQWO4r5DLWY_8 bicycle +bQZ8WQ2mS9o_0 horse +bQd1k1RNZZA_0 person +bQwDt3XOok0_1 skateboard +bQy9W_tIPJg_0 cat +bQ7FEMZ309U_0 bicycle +bRElYolSzbI_2 horse +bRKfUmz_7hE_0 bicycle +bRKfUmz_7hE_5 bicycle +bRP4TElBetA_0 skateboard +bRUtCCY00Yw_0 person +bRd_NGjRFpU_0 cow +bRgNc063rsk_0 person +bRgNc063rsk_1 person +bRiVaIWzo4k_0 person +bRiVaIWzo4k_1 person +bRpbblTb1VU_1 person +bRq06zdCv4k_0 dog +bRsjD1GTjeE_0 truck +bRuSrTOibGY_0 skateboard +bRw2PFlL8l8_0 cat +bRxyuZTXkWo_0 person +bR61bP65wdI_0 person +bR_EeaX8Kns_0 cat +bSC7MwTZ0Og_0 person +bSJbBDA3-rI_0 person +bSJbBDA3-rI_1 person +bSSSYoS7HhY_2 person +bSSX8qJnGak_0 person +bSVCTx_L7lU_0 person +bSbZuDkimC8_1 cow +bScFgdC-DH8_0 motorcycle +bSkEsUu7aBI_0 cat +bSqX5D_GrEc_0 person +bS4mTtP-Ud4_0 person +bS4mTtP-Ud4_1 person +bTAxiISsPNE_0 cow +bTHRXr-yw54_0 person +bTOZp15gd24_0 airplane +bTOZp15gd24_1 airplane +bTOZp15gd24_2 airplane +bTO9Pid9808_1 cow +bThFysASYJg_0 person +bThX-5t7OWM_3 bus +bTl-dt761p8_2 bird +bTp1hk4dhPE_0 person +bTuho6CpJpg_0 horse +bT7mzx9P1Yo_6 bird +bT7mzx9P1Yo_8 bird +bUDYPhSFyyw_0 airplane +bUFCsL247kY_1 person +bUFCsL247kY_0 person +bUIov_O62GU_0 train +bUVi7VVygmM_0 person +bUa61WY6E38_1 person +bUu6iW_nRvM_0 person +bU8cBepgoMY_4 elephant +bU8cBepgoMY_1 elephant +bU8cBepgoMY_3 elephant +bU8r7rNDaHQ_0 motorcycle +bU8r7rNDaHQ_1 motorcycle +bVCLNxl4PQY_0 person +bVPgCZmg1CY_0 person +bVTzUiTPtww_0 person +bVZixqlT1AI_0 person +bVbT4F3I0s4_0 person +bVbdO8rj6TQ_0 person +bVbdO8rj6TQ_1 person +bVdjQbIzOGc_0 horse +bVgKe0-_228_0 bear +bVkYqw1YJ6c_0 person +bVnmeQsd3xk_1 car +bVph6GZ3jLE_0 skateboard +bVrck_XYsR8_0 bicycle +bVtMukuPx9A_0 motorcycle +bVtWuhD1L1s_0 car +bVvVMOxHOT4_0 cat +bVwWkzYdrvk_0 person +bVw9txmBeX0_0 person +bVz-pHuWNfc_0 person +bV3UXbGCshc_3 elephant +bV3UXbGCshc_4 elephant +bV3UXbGCshc_0 elephant +bV3UXbGCshc_2 elephant +bV8k_w0cphI_0 person +bV9tUYWi-9o_0 truck +bV9tUYWi-9o_1 truck +bWCW4QZTIXE_0 person +bWCxObc3uVo_0 person +bWEnwFThRlA_0 person +bWEtMBeQQCA_0 bus +bWEw8rNQ-kI_0 person +bWJg9jatoBY_0 person +bWLcKJauKIs_0 person +bWO4NBx37Vk_4 airplane +bWdWgIB371Y_0 person +bWdWgIB371Y_1 person +bWkKy-_YzW8_0 umbrella +bWotjBNgmiA_1 motorcycle +bWotjBNgmiA_2 motorcycle +bWo4CzHWaZ8_0 dog +bWqayCqhqVQ_0 person +bWtXkAzA6zE_0 person +bWtXkAzA6zE_1 person +bW1JoZnZpXs_0 bicycle +bW1JoZnZpXs_2 bicycle +bW2I1hUiWgg_1 bear +bW2I1hUiWgg_3 bear +bW2I1hUiWgg_2 bear +bW6PJACBEFo_0 boat +bW6PJACBEFo_1 boat +bW7x14tLsxU_0 cow +bW7x14tLsxU_1 cow +bXGa-FIGViQ_0 truck +CXOKkaurfXo_0 person +CXVmfrDfalE_0 person +CXVyHpmc_fU_1 cat +CXXWvUVLBBE_1 train +CXXWvUVLBBE_3 train +CXaF0E3wEzI_4 boat +CXaF0E3wEzI_1 boat +CXaF0E3wEzI_2 boat +CXdGDPRtlo4_1 cat +CXdjIo4q-w4_0 dog +CXoeLQPShqU_3 horse +CXoeLQPShqU_0 horse +CXrwHki5ShI_0 person +CXw5HMRQwEk_7 bear +CXxPPuZcT2k_0 knife +CXyujV2S5aE_0 person +CX1US3Y-2jI_0 person +CX5Y01eJ_g0_0 knife +CX838M4iPkw_1 bear +CX_YxpWurRk_0 person +CYEtgx1uVTM_0 train +CYEtgx1uVTM_1 train +CYFtiy8FtgM_0 person +CYGBUw8HZ8Q_0 person +CYKbj5BgaiI_0 person +CYPFpTJXCp8_1 person +CYXd3muNlJ8_0 person +CYcxxdqG02k_0 person +CYcxxdqG02k_1 person +CYghFhQySik_1 person +CYghFhQySik_2 person +CYghFhQySik_0 person +CYg8fy66poA_0 train +CYjEASXRoys_0 person +CYkow-sm2pA_0 person +CYmpj4UFFtA_0 cow +CYsgb4GhJ_0_1 cat +CYtehjvIIIE_0 cat +CYw9ONxIi0M_4 bear +CY3-VTI7lQU_1 cow +CY48729zIgM_0 bus +CZAt34OJpoI_0 elephant +CZGoAqWEDQM_1 horse +CZJz6zZt3cE_0 person +CZXHqexGqfI_0 cow +CZduQndn_Eg_0 train +CZfMxEFk9hc_0 motorcycle +CZfe1GuZxPI_1 person +CZws8sfLA8M_0 person +CZ8bjG4wdZU_0 person +CZ9MT7tZZ2E_0 knife +CZ-Kodbg_2A_0 bus +CaA-PFuqaXw_0 truck +CaFlo5YQHXw_0 train +Cag3vCKRh6c_0 bicycle +CajF9IxbOvI_0 person +CajF9IxbOvI_1 person +Cam_wHie6XQ_1 person +Ca4_dI-Ii8o_0 person +Ca5GzZ-rifE_2 horse +Ca5GzZ-rifE_0 horse +Ca5GzZ-rifE_3 horse +Ca5mOzqFz70_2 bear +Ca6g367yxss_3 dog +Ca9JsTGifmQ_1 knife +Ca-l5zpgIL0_0 horse +Ca-wDaXxSn8_0 train +Ca_LwXljv5I_2 dog +CbBrv9GkBDM_0 person +CbKVR2EGoWU_0 cat +CbO4r5w5NEM_0 cat +CbTbpHHYfGo_1 cow +CbYQk8GFQwY_0 person +CbYXzAv9G40_0 person +CbZA75LYWsk_0 boat +CbZA75LYWsk_4 boat +CbZA75LYWsk_7 boat +CbZA75LYWsk_8 boat +CbZA75LYWsk_6 boat +CbbsxxHKQBs_1 bicycle +CbbsxxHKQBs_3 bicycle +CbfML92fBFc_0 person +CbrOGI6D5oo_0 dog +Cbz0hgvZtyM_0 person +Cb0EbSTABAw_0 person +Cb31aGVbcGE_0 person +CcJ-51mUw00_0 person +CcNfpk8tVxA_2 person +CcNfpk8tVxA_0 person +CcNfpk8tVxA_1 person +CcadL-XHA8w_0 person +CccC-FK79hM_0 skateboard +CceETksmvEc_0 bus +CcfAKl1kCRM_0 person +Ccl3EZzzNhc_2 bird +Ccl3EZzzNhc_3 bird +CcmiWGPbuT4_0 car +CcyRYeSG3sQ_0 truck +Ccyqd4ZzDtQ_0 person +Cc5DUip1-eE_0 person +Cc9-Kd--ejs_0 car +CdA-Gg7O6d4_0 person +CdD0W0pS7gk_0 skateboard +CdG8sd9UZFM_1 elephant +CdG8sd9UZFM_3 elephant +CdOwMZqCiMs_0 bird +CdRgo9V_e_U_0 person +CdTDo40rdz4_3 umbrella +CdVnK1TcGcQ_0 knife +CdW2qTShGbY_2 person +CdW2qTShGbY_1 person +CdYkEASWMqQ_0 person +CddXUsFqg4Q_10 bicycle +CddXUsFqg4Q_12 bicycle +CdeUORbvfgs_0 person +CdkbBdQwTX0_0 person +CdmrCOVxj8c_0 person +CdosWRXaOgY_0 person +CdtY-oTmACc_0 elephant +Cd3qxnZC6s4_0 airplane +Cd8dfcT-D9U_0 horse +Cd8zY0wsrLc_0 umbrella +Cd_ZgXZ7qKw_0 person +Cd_ZgXZ7qKw_1 person +CeCnRUGvs9Q_1 horse +CeEMUoHNeVA_0 person +CeICmGeQXOk_0 motorcycle +CeICmGeQXOk_1 motorcycle +CeVjsWpfoCY_0 person +CekBpSMLr08_0 horse +CetmVa_LV2A_0 bird +Cetw-N1I1bA_0 dog +Cew6y9K7ynI_0 cat +CezGmkW4sRY_0 person +Ce1tW6uV_lw_0 person +Ce1tW6uV_lw_1 person +Ce_dgPawIkU_0 person +CfC--i0DQ-o_0 car +CfThv8Vk-oM_0 umbrella +CfbzDUZ6PyQ_0 truck +CfqtCB_f_Z8_3 skateboard +Cfwk3niR9Uc_0 motorcycle +CfyvbbrxquI_0 cat +Cf_GVLLQaTA_0 person +CgB0fwUOZd4_2 bus +CgDcN1Lk7ag_0 car +CgDcN1Lk7ag_1 car +CgDcN1Lk7ag_2 car +CgDyrbc-LLo_0 person +CgHCCqADKys_0 person +CgQl21vwrqk_0 person +CgQv6o97KqY_0 person +CglmlO92nKA_0 person +CglmlO92nKA_1 person +Cgod2p17L48_0 person +CgwHXWDGAak_1 person +Cgzt1Kv6Sqg_0 cow +Cg9H20lr5Uk_0 person +Cg9H20lr5Uk_1 person +Cg9H20lr5Uk_2 person +ChBKKPEO8N0_0 person +ChOKPIVr5XE_2 bicycle +ChPBGkSbJ0g_0 elephant +ChRNCk9Bq-k_0 cat +ChZB3vAX8sk_0 person +Chc7poZ9r-k_3 skateboard +ChmcE3Lz1Vc_0 person +Ch2_CQg4r1o_0 person +Ch-PosNzqZ8_4 elephant +Ch-PosNzqZ8_0 elephant +CiCqdFq_a7U_1 person +CiCqdFq_a7U_0 person +CiLbnwjSJ9w_0 person +CiQOmR8VCzs_0 person +CiQOmR8VCzs_1 person +CiQS0RMaLZQ_0 truck +CiT09gfBJPA_1 person +CiVwjoLvdAs_1 horse +CiWhBWV1zGM_0 cow +CiWhBWV1zGM_1 cow +CiYOn9VW1eY_0 horse +CihCAad2Duo_0 person +CilRWTfS8e4_0 person +CiwaaMNfvCo_0 airplane +Ci0S27Qp1w4_0 cat +Ci2vW1OGHe0_0 cat +Ci6mTJ6BqYI_0 person +CjJ3l2smqAc_0 person +CjMaorKuwf0_1 horse +CjRX9J2BM4Y_0 skateboard +CjUf3D9IsCQ_0 person +Cje7Ip85T1I_0 person +Cjm9Wky44TM_0 elephant +Cjm9Wky44TM_1 elephant +Cjn-mt97y-w_0 person +Cjq3dda3PlA_1 person +Cjq3dda3PlA_0 person +Cjw2f0M_eB8_0 bird +Cj1CpXDG_Qw_0 person +Cj3PTZcRbd4_0 person +Cj3ZEx4SDe4_0 cow +Cj-a9t9yiiA_0 person +Cj-a9t9yiiA_1 person +CkBGaJnF9vo_0 person +CkC43WVctnk_0 cat +CkKQhDP2FGY_1 person +CkKQhDP2FGY_0 person +CkKQhDP2FGY_2 person +CkLE-s6CsgY_0 cow +CkLwgOIBF_I_0 person +CkLwgOIBF_I_1 person +CkP_70u-2zU_1 boat +CkX8laawskQ_2 horse +CkZeki9RVDI_0 person +CkZhHtevDk8_0 person +CknHFY05prw_0 person +CkoK8C4Rzj0_0 person +CkvEr5T38Wc_0 person +CkvEr5T38Wc_1 person +CkvEr5T38Wc_2 person +CkyU5jU74Js_1 dog +CkyU5jU74Js_0 dog +Ck8GRgUrpoE_0 person +ClBCXl7l2pw_0 skateboard +ClH2-R5LeVo_0 cat +ClLZcmIHrTw_0 person +ClM3Ftm0S7o_0 cow +ClRLFlpMUhU_1 horse +ClSzHW4AuJ0_0 person +ClV1oHNuF9o_0 person +ClV6A8WNCvw_0 cow +bXcKQNGRBvw_3 airplane +bXcKQNGRBvw_0 airplane +bXcKQNGRBvw_1 airplane +bXcKQNGRBvw_2 airplane +bXjVvJ8eOJc_0 skateboard +bXkjwotai0Y_0 bicycle +bXnvGCFA9Dg_0 person +bX9TcejzzTM_0 person +bYCvd_BTMsk_0 dog +bYE-vUOh10s_0 boat +bYN8lkupLt4_0 bird +bYQiCAwebzs_1 bicycle +bYSbuWYiixQ_0 person +bYVgzwF1hNw_0 bicycle +bYWGnwi8nDQ_0 motorcycle +bYm9aUK2zzk_0 person +bYpG750b7pE_0 motorcycle +bYvzSXZ0w_I_1 person +bYwwOO6vMAw_0 person +bYwwOO6vMAw_1 person +bYyFEbIGMfo_1 dog +bY3sDu5BZDI_0 elephant +bY3sDu5BZDI_1 elephant +bY3sDu5BZDI_2 elephant +bY6vPIaJDGA_0 person +bY8BdyCsCAw_0 person +bZL41d9eFyc_0 cow +bZRpdnJtcT4_0 train +bZRpdnJtcT4_2 train +bZVMygQQgNg_0 person +bZVZbn0oTjo_1 giraffe +bZdq8Rk75M8_0 knife +bZgZihlL0IU_0 person +bZsoMlw4CnI_2 bus +bZuOWV67gnY_0 cat +bZwJl6ye9Cc_0 motorcycle +bZwJl6ye9Cc_1 motorcycle +bZzzlD0C8Jg_0 train +bZ2u1x38Qbg_1 airplane +bZ6gk6FLGss_0 person +baDesUZ9Pyc_0 bear +baRyXrRn_ls_1 motorcycle +baWLnj87FOc_0 cat +babQ3FBdeqQ_0 cow +bagbzsb-tg4_0 person +ba1hwKdPRx8_0 cow +ba3cGHmc_OA_0 person +ba5407XQYAQ_0 cow +bbHdRyrdpDA_0 boat +bbH4CQx07Go_2 knife +bbLW6902ITg_0 person +bbLW6902ITg_1 person +bbLW6902ITg_3 person +bbLW6902ITg_4 person +bbM0SbH_pgk_2 bear +bbZAdo3awRs_0 car +bbZeVbzmLVw_0 elephant +bbaUzB0Na2o_0 person +bbfDHSIT9ys_0 person +bbhyEgEjfvQ_0 cow +bbjuucY5QQc_0 person +bbkjnF0iGrs_0 horse +bbkjnF0iGrs_2 horse +bbkjnF0iGrs_3 horse +bbkjnF0iGrs_6 horse +bbnb-beW0p0_0 horse +bb0DRm0ueKk_0 horse +bb4sgALviyc_0 bear +bb5OO1wMKr8_0 person +bcJ1MAj_A_w_1 person +bcLW7YqnUGs_0 skateboard +bcdQmV1-Z5k_0 motorcycle +bcgTPCycRIw_0 skateboard +bcksTLjC1fs_0 motorcycle +bcrQdxrU_vI_0 person +bc1C8HrNVqE_0 horse +bc28CjoKODI_0 person +bc28CjoKODI_1 person +bc3rySF6iao_0 person +bc6jeLN-DUo_0 train +bdU9JALjnmw_0 person +bdYKw4SpkQQ_0 zebra +bdZpXHSW4Ps_0 cat +bdbVAdua3uI_0 airplane +bdbVAdua3uI_1 airplane +bdcoNmelRw4_1 dog +bdcoNmelRw4_2 dog +bdcwT2ufUBg_0 bird +bddes6RyfCI_0 skateboard +bddes6RyfCI_1 skateboard +bdeoe5gmCd4_0 elephant +bdeoe5gmCd4_2 elephant +bdgSMIY2A8Q_0 horse +bdoNsiMM1RY_0 bird +bdwlZMpXPJo_8 bird +bdwlZMpXPJo_7 bird +bd--DVCeT-s_0 cow +beE5VOzxibM_0 giraffe +beLTv9YiY78_0 dog +beLTv9YiY78_1 dog +beLTv9YiY78_2 dog +beQOHdCA8KM_16 elephant +beQOHdCA8KM_3 elephant +beQOHdCA8KM_6 elephant +beQOHdCA8KM_7 elephant +beQOHdCA8KM_10 elephant +beQOHdCA8KM_12 elephant +beSTl1azmTY_1 skateboard +beVVM2pBQdA_0 cow +beVVM2pBQdA_1 cow +becTICXjrg4_0 person +beliMXc3JE8_0 train +besXR1P9Oew_0 car +beu-edT1daM_0 person +be9BCy6kHvY_2 person +be9CXLatX9I_0 horse +be-ggiVD4V0_0 knife +be-5ARU_aHA_0 person +be_IhYef3hE_0 person +bfBZLLwpNWA_0 giraffe +bfJaD1qZ2gE_0 bus +bfJaD1qZ2gE_3 bus +bfJtapJ86Gw_0 person +bfRgL9oanEc_1 person +bfRgL9oanEc_0 person +bfS8FB_HOlY_0 person +bfZfMA1mLrQ_0 dog +bfZfMA1mLrQ_1 dog +bfaMdaYiK90_0 cat +bffC89pE6fo_0 person +bffC89pE6fo_1 person +bfkNVFr6Cwg_0 cow +bfkNVFr6Cwg_1 cow +bflVgDgAHSo_0 umbrella +bfrY2wEePwY_0 person +bfrY2wEePwY_2 person +bfwWF0XO7bE_0 boat +bf9YySHJcdQ_0 person +bgAOYaooc18_0 person +bgAo5vgwe2M_0 zebra +bgBK4sMnLig_0 cow +bgBK4sMnLig_1 cow +bgC-r6p-XHU_2 elephant +bgE_uy3Ml6g_1 umbrella +bgHMLwWY4Qo_0 person +bgV-FqQ8Tv8_0 umbrella +bgXZ3BpIOh8_0 train +bgaD7K2iEPI_0 person +bgbS11O9lSw_0 bus +bgelX1blhpQ_0 truck +bglPgA_0LAk_0 motorcycle +bgpB-A04RLI_0 person +bgyEHsMav4U_0 person +bhBMa8wQ5KA_0 bird +bhGJ9gZmP90_0 person +bhGJ9gZmP90_1 person +bhH_pqCQ3Co_0 cow +bhJGFbgXlts_1 person +bhNfsUPLKDg_1 train +bhWmpmnXSlc_0 person +bhZZubkX8_o_1 bird +bhdtzsUvieg_1 person +bhqr680CLr0_0 person +bhrOzwB-7qA_0 person +bhsCCw1J_JU_0 person +bhuOX61sk8M_0 person +bhz6HG2KpnI_0 skateboard +bh0ZZ4Z76cc_0 person +bh3QacG9JYk_0 airplane +bh3QacG9JYk_1 airplane +bh3QacG9JYk_2 airplane +bh8aMNVny8s_1 truck +biAdsjypETI_0 knife +biFm-y7gSrc_0 horse +biGJ8vHOsZM_0 umbrella +biLY6NMsqJU_0 cat +biUFB3c0Ucc_0 bus +biZU5SOHQvc_0 umbrella +bibJ3Bv5YmQ_0 motorcycle +bik9GuCughc_1 bird +biuEbYnn68k_0 bus +biwbqbVsZeE_1 elephant +biyu3sxIOYc_0 person +bi1kYvu5Irg_0 train +bi1kYvu5Irg_1 train +bi3GSUnfzd8_0 person +bi5Bkz2MVP4_0 bird +bi5Bkz2MVP4_3 bird +bi6BNwvsR_0_0 person +bi-GKlUZMR8_0 motorcycle +bjBwCQ5z4IQ_0 cat +bjH2OQR68Vc_0 person +bjRQ69TaeKs_2 person +bjgooTfy3JM_0 train +bjgooTfy3JM_1 train +bjgooTfy3JM_2 train +bjhEqucWULo_0 cow +bjq8de0pw5M_0 person +bjq8de0pw5M_1 person +bjrq_Kj-wSU_0 airplane +bjrq_Kj-wSU_1 airplane +bjrq_Kj-wSU_2 airplane +bjrq_Kj-wSU_3 airplane +bjwdTl5zyaI_0 skateboard +bjx96uw-Q24_0 person +bj-Grf4s790_0 elephant +bkElaSUqJjM_0 train +bkIBcqXKARI_0 person +bkMU7xViDvA_0 person +bkXBjOrn2yI_0 person +bkggwniG4vc_0 person +bkiQTbQF_TA_0 elephant +bkigtjV1zA0_1 motorcycle +bklheVvsfac_0 truck +bkoOiNz6Zmo_0 person +bkok3wr4188_0 person +bk2l-O9wSEc_0 person +bk8UlOzFy7U_1 person +blAiGXbJxmI_0 train +blIpNvBakFI_0 person +blW8z3TPVvo_0 motorcycle +blhCjXE5cRo_0 person +bli5Z83QY_U_0 person +blnFzQdaVRc_0 person +bluU1CAbJfo_0 person +blubKbt8mLE_0 car +bluqyqDv2eE_0 car +blv0QslQ524_5 bus +blv0QslQ524_6 bus +blzDAgvxJMw_0 person +bl1XJCtyP2E_0 truck +bl2xZSpcZqs_0 cat +bl6wIjxfuJo_1 bicycle +bl6wIjxfuJo_2 bicycle +CloG2hcM5nU_9 bicycle +CloLHr7NJqg_0 person +CloOQkTkYfY_0 bus +ClpDLu1qCx4_2 person +ClpDLu1qCx4_3 person +ClpDLu1qCx4_1 person +ClvAi34e1zM_1 elephant +Cl1mEpQ3wy4_0 boat +Cl1mEpQ3wy4_1 boat +CmEoz728tlo_2 bear +CmGSMnkcvrg_1 train +CmIXZuJDwt0_0 person +CmNv_yKt5oM_0 person +CmOIqZyQpPI_3 bird +CmOIqZyQpPI_1 bird +CmVoggJ6fxY_1 horse +CmYL2EyELbA_0 elephant +CmezWT8A2i8_0 bus +CmjUCOwcOT8_4 bicycle +CmjUCOwcOT8_11 bicycle +CmjjEuS9_Ww_0 bicycle +Cmjw8kbfDCw_1 knife +CmoknpL1cMA_0 person +CmqXoT7CXJs_0 dog +Cmq1qVX-Ugo_1 cat +CmsqpFOcosw_0 person +CmtmoydPH08_0 cow +CmxhIEztsyg_1 skateboard +Cm1y7USHcrg_0 person +Cm3tYZlSc0o_0 skateboard +CnBJ9TMTRAA_0 person +CnBJ9TMTRAA_1 person +CnCTVtsK5Kw_2 bear +CnEXHgq3AE4_2 elephant +CnGp9Wq2rTs_0 bear +CniS9Q6Y200_0 person +Cn0UKsWocEI_0 elephant +Cn0UKsWocEI_1 elephant +Cn1dXZ_p3dw_1 person +Cn9Bj5B29UI_0 motorcycle +CoBuNWx_OwM_0 person +CoDB7ZeilsQ_0 person +CoKMowfrd5Q_2 truck +CoKMowfrd5Q_3 truck +CoKVaYX3c1k_0 person +CoKVaYX3c1k_1 person +CoKVaYX3c1k_2 person +CoOwm7ccDrs_0 truck +CoSIyrW5lvA_1 skateboard +CoSSvI2-U_w_1 bicycle +CoZY8o0c-h8_0 elephant +CoZY8o0c-h8_1 elephant +CocSNWws-Qo_0 person +CodelARKQ10_0 skateboard +CosYvoW04Uk_0 person +Cot7Xj8C308_0 boat +Coz9g_0N91c_0 person +Co_XBpd6lxE_0 person +CpDHwc5JmK8_3 elephant +CpFiT_6KvM4_0 person +CpF-80dM2aY_0 person +CpF-80dM2aY_1 person +CpxxxHYsJy8_0 person +Cp0lT2opaL0_1 person +CqANE5ByBvY_0 person +CqDjHjvw8T0_0 elephant +CqDjHjvw8T0_1 elephant +CqVeLNnA0vk_0 horse +CqZz9FnLLjk_0 knife +Cqkhrld_7LU_0 person +CqzahbOVzO4_0 person +Cq02-pFNn6w_0 motorcycle +Cq02-pFNn6w_1 motorcycle +Cq4KAVAWq7g_0 person +CrAxPJajbcs_0 airplane +CrCNqDd18fw_0 umbrella +CrUmEDCjFtU_0 person +CrUmEDCjFtU_1 person +CraDHWuN4Q0_0 person +CrgMhrCYmOo_2 motorcycle +CriTKYemGmo_0 person +CrmzwYKpLAY_0 umbrella +Crn24ZKAP1k_0 person +CrsjxpJoY5Q_0 person +Cru8KBJqhng_0 person +Crz3l2CEDzA_0 person +Cr0SWcS1qX0_0 cow +Cr_B3I0QPEQ_6 airplane +CsM_GTD0TZE_0 person +CsPLGd2dgl0_1 airplane +CsTntmE8EWs_0 person +Csa542XNEXo_0 person +CsfkuwD6-nA_0 person +Csh_4yR8bFk_1 truck +Csh_4yR8bFk_2 truck +Csii4vkefsM_0 boat +Csii4vkefsM_2 boat +Csw3kLrhjoM_0 person +Cs38JY7Gqjo_3 skateboard +Cs-Vx_ym23o_1 bicycle +CtC2yC9NGTk_0 bird +CtD4wnIU0Pw_0 bicycle +CtF9IxfLhaQ_1 person +CtF9IxfLhaQ_2 person +CtF9IxfLhaQ_0 person +CtHIoS1lGKA_0 person +CtLVK2j48gA_0 person +CtO5dmTdzYQ_0 person +CtPEAoFPnE4_0 person +CtQPPKpIEIc_0 person +CtTcyoZvRvU_2 skateboard +CtUPPSKU8cE_0 bus +CtVUqIFqqr8_2 bus +CtYDJRkhtpg_1 umbrella +CtYDJRkhtpg_5 umbrella +CtfPPnpBKHs_2 bird +CtipU0GHAEo_1 elephant +CtjTAe-FFe4_3 elephant +Ctkjh9fntpQ_0 bird +Ctkjh9fntpQ_4 bird +Ctkjh9fntpQ_5 bird +Ctkjh9fntpQ_2 bird +Ctkjh9fntpQ_3 bird +Ctnjw80kgcw_0 person +CtxK3wGlqx0_2 motorcycle +Ct1QrXUgBGg_0 person +Ct1QrXUgBGg_1 person +Ct8S9nC7sfk_1 person +Ct870xrnBGU_0 person +CuDfCpgoIjg_6 boat +CuGfRQMwYd8_0 cat +CuHF9Hd0uwI_0 person +CuIkNejeZrY_0 cat +CuUJUrjEcc4_0 person +CuWdZPYMLww_0 person +CvDW2A8hD78_0 person +CvRJwKt7FfY_1 skateboard +CvVVS4SUiuw_1 train +CvZaA28QUK4_1 knife +CvajmAL3sjQ_0 person +Cvda-hutmbg_0 dog +Cvqylkq9fwI_0 truck +CvxsoaCV1_8_0 person +CvzsX_s6tek_0 person +Cv2T8U0uQcQ_2 person +CwAdBrBzIcA_0 truck +CwBiMh4zHWQ_0 person +CwFcmrnz1yw_0 elephant +CwFcmrnz1yw_1 elephant +CwFcmrnz1yw_2 elephant +CwR2tJptu0Y_2 motorcycle +CwVLRawns04_0 person +CwVTSONqnVw_6 knife +CwnHi50fuuQ_0 person +CwnHi50fuuQ_1 person +Cw22-zpE1UY_0 person +Cw3iLs4yV4g_0 person +CxFRYsUCyWc_0 cat +CxH8vGqLVM0_0 bicycle +CxH8vGqLVM0_1 bicycle +CxH8vGqLVM0_3 bicycle +CxH8vGqLVM0_6 bicycle +CxJ7Uww1mSk_0 elephant +CxN5CG94Q5Q_1 airplane +CxN-YEErXFg_0 train +CxPyIeBtRec_2 truck +CxWaiU0rF9g_1 cow +CxWaiU0rF9g_0 cow +CxXdw0Cqr4Y_2 airplane +Cxa8q3QXoRs_0 person +CxgqklOxSfo_0 airplane +CxgqklOxSfo_2 airplane +CxnCTBBNWCY_0 person +CxnCTBBNWCY_1 person +CxoZT0--IBo_0 person +CxooWldim98_0 person +Cxs-xZDDZWw_0 person +Cxug83tjWyc_0 horse +CxzJV_HYpAc_0 airplane +CxzJV_HYpAc_1 airplane +Cx0XeFKQ06o_1 train +Cx7ZY8oqOmE_10 bicycle +Cx7ZY8oqOmE_6 bicycle +Cx7ZY8oqOmE_8 bicycle +Cx9efnltcUY_0 person +CyE1kuECzfg_0 person +CyH0woBc0zU_0 boat +CyI7nyp65bI_0 person +CyI7nyp65bI_1 person +CyLLTzV_lAg_0 cat +CyOXSqLm7ao_1 person +Cyb4-vF1WMM_0 airplane +Cyedl__okwE_0 person +Cyedl__okwE_1 person +CynfaDsQ1AI_0 zebra +CysFfEkdDT4_0 bear +CytiPd_Wbkg_0 airplane +CytiPd_Wbkg_1 airplane +CyvInNqvQyE_0 truck +Cy002CigJRQ_0 person +Cy_hvqOd0RY_0 knife +CzFRG22Jmvs_0 cow +CzHeIzQZUEg_0 person +CzNFSb4N6p8_0 person +CzQ03Z7Dv5U_2 skateboard +CzQ03Z7Dv5U_3 skateboard +CzQ03Z7Dv5U_6 skateboard +Cza2-_wwpd4_0 person +Cza2-_wwpd4_1 person +CzcwXF0Z1TQ_0 cow +Czt8McI8UTE_0 person +Czze2Jy6Ook_0 cat +C0Tk6QryTA0_0 bus +C0Tk6QryTA0_1 bus +C0a9pkujXQg_1 person +C0lvs-UEqKs_0 person +C0pOQ36uosU_0 person +C0pOQ36uosU_1 person +C0qbh7OJTHI_2 skateboard +C0tGKqnFyZA_0 person +C0xTDmlUYSA_0 person +C0xZYHsXNws_0 person +C0xZYHsXNws_1 person +C0xjvq51pVA_0 horse +C0xl46ieUxg_0 skateboard +C0zUOQoeQrA_0 person +C0zrmcMf8D4_0 bird +C05P4mCw-xA_0 bear +C1DCcNlUQDk_0 boat +C1DX9TjKTrE_0 bus +C1MfcNYih9c_1 person +C1RCXQFjvvc_1 person +C1RCXQFjvvc_0 person +C1bdSMUVy2Q_1 truck +C1bdSMUVy2Q_0 truck +C16ZlJRDfUc_0 bird +C16_rFYBwUA_0 person +C17jwrOnSCI_0 horse +C19rR4b8CSQ_0 dog +C1_gk-bIL6Y_0 airplane +C1_tauCAYjs_0 person +C2GvHXU8mIc_0 person +C2HZBTrCAf8_0 horse +C2Hcs2itPTc_1 elephant +C2H_P7MX3zw_0 bus +C2H_P7MX3zw_1 bus +C2IJYHPWHJM_1 cow +C2K7zu49SKw_0 person +C2K7zu49SKw_1 person +C2LdkQMjxJk_0 cow +C2ROFMcXam4_0 cat +C2S4CV9mnC0_0 truck +C2VjZHe3ID8_0 person +C2r9VGslxTE_0 person +C2v7hcs3Ax0_0 zebra +C2zRn25TBOo_1 airplane +C2zRn25TBOo_2 airplane +C2zRn25TBOo_4 airplane +C2zRn25TBOo_6 airplane +C23ZGYnWhgo_0 person +C26HiGgIjYg_0 person +C2-glFtt9Vw_0 umbrella +C3LbuiUjzvo_0 cat +C3LbuiUjzvo_1 cat +C3LbuiUjzvo_2 cat +C3Qu-KUydyg_1 cow +C3UX9hrlLeE_0 person +C3YcvZKgCgY_0 person +C3terpXzPm4_0 person +C3z1zbkmwdU_0 bird +C30B6KXg9vs_0 person +C3399zrSQ6A_0 horse +C34_EkCWJaU_0 motorcycle +C4HzsadhLW0_0 boat +C4QHknuNLYI_0 person +C4RAj-omUMo_0 person +C4W_g9eheB8_0 skateboard +C4XGGPoj4q8_0 person +C4dV8SPq6Mk_0 person +C4e-5QS1FmU_0 umbrella +C4e-5QS1FmU_1 umbrella +C4irKghQYTE_0 horse +C4jghf6KKYI_0 skateboard +C4vFHmzTY-s_0 cat +C4xJ3_Wrrn4_0 train +C4yVuAqcr0U_0 train +C409K0fAxiM_0 person +C42397qio9c_1 skateboard +C4317zxtzKA_0 person +C4-k1XW5O3U_0 dog +C5DAyL_gEQU_0 cow +C5GJx1VFRm8_2 cow +C5HT9La1jDY_0 person +C5JobuZa590_0 skateboard +C5MJ8fSfmLw_2 bear +C5dPwnswp8Q_0 cat +C5jo-fCBqmA_0 person +C5jo-fCBqmA_1 person +C5jo-fCBqmA_2 person +C5pop0SvnOM_0 person +C5r41vkLsKE_0 person +C5sXGZRLfmU_4 truck +C5sXGZRLfmU_6 truck +C5umaWklWFQ_0 boat +C5ybfGh51LM_0 cat +C55z9Fe6H7A_0 dog +C56Bp4toMG8_0 person +C6NYuB7zIzs_0 person +C6NYuB7zIzs_1 person +C6XCgppHkHA_0 bus +C6Yy8uEd0bQ_0 person +C6aB6M0DHrU_0 person +C6cOmWIisxU_0 person +C6eN6sMtuXY_1 boat +C6gNbZUU7xg_0 person +C6ia-W4TV1U_0 horse +C6nHtSy67OY_0 cow +C6n6ECY5h84_0 cow +C6qWzx58kxo_0 elephant +C6qWzx58kxo_2 elephant +C6rqmPvlIlI_0 person +C6upTeuDG4E_1 skateboard +C6xv6Wmy97M_0 horse +C62nD-_VXpM_0 horse +C62nD-_VXpM_1 horse +C66OM90TFXI_0 train +C66OM90TFXI_1 train +C66z-I_UHqQ_0 airplane +C6_p7BXwCTA_0 elephant +C7CB2A_bxa0_0 person +C7COsB9pcOQ_0 person +C7CXGBdoJWo_0 cat +C7KZnM_0j8s_0 person +C7QYoT22ZYo_0 train +C7W0oxkg-nU_0 bicycle +C7kKR6pqYzw_0 horse +C7to6tRsC9U_0 person +C72k6hv1NPM_1 cow +C72k6hv1NPM_0 cow +C7-sqpILAXM_0 person +C7-sqpILAXM_1 person +C7_HhvBNDSw_0 person +C8ETc2K6ef0_0 train +C8G_kcqjspU_0 knife +C8IE7aLZvIA_0 person +C8IUB4Opf44_0 person +C8IUB4Opf44_1 person +C8PqOHn0izQ_6 bird +C8Zex-ptYyk_0 person +C8daRmtyPo0_0 person +C8fcFW4HKGs_0 airplane +C8mEWe-TWYs_0 knife +C8n1dTEDWvk_0 skateboard +C8ukXeoRjbI_0 cow +C9Zq_rDHwgg_1 cow +C9dD6oS_Zs0_0 person +C9je005HOlA_0 bus +C9jqFBMRyPs_1 person +C9vG5qPPhzE_1 train +C9wgqGACPso_2 elephant +C95TX0IOPa8_0 skateboard +C97oHqKqdBk_0 person +C97t3TGT2oc_0 person +C-AoVBwcBUw_0 person +C-FX5hgFDd0_2 person +C-Q9RDsPyOw_0 person +C-Q9RDsPyOw_1 person +C-S34-Drg7M_0 cow +C-TWHpbtVNY_1 person +C-WsGZQoLx0_0 boat +C-cL2hzThKI_3 airplane +C-cL2hzThKI_6 airplane +C-omy9mzD7E_0 person +C-q9nO8X1rs_0 person +C-seg-BCK0U_0 bird +C-v3Ttrvuo8_0 airplane +C-38hraIyOs_0 person +C-47EdafspI_1 airplane +C-54wttM4AA_0 person +C-9LBJqCMm0_0 train +C-_ebeJtjyE_0 person +C_BX3dg-lc4_0 person +C_DOGAVETwk_1 bird +C_EMJm-Z2I8_1 bird +C_EMJm-Z2I8_2 bird +C_EwPB6zgIA_0 person +C_EwPB6zgIA_1 person +C_GnC_IEwJM_0 person +C_GnC_IEwJM_1 person +C_HBU7EUsoE_1 person +C_HBU7EUsoE_0 person +C_IjqR1NOxw_0 person +C_POS7ndKw0_0 truck +C_PXq5TsPRQ_1 train +C_TfufSsuEU_1 person +C_VePcGhr10_0 knife +C_aP0fKyudQ_0 horse +C_aYcFttRC8_1 person +C_aYcFttRC8_0 person +C_cUky_0p2Q_0 cow +C_uGdKk79X0_1 person +C_ykabkQ2U0_2 person +C_2EFIuyDSA_0 person +C_2p_N8Kvpk_0 person +DAJkfl5W8Vc_0 horse +DANymtBuoIs_0 dog +DAOBGjTf7xI_0 person +DAQ9-YTrpp0_0 cat +DAU6UNdxbRI_0 person +DAn4fH-1Ucs_0 person +DApkEgrJX0Q_0 person +DAqHnZA6tBQ_0 truck +DAtSTeTmg8I_1 horse +DAwdyKiZyzM_0 person +DA1bsx2RsGA_0 person +DA1bsx2RsGA_1 person +DA4LF3u2VTI_0 car +DA5X-ADHM1w_0 person +DBFMXaS9LRg_1 umbrella +DBLaZSSthxo_0 person +DBR0l2rW6Ew_0 horse +DBVbRonJkb8_0 person +DBaAVcI4Ftw_0 person +DBaAVcI4Ftw_1 person +DBmVOTuCJ8Q_0 person +DBvOm1qnWrA_0 cow +DBySPDEqsO8_0 person +DB1Cvyyike0_0 airplane +DB3lsf7fD84_0 dog +DB6TJh9r1Dw_0 person +DCE8Dg_ycjo_0 truck +DCHv6sxfCAs_0 person +DCPk1uyVNlU_0 person +bmHyfvCZWsg_0 elephant +bmHyfvCZWsg_2 elephant +bmHyfvCZWsg_3 elephant +bmLLdC88ohM_0 train +bmMB6Mr1uKI_1 person +bmPhh5NpV7U_0 person +bmQbHpw-4fY_1 bird +bmUFMo3pjyo_1 airplane +bmhSkbKIg0U_0 cow +bmhSkbKIg0U_2 cow +bmhSkbKIg0U_1 cow +bmhfPSKCY8I_1 dog +bmqPIwMWGj4_0 person +bmuIwo4T6rk_0 cow +bmvh7yxyWcY_1 horse +bm2eU4uLgQE_0 skateboard +bm8MRDfmerA_2 person +bm8MRDfmerA_0 person +bnOUoCjxIvA_0 bird +bnWQnn3a2xE_0 cat +bnZwZd6xdHY_0 person +bnc1LyPUCLg_0 train +bnfN43NoRbA_0 person +bnqbJR2oSPk_1 person +bnqbJR2oSPk_0 person +bnsuTEBQy44_0 person +bnw6G0Prvc0_0 bus +bnyALwWqo4Y_3 cow +bn8epY7auRE_1 person +bn8epY7auRE_0 person +bn9y-iIDoUU_0 person +bn9y-iIDoUU_1 person +boHeJDDjRf4_1 person +boIKCyPzxr8_0 bicycle +boNYwNYmh1E_0 cat +boVVWwoXNDw_0 truck +boZ6xZrNpzc_0 person +boadjC5Lci8_0 person +bocql7vYA4o_0 bus +boja3N4XQVo_0 person +borBr_AiOmM_0 person +bornws-twE0_4 airplane +bosTHwpZ8Ao_1 dog +bo7P3hYkeog_0 person +bo9sUjViaHQ_0 person +bo-qyHCKssw_0 bird +bo-qyHCKssw_4 bird +bpI4nUgSqbE_2 person +bpI4nUgSqbE_0 person +bpI4nUgSqbE_1 person +bpJNbivFLKE_0 skateboard +bpdgYRz5hPs_0 person +bpiM4FHf540_0 person +bpjVhXyB4M0_0 airplane +bpjVhXyB4M0_2 airplane +bpsMni7yj3M_0 truck +bps3HXPsekI_0 bear +bpu9NYWxcEE_0 skateboard +bpyH8PRkBQM_0 person +bp1zW8j_ajo_3 bus +bp26IdTs4XE_0 person +bp3rDJju8n4_0 person +bp3xwI_FfOI_0 elephant +bp6K7EUtORo_0 cow +bqBtysMz94c_0 person +bqEmBkEnR1c_0 person +bqGkchWbZYE_0 car +bqJcZwUB1Go_0 person +bqPKigpT9AY_0 person +bqQk37pcpVA_0 person +bqaeUBH6J3Y_0 person +bqhQG8t_2XA_0 person +bqjcNzWyaC4_1 airplane +bqoG__OO_5g_0 person +bquLxAXnaww_0 truck +bqwFWjwCZas_0 truck +bq6n9q-Qpv8_0 person +bq6870eY1a8_7 bicycle +brDq8RFzVTo_1 truck +brIIDuCmk-E_0 person +brLbzZeRz1o_0 person +brLeJHMfMXQ_0 horse +brNR68fKeMk_0 bus +brWg7FAeBEA_0 person +brZj8bv9oxY_1 person +brhA4NqjrgQ_0 horse +brh4hrmrs0Y_1 skateboard +brpbaoTNe4s_4 bicycle +brpbaoTNe4s_0 bicycle +br3e--6oH8Y_0 airplane +bsGmFJGua4w_0 elephant +bsR9KXIHlCM_0 umbrella +bsVBX8u9pW8_0 bus +bsXpGvnXpmk_0 cow +bsa-G_HEllM_0 person +bsbzpk_ejJk_0 person +bsbzpk_ejJk_1 person +bsgdfqE8ySk_0 person +bspbqjb3wAg_0 person +bsv_swJ9_KY_0 knife +bs2FVeXKiYQ_0 person +bs3u00S0eu0_0 person +btI7FYFXsfI_0 person +btL1Ptjq7pM_0 motorcycle +btMmnZdL_uQ_0 person +btO34shZMZo_0 horse +btSyjckocDA_0 person +btVQJbFp8Dw_0 cow +btdt4lysW6U_0 dog +btihrVidTTg_0 cat +btk27mnJY_A_1 person +btrdQ6N7QJc_0 truck +btrdQ6N7QJc_1 truck +btsT4XRF0nI_2 cat +btul_U3BMKI_0 bus +btvg47tz3Ps_1 person +btvg47tz3Ps_0 person +btz7EwI5rYY_0 person +bt75khQG0w8_1 bird +buFiFNHj41w_0 person +buOqwfPnqkI_0 cow +buRfiT3Mq6Q_0 bear +buSgd-PrRmA_0 elephant +buSgd-PrRmA_2 elephant +buSgd-PrRmA_6 elephant +buSgd-PrRmA_8 elephant +buWf8ffXWTs_0 person +bue8SUcqigE_0 cat +bugTv6zkE0Q_0 person +buh8d20UxNw_1 airplane +bulc7gZ_YQY_0 boat +buqR3s7EZeQ_0 person +buq0_IIvQqc_0 person +busJdrzEeJU_0 truck +buyJwHRaSYc_0 person +buyJwHRaSYc_1 person +buzd3FYmwQQ_0 bus +bu6QE_qf8fw_0 skateboard +bvLQLfRAI9s_0 person +bvW_ZJYSOLg_0 person +bva98_iD8pI_0 person +bvc6dUfKFpM_0 skateboard +bvg-QHsENSc_0 umbrella +bvnuyMz5Pk4_1 person +bvnuyMz5Pk4_0 person +bvqPJIDHXHI_0 person +bvqPJIDHXHI_1 person +bvwJ75OkrTk_0 person +bvwJ75OkrTk_1 person +bvwwPOK7lN8_0 skateboard +bvw4raRDAys_0 person +bvxAWBUG1zk_0 dog +bv6ASjMljew_2 person +bv6ASjMljew_0 person +bv6ASjMljew_1 person +bv7NOTxSDhg_0 person +bv7lroHoMyE_0 person +bv8CHN4kwyM_0 person +bv9J7oplKjY_1 bird +bv-ps8hofSY_0 person +bv_rrakMnsY_0 elephant +bwB-cfh8UFY_0 cat +bwIBXBulTRg_0 person +bwM3RKdZAd0_1 airplane +bwM3RKdZAd0_2 airplane +bwSSE1XeKkg_0 person +bwSSE1XeKkg_1 person +bwTJKRhesM4_0 person +bwZEDD10b44_0 person +bwd7bbxG4Kw_1 person +bwjUOg-CI1E_0 horse +bwotbTZHoPA_0 horse +bwotbTZHoPA_1 horse +bwv4Q2VqV5A_0 bus +bwv4Q2VqV5A_3 bus +bwwud6bxEeY_3 elephant +bw1HepCVmL8_0 person +bw3c96BQrRU_0 car +bw3c96BQrRU_1 car +bw96DHOgI1I_0 airplane +bw_opOTzI6k_0 dog +bxRX_05rH9Y_0 bus +bxXWi1nvXjI_1 bird +bxYeOYlqDPc_0 cow +bxaC_opt7IU_0 truck +bxjIDI2ZkO4_0 cat +bxnu-AITJt4_0 person +bxoclb4AFb8_0 person +bxsI00qOi6c_0 person +bx0h8tvY6kw_0 person +bx6BVBAcBtM_0 person +bx6BVBAcBtM_1 person +bx7PtvZe6O8_1 airplane +bx7-RzWnIe4_1 truck +byDPGQJdn1s_0 person +byQIRt1JF9I_2 dog +byQIRt1JF9I_0 dog +byQIRt1JF9I_1 dog +bycJD4U6rIs_0 bird +byehVoG0_eg_0 person +bye0FepI8wg_0 bird +byi-4Qx3vx4_0 person +bykN9ap_QTw_0 bird +byvddKaL_kw_0 person +DCRIRGz2xhc_0 person +DCRIRGz2xhc_1 person +DCUcxHDfYiE_1 cow +DCUvhnZnRGQ_0 horse +DCXrBMEdS4E_1 person +DCrv8CyK9zM_0 bus +DCx698xXxjs_0 person +DC0PPRyXlD4_0 person +DC4ZTdVoj2o_0 boat +DC5fRZmUZV8_1 airplane +DC8lKdla6rE_0 person +DC8lKdla6rE_1 person +DC_Kd2iaw9U_0 person +DDZILIDFFXc_0 elephant +DDd8CfnxkYM_0 person +DDgtm9B7Yj0_0 train +DDhlugZ-vro_0 person +DDhlugZ-vro_1 person +DDjUzAM4mLE_0 bus +DDjUzAM4mLE_1 bus +DDjUzAM4mLE_2 bus +DDjUzAM4mLE_4 bus +DDoBBLQQ1Mg_0 train +DDtWIKexWpM_0 skateboard +DDw2iF2W4HI_0 bird +DD4YGjlBsHc_0 boat +DD844YVVMXE_6 bicycle +DD844YVVMXE_0 bicycle +DD844YVVMXE_1 bicycle +DD844YVVMXE_3 bicycle +DD844YVVMXE_4 bicycle +DD844YVVMXE_5 bicycle +DEHHjz2xiz4_0 person +DEI-qJD08Pc_0 person +DELUfY3m37k_0 person +DEVUyfQt_G0_0 cow +DEVUyfQt_G0_3 cow +DEVUyfQt_G0_1 cow +DEXhh5rt_24_0 motorcycle +DEXhh5rt_24_1 motorcycle +DEZHoMWiFBQ_1 person +DEau5L3A9S0_0 person +DEjPKQLASJg_0 umbrella +DEtj0Fb-Jbo_0 skateboard +DEuYWYNXbw4_0 truck +DE3kl7rbakE_0 skateboard +DE6z5oB-0vo_0 elephant +DFBlkKPYtl0_1 cow +DFBlkKPYtl0_0 cow +DFI7_dtUb0U_1 giraffe +DFI7_dtUb0U_3 giraffe +DFRmdyjR_Dc_0 giraffe +DFb4KWUX31Y_0 person +DFpZ6f1iWT4_0 person +DFwPVEPK4-Y_0 cat +DFzgqOHlnAk_0 person +DGC_pivLAEE_0 person +DGMfSMlhL4w_4 elephant +DGMfSMlhL4w_6 elephant +DGMfSMlhL4w_13 elephant +DGMfSMlhL4w_17 elephant +DGM9CDF3ks8_2 motorcycle +DGM9CDF3ks8_0 motorcycle +DGM9CDF3ks8_1 motorcycle +DGbZYKPp7XI_0 person +DGc9VSWQUyQ_2 person +DGc9VSWQUyQ_1 person +DGp5vBVf28g_0 person +DGsQAjKXPBw_0 cat +DGs0ZHnAtkg_1 person +DGs0ZHnAtkg_0 person +DGvsndSWlBw_0 elephant +DGx5aC4h8wg_0 horse +DGygUuHcJhs_0 person +DGygUuHcJhs_1 person +DG8TJBoerZ0_1 person +DG8TJBoerZ0_0 person +DG93jIsco3E_0 person +DG93jIsco3E_1 person +DHB_RgHOHdo_0 umbrella +DHB_RgHOHdo_1 umbrella +DHLK8xDGwL0_2 knife +DHLg5KzzoOM_2 cow +DHLg5KzzoOM_0 cow +DHPWnuYI2qA_0 person +DHSGQLguGZ4_0 truck +DHdFVfp7SvM_1 horse +DHl_QoiyZ2I_1 person +DHl_QoiyZ2I_2 person +DHl_QoiyZ2I_0 person +DHqrGwHgnAA_0 person +DHr77uGYi-g_0 dog +DHsorh6ngMI_0 umbrella +DHs1KtWx2n4_0 person +DH0OVsYB2vs_0 person +DH5nSZZ6uJE_0 umbrella +DH_wEdP1Glk_2 train +DIFEQ3rorSw_0 person +DILtO1oyoCY_0 person +DIOuJC_mv_k_0 person +DIO8l6DAJX0_0 person +DIO8l6DAJX0_1 person +DIP8d1YC6vM_0 person +DISU2i6bJqs_0 cow +DIaTXSXAfJM_1 person +DIaTXSXAfJM_0 person +DIpJyhb8gzw_3 motorcycle +DI7rj5AAYEE_0 elephant +DI801ysby74_0 knife +DJD4Xlf0eNg_0 person +DJKFzJe6KAk_1 skateboard +DJKokwprK90_2 skateboard +DJLSHLPE0po_0 person +DJQ8goQ4xyo_0 person +DJV-ft_10HY_1 person +DJjjrdYts2s_0 elephant +DJ4oQ03HqyE_0 bicycle +DKBIz_MLIpw_2 knife +DKC58UBq-0w_1 airplane +DKEmSml-t4c_1 person +DKEmSml-t4c_0 person +DKHCjzNZE3U_0 elephant +DKHCjzNZE3U_4 elephant +DKICHseWnGQ_0 person +DKJ3As_9Mlw_0 person +DKKsGGUWero_0 person +DKLxBVm3HHk_0 airplane +DKMUARFnh2Q_0 person +DKShwn6Xk8w_0 cat +DKZ21QA0lBM_1 person +DKcpPg_tEUU_0 skateboard +DKj3fFeAaL8_0 person +DKq7d2C6gOI_0 motorcycle +DKxIadOj4D0_0 horse +DKyckH3XY8Y_0 bicycle +DKydJWySeUw_0 car +DLKE31mt2Qc_0 bird +DLLrkv1aF-k_0 train +DLMDzB4XBPg_0 person +DLPmEX5pwY0_0 cow +DLT57E3vm98_2 truck +DLct7_2tyWI_0 person +DLd6kxxgSUM_0 person +DLkx4w5oteM_0 person +DLmCj6q5vD0_0 person +DL3V2mhMX7M_0 skateboard +DL3eQSTbZ9Y_0 skateboard +DMB6Mr7lTSI_0 person +DMEXGsc-PaU_0 person +DMFEU87_IrU_2 boat +DMR4kX1M_zk_2 elephant +DMR4kX1M_zk_1 elephant +DMTP7OyjdJ4_4 bus +DMT_n1VJG80_2 bird +DMbwyGKLF4c_0 person +DMb-AjUXKe8_0 giraffe +DMiFC67o2P0_1 horse +DMiFC67o2P0_2 horse +DMiFC67o2P0_3 horse +DMn1JpU6MBE_0 person +DMn-kaSNd5Q_0 person +DMuLn7wJTcc_0 person +DM7c57qvjgs_0 person +DNAMMWkSfLY_11 umbrella +DNAjFU24eK8_0 boat +DNB4bgEP-8Y_0 person +DNGlLqzJF6Q_0 person +DNGlLqzJF6Q_1 person +DNOZeC0gZzs_0 truck +DNXuVh_X_qY_1 person +DNXuVh_X_qY_0 person +DNhOrRaOe2M_0 person +DNul7ILzxkQ_0 person +DNul7ILzxkQ_1 person +DN0xWDfCAM0_0 motorcycle +DN1ujoUaAKU_0 person +DN1ujoUaAKU_1 person +DN4TuB3csDg_0 person +DN4e8ljPm1g_0 bicycle +DN5mGCGzOOY_0 person +DN7FitWe9k8_0 person +DN8yb60bxNc_0 person +DOAU-JodN0U_1 airplane +DOAmtFxCuKA_1 person +DODU9JghuAA_0 cow +DORauVZJhAU_1 person +DORauVZJhAU_0 person +DOhLqHOLbQY_0 person +DOiUy3AGiKw_0 person +DOiUy3AGiKw_2 person +DOoTpSSHVho_0 truck +DOoTpSSHVho_1 truck +DOsVwDV787M_0 bus +DOuULWa1RKM_0 person +DOvC_-Yrn5k_0 cat +DPAEt1AqwbQ_1 car +DPCyQOQdLHE_0 cat +DPFO_O_f3hc_0 cow +DPIm8x0i2yo_0 motorcycle +DPJ7ZSWY2Qs_0 skateboard +DPXJpAVtRfM_0 train +DPXJpAVtRfM_1 train +DPZi4DZaTmk_0 person +DPZi4DZaTmk_1 person +DPelBJ73uaU_0 bicycle +DPo9M61p8gI_0 umbrella +DPvxwOvedrQ_1 knife +DPz3CG4lD2Q_5 truck +DPz3CG4lD2Q_6 truck +DP2q1TrqjAE_0 person +DP2q1TrqjAE_1 person +DP6ZB5PxNfc_0 person +DP-JZPR9HFc_2 elephant +DQDV1Wr7qo8_0 bear +DQOglBZHFCs_0 bear +DQZiSQmMBnc_0 bird +DQcCfbTKP1s_1 person +DQcCfbTKP1s_2 person +DQcCfbTKP1s_0 person +bywgcqNg6RU_2 car +by7PLb7MqM0_0 motorcycle +by_OJvQqlKE_0 person +bzKVRbSQpZE_0 knife +bzLdvZQAWgA_0 person +bzO5MBTTrdQ_0 person +bzRELZo9WMU_2 dog +bzRELZo9WMU_0 dog +bzZgsynjAGk_0 cow +bzfE3U02_44_1 person +bzfE3U02_44_0 person +bzimWzymgu0_0 person +bzquVP0NUms_2 truck +bz5Ht4jyT0k_0 bus +bz66OedbeoI_0 person +b0C_2T7-IfU_0 cat +b0GlXXGkfRQ_0 person +b0GlXXGkfRQ_1 person +b0HXAfyZ7Sk_1 person +b0Q3EfK70fg_2 airplane +b0Q3EfK70fg_4 airplane +b0Q3EfK70fg_5 airplane +b0Q3EfK70fg_6 airplane +b0a7ewqE8S4_0 dog +b0nOQfZSaUo_0 person +b0nt17hBmDw_0 boat +b0qXUUs3-WE_1 person +b0t8uuynzIM_0 train +b0xQRq8njAI_0 cat +b0z1nalEX08_0 truck +b0-UOt-DT1A_0 person +b1ETK4nP9ag_0 dog +b1EnXvOZQbQ_0 truck +b1Gd5IWJBRI_0 person +b1R3uk0VLc4_0 person +b1SyeZsSk80_5 elephant +b1SyeZsSk80_3 elephant +b1UAPTD4s74_0 person +b1UpjRRBrTw_0 cat +b1cpAYk99_U_0 person +b1cpAYk99_U_2 person +b1cpAYk99_U_3 person +b17OiOMReIs_0 person +b1-WFxZ7Lcs_0 truck +b2DqNP9s4t0_0 person +b2Tm_7DUimQ_0 person +b2Y6KLIX5vE_1 motorcycle +b2Y6KLIX5vE_0 motorcycle +b2azzMxEH84_0 motorcycle +b2fq5Ba1L8M_0 person +b2fsE3wZfWM_1 person +b2m2gaVpjNE_0 person +b2qNS9qjYbE_1 person +b2tlrwd_LIg_0 person +b28pEbOSeUs_0 dog +b2_dSc2NxNI_0 person +b3KP0d-WX38_0 bicycle +b3KP0d-WX38_1 bicycle +b3KP0d-WX38_2 bicycle +b3R6fHlRZu4_1 bicycle +b3R6fHlRZu4_3 bicycle +b3R6fHlRZu4_4 bicycle +b3SsKosfjOA_0 train +b3SsKosfjOA_1 train +b3SsKosfjOA_2 train +b3UOZHA5jRI_0 cat +b3Z1Ay2o1zQ_0 knife +b3bkNCYQbwc_0 cow +b3p-fFVYM4E_2 train +b3p-fFVYM4E_4 train +b3p-fFVYM4E_6 train +b3tgGsan2vc_0 truck +b3x6f5xFPTQ_0 horse +b3x6f5xFPTQ_1 horse +b3x8Gwk4V8o_1 person +b3x8Gwk4V8o_0 person +b323CLKf_vM_0 person +b34Cdm6l5_k_1 airplane +b34JUq19S0E_2 motorcycle +b34JUq19S0E_0 motorcycle +b34JUq19S0E_1 motorcycle +b344je6lVYA_0 airplane +b35ihWGyz_4_0 cat +b37tPdAEkEw_0 person +b39uBVwcm48_0 motorcycle +b4E8uT19QkY_0 bus +b4E8uT19QkY_1 bus +b4FBbr4Pud8_0 person +b4GXrkSKAdA_0 cat +b4HAPQ_xX5E_0 person +b4HAPQ_xX5E_1 person +b4KwBIif5OY_0 cow +b4KwBIif5OY_2 cow +b4KwBIif5OY_3 cow +b4KwBIif5OY_4 cow +b4UXSjdnqZ0_0 person +b4Xn8--nfvI_0 person +b4aEJNvYqtU_0 bear +b4j8lkkY_lE_0 zebra +b4tTUDVt6Gk_0 person +b42WUwHAKPs_0 boat +b455pPKgTj4_0 person +b5D9lQq3uf8_0 bear +b5IshxZjL7o_0 motorcycle +b5NxbNaAo_8_0 person +b5R1HVvc040_1 train +b5S8Db1Gu7I_1 bicycle +b5S8Db1Gu7I_3 bicycle +b5T_VSM7nbg_0 motorcycle +b5nwFyniymA_0 dog +b5ud9dsnS1c_1 person +b5ud9dsnS1c_0 person +b51dSWD8MF4_0 elephant +b59pPUKW_78_0 car +b5-eXPHW4Mg_0 person +b6AoStVIzkw_2 person +b6IE2imnfp4_0 person +b6MtzhRufn4_2 skateboard +b6MtzhRufn4_0 skateboard +b6RIavVJ660_1 person +b6dVZMAHwro_1 airplane +b6gsIu7Pxbc_0 dog +b6ndIInoIzU_0 boat +b6xUAyNCbdY_0 person +b61MghNCCTI_0 person +b61MghNCCTI_1 person +b65S2P2Pfms_0 person +b66BE9WdQP0_2 bicycle +b7HqfhRNtAQ_0 cow +b7H_n_w2eFQ_0 person +b7Igw_OO-P4_0 person +b7LHlx86tk0_0 train +b7RYkf4oXv0_0 skateboard +b7WQe48-0NI_1 giraffe +b7WQe48-0NI_0 elephant +b7WiE1a8IAM_0 person +b7go-l8jA5s_1 boat +b7hJ62ORLHc_0 person +b7iLQoOKVrM_1 horse +b7ivqvv6s6A_0 motorcycle +b7mawJlPASQ_0 person +b7u0NZEc8OI_1 person +b7ycKg8GLHA_0 person +b71SThzfrDg_0 bird +b78PYqyYWZA_0 person +b8LqaxvNRHw_0 person +b8LqaxvNRHw_1 person +b8VoRclgULc_0 cat +b8aWJIa4RFI_0 giraffe +b8es8BWiC5c_1 person +b8g4M9Yov8M_11 bear +b8g4M9Yov8M_3 bear +b8xtOCMwjJM_1 bird +b8x1qHT8nvE_2 boat +b8yA8bHlrtQ_0 bus +b8yqEFXS8Ck_0 horse +b82N91HYnUo_0 knife +b9O_mJTNj2A_0 train +b9SLHObDJzQ_0 horse +b9Y5tpPv-LQ_0 car +b9iCmG9fIHc_1 motorcycle +b9melHkIeV4_0 bird +b9oiO21MJh0_0 horse +b9oiO21MJh0_1 horse +b9u4WV9ft4s_0 motorcycle +b9wwfAu5DCs_0 skateboard +b96WdT0DXKk_2 bicycle +b96WdT0DXKk_0 bicycle +b96WdT0DXKk_1 bicycle +b98Gs0d8AKo_0 motorcycle +b9-xiVm1Xck_0 skateboard +b9-2bW13faI_0 person +b-Cp0i6fBOU_0 person +b-Cp0i6fBOU_1 person +b-S7G5A0MNI_0 person +b-T0AS7CuxI_1 knife +b-VYy9eEU6w_0 person +b-W1PY33nQg_0 person +b-hT8zKObfM_0 person +b-hqwYjKCH8_0 truck +b-i49sLOjBo_0 person +b-i49sLOjBo_1 person +b-mQajOHUAA_0 person +b-mQajOHUAA_1 person +b-mQajOHUAA_2 person +b-ncxt38EFw_0 person +b-wiIOBccF0_1 person +b-x--HjbnpM_0 knife +b-5K7RwiHdw_3 boat +b-8ARNgk-Tw_0 person +b-_FeNpM_wI_0 person +b_B3oYiBWi4_1 skateboard +b_KBD-NL4Vo_0 train +b_ZVDwMrcEU_0 airplane +b_exMPY7gnM_0 person +b_fR7aS10Z0_0 bear +b_h4xugql44_0 umbrella +b_kksCK6cbw_0 cat +b_n776bwyJo_0 boat +b_n776bwyJo_1 boat +b_vDLf3193s_0 bus +b_1TwBIgwKE_0 car +b_7EvlxDWFc_0 truck +cAARR6q3Qq8_1 skateboard +cAARR6q3Qq8_0 skateboard +cAFqK_6ltXw_0 cat +cAJsxlkMG_s_0 dog +cAJsxlkMG_s_2 dog +cAJsxlkMG_s_1 dog +cAKfCLDFg34_1 person +cASL6wZ33vA_0 boat +cAYIECe6Bvs_0 truck +cAnDryag2FA_0 truck +cAqs3d9KNzk_0 person +cArYvJEUdOg_0 horse +cA0HCmGOK84_8 horse +cBAG9pjaV70_0 cow +cBBDfwkH23A_5 horse +cBBDfwkH23A_2 horse +DQk3Xvbv57I_0 cat +DQqBXfTgqTE_0 train +DQ04rtHIqHQ_0 elephant +DQ7GZOJxra8_0 person +DQ-vQygnOx0_0 train +DQ-vQygnOx0_1 train +DQ-vQygnOx0_2 train +DQ-vQygnOx0_5 train +DQ-vQygnOx0_7 train +DQ_yyvagS0g_0 truck +DRMoOpmUgn8_0 person +DRO4MalcQFk_0 person +DRSSiSNzV7Y_0 person +DRXxJArWrQA_0 person +DRaIGIiQXd0_1 train +DRaX3P2ysBk_0 person +DRhRKwI26n8_0 bear +DRhRKwI26n8_1 bear +DRseWxukwaI_0 person +DRsoi5DxAJk_0 car +DRuDqkZ0zfE_0 person +DRuDqkZ0zfE_2 person +DRuDqkZ0zfE_1 person +DRxLQ6we5YU_0 horse +DRybt0Cgr_U_1 bird +DR0QGL0n_wM_0 person +DR4mzyMklY8_0 skateboard +DR82KhNzs1w_0 person +DR-AMnnLCCQ_0 cat +DR_jo4aSqn0_0 person +DR_jo4aSqn0_1 person +DSAbzYpUW5w_0 cow +DSB9X3bgG2A_0 person +DSCt67aveiw_0 truck +DSCt67aveiw_2 truck +DSEt02E1kJE_0 person +DSM_BlK-ggg_1 person +DSM_BlK-ggg_2 person +DSRGbK9rPbo_0 train +DSWlLGL3xj8_0 horse +DSZkEwhJEI4_0 skateboard +DSaSooZZeAg_2 bus +DSn5-dKW_P0_0 person +DSoRmFNRxiE_0 person +DSoRmFNRxiE_1 person +DSqy2MlVOxE_0 person +DSq0q8dCuCw_0 truck +DS5z-K8Cpzs_0 person +DS-V_NKOawo_0 knife +DTBhYAFcQ94_0 skateboard +DTFg8SeWhbE_3 skateboard +DTYiSIRTXW8_0 knife +DTZkCYvGZ9E_0 person +DTm5L6IAHC4_0 person +DTnIC_Q8YoY_1 boat +DTs2uXh47Xw_0 person +DTtejx1VYBs_0 person +DTvjWj60ixI_0 person +DTvzQwX0KRQ_1 horse +DT4KxrhD89E_0 person +DT7TSCbFXek_0 person +DUAhVOWkluQ_0 person +DUAhVOWkluQ_1 person +DUBzIIKht_w_0 person +DUBzIIKht_w_1 person +DUB3OOi7dQc_0 person +DUHEv94Tyno_0 person +DUHEv94Tyno_1 person +DUHEv94Tyno_2 person +DUPQ3fPhomY_0 person +DUQa7q5NTQI_1 horse +DUZhPq4FiJM_1 person +DUb6-VQcokc_0 cat +DUlYPwiuBrw_0 truck +DUlYPwiuBrw_1 truck +DUmKu-rc7jI_0 person +DUwVOy7IYvA_0 person +DUxGnuYB_GI_0 cow +DU1ww3ryP7s_0 person +DU4acd1_vuI_0 person +DU8jvzO9tEA_0 zebra +DVFfZw4HW3E_0 train +DVFfZw4HW3E_1 train +DVK9BrG_Y_8_0 person +DVOFKTeh9BY_0 person +DVgCgSDZVw0_0 person +DVjOMylPUfU_0 person +DVlEnd5Ra2Y_0 person +DVm_-u6oWwA_0 car +DVqsCPYrMrg_0 person +DVqsCPYrMrg_1 person +DV4GPAloBks_1 person +DV4GPAloBks_0 person +DV79-MpnE1Y_0 person +DWQ0kmCIT0E_0 person +DWZNfCg0W8o_0 person +DWjj9U_lr30_0 person +DWoRZEAFpUI_0 person +DWqyeu4eovM_0 horse +DWuaB5j6-CQ_0 person +DWwGWBcxL0k_0 person +DW1iqzQEWkE_0 person +DW4OTTF7Jc4_0 person +DW8G3A0trOk_9 bear +DXEqDJWN72E_0 person +DXEqDJWN72E_1 person +DXI2AmrILgw_1 cat +DXa15hEKLAc_0 truck +DXgs-pfW-0M_0 train +DXpyVrXMs1w_0 person +DX5AP4s6u0k_0 bird +DX867I2CNRk_0 airplane +DX-PbjeeB6o_1 giraffe +DYJJBRoUlnU_0 knife +DYUiMLisOzs_0 person +DYbb8_mMeLs_0 horse +DYhTdNMuv5g_0 knife +DYkV2TPfOBk_0 truck +DYlrCUMDv_g_0 cat +DYpBOmbclGY_0 person +DYqIQv97tuE_0 person +DYvHdc4rnxk_2 person +DYvHdc4rnxk_1 person +DY0ggbU0cIk_0 person +DY3h0Y3ijmo_0 elephant +DY3h0Y3ijmo_2 elephant +DY6eQdk8jaE_0 person +DZESlirYB3I_1 train +DZGEjl9U78c_0 person +DZIFKtO6y2Q_0 person +DZIFKtO6y2Q_1 person +DZMd9NPNnLE_0 person +DZRZg1gGn1g_0 bus +DZWsGelqCPg_0 person +DZXldsAgY7o_4 skateboard +DZYjfZMMVAE_1 person +DZgbeXD-bZg_0 bear +DZqs7ie6HPU_0 person +DZ3JlgmRHQ8_0 person +DZ4G9EBImOM_1 person +DaMdWu7CyRE_0 person +DaRYBq6zsmY_2 elephant +DagKzwyphZY_0 person +DapmUIRDw3o_0 airplane +DaqVTidNtg0_1 person +DatNYbTqxlw_0 person +Daz5kZBXn5c_1 elephant +Da10JheIcaw_0 person +Da25bjhf1WQ_0 person +DbAZPBnTh3U_1 person +DbGX12xMbWM_0 person +DbNOHXsDP5I_1 boat +DbSGsjNmQ8A_0 cat +DbXz_8anwSM_0 person +DbZGV4ixs2E_0 bird +DbdZugU9GWk_0 bus +DbeCxvMCD-Q_0 person +DbfJ2s7qQJ8_0 truck +DbivV-It_rM_0 person +Dbmwr1_ObHM_0 person +DbnhReILFSs_0 person +DboUAm-F7Rg_0 person +Dbpte835xwc_0 person +Dbqj1XCvcGw_1 cow +DbrGY3BalZ0_0 skateboard +DbrGY3BalZ0_3 skateboard +DbrGY3BalZ0_2 skateboard +DbvkTKJjRj8_0 person +DbwEevYFGrg_0 person +DbzakdG34mg_0 car +DbzakdG34mg_1 car +Db3OG025sz0_0 person +Db74WjMmf-0_0 bear +Db74WjMmf-0_1 bear +DcAxPsNVe28_0 train +DcFWetycnqY_0 person +DcKjrocJ8iM_0 person +DcKjrocJ8iM_1 person +DcOl0Ec1kuI_0 person +Dca5CTtFQZ8_0 motorcycle +DcexSE28IOA_2 person +DcexSE28IOA_0 person +DcexSE28IOA_1 person +Dcfs-bFQcxk_0 person +Dcj-1vKe6iI_0 elephant +DckRd1CpSm0_0 skateboard +DckTHE_Pn5Q_0 person +DcknQtmjIDA_0 elephant +Dclr-tDJMO8_0 person +DcpuJSx5z78_0 person +DcpuJSx5z78_1 person +Dc3yhv5mfN8_0 person +Dc4EXPP0fqU_0 cat +Dc9dWfPxIEM_0 bicycle +DdGvFcujfxo_0 person +DdHWfz7kw4I_0 person +DdJuIi7LexI_0 bus +DdKvI-6rMII_1 person +DdNpi-Pmvgc_0 person +DdNpi-Pmvgc_1 person +DdNpi-Pmvgc_2 person +DdOk9lG9b1k_0 knife +DdUa-CozM14_0 person +DdUa-CozM14_1 person +DdYyeGgXLKw_0 person +DddB5joJQC4_0 airplane +DddRHyvYqFI_0 person +DddRHyvYqFI_1 person +Ddf4T9I0sdI_0 person +Ddz7VVJXgHs_0 person +Dd2qrXASEzk_1 person +Dd2qrXASEzk_0 person +DeCtt_QZqjk_0 person +DeCtt_QZqjk_2 person +DeFuoRV0yCw_0 person +DeFuoRV0yCw_1 person +DeHiMvczAD4_0 person +DeIpwOsUzjw_0 person +DeVZ83g93sE_1 bird +DeViLrLvD1Y_0 horse +DefHSc2VTOo_0 person +DfGzSVv2ELQ_4 horse +DfGzSVv2ELQ_1 horse +DfGzSVv2ELQ_3 horse +DfS7lvAcDQc_0 umbrella +DfS7lvAcDQc_12 umbrella +DfT_7BUGNQA_0 person +cBI2gZhpA-8_0 person +cBMnKBVcoOE_0 person +cBMnKBVcoOE_1 person +cBQJU95uwwM_0 person +cBQJU95uwwM_1 person +cBSbDKv-Z_o_0 car +cBb6VPKgF1M_0 knife +cBeH0xcCCWE_1 person +cBhDn0TkAdc_0 elephant +cBhDn0TkAdc_2 elephant +cBhDn0TkAdc_3 elephant +cBhDn0TkAdc_1 elephant +cBlqBEElvDI_0 person +cBpFzTn_uOo_0 person +cBvZAwlCN4M_1 horse +cBvZAwlCN4M_2 horse +cB1RhnpteUg_3 airplane +cB9XRu3bb_0_0 person +cB_RQN9IXg8_2 skateboard +cCA7llOU4HQ_0 person +cCEUd1IZ6OQ_0 person +cCEUd1IZ6OQ_2 person +cCMe4KdqzeI_0 person +cCaz75u-bCM_0 motorcycle +cCfInBOvqkk_0 person +cCfVriTflG8_0 person +cCnjh5F8dvM_2 boat +cCvpQCZ33xQ_0 train +cCwB7O-yg4Q_1 airplane +cCxZRIxh_yk_0 cow +cC2UgNbG7Rs_0 cat +cC3-bziiNKk_0 cow +cC3-bziiNKk_4 cow +cC4nZNGoC-g_1 horse +cC4nZNGoC-g_2 horse +cDGz5cnIzK0_0 train +cDIc8cs3igI_1 person +cDL0YZ_vXOk_1 person +cDaR5WdXvIo_0 dog +cDfSk2g6wRM_0 dog +cDg-vYWO3AI_0 umbrella +cDvCYN97QYU_0 dog +cDvWWER9oeI_0 person +cD_EAISZcwM_0 person +cD_zwwrcvkI_1 person +cEAwCEnfITY_2 horse +cEFLP7rdZSU_0 person +cEIAg54WPCs_0 skateboard +cEOHFcu3Uic_0 person +cEOqnkbgfMQ_0 person +cEXYVwmcpSg_0 person +cEdeOfPvcQ0_0 person +cEomNeUqQUI_0 umbrella +cErRs5qv8mc_0 elephant +cEyCX-t8Jlo_0 bird +cEyCX-t8Jlo_1 bird +cEzC3hwdO_o_0 person +cE7AS1hrlYA_1 person +cE7AS1hrlYA_0 person +cFBoLads7vA_0 person +cFHTt7uFxH4_4 umbrella +cFOk-AMS2Aw_0 motorcycle +cFOk-AMS2Aw_1 motorcycle +cFkmNa2nYEk_0 person +cFoUf9UmoZ0_0 person +cFq4fzO00qE_0 cat +cFtfKwaxphA_0 person +cFuoJPf6prU_0 skateboard +cFzjl_SiNhg_2 dog +cFzjl_SiNhg_0 dog +cF0SM2Lf82s_0 person +cF7uQwB8sEg_0 person +cF9YklqKEp0_0 cow +cGBOBTCgzP8_3 horse +cGBOBTCgzP8_4 horse +cGCbcyeQqG8_0 person +cGCbcyeQqG8_1 person +cGC4pGWPOUk_0 person +cGC732t-itM_0 person +cGEvxRn1UtQ_0 person +cGNmKg25XMs_0 boat +cGUXUioIa4o_0 person +cGVaIIV18ug_0 person +cGcyxMp1ZQc_0 person +cGcyxMp1ZQc_1 person +cGdeftwBWL4_0 person +cGiVzhQI2a0_0 person +cGpNQ9Vk-5E_0 person +cGtaJVgvTJg_0 person +cG1_sZqy7lU_0 person +cG2fL1nRZmE_0 person +cG5TxH-1Sf4_0 person +cG65cBtyj20_0 cow +cG7BBtumZnQ_0 dog +cHCYX0EqsfE_0 person +cHQLun1YTiM_1 person +cHQLun1YTiM_0 person +cHSjCxvPumA_0 motorcycle +cHWE72lnzZo_0 person +cHYcXW7HAkA_0 person +cHaBQgTFdr4_2 knife +cHjKy80ojXM_2 bear +cHkm25QAG8A_0 truck +cHnV0yZTha4_0 car +cHpaD5PtHnM_0 cow +cHv3ulnF1fo_0 person +cHyjhzLIeO0_0 person +cH2A35uULdc_0 person +cH2g9vV4SyM_0 bird +cH27awicc50_0 person +cH8zYhvzdb8_0 person +cICrfFzHoZs_0 person +cIFXOWG5Dd0_1 person +cIF9coXttVs_0 person +cIIlWssV9Sk_0 person +cIJSKwcTQ10_2 bicycle +cIJSKwcTQ10_3 bicycle +cIPlCULXXHQ_3 elephant +cIPlCULXXHQ_2 elephant +cISwax-t_78_0 person +cIVGJQrNkT8_0 person +cIV9T5ZQmdI_0 person +cIh9baL5Hzw_1 person +cIjMwiaApEc_0 person +cIvqOdvwX6w_0 person +cIwDGqmKrfY_0 person +cJH4RK9aVR0_0 elephant +cJJDfdbopiQ_0 person +cJSjHpF7ILg_0 airplane +cJUj9q6wgis_0 person +cJfW0Gfkzrg_0 knife +cJjaVdNaUko_0 bus +cJnihDxg0wg_1 dog +cJtGcHMJlMA_0 person +cJ0hAba-pck_2 giraffe +cJ0_u3Ta6kU_2 skateboard +cJ0_u3Ta6kU_0 skateboard +cJ2f7qDBm7M_0 horse +cJ41GQMsJIA_0 dog +cJ6BfbrgwDM_0 person +cJ7Akre7-Sc_1 cow +cJ7ZHI-8gU0_0 person +cKO8G1ZXQgo_0 person +cKdank8BDik_0 person +cKgqIdOoBmE_0 person +cK4yj3jgWek_0 person +cK5MabT7iIA_2 train +cK5MabT7iIA_0 train +cK5MabT7iIA_1 train +cK9R8KdVuIE_0 person +cLKgng5yuC4_0 person +cLKgng5yuC4_2 person +cLKgng5yuC4_1 person +cLPSEK3_jEE_2 horse +cLPSEK3_jEE_3 horse +cLPSTXefj2Y_0 person +cLY_N1jEC8E_0 person +cLg1pn5Oh1k_0 person +cLlL2uHDyBw_0 bird +cLnQAhX42Eo_1 horse +cLnQAhX42Eo_0 horse +cLn0Kz_p2U0_0 train +cLrXQvFZ-y0_0 knife +cLvgs19Vm18_1 person +cL2jFa-Zd_M_0 person +cL4k6bdNmbs_0 boat +cL6G_y5LoDo_0 motorcycle +cMGnmOyYWcM_1 person +cMIyGPpW9Xw_0 person +cMJhk7y1Nng_2 bird +cMJhk7y1Nng_0 bird +cMJhk7y1Nng_1 bird +cMOULCqujvs_0 cat +cMRhR707ZfA_11 bear +cMRhR707ZfA_13 bear +cMeXNjQUwe0_0 horse +cMg1O__kPFA_0 horse +cMwsAfZMG1c_0 person +cMwt7xBZ9i4_1 person +cM6-id-uhMg_0 person +cM6-id-uhMg_1 person +cNLuZxPpWho_9 elephant +cNLuZxPpWho_14 elephant +cNLuZxPpWho_1 elephant +cNLuZxPpWho_4 elephant +cNLuZxPpWho_8 elephant +cNLuZxPpWho_11 elephant +cNLuZxPpWho_13 elephant +cNalYSGXOkM_0 person +cNnMvF7oiUo_0 horse +cNr9rjOJ0ps_0 person +cNxEreBWMRc_0 person +cNxEreBWMRc_1 person +cOD8xhwGfME_0 person +cOD8xhwGfME_1 person +cOYK17trE9k_0 person +cOYK17trE9k_1 person +cOZOzY6XDLU_0 person +cOalncX8fwg_0 airplane +cOalncX8fwg_1 airplane +cOalncX8fwg_2 airplane +cOalncX8fwg_3 airplane +cOalncX8fwg_4 airplane +cOkVxYbnFRs_0 person +cOkiG4LRtQU_1 truck +cOp33oi4C8E_0 skateboard +cOzNmIBhiMY_0 person +cO1F_0l1vSU_0 person +cO1MbnbgUbU_0 dog +cO3WA2g_UeM_4 bear +cO3WA2g_UeM_2 bear +cO5xsG3ud_0_0 train +cO7nCAZ-uLk_0 person +cPBvSHKPNvk_0 person +cPdRddyxsVA_0 cow +cPdjr1zTQQ4_0 person +cPeGSXSLepg_0 person +cPkbg5bdpcE_1 person +cPkbg5bdpcE_0 person +cPn5c5t2g6w_3 skateboard +cPqAK1E1Ajo_1 dog +cPqAK1E1Ajo_0 dog +cPsXS3_4zOk_0 bus +cPu-riLrt1c_0 person +cPu-riLrt1c_1 person +cP-gl2IN_AI_1 person +cP-gl2IN_AI_0 person +cP_nenKIU4g_2 bear +Df70QgKA_Hc_0 person +Df70QgKA_Hc_1 person +DgSwJVCLkYM_0 person +DgcSsQKaX7Q_0 person +DgoFmJFWpUw_0 bear +DgtiaphLkMc_0 person +DguiMPx8nn0_2 person +DgvI1azs_0E_0 airplane +DgwM5b-eKvc_0 person +Dg2sU0bmBho_0 person +Dg8r8QlJw80_0 person +DhAkswxLuAs_0 person +DhJZwbql4dc_1 person +DhLD44-KIUU_0 person +DhYbvvwSsEA_1 person +DhYbvvwSsEA_0 person +Dhd-0-xOF6I_0 cow +Dhl-jIQaam0_3 person +Dhl-jIQaam0_0 person +Dhl-jIQaam0_1 person +Dh6APdqkNZ0_0 person +Dh_6tF8ndZs_0 person +DiAj24Xsadk_0 person +DiDELcBJWh4_0 person +DiPjO5frbNc_0 person +DiQ-VgXIDMo_0 person +DiVX_-kQv0k_0 person +DiVX_-kQv0k_1 person +DiWi-oWT9EI_0 boat +DiXsD6VHEr4_0 person +DiZ4OCT30AM_0 person +Dia6QIxORbM_4 airplane +DihnxPkojnQ_0 giraffe +DihnxPkojnQ_1 giraffe +Di41WoS7T1M_1 bear +DjAQs68BiwA_1 giraffe +DjB4dpC4TVs_0 horse +DjD15NlLBYI_1 truck +DjD15NlLBYI_0 truck +DjK1R_LBqgM_0 person +DjMnoAbMiIU_0 person +DjMnoAbMiIU_1 person +DjQF34GUthk_0 person +DjS-0VOep0Y_2 person +DjXtIIwfITI_0 person +Djb2blFeoNM_0 person +DjdAxUWgSdk_0 knife +Dju4Bl2fx88_0 bicycle +DjyldIzPJbA_0 horse +Djy5UE0Ofa8_0 person +Djy5UE0Ofa8_1 person +Dj7DVsCVqqY_0 cow +Dj9npayKJqk_0 elephant +DkAG7dFDk94_0 person +DkC_iJTIrYc_1 person +DkC_iJTIrYc_0 person +DkF-LqA7wSk_0 bus +DkNY4yun6ek_0 boat +DkPYbKRQBE4_1 motorcycle +DkTfU9q9U_I_0 cat +DkTqTY04y30_0 person +DkTqTY04y30_1 person +DkbRBY4ZlFY_0 bicycle +DkbRBY4ZlFY_5 bicycle +DkbRBY4ZlFY_6 bicycle +DkbikYoLycQ_0 bus +Dkmab-wxSy4_0 person +Dkmab-wxSy4_1 person +DknRMqifZFE_0 skateboard +DkpZP7RtrJM_1 bus +Dkqy-okNDVM_0 person +DkrkY6blx3U_1 person +DkrkY6blx3U_0 person +Dk0wXCp-USs_0 boat +Dk1QPiNji5I_0 skateboard +Dk4V0c6Yzbs_1 boat +Dk47lOWl3NM_2 cat +DlCMYyDhSVY_1 person +DlCMYyDhSVY_0 person +DlDFQ88ui2A_0 person +DlDJpNWKuPM_0 knife +DlFJTfO-mc0_0 cat +DlG-VsdsPCk_0 motorcycle +DlTE01-45gQ_0 airplane +DlX2Yvp20gY_0 person +DldXGda7zfE_0 person +DldXGda7zfE_1 person +Dlg5BFm20wI_0 person +Dlg5BFm20wI_1 person +Dl3fDWG23zU_0 person +DmG9v9xVPbg_0 person +DmIeMGzqZEc_0 cow +DmJ9x-DFdqA_0 person +DmJ9x-DFdqA_1 person +DmLGGv6YNEo_1 bus +DmL_6_a_54g_0 bird +DmNmgatXwU8_1 knife +DmSRZp63qTo_1 truck +Dme3Rfsqbz8_0 person +DmiucPhqXMg_1 bus +DmiucPhqXMg_4 bus +DmlMgF-BuRo_0 person +Dmt8pgQG3M4_1 skateboard +DnLVGRyXAR4_0 person +DnN9tjwPn-0_0 person +DnR4VFNo44s_1 airplane +DndaJVRuOoo_0 person +Dniy3zze90s_0 person +Dniy3zze90s_1 person +Dnj_fhGXHC8_1 bird +DnkUzsPqjE8_1 person +DnkUzsPqjE8_2 person +DntJ297deXI_1 person +DntJ297deXI_2 person +DntJ297deXI_0 person +Dnx6TlTvRfI_0 person +Dn80jV69sbs_0 person +DoEWhY2BkZo_0 person +DoOq_FhWze0_0 person +DoPKGr2HJwM_3 bird +DoRoLk97UqY_0 truck +DobAdZVysXc_0 cow +DohloSZ6YdA_0 person +Domgj6ptFOs_0 bus +DpH2eSmcTk4_0 bus +DpJA_qYLobk_11 bicycle +DpJA_qYLobk_0 bicycle +DpJA_qYLobk_2 bicycle +DpJA_qYLobk_5 bicycle +DpJA_qYLobk_6 bicycle +DpJWhFnF2Fo_0 dog +DpR63uhHTjo_1 horse +DpWw1SaCdTQ_0 person +DpbGsvglx7Q_0 elephant +DpbGsvglx7Q_1 elephant +DpimIW1T2Sw_0 person +Dpp32dLn0hQ_0 person +DpvuhymOiUM_0 person +DpwjQ_KcYAc_0 person +DpxoJ_GWJA4_0 giraffe +DpxoJ_GWJA4_3 giraffe +DpxoJ_GWJA4_4 giraffe +DpxoJ_GWJA4_1 giraffe +Dpz-s6E9VWg_0 person +Dp2pGcutqDQ_0 person +Dp2pGcutqDQ_1 person +Dp4XaG6247k_0 person +Dp5KRKUJBGE_0 cow +Dp6qJvgV4fQ_0 person +Dp71z8eyq7o_0 bus +DqBNoutsr4M_0 person +DqBNoutsr4M_1 person +DqDElT9H4Tg_0 boat +DqESUtRuhPw_0 dog +DqVUeH6XI2Q_0 person +DqegnRXQd5Q_0 airplane +Dqi5KTmt04s_0 bus +Dqy6NbRkVPE_2 skateboard +DrAnw0S9Pmc_0 person +DrCKp4YB7rI_0 person +DrE7aW7O0eQ_0 person +DrFxlXYC6-o_0 person +DrGCtlmxxVc_0 person +DrPpkd-UxFY_0 cat +Drc0Grdb_LU_0 cat +DrgjySu3e-c_0 motorcycle +Dr9XXUA4UKc_0 person +Dr9XXUA4UKc_1 person +Dr--We7lD3I_0 person +DsA5QOOIZJw_0 person +DsP87b0IuoU_0 person +DsZ6Cf42EdQ_0 person +DsiAcCUi8iE_2 bear +Dsm48Msjw6k_0 bird +DsxyH6AKBd0_0 truck +Ds0GIUe1AFo_2 person +Ds0GIUe1AFo_0 person +Ds0GIUe1AFo_1 person +Ds3E7n1kRQk_0 train +Ds44yYfSEr8_0 bird +Ds8xwquSVkw_0 skateboard +DtKSEQhjq2I_1 cat +DtQGDwZ1PIU_0 truck +DtQGDwZ1PIU_2 truck +DtSpyLMbD9o_1 motorcycle +DtU93_s53sI_0 train +Dtc3hZBmn9Q_0 person +DteEg93cINc_0 person +Dtf2WRyd4OA_0 airplane +DtgUpKmdw_g_0 person +DtuRiD_E6HU_0 person +DtyatJX8J1A_0 bicycle +Dt1MDqN3TCs_1 elephant +Dt1PLFoRvoM_7 airplane +Dt1PLFoRvoM_0 airplane +cQAr7IVeBrU_0 person +cQC7jBc1pC0_0 person +cQIviFGN-_M_0 train +cQOFvBNN9to_0 airplane +cQOFvBNN9to_1 airplane +cQPP6SqX-uk_0 truck +cQbqByuUnW8_1 car +cQgUGmyvkJ8_0 train +cQttS-GIM5c_0 person +cQttS-GIM5c_1 person +cQw1wXvFnLM_0 person +cQ29m5z8Cnk_1 cow +cQ4aR8OLr74_0 motorcycle +cRGrqg7y9tE_0 boat +cRVqyVvxjHI_0 train +cRczdkzrJ-w_0 cat +cRnDFinbH-s_0 bird +cRrjU515FKg_0 person +cRvAv1Nn-WQ_0 cat +cR6qM7wjtDw_0 knife +cSDafQMsYwc_0 cat +cSJ2ISog6Pw_0 bird +cSJ2ISog6Pw_1 bird +cSLerMX3IBg_0 person +cSNwXF8OcR8_0 cow +cSO-70KCypM_0 skateboard +cSVIvCYuDtU_0 cow +cSdBaGsGWKk_4 bird +cSdBaGsGWKk_9 bird +cSdBaGsGWKk_1 bird +cSdBaGsGWKk_3 bird +cSdBaGsGWKk_6 bird +cSdBaGsGWKk_7 bird +cSdUwiTGXPc_2 motorcycle +cSor-u6VHHw_1 dog +cSqMDH0-sDs_2 person +cS398dAyQ9k_0 cow +cS-QgqiUgLQ_0 person +cS-QgqiUgLQ_1 person +cTGOQnmi7bo_0 person +cTLa1dxk76g_0 person +cTUTNgp9rZ4_0 person +cTUTNgp9rZ4_1 person +cTayBCWq6xo_0 person +cTiETDBrGv4_0 skateboard +cTiETDBrGv4_1 skateboard +cTk8pacLUcc_0 bus +cTmv-vp89sY_0 elephant +cTmv-vp89sY_1 elephant +cTsipIh7xF8_0 cow +cTvxGA-EvvY_1 person +cTzz_ZCUpxc_0 person +cT4Y0HSeBgg_0 elephant +cT5UlPnc5MQ_0 person +cT5UlPnc5MQ_1 person +cT7LjXG7ByI_0 airplane +cT7LjXG7ByI_1 airplane +cT7LjXG7ByI_2 airplane +cT7kZP5B_2s_0 bus +cT_US5II64I_0 person +cUEWtKzcAsM_2 airplane +cUEWtKzcAsM_1 airplane +cUM5ajI3KJg_3 horse +cUNExkBml18_0 person +cUSRVmcbXxI_0 person +cUS9QgCXcPo_0 person +cUWmN_HuZiA_0 person +cUYlfMGqB_8_0 dog +cU7JEUo5qdM_1 person +cU7sT9UHs7s_0 person +cVCqOzgt2vI_2 train +cVCqOzgt2vI_0 train +cVM2h5qbyUw_0 elephant +cVXIaONp5o8_2 person +cVYqiMXSh9g_1 person +cVbcrOx7768_0 person +cVfH0tFh5Kc_0 person +cVfWBtl-qK4_0 truck +cVq5VnfZtNw_0 person +cVr16pInr5k_0 person +cVsZMfMaxSM_0 person +cVtyGQKWFcI_0 motorcycle +cV0a2ScBxpE_0 person +cV0a2ScBxpE_1 person +cV1mBGRlLe8_0 bird +cV1szYodba0_0 motorcycle +cV8BGLBROa8_0 person +cWBCCAo3pUM_0 bird +cWBTkrImlLQ_0 train +cWBTkrImlLQ_1 train +cWGCbw5I6cI_0 skateboard +cWIDcoPB3Rg_0 person +cWKf_KANUSM_0 person +cWRO27zzxF4_0 person +cWaVXNQ5cvg_0 person +cWb-i8hj8uc_0 person +cWcJrAQuNA4_0 bird +cWtIT6V98zc_1 person +cWxELKsh43s_0 person +cW2hQE3lS9k_1 person +cW4fmuV2JuU_0 skateboard +cW7OrsSn-m8_0 person +cXP1Lit5Pmk_0 person +cXS9VytLIjM_0 cat +cXT5_AFSI8Q_0 person +cXUdqfIp-Hs_1 person +cXUdqfIp-Hs_2 person +cXWgDE6boPQ_0 person +cXZt2UZe6QQ_0 motorcycle +cXaAcHkHUzU_0 person +cXsRP67GHA0_0 person +cXsRP67GHA0_1 person +cX0yQ5KIAKw_0 person +cX3mnglolLE_2 elephant +cX3mnglolLE_3 elephant +cX6lyv1DI80_1 airplane +cX-s4BNxb0c_0 person +cYHq8xoYMO4_1 bus +cYVLbgGxJMM_1 person +cYnyDXx580I_0 person +cYpas0B5zEo_0 cow +cYvyTVEqiEU_0 giraffe +cYwkpA75A8Y_0 person +cY1cmlwRnaE_2 bicycle +cY1cmlwRnaE_1 bicycle +cY6HDOEiINs_0 skateboard +cY_INarfLQ4_0 person +cZA_Yoq3vy8_0 person +cZB5MQY5kVA_0 skateboard +cZDoXwn5lv8_1 person +cZPvtKaqRxc_0 person +cZU2LAWtwUM_0 knife +cZZT6OJ6xGk_0 horse +cZZT6OJ6xGk_1 horse +cZe888DWA8M_0 person +cZgt8s4mARc_1 person +cZugy4cYVng_0 cat +cZz6eOuSV9Y_0 person +cZ155yARalk_0 person +cZ155yARalk_1 person +cZ7siEIFHlI_0 cow +caAnHYU-Gwk_0 horse +caGQ2b4L930_0 person +caGzwv3HLKU_0 skateboard +caLKu0yKW0Y_0 dog +cacCjMLNpIg_2 bird +carYHHE3y3A_3 knife +cavT34ZvciI_0 elephant +ca4_gKs6MN0_0 bear +ca8aNafTzeY_0 person +ca_weHSJH80_1 train +cbRztq6KZn0_0 horse +cbVll1hxlDA_1 person +cbVll1hxlDA_0 person +cbvbRxOMJ-A_0 truck +cb6YFX4CVqc_2 airplane +ccIWh5JBil8_2 bear +ccIWh5JBil8_0 bear +ccQ7JnYrTL8_0 bird +ccQ7JnYrTL8_1 bird +ccRdzj5Zi-U_0 person +ccR-h9z3bRI_1 knife +ccR-h9z3bRI_2 knife +ccVJXErLdOo_0 dog +ccWTUq_mvsU_0 elephant +ccWTUq_mvsU_1 elephant +ccaCWXJ0jKY_0 person +ccaYdn2p4Uk_6 knife +ccaYdn2p4Uk_10 knife +ccfTQmE0zsA_0 person +ccfTQmE0zsA_1 person +ccwFXG9D98w_0 person +cc0S9924O-s_0 skateboard +cc76qcSHNMM_1 dog +cc76qcSHNMM_0 dog +cdBO6xYUmzE_0 person +cdBO6xYUmzE_1 person +cdKEh34fsYk_0 person +cdNWg2zU6bY_0 person +cdOQ7lTQJBw_1 cow +cdOQ7lTQJBw_2 cow +cdSG1fcxNAA_0 person +cdS-7_Egk88_0 person +cdW8PgwFm6o_0 motorcycle +cdZqtqh5PwE_1 person +cdZqtqh5PwE_0 person +cdZ1ODMJYKM_0 bird +cdbmvoa89QU_3 train +cdbmvoa89QU_4 train +cdbmvoa89QU_5 train +cdf-C-P2bW0_0 elephant +cdkSgKIMQEM_0 truck +cdkSgKIMQEM_1 truck +cdoGDD6m8Og_3 person +cdpYTik8eL4_0 person +cdruQqCvfrI_0 truck +cdxkCeoDX6Y_1 person +cd80Ii4FB1Q_0 bird +ceH46gqMWak_0 person +ceIoRNo5FBk_0 person +ceIoRNo5FBk_1 person +ceLI06w8-Yo_0 person +ceVkcz1wysc_2 dog +Dt5UnNOUlZA_0 motorcycle +DuMGrFowOWE_0 airplane +DuUmKpZym5U_4 boat +DuV6ahfZ_yw_5 knife +DupWsV-iiys_0 knife +Dur1W4FemFs_0 person +Du7sKt25RiA_1 knife +Du8hVxuK10c_1 airplane +Du8hVxuK10c_2 airplane +Du8hVxuK10c_3 airplane +Du8hVxuK10c_4 airplane +Du9r_1zpPkA_0 person +DvEWbWxGJvQ_0 bus +DvEykMsNibg_2 bicycle +DvIS9FV5pag_0 person +DvIS9FV5pag_1 person +DvKLYYQzmas_0 person +DvNTMqUwwWo_0 person +DvR9Ctfk8lg_0 person +DvWCGbG9LT4_0 car +DvWDBQ9eMNQ_0 elephant +DvWDBQ9eMNQ_2 elephant +DvuQOS7UVI0_2 elephant +Dv1e0Y8A8yg_0 cow +Dv4azGPr4YI_0 truck +Dv7eGdF004Y_1 person +Dv7eGdF004Y_0 person +DwJntGNV4Gw_0 person +DwWzbtiIs7k_0 skateboard +DwhCZK1eUPw_0 person +Dwi-kq9Gcsw_0 zebra +Dwi-kq9Gcsw_1 zebra +DwlOBOv0IC8_1 bicycle +DwlOBOv0IC8_0 bicycle +DwvclcpHQNY_0 horse +DwzuhLu_Jew_0 bicycle +Dw2QHLXWmos_0 truck +Dw7BXQFtH60_0 person +Dw8lXatl4wE_2 person +Dw8lXatl4wE_0 person +Dw8lXatl4wE_1 person +DxAMNpw-4qg_0 person +DxB962sZJ_c_0 airplane +DxB962sZJ_c_1 airplane +DxB962sZJ_c_2 airplane +DxFjGsjegtk_0 person +DxHhkA1fVdA_0 person +DxPOOsSCJpc_0 cat +DxU9ZTI7KzY_0 bird +DxXEapsjhOg_0 cow +DxYW3ZMCXUw_0 person +DxegJbsalCo_0 person +DxegJbsalCo_1 person +Dxl8-fknJjM_0 bird +Dxl8-fknJjM_1 bird +DxmdjAoDhkE_4 knife +DxpMePWSgjs_0 person +DxsdKCCUvCY_0 person +Dxw3Y-UB0jk_0 airplane +Dx0fgXYBRV0_0 knife +Dx4a9ZiekrQ_0 elephant +Dx4a9ZiekrQ_1 elephant +Dx5VMmCltKo_0 person +Dx8eIjF--eo_0 person +Dx8eIjF--eo_2 person +Dx8eIjF--eo_1 person +DyFNZgEaw24_1 bird +DyZHVNsbZeE_0 person +DyceiTbkpMw_0 bicycle +Dyd1Aj3RO3I_0 cat +DyfyfDI4jqk_0 person +DytAOZD9DLU_1 person +Dy1-ch56AMc_0 boat +Dy5kD11Wnbk_0 person +Dy5kD11Wnbk_1 person +DzAi_cumPY4_0 person +DzCPCgkI8XA_0 motorcycle +DzCPCgkI8XA_1 motorcycle +DzFhvnd07Ck_0 train +DzKdERTAA8U_0 cat +DzMXxF7XRaI_0 person +DzW2oC31Gcs_1 person +DzXDPH8p-6Y_0 motorcycle +DziXgWdCrvY_3 horse +DzkCtRPiI-Q_0 cat +DzlPtZXxtpU_6 elephant +DzlPtZXxtpU_4 elephant +DzlfBATujA8_1 horse +Dzp0BrJSMBU_0 person +Dz0d79BMerc_0 motorcycle +Dz34hVhjpzA_0 person +Dz7kWPDxgbg_1 bicycle +Dz73CrM7pH8_0 person +Dz8_y0iOjLM_0 skateboard +D0DtV2eD7cs_0 knife +D0HGjOZ5XWU_1 elephant +D0O-T4E2DVo_0 cat +D0R59ANL6o4_0 person +D0TQLmGtPm4_0 airplane +D0TTR7qCVXQ_0 person +D0WAC7ByU0M_0 person +D0Yx5cLcrqk_0 skateboard +D0mf15dFGhk_0 person +D0pcdPd6hwY_0 dog +D0qo2f2Cshk_0 person +D0xc1K3BQnQ_1 bicycle +D0zhUpZhZi4_1 airplane +D04tMZ7n3YM_0 skateboard +D09x5ezi5hU_0 elephant +D0-sW80X3kI_1 elephant +D1Ct81qiyT4_0 truck +D1Ct81qiyT4_1 truck +D1DYQay-d_E_0 cat +D1IQfkEa2-8_0 truck +D1KUzeiWmUE_1 cow +D1XPuPzMvv4_1 bus +D1cTj9Fy4yE_0 dog +D1dWoFMnKhc_0 person +D1f92BE9HmI_0 person +D1ktXwG0_jM_0 person +D1plKiNFzvI_0 cat +D1tZzoBOWfA_0 person +D1yVIEgFGrY_1 airplane +D10WSuM8eqU_0 person +D19A7AUqZJ0_0 person +D2CXHzxp1TU_0 cow +D2Iqqb3RP6c_0 person +D2Iqqb3RP6c_4 person +D2Iqqb3RP6c_2 person +D2Iqqb3RP6c_3 person +D2KcVzav3YU_2 airplane +D2KoBI6R7W8_0 train +D2Qw63hsi1E_3 bear +D2RT-qUSw_U_0 dog +D2RZP8Y6VT8_0 dog +D2Ri5Wy9XPQ_0 person +D2RkdlTKlsE_0 person +D2VABHjSM6E_0 bus +D2VABHjSM6E_2 bus +D2co1ZGkwCs_0 skateboard +D2rbERtPxNM_0 person +D2t36StaDcc_0 elephant +D2t36StaDcc_1 elephant +D2wSgbAelUc_0 cat +D2yQaYJDNvs_2 bicycle +D2yQaYJDNvs_0 bicycle +D24GJS9nKC0_0 person +D3EIh6pBTdQ_0 train +D3F3xWCoWD8_0 person +D3IDGSQSrFY_3 giraffe +D3IDGSQSrFY_4 elephant +D3IDGSQSrFY_5 elephant +D3IDGSQSrFY_7 elephant +D3IDGSQSrFY_8 elephant +D3OvvA5jYlM_2 bird +D3OxudXglSM_1 cow +D3XqhAXefSA_0 person +D3Zg90Ib5GI_0 cat +D3b-w5J-wR0_0 person +D3tuGaFbdbE_0 person +D36Pwfuad5E_0 horse +D4CWBceBJEk_0 person +D4OMvYw25w0_0 bus +D4aL-0UevEY_0 person +D4do8kCWydY_0 person +D4do8kCWydY_1 person +D4goZXgzVC8_0 person +D4oLradsvXE_0 person +D4qq5Olmh24_0 person +D410FuTGoPI_0 bicycle +D4_2g_M4CXM_1 person +D5GNIcodIw0_0 bird +D5KLVLNs7-0_0 train +D5KWKhPhqWE_0 dog +D5OtHFsiXiI_0 person +D5UGpkiG-CQ_0 person +D5hYrAC2iIg_0 person +D5jUPc4nQO0_0 person +D5kSwHOWPBU_1 bird +D5kSwHOWPBU_0 bird +D5n4B-O8y8g_0 person +D5tLtHWe0Jk_0 person +D5uTmoMYXDE_0 cow +D5x402SaAk8_0 truck +D537kaRoYEk_0 person +D552mK5tfLU_0 dog +D59Eb3u0iPs_2 person +D59Eb3u0iPs_0 person +D6EDJA1bO3s_0 zebra +D6G1X8WFAA8_0 person +D6LDq6Q1Aic_0 person +D6NzaXWZGEA_1 person +D6UsriFwkjQ_0 person +D6XIhwBoaik_0 person +D6XUUDKA1CA_0 person +D6d20KAVyzk_0 person +D6f2wdAt_Ug_0 person +D6kIRV5rEPk_0 person +D6qXaD6WnVQ_0 bicycle +D6zUwxeZ1zU_0 person +D7c2tRlXz5k_0 skateboard +D7dAkMkQf4I_5 elephant +D7kHPyS4Gw0_0 person +D7r_HLTwhWY_0 person +D71B5jrYOig_2 elephant +D77yNiFrtmw_0 person +D78FDAi2log_0 skateboard +D7_S2hp6aKI_1 airplane +D7_S2hp6aKI_0 airplane +D7_tUVFGy2o_0 person +D7_zjfakeYM_0 dog +D7_zjfakeYM_3 dog +D7_zjfakeYM_4 dog +D8GQWYiVK1U_0 dog +ceczRgI6HDM_0 boat +cev1umQFsVA_2 person +cev1umQFsVA_1 person +ce8j1r_CDH8_0 dog +cfD9yGF5XmY_0 car +cfFAjaziwn4_0 person +cfWqngaDvvg_0 person +cfWqngaDvvg_1 person +cfex3QJFkTY_0 dog +cfex3QJFkTY_1 dog +cfpiw6KGB70_0 dog +cfyY4mfwN7A_0 airplane +cf0a6xp7r9s_0 bus +cf3VOLwZdKY_0 dog +cf6daxmvx6M_1 person +cf6kCO9JdOM_1 person +cf6kCO9JdOM_0 person +cgAiH_9c5DU_1 bird +cgD7Gr2Y-c8_0 person +cgQ_34JYUkU_0 car +cgT26vQK-4A_0 person +cgZo7nUeCNE_0 bus +cgjjdvXBsFI_0 person +cgj_bzL4vsQ_0 skateboard +cgmkRlhxVQ8_0 person +cgmkRlhxVQ8_2 person +cgmkRlhxVQ8_1 person +cgxIrs3ySiA_0 skateboard +cgyRQ1a79c0_0 train +cgyRQ1a79c0_1 train +cgzHPxfb-R4_2 person +cg4GIYiUNiI_0 person +cg9Y2DTUiDQ_0 cow +chc30sNO6KA_0 person +chl-Wa4_hic_0 person +chrXgx4NWck_0 person +chrXgx4NWck_1 person +chwYzLEqKp4_0 person +chyVy1kdL5M_0 person +ch_yUR9RHIM_0 dog +ciEhviIYSFY_0 bicycle +ciFKNPdVskg_0 airplane +ciUZ2LoiaCs_0 person +ciZNBF9RdaA_1 knife +ciZNBF9RdaA_0 knife +ciZNBF9RdaA_2 knife +ciZNBF9RdaA_4 knife +cifpYBLq6dM_0 person +cit4hdvCIp0_0 motorcycle +ci83tdO3GuM_0 horse +cjAhjjWOj24_1 cat +cjL-hMHdmN8_0 person +cjdImYwFXEI_0 person +cjlPNeNKoSo_0 car +cjmps6UKu_Y_0 person +cjtjQu1YoTc_0 person +cjuRQJf1_qs_0 horse +cjvMLM_Uzbw_0 person +cjye6t7P2XY_0 person +ckIaNsLDst8_0 person +ckJHbJCefVc_0 bear +ckY7Izfnggc_0 person +ckfgZsmJEbs_1 elephant +ckyL1lkCzU8_0 person +ckzaUAcrtY4_0 person +ck6hJJVJfvQ_1 person +ck6hJJVJfvQ_2 person +ck6hJJVJfvQ_0 person +clCQhmV8nf8_0 person +clL4lyl6J7I_0 person +clO2SRgOzAk_0 person +clQ98CON1pE_0 person +clUGOwaYaPg_0 cat +claqhrkmhPg_0 person +clmsmTFOSLo_1 dog +cl410aCQA8k_0 train +cl6C5KiOEHQ_0 train +cmAN1SqRkDM_0 person +cmGz-63gi5Q_0 train +cmHjbUBM4q8_0 elephant +cmKnHqPGlTw_0 person +cmV1BLuEvpU_0 cow +cmeGuaSUg34_1 car +cmqxX05lPiI_0 person +cmtruoCpSec_0 person +cmwRk4-z_BQ_0 person +cmwzhxa6Kd8_0 boat +cm7Xd_WXZAs_0 person +cnAC9g_fYUY_0 train +cnAC9g_fYUY_6 train +cnAC9g_fYUY_1 train +cnAC9g_fYUY_3 train +cnAC9g_fYUY_7 train +cnAC9g_fYUY_8 train +cnAC9g_fYUY_9 train +cnJKH5dTKyI_0 skateboard +cne8MAKWcjo_2 person +cne8MAKWcjo_1 person +cnoIwn3cQ7Q_0 bird +cnplEeb8Iuk_0 motorcycle +cnp30cLXzq8_0 skateboard +cnrSdMSCW6w_0 truck +cnrSdMSCW6w_1 truck +cnrSdMSCW6w_3 truck +cnryAbqs0sM_0 horse +cnryAbqs0sM_2 horse +cnt7MyeNlHA_0 person +cnvzLGyGalU_0 cow +coBLne1vSV0_0 person +coDrWV3qbQE_1 car +coIhjdND3yY_0 person +coVT-MPjIsc_1 cat +cobC6BjJahk_0 person +codE_-LtIRY_0 boat +cofwfK4F5ac_0 person +cohdkT2S_oA_0 skateboard +coh6clK_Q6A_0 person +comEv_WJ4Uc_0 person +cousEghehEo_1 person +cousEghehEo_0 person +co17Vvf3bag_0 knife +co17rRdOvwc_1 motorcycle +co5rBTsE2i0_0 knife +co7SR4bgOM4_0 knife +co9DJtEU4eg_0 person +cpEYJnyJ9XM_0 train +cpLmgivniko_3 knife +cpLmgivniko_2 knife +cpO5pHTOelo_0 cow +cpQ9HawKR-Q_0 airplane +cpQ9HawKR-Q_1 airplane +cpUTjBksgdA_0 person +cpmMEngbDHE_3 person +cpmMEngbDHE_0 person +cpmMEngbDHE_1 person +cpnZFfnjGYs_0 car +cpre_wIt0hs_0 train +cpre_wIt0hs_1 train +cptcOzotQ0E_0 person +cpuYK9y7zu8_1 boat +cpxkLEREnwo_0 cow +cp4ttild7EA_0 train +cqEdqz5F7tg_0 cat +cqOLpxxqIBw_1 person +cqOLpxxqIBw_2 person +cqOclzkqkVg_0 person +cqO2VRSBGGg_0 bus +cqRNPM3jgNs_0 cow +cqS_ZvZF4Kk_0 person +cqS_ZvZF4Kk_1 person +cqez5FuSf44_0 person +cqf4Vh7Vy9M_0 person +cqkZZqtr3z8_0 person +cqkZZqtr3z8_1 person +cq3TwUTSBFA_0 horse +cq84vJoKj0A_0 person +crXlnYSuCuw_0 person +crgSyPjbLBw_0 person +crh-ncEjMd8_0 umbrella +criMO4N0K5E_0 person +crmw_2KCRlY_1 horse +crmw_2KCRlY_0 horse +cruWABLWvD0_0 person +crzo7x07GTs_1 elephant +cr02TlSWnkI_6 elephant +cr5ddm3njdQ_1 bird +csGJS_sNJx4_0 person +csKSGFZyk04_0 horse +csTChnltOdg_0 cow +csiWQna-zcg_0 skateboard +csl1NFlhS0I_0 person +cswk8vZ6th8_0 person +cs16RhEpmu4_1 person +cs16RhEpmu4_2 person +cs3PfcpDro8_0 cow +cs_yLDexfXk_0 person +ctAtCH6V1Dw_1 person +ctAtCH6V1Dw_0 person +ctCQsTBheHg_1 person +ctJATSvGLTo_0 elephant +ctJATSvGLTo_4 elephant +ctJATSvGLTo_1 elephant +ctJATSvGLTo_2 elephant +ctK8CQu6Nvg_2 boat +ctLUri8cnqU_0 bear +ctNE8tj4Z18_0 truck +ctOTsI_RZps_1 person +ctOTsI_RZps_0 person +ctPfu5shFA0_0 person +ctPfu5shFA0_1 person +ctRpeLVhC50_0 bicycle +ctWUEkluOFo_0 truck +ctWrHmTAoxw_4 dog +ct24BXc-tWg_0 person +ct8_KhvMuHo_0 motorcycle +ct_TbfWVBQc_0 person +ct_TbfWVBQc_1 person +ct_TbfWVBQc_2 person +ct_TbfWVBQc_3 person +ct_vznHYblc_0 airplane +cuHFcWEuUNo_0 skateboard +cuQ5swAtzfk_0 person +cuRuiFR7bNY_0 person +cuU3htRHPgM_0 person +cuWjLEIrs8k_5 bus +D8btdwmdRNU_0 knife +D8sBFUu104g_1 knife +D8urBZQXl6o_0 person +D8wVRKGVcLw_0 dog +D804JptI7_4_0 motorcycle +D8-J5NgmOQg_0 person +D9J-SuKzTU4_0 bicycle +D9RlyV_QhoQ_0 bear +D9WsxKDzM80_1 horse +D9WsxKDzM80_3 horse +D9WsxKDzM80_5 horse +D9XDsr6tkug_0 dog +D9XDsr6tkug_1 dog +D9XwHuLUv_E_0 car +D9ixoNe1mQ8_0 person +D94_XdBnfjQ_0 horse +D97nupvam-4_0 person +D97wkVsbfJk_0 person +D97wkVsbfJk_1 person +D98TSSeEEXc_0 person +D9-PVz9eRtA_0 person +D9-PVz9eRtA_1 person +D-DNyYPMTvE_0 car +D-EA0oKq0qI_0 cat +D-UToJ9lT9w_0 person +D-YgpB48Efg_0 person +D-YtknfK7cQ_0 person +D-a0sdpLGlI_0 umbrella +D-gTVzHdFAE_0 bus +D-gxEOUdm98_0 person +D-jl7sUktcE_1 person +D-pfJT6Nyfo_0 person +D-pfJT6Nyfo_1 person +D-u2wEUntuI_0 person +D--GMbo7meg_0 person +D_FozyNGP_g_0 person +D_OvU_wvmsg_0 skateboard +D_QDxlwnenM_0 bird +D_TbGwH_U4I_0 person +D_XHitiDPXI_0 person +D_XwOiOHuZU_1 person +D_XwOiOHuZU_0 person +D_g7kf5F2CE_0 motorcycle +D_kMPno6xDw_1 person +D_r43ev6HHs_0 airplane +D_uO4kxnCwM_0 train +D_vXQa4wYoY_0 person +D_vxl0ffX4U_6 bicycle +D__WGD95lSY_0 cat +EABbbYMrVPo_0 person +EABxiYRLhro_1 knife +EANBKNPscIU_1 dog +EANBKNPscIU_0 dog +EATgn3uQFCc_0 truck +EAecqVilQ60_0 airplane +EAh-eJriiEM_0 cat +EAlTNLBenas_0 elephant +EAmeB0UClfE_0 person +EAoS9E3JQM0_0 knife +EApLpwcDY04_0 cow +EApLpwcDY04_1 cow +EAvGskBbSsI_0 person +EAvUn45orps_0 person +EAvhz7EUrHs_1 person +EAvhz7EUrHs_0 person +EA2Zq7j78Zw_2 horse +EA33eNV3TsM_0 bus +EA4Pppxm9q8_2 airplane +EA9IwJGPZFo_0 person +EBBWzGDSfhQ_0 train +EBCEcy1RAZU_0 bear +EBDSyGzaeVM_0 person +EBDSyGzaeVM_1 person +EBGwUwk8_KI_0 motorcycle +EBL5WSEhHwQ_0 cow +EBTH0ShVz5s_1 horse +EBYJEkaJizQ_0 truck +EBmABlnU3Ns_0 person +EBpvJEz7GAs_0 cow +EBqxBh52uek_1 person +EBrNePUYA80_0 cat +EB0XdJ6nl5Q_1 bear +EB5sThk9G-k_0 person +EB7yZ9myXmo_2 horse +EB7yZ9myXmo_1 horse +EB-GUW188Kc_0 person +ECDxDS-R1ZU_0 train +ECEv0inW5Cs_1 dog +ECKwTK9kBHk_0 cat +ECLYb63wsdY_0 person +ECT7_2qKJJw_0 person +ECUpMJzxafs_0 person +ECXdLGCGSRU_1 person +ECdvMn526ho_0 skateboard +EChWuqD2kxc_0 person +ECofUr-jIIU_0 person +ECpmJNOAfZU_0 person +ECuo32_WqfU_0 person +EC0Q7uMrJh0_0 cow +EC1pupdSC2Y_0 person +EC-RADUn0SA_0 skateboard +EC-RADUn0SA_1 skateboard +EDBYWaa97hs_0 person +EDUY2xl1Jkw_0 cat +EDYGYkJTUAw_0 person +EDZ9Cu6WUAU_1 horse +EDcpyGbwAVs_1 train +EDcpyGbwAVs_2 train +EDqFOrLwfpE_0 elephant +EDqFOrLwfpE_1 elephant +EDrX2_SzLF8_0 elephant +EDtN3eOjUXg_1 motorcycle +EDvdnYUw9b0_0 person +EDxj4RwQr7k_0 truck +EDxj4RwQr7k_1 truck +EDxj4RwQr7k_2 truck +EDxj4RwQr7k_3 truck +EDxj4RwQr7k_5 truck +ED-QWlNA_QI_1 person +ED-QWlNA_QI_0 person +EEFgTj2V6IY_0 person +EEMkBuPFopc_0 person +EENkey7gvFA_0 cat +EENyo-VOtiA_0 person +EEQVWkmTS6A_0 person +EEQVWkmTS6A_1 person +EEfWTq58rX0_0 motorcycle +EEfWTq58rX0_1 motorcycle +EEiUwF9ID5k_1 elephant +EEiUwF9ID5k_0 elephant +EEiUwF9ID5k_2 elephant +EEiUwF9ID5k_5 elephant +EEnpnVNwpgk_0 person +EEnpnVNwpgk_1 person +EEn1JwzcH7Y_0 person +EEtv5FqPqG0_0 motorcycle +EEx5nPfhJdI_0 bear +EE5owiH92Io_0 bird +EFHnwo5U2Bc_0 bird +EFHnwo5U2Bc_1 bird +EFTcDwwNw_M_0 person +EFd6XVMNdEk_0 umbrella +EFpWVH06Tf4_3 motorcycle +EFpWVH06Tf4_1 motorcycle +EFpWVH06Tf4_2 motorcycle +EFryCLs5aWc_0 person +EFwar_GkK6Q_0 cow +EF0hPkNXnoA_0 skateboard +EF1htFUPo80_1 bus +EF23dhLqzKk_1 person +EF23dhLqzKk_0 person +EF4KGrH7s08_1 train +EF4KGrH7s08_2 train +EF4KGrH7s08_0 train +EF8PHVKHaq8_0 person +EF9VafNyS20_0 person +EGCQIKdLkIU_1 train +EGHYSrxI1Ek_1 person +EGIhtnFv2f4_0 person +EGI5Yk7IU8s_0 boat +EGOtOZyUpk4_0 train +EGOtOZyUpk4_1 train +EGOtOZyUpk4_2 train +EGZ7-ChFJQI_2 knife +EGd19Lwe3vM_0 person +EGgvoXoby8c_0 person +EGgvoXoby8c_1 person +EGiEfcahLzY_0 person +EGsRldGZ4Bc_4 truck +EGsRldGZ4Bc_5 truck +EGsRldGZ4Bc_0 truck +EGsRldGZ4Bc_1 truck +EGsRldGZ4Bc_2 truck +EGvzZJ10zwQ_0 train +EG7cF7KMqs8_0 motorcycle +EG-A5-_1i-o_0 car +EHD613XdEQc_0 person +EHMEQV26qfk_0 boat +EHUgk_5vbps_0 horse +EHafuO8IcpI_3 bird +EHcP0uDfEyE_0 umbrella +EHft6kH6siE_0 person +EHft6kH6siE_1 skateboard +EHtU4jYmFWw_0 elephant +EHvP9Bwmq7M_2 person +EHvP9Bwmq7M_0 person +EHvP9Bwmq7M_1 person +EHv9RwkIPXM_0 skateboard +EIIC6lIbxO4_0 cat +EIRbrmP8N9U_1 elephant +EISmAs76j_g_0 train +EIUHtk1IdtA_0 cow +EIcGpS1nsXk_6 elephant +EIcGpS1nsXk_4 elephant +EIdaSifBFgk_0 person +EIdaSifBFgk_1 person +EIe7fhZxKpQ_0 person +EIe7fhZxKpQ_1 person +EInkqD_T5Os_0 train +EIwa8hvMQ9g_2 bicycle +EIwa8hvMQ9g_0 bicycle +EI8OMIBxEOo_0 person +EI-G2_K6zus_0 person +EJE1AAlhjcQ_0 person +EJE2EqHSaLA_0 airplane +EJJefx2O7lo_0 person +EJJ0aK1Mefo_1 bird +EJMke8tdD9c_0 person +EJMp6Gszq8M_0 person +EJM15lQ1nds_0 bus +EJM15lQ1nds_1 bus +EJNv-W_Wh3s_0 airplane +EJNv-W_Wh3s_1 airplane +EJOO-gnqZOQ_0 person +EJQZBc87T7Q_0 person +EJTbpxYS19w_0 person +EJdJUArfCgA_0 person +EJdJUArfCgA_1 bicycle +EJ2XL046J4A_0 person +EJ3IJ7_jx0s_0 knife +EJ3IJ7_jx0s_1 knife +EKDm7Y7dQ-g_1 bird +EKETFVqhfZI_0 person +EKOgJfGpWw8_0 horse +EKPKBwGLkg0_0 person +EKR2BQWkMTI_1 person +EKf-TzUsoG8_0 person +EKsbh9eVG0w_1 airplane +EKv1nvgLQLc_0 motorcycle +EK2VY_FFN04_0 person +EK56Obpu5ME_0 elephant +EK56Obpu5ME_4 elephant +EK5-ZuOavbM_0 train +EK5-ZuOavbM_1 train +EK5-ZuOavbM_2 train +EK7wRGel2vk_0 person +cuXky9bc80o_1 elephant +cuXky9bc80o_3 elephant +cuXky9bc80o_0 elephant +cuYker921kg_0 person +cuZPt_f2GfE_0 person +cusvncJOcwQ_0 horse +cu0Z8d-ioZA_0 airplane +cu_YsyYcbL0_0 cat +cvBKWYZidIs_0 person +cvFAAQuXQR8_0 person +cvJuXsDfcUY_0 train +cvUktXqTBBA_0 car +cvUktXqTBBA_1 car +cveuhB6Z_D8_1 bicycle +cveuhB6Z_D8_6 bicycle +cvfI6ccn-J4_0 person +cvgZ-1Uaigk_0 person +cviAzkIEA00_0 skateboard +cvlOlYpovm8_0 person +cvyLalOdUEY_0 person +cvyTQ9oFD8s_0 elephant +cv9PMwKXLoA_0 person +cwBgT8f3504_0 person +cwB99KCLazI_3 person +cwEuIwecOZA_0 car +cwHQZi15U3s_1 bear +cwHQZi15U3s_2 bear +cwKndGwjXho_0 person +cwKndGwjXho_1 person +cwPtR7LsWag_1 person +cwPtR7LsWag_0 person +cwTq-wB6R3U_0 skateboard +cwe2t4eoAs0_0 person +cwf1OksNfQ0_1 horse +cwjK5oxoq5Y_1 person +cwjK5oxoq5Y_2 person +cwmY9UYaukc_0 person +cwnltT3Eelo_2 bicycle +cwp0G17bk0I_0 truck +cwp8Oe0F6y0_0 truck +cwsLz_ppMx8_0 truck +cwsx0Rs732s_0 person +cwyDOlWxH00_0 bus +cwzHLMKmpWM_0 horse +cw054hU6MdM_0 person +cw4vlk-0siU_1 boat +cw45Y0beNG4_0 bus +cw55i8mKHnE_0 person +cw55i8mKHnE_2 person +cw57dOs_v5A_0 bear +cxAcLoLkk2g_0 person +cxJp5-r_mjQ_0 person +cxLrrWl89wo_0 person +cxMcoeT1INo_0 person +cxQENdEkIVQ_0 skateboard +cxSj2n8O4Vk_0 person +cxUXpTWO4iY_0 train +cxbTIQtmtLs_0 person +cxiI7jApblc_0 boat +cxkH0GxPEqU_0 motorcycle +cxm8wGi_pl4_0 person +cxsitsK8l9w_0 horse +cxsitsK8l9w_1 horse +cx0cCIp1KeU_0 person +cx0cCIp1KeU_1 person +cx0tj_0g0-k_0 person +cx2bUajKTrw_0 person +cx4EC6uXkkY_3 boat +cyBgPXda4lw_0 person +cydwQgvjXlk_1 person +cyd0m3k4Iv8_0 cat +cynwjNSXfDs_0 elephant +cyz45rMhH9E_0 person +cy4xwLUwDN4_0 person +cy4xwLUwDN4_1 horse +cy4xwLUwDN4_3 horse +cy5IjIQ0UNQ_0 motorcycle +cy58Sr7mA_Q_0 knife +cy6woAEQ0aU_0 knife +cy8BRHRLKa4_0 train +cy9CeQwHsws_0 bird +cy9kq-lD2Q8_0 skateboard +czD_BiifXv4_0 knife +czLen_XZrRo_0 horse +czUjYoRVVYw_1 horse +czec9DaQ1sQ_0 person +cze3sm-N48s_0 person +czjU6Q4s1jc_1 person +cznO_APZ6xQ_0 bear +czpxbOFiY_Q_1 person +czpxbOFiY_Q_0 person +cztHS4laeBQ_1 bicycle +czto2OaEIww_0 person +cz0dXFpjC6o_6 bear +cz0dXFpjC6o_4 bear +cz0dXFpjC6o_5 bear +cz5kAZB6n0k_3 bear +cz6eGvs1xNE_1 motorcycle +cz8sE1Vn4Gw_0 person +cz83QPHVLnk_0 umbrella +c0GrJULqad0_0 person +c0GstZDjoNM_0 person +c0IYOMYovRo_1 person +c0J3zJ8n3SI_0 horse +c0LibLcues0_0 bear +c0MEfCeuV5U_0 bird +c0MdSWVdmqY_0 bus +c0PyfX2HFqE_0 person +c0TJZWOz78g_1 dog +c0XKBQNwSlg_0 truck +c0aHKGTYgeo_0 person +c0bZsiE4obs_0 horse +c0jq_aReY5M_0 motorcycle +c0kH2qIyG7E_6 horse +c0kH2qIyG7E_4 horse +c0lBfqi79wQ_0 cow +c0lDR6ABjTE_2 person +c0nRMc9KiiQ_0 dog +c0nXpd7yJsk_0 person +c0o_nv0BL6Y_1 bear +c0pzN4lVApI_1 person +c0qkbu5wLF8_0 elephant +c0qkbu5wLF8_2 elephant +c0wve_629pA_0 person +c0yrclVs1YA_0 cat +c02KdAN0Hwg_0 bird +c04Vd9VQao8_0 person +c04ixznYflE_1 giraffe +c07Yqknz4KI_0 train +c07k0EtqcVs_1 car +c08cFHAOc7I_0 train +c0_M6VhGXOo_0 person +c0_M6VhGXOo_1 person +c1JGF-ltiJ8_1 bicycle +c1JGF-ltiJ8_2 bicycle +c1PUETYl8Lk_0 airplane +c1QAgByBiYE_0 person +c1WZ6dEz6kw_0 airplane +c1XMeGkSwJQ_0 person +c1XfiRiOTb0_0 horse +c1a_E7CZsVk_0 person +c1djg96PnM0_1 person +c1djg96PnM0_0 person +c1hBqL_LWE0_3 bird +c1j8TlZsEmQ_0 boat +c1laLoj4fM8_0 person +c10eOkpL080_0 person +c10eOkpL080_1 person +c2B7cQwr4Pk_0 person +c2EIdJJnku0_0 motorcycle +c2E5_n_bZKc_0 train +c2Kh-3yj9Ak_0 person +c2MTwEvPGGk_0 person +c2MUYY-qPhA_1 bus +c2MqPrUNXQ4_0 train +c2UDI136z20_0 elephant +c2UDI136z20_4 elephant +c2UDI136z20_5 elephant +c2UDI136z20_7 elephant +c2YlmT-aFE4_0 cat +c2a9uwUCFK8_0 cow +c2dk3AjUcYs_0 person +c2gJYqYcsZg_0 person +c2luSxdPZ6A_0 person +c2m_PmRSEmw_0 elephant +c2qJhOvlIUU_0 airplane +c2xTBZttrzA_0 person +c22HGSTHjBA_2 knife +c22HGSTHjBA_1 knife +c22yvcXZcM0_0 bird +c2_qHguvZbI_2 bear +c2_qHguvZbI_0 bear +c3E9z6F-Txk_0 train +c3J2U0kR6Hg_0 person +c3TisGCbmoU_1 person +c3Ur6j05SgQ_1 bicycle +c3YFgnDBuXw_0 person +c3bCGnwqGxc_0 car +c3eo0_ftrn4_0 cow +c3pP__Uybq8_0 person +c3wt1MUbgD4_0 person +c3wt1MUbgD4_1 person +c37EOoRHd7E_2 truck +c4A01X82TfI_0 train +c4FmSUmvYbo_0 person +c4FmSUmvYbo_1 person +c4Hh2XdTBGY_0 cow +c4ICOFVvcTs_0 person +c4e-qA4esVY_1 person +c4iCXPdqm6c_0 elephant +c4jbOCZyGsQ_0 person +c4k8Yk1x3H8_1 person +c4k8Yk1x3H8_0 person +c4xRJS9_5Fk_0 train +c4xRJS9_5Fk_1 train +c40Mwg88VJI_0 person +c43ihGsR1eA_1 person +c5AKIs1XUhc_1 bicycle +c5AKIs1XUhc_2 bicycle +c5AKIs1XUhc_3 bicycle +c5BYdZTaBgc_0 person +c5CmxgLHcxA_0 bus +c5Fw-Fi4daE_0 cow +c5GANV8PlSM_0 person +c5GIQcIJ9Tc_0 truck +c5GOwfkZXFk_0 person +c5GOwfkZXFk_1 person +c5Q2ZeMDx3o_0 train +c5TlkWtFymE_3 dog +c5WT0W8SfGg_0 cow +c5WT0W8SfGg_5 cow +c5WT0W8SfGg_1 cow +c5WT0W8SfGg_2 cow +c5WT0W8SfGg_3 cow +c5WT0W8SfGg_4 cow +c5cooFy7-SM_1 elephant +c5hEygqOXOU_0 person +c5oiA5xy15M_0 person +c56nid2YSes_6 bird +c56nid2YSes_0 bird +c56nid2YSes_1 bird +c56nid2YSes_2 bird +c56nid2YSes_5 bird +c56nid2YSes_8 bird +c56nid2YSes_9 bird +c5_dNG2vWXg_0 car +c6EIognIYWs_0 bird +c6ZQRNXfcZA_1 person +c6a4xySAJ0o_0 truck +c6niMRNXDeo_0 person +c6qKbpvd-iw_0 person +c6rbqnU4LXs_2 motorcycle +c6rbqnU4LXs_0 motorcycle +c6s839WnVhE_0 truck +c6yBOD3Wo5A_0 person +c7B-3x-3V34_0 person +c7ILC5wYs8A_0 person +c7KoGv5Ha7k_0 person +c7PMPnuPjp8_0 person +c7RFexe2Ba4_1 bicycle +c7RFexe2Ba4_3 bicycle +c7RFexe2Ba4_0 bicycle +c7RFexe2Ba4_2 bicycle +c7SMRurbkY4_0 bus +c7bKlPVR5pI_0 boat +c7hVbIhp0Wc_0 person +c7jWXqWoMz0_4 bicycle +c7s8weR8lEY_0 person +c7v4ZFCK-A4_0 person +c70kaPblMLU_0 cow +c74hYNtpwdA_0 dog +c75cllxWxZE_0 person +c7_op6G05l0_0 airplane +c8B4ZVLv364_0 person +c8Cl-5olqWk_0 motorcycle +c8Gaja-xUeQ_1 person +c8I3JAxoLTs_0 bicycle +c8I3JAxoLTs_1 bicycle +c8I3JAxoLTs_3 bicycle +c8LHqWmKrJU_1 airplane +c8LHqWmKrJU_2 airplane +c8Mo16hH7qs_0 person +c8UrmdREAO8_0 person +c8Y7MJRWFqE_0 cat +c8Y8y9BsPHw_0 cow +c8b9qqF9Xvw_0 person +c8b9qqF9Xvw_1 person +c8ezNTNUXqc_0 cat +c8wbvQnndJc_1 bicycle +c8wdGQw1jB4_1 bus +c8wdGQw1jB4_2 bus +c8y3bmW0X9s_1 cow +c8zphqgYcJM_0 person +c80SYyKXCCw_0 person +c8_fHVnrzZ8_2 elephant +c9EDbgCRGP0_0 person +c9GKsfyRkmE_0 person +c9IdrMV-Y_Y_0 person +c9Q9LPaqyug_0 umbrella +c9SbfXgAoO8_1 airplane +c9Somjq2gLs_0 umbrella +c9WDXLFtYLU_0 bus +c9XaEHVxu4M_0 person +c9Y9a6KVWRE_0 bird +c9Y9a6KVWRE_1 bird +c9ZWCwVv6Q0_0 person +c9dPiEkCwR4_0 motorcycle +c9gCDztKasg_0 elephant +c9pYz2lTh3I_1 person +c90ldeMSfL0_0 cat +c94gzpjmj24_0 person +c9_87BKOW1I_0 cow +c-CCw_cyicE_0 cow +c-G0LV4kyY0_0 car +c-T9ITcEW9c_0 person +c-T9ITcEW9c_1 person +c-ZnwBvVFGE_0 person +c-gH6T1q-sk_0 person +c-pKAy_3arM_0 person +c-uOjPSq-10_0 cow +c-vwn6zqogs_0 person +c-vwn6zqogs_1 person +c-4uPwFKBdY_0 person +c-_iMD-ihnE_0 motorcycle +c-_94CuEo_M_1 person +c_SQI7NirwY_0 person +c_THUYYi_-k_0 airplane +c_YojhaB5pI_0 motorcycle +c_jNM33kJuA_0 person +c_rUQgBtHY4_0 person +c_rUQgBtHY4_2 person +c_rUQgBtHY4_1 person +c_wkIYzEEDk_0 dog +c_6OcDyZ93k_0 bus +c_9GO2BbPz4_0 horse +dAQu2GQSyrY_0 cat +dAS6SqC7TCw_1 elephant +dAVIZQJ5Af4_0 person +dAqurx13i7I_0 knife +dAynVVxxb_o_0 person +dA7mx3mrJeA_0 train +dA_ZtitJeMA_0 person +dBDSqZ8rirA_0 person +dBGKqrEvsIE_0 boat +dBGKqrEvsIE_4 boat +dBKexOUQSQA_0 cow +dBKexOUQSQA_1 cow +dBKexOUQSQA_2 cow +dBKexOUQSQA_4 cow +dBKexOUQSQA_5 cow +dBKexOUQSQA_6 cow +dBOrrvJDv54_1 skateboard +dBPu5iVlw1Y_2 horse +dBSryinfjiI_0 person +dBS9maEElcw_0 person +dBUpfcdFDUQ_0 bicycle +dBWeUQd06l4_0 person +dBWeUQd06l4_1 person +dBiGneGqmh0_0 cow +dBk2FwZgrtk_0 cow +dBq77lvujCk_0 bird +dBuvGegR_vA_0 person +dByVvpTlwL4_1 knife +dB29dsCcN9s_0 train +dB43vSgLY2M_0 person +dCG24UL_NeM_0 person +dCSF80Y6lso_0 person +dCSF80Y6lso_1 person +dCZ9suBocXk_0 person +dCgz-7OgwMQ_1 person +dCl8hSleXYQ_0 cow +dCoi3rXWgbM_0 person +dCqdvmS1jts_0 person +dCqdvmS1jts_1 person +dC9rTC3kzsI_0 cow +dDADJZV4i74_0 horse +dDA5p5TJ03g_0 person +dDB84W_zVOI_0 skateboard +dDB84W_zVOI_1 skateboard +dDE3p8Gs878_0 elephant +dDGiQLFJtPs_0 bicycle +dDIbBZtEJ2w_0 knife +dDLgQQ2XRc8_5 horse +dDLgQQ2XRc8_3 horse +dDLgQQ2XRc8_6 horse +dDO-RlSt3Gw_0 person +dDQ58wciink_0 cow +dDZYTPEd9KE_1 airplane +dDacKPH4sOw_0 car +dDacKPH4sOw_1 car +dDcBtNpmCeU_0 person +dDgcHWpKMeo_0 person +dDkaPLEvAwM_0 horse +dDkaPLEvAwM_1 horse +dDkaPLEvAwM_2 horse +dDqe9sBGR24_0 bird +dDx0MqaKT2w_0 person +dDx0MqaKT2w_2 motorcycle +dD-AlVwxf-g_1 cow +dD_Ew85jXzk_1 train +dD_PbxvCBcA_1 person +dECTTSpEUKg_0 person +dEW9ZwvMsDE_0 cat +dEc5fHlEXCo_0 truck +dEuzpQL0tNo_7 elephant +dEuzpQL0tNo_1 elephant +dEuzpQL0tNo_2 elephant +dE7OwbOHsu8_0 person +dE7WsfeVkI8_0 person +dE7X93gdVPQ_0 cat +dFCUyBTrvNM_0 horse +dFCu7E6aYM4_0 person +dFCu7E6aYM4_1 person +dFEo5YKHAcA_2 skateboard +dFEo5YKHAcA_0 skateboard +dFMPz16FOzE_0 motorcycle +dFZSSPvMBqE_0 zebra +dFZSSPvMBqE_1 zebra +dFa7TcQRCUU_1 bird +dFbZxetmjCQ_0 skateboard +dFkNDweVNFU_0 cat +dFpJq9s5fec_1 bicycle +dFpJq9s5fec_2 bicycle +dFsDjjWW00Q_0 knife +dFth5-8MEhM_0 person +dF7OkxFt3I8_0 person +dF_aGgW1jcM_0 person +dGE7t6KgXHc_0 person +dGFrWX61Zk0_0 person +dGS01inQU1U_2 person +dGS01inQU1U_0 person +dGS01inQU1U_1 person +dGZBUkIXMpo_0 person +dGZ_pzDrl70_0 person +dGdh_BHleU4_0 boat +dGh51ZQ9QAg_0 bird +dGk8D_De-2E_0 person +dGk8D_De-2E_1 person +dGpbPaorWys_1 bear +dGq1bpRxbiA_0 person +dGyR5TWO-p4_1 person +dG0CtnphYzg_0 person +dG5mjfvTY7c_0 boat +dG7DSOtetMY_0 knife +dG9J5UpxeyY_0 person +dG9J5UpxeyY_1 person +dHCgtjlT_Lg_4 horse +dHCpH8dTwfw_0 horse +dHF9NIqrx6Q_0 car +dHGIXivupi4_0 person +dHGIXivupi4_1 person +dHGIXivupi4_2 person +dHJkOetpjQw_0 bus +dHO6vTrB66w_0 person +dHO6vTrB66w_1 person +dHVDjpivOKw_1 person +dHVDjpivOKw_0 person +dHVgQCO07SU_1 person +dHVgQCO07SU_2 person +dHfs5GT-YpY_0 cow +dHg1Xorklm0_0 person +dHimuOjriUc_0 cow +dHnk6ulSNSo_0 person +dHnsZs2Riqk_0 person +dHnsZs2Riqk_1 person +dHsD3F8dTpc_0 bird +dHvlIrb2Q-k_0 person +dHwR5d4xGEk_0 knife +dHwR5d4xGEk_1 knife +dHwR5d4xGEk_2 knife +dHwR5d4xGEk_3 knife +dHwR5d4xGEk_4 knife +dHxmY1bGbNc_4 bird +dH89qyunr6s_0 person +dH94i4xFlZU_1 elephant +dH94i4xFlZU_6 elephant +dH94i4xFlZU_0 elephant +dH94i4xFlZU_5 elephant +dH94i4xFlZU_7 elephant +dICl73jYZ3M_0 person +dICrafh45_I_3 airplane +dIDxqrhmBE4_0 truck +dIDxqrhmBE4_2 truck +dIEZ2kfTzzY_0 boat +dIJk0w4SnH8_0 bird +dIVtaleUNWI_0 person +dIVtaleUNWI_1 person +dIX81Ov0fUY_0 person +dIZM-9d8bSQ_0 person +dIZM-9d8bSQ_1 person +dIm0Sv_iE2E_0 motorcycle +dIqYGVVgYsU_0 person +dIzMmAGaF6U_1 skateboard +dI93uXfSaRM_0 bird +dJB-DXpgq2U_1 bird +dJKAhixNM9Y_1 truck +dJYNs94fv_0_0 person +dJgqX3uy6z4_0 person +dJg4R9cpbjI_0 person +dJisrPH71tE_0 person +dJi_dOrUZnw_0 person +dJjrFTy9H3c_0 person +dJkzzYh6BkY_1 cat +dJnRg-1zO1g_3 knife +dJqGj0FeC9I_0 cat +dJvoaqZjIDw_0 person +dJ2B9A0mYl0_1 dog +dJ2kWscI-tc_1 dog +dJ4PR9zme-s_0 person +dJ6S9bSEYDc_0 cow +dJ8J7WOLZtk_0 skateboard +ELDxjZXMtCg_0 person +ELLTxQ47f90_1 person +ELLTxQ47f90_0 person +ELNgTt9Jswc_0 train +ELOZutiZKMM_0 person +ELOZutiZKMM_1 person +ELPpy9ABb3s_1 elephant +ELTeW4X2mGY_1 cow +ELbg8i93W8I_0 person +ELbjX2Ya0_o_0 dog +ELmktutrkDk_0 person +ELqA6fb0un8_0 person +EL8H94Lycf8_0 person +EMAVfcO6JFE_0 person +EMKcTJp7ehY_0 person +EMOpCv3vVfE_1 skateboard +EMP7p3FNxZU_0 person +EMU8vGL7ZFQ_0 person +EMb28oLn66k_0 airplane +EMgh3pwtnXg_0 person +EMiRla730lM_1 person +EMiRla730lM_0 person +EMmg9OKgyBE_1 boat +EMmmZ6ADzfI_0 skateboard +EMngQ4YMTv0_0 motorcycle +EMorunu9Ik8_0 truck +EMqd3lVNUxg_7 bus +EMuGAIADn3s_0 person +EMwcDTRPPMw_0 airplane +EMyQWQ_Yobc_0 dog +EM0yGxKJWqY_0 elephant +EM1R3HXt7DY_0 person +EM1z9o601v4_0 knife +EM3tBaIyR0o_0 motorcycle +EM5e1snhsCs_0 person +EM-k8ZAva6k_0 person +EM-zjCQyGAc_0 dog +ENAr6j6fcWU_0 bird +ENCHiWUV4dk_0 person +ENI-JuSPNQA_0 motorcycle +ENSEWig-4ZM_0 knife +ENXXFcrrxGM_0 car +ENc0uxXKsaI_0 person +ENkqstdLKl4_0 person +ENk4JRIbEaE_1 person +ENnPjtPjU6c_0 person +ENtoAci6OwQ_0 cow +ENvdCzm4whM_0 truck +ENvdCzm4whM_1 truck +ENvdCzm4whM_2 truck +EN0Klsi-AKY_0 bicycle +EN4IIJjhBeI_0 zebra +EN-QCSvtEd0_3 elephant +EN-4SsZnn-k_0 person +EOEXVXG1TDk_0 person +EOVNlasJhIo_1 person +EOdHjLYopi0_1 bird +EOedzXaVI4U_2 bird +EOe3CfOT53g_0 person +EOmVKXeoKBc_1 airplane +EOq-3ZRn0SQ_0 skateboard +EOt6j5ecODw_0 train +EO7NccQDQyM_0 cat +EO8Dpvy4oXs_0 zebra +EO8mQrkIZuY_0 person +EO_DwtyWh0s_3 person +EO_DwtyWh0s_0 person +EO_DwtyWh0s_1 person +EO_DwtyWh0s_2 person +EPOXqdKNjKg_2 giraffe +EPU630RSI5c_2 person +EPU630RSI5c_0 person +EPWmdYKJaXk_0 bird +EPycDWf2vY4_0 skateboard +EP_ezteElzk_0 person +EQBFPIdI8gY_0 person +EQC8eEghvs8_0 person +EQNSjjkyRBg_0 person +EQNSjjkyRBg_1 person +EQTee9qqTZs_0 person +EQVCizuJQFY_0 umbrella +EQdEm5HuPG4_5 train +EQx1XHc0mRM_1 motorcycle +EQzXCoQRbas_1 train +EQ5rBLoiT78_0 bus +EQ9-lbsee1s_0 person +ERCvzMzkDhg_0 skateboard +ERGwo6vIXdQ_0 person +ERJR-zQYyH4_0 person +ERR-qjVJ3lY_0 person +ERVp_cX1juc_0 person +ERev6rrd5XA_3 motorcycle +ERyyYMb2fFk_0 cow +ERzh41uuxUE_3 bicycle +ER0IdSeymeI_0 person +ER0IdSeymeI_1 person +ER03PLUBt4c_0 train +ER03PLUBt4c_1 train +ER03PLUBt4c_2 train +ER03PLUBt4c_3 train +ER53sUYwz1I_0 zebra +ER6vMbAyQ6E_1 skateboard +ER6vMbAyQ6E_0 skateboard +ESDQMC_70Pk_0 bear +ESInVf3ioiA_1 dog +ESMdbpGXk4I_0 person +EST4CUX19Eg_0 person +ESokfN84OYk_0 elephant +ESokfN84OYk_3 elephant +ESokfN84OYk_4 elephant +ESpwZsbwQGA_1 elephant +ESpylyha7g0_0 horse +ESt5TEXuGIM_0 person +ESt5TEXuGIM_1 person +ESwsyjITYGM_0 skateboard +ETBia7K3ZHw_0 motorcycle +ETBia7K3ZHw_2 motorcycle +ETQTZgnfRK4_1 person +ETQi93bP3YQ_8 elephant +ETQi93bP3YQ_2 elephant +ETTgj1pxvME_2 person +ETWI4nXFANg_0 person +ETcmjY7Jigo_1 motorcycle +ETgN7EcVVQI_1 person +ETmYIq5CF2k_0 motorcycle +ET4xC8Wl_CA_0 person +ET4yAsJTvlk_0 cow +EUH3oSBX950_0 person +EUH3oSBX950_1 person +EULIYiiV-O0_0 person +EULIYiiV-O0_1 person +EULchAlLDfM_0 train +EURUU5P5flo_0 person +EUcHraiUCjA_0 bicycle +EUcWvzarnb0_0 umbrella +EUdNEi4myuA_0 person +EUtfoblvHn0_0 person +EUuCDfb8lf4_2 person +EUuCDfb8lf4_1 person +EU93Mw9WGkc_0 skateboard +EVBHY1qGVos_0 person +EVBHY1qGVos_3 horse +EVElggpPSCM_0 elephant +EVE2SBJ-2S8_0 person +EVH8Ql7_pYE_0 person +EVTW6Ka7-NU_0 person +EViJ_JQcv5c_0 train +EVmGPGaP6bY_0 person +EVnnSfmb4go_0 giraffe +EVn52FBjG9E_0 person +EVn52FBjG9E_1 person +EVxEEc26TWg_1 giraffe +EWLiwu56oQc_1 person +EWNd02yWiYw_0 person +EWP0Hhxsf58_0 person +EWQo_1YXfYM_1 person +EWQo_1YXfYM_0 person +EWTvjjpAUm0_0 airplane +EWXyQ1tS3jI_0 elephant +EWdNgXvr54s_0 dog +EWfPRTjQO9k_0 dog +EWgsivaLhl0_6 elephant +EWgsivaLhl0_1 elephant +EWgsivaLhl0_2 elephant +EWi25l2D0cw_0 cat +EWkndzLXvLc_0 bicycle +EWuOSRFWTzg_1 elephant +EW0Mgele6Gc_0 person +EW0Mgele6Gc_1 person +EW6FHYagN0Y_0 person +EW98OEvTxM8_0 person +EW-Zuo7ArI4_0 dog +EXDDO7gLoL4_1 person +EXDDO7gLoL4_2 person +EXDDO7gLoL4_3 person +EXDDO7gLoL4_4 person +EXGwKMtyR1M_0 person +EXHZgqkcXG8_1 cow +EXJITC62tU4_0 umbrella +EXSMz4HnWfg_0 dog +EXaiYiUQrMI_1 dog +EXfiGeKWKTk_7 airplane +EXfiGeKWKTk_1 airplane +EXiGyq1TD80_0 person +EXiGyq1TD80_1 person +EXkbZbo1n5U_2 elephant +EXkbZbo1n5U_0 elephant +EX817S50E5U_0 person +EX-dqihLUwY_0 motorcycle +EX-dqihLUwY_2 motorcycle +EYCaJR9md8k_0 airplane +EYEWPdaJuL0_4 bird +EYEWPdaJuL0_5 bird +EYEwLM8YTwc_0 person +EYFMOBeF9UE_0 knife +EYHtNGztiRQ_1 car +EYKrEDelAdU_1 bear +EYM1oXAmBq0_1 bus +EYRf00qGMVU_0 train +EYV6D6G6t2c_1 person +EYZsYCSedGw_0 person +EYd9lSK7Bbk_0 person +EYhtY59whvs_0 person +EYmWVBDEutA_0 horse +EYnEMtlMaPY_0 person +EYoj8D64YLA_0 skateboard +EYuLodJTgYs_0 train +EY2pZ9A48ng_0 truck +EY2pZ9A48ng_1 truck +EY2pZ9A48ng_3 truck +EY25PJWD2j4_0 person +EY36YeIgOYI_0 person +EY36YeIgOYI_1 person +EZWcsRlXIA8_0 person +EZbOH9yEe-A_0 dog +EZh1lf4yfCg_0 person +EZ5Wa2duCoM_0 person +EZ5Wa2duCoM_1 person +EZ7d9ab31ys_0 giraffe +EZ9-_7o9Vds_0 bird +EZ9-_7o9Vds_1 bird +EZ_xC5EBwvk_0 bus +EaBdeSUjDYs_0 dog +EaFSd7_S8kc_0 horse +EaQ1P4QyRsY_0 person +dKEVBoMMD2w_0 boat +dKJz_EakSc4_0 person +dKMb2S2SSfI_0 skateboard +dKTgMjbnNPQ_0 skateboard +dKiwficH2d4_0 person +dKi4xI4vB-k_0 umbrella +dKlCFQxk5Dc_3 person +dKlCFQxk5Dc_5 person +dKlCFQxk5Dc_0 person +dKlCFQxk5Dc_1 person +dKlCFQxk5Dc_2 person +dKq4S1IVjlA_0 person +dLFWcgSewxs_0 truck +dLH8fBNk89Y_0 cat +dLIld9ux7p4_0 airplane +dLT61O_htwI_0 cat +dLUCKkji5wo_0 person +dLUCKkji5wo_1 person +dLV2VJkpyMI_0 airplane +dLbhzrFtNC0_0 person +dLhVV7DMXkw_0 person +dLoxdmLuphk_0 dog +dLq5OW1xY54_0 elephant +dLq5OW1xY54_3 elephant +dLq5OW1xY54_2 elephant +dLtQB9P_7BU_2 bear +dLty27VgJcc_0 train +dLvr7BjgsHg_0 person +dLwXzYr8beg_0 car +dL3dSZMnBko_0 person +dL3vGWsRVCg_0 knife +dMDGwTdSHIo_0 motorcycle +dMJQi7oYiqQ_1 person +dMS5hB4uWdk_0 bird +dMWgiVqknaE_2 person +dMWgiVqknaE_0 person +dMZONdbNFbk_4 bicycle +dMZONdbNFbk_2 bicycle +dMdUZi9lxrU_0 cat +dMiwR-DS6UE_0 car +dMsIDwHkWNE_0 person +dMulBz-N8oA_0 horse +dM7lOj89YZE_0 person +dM7-xh2kSmc_0 person +dM7-xh2kSmc_1 person +dM9u0c0qSV0_0 cow +dNCm5MtFcp0_0 person +dNEAY77it7o_0 person +dNShS9OdIoA_1 person +dNShS9OdIoA_0 person +dNSlL572gMU_0 truck +dNSlL572gMU_1 truck +dNVvIPWEH1Q_0 person +dNVvIPWEH1Q_1 person +dNdTs9Qa1A0_0 truck +dNeF_3qppZQ_0 skateboard +dNj_77jiPcs_1 cow +dNknNwahiv4_0 giraffe +dNoz32bgN0U_0 car +dNpQfDg_dIg_0 person +dNqdMh44imM_0 train +dNs2JO9SgGo_1 airplane +dNs2JO9SgGo_2 airplane +dNyMDstraS0_0 person +dN1cn1CPEa8_0 person +dODPVlzMR1A_0 person +dOHuuTREVQk_0 person +dOHuuTREVQk_1 person +dOHuuTREVQk_2 person +dOHuuTREVQk_3 person +dOMW6BLHI2s_0 elephant +dOMW6BLHI2s_1 elephant +dOOQ32tmk14_0 elephant +dORLSKDLr1w_0 cat +dOUVBpTWHzc_0 person +dOVzO5pkY2o_0 horse +dOWhuaTBmr8_0 truck +dOdX5nkOBoQ_1 person +dOdYYCqd6i0_0 person +dOdYYCqd6i0_1 person +dOd-8kfbjz4_0 train +dOd-8kfbjz4_1 train +dOfNevz8wlc_0 bus +dO2CbXVpSl0_0 elephant +dPA7g60qlnk_1 boat +dPJk57_DSuI_0 truck +dPJ7_mdmjJo_4 truck +dPJ7_mdmjJo_1 truck +dPTnDrK0jl0_0 knife +dPZPjPwJCnA_0 person +dPiOaLH0K4Y_0 bear +dPiOaLH0K4Y_2 bear +dPma_hb-MR8_0 skateboard +dPnxUa8yPbw_0 train +dPpwBkl-F9k_3 bicycle +dPpwBkl-F9k_0 bicycle +dPp0no_eYOQ_0 dog +dPqheqisvs8_0 person +dPvgWsIPDr0_0 horse +dP0jXsi0KUw_0 skateboard +dP_-3SJLP1Y_0 person +dQB4GI0Bgus_0 truck +dQCFCRTz2rc_1 giraffe +dQCFCRTz2rc_4 giraffe +dQCFCRTz2rc_5 giraffe +dQCFCRTz2rc_0 giraffe +dQIQv4YkBaM_0 truck +dQI-ReUS1hk_0 person +dQM_-V4jSpM_0 cat +dQNG1syFdKQ_0 person +dQPdAoRj8vw_0 dog +dQWw3losmfA_1 bicycle +dQY2wbSJyOQ_0 person +dQh9dmaqW3s_0 person +dQh9dmaqW3s_1 person +dQlybGW3tbw_1 cat +dQnNTlCD_AQ_0 elephant +dQnNTlCD_AQ_1 elephant +dQoX3OkaI4M_0 person +dQzWZhDVLYk_1 person +dQ4hJadqL_w_0 person +dQ62PlC9Frc_0 zebra +dRBb5v_Fv3g_0 elephant +dRDdBvl4olg_0 person +dRHTO6H764g_0 person +dRHYGXImEBk_2 person +dRHYGXImEBk_0 person +dRInM_HaQZs_0 bus +dRVEs1099F8_0 horse +dRcLZtR6KFs_0 person +dRcrvTR9xIY_0 person +dRiBVua-2Ck_0 person +dRjzvcGshbA_1 person +dRjzvcGshbA_0 person +dRs8FcKuu6w_0 boat +dRt8H1uQ5Og_0 umbrella +dRt8H1uQ5Og_1 umbrella +dR7jBT3cxr8_0 person +dR8kCc9XNJs_0 boat +dR-8FlykNZ0_0 person +dSAODa472ys_0 bird +dSAYK4yUlDs_4 person +dSAYK4yUlDs_0 person +dSAYK4yUlDs_1 person +dSAYK4yUlDs_2 person +dSAYK4yUlDs_3 person +dSEv_R8nQik_0 zebra +dSFMrnh2szI_0 cat +dSLakvIEH9o_0 bear +dSLmBYdUku8_0 person +dSQTVC-RyAU_0 person +dSWhe4RgQ_w_0 cat +dSZBg-Vcr7E_0 motorcycle +dSojBtCOkqQ_0 person +dSx4IloBWZs_0 person +dSzAX5l_fs0_0 person +dSzAX5l_fs0_1 person +dS0mBDDgP_A_0 person +dS0mBDDgP_A_1 person +dS8x0l5I7f0_0 boat +dTDxzi0o_Qg_1 airplane +dTMe2Vse97w_0 cat +dTVBSXs5Me8_0 person +dTVKs9m3eZU_0 cat +dTm_DRCtjCo_0 elephant +dTm_DRCtjCo_1 elephant +dTrt1C_90H0_0 knife +dTurjz-gJek_0 person +dT6A3DwqZb0_0 boat +dT8wudfW9gg_1 horse +dT-INB6puFM_0 skateboard +dT-INB6puFM_1 skateboard +dUAtLBDfmBo_0 airplane +dUAtLBDfmBo_2 airplane +dUC_SF_mN_E_3 horse +dUC_SF_mN_E_1 horse +dUInMUIPtTs_0 person +dUJH8d3CMU8_0 bear +dUMLWt99A7o_0 person +dUP4OTLrOA0_0 person +dUW_G_--wI8_0 train +dUXFUWivXPA_0 horse +dUXFUWivXPA_1 horse +dUbP54CBYd0_0 airplane +dUm9A-1AoMU_0 person +dUqrowFcbD0_0 person +dUx_UfS9cQI_1 dog +dUx_UfS9cQI_0 dog +dU-bQRDInro_2 bird +dU-bQRDInro_4 bird +dVAMoKYgrwE_0 person +dVKQhCF8o8w_0 person +dVTHVxh6Tro_1 knife +dVWAD4gOu-8_1 person +dVd7OzbhOq0_0 person +dViVbA7N_AE_0 airplane +dVqPo7-p71Y_0 person +dVtqTTZTFDQ_0 person +dWCqnck4Um0_0 person +dWFVX1psRZI_0 bird +dWGkW13rQBY_3 horse +dWGkW13rQBY_5 horse +dWGkW13rQBY_8 horse +dWVJFIzIKEc_2 bicycle +dWVJFIzIKEc_0 bicycle +dWVJFIzIKEc_1 bicycle +dWXSWEaCId8_1 person +dWdOl13DwwY_0 airplane +dWdl9RdXrHo_0 person +dWdl9RdXrHo_2 person +dWd0sszZOXc_0 person +dWesodD0ff4_0 airplane +dWgfwKBrSiE_0 person +dWgpYitSv0c_0 person +dWkrnxWB1CU_0 person +dWlDN9Hozgg_0 dog +dWtqRwEurDU_0 person +dW1oE_LHALo_0 elephant +dW4DX7lQoGg_0 elephant +dW5aU0U7K28_0 person +dW53l1sR_zM_0 person +dXEH9QiCyHk_0 train +dXEH9QiCyHk_1 train +dXKi3ZHjgWM_1 umbrella +dXLyWGJxHnI_0 person +dXOsaszlVY0_0 horse +dXSuppGXFeI_0 elephant +dXSuppGXFeI_1 elephant +dXdFEix8vu4_0 train +dXjUZeuzgaw_0 train +dXkmG8AR82Q_2 airplane +dXkmG8AR82Q_5 airplane +dX6W4-sxsX0_0 cat +dX9J6yDM5Q8_0 person +dX-4XwYWv48_0 person +dYGOSaGjHQU_0 person +dYQMrQe1pSk_0 person +dYRIEDyD9Qs_0 airplane +dYRKwU2TJYI_0 elephant +dYVcalOS1SE_0 dog +EacR2o35-kc_0 bicycle +EaeD7utPpTQ_0 person +EakGzU5UgWI_0 person +EakGzU5UgWI_1 person +EakGzU5UgWI_3 person +EamZ8De_WFE_6 elephant +EamZ8De_WFE_0 elephant +EamZ8De_WFE_2 elephant +EamZ8De_WFE_3 elephant +EamZ8De_WFE_4 elephant +EavqjWy5gag_0 person +Eaxszmfn7WA_1 person +Eaxszmfn7WA_0 person +Eay0MFBCdqY_1 horse +EazzsVK1-pM_2 umbrella +EbJV0e75xtk_1 person +EbJV0e75xtk_0 person +EbWt1hAb3LQ_0 person +EbXzlcsBsfA_0 person +EbYJAv5c_G8_0 person +EblX3oKGsBA_0 skateboard +Eb1n2o0YpOM_0 cow +Eb3sGSIWtCw_0 person +Eb7juFDG3Dw_0 car +EcMh5TIKmzY_0 person +EcNpsheyrIU_0 person +EcNpsheyrIU_1 person +EcWrNFz5J-o_1 dog +EcpsBV2FEBE_3 horse +EcsiLHpIvL4_0 person +Ecu8VEIC2y8_2 elephant +Ecu8VEIC2y8_1 elephant +EcvYBldDm_U_0 person +EdE8zCwJ56g_0 person +EdE8zCwJ56g_1 person +EdIfx7lQxEw_1 dog +EdIfx7lQxEw_0 dog +EdOvSD40Tb0_0 cow +EdTkeITBkvY_0 person +EdTkeITBkvY_1 person +EdaY0DFamDc_1 skateboard +EdfKMOIOHtI_0 person +Eds-fi9s-O4_0 person +Ed486SKW0kM_0 train +Ed-ENhlS7Dg_1 boat +EeCjxMzh5_A_0 person +EeDhzR9I-Tc_0 motorcycle +EeLllq2Zim4_0 dog +EeMUemitsFU_0 person +EeRqVkQ1Z7Q_0 car +EeRqVkQ1Z7Q_1 car +EeTRT4j5GcQ_0 person +EeYRHJuK3wo_0 boat +EeYqy9QZZTU_0 airplane +Eeb2vPJsaN0_0 person +Eee6rmiMYKY_1 car +Eesk8VSxpIU_0 cat +EetKMgVh0Pk_0 person +EexaBL5jDL4_0 knife +EexaBL5jDL4_3 knife +Eeyjjk9-BvY_0 horse +Ee7CW7lZfXA_1 person +Ee7CW7lZfXA_0 person +EfE6r-Iq5CM_0 person +EfG_eBrAjdI_0 motorcycle +EfHCZUHt0d8_0 person +EfMCesQKyoE_3 airplane +EfNSTkpl6dQ_0 person +EfSMsLkasg8_1 person +EfjC0VVD2Do_0 person +EfvRGCuPoF4_0 person +Ef1Tm3dKzbY_0 motorcycle +Ef2GKdopP_A_0 person +Ef7-yzJqZto_0 person +Ef9YiYODEbg_0 cat +Ef9q8mAPYZA_0 person +Ef_N7JmICUU_10 bicycle +Ef_5u21WLbs_0 cat +EgDOCraAd64_2 train +EgHVReOnDpM_0 person +EgPKMlxhH0A_0 person +EgPxUnCFS10_3 knife +EgYCBIlDm98_0 horse +Egf4iNTfanU_0 airplane +Egf4iNTfanU_2 airplane +EghxGvj6pTs_0 person +Egl_1FgGUyE_2 bird +EgpSSMkQOEE_0 bicycle +EgxlP5S15uQ_1 motorcycle +Eg6YUwqAQqM_0 person +Eg7bJ46L4Cg_0 airplane +Eg7bJ46L4Cg_1 airplane +Eg7bJ46L4Cg_2 airplane +Eg82FN1vC3A_0 knife +Eg9-5uBMrpc_0 cat +Eg-cp7jgFA0_0 person +EhF73HJvEWo_1 train +EhKAs4Z1JE0_0 person +EhSaOGOPUns_0 skateboard +EhbaW6F3U6I_1 person +EhbuzBK5bes_3 giraffe +EhbuzBK5bes_2 giraffe +EhcmJOG2Jws_0 person +EhfmC9Wa8xs_0 person +Eho09eptX7c_0 person +EhpwK0_8UJA_0 boat +Ehpz_gcdCcY_0 knife +Ehpz_gcdCcY_1 knife +Ehpz_gcdCcY_2 knife +Eh6FARrS1VY_0 skateboard +Eh7f9wgtUns_0 bus +Eh88_JdkWWs_0 person +Eh-x-OzZxGo_0 person +EiE9eIJ-Rv4_0 car +EiLWN5T6wko_1 person +EiNTdTOmvDU_0 person +EiUbGE2f6fU_0 train +EiUbGE2f6fU_1 train +EiZG3M9_EMc_0 bird +EiaYgqLcbqM_2 elephant +EibdBvTND-I_0 person +EibdBvTND-I_1 person +Eine_0RExlI_0 person +Ei1XBJFaUeI_0 person +Ei1XBJFaUeI_1 person +Ei6ZitRjwdA_0 person +Ei7n3944Ovs_0 umbrella +Ei9d8OX0ui0_1 airplane +Ei9d8OX0ui0_0 airplane +Ei9724H_wUs_1 person +Ei9724H_wUs_0 person +EjcMZ8Y0Oeg_0 boat +EjgxtJaNIH8_0 skateboard +Ej2wn6JRBzA_0 skateboard +Ej7xV32Trwc_0 person +Ej8UwQiT5jk_1 knife +Ej8UwQiT5jk_3 knife +Ej_zFc5qxRw_0 cat +EkMGStKSilE_0 person +EkMdmPclE3k_1 dog +EkTrskvsL5c_1 horse +EkWd3wPBEyg_0 airplane +EkawSvsvh3g_0 person +EkdP_pWa9s0_1 airplane +Eke0rATHhX4_0 person +Ekh_cm7q1y8_0 cow +EklOuZWH-8Q_0 motorcycle +EkyydrsMSkY_0 person +Ek1DlGGsUdY_0 umbrella +Ek4323MkRYo_0 bicycle +ElJtz3uv-AQ_0 person +ElLiin7Cda4_1 person +ElLiin7Cda4_0 person +ElNzy4USrLA_0 truck +ElR4MuOUYKM_0 bird +ElgmQr70py4_5 train +Elrxptn-Zqo_0 person +EluRnlB_s6c_0 train +EluRnlB_s6c_3 train +ElwZ1M6McHo_0 skateboard +El2nzuCxrGk_1 horse +El5fRl-4vko_0 knife +El9Efl32L8w_0 person +EmDjVcaznIA_0 zebra +EmDjVcaznIA_1 zebra +EmDjVcaznIA_2 zebra +EmJeLKaG_hE_2 bird +EmJk7hDSzaM_0 person +EmJk7hDSzaM_1 person +EmJk7hDSzaM_3 cow +EmWzmxDjjOs_0 person +EmkwHglcEKA_1 motorcycle +EmlvoH2AxWs_0 person +EmqEntvqLw0_0 airplane +EmsMjm0VXJc_0 skateboard +Em44RLa7Qp4_0 person +Em_UT-f7q0E_1 train +EnJkvPAMuaM_0 train +EnJkvPAMuaM_3 train +EnJkvPAMuaM_1 train +EnL2FiVIuJg_0 elephant +EnL2FiVIuJg_1 elephant +EnS1Yte0Xzw_5 knife +EnS1Yte0Xzw_2 knife +EnUW7YSmli0_0 horse +EnVtYzkXwjM_0 person +EnbXP2xywwk_0 person +EnmwKpZJTQc_0 person +EnoNrjMNAC0_0 person +EnrcDrbyUxY_0 person +EnrcDrbyUxY_1 person +EoaeqRc88HU_0 person +EoallCLchmo_0 cow +EodtHMtH9zw_0 person +EojPQY8nQ2Y_0 train +EouV6Ut4NP8_1 person +EouV6Ut4NP8_0 person +EouZIHzCFq8_0 airplane +dYVtJPfJmf4_0 person +dYgPc190feM_0 person +dYgxCdKNrIo_1 airplane +dYjCbeBAgYs_0 person +dYmREF5dDkw_0 dog +dYosdOz5mZo_0 person +dYr1OKT1lCA_0 person +dYyHudM-fQc_0 person +dYyHudM-fQc_1 person +dYzh49Wr9bQ_0 airplane +dY9dlzr4w0Y_0 person +dZFiRqMkFPc_0 person +dZHJc_1os9Q_1 person +dZHJc_1os9Q_0 person +dZHJc_1os9Q_2 person +dZMQgxFHQPA_0 train +dZQ2o-4a5tU_0 person +dZSQXDQcafc_0 knife +dZUOCWwr2xs_0 knife +dZaFo3C_1ts_0 person +dZdvK41DxLI_3 car +dZio0uN6DHY_0 horse +dZio0uN6DHY_1 horse +dZjnkqYO2lE_0 truck +dZmG64W2CtM_2 umbrella +dZmG64W2CtM_0 umbrella +dZsXB4o-wdE_0 airplane +dZzfVDrmMj0_0 bird +dZzfVDrmMj0_1 bird +dZ1vVETiQAQ_0 person +dZ6ub2CEvbg_1 bicycle +dZ6ub2CEvbg_2 bicycle +dZ6ub2CEvbg_3 bicycle +daBl0Q92zLE_4 bear +daBl0Q92zLE_0 bear +daIJjuHo2EQ_0 cow +daMcE2oorrE_1 person +daWo89I2Tuo_0 skateboard +daWo89I2Tuo_1 skateboard +daWywQD6R4g_8 elephant +daWywQD6R4g_0 elephant +daWywQD6R4g_2 elephant +daWywQD6R4g_4 elephant +daWywQD6R4g_5 elephant +daWywQD6R4g_6 elephant +daXEykL8UQ0_0 horse +daZHZXfmY7k_0 cat +daaHTdFcx5o_0 boat +daaX2TXbYmo_2 airplane +dadAGYt0vS0_1 horse +dalHUNR5yAA_1 person +dan-4YoB-Vw_0 person +daoysu5sfUQ_0 person +dapxBMe8Wz8_1 person +daqWFFdK8Ck_0 person +dawGJDtHlcs_0 person +da4jNzO5wL0_0 person +da61HPBGEwo_0 bicycle +dbU6Fn_5bHI_0 bus +dbXr-9m66-U_0 person +dbdhdeVMuL0_0 bird +dbhGB6XW3fM_0 horse +dbxb42TzQ_g_0 skateboard +dbysY1V2TwI_0 person +dby-fBGIPRU_1 boat +dby-fBGIPRU_4 boat +db9i2fI8dv4_0 horse +dcADt99ndxg_0 person +dcADt99ndxg_1 person +dcBMrHLTvPo_0 person +dcEW4y5AI1E_1 elephant +dcHcm85hd5s_2 bear +dcH304rxwLY_0 person +dcJN3WJZLOE_0 train +dcLR55c41rg_1 horse +dcLoVk60Gkg_0 cow +dcLoVk60Gkg_1 cow +dcLp5mtSkPA_0 cow +dcO5id4LTVE_0 person +dcO5id4LTVE_1 person +dcO5id4LTVE_2 person +dcO5id4LTVE_3 person +dcO5id4LTVE_4 person +dcUA_Wf8vrc_2 skateboard +dcXdmOY1YCw_0 car +dcXdmOY1YCw_1 car +dcblbU5lyQU_0 person +dcdXiEQkghM_0 person +dcdXiEQkghM_1 person +dcf4zn9wOjM_1 person +dcj9u89LAu8_0 umbrella +dcoFS0-09xc_0 person +dcoFS0-09xc_1 person +dcwbXzJsVDw_1 car +dcxhSnf9sg0_1 horse +dc1_WHDpL3w_0 person +dc-BpV5fuQM_2 cow +ddK4WXTyoWw_0 cow +ddPN4QZuLBE_0 train +ddPxOsA2Cro_0 person +ddPxOsA2Cro_1 person +ddW0MYEUWlc_0 person +ddaqR7COVYo_0 person +dddKAnk7-hQ_0 umbrella +ddlPux88liU_0 person +ddruq0KhCxM_1 skateboard +ddsTE3NwHyM_0 person +ddtNIDCxqCk_0 person +ddw0wDJgJwM_0 person +ddxQR-NB6E4_0 person +ddzrzJEogWQ_4 motorcycle +ddzrzJEogWQ_6 motorcycle +ddzrzJEogWQ_0 motorcycle +ddzrzJEogWQ_1 motorcycle +ddzrzJEogWQ_2 motorcycle +ddzrzJEogWQ_3 motorcycle +ddzrzJEogWQ_5 motorcycle +dd0CsqY6Fbo_0 airplane +dd8a6btF_B4_0 person +deDEnw72hQk_0 person +deNoMwyFOO4_0 person +ded6WOfO9O8_1 person +deep6EOo6ds_0 person +deihMrgBXEc_0 person +delKGPVRJsY_0 person +demxgFkqGxA_0 bus +deqo50gGTBo_1 airplane +dew_lb_L9hE_0 person +dezAUC4KbJI_0 person +de1f8qTDYUI_0 person +de2HZ6DBOuM_0 person +de4mcJTPj48_0 person +de4mcJTPj48_1 person +de7-gbLffxs_0 cow +de8KeV2waGY_1 person +de8V1ovs5eM_0 person +de_fGa7Zxus_0 person +dfAvID4lRsE_0 person +dfAvID4lRsE_1 person +dfDTR9mCUZI_2 dog +dfEF6SMFbGM_0 skateboard +dfKBB3-VicU_0 bus +dfK1HsVc2B0_0 person +dfh2lETTLZI_0 skateboard +dfp4iVaXCpg_0 skateboard +dfqLJxxdinA_0 train +dfsTKKT5-UU_0 person +dfseA2X5Cow_0 person +df_PzyC0gTw_0 cat +df_SYY4pb3I_2 cow +dgGYa05XpYo_0 skateboard +dgIsZXSKACE_0 person +dgOQKwvhLpE_1 dog +dgTYRveHMjM_0 cat +dgYN1OH5oc0_0 zebra +dgl2b2bRpq0_0 person +dgtaJOOOtKg_0 person +dgweyIjmmDY_0 cat +dgyGZqXgvag_0 person +dg6u7R87Gh4_0 person +dhFII58PWhI_0 person +dhIL9wRZMm0_1 horse +dhIt9lg6Sbw_1 boat +dhUG1gnTlso_0 dog +dhZ-JmFNyak_0 person +dhcVp1GmJyI_0 elephant +dhcVp1GmJyI_1 elephant +dhgs2glg_N8_1 person +dhgs2glg_N8_0 person +dhiYTV7DJLY_0 cow +dhjeKi58cuU_0 cow +dhkFVTvJ6ZU_0 cat +dhy85XNJT3c_0 horse +dh03d5vq1B0_2 dog +dh1XFXciUf4_3 bus +dh1XFXciUf4_2 bus +dh6zZFXD0_c_0 elephant +diDDNe-MVfs_1 elephant +diMmgSNBO8k_2 person +diRn1fE6zMg_0 person +diSTaGHORrc_0 person +diSZzd4jM0E_0 person +diUCxWmV084_0 person +diZ-mRLPpqI_0 person +didB6Es7Des_0 person +didTjworKXg_2 umbrella +dif0t09rdZg_1 cow +dioELry6bbk_0 airplane +dix7GRytfcw_0 person +dix7GRytfcw_1 person +di1KJ0Mb5M8_0 dog +di2TPYyIeWc_0 dog +djIw9AQoU3o_2 person +djLPrNtPSY8_0 person +djLUJy1sWMg_0 cat +djNzrBpqnnY_0 car +djSxYfG99k8_0 car +djaGBINLXTQ_0 elephant +djh9QeYLg7M_0 airplane +djiTvgkjTW4_0 train +djiTvgkjTW4_3 train +djiTvgkjTW4_4 train +djiTvgkjTW4_5 train +djiTvgkjTW4_7 train +djlet5--ZW0_0 person +djlet5--ZW0_1 person +djpCG2oprrA_1 person +djvQyzGNp7o_0 person +dj2Qk--KIkk_0 person +dj6yGGCBFWc_0 person +dj8d91U-F_0_0 person +dkQWD9hv4fo_1 train +dkQbDCav3eM_1 person +dkSetHNXnNY_0 cow +dkb-6x7zo5E_0 person +dkdCTCL5imo_2 truck +dkdCTCL5imo_3 truck +dkdCTCL5imo_4 truck +dkiOcFZwrA0_0 bear +dknj-Sv4HUs_1 person +dkpsViIYlsI_0 cow +dkw4aWG9l6E_0 bear +dkw4aWG9l6E_4 bear +dkw4aWG9l6E_5 bear +dkxLcr2kvIM_1 horse +dk3Nf8K3RzI_0 boat +dk4gT0vHgeU_0 person +dk6h_GL9OZo_0 person +dk7QISqnWZc_0 bird +dk7juEuA2is_0 bear +dk7juEuA2is_2 bear +dlAMvsjssrY_0 person +dlDsSVM3JJ8_0 person +dlG7MtSpAK4_0 person +dlIG99k9Hoo_0 elephant +dlIkYaty1Uw_0 car +dlNMnGKJJjU_0 cow +dlQ1Gr54T74_11 bicycle +dlQ1Gr54T74_14 bicycle +dlQ1Gr54T74_5 bicycle +dlVOuZK_1bY_1 person +dlVTSnDsl38_1 knife +dlW_HPbVriI_1 truck +dlW_HPbVriI_3 truck +dlW_HPbVriI_0 truck +dlW_HPbVriI_2 truck +EpH59JsxI3w_0 car +EpIb8r7uBqM_0 person +EpJ_M6rB_PA_1 bird +EpOaQjhIh_M_0 airplane +EpP_TLXxb7Y_0 cow +EpSURaF1BfY_0 truck +EpT8zxDFPf8_0 cow +EpVdzlk5GYU_0 truck +Epd3r6iiqVk_0 bicycle +EpeIZCFbjw0_0 skateboard +EpnttpyYTAo_0 person +Epoqtu0Pqe4_0 cow +Ep8bd1STWKw_0 motorcycle +Ep81Lk66O50_0 person +Ep84L7WDoyE_0 person +EqBJeYu5f_E_0 elephant +EqBJeYu5f_E_3 elephant +EqHBjvHkvf0_0 person +EqJR5UZAlSg_1 car +EqLYPeo9ZC0_0 person +EqMqvcHp8Ko_0 car +EqMqvcHp8Ko_1 car +EqSYKCxmeDA_0 dog +EqSYKCxmeDA_1 dog +Eqh7XqsYl5M_2 person +EqmnFPweBmk_1 boat +EquATbp9uL0_0 person +EquATbp9uL0_1 person +EqvMMBAZP2o_0 person +ErUllSQJNgI_4 elephant +ErUllSQJNgI_5 elephant +ErWUOje4g8Q_0 motorcycle +ErX04vJ-JcU_0 cat +Erf0FkqYsTE_0 person +Ero36xFQKS4_0 truck +Ero36xFQKS4_1 truck +Er4yJXTWNNo_3 bicycle +Er4yJXTWNNo_4 bicycle +Er4yJXTWNNo_5 bicycle +Er5D0fXZsjk_0 person +Er9tboOA5k8_0 person +EsEreMKZP7Q_1 person +EsQ05q5ZZVM_3 skateboard +EsQ05q5ZZVM_5 skateboard +EsQ05q5ZZVM_2 skateboard +EsYZbF7hCTE_0 person +EsZV26-jxX8_0 motorcycle +EsbWwOYbT8Q_0 train +EskqA8x8mX4_2 airplane +EsrUSkNrqWs_1 person +Es0O5wtTZ2Q_0 person +Es9GOUryI0U_0 person +Es9Yq8uZ4fA_0 person +Es-W0AxQ5Us_1 cow +EtebDuK3fUY_0 person +EtlKR9-Q2dk_0 person +Etx8YkcrSF8_0 person +Et0RRuaW-Rg_1 dog +Et1PKq61KAk_0 person +EuETmswYRrs_0 cow +EuHJB5UXmZg_0 umbrella +EuHvelij5ao_0 cat +EuIGG3PoslE_0 person +EuInxfWuqqA_0 person +EuZnOeXR020_0 person +Eua2VIbXEMs_0 boat +EufXUqphYVw_0 person +EumfsHXsVGk_0 person +Eunz2V1RXXo_0 train +EurWaA7qCDw_0 bear +EuwjSGtSYlY_0 person +EuwjSGtSYlY_1 person +EuzDIk8ag30_0 person +EuzVaAXsy4o_0 motorcycle +Eu0nzh2HQNk_0 person +EvDZK2cFYVE_0 motorcycle +EvGoGf-YCA8_0 bicycle +EvKPt0vynKY_0 truck +EvN8x67_EQ0_0 person +EvZF9DagIoQ_4 horse +EvZF9DagIoQ_0 horse +EvZF9DagIoQ_1 horse +EvmcyDEPnoA_1 skateboard +EvvbUe6FBSM_0 bird +Evvij-hmE4A_0 person +EwBKceBTBbo_0 dog +EwBwIUrHR3o_0 person +EwBwIUrHR3o_1 person +EwDyryqt94g_4 airplane +EwDyryqt94g_5 airplane +EwKIz0qAvKQ_0 person +EwSJeylFWsY_0 person +EwUGFtWeyMA_0 person +EwUeAvO5mrE_0 cow +EwU8puKxN8Y_0 person +EwU8puKxN8Y_1 person +EwWCc9whfDI_0 cow +EwYNowdS57c_0 person +Ewet2EA1xX8_1 elephant +Ewet2EA1xX8_2 elephant +Ewet2EA1xX8_0 elephant +EwozH_35SDg_0 person +Ewq-V9jATzg_0 person +Ew8lEc8Ufi8_1 bus +ExCPGilpuMM_0 person +ExCPGilpuMM_1 person +ExCjkt_zXuw_0 person +ExCjkt_zXuw_1 person +ExJjWM_rAnI_3 airplane +ExJjWM_rAnI_1 airplane +ExPBVcERfwY_1 person +ExPBVcERfwY_3 person +ExPBVcERfwY_4 person +ExT3xg9phtQ_0 person +ExVHmko3jfY_0 horse +ExW1ju88BW8_0 cat +Exb1TjMi76I_0 boat +Exc3W9o5-04_1 horse +Exe2EizU9VQ_0 cow +Exe2EizU9VQ_1 cow +ExfZl3DY8JM_0 person +ExfZl3DY8JM_1 person +Exl9alp64lE_1 person +ExqpcHBGBlw_1 person +ExvcP05yrS0_0 person +ExvcP05yrS0_1 person +ExxZODpPkQQ_1 train +Exz2WL2-kR0_0 giraffe +Ex4__JMKkqI_0 person +EyMzZV5iTEA_0 horse +EyP_0uEuXVs_1 bear +EybT7tq6XGk_0 person +EymmgPoUyuM_0 person +EymmgPoUyuM_1 person +EymmgPoUyuM_2 person +Eyn7IfnWm4o_0 airplane +Eyn7IfnWm4o_3 airplane +Eyn7IfnWm4o_1 airplane +Eyn7IfnWm4o_2 airplane +Eyp8nornJW0_0 bear +Eyp8nornJW0_1 bear +Eyrfi9lGdoo_1 airplane +EyuKu6qMB6g_0 person +EywYZ3Gjwuc_0 person +EywnxH68jDU_0 cow +Eyzwbz1ZxmU_0 cat +Ey2TgrQ30Z0_1 bicycle +Ey2TgrQ30Z0_2 bicycle +Ey36TlCS4rQ_0 person +Ey4BLGQL2Bg_0 bear +Ey7eosaz0zU_0 person +Ey7us0SSVAs_0 airplane +Ey7us0SSVAs_2 airplane +Ey7wIzCkFU4_0 person +Ey7wIzCkFU4_1 person +EzC0tuKaVGA_0 person +EzEX4OUEHHQ_1 skateboard +EzGa4SSPsbI_0 bicycle +EzYjRjhff20_0 person +EzZEWp1cluc_0 person +EzeDITt3y5I_0 person +EzeDITt3y5I_1 person +Ezlyx_EudUQ_0 person +Ezlyx_EudUQ_1 person +EzuizVcVbSA_0 person +Ez6I4TpzC5I_0 person +E0K5Ll7wHUw_0 bird +E0YZDyUoHTM_0 knife +E00cOMpNw3o_0 motorcycle +E01EgIBFxRk_0 person +E038teDC3EM_0 person +E0-Z0KM1UB4_1 person +E1AwHXQ00ns_0 person +E1MTmF3FAN0_0 bicycle +E1NfSTmGCRE_0 knife +E1ZhuBRYvKY_0 cow +E1bNSKg9iv8_0 horse +E1oEO09-bAw_0 dog +E1pmsS_ufrs_0 person +E1xPwEvYymk_1 person +E1xPwEvYymk_2 person +E1xPwEvYymk_0 person +E1zxNG3Fglo_0 bird +E17S76lXHfI_0 person +E1_ETAQHwcM_0 person +E2O5Y6VAhIc_0 person +E2O5Y6VAhIc_1 person +E2Pobz5qoAE_0 person +E2Pobz5qoAE_1 person +E2Vqlq1BQYs_0 airplane +E2WWQOKGeb4_0 skateboard +E2aiCls-clY_0 person +E2lj1iRVceA_0 skateboard +E22IW-PgLfU_0 person +E28Cad7vBrw_0 person +E28Cad7vBrw_1 person +E29-bZY3lEo_0 airplane +E3NmlH6taDs_0 truck +E3SKOBDl6u0_0 person +E3enDSeq6P0_0 person +E3tmvYSpQSQ_0 person +E35M5UWMXeE_0 horse +E35M5UWMXeE_2 horse +E4Bl9c7JbYs_0 person +E4DFW1SxJfY_0 dog +E4DFW1SxJfY_2 dog +E4TfSUdVt8U_1 truck +E4pulnGY9X8_1 person +E43SZ65LnfY_0 cow +E45LqepDuqg_1 person +E5BtXla2lCQ_0 bicycle +E5CQkNJct6Q_0 motorcycle +E5HB-EDNtE8_0 person +dlZZzrMO6yY_0 person +dlbAWAuByWk_0 person +dlcovhFKigE_0 person +dlh5RGS5Bzw_0 bird +dlkVXsIhcZg_1 person +dlo83yH621I_1 cow +dl2g71ftw9A_3 train +dl2g71ftw9A_4 train +dl2g71ftw9A_5 train +dl6ogvuxF78_0 person +dl_fuQYhAP8_0 person +dmDdRd6wULk_2 dog +dmJ1DuWiAdM_0 person +dmMz5FhGOCc_1 person +dmVAi4WMi3M_0 person +dmVAi4WMi3M_1 motorcycle +dmVAi4WMi3M_3 motorcycle +dmW77KHtuCQ_0 horse +dmYSNG-7VCg_0 elephant +dmfX7DsSS1k_0 bicycle +dmuWxnAfMn4_0 elephant +dm4rFNN7FZQ_0 truck +dm-lOmiP2d8_0 cow +dnAQ7q60f_g_0 elephant +dnB0we4_DrY_0 cow +dnB6auv8PBk_0 person +dnFZkG7_E1w_0 person +dnNh07bnI_s_0 cat +dnUXo5nstys_0 person +dnVV1s-LcAY_0 person +dnY-4hOzYts_1 person +dncQtuB_6qA_0 motorcycle +dncxd1B2sLk_0 giraffe +dnwqVE3lPyY_1 train +dnwqVE3lPyY_2 train +dn_r7u_5apk_0 skateboard +doHOuG6wqXY_0 motorcycle +doSDuIGLFXY_0 cat +doTj5H8Uf1I_0 cow +doUwj_z1x5o_0 elephant +doX3oiADm_s_1 person +domu9ia2Vo8_0 person +dorx67yK7WU_0 bird +dovn1QHCR7o_0 person +dowbL0CZ5do_0 bicycle +do1QIWrYeW8_0 person +do5o5Dw0vPc_1 elephant +do5o5Dw0vPc_4 elephant +do7abiC5aZk_1 car +do82ENX9cOc_0 person +do-LmSJTPj4_0 skateboard +dpDG64ULlUg_0 boat +dpGCSoTITrw_2 elephant +dpJWbIaQYoI_0 person +dpJWbIaQYoI_1 person +dpQP5r61_GQ_0 person +dpUorqkSYZE_0 dog +dpYYMgh5TS0_0 truck +dpcwUs5srlc_0 horse +dpi0u6pfCTM_0 person +dpjLyHb9AyI_0 person +dpkF3SwOunc_0 dog +dpn6vUVXBuM_2 umbrella +dptZbHZQYPM_1 dog +dptZbHZQYPM_2 dog +dpxGzRQqAaU_0 motorcycle +dpxGzRQqAaU_1 motorcycle +dpxGzRQqAaU_2 motorcycle +dpxVPiv62SY_0 person +dp2cUWhnP0A_0 knife +dp3Q_aTYeJ4_0 person +dp_JQh45a50_0 person +dp_1VrEUWbU_0 person +dqCFYWRf9g8_1 elephant +dqDLl7BlAAA_0 skateboard +dqFRS9o1CSU_1 person +dqOoL5LiXc8_0 boat +dqQPbKE4UhQ_0 person +dqTlCZzLk6A_1 cow +dqWEwvhVNiI_0 person +dqavRiIA-38_0 truck +dqj-msAUvnc_0 cat +dqzc4W6f-x4_1 person +drAhAL_F38Y_0 person +drAh2lmjDs4_0 skateboard +drJGoPHMunk_0 person +dreDU-1isrI_0 person +dre_PgfS8yw_0 elephant +drf5ijiEkUo_0 person +drm2oJ3X1HM_0 person +drqFwF60pgE_0 airplane +drqFwF60pgE_1 airplane +drqFwF60pgE_2 airplane +drqe2hP0PKI_0 person +dr3TumG_tlI_1 cow +dr4dU5UDF-Q_0 person +dr8s5VC9Fxg_1 person +dsLbM2wZHrc_0 dog +dsPwJ3J1ZKA_0 person +dsTR1vv9XLE_0 person +dsTR1vv9XLE_1 person +dsUuAVsJSi4_1 motorcycle +dstcI7MYsZ0_0 person +dsyBSejpe-k_0 person +ds1BJMsasQI_0 person +ds6FmQYwgYw_0 skateboard +dtDGbuCwBuY_0 bicycle +dtHgnX0NtxE_0 person +dtMbzXL9wO4_2 bear +dtOFqz41TJ0_0 bird +dtR2UeJbIvg_0 person +dtWfbusf4Es_0 horse +dtYdUj-d8fA_0 train +dtZrB9iDzgQ_0 horse +dtlUL4D7_NM_0 bird +dtvZaXxNgKQ_0 person +dtwUG12h74g_0 person +dt8Tngmse50_0 bicycle +duOX3z4IJSY_0 person +duTvmDpj0sI_3 boat +duTvmDpj0sI_2 boat +duV82Wn9rXk_0 car +duZYUVeDXEM_0 cat +duaO7S-EH1A_1 person +ducdg4KXQsg_0 person +duoFWPZbeNc_0 person +dupnmzaPsWA_6 elephant +dutp3txJPTY_0 person +duvuNqufLjs_0 cow +du5hbB5w3UU_0 horse +du96VR7vtOk_0 bird +dvKKmu56UkE_0 person +dvS2DSYGOGg_0 person +dvbVbBosw38_1 person +dvgf3R9k0uY_0 bird +dvur4MZD_yc_0 person +dvur4MZD_yc_1 person +dv0ptUC-DIE_0 person +dv6ymk8duso_0 bird +dv_KURooPDU_0 person +dwbRsYPV7Ag_0 person +dwpopXTeeGc_0 person +dwrYJ92znpw_0 cat +dwy7k_gtEco_1 boat +dw8kejnR7L4_0 person +dw-2_KqGeYY_1 bird +dxFrLHoW9jI_0 motorcycle +dxGlDl4IukI_0 horse +dxGlDl4IukI_1 horse +dxViI6VXh6Y_0 dog +dxn8VDPNvJM_0 person +dxq9r-qrJ2A_0 person +dxsQn1MuZRA_0 bus +dx0z7DYxGSw_0 person +dx4rtOOz7tA_1 umbrella +dx6ucdpKZP0_0 person +dx8nEHWD1xc_0 person +dyAC2ey1DQU_4 bird +dyJ83t1zgkU_0 skateboard +dyPMbIsTtFs_0 person +dyPt3VKGZPo_1 person +dyR4vnjF5do_0 truck +dyZixtbxEE4_1 person +dym-lDsiSTM_0 boat +dyt8LtUqIMU_0 boat +dyy3oxsiErU_19 truck +dyy3oxsiErU_14 truck +dy2J0aeX5eQ_0 truck +dy3nkqKOjbk_0 person +dy6zETD5NFo_0 cow +dzEKq7fsVnQ_0 train +dzNRDfnNbeE_1 person +dzS2ClyakEg_0 truck +dzXv_YFLPqg_0 person +dzahMuEcbCM_0 cow +dzeNnQOePGs_0 person +dzhSVb26d7Q_0 umbrella +dzoQb8C3vxE_0 person +dzsHYOJpBbY_0 bear +dzv-u3s_YtI_0 person +dzyVndvBofo_1 horse +dz3SP1rd9zE_0 car +dz_ATSJBx6k_0 airplane +dz_ATSJBx6k_1 airplane +d0J7uodSxF8_2 motorcycle +d0NY8eqs19s_0 motorcycle +d0NtMMBjQp0_1 truck +d0NtMMBjQp0_2 truck +d0NtMMBjQp0_0 truck +d0RIwZfoGNg_0 person +d0ZEYzyD9Vg_0 person +d0b8-K_6D68_0 umbrella +d0hJditcWj4_0 person +d0hQQC2i1Y0_0 person +d0hQQC2i1Y0_1 person +d0hdtlKidzs_0 person +d0h9QWelhII_0 boat +d0lVKBOzOQ0_0 skateboard +d0qGN1A7XJA_0 person +d0vHpkvShqg_0 giraffe +d0vUARlHvjc_1 cow +d0v47QFRyvg_0 person +d0v47QFRyvg_1 person +d00UKAQHK2A_0 person +d02xOzIVP-s_0 person +d04Dr38addQ_0 airplane +d09H7U6x-Fc_0 cat +E5OHeMbBp9s_1 giraffe +E5RbbN1bPN8_0 person +E5YibOn90Co_0 skateboard +E5b9Yug5vbk_0 bicycle +E5b9Yug5vbk_4 bicycle +E5b9Yug5vbk_1 bicycle +E5b9Yug5vbk_2 bicycle +E5b9Yug5vbk_3 bicycle +E5dBaFyBYX0_0 airplane +E5me_giHEOE_1 person +E5trQkGM3Wk_0 cat +E5wZ4pk5X0I_1 train +E59OnpOGBLU_0 skateboard +E6Am4hIuXvk_0 person +E6Avey2AVRM_1 person +E6A8vfHTdOQ_0 person +E6EtoMfo384_0 train +E6EtoMfo384_1 train +E6GvpwdOQrw_2 train +E6GvpwdOQrw_3 train +E6GvpwdOQrw_8 train +E6JLxU918TE_0 bicycle +E6XGO0hx4N8_0 person +E6Y2QsetU0M_1 person +E6s0XT5G7Eo_0 bird +E6s0XT5G7Eo_1 bird +E6uGh-cPDjI_0 bicycle +E62w4NFSm5E_1 dog +E64d0EH39M4_0 train +E67ceZopcqQ_0 person +E67ceZopcqQ_1 person +E68IhhK04s0_1 giraffe +E68IhhK04s0_2 giraffe +E7BIM8cnCrc_2 train +E7BIM8cnCrc_0 train +E7F0Gt3Rea4_1 person +E7F0Gt3Rea4_0 person +E7LY2yKO0Jg_0 knife +E7MvCesCxNk_0 knife +E7dG4qPI_QY_1 knife +E7eYGQjaVYs_0 bird +E7hXPqOOiqo_1 boat +E7hXPqOOiqo_0 boat +E7qoCZ2e-vQ_0 dog +E7rhwzBxMqY_0 person +E7zwjNToyao_0 person +E70FO7I2AQ0_1 person +E70FO7I2AQ0_0 person +E76moy2SQhA_0 person +E8JYTxKfqmQ_0 boat +E8OzYJ2gVAs_1 bicycle +E8OzYJ2gVAs_2 bicycle +E8OzYJ2gVAs_3 bicycle +E8RSSepY8tk_0 person +E8R5lzlo5qw_0 motorcycle +E8Xxr8SUaEY_0 horse +E8h4YnZbJg4_1 person +E8n_eTUwyhc_0 person +E8pbsHhMGOw_0 person +E842T5CgJfk_0 person +E854nPMWssI_0 horse +E8-Z9saoTjk_0 person +E8_NjWtQtgI_1 car +E9J2Brm4LSg_0 truck +E9J2Brm4LSg_1 truck +E9N59GTZ8uE_0 person +E9R_qLxcZdY_0 bird +E9S5Tk5r2wU_0 person +E9ZjM9SY__o_1 person +E9ZjM9SY__o_0 person +E9sCn_XaSHw_1 bicycle +E9sHGoiMmXc_0 person +E9zmtafFrCo_0 dog +E9-1FSPKZ7k_0 person +E-DE7HZ04WY_1 person +E-OdBMMpwlo_0 umbrella +E-VRMpgKXIE_0 elephant +E-VRMpgKXIE_7 elephant +E-VRMpgKXIE_1 elephant +E-VRMpgKXIE_2 elephant +E-VRMpgKXIE_4 elephant +E-YDPyDXtR8_0 cow +E-h1XNBlqsE_0 person +E-pnZZeRFyQ_0 person +E-q9j7xipsA_0 cat +E-seUZ3B-Ts_0 motorcycle +E-zFmY_9LWk_0 horse +E-0FMMDuLw8_0 person +E-3jsRP7KHc_0 elephant +E_En6n1IyBw_0 elephant +E_GC0IeKtu4_0 person +E_K6zdkr0mo_1 person +E_Xi5uEIiec_2 bicycle +E_e6E8T7on0_0 dog +E_02tA9RLyw_0 umbrella +E_7qbAkVDYE_0 elephant +FAKE4Rfwdik_0 person +FATjlgllzBU_0 person +FATjlgllzBU_1 person +FAdlwBJZk78_0 elephant +FAeK9y98GL8_0 zebra +FAiIhoJh5uQ_0 cat +FAm6HgSzPTA_0 cow +FAn11rZ-gsU_0 person +FAqiar6B2U8_2 bird +FAu0yvyjW-Q_4 boat +FAu0yvyjW-Q_9 boat +FAu0yvyjW-Q_1 boat +FAu0yvyjW-Q_5 boat +FAx0CsAigS4_0 motorcycle +FA_K15dKk6k_0 bear +FBAcUphtxR4_0 person +FBIVWWIbq-8_1 cow +FBIawPqElJ8_0 bus +FBKIUCHqUQk_0 skateboard +FBKIUCHqUQk_1 skateboard +FBNFSYoMCNM_0 bird +FBOWbksU5pI_0 person +FBOWbksU5pI_1 person +FBjp-C_Sbug_2 bicycle +FBjp-C_Sbug_11 bicycle +FBnFn5mY2R0_0 person +FBwWw9c4KdY_0 person +FBz0aAYDBFI_1 person +FB8F1ku1XkU_0 person +FCBsCwjCPWU_0 person +FCQB6p_GcDY_0 person +FCRAvY0glAI_0 airplane +FCd1d_7Hfpg_0 umbrella +FCkT11nk468_0 airplane +FClLRpdDi9A_0 person +FCnE02wQQk4_0 bird +FCp7AKKYViY_0 person +FC-ONjCL7tM_0 person +FC_gwQU4yrs_0 horse +FDJyHtHix-0_0 train +FDYS2AyPJhc_0 person +FDZBIlbFrk0_0 person +FDej1TTCjP0_0 umbrella +FDfaLuM3y5A_0 person +FDkiv1x0OGQ_0 car +FDq3yKNo4Qs_1 person +FDvTPzckQKc_0 motorcycle +FD3pT-lj2tc_0 cat +FEM7OGFO_BI_0 elephant +FEN0F0V1nhg_0 dog +FEOAvRWKb-k_0 airplane +FEU4yHFzkZs_1 person +FEU4yHFzkZs_0 person +FEWZolQuMv0_1 person +FEfYdrS3kFc_0 bird +FEjcdYO4xPo_0 person +FEoFDmI0pxI_0 airplane +FEzBza78J4w_0 person +FEzBza78J4w_1 person +FE0DpZ9GXoM_2 person +FE0DpZ9GXoM_0 person +FE0DpZ9GXoM_1 person +FE0Q5phKq3c_0 person +FE0Q5phKq3c_1 person +FE4gj8EYF9k_0 person +FE51Dml-nZY_0 person +FE7iv_llNT4_2 bicycle +FE-JTPLk3fI_0 truck +FFCtm1GZH_s_1 bird +FFHJUeZ_KKE_1 truck +FFHJUeZ_KKE_2 truck +FFLxkwDj1b0_2 bus +FFME8B_6LNA_1 motorcycle +FFQl2DLyjdk_0 cat +FFQl2DLyjdk_1 cat +FFantnd2gLY_0 person +FFantnd2gLY_1 person +FFd_4DPNyRI_0 car +FFijp_s0YwA_0 dog +FFi3nSvA0WY_0 person +FFjqbw4R9l0_0 cow +FFm26XU-R7c_2 person +FFm26XU-R7c_0 person +FFm26XU-R7c_1 person +FFndlV1rKas_0 airplane +FFpyQ_5PU7M_0 bus +FF9eHa3K8fM_1 bird +FGO6y3WssIg_0 person +FGQCxd5EAx0_2 airplane +FGQCxd5EAx0_3 airplane +FGQCxd5EAx0_1 airplane +FGcS28ri5uY_0 person +FGdEufjjhtg_0 person +FGicL13npRI_0 person +FGkNC4hzcfM_0 person +FGkx6qk4oDk_0 person +FGmjmDC1RoU_1 skateboard +FGmjmDC1RoU_0 skateboard +FGoutavzP5Y_0 person +FGqrkJ3h0DA_0 skateboard +FG0PrdHReB0_2 person +FG5l2wX8ccA_0 horse +FHAj71IwE7E_0 skateboard +FHA6nVCnv28_0 person +FHB5eraeYEw_1 knife +FHJupOaUmtQ_1 train +FHOLOunv9Ec_0 horse +FHTc_V_05W0_1 bird +FHT1DAZpJVY_0 cow +FHZ-3pbJQrY_0 bird +FHgO4zu5RGA_0 person +FHu50D73Fzo_0 person +FIA67WzAuNs_0 bear +FIA67WzAuNs_1 bear +FIB12MYkANg_1 bear +FIDI0sZMPVU_0 person +FIGhnuJWX5M_0 person +FIGhnuJWX5M_2 person +FIHYnB8Jrh4_0 person +FIMbYQASgkk_0 horse +FIQ1iL3jVkM_0 giraffe +FIV4OFmfS_s_0 person +FIV4OFmfS_s_1 person +FInOWVIV_go_0 motorcycle +d1N4NJqa_8E_0 person +d1PqtOyYTY0_0 train +d1PqtOyYTY0_1 train +d1PqtOyYTY0_2 train +d1Quy8k5O88_0 cow +d1UWs3bPTsc_0 person +d1UWs3bPTsc_1 person +d1YYgiXq3tw_0 person +d1YYgiXq3tw_1 person +d1bzn92PO0c_0 person +d1eo2OWc45Q_0 cow +d1tf08A41eo_0 person +d1ukwE8h4f8_0 horse +d1wbMXvcgNc_0 person +d1wlubAM1-k_0 person +d10K79pdybE_3 train +d14rOFFvTg4_0 person +d14rOFFvTg4_2 person +d14rOFFvTg4_1 person +d165nDy63o8_0 bicycle +d165nDy63o8_1 bicycle +d17kaiZ5Ztc_0 person +d2DRRd9l3TI_0 person +d2RD5tyZt6c_0 person +d2TxcbWHoBM_0 cat +d2WfBDEMf40_0 truck +d2ZGi2fOtPY_0 person +d2cDVorBK8s_0 airplane +d2cDVorBK8s_1 airplane +d2e49A9MnF4_0 person +d2lSueNvuG4_0 horse +d2ns5iCGj78_0 elephant +d2sn_b1z1Vw_0 person +d2wHwCwQymw_0 person +d2zgNRFDpSw_1 bird +d203fSHLzv8_0 train +d21TfucuHss_0 umbrella +d217pENbZVs_0 person +d28DHw2okF8_0 person +d3F_Gm514J0_2 elephant +d3G8COtsJco_0 person +d3MN8Sm5tiY_0 person +d3MVAijPTjY_0 motorcycle +d3P2bH2t8IQ_0 person +d3Wdg9MPgLA_1 skateboard +d3Wdg9MPgLA_0 skateboard +d3duKA35FEI_0 person +d3jP_YP-6EQ_0 person +d3ro5gubiaQ_0 person +d3ro5gubiaQ_1 person +d3rzFaWiWwA_5 truck +d3sHFgbvhIU_0 car +d33yoN6QyYg_0 bus +d36tDEgs-IA_0 person +d4A2uUrnVWI_0 person +d4Cumy6qZPY_0 truck +d4DbIWORtjY_0 person +d4DbIWORtjY_1 person +d4GvMFc_Vqg_0 knife +d4Le0GuzhaY_0 skateboard +d4QkJdQwkCo_0 motorcycle +d4VJot5IZek_0 person +d4VJot5IZek_1 person +d4WRTfC57h0_0 horse +d4b9-LX5V1s_1 cow +d4hB6abJCs8_0 person +d4mhHPSo7C8_0 skateboard +d4q-0AcOs78_0 person +d4vhL4dar5s_0 giraffe +d4vhL4dar5s_1 giraffe +d45YTUkd_9M_0 person +d47DPSbvftI_0 person +d484zxSSkJM_1 person +d4_lDGwny4k_0 skateboard +d5Ao3JBz7WM_0 person +d5B0EMjLeZE_0 person +d5PBtpn_6JQ_0 person +d5gDBPwofbs_0 person +d5gDqlNLGmw_0 person +d5hj8eaC5fQ_0 person +d5jIlHa1Y6o_0 cow +d5m8giMORSk_0 person +d53_McJDtt4_0 person +d55FAEl6kfM_0 cat +d55rz05ynyg_0 airplane +d6AkvjKCaE0_0 person +d6AkvjKCaE0_1 person +d6TWHVESLa8_6 cow +d6TWHVESLa8_5 cow +d6VCXnnHXGQ_0 person +d6VCXnnHXGQ_1 person +d6YTAD3T2i8_0 person +d6a2EN1cB-4_0 person +d6cgbxc35Ms_0 person +d6mM21E4x-4_0 umbrella +d6m3DUG5E7Y_0 person +d6uLbEhrIvw_0 airplane +d65wDJoMyA8_0 person +d67YXl13SSo_0 person +d6-bn34gHFc_0 person +d7H5qLPNFz0_1 elephant +d7cwZ3G7xSU_0 bird +d7kWNGqyvRk_0 person +d7mQdSSoZ2E_0 person +d7m0BF65qro_1 person +d7m0BF65qro_2 person +d7n5m9UuhP4_0 person +d7n5m9UuhP4_1 person +d7yxmt8AvOM_0 person +d7yxmt8AvOM_1 person +d71rdGKeKkE_0 person +d74EhPMCxb0_0 person +d7-3m4Nz8fk_0 horse +d8CJ5urtRlk_0 train +d8HIJN0pULI_0 person +d8XcNMVXCD8_0 bicycle +d8b-SN3JEvk_0 person +d8dPRbquLuM_1 person +d8dPRbquLuM_0 person +d8t8y3kLzgc_0 person +d84iekZaJHc_4 knife +d9JyT5Kko5c_0 person +d9LvxSh5P-Q_0 person +d9OaiymMq0w_0 person +d9PCSJzZTy8_0 person +d9Pj3WrvXXc_1 person +d9S0dKjWhNU_0 person +d9S0dKjWhNU_1 person +d9S0dKjWhNU_2 person +d9YlucRFs0U_0 person +d9cSZXEb_5E_1 person +d9dysX9rdmA_0 skateboard +d9hh6urZ5FU_0 train +d9kzobAaimY_0 motorcycle +d9lIw5maa3M_0 person +d9qijNyVVmU_0 person +d95k-74VSVE_0 cow +d-JD-mAXyIA_0 dog +d-Mnc38YAmw_8 truck +d-OQw6tKhuM_0 knife +d-S3AmiMI1s_0 car +d-e8mKtYWjk_0 person +d-e8mKtYWjk_2 person +d-e8mKtYWjk_1 person +d-fv8fmGSlY_0 person +d-hMPjLP2WE_0 bicycle +d-hMPjLP2WE_1 bicycle +d-hgDDQ3kwg_0 person +d-h6ncywZ58_1 person +d-h6ncywZ58_0 person +d-oFe9Z0Obs_0 dog +d-oFe9Z0Obs_1 dog +d-rpsQgR8sw_0 person +d-22m5Sq5OU_0 elephant +d-5xdAZSjX8_2 skateboard +d--9RMf5LCA_1 boat +d_AudyfCYzg_0 car +d_EP2nM4YMw_0 bus +d_ElAbuvxGQ_0 dog +d_ElAbuvxGQ_8 dog +d_SB-LVXyi0_1 horse +d_SmnRMWLD8_0 dog +d_S0JCKcFCg_0 cow +d_hsQ2L-klo_0 person +d_nTA-SKHNM_2 knife +d_nTA-SKHNM_6 knife +d_ocJQiPpn0_1 skateboard +d_vnePeLmwI_0 person +d_2HhXHP8fg_1 cow +d__UUbvo2t4_0 person +eADPEBi8wWs_0 car +eADPEBi8wWs_1 car +eADqJI9JKq8_0 person +eAFdLVF01GU_0 bicycle +eANH6WnEpPs_1 person +eAPcJi7CaBw_2 horse +eAPcJi7CaBw_1 horse +eARl2H_FaEU_0 cat +eAXN0KAt66I_0 person +eAXN0KAt66I_1 person +eAYoRncVO74_1 person +eAZbke5Perk_0 car +eAfmOFI5jUM_0 horse +eAsHKktPNSo_1 horse +eAvDt4p-AvA_1 knife +eA3lmhfjTuM_0 cow +eA5hiUXY2_Q_4 airplane +eA5hiUXY2_Q_6 airplane +eA7FV9uQbYw_0 bus +eA8fIAfGi5k_0 person +eBB5vRA9JPE_0 knife +eBHEKUkaBcI_0 bird +eBLisw9b8i8_0 cow +eBLisw9b8i8_1 cow +eBLisw9b8i8_2 cow +eBMqhmQr7vI_0 bicycle +eBRcZ5KDeEA_0 knife +eBgLKDW3lH4_0 person +eBmdALv9WEE_0 person +eBwWJ_geg4Q_0 knife +eBy554vRg9M_0 person +eB83_xIotrw_0 bicycle +eB83_xIotrw_3 bicycle +eB_ZHbAvx-c_1 person +eCInOWr32gc_0 dog +eCNG8qj36vs_0 cow +eCSzfVb87kI_0 person +eCUuH2vPeDI_0 person +eCWhtTVetLA_0 umbrella +eCeVtq40bcM_4 bus +eCf8h359-j0_0 bus +eClBvJnyYa4_0 truck +eCmgHa6ThE4_1 person +eC3Fwv7Uows_0 person +eC-5SEhAGvo_0 cow +eC_fRVwxsiI_0 person +eDJamx945Ao_0 elephant +eDJamx945Ao_1 elephant +eDSAGlcfwKA_0 person +eDSmePW-Vrg_0 person +eDXqzj7vKFI_0 motorcycle +eDX2HUt9ttU_0 person +eDX2HUt9ttU_1 person +eDuzDDESzU0_0 person +eDwjZL3IGqM_0 person +FIrviDrZriY_0 bus +FI2T176uKi4_0 person +FI4oF175yHo_0 cow +FJCE3uzu0i4_0 dog +FJL5lb3wBKI_0 airplane +FJPRJ0A8BII_0 boat +FJVcRzA_pdI_0 airplane +FJdcStnbgU0_0 person +FJl_FwYbg8s_1 knife +FJmyu27Omwk_0 person +FJsMdQrRgFs_0 train +FJvHbRGgbXM_0 giraffe +FJvSXVq8PPk_0 bicycle +FJxbfz8q8Qw_0 person +FJzU4eC5GiI_0 person +FJ5jeLsVXys_0 elephant +FJ5jeLsVXys_1 elephant +FJ7oeGn4dBM_0 cat +FKGFVLnchKE_0 skateboard +FKGFVLnchKE_2 skateboard +FKGFVLnchKE_4 skateboard +FKGFVLnchKE_5 skateboard +FKKoXDLhFjo_0 person +FKMCYA2_RMs_0 horse +FKMCYA2_RMs_2 horse +FKMsbMSiqrQ_0 person +FKTETXdoJjk_0 person +FKVxjU1kTMM_0 person +FKWzB37H8-E_0 cow +FKdcZ0D4-K8_4 horse +FKdcZ0D4-K8_1 horse +FKhBf2FcrKE_1 person +FKhBf2FcrKE_0 person +FKnj73Wv84c_0 umbrella +FKsZiccYt_g_0 person +FKwKsWjLhiI_0 person +FKzvgRVfOjM_1 horse +FKzvgRVfOjM_5 horse +FK0ezSvbg7o_0 dog +FK37T3KvNUU_0 cow +FK8OxK802HI_0 person +FLF92L3WRrs_0 person +FLF92L3WRrs_1 person +FLQzeGFBo2I_1 bird +FLQzeGFBo2I_2 bird +FLTewjXG6Wc_1 person +FLTewjXG6Wc_2 person +FLTewjXG6Wc_0 person +FLWAw0tGOo8_2 bicycle +FLWAw0tGOo8_3 bicycle +FLZeutEdtzU_1 horse +FLqZVv798FE_1 person +FLqZVv798FE_0 person +FLq3zU7UtgQ_0 skateboard +FLr23Hv4LfE_0 train +FLr23Hv4LfE_2 train +FLskMa3WD7M_0 person +FLyV4pkEHUg_0 person +FL1q74zVLvo_1 truck +FL8ulwhcOho_1 car +FL-QttmKDc0_0 airplane +FL-73OGqifE_0 cat +FL_DeYOGkaU_2 horse +FL_DeYOGkaU_0 horse +FMHc-oH_rOE_0 person +FMTZga_deFY_0 dog +FMig7WOUQyU_1 bear +FMig7WOUQyU_2 bear +FMv3NfETfq4_0 bicycle +FMv3NfETfq4_1 bicycle +FNCMx4Aum_M_1 motorcycle +FNJmejn3KNQ_0 truck +FNJmejn3KNQ_3 truck +FNJmejn3KNQ_5 truck +FNKJAi0Xbz0_0 person +FNNdAL0qtWM_0 horse +FNSpSfZSQfE_0 person +FNbjJJgHt6c_1 person +FNgfcu9JUHA_0 cow +FNjDy-du_gs_0 truck +FNv5k4sCs5k_0 person +FNxfPhr1AZk_0 person +FN1B1veyxCQ_0 cow +FOAmP97Gboo_0 elephant +FOAmP97Gboo_2 elephant +FOL80Pq_HSs_0 cat +FOXwGm4ddCk_1 person +FOacAsl9vUM_1 bird +FOnRpTgHAdI_0 person +FOyA2uyFS0s_0 car +FO-yhRhInHQ_0 motorcycle +FO_sYJabdgQ_1 bird +FPBkLbjkE0I_1 person +FPC9a1ebnRk_0 person +FPFEZjz68RM_0 person +FPHxPqZ9of4_0 elephant +FPIVRAQI9Ao_1 airplane +FPS-rWu8sfw_0 truck +FPdj2aDA2Is_0 person +FPd8NgysFbw_0 person +FPhiHYzZrc8_2 bird +FPmbKUp9Apc_0 person +FPoBK2S6-kE_0 elephant +FPpdaMeuTPM_0 person +FP-joReSPjM_1 train +FP-joReSPjM_4 train +FQBe4ewvq3k_0 bus +FQDYCsUTzLU_0 person +FQIKRtrwRJU_0 person +FQKMItJWON8_4 bicycle +FQNa7v1nuHs_0 bird +FQNa7v1nuHs_1 dog +FQPeEa0PIhY_0 person +FQQ5mFLQS_8_0 airplane +FQTA_Rs2r4k_0 airplane +FQa2-poPUOQ_0 person +FQiI3CA-HsU_2 person +FQiI3CA-HsU_0 person +FQiI3CA-HsU_1 person +FQnnRHyzLcE_0 boat +FQyvUPmvsSo_0 bus +FQ0G5VjpRO8_0 cat +FQ09pTeRKXM_0 person +FQ8nNpJodyM_0 person +FQ_PnAPHimg_0 train +FQ_YvOmwGng_1 skateboard +FQ_YvOmwGng_2 skateboard +FQ_YvOmwGng_0 skateboard +FRBmAObAjLg_0 umbrella +FRCsksZQW0g_0 motorcycle +FRFZtNbUMfU_0 person +FRFZtNbUMfU_1 person +FRKbwt_HIJY_0 cat +FRUF5D_Bg4I_0 boat +FRZeTLb7R70_0 person +FRcpw1KTh4w_0 skateboard +FRh68K9peM8_0 knife +FRs6gVga80M_2 airplane +FR0IeE_jWVE_1 person +FSCpm1kxTIE_0 umbrella +FSJSVNwlHck_0 person +FSSrkLtKRBk_0 person +FSchPfgxMmk_0 person +FSmTDuGYKRo_0 person +FSrvVBrHdIY_0 person +FSrvVBrHdIY_1 person +FSs-_cK-4DE_1 bird +FS8ZnDA42Xg_0 zebra +FTHxfldxSrg_0 person +FTlLAXuBE2M_1 person +FTlLAXuBE2M_2 person +FTlLAXuBE2M_0 person +FTr8b641J_g_2 zebra +FTr_sg-tAYA_0 person +FTr_sg-tAYA_1 person +FT7LfULOrmU_0 person +FUNI1-oxWb0_0 person +FUPer2xPyRM_0 person +FUQokq7Dm_0_0 bird +FUWPXNKt90g_0 skateboard +FUcLObUwigo_1 person +FUcQGevNVQs_0 person +FUp8cy7p6kc_0 person +FUt-f-8QJmk_0 boat +FUzb9oSwhq4_2 horse +FU63gEB5T14_0 person +FU63gEB5T14_1 person +FU-Gyo-nX8w_0 person +FU-Gyo-nX8w_1 person +FVGYeJ_eKRY_0 person +FVGYeJ_eKRY_1 person +FVSihamjW0c_0 person +FVcaEg-4Saw_0 airplane +FVm133076uE_0 person +FVxqyMXxbTg_0 person +FVxqyMXxbTg_1 person +FVyZRq7FJUM_2 person +FVyZRq7FJUM_0 person +FVyZRq7FJUM_1 person +FWAdovzWBpk_0 person +FWCxpF5CAAo_0 person +FWH6qzGM4Ko_0 cat +FWTx-_C46YA_0 dog +FWVW97tTSiI_2 skateboard +FWZANVS2JwI_0 bird +FWbVfjbC570_0 train +FWd_KJNB1hY_0 person +FWeJwZsAuq4_3 knife +FWiwkCVxsvU_0 airplane +FWpcgznz11Q_0 knife +FWqFrwl7d-g_0 airplane +FWqFrwl7d-g_2 airplane +FWuSKVVP9Gw_0 airplane +FXPnVqm98h8_2 car +FXbqlcQOm4U_1 car +FXcjcGBH8uA_0 airplane +FXdP8V2Fyag_0 bus +FXdevKY06to_0 bus +FXjUPTGnrIk_1 person +FXjUPTGnrIk_0 person +FXrzFKXFtUE_0 skateboard +FXvqDQa0_pw_0 bus +FXz3PiouB_s_0 truck +FX7DATABx3o_0 person +FYPRZ3A5Wug_1 horse +FYQxEw6enVw_0 knife +FYR_8E37mhY_1 boat +FZJlwJ_5CIY_0 person +FZJ0L36775Q_0 bear +FZOwW_igs2Q_0 person +FZUo3m0w40U_1 boat +FZXz9ivLbZE_1 person +FZfD0ASOr-0_0 person +eD5a0lOEA4c_0 person +eD5_C8Rnll0_1 cow +eD9mxZpbjpo_3 knife +eEBoNITml_U_2 airplane +eEBoNITml_U_5 airplane +eEKY2ZIJ7cw_0 person +eEKY2ZIJ7cw_1 person +eEUzIzmFpmg_0 dog +eEZirBqUuUc_0 cow +eErb9l8tm9Q_1 person +eEwALO20qQs_0 motorcycle +eEzaprIjPOA_1 horse +eE7zgmIkklg_0 person +eE_bJ6JguBg_0 person +eE_bJ6JguBg_1 person +eFDTDuBtPdg_1 elephant +eFIUN94eOFY_0 skateboard +eFKWB3vWXzM_0 person +eFNnJotKCuE_0 dog +eFQAqsrxJIk_1 cow +eFQAqsrxJIk_0 cow +eFYXRQfFBFk_0 person +eFYi8GYHOwc_0 bus +eFYi8GYHOwc_2 bus +eFYi8GYHOwc_1 bus +eFbHzEjDjsQ_0 person +eFbHzEjDjsQ_1 person +eFbOmylKLps_0 bicycle +eFbOmylKLps_1 bicycle +eFbOmylKLps_2 bicycle +eFbOmylKLps_3 bicycle +eFbOmylKLps_5 bicycle +eFbmkhM4yvA_1 skateboard +eFeLxXgEWb4_9 airplane +eFeLxXgEWb4_10 airplane +eFeLxXgEWb4_19 airplane +eFkMiDqxNNg_0 person +eFn7qz_Ik-g_1 bicycle +eFsEtWFKOCE_0 person +eFsEtWFKOCE_1 person +eFsJVO58dOk_0 motorcycle +eFsJVO58dOk_1 person +eFtXO4KQyP0_0 person +eF6vo2K3X7Y_1 horse +eGANqnJQvcA_0 person +eGEeIkSKn9I_0 person +eGFxLRdHt9o_0 person +eGIMcDTDuZI_2 giraffe +eGKe_SHbpew_0 dog +eGLaqISw-ZU_0 cow +eGXX9n0KkAw_0 train +eGavpqx_a-Y_1 person +eGeSgNqD64Q_0 cat +eGp90l6AeQM_3 horse +eGp90l6AeQM_4 horse +eGp90l6AeQM_6 horse +eGp90l6AeQM_7 horse +eGp90l6AeQM_1 horse +eGp90l6AeQM_2 horse +eGsO1ybeNmw_0 person +eGulNc3Hz6E_1 person +eGw-BT7HLw0_0 person +eGx11vRzfMI_0 person +eG420j0UncU_0 cat +eG9ay7ouawQ_0 boat +eG_gCk-NdFc_0 bicycle +eHFxA8eOkKo_1 dog +eHJOSAF8Ksc_0 boat +eHMokGJS_8k_0 bird +eHPZiFRZgH8_0 person +eHS3e7Drwlw_0 horse +eHYl5vL9urI_0 person +eHYl5vL9urI_1 person +eHZGFVBiNbM_0 person +eHhu8cP6sYY_1 truck +eHlKAc_jO3w_0 horse +eHlKAc_jO3w_1 horse +eHmn6jMH470_0 bicycle +eHo7GgOz-4M_0 bicycle +eHo7GgOz-4M_1 bicycle +eHpMDoo4x9o_0 person +eHpMDoo4x9o_1 person +eHrYu8_xQuI_3 airplane +eHuFhF5mn60_2 dog +eHuHorwvDFE_0 person +eH-lfDuzZRU_0 person +eIbRJYX77lM_1 person +eIceWO1K4hg_1 knife +eIlLo4L0TBY_0 person +eIm2mZqCQIU_0 person +eItSvz_9tc8_1 horse +eI5A6Q8wsk8_0 person +eJGswWs5a_U_0 person +eJJBtIMsces_0 cat +eJNeGPvJZBs_0 person +eJN7jtqxGc0_1 person +eJO3ahTuQlg_2 knife +eJTzEdYt2KA_0 person +eJTzEdYt2KA_1 motorcycle +eJZyuG0FB0M_1 person +eJg7Dq1HzW8_1 person +eJi66YisQnM_0 cat +eJnTGfqwSKw_0 person +eJntPRQdD6A_0 cow +eJntPRQdD6A_3 cow +eJxFV3LV_-o_1 elephant +eJzkkZWgmiM_0 person +eJ2omVOUJv4_0 person +eJ4AprAxRh4_0 airplane +eJ4AprAxRh4_7 airplane +eJ4AprAxRh4_5 airplane +eJ9q5sR4oiE_1 train +eJ9q5sR4oiE_3 train +eKBgCy3izjg_0 person +eKCONra70xU_1 person +eKGFKx5vbJw_1 bird +eKGFKx5vbJw_2 bird +eKJMggclbAI_0 truck +eKYCRb3cMSc_0 cat +eKcN648xBxg_0 cow +eKdNbqJsxIY_1 car +eKirxEVv1N4_1 giraffe +eKpHpiZZSOY_0 motorcycle +eKsu0SXh0Cg_0 giraffe +eK5wkhSqhQg_0 person +eLAIclbgwtw_1 motorcycle +eLAIclbgwtw_2 motorcycle +eLCZ9U490do_0 person +eLK_O-E6TXY_0 cow +eLLFV2_GBOs_1 cow +eLLFV2_GBOs_4 cow +eLLFV2_GBOs_5 cow +eLLFV2_GBOs_0 cow +eLLFV2_GBOs_3 cow +eLRLhwJpaKE_0 person +eLXWvZhL6g4_0 cat +eLfUxNIWQn8_0 cat +eLsJ-MoKt-c_0 motorcycle +eLzEA8IlB5E_0 cat +eL2OKu4DhkM_1 bear +eL-v_R-bG30_0 skateboard +eMJ8eEFu7lo_1 car +eMJ8eEFu7lo_3 car +eMN980Fn4Kc_1 horse +eMQEyMimXFU_0 cat +eMWM---NOF0_0 person +eMcgmNHMY_g_0 person +eMdVb5oIUWc_0 person +eMgUOtsKC0w_0 train +eMsSwXfIf7o_0 person +eMv2h_s0LpQ_1 skateboard +eMwSfQmonxM_0 bird +eM5e2PBO5hY_0 giraffe +eM-1RwyzQpI_1 truck +eM-1RwyzQpI_4 truck +eM-1RwyzQpI_5 truck +eNDHGq_Vm3A_0 person +eNEaC09BQF8_0 person +eNG3je3HCHI_0 person +eNG3je3HCHI_1 person +eNIXfUjWW10_0 bus +eNSkFxbG_L0_0 skateboard +eNTeTVBDq8U_0 person +eNVGmOIKNII_0 skateboard +eNVGmOIKNII_2 skateboard +eNYeXwUr7rY_0 skateboard +eNbwp7DEy6A_0 dog +eNbwp7DEy6A_1 dog +eNlXrdcWYPA_0 person +eNllsU_utBs_0 giraffe +eN0ufEmLTDM_0 person +eN3a3uFzNxw_0 person +eOJorgJNcl4_1 car +eOMSAOLQMc0_0 person +eOMro57lp5o_0 bicycle +eON5oS1ddkA_2 knife +eOXMKiuur7c_0 person +eOZ2mMo0l60_0 person +eOe9DskHw1g_4 airplane +eOe9DskHw1g_3 airplane +eOhLZkf2gyQ_0 person +eOj2KctQDKQ_1 bear +eO0M1RCeWaA_0 dog +eO9s3APOXdI_0 bear +ePDBmIR0Mnk_1 bear +ePEoVXrSERQ_0 person +ePPnXOa8FII_0 motorcycle +ePWPPUSuctk_0 horse +ePWPPUSuctk_2 horse +ePWPPUSuctk_3 horse +ePaqZZz_gtY_1 horse +ePgL4a_1DcI_0 person +ePgqzaxKKo8_0 person +ePhchRaBs-k_1 airplane +ePhchRaBs-k_2 airplane +ePjAF53eBSA_0 person +ePkzyffCJhs_0 person +ePli_zXbgF4_5 bear +ePli_zXbgF4_1 bear +ePli_zXbgF4_2 bear +ePli_zXbgF4_3 bear +ePli_zXbgF4_4 bear +ePoC0Pj8xLA_2 person +ePo6J3guHBw_0 person +eQA0KwcbJlQ_0 person +eQI72zFfl34_0 cow +eQI72zFfl34_2 cow +eQMmOyBJUaA_0 person +eQOqA8LeUOU_1 truck +eQOqA8LeUOU_2 truck +eQOqA8LeUOU_8 truck +eQS3V0HV61g_0 person +eQTlUSSbOyY_0 person +eQWRQaVSPT8_0 skateboard +eQXSsw2MJGk_0 horse +eQZEFoxVGuY_2 person +eQZOAGlSYBc_0 person +eQcocP3auyk_0 car +eQfbBM_c96I_0 knife +eQfbBM_c96I_1 knife +eQi8AZ4DQO4_0 airplane +eQjFi5iBL-c_0 skateboard +eQl0Q82jNOY_0 cat +eQmSzg2ZEpw_0 person +eQmSzg2ZEpw_1 person +eQoRdZR8_q8_0 person +eQpbjnMSNLE_1 bus +eQ1R5EruVgo_0 bird +eQ1R5EruVgo_1 bird +eQ2eWzgVggo_0 person +eRAZ8LnDRN4_0 person +eRBc8OmROx4_0 cat +eRCMzS-dM8o_0 person +eREzhoz4UA8_0 bicycle +FZieBxFsZO4_4 bird +FZieBxFsZO4_7 bird +FZieBxFsZO4_8 bird +FZieBxFsZO4_11 bird +FZsDQUdCBiE_0 person +FaINra3PYko_0 bus +FaINra3PYko_2 bus +FaINra3PYko_1 bus +FanmFyCIvSc_1 skateboard +Faxr0F1n4lk_0 person +Fa8JS9CCs60_0 person +FbC6M7cRN1k_0 person +FbLE0CqDZ_I_0 person +FbN-_RdBAoA_0 person +FbRfH2tJCZg_0 train +FbUasHXeVXg_1 person +FbVrmfwHLD8_1 car +Fba1mHso_c8_0 person +Fbcl3O89qPI_0 person +Fbryy4ItyRo_0 motorcycle +FbsxP5HIH-w_0 person +FbtbQbo3w6A_0 person +FbtbQbo3w6A_1 person +FbtbQbo3w6A_2 person +FbzdX2M1spw_0 person +Fb9GVgZUQkk_1 bird +Fb-bT-5HFvo_1 person +Fb-bT-5HFvo_0 person +FcAKq2q6WuI_0 person +FcGoc7P1MnA_0 airplane +FcHZFDzsW6U_0 person +FcI2xE1s0tE_0 person +FcJofbjqKR0_0 person +FcNTnULQ914_0 train +FcPxUMks1f8_0 airplane +FcQ9ypCnsnM_3 elephant +FcdE5l-9Cl4_0 person +Fcfkxe_EegE_3 skateboard +FckxSGw75TA_8 elephant +FckxSGw75TA_1 elephant +FckxSGw75TA_3 elephant +FckxSGw75TA_4 elephant +FckxSGw75TA_6 elephant +Fcmq6FVlPrs_2 horse +FcyT7NFOtOU_1 truck +FczLlZB8PPQ_0 horse +FdBcdDQa2Yc_0 person +FdG3QrZtdYo_0 person +FdM1BVOZnpc_0 person +FdM1BVOZnpc_1 person +FdYZH48B1gQ_0 giraffe +FdYpikKc6Rk_0 person +FdcxQx4sFow_0 person +FdgWx-kasEQ_0 car +Fdgw87Au0kg_0 person +Fdp1t1Kk42s_0 person +FdvgBe0Ix0A_0 person +FdvgBe0Ix0A_1 person +FdviMb1gxkI_0 elephant +FdyA9CQ40Xo_0 cat +Fd1Rn6HvibQ_0 bus +Fd1ZmuLPSNA_2 truck +Fd1ZmuLPSNA_0 truck +Fd1ZmuLPSNA_1 truck +Fd1ySlMqOEk_0 horse +Fd6kpMD00LI_0 person +FeAmji-BcLE_0 skateboard +FeHGwC6UYlQ_1 person +FeHGwC6UYlQ_0 person +FefqZU-M3NQ_0 dog +FeioRbELmKY_0 cat +Fel-MqoIa98_0 person +FenJI9gPekk_0 person +FevOpclGxX8_0 person +Fe0XVxKTD10_0 person +Fe1ne3adKqs_0 person +Fe1o0fdRyjk_0 person +Fe1o0fdRyjk_1 person +Fe1o0fdRyjk_2 person +Fe_r1BcuOm8_0 airplane +FfCfKve9svg_0 elephant +FfGzM6IRg6I_0 person +FfTyXxo_JLY_0 horse +FfWtRI5MlvQ_1 person +FfWtRI5MlvQ_0 person +FfddIx2fdDE_0 person +FfkcxMLN90Q_1 person +FfkcxMLN90Q_0 person +FfpScNxcfaE_0 person +FfpuED53W2w_0 person +Ff3kCsp4dss_0 horse +Ff37VadXulw_0 person +Ff37VadXulw_1 person +Ff-s3k4nzl0_0 cow +FgAW1wm55t4_0 umbrella +FgBAfHhZDtY_0 cow +FgCkJ9L956k_2 horse +FgHkoen3Fbs_0 person +FgHkoen3Fbs_1 person +FgHkoen3Fbs_2 person +FgK205YdiNI_0 zebra +FgaH6B8Im-s_1 person +Fgh-oweWR10_1 truck +Fgh-oweWR10_2 truck +Fgh-oweWR10_5 truck +FgkgjnYWuvc_0 motorcycle +FglWoBFeCGs_0 boat +Fgqe5FVDM7w_1 bus +Fgqe5FVDM7w_3 bus +FgtxhgrL-1s_0 bicycle +FhAkQ-D6j7M_1 person +FhNe0p3NvAk_0 person +FhS2OrbfOqA_0 horse +FhTIUIB4MQk_0 person +Fhdb7UXlKgw_0 person +FhhQQi3XBRs_0 person +Fhim9zq_3dc_0 dog +Fhtl-JSkWvY_1 skateboard +Fh1QSbERb_I_0 person +Fh1jlYGKYy8_0 cow +Fh2wm1SuBlM_0 person +Fh5hapK4iY0_0 horse +Fh-e1BaovqE_0 person +FiAj5FRP_QI_0 bear +FiAj5FRP_QI_1 bear +FiAj5FRP_QI_2 bear +FiGZEZ8BFeg_0 person +FiLeL7fMtKI_0 person +FiMl9o33Uaw_0 person +FiQbZpev_LA_0 person +Fim4ZNdANXI_0 horse +FipIgAA0lFk_0 bicycle +FirrKl6H41c_0 person +FirrKl6H41c_1 person +FivrGIBKDvo_1 elephant +Fiz1rnLi2OM_0 person +Fi4kJfnwDFc_1 bicycle +Fi4kJfnwDFc_0 bicycle +Fi7LPQxqu14_0 person +Fi9uLLmtWaQ_0 person +Fi_IAiAUqaU_1 horse +Fi_IAiAUqaU_0 horse +FjBRf4S85bg_0 elephant +FjBRf4S85bg_1 elephant +FjCz86a5wp4_0 person +FjF5nRRKjKc_0 person +FjMslXNPmHo_0 airplane +FjRDB5KtmZk_0 cow +FjUvDc65QJo_0 person +FjZltjNG2NU_0 skateboard +FjfP5wdsmM0_0 cat +Fjo3Q6r1Unc_0 cow +FjsVcnD_MIg_0 motorcycle +FjvoIjZBqfU_1 person +FjvoIjZBqfU_0 person +Fj98ZrblH1g_0 umbrella +FkAQLLdAAbk_0 elephant +FkAQLLdAAbk_1 elephant +FkFAVoUYxPc_1 skateboard +FkOkAlvY34U_0 cow +FkSrQgrkwxM_0 person +FkSrQgrkwxM_1 person +FkZy3LGoN9I_0 dog +FkkUslZGIbg_0 bear +FkvcJknwKuY_0 person +FkzewHxki8o_0 skateboard +Fk4XzK5XI6A_0 bus +Fk4XzK5XI6A_1 bus +FlD1RAiVpek_0 person +FlD1RAiVpek_2 person +FlD1RAiVpek_1 person +FlEhS-F3ygQ_0 umbrella +FlGO6UYJUzE_0 horse +FlNEteNmUhc_0 person +FlR1fAhH2Xo_0 dog +FlYY0RaMPNY_0 person +FlgN1oA45yM_0 bear +Fl2yqFTps4E_0 person +Fl6OhW0-1w0_0 person +Fl9EhNo7Keg_0 person +FmDFcSMFeno_0 person +FmDFcSMFeno_1 person +FmDOHRJspxI_0 person +FmMYoani5Vg_0 person +FmOLwdbHDxQ_0 person +FmOfXWRFoXQ_2 bird +FmUhkvEy_7s_0 person +FmUhkvEy_7s_1 person +FmVDxGIS5zk_5 train +FmVDxGIS5zk_7 train +FmVDxGIS5zk_8 train +FmVDxGIS5zk_9 train +FmVDxGIS5zk_10 train +FmVDxGIS5zk_1 train +FmVDxGIS5zk_2 train +Fmc6udEpldU_0 cat +Fme4Abd5nUA_2 bird +Fme4Abd5nUA_1 bird +FmoAxj0I_HE_0 person +FmqOvCWa7zg_0 person +FmrozJZpKR8_0 train +FmsAY671mqQ_7 knife +FmuPNtoqS2E_0 elephant +Fm1Depfmi_k_1 person +Fm5EMiek6AE_0 person +Fm6Hq8f2Qxk_1 airplane +Fm6Hq8f2Qxk_2 airplane +FnEnQ8PP_eE_0 skateboard +FnEnQ8PP_eE_1 skateboard +FnGScEGhwDA_0 person +FnKvuj-emb4_0 person +FnKvuj-emb4_1 person +FnMl1BAE_jc_0 bear +FnMl1BAE_jc_4 bear +FnNceIdqZ3w_0 person +FnNceIdqZ3w_1 person +FnTofG0IZf0_0 person +Fnb6xihA7ck_0 person +FncXKaqIxJo_0 person +FncXKaqIxJo_3 person +FniMTwzxRZQ_0 person +Fnv6GlZeZ98_2 airplane +FnwZm6-uVkU_0 person +Fn6j8CspFw4_5 horse +Fn6j8CspFw4_2 horse +Fn6j8CspFw4_3 horse +Fn6j8CspFw4_4 horse +Fn7CPx1Df1I_0 dog +eRGlFEYZ74g_0 person +eRQQ8fY6DVA_0 person +eRToPN2xDdI_1 horse +eRToPN2xDdI_2 horse +eRVbBhT_bcs_0 person +eRXcoQINrwY_0 cow +eRa3aIGemkw_0 person +eRiOVczmKs0_0 person +eRk0k7ru0C0_0 person +eRlVo64o3EE_0 horse +eRn_VZZAhDc_0 bird +eRpQzm5PYXw_0 person +eRvRu0q-GoE_0 dog +eR2L8Yeikhc_0 person +eR2s4XgNo7o_2 dog +eR6IwGLaa1M_0 bicycle +eR7y-Ei3DLg_0 person +eSGBtfzFobI_0 train +eSId-3VXvKk_3 dog +eSIwAUMyFgU_0 person +eSKH9cYOKk8_0 horse +eSPrJOSU8AM_0 train +eSa1vsOaz1c_0 knife +eSiLV8rS59E_0 person +eSiLV8rS59E_1 person +eSljhVPS-Ik_2 person +eSljhVPS-Ik_0 person +eSpAsKZSmiA_0 airplane +eTDKrXMMrQ0_0 cow +eTKPoRwNChU_0 person +eTKPoRwNChU_1 person +eTKSWSWvAyw_1 person +eTNf-Cqbbro_1 person +eTQF3UDg8qc_0 truck +eTTKvmF97nI_0 elephant +eTUWLCcJU2k_2 bus +eTU8LeMW9qA_0 person +eTc1z6mbb50_0 truck +eTdIp3O6Gdc_0 bear +eTkYJ5e2d6g_0 person +eTkbZ2QtHvw_0 train +eTkbZ2QtHvw_1 train +eTpyN9lx8_4_0 horse +eTsE0jLxU3w_0 truck +eTsE0jLxU3w_2 truck +eT3B8Dicg34_1 person +eT5K9fPU-0g_0 person +eUGoobFpS4s_0 person +eUKe6XaWIfA_0 motorcycle +eUQjLdCSTbY_0 person +eUQ4P2JG1yg_0 bus +eURPg0TbtFI_0 person +eUU0KJ-w2bc_0 person +eUVgOxQT_-8_0 cow +eUbEHnOzRA8_0 person +eUbEHnOzRA8_1 person +eUbEHnOzRA8_2 person +eUe_Rayk8X8_0 person +eUyzGl0--ms_1 person +eU6G8jITD_Y_0 airplane +eVJOOrHqc34_1 skateboard +eVL1UQ_nteE_0 car +eVNGBAn5Oxc_0 cat +eVPABDrI9js_0 bird +eVYydWvg5Go_1 person +eVcLRosJZew_0 person +eVhB8QJJogM_1 knife +eVn8akHyS64_0 airplane +eVn8akHyS64_2 airplane +eVn8akHyS64_3 airplane +eVn8akHyS64_6 airplane +eVuy4uctm28_0 person +eVu1gME4-Qs_0 elephant +eVu1gME4-Qs_1 elephant +eVywFyCLwko_0 person +eVzfhyg8qFU_0 person +eV2KIbTSnH4_1 train +eV4pA62ABv8_1 train +eV6nRsgY8PQ_0 person +eV64Qw4Zebk_0 person +eV-VIypuuNY_1 bird +eWHnCpVoKhw_0 truck +eWbvhqFVvXk_0 boat +eWlQOgHQT7g_0 airplane +eWpIepmfRus_0 person +eWpIepmfRus_1 person +eWsle8FxRvY_0 person +eWyDiulNMGo_0 motorcycle +eW6l7xJBq-Q_1 boat +eW6o2X8qAtQ_0 car +eXDegroOl34_0 person +eXECAC_iXPc_0 person +eXLLe0Z-fJk_0 person +eXUIt5B2NQc_0 person +eXYniqUW4z8_0 bicycle +eXYniqUW4z8_2 bicycle +eXaCA1qL7uY_0 person +eXeifN6Jv8c_0 elephant +eXeifN6Jv8c_1 elephant +eXeifN6Jv8c_3 elephant +eXeifN6Jv8c_4 elephant +eXeifN6Jv8c_7 elephant +eXfkthdw2L4_0 person +eXixQXmPyYw_0 elephant +eXoF6xS_5u4_3 knife +eXuelMqu_1M_0 knife +eXveKyc2TQg_0 horse +eXxAlPRFiqs_0 person +eXxAlPRFiqs_1 person +eXxAlPRFiqs_2 person +eX3bd4kHxuc_9 airplane +eYDpQFJpz7k_0 person +eYJe2k1E0XQ_0 bus +eYY-Mz3L_Ac_1 elephant +eYeHu-IftM0_0 person +eYnlQEvgHVc_0 cat +eYqlHj6MSc0_7 bicycle +eYyGqoW9Q3c_0 bus +eYyri5GAJDE_0 person +eZEN_5rnTLM_0 person +eZL3Ew4O7YI_0 person +eZXS_3nTpdo_1 motorcycle +eZXS_3nTpdo_2 motorcycle +eZZb5rnc1iA_0 bus +eZf-Rsr1aNs_1 train +eZgo_XfmmO0_0 person +eZgo_XfmmO0_1 person +eZl_FRsZx3o_0 person +eZym_LkJnpY_1 knife +eZ2Y_Qtg0VU_0 horse +eZ2Y_Qtg0VU_1 horse +eZ4N2Y737ss_0 person +eZ_peGgPSDE_0 person +eaHXGY8ImzY_0 person +eaOqHSeEVG0_0 elephant +eaR-dFaZRGc_2 giraffe +eaTX3J2X23g_1 person +eaTX3J2X23g_0 person +eaalMrdHsQ0_0 horse +earUgdES0lk_0 person +eaxPmkwGK5U_0 bird +ea1EeKBBjxk_0 umbrella +ea1YcZPjbxU_2 truck +ea4saeRZ0_M_0 person +ea8mbQn2kv0_2 dog +ea8mbQn2kv0_1 dog +ebFgEyNciRc_0 cow +ebMZJ-lUhbw_2 bicycle +ebMZJ-lUhbw_3 bicycle +ebMZJ-lUhbw_1 bicycle +ebOubiwIUC0_0 person +ebV9mcxICDs_0 dog +ebY5nNOPdN0_0 person +ebY52fJyTPs_1 person +ebY52fJyTPs_0 person +ebagV2pOV20_0 boat +ebhnTUXh7Pc_0 cat +ebh7xOXlO7Y_1 person +eboXP28MlOE_0 airplane +ebt0_AWnuyM_3 bear +ebyMEAOqPhQ_0 skateboard +ebz4umtEYag_1 motorcycle +eb0UO8Y5r5A_0 car +eb1-qD5D7Us_0 person +eb5d4XIDSqs_0 car +ecDEmZdWz8Q_0 person +ecGOS5ZO0Tw_0 skateboard +ecGOS5ZO0Tw_1 skateboard +ecJIf9dcDHk_0 person +ecKMZLATsNg_0 person +ecKst7suEZo_1 motorcycle +ecPynengjhg_0 person +ecUmR_974l4_0 bear +eccbjuLjCr0_0 bicycle +ecex13DrS00_1 bus +ecgqb4spDo0_0 cow +eclnV3fwFVg_0 car +ecndV9N-b9M_0 boat +ecrgwn6gB7c_2 person +ecrgwn6gB7c_0 person +ecrgwn6gB7c_1 person +ec0L5W9HzYQ_0 person +ec0zPF4t8jM_0 person +ec10-YUa1PE_0 person +ec4Mjwm2hyQ_0 person +ec4ya7ogbFU_0 person +ec59VG2krTI_0 knife +ec7hzm4ZgOM_0 bus +ec8daVdUMW8_0 elephant +edErePLiFl4_0 truck +edFb7FxjVPc_1 person +edOvHaEGfM0_0 train +edO7Q7znUJA_0 cat +edPmPMqUt4c_1 person +edPmPMqUt4c_2 person +edS79MnRXwE_1 person +edYcGdD4UGI_0 person +edd8R4oDMdg_0 person +edlAlkitTfg_0 bird +edlAlkitTfg_1 bird +edq1Zw1FWGY_0 person +edrtSs6UdCI_0 boat +edtqJ_N0258_0 person +ed0O35MjM6Q_0 cow +ed5jfyH6JyI_0 person +eeEjRmROBZs_0 train +eeEjRmROBZs_1 train +eeJDVUC0bio_0 bird +eeV0a3p0uz8_1 dog +eeYr-ujfh4Y_1 person +eeYtwUSuQzY_1 airplane +eeYtwUSuQzY_2 airplane +eeYtwUSuQzY_0 airplane +eeZyIsjtgj0_0 train +eeahFaPbx5M_0 skateboard +eea6uRdJLL4_1 bird +eee-1I8uLeU_0 cow +eefTfPIGkq4_1 person +eef-qkyU0jY_0 boat +eepn_UxMI5o_0 skateboard +FoFA-VOPhV8_0 zebra +FoIc9MjzbBk_0 person +FoSynLz7aJ8_0 horse +FoSynLz7aJ8_1 horse +FoUqmWxXlNU_0 person +FoUqmWxXlNU_1 person +FobAHnW_q6s_0 person +Fog-McdMlO0_0 person +FomH9b8uRKs_2 knife +Fot4m5WU4Aw_1 person +Fot4m5WU4Aw_0 person +FouVJvkYyPs_0 person +FpCdNHknwMQ_3 car +FpCdNHknwMQ_5 car +FpEzn8x46OE_0 bird +FpGO4RTCIuk_6 bicycle +FpGO4RTCIuk_0 bicycle +FpGO4RTCIuk_2 bicycle +FpGyjKY-NIk_0 motorcycle +FpGzMvzCvKo_0 person +FpI0Do5LaU8_0 person +FpTdRnuOS8M_0 person +FpTdRnuOS8M_1 person +Fpaob2f1sqE_1 person +Fpaob2f1sqE_0 person +Fpev0w7vGO4_0 person +FprxIVYXUL4_0 horse +FpzpuYeDf6M_0 bus +Fp1vbL5guA0_0 person +Fp2HgWZlr2k_0 person +Fp7RJqXwz6c_0 person +Fp-TG2XDrC4_4 car +Fp-TG2XDrC4_0 car +Fp-TG2XDrC4_1 car +Fp-TG2XDrC4_2 car +Fp-TG2XDrC4_3 car +Fp_5yBxyvR4_0 umbrella +FqFhpogmR2s_0 cat +FqHStgmNnKA_0 bicycle +FqHStgmNnKA_1 bicycle +FqTHQ5KBbaY_0 elephant +FqjhuAhttZw_2 train +FqjhuAhttZw_1 train +FquAMi_ikSA_0 truck +FqxWiT-6dLM_0 person +FqxZmvVkHIA_0 giraffe +FqxZmvVkHIA_2 giraffe +Fqx-wOpqzZo_0 airplane +FqzYUW3X9pc_0 person +FqzYUW3X9pc_1 person +Fq_esHSu_sk_0 person +FrC2HuRBsYA_0 person +FrC-Gp1GmVw_0 cow +FrC-Gp1GmVw_1 cow +FrIO6gNGeao_0 person +FrUCytgm6sM_2 horse +FrViqM6fVR0_0 dog +FrVxG6x7tj0_0 knife +FrVxG6x7tj0_2 knife +FrgvokGeeds_0 person +Frk0tcM1o_w_0 person +Frm5N8YRz_E_0 person +FrpsbU7nO00_0 person +FrxIGKawDiA_0 person +FrzgyfVukw4_0 person +Frz8huGrR4M_2 motorcycle +Fr0K__Q_Kv4_1 bird +Fr2qdnHURF4_0 boat +FsHjWJUILr4_0 person +FsScYp1HNk0_0 person +FsXYM3nf7O4_0 horse +FsZyoaRLGfw_1 person +FskWl7cTGUU_4 motorcycle +FslFjbzL4rY_0 train +FsuA_2-7e1w_0 elephant +FsuA_2-7e1w_1 elephant +FsvwyL1hLDU_0 bus +FswGt3qhUXE_1 horse +Fs6Lk0xDsWk_0 dog +Fs6Vua80iU4_1 bus +Fs-DmOC6Ksw_0 person +FtAgz58w2vs_0 person +FtC0Y3Dca60_0 dog +FtD8uBgTi3E_0 cat +FtJ8y0gIpKg_0 dog +FtJ8y0gIpKg_3 dog +FtJ8y0gIpKg_5 dog +FtJ8y0gIpKg_1 dog +FtJ8y0gIpKg_4 dog +FtMshKheG8Q_0 elephant +Ftet3EW_gR0_0 skateboard +Ftet3EW_gR0_1 skateboard +Ftj_1qTEwE8_0 cow +FtqLCjhRQgQ_1 person +FtqLCjhRQgQ_0 person +FtwMaVMlLbM_0 person +FtwZasadNWo_1 person +FtwZasadNWo_0 person +Ft3Xr78g1jg_0 dog +Ft4RUB75d64_0 horse +Ft5ZV3L5LV4_0 person +Ft8VPp_VNJs_0 knife +FuCuNV5vL-8_0 person +FuIIvsD7qyY_1 person +FuMf00RPDmg_0 bear +FuNvDTe7cAM_0 bird +FuR3p7f2R30_0 person +FuTf8iiIHWI_0 motorcycle +FuVQuZfX71w_1 elephant +Fuc49AUfyaA_1 train +FufG8eRehvk_0 person +FuoKMOMcl0I_0 bus +Fu3A7S4V26Q_0 person +Fu4p4U9AqY4_0 train +Fu5TDXXdHyc_3 train +Fu5TDXXdHyc_0 train +Fu5TDXXdHyc_1 train +Fu5TDXXdHyc_2 train +FvB0FA24g0c_0 motorcycle +FvD-5pXN6B4_0 person +FvF8CGSAVBw_0 horse +FvIqBpjD4A4_0 person +FvKJQTsxS6o_0 bus +FvNiWF5wWJA_0 truck +FvN6HD0c3I8_1 bicycle +FvQ8wYSFAhA_0 bird +FvZ_lMA5MYE_0 person +FvZ_lMA5MYE_2 person +FvZ_lMA5MYE_1 person +FvcxD9PJ1-g_0 bear +FvcxD9PJ1-g_1 bear +FviKCn2JGbY_0 person +FvksDxENves_0 bird +FvksDxENves_1 bird +FvmW4A9wN1c_0 person +FvslrkU6Ii8_1 skateboard +FvslrkU6Ii8_5 skateboard +FvslrkU6Ii8_4 skateboard +FvuJoToFsZ0_0 skateboard +Fv2LjW2C5SU_0 knife +Fv2LjW2C5SU_2 knife +Fv2SAN8CNlg_0 horse +Fv6OQz_y5V0_0 person +Fv80QjBLyXw_3 train +Fv80QjBLyXw_4 train +FwBCZ90I_aw_0 cat +FwIN5LlmnSA_0 person +FwMy9UR3xJA_0 person +FwMy9UR3xJA_1 person +FwNHDlUxkVE_0 person +FwSQA6A_bWE_0 person +FwZzzptQg0s_0 person +FwZzzptQg0s_1 person +Fwf5SGfOguQ_0 bird +Fwf_1L-RQB4_0 cow +FwhmGtqpt5s_1 skateboard +FwrkNuHACuE_0 person +Fwtyj6Ut62E_2 dog +Fw8NHywJSJw_7 airplane +Fw8NHywJSJw_8 airplane +FxHZCFGlLk8_0 truck +FxI0-u_zPQQ_1 skateboard +FxI0-u_zPQQ_0 skateboard +FxJg66y6Vj4_0 person +FxJ0douRc4s_0 person +FxMnA-aNvVI_0 knife +FxXVgnAjOCs_0 person +FxXVgnAjOCs_1 person +FxitbyLzBbw_0 person +FxmfshFrhyg_0 person +FxmfshFrhyg_1 person +Fxp_EDLEylo_1 bear +FxxuVRsJiCQ_7 bird +FxxuVRsJiCQ_9 bird +FxxuVRsJiCQ_11 bird +Fx74SXbZiUI_0 boat +Fx-8EgSEaDg_0 person +FyFea2NifCo_0 elephant +FyKB3iEKNlg_0 person +FyO1UliwWNQ_0 skateboard +FyQulDaVp8I_0 person +FyTFrxalrzY_2 bicycle +Fyb5_PxuzrI_1 airplane +FyjgIZnRT0A_0 person +FylDI9Ssx18_0 dog +FyqooE73pSs_0 train +FyuLo6pvAxk_0 person +FyuLo6pvAxk_1 person +Fy6UODQTxBw_0 dog +Fy8cULzM424_0 person +FzJOOqEWb48_0 person +FzP8vDH_ynM_0 bicycle +FzV_56qru4c_1 person +FzV_56qru4c_0 person +FzaaAJ_dGjI_1 dog +Fzc4L1eWvQ0_0 knife +FzeiG746wec_0 person +FzoJlCfL5bc_0 person +FzpV3zrU7w0_0 cat +FzufL9SIDZ4_2 person +FzvLoCiUbCU_0 person +Fz4RMW4ONrQ_0 skateboard +F0Ekv-HAlnk_0 airplane +F0G64yaBMBM_0 person +F0G64yaBMBM_1 person +F0I59IAm-vo_0 person +F0Qk5fG3X-M_0 person +F0Q9zBIa4vg_0 knife +F0Q9zBIa4vg_1 knife +F0Q_-7qxWws_3 elephant +F0UBtRxGNhA_5 bird +F0XjqeFLlgU_1 bird +F0ZAshDVPxg_0 person +F0c4qnJQtDU_0 bear +F0gFV3Zl1ew_0 train +F0gFV3Zl1ew_2 train +F0hx5kgZ3go_0 elephant +F0mBUyvb90Y_0 person +F0qXU9y4p-Q_0 person +F0z1cmfnPsQ_1 bicycle +F1B_Y1twDK0_0 cow +F1CZ2DPXJ9M_4 bicycle +F1CZ2DPXJ9M_1 bicycle +F1KHVI6XeVo_0 person +F1eNAhwM5Pc_0 horse +F1jGg9828BI_0 person +F1j27LEBSpI_1 car +F1qXLHQywDc_1 elephant +F1sQlUVWZLM_0 person +F15XLgp6ED4_0 skateboard +F2Bb2pFQRyU_1 person +F2EV6W4vdT8_0 bus +F2GhztG-3ZM_0 cat +F2HupbPd4Rc_0 person +F2JDbaIJXuM_0 person +F2JeBrL43Kg_0 person +F2JnnpLll3c_1 horse +F2Kd_wTgfHc_0 bird +F2N-fmDDyCs_0 train +F2an_w-D4WM_0 dog +F2bbT3y10lk_0 person +F2dx02YK1MY_0 cat +F2kBHcrY7Ck_0 person +F2nvlBMOvGc_0 boat +F2nvlBMOvGc_2 boat +F2nvlBMOvGc_3 boat +F2nvlBMOvGc_4 boat +F2yvXHbr1Us_6 bird +F2yvXHbr1Us_7 bird +F20W1m4x2Ys_0 person +F20_Ihwr_1Y_0 elephant +F21R2kQ-je4_0 person +F2244CO9Fuo_0 airplane +F250PqK5Gb4_1 airplane +F3AMItpIJlI_0 dog +F3AMItpIJlI_4 dog +F3FUBdTgY7c_0 car +F3FUBdTgY7c_1 car +F3Lz3rnQ-7A_0 person +F3Lz3rnQ-7A_1 person +F3NneLgyZiU_0 person +F3RkQzIQjeU_2 bicycle +F3XFJeSjPDU_0 bird +F3XFJeSjPDU_3 bird +F3gY7oCc-j8_0 cat +F3j318NP2P0_0 person +F3j318NP2P0_1 person +F3oP1Se_HdQ_0 motorcycle +F35JtGCIiCo_0 dog +F377W3trtdg_2 dog +F4DJmxH-fuw_0 skateboard +F4FXVb3DdJE_0 person +F4FXVb3DdJE_1 person +F4HgVMHEiVQ_1 bird +F4Ja9TDp5eg_0 person +F4R1rt0I4Ik_1 person +F4R1rt0I4Ik_0 person +F4WWEXEO6Cw_0 airplane +F4hUo05eI2s_0 person +F4hVb1AsJ9M_0 umbrella +F4hVb1AsJ9M_1 umbrella +F4hp-2UBFcI_0 person +F4l8U4NGPMU_1 elephant +F4rQJlBkGa8_0 person +F4tzOjT91r0_2 elephant +F41NWCYabpM_0 person +F44j0JHVdfU_2 bicycle +F44z7XXoIZk_0 cow +F4-R6x6hSno_0 airplane +F4-R6x6hSno_3 airplane +F5IEcbmSBiU_0 person +F5UiBt9FiQ4_1 truck +F5brWxznDYA_0 bicycle +F5drV0qDFvU_0 person +F5pSgana5Ds_0 person +F5pwABHMaZM_1 skateboard +F5y_lQCCiYk_0 person +F51aHL_AuQ8_2 person +F51aHL_AuQ8_0 person +F51aHL_AuQ8_1 person +F54NzXjey4Q_1 person +F6AkwJu9acQ_0 person +F6BUhbvKAY0_3 bear +F6I3hGIdHBM_0 airplane +F6L1DckOdFs_0 person +F6L1DckOdFs_1 person +F6L1DckOdFs_2 person +F6UTU1zVfY0_0 person +F6X-PDReV8U_0 skateboard +F6uVxnnSkQg_0 cat +F63FWqs6n6A_1 person +F63OB46zw20_0 person +F66U-dCKTVs_5 elephant +F67kQb83GEo_0 person +F7Aw74QT7I8_0 motorcycle +F7D1ccHfWQM_0 train +F7GYFMuRxr8_0 person +F7MruF3gqRk_0 person +F7MruF3gqRk_1 person +F7M2n9Irv10_0 person +F7adrDrejOI_0 bicycle +F7adrDrejOI_3 bicycle +F7adrDrejOI_7 bicycle +F7iFGXShjIg_1 knife +F7lmwAhsTVE_1 cat +F7lmwAhsTVE_0 cat +F7wyUoc1ELM_1 person +F7wyUoc1ELM_0 person +F72e40LPG8g_2 airplane +F72e40LPG8g_3 airplane +F72yH9hRoS0_0 person +F77I6mkMOmM_0 person +F77I6mkMOmM_1 person +F77WzfDD-Ac_0 person +F77WzfDD-Ac_1 person +F8VZcw3-DMg_0 person +F8XbiaxQYFA_0 car +F8kTGPYH29o_0 airplane +F8sVrU5FfZw_0 person +F8vyo42LQM0_0 airplane +F9KIXBo3lNI_0 bird +F9KIXBo3lNI_1 bird +F9WnfUhb8A4_0 boat +F9hhOJk3fdY_0 person +F9jiY40SX4g_0 person +F9kDOaogdPA_0 train +F9kDOaogdPA_1 train +F9nirQJj4wc_0 motorcycle +F9qYvrO4nMM_1 person +F9qYvrO4nMM_0 person +F942FTRne2Q_0 person +F95fIsG0A7U_0 horse +F98XVAomn1s_0 person +F-AROt5V1zQ_0 airplane +F-L2byRMMEI_0 truck +F-QpXlvCAdw_0 giraffe +F-RVugkjZ1k_0 person +F-RVugkjZ1k_1 person +F-dxzMmjOT0_0 person +F-dxzMmjOT0_3 person +F-dxzMmjOT0_1 person +F-poowwxrxU_0 person +F-3G1FhnsdY_2 cow +F-3G1FhnsdY_3 cow +F-7EAK7rTI8_0 bird +F_AoZsBu8j8_0 person +F_AoZsBu8j8_1 person +F_BBB0J-9tQ_0 motorcycle +F_CsG_jIxC8_1 truck +F_I4rwh1mtE_0 person +F_JJmqKJBnY_0 person +F_Kw8qyfgjU_0 person +F_WtOi2ZeSE_0 umbrella +F_oxJfyCUrw_0 person +F_wVAS7hR9E_0 cat +F_5NdFCcCrQ_0 airplane +F_59LD9YnAU_2 person +F_8qVC7MHM0_0 person +GABXImD8qwM_3 dog +GADBGhd7Hbc_0 horse +GAF3BbJqKos_0 person +GAF3BbJqKos_1 person +GAGFuwQyn2A_1 person +GAVdXzEftIU_1 person +GAaPJd_iVeU_0 train +GAb6ZqG64o4_0 person +GAb9NG_JnoU_0 cow +GAe7SnwoPQQ_1 airplane +GAg-aVsz7AI_1 person +GAinaDnPPO0_0 elephant +GAnYrNhN90c_1 person +GAoDRtFNSeQ_0 bird +GAoaBt8kfHQ_0 train +GApyoyRTlPk_0 person +GArUrBTpgzk_4 airplane +GArUrBTpgzk_1 airplane +GArUrBTpgzk_3 airplane +GAzsUwyCRAI_0 cow +GBF7wVda328_0 dog +GBLwQswYGpQ_0 dog +GBUiAfFHr8o_0 person +GBYAc4swbr8_0 person +GBYFzcFWKtI_0 skateboard +GBYeOSgHxaw_1 person +GBhV-vm_cDs_0 motorcycle +GBhV-vm_cDs_1 motorcycle +GBhV-vm_cDs_2 motorcycle +GBhV-vm_cDs_3 motorcycle +GBjWoHEvi24_0 truck +GBnf-AAsQts_0 person +GBvWcmiB_zQ_0 person +GBv60Rpf6hA_0 person +GBwqR6gIUJk_0 person +GBwqR6gIUJk_1 person +GB0RUQ72TDU_1 motorcycle +GB0RUQ72TDU_2 motorcycle +GB0RUQ72TDU_4 motorcycle +GB1A1gXLxF8_1 umbrella +GB1A1gXLxF8_0 umbrella +GB2Z9Zd9kCM_0 cow +GB3M7jlJvZo_0 umbrella +GB3dD_Sz5yA_0 cow +GCECUCM275I_0 truck +GCECUCM275I_3 truck +GCECUCM275I_4 truck +GCECUCM275I_1 truck +GCECUCM275I_2 truck +GCHyhn505e4_0 person +GCL5aSCyDAQ_1 horse +GCR8piyI8to_0 person +GCdYlCKelqg_2 bird +GCf79ImcoV4_0 truck +GCiR2DBKEUo_3 umbrella +GCiR2DBKEUo_0 umbrella +GCyZCLCX4jI_1 bus +GC5X3-Zi5fo_0 bear +GC_4PRhWwy0_1 person +GDBvvswiioY_0 horse +GDErDO6sQxg_0 person +GDHukw9i8AE_0 bear +GDPBufHJ6pE_0 person +GDVxjq335kg_0 person +GDVxjq335kg_1 person +GDW_ebhUmXg_0 person +GDeoeNk-jj8_1 train +GDgRHR5rt5g_0 dog +GDhVskUd-i0_0 truck +GDkTfXax1EI_1 person +GDr1CfMsWCo_0 knife +GDyR3j6e9uU_0 bear +GD0qZhFYMtE_1 bear +GD5H2vUIQUM_0 bird +GD7nVz18opA_0 cow +GEC16HE9LPs_0 skateboard +GEK0W7Soe5I_0 person +GEOILdSs_m4_0 person +GEXtPkuLXV4_0 person +GElPgxFGsYM_0 person +GEmM96O2bm0_0 person +GEoAqEILC5I_0 bicycle +ee4MHg5K9xo_0 person +ee4MHg5K9xo_1 person +efANTTg0s7E_0 person +efD7irKhsjg_1 zebra +efFDVTrJnI0_0 person +efQ-zUFNN-U_2 airplane +efQ-zUFNN-U_3 airplane +efQ-zUFNN-U_0 airplane +efQ-zUFNN-U_1 airplane +efUVmXxR3pI_0 person +efXikRhGmrs_0 person +efdHHLZ3g1Q_0 motorcycle +effHbT0DhsY_1 horse +effHbT0DhsY_2 horse +effHbT0DhsY_3 horse +efj0ZypW97U_0 person +efl9qpSfN9o_0 skateboard +efo_cgnnucQ_4 knife +efqCl5PWA5Y_2 bear +ef6fQWU1KdY_0 person +ef9zPCUJ5uQ_0 boat +egByT16s_54_0 person +egByT16s_54_1 person +egHnmalt3d8_0 horse +egQiifLgKHE_0 person +egVsaW3pIR8_0 bus +egotrU2sxIs_1 cow +egotrU2sxIs_0 cow +egymuz3YUjw_0 person +eg0xHA2KO2M_0 car +eg0xHA2KO2M_1 car +ehAg6V-5Puk_0 airplane +ehB-VoBE8As_0 person +ehFoBFIrRho_0 person +ehFvz7g6tcc_1 person +ehFvz7g6tcc_0 person +ehF--LpGjPU_0 person +ehI3hX4P2gg_0 bus +ehSU0TuduDM_9 boat +ehSU0TuduDM_0 boat +ehSU0TuduDM_3 boat +ehSU0TuduDM_7 boat +ehSU0TuduDM_8 boat +ehTOHuz8De4_0 horse +ehhoOXi21uc_0 person +ehhzn87_kyY_0 knife +ehpsJCYWhMo_0 dog +eh0-hoyeQv4_0 person +eh383O3j2o8_0 train +eh8ClQx55Pk_0 elephant +eh8ClQx55Pk_3 elephant +eh8ClQx55Pk_1 elephant +eh-Hpgj7SPM_0 bird +eiIxHOvvvog_0 person +eiKfZPTeN-M_0 person +eiMVAVfFk50_1 giraffe +eiNlPbSqaQM_2 bear +eiOC7H2_I7E_0 motorcycle +eiYV7UFe9_4_0 person +eiZm5CglnLc_0 person +eiirsESzuHs_0 bicycle +eim8NPBqZXg_1 person +eis2vlxPtf4_1 person +eivFKGFBySc_0 person +eivMnaQyUKU_0 person +ei0PFx0qNIQ_1 person +ei0PFx0qNIQ_0 person +ei4Yn0KXnAM_0 person +ejDpzIUHAMk_0 person +ejD4KjqrkFo_0 cat +ejIMw0_a1Zo_0 person +ejIMw0_a1Zo_1 person +ejVKT8cDDTY_2 motorcycle +ejoDQZqi4DU_0 person +ejsflVtvinE_0 dog +ejzqfqBU2XY_2 horse +ejzqfqBU2XY_0 horse +ejzqfqBU2XY_1 horse +ej5D22-gpzY_0 person +ekBhYo1n09M_0 person +ekGn7Al_5S0_0 person +ekOQkNLi9gA_0 person +ekPQmhXqsJs_0 cow +ekQPPxQDQrA_0 bird +ekYErFjRBcY_0 person +ekaQzIhIz6U_0 person +ekhId7QWajE_0 person +ekw22HGT0TY_0 person +ek6F1Yy6r4g_1 person +ek6F1Yy6r4g_0 person +ek9m3wFRD78_0 motorcycle +elAJmgZ3uV8_1 person +elIopJ6sLS8_0 motorcycle +elS7CV83kDQ_0 cat +elbH9USSXbU_1 person +ele_x5If5RM_0 cat +elfDIDNaxO8_0 bicycle +elfDIDNaxO8_1 bicycle +elk9Eg_zAzA_0 horse +elwOqTHVPb4_0 car +el_1tnvsCAY_0 elephant +emAlGe0D2Ro_0 car +emBk5WfF9MA_0 person +emFvwwYH0Dk_0 person +emLp02HobE4_0 person +emO2DsNKmTw_0 train +emVjapACNME_0 person +emWHcaPL5H0_0 person +emXkTzHEyT4_0 boat +emhCPyXIbNk_0 person +emqrQO4JZsU_1 skateboard +emxIavKneZw_0 person +emzfRpng4hM_0 bicycle +em3XyVBpKCc_0 train +enA3HVeW4MM_1 person +enCpXewY40c_0 truck +enCpXewY40c_1 truck +enR0OQhVBwE_0 person +enWAeU6n9LQ_0 person +enXS9AGUoow_0 motorcycle +enY96p1ZALE_0 knife +enfPrTim6AU_0 cow +engcDIwacLg_1 person +engcDIwacLg_0 person +en06DIx0cz0_1 person +en06DIx0cz0_0 person +en6AOaqCY1s_0 truck +en9gUgAJoek_0 person +eoFFf1yMhOg_0 person +eoauVNDdle8_0 person +eodvToXk2OQ_1 cow +eodvToXk2OQ_0 cow +eohpHQHPoXo_0 dog +eovUEztTVZ4_0 person +eoyj6UfwM1c_0 airplane +epIcFi7yUZg_3 cow +epK_YUgNzQI_0 cat +epUTWEmTW1o_0 bus +epXYWAgJeJM_0 person +epZSAxAzWRs_0 person +epeLK68bI3k_0 person +epeLK68bI3k_1 person +eph8ACa_bv4_0 person +eph8ACa_bv4_2 person +epis0oQPudE_1 person +epu8oDLyhBw_0 cow +epxbwMupoU0_0 truck +epxxfkiUpVQ_0 person +ep15pnX1AxU_0 truck +ep4od2aZYv8_0 dog +eqAMk_GzwUg_0 truck +eqMRouLMQI0_0 person +eqPXFnE2SxE_0 person +eqTdm4-YomY_0 train +eqWb0eTMl98_0 cow +eqiPG6XAei8_1 person +eqiVR6aa8XA_0 person +eqnF1_Lwa94_0 motorcycle +eqswu7XtVeE_0 boat +eqswu7XtVeE_1 boat +eqvu61eQ-D0_0 person +eqwZeHPEjT0_0 bus +eq2VUeTEEGM_0 elephant +eq2VUeTEEGM_1 elephant +eq2-yJIiWyA_0 skateboard +eq7fzAhOZEo_0 person +eq8-99wqpC4_0 motorcycle +eq-XVpUOFlQ_0 cow +erDb15O0GYM_0 person +erIMuEor6gc_0 person +erJzcEpQ-sA_0 person +erKEWcCPgjU_0 person +erKRZXMcCzQ_0 bus +erLW6pBgIrE_0 person +erLW6pBgIrE_1 person +erWerfoGejo_1 dog +erZ0-WmkPj8_0 person +erfJrdfPp8M_0 truck +eri-jOmjJ5U_0 person +erprzr0GCa0_0 person +errX-c_luf8_0 horse +erwHbfRwbDc_0 train +eryYeuoNAdw_0 person +esEKixC0bi0_0 motorcycle +esFUx8MS7FU_0 person +esFUx8MS7FU_1 person +esHEHZv3XAw_0 person +esdMTvdz7G8_0 person +esd9prHEDmY_0 cat +esnr6cTpfQI_0 skateboard +esnr6cTpfQI_1 skateboard +esrkVh27SSg_0 giraffe +esr3dKZtZ9I_1 person +estRADheTso_0 person +esxEV1BYf8g_0 dog +es0lurDiGrM_0 truck +etCrz_vcvJI_0 zebra +etFtHhL2hac_6 bicycle +etHjccaFHjw_0 person +etZXvy6wqZM_0 cat +etZjkcz1NXE_1 person +etfOefeQ0NA_2 knife +etgjVXNON5k_0 person +ethiyhktDW0_0 train +etrQY3yeg8M_1 person +etrQY3yeg8M_0 person +etu6chaT_o0_0 motorcycle +etu6chaT_o0_1 motorcycle +etu6chaT_o0_2 motorcycle +euNO4mGjpL4_0 person +euS2rEsG-jA_0 person +euaiFpmh6SU_1 person +GEuy-JvOFBM_0 horse +GEwLV10zHSM_0 person +GEwYE_QVNHE_0 boat +GE061if8j60_0 horse +GE8D0jEjasg_1 bird +GFCN_4akSi4_0 person +GFMwf7Ly_Sc_2 person +GFMwf7Ly_Sc_0 person +GFN08ryY-U0_2 knife +GFTwQgse_Lk_4 knife +GFXh14V5BN0_0 cow +GFkCQFowcfs_0 person +GFkCQFowcfs_1 person +GFlTNatYs1E_2 horse +GFlTNatYs1E_0 horse +GFmBVLxS0W4_0 person +GFsVA4Rxqv0_0 cow +GFtZEmPze30_0 person +GFytNaOS7eE_0 boat +GF28RuK9Mio_0 person +GF28RuK9Mio_1 person +GF29WU5hVFU_1 umbrella +GF29WU5hVFU_2 umbrella +GF4b86WLzWE_0 person +GF-zdmzb4zY_0 bus +GGBhXIkXN-U_0 dog +GGCSOyr8iNg_0 cat +GGNkUcwxgU0_1 airplane +GGX2r0RT9h4_0 bird +GGY5BDDn5LE_0 person +GGtf7t-SVb0_0 person +GGytoCC23B4_0 dog +GG2kiaUm9pg_0 person +GG_CxOFs69U_0 bicycle +GHAR-041e4w_0 person +GHF_00q4fw0_0 person +GHN9eBe1Bp8_0 knife +GHWPuquucrM_0 cow +GHZjWHKMwyw_1 truck +GHqedSEAQ9k_1 person +GHqmzbJnjVg_0 person +GHu-Q-Jbh6E_0 umbrella +GH_-l0dCs1A_0 truck +GINmKyxk55E_0 person +GIOByl4-GaE_0 person +GIQcZHeI0rA_1 knife +GIRWosek2kk_0 person +GIesL1NmKrU_0 airplane +GIiKoRSDN-Q_0 skateboard +GIiKoRSDN-Q_1 skateboard +GItE5rGj_-g_0 person +GI0iwCtSgJY_0 person +GI7YeWGyVRM_0 horse +GJAe8ctAWb0_0 person +GJHbNDEY178_1 person +GJHbNDEY178_0 person +GJIPOsnsWAg_0 person +GJIPOsnsWAg_1 person +GJL8p4_PeKo_0 person +GJMk0Meedm0_0 person +GJbtzWK_dYk_0 person +GJpkQJ1A6Gw_1 cow +GJy5Zhvk6lE_0 person +GJ1O_aGTN94_0 motorcycle +GJ4kWS7SklQ_0 person +GJ7mp6eUiPg_0 car +GJ9641JuJGs_1 person +GJ9641JuJGs_0 person +GKCr5DPt-O4_0 car +GKC9zObtOMM_0 person +GKEhy910De4_0 train +GKWJ0lgaDCg_0 umbrella +GKWJ0lgaDCg_2 umbrella +GKewJtAM0mQ_1 person +GKewJtAM0mQ_0 person +GKhEkZ-cdNQ_0 train +GKlP0uncbyg_0 person +GKlP0uncbyg_1 person +GKlP0uncbyg_2 person +GKlP0uncbyg_4 person +GKmEvD6kEV0_0 bicycle +GKn-IcumftE_0 person +GKpcLh6EzTI_0 truck +GKs6SswOMow_0 skateboard +GKyR_cV3NzE_0 bird +GK1HKUicpqc_0 person +GK7khWET2AA_0 person +GLBHzmRhRXw_0 person +GLCLinUtVWM_0 person +GLJJdMPYSaY_0 person +GLLgtpj5VIc_2 elephant +GLLkz3ew2Cw_0 person +GLN48vyNNE8_0 person +GLOfyCC7cpg_1 person +GLOfyCC7cpg_0 person +GLTbuhg3c9c_0 cow +GLTcmtEP3PQ_6 person +GLTcmtEP3PQ_0 person +GLTcmtEP3PQ_1 person +GLTcmtEP3PQ_2 person +GLTcmtEP3PQ_4 person +GLT0qdbJFmE_0 person +GLYc7lsUKvQ_0 cow +GLemLQ7Taz4_0 dog +GLiiNf5XBGw_1 person +GLnBX7vZMds_0 car +GLncyVpSovs_0 person +GLonpYW6Yi8_0 person +GLsxpYW-07A_0 person +GLy3RuBdLZ4_0 giraffe +GL2K160VZnM_0 airplane +GL5i6mrfwJQ_0 person +GL6eTReYh8E_0 giraffe +GL7g579uon4_0 bus +GL_EwiiBm1A_1 person +GL_EwiiBm1A_0 person +GMCQFxoF1UE_0 bear +GMJi6djWGYg_0 elephant +GMLP7F_Da2w_0 person +GMVqWicQ2d4_0 motorcycle +GMeN9Z1A9X4_0 car +GMj9b1A2R98_0 bus +GM3BiiUS2Xw_0 cat +GM31sVP8NMA_0 elephant +GNJ088XwXpI_2 skateboard +GNLzZ4OPnHc_0 boat +GNLzZ4OPnHc_1 boat +GNN-BevC79g_0 knife +GNRZ4AjoiSE_0 airplane +GNawMpiTEFs_0 person +GNnrNuC9zGU_2 person +GNnrNuC9zGU_1 person +GNqCvE7d9mE_0 person +GNr1nF-F-40_2 boat +GNvEs3KBgRw_0 person +GN97F0ERx8k_1 person +GN97F0ERx8k_0 person +GOE3QOj97xk_0 person +GOLZ7CWDXjk_1 person +GON778LYTqk_0 person +GOQICMUoGL8_2 person +GOWRiwkZo2U_0 person +GOW84-_w-LQ_0 bicycle +GOZwEuPDmzc_0 person +GOb0e4ojb3c_0 airplane +GOkeNGfFi8Q_0 person +GOkeNGfFi8Q_1 person +GOpAs6aca30_1 person +GOpAs6aca30_2 person +GOrO-A4yd5c_0 person +GO0RyAWdVQA_0 person +GO1tmJmOjZU_0 cow +GO9YRVC_2SA_3 elephant +GO9YRVC_2SA_4 elephant +GO98cqZbP2o_0 car +GO98cqZbP2o_1 car +GPABD8HFpQU_0 skateboard +GPCArlk4udc_0 bird +GPHwY1J1u04_1 cat +GPLKI0foxxc_0 person +GPUUqd1IyNA_0 dog +GPUdCDtaGOQ_2 boat +GPViSMkz1ds_1 horse +GPViSMkz1ds_0 horse +GPZznxc87vA_0 cow +GPlHiCxNeIU_0 person +GPnO7jt_-JI_0 person +GPn2JSguaBI_4 umbrella +GPn2JSguaBI_0 umbrella +GPn2JSguaBI_1 umbrella +GPtN0Kb9qZs_0 train +GPzwYc908OM_0 bicycle +GP2YaQXsf0s_0 umbrella +GQJu2FlmC0A_0 knife +GQRDl6gw-n8_2 bear +GQRDl6gw-n8_3 bear +GQV1QfplpXU_0 person +GQ6mrqpELDs_0 person +GQ99sfZjwTo_0 person +GRMv9irLuQw_0 motorcycle +GRQUwn0jA8Q_0 person +GRRXv9O7hNk_0 motorcycle +GRRullNXQUY_3 skateboard +GRTcBPmHWPU_0 motorcycle +GRjf8G-WDvc_0 person +GRk94EZiwO8_0 skateboard +GRo9Bmi4ghA_0 cat +GRwCcOF0NyI_0 train +GRwCcOF0NyI_3 train +GRwCcOF0NyI_1 train +GRwCcOF0NyI_2 train +GRwvd8Xl-l0_0 bird +GR5qTAjCnB4_0 cow +GSD3hdUWKNg_0 person +GSD_Asi3tsA_0 elephant +GSD_Asi3tsA_6 elephant +GSIFRlloCGA_0 cow +GSMYNBUuI74_1 motorcycle +GSb8ilGRCd8_0 umbrella +GSkpDZZFQd4_0 boat +GSmR-G7zCN0_0 airplane +GSqatXKKzUU_1 boat +GS1El_XLryU_3 bird +GTaW87cQCZk_0 bird +GTegSO4BiDY_0 person +GTgztSxvdzw_0 horse +GTg35QGB0bQ_1 person +GTg35QGB0bQ_0 person +GTjqtTiUFFA_0 person +GTkZ7eZIV5I_0 skateboard +GTpF9CW8Kyo_2 cow +GTpF9CW8Kyo_3 cow +GTpF9CW8Kyo_0 cow +GTpF9CW8Kyo_1 cow +GTt9sqczKqg_0 person +GTuP3gwjf70_0 person +GT4askC-EmE_0 skateboard +GT4askC-EmE_2 skateboard +GT6Ta63CfGc_0 bus +GT7pB1SoSWQ_0 horse +GUA64cJx_1s_0 person +GUG7toTLyt4_0 bear +GURTVjQ25hM_0 airplane +eufhHTT-6cc_0 person +eujtr13Kbtg_0 cow +eutsycO_2Zw_0 umbrella +eu0WWqOzPNI_1 boat +eu07YiPAVxk_0 truck +eu6zY6HpY1M_0 person +evA7SzcjAkU_2 knife +evA7SzcjAkU_3 knife +evA7SzcjAkU_0 knife +evDr0RJRRV8_0 horse +evMMyqn2S94_0 person +evRaMSC7xlI_0 train +evVOgDU7DsE_6 truck +evcE8ru07G8_0 umbrella +evcWn6cN50A_0 umbrella +evhP2M5P0rM_1 person +evksM4sehcQ_0 cat +evtk4IiqjkM_1 person +evw-tqTTtQ8_0 horse +ev1ATOeJPxY_0 person +ev1ATOeJPxY_1 person +ev53NALjp3I_0 person +ev7a6Z-ZOv4_0 person +ev-fVsUuvfA_0 person +ewB46nb-ZFI_0 bird +ewFZmQCCZm0_0 truck +ewFZmQCCZm0_2 truck +ewOgoCimrdA_0 elephant +ewUWpmdjLHA_0 bicycle +ewUWpmdjLHA_2 bicycle +ewgdEY7GtsQ_1 airplane +ewkBRzmoZzo_1 train +ewkBRzmoZzo_2 train +ewkeB8zzSVE_2 dog +ewkeB8zzSVE_3 dog +ewkeB8zzSVE_1 dog +ewoUjWEEJS4_0 dog +ew9rbdv73TA_0 umbrella +exR3lT_G3Yk_0 knife +exZF88kJoP8_0 person +exjWaQ0ssbM_3 airplane +exjWaQ0ssbM_0 airplane +exjWaQ0ssbM_1 airplane +exn-_MfEP6Q_0 person +exoNfV0vU_Q_1 person +exoNfV0vU_Q_0 person +exw_qJh1qp8_0 cat +ex6Il_1Ielw_0 motorcycle +ex7mPB9cYwc_0 person +ex7mPB9cYwc_1 person +ex-yo1W_s34_0 skateboard +eyAxkbxVdHA_0 person +eyAxkbxVdHA_1 person +eyNJXyldIhM_0 person +eySeJsY8tZU_0 horse +eyZeTi4-udw_0 boat +eycvZhhuzOI_0 person +eyd3cO1cRyw_0 person +eyg_dFAAJ_c_0 umbrella +eyi_kSPelbM_0 person +eyo2iTfyALs_0 cat +ey49lNbkqdQ_0 person +ey7evH7qmFA_1 person +ey9CIllx21w_2 truck +ey9CIllx21w_5 truck +ey9CIllx21w_8 truck +ezOxb6H18Dk_0 person +ezX_8NsARn4_1 person +ezYCeDV1Aew_0 bicycle +ezam_iANUkY_0 motorcycle +ezdehi1wmW4_0 cow +ezktd-PtOQo_2 horse +ezktd-PtOQo_3 horse +ezrNhnjWp-s_0 person +ezrNhnjWp-s_1 person +ezu6OcJjjLk_1 person +ezvAmpvi364_1 person +ezyLlrEVZRU_1 train +ez4u6-2yh8U_1 person +ez7mJtg4aoU_0 cow +e0Al-yQwL8w_1 bear +e0C174hEUpI_0 person +e0HCj6FnKMo_0 person +e0HrgDMAL5c_0 boat +e0K-Wc2SGSk_0 person +e0V--elE2Dc_3 boat +e0V--elE2Dc_0 boat +e0XejLvBbTw_0 motorcycle +e0dXS2okSxo_0 train +e0jUh6hQykw_0 person +e0jUh6hQykw_2 person +e0kJTvItoXc_1 person +e0kJTvItoXc_0 person +e0qJxStHuGA_1 skateboard +e0rXPv5Q8ac_0 person +e1KQ3rXcBVg_0 airplane +e1KQ3rXcBVg_2 airplane +e1KQ3rXcBVg_1 airplane +e1S7tY6zlBs_0 bus +e1ZNGYPt280_0 cow +e1a0tLtZdm8_0 person +e1dAdTW0-s8_0 person +e1guDr5Lq88_0 person +e1iYijyYnIc_0 person +e1iYijyYnIc_1 person +e1v5-Vy3ikU_0 motorcycle +e11u2SRsMQk_0 umbrella +e110Ssoc3rc_0 horse +e2Biqc_Y8fI_0 boat +e2Biqc_Y8fI_1 boat +e2C6vpxx1BQ_1 person +e2C6vpxx1BQ_0 person +e2DeceLJ4QU_1 elephant +e2DeceLJ4QU_0 elephant +e2DmJ2nN-bM_0 person +e2DmJ2nN-bM_1 person +e2IXk3LUK0k_1 truck +e2Jc499uBac_0 bus +e2MbvKCUxBQ_0 skateboard +e2oWEimFUeM_0 boat +e2oWEimFUeM_6 boat +e26M0NUTUcs_0 person +e29Si0sk8Vs_0 person +e3Ep8F-TVbQ_1 bicycle +e3Ep8F-TVbQ_0 bicycle +e3MrKt1yh3E_0 airplane +e3ezeG4Gm80_1 knife +e3fz03vzrmQ_0 person +e3pGW6uqeQA_0 cat +e3tP581aZ0Q_0 person +e34jQApS9Bw_0 person +e3_zIH1Jrf0_0 person +e4R8Aj-X5iA_1 horse +e4ZrrwoRRXc_0 bear +e4c8OdRhAyA_0 knife +e4c8OdRhAyA_3 knife +e4iZ27N3agg_0 person +e4rO9AJXQzY_1 person +e4yT58KhTcs_1 airplane +e4yT58KhTcs_2 airplane +e4zdJYlc4z8_0 person +e47QRGUx_Hs_0 truck +e47QRGUx_Hs_1 truck +e48A0CBQct8_0 person +e5CFfGS4B1s_0 person +e5DZWu7GqG4_3 bicycle +e5MbNYLt7wU_0 person +e5MbNYLt7wU_1 person +e5RlRpaBXnE_0 dog +e5UjJAZHaBc_0 person +e5VUEXqXFTM_0 umbrella +e5kfPy-MIGw_0 elephant +e5lFDgi4EIs_0 cow +e5-Pz_Q8VUA_0 person +e6F88LQJoLc_0 person +e6G0gHixPGE_0 boat +e6IQ-jfygns_0 person +e6IQ-jfygns_1 person +e6T5hbKQwAs_0 person +e6aWxOF189s_0 person +e6hz-jEGxsg_0 person +e6muu75RFmg_0 bus +e6s13mZyuYY_0 skateboard +e6s13mZyuYY_2 skateboard +e6s13mZyuYY_3 skateboard +e6xT3S6wuwE_0 person +e64lVlYKNYs_0 horse +e7IeNjbA7ms_0 motorcycle +e7JZ2C-e9_w_1 skateboard +e7Q3z9gbUw8_0 skateboard +e7TKWwysO8Q_0 elephant +e7W79Xp4qxI_0 person +e7aF0fG2O2U_0 bear +e7aF0fG2O2U_1 bear +e7eZQb8WjmQ_0 person +e7xAzZCvd_Y_0 truck +e70XtlB-Au8_0 truck +e70XtlB-Au8_1 truck +e70XtlB-Au8_2 truck +e70XtlB-Au8_3 truck +e70XtlB-Au8_7 truck +e70jqVThihE_3 knife +e70jqVThihE_1 knife +e72VJJ7jkoI_2 airplane +e76gr0pJMLg_0 boat +e8BQbcBgcjc_0 person +e8VeeESy9Xc_0 horse +e8XzpXJnucs_0 motorcycle +e8XzpXJnucs_1 motorcycle +e8XzpXJnucs_2 motorcycle +e8Y4hXyFPDY_0 person +e8ZFu6n4mg8_0 person +e8b7eo56B5Y_1 person +e8b7eo56B5Y_0 person +e8mSJe1G9U4_0 horse +e8mSJe1G9U4_1 horse +e8mSJe1G9U4_3 horse +e8mSJe1G9U4_4 horse +e804z6ehgWE_0 train +e836XbTclWA_0 person +e86xkdgTdTA_0 person +e873uWjeaPU_0 person +e88X3OKvqTI_0 cow +e9Ceg407V2o_1 bird +e9GSzFiQj8I_0 person +e9GoxfmycMQ_0 person +e9MugXot7JI_0 elephant +e9MugXot7JI_2 elephant +e9MugXot7JI_1 elephant +e9Y8BHEdYpg_1 person +e9Y8BHEdYpg_0 person +e9Z237Wup_E_0 boat +e9aADbJBMmQ_1 boat +GUY72Rg_9g4_3 airplane +GUY72Rg_9g4_0 airplane +GUY72Rg_9g4_1 airplane +GUY72Rg_9g4_2 airplane +GUcZWh6tol4_0 cow +GUq5xrqphew_0 cow +GVCJZzVnGUQ_2 person +GVCJZzVnGUQ_0 person +GVCJZzVnGUQ_1 person +GVG_dHMt7eA_0 truck +GVRLfBtpGgA_0 person +GVeNt6hXwK4_0 person +GWCwYIRE8YU_0 person +GWIAU4GsgZM_0 person +GWQD6FxWwpk_0 boat +GWckuI3sTHA_0 bear +GWmOpSmpGmg_0 car +GWmOpSmpGmg_1 car +GWmOpSmpGmg_2 car +GWsXKIAM9yY_1 cat +GWsXKIAM9yY_0 cat +GWygvbszdUs_1 train +GXS6axKBr7A_0 person +GXX1pJeR1HE_0 elephant +GXX1pJeR1HE_1 elephant +GXZ3IXi7YXk_0 person +GXcbgDsx_Zc_0 person +GXfsYdVEMeA_10 elephant +GXfsYdVEMeA_0 elephant +GXfsYdVEMeA_5 elephant +GXfsYdVEMeA_6 elephant +GXfsYdVEMeA_8 elephant +GXgoAnrkdVg_0 person +GXiDQ52vcoY_0 person +GXoA1zfvnOA_0 car +GXrzW-OHh_Q_0 cow +GXtA9dxzvII_0 person +GXyeuhOYX2k_0 truck +GXyeuhOYX2k_1 truck +GX1v3ymtHtc_0 person +GX-3aTTy4lM_0 person +GX-3aTTy4lM_1 person +GX-3aTTy4lM_2 person +GYA-3PblNaU_0 person +GYHWtVM2x6c_0 person +GYTD79P3b8w_1 person +GYT5Cq1tl2Q_0 cat +GYWNYnWPaeE_0 person +GYY-ElZl7ZM_0 dog +GYldHkVSD_A_3 airplane +GYmeM7epDjY_0 person +GYmeM7epDjY_1 person +GYoXwAkvJns_0 person +GYsx_49_O1U_0 truck +GYuIsHEGV6o_0 person +GYuMuXQgLPI_0 person +GY0HVEiAPvo_0 person +GY3D9bb9kLY_0 airplane +GY65ShkktrM_1 person +GY9iCFFBA20_0 person +GY-carc6vxw_2 horse +GY-carc6vxw_3 horse +GY-carc6vxw_4 horse +GY-dmOLQNH4_0 truck +GZIpKCyb0bU_0 airplane +GZLsv-Y_aRw_0 person +GZM5nvvMeNo_1 airplane +GZOUGcF_xaM_2 train +GZThnpa-8Ak_0 train +GZUk3BlrK7k_0 person +GZWH1bUqm9U_0 person +GZYSkuRZwGE_2 skateboard +GZb9G8sVRz4_0 person +GZb9G8sVRz4_1 person +GZgL3ZQI9nM_0 cow +GZhuCclpFuk_0 elephant +GZq8tIKR9b4_5 bus +GZsP_n7aFMo_0 person +GZxvpxqvHFs_1 airplane +GZ0bYvVD_us_1 bird +GZ1aL_iE5a8_1 person +GZ6PRvVVeZk_0 person +GaAL3IYDUgM_0 skateboard +GaD4QsNCcik_0 person +GaF_t9Af1hg_3 umbrella +GaJvFxg_lFY_0 person +GaJ7Bu5UrgQ_1 bus +GaJ7Bu5UrgQ_2 bus +GaVmURUD-i8_0 person +GaYAyNs2FDI_1 person +Gad1St-JBls_0 dog +GaeWhfSP3EA_2 knife +GagCDetg0dg_0 bicycle +Gai7qgVSFc8_1 cat +GangZBQawtQ_0 person +Gax9nZtMs7M_0 person +Gayl2EVJTkw_0 dog +Ga3YHyqOqYY_1 person +Ga3YHyqOqYY_0 person +Ga_Oju23T9s_0 person +GbBl5CcJgeE_14 elephant +GbBl5CcJgeE_6 elephant +GbBl5CcJgeE_8 elephant +GbBl5CcJgeE_9 elephant +GbBl5CcJgeE_10 elephant +GbC0DAAn-XU_3 bear +GbC0DAAn-XU_12 bear +GbC0DAAn-XU_14 bear +GbE-oXaNVBA_0 elephant +GbE-oXaNVBA_3 elephant +GbE-oXaNVBA_5 elephant +GbE-oXaNVBA_6 elephant +GbE-oXaNVBA_7 elephant +GbE-oXaNVBA_8 elephant +GbE-oXaNVBA_9 elephant +GbE-oXaNVBA_12 elephant +GbGEC5pQ9f8_1 cow +GbHLET097K8_0 boat +GbN_zMz1D6o_0 person +GbOK07Tq7mA_0 boat +GbVDftpuPMo_1 person +GbW-55xLUnQ_0 airplane +GbY3uHcC3ys_0 truck +Gbbhlv2Obsc_0 person +Gbbhlv2Obsc_1 person +Gbd1-rm9Oyw_0 truck +GbmEMxbMtCI_0 bicycle +Gbs4s3pX3H0_5 knife +Gbs4s3pX3H0_0 knife +Gbs4s3pX3H0_1 knife +Gbs4s3pX3H0_2 knife +Gbs4s3pX3H0_3 knife +GbulfCx1hwo_0 person +Gb_YkJHLgns_0 train +Gb_YkJHLgns_1 train +GcCQF52Ok14_5 person +GcCQF52Ok14_1 person +GcCQF52Ok14_3 person +GcCQF52Ok14_4 person +GcEgsdqMiBg_1 person +GcEsDxUkr00_5 elephant +GcEsDxUkr00_1 elephant +GcRRhnk4ynk_0 person +GcnVDv6bIAk_0 person +GctFFbsebBs_0 person +GcwS7IyeG5Y_0 motorcycle +Gc0lgXRlxGE_1 person +Gc0lgXRlxGE_0 person +Gc3iNFz3s-o_0 cow +Gc5OyOM0VxI_1 person +Gc5OyOM0VxI_0 person +GdI2CnryrFQ_2 car +GdNJ-VDNc3k_1 person +GdQuxx_RXvs_2 bear +GdbphRsxpKU_5 horse +GdbphRsxpKU_3 horse +GdfyxcmHHOQ_0 person +GdiGBeJ9m_k_0 person +GdiGBeJ9m_k_1 person +GdsJ0QHb83w_1 person +GdsJ0QHb83w_2 person +GduwjeptozQ_0 person +Gd5qUjEeqZ4_0 motorcycle +GeHV-tf-ZGA_0 bus +GeUECF6hDkg_0 airplane +Geb74PkjTYY_1 person +GehgPYVYwDs_0 person +Gek3IJfBaU0_0 train +GeuYAXldbbg_4 airplane +GeuYAXldbbg_1 airplane +GeuYAXldbbg_2 airplane +GeuYAXldbbg_3 airplane +GewTJtB97l8_2 knife +Ge2suMLyOTY_0 cow +Ge4SjOnEYWs_1 person +Ge4SjOnEYWs_0 person +Ge8RWLzmrE0_0 person +Ge8RWLzmrE0_2 horse +Ge9uJatNWuw_0 person +Ge9uJatNWuw_1 person +Ge-VfDpriPY_1 person +Ge-VfDpriPY_0 person +GfCjURNr9T4_0 person +GfLxzlZxHic_0 person +GfbcHsH3DKI_0 person +GfeXUZVyvL4_0 person +GfefENTSQOI_0 person +GfkX7I9bclY_0 cow +GfqA0SZPeXU_2 horse +GfqA0SZPeXU_3 horse +GfxwasnA0Ao_0 bird +GfxwasnA0Ao_3 bird +GfyBiJNU7bY_0 car +Gf50aWojLhk_1 airplane +GgV4eSmNyaA_1 elephant +GgV4eSmNyaA_0 elephant +GgcoCmlTlbc_0 person +GgfESlKFIkU_0 dog +GgkncqtrgPI_0 person +GgsFohIKlpw_0 dog +GgyOGY2q9xE_0 skateboard +Gg9uDi7KjJ0_0 person +GhBPvHC15BE_0 person +GhHPtGuUtRY_0 person +GhI4uqxOQpc_0 horse +GhLdswZDYMs_0 bicycle +GhLdswZDYMs_1 bicycle +GhMC34aeHnU_2 person +GhMC34aeHnU_0 person +GhMC34aeHnU_1 person +GhQRZOseJfY_0 truck +GhbtO__NASs_0 person +GhbtO__NASs_1 person +Ghbt5lVT3dk_0 truck +GhiVm-6oFyg_0 train +GhwtPgHjLvg_0 dog +GhxWr3HvvXA_1 person +GiRzA3Fe1-s_0 person +Gijruln92tk_0 truck +Gik59IGJFLo_0 bird +GioAI9XlGGg_0 bird +GioEMsI07Jw_0 person +e9ihaIQuVMU_0 knife +e9ihaIQuVMU_2 knife +e9iolRKSwBw_0 person +e9mOqKDBOVg_0 person +e9nH--aGWDM_0 person +e90GV6rl3NE_0 person +e9-w67QSEBs_0 person +e9-w67QSEBs_1 person +e9_LqDqVkGs_0 person +e9_LqDqVkGs_1 person +e9_LqDqVkGs_2 person +e-PcZyfAPZ4_0 person +e-R-FxrDQao_0 person +e-dVHSE1qXI_0 person +e-gU8I2kZyY_1 bicycle +e-n0pRU6uSk_0 bus +e-n0pRU6uSk_1 bus +e-qbVMLqnEw_0 person +e-siUblegSA_0 dog +e-siUblegSA_1 dog +e-v2yWUGKiU_1 boat +e-zbkYroVUk_0 person +e-43rdp3psc_0 person +e--Qr92yhBo_2 horse +e--vN-5QX-E_0 person +e-_nLPye6sc_0 person +e_APlM8VSiw_1 person +e_APlM8VSiw_0 person +e_FyX6iUBZk_1 person +e_GD2rN9Jcg_0 person +e_SYVD0TY14_0 airplane +e_UwPkRMD74_0 person +e_aHtRh2PpI_0 cat +e_b_4zlKmdo_0 giraffe +e_qdDAeerKQ_1 bird +e_-SOM0hufo_0 truck +fAHFZWyNZQ4_0 bird +fAHFZWyNZQ4_2 bird +fAJAQb5tzFA_0 dog +fAJ939SI_YI_0 person +fAKXvHREf8E_0 bird +fAMkbedQ0GI_1 person +fAQoNDLgds4_0 bear +fAUG8-TdflE_0 person +fAjj5137yKM_0 bicycle +fAm_6grpTOI_0 person +fAyBUKM7898_0 person +fAz2ecihxEU_0 person +fA5ArJS7ScI_0 car +fA6XfSl7pqY_0 person +fA_OWAI_8kc_0 person +fBH6rLEukMU_0 person +fBIh-CAYfy0_0 person +fBLrr2zYnRw_1 person +fBLvIU3Q7Rw_0 horse +fBPjBSdwz1o_0 elephant +fBPjBSdwz1o_1 elephant +fBP3dZYp3sM_0 person +fBT1cNog4Lw_0 person +fBkDTXhVYCs_0 giraffe +fBmp8URVoB4_0 car +fBsQegHOF8Y_0 person +fBtfkn4uDKE_0 cow +fBvAf66603Q_0 person +fBwrgO05rqo_0 truck +fByljFegqK4_0 person +fCADagfWgSU_1 elephant +fCK_OirKTO4_0 person +fCMJnkyFS5c_0 person +fCMJnkyFS5c_1 person +fCPVsi1S2jM_0 cat +fCTNp-hiUkQ_0 person +fCTNp-hiUkQ_1 person +fCT0UeuTcQk_0 person +fCUZclkgF-c_3 car +fCUZclkgF-c_4 car +fCUZclkgF-c_5 car +fCVoLETgca4_0 bicycle +fCW56GByDs0_1 person +fCW56GByDs0_0 person +fCX_8Q_OAos_1 dog +fCZXrHFimHM_0 person +fCbvdNQUcRE_0 cat +fCdlrWXZ7kY_0 person +fCiWi1Dk-yE_1 person +fCkgtao7rJk_0 motorcycle +fCmwPCLYVXE_0 skateboard +fCmwPCLYVXE_1 skateboard +fCm-8YmQfoY_1 giraffe +fCoXLMBzqTc_0 cat +fCohGx6PWyM_0 person +fCr-fmsVVWE_0 person +fCsSoErwvfw_2 skateboard +fCsSoErwvfw_0 skateboard +fCsSoErwvfw_1 skateboard +fCtyUxRaSdQ_0 skateboard +fCwicNYDKmo_0 person +fCzWVcZvGuk_1 motorcycle +fC6O_2ljm_c_1 person +fC6O_2ljm_c_2 person +fC6O_2ljm_c_0 person +fC8FUnipL3M_0 bird +fDBgRd9yK8Q_5 airplane +fDBgRd9yK8Q_1 airplane +fDBgRd9yK8Q_4 airplane +fDCK-s1gX18_0 skateboard +fDCadv28EEo_1 person +fDCadv28EEo_0 person +fDFpsal4hHo_0 person +fDIVkvMCQ9I_1 cow +fDJjIhw4XBI_2 person +fDJjIhw4XBI_1 person +fDLBxom0wgI_1 cat +fDVesIz_ON0_1 person +fDe30IPiQ0Y_1 horse +fDuiW9_sHcQ_1 person +fDyXAhF761Q_0 person +fD89z8ycv7U_0 person +fD89z8ycv7U_1 person +fD89z8ycv7U_2 person +fEDj20Gce80_0 boat +fEK6hdzjG5E_0 cow +fESV3o1vc1A_1 bird +fES_1kR2d8o_0 person +fEVLKYBuE7k_0 truck +fEXq69B6L0s_0 giraffe +fEZ5cqJWg0A_0 bicycle +fEdlpwoza6o_0 person +fEdlpwoza6o_1 person +fEdlpwoza6o_2 person +fEgqRE0XOMM_0 person +fEh5hyz4LCU_0 skateboard +fEiWI60P4XI_0 bicycle +fElOryAiN0s_0 person +fEmh4mfGsCA_0 person +fEupHSTMXLk_0 knife +fE0raHY_nY8_0 cat +fE_sSvVFvZU_0 dog +fFBkKrJlobs_0 cow +fFEDu-fiUUM_0 person +fFGmvl4E9QI_0 bird +fFImZECw1c0_0 skateboard +fFImZECw1c0_1 skateboard +fFOTZMvg0n0_0 horse +fFRp0dBucFA_0 bus +fFTJuANVr2I_0 person +fFWU4PNTKDo_0 person +fFWU4PNTKDo_1 person +fFaJ5epORzQ_0 person +fFd91uPKDVA_0 person +fFksYDaR-NI_1 elephant +fFmCHQgzMRc_1 person +fFmCHQgzMRc_2 person +fFmhW2ygNKw_0 person +fFncU3kR5qw_0 car +fFogpyIr-Ic_0 person +fFq0hnzgGSw_2 bicycle +fF0RlMrKBFo_0 bicycle +fF1S-952IOU_0 horse +fF3WOuwnvrA_3 elephant +fF3WOuwnvrA_5 elephant +fF3pBoS7xFg_1 person +fF3pBoS7xFg_0 person +fF34g3sNiHo_0 person +fF7snD5S5Q4_0 car +fF_BanWRtKo_1 skateboard +fF_BanWRtKo_0 skateboard +fGGJnSDPzUI_0 person +fGI6_U9U_zc_1 person +fGPsR0YiVaE_0 train +fGgJ0VACAo4_0 umbrella +fGlnCmVPzIs_0 person +fGrC6VCXVL4_0 person +fG1NOqIRoLA_0 person +fG6uSVeocMo_0 person +fG-4n3Gy1fk_0 person +fHO3g6Q_bNE_0 person +fHUjlWalvJQ_0 person +fHVJzD_AvV8_0 person +fHepRAiQQ04_0 cow +fHlfVMMfXNg_0 person +fHm5WgSYk2Y_0 bus +fHoBjwC8H50_0 dog +fHoBjwC8H50_3 dog +fHsaxiTw0dI_0 motorcycle +fHzSK8AEv5U_0 person +fHzzixV1xyg_1 cow +fH5U2jXbkEg_1 knife +fH8PS8Fjvbg_1 cow +fH8PS8Fjvbg_2 cow +fIABVBcluZ0_0 skateboard +fIABVBcluZ0_1 skateboard +fIFMCt78hmI_0 truck +fILyoB3Pgrg_1 dog +fIM7jmsq_FE_0 person +fIN8z4lkdyA_0 car +fIN8z4lkdyA_2 car +fIN8z4lkdyA_3 car +fIPXE6MOZp0_0 airplane +fIT1bTlW3UQ_0 person +fIVT3rTMptI_1 truck +fIXFrPFEL0w_0 giraffe +fIlXSJxnKD8_0 person +fInEVgREyyY_0 dog +fInYB8sD7tM_0 person +fIrb5Y93wjw_0 train +fIvUwaa2ziY_0 person +fIyrHecb8SQ_0 elephant +fI0VoDDN2lE_2 person +fI0VoDDN2lE_0 person +fI0VoDDN2lE_1 person +fI5fnVs_kWg_0 motorcycle +fI8DySScPWU_0 skateboard +fJGPTgv8EUs_0 person +fJJBGybbnH4_1 knife +fJJX9D4siG4_0 cat +fJTeqi3aqRc_0 car +fJYGkMT9c6U_0 truck +fJY5zGaYs8s_0 person +fJdWgbIMXZ0_5 train +fJdWgbIMXZ0_0 train +fJdWgbIMXZ0_2 train +fJpRqXhL3wE_0 skateboard +fJp4DAu46Yg_1 person +fJxbRDMY46o_0 person +fJyBgU7rZvE_0 person +fJ71o3Q-oVE_1 cat +fKDRpRcSnrw_0 cat +fKHs2FNZk6M_0 person +fKLJqhEdsTY_0 cow +fKLJqhEdsTY_1 cow +fKLS0DAexvw_1 boat +fKLS0DAexvw_2 boat +fKLS0DAexvw_3 boat +fKRZ4PPWgg8_1 person +fKcOtlmf6r0_3 boat +fKcOtlmf6r0_2 boat +fKgpRiyDlvc_0 person +fKhENDvpnmA_0 boat +fKhe37bCgeA_1 horse +fKp-Lvw2bUM_2 elephant +fKp-Lvw2bUM_3 elephant +fKp-Lvw2bUM_4 elephant +fKrxRvMxZqM_0 person +fKxBpYS29uM_0 dog +fKyPRwF5y6s_0 person +fKzFEc6hR-c_2 person +fK89Z2AwlCg_3 bus +GiuUBGsdiqI_0 person +GizeLrnWRmk_1 person +GizeLrnWRmk_0 person +Gi--TM8Xz3I_0 person +GjCs_s2EnpE_0 person +GjFr4qO_LX4_0 dog +GjJFQButa0w_0 bear +GjJk6U2crcw_0 skateboard +GjJp-yqt7xk_0 airplane +GjZDPTKpIdE_0 person +GjZP-buSAG8_0 person +Gjdyi0kf79Y_0 truck +GjfhgZMeHAA_0 person +Gjgu3OFbWKI_0 bear +GjkrI0adkJk_0 person +GjmNPrYyCwg_0 person +Gj87GZKvhdo_0 horse +GkCXvg93pAA_0 cow +GkGG1F5by14_0 person +GkddmkbGSAc_0 cat +Gkfp-yV9e94_0 person +GklwzbjOzYQ_0 person +GkmRFBuktnQ_0 person +Gkxkfi_wHeA_1 motorcycle +Gkxkfi_wHeA_0 motorcycle +Gk6IzYQADXg_1 skateboard +Gk6IzYQADXg_0 skateboard +Gk9v8ABOPNw_1 elephant +GlLzIn-6ouU_1 bicycle +GlLzIn-6ouU_2 bicycle +GlPdixjfu44_0 cat +GletqIQ8irw_0 motorcycle +GlsMcq1cM2c_1 bird +GlxEVs7z_7Y_0 person +Gl7S2JNezLg_0 boat +Gl7S2JNezLg_3 boat +Gl9cy66E4FQ_2 knife +Gl_UMssuTWU_0 person +GmI47tbiNQ0_0 person +GmKT2rhDILU_1 knife +GmQX3sIhhqo_0 cow +GmS0yrU3Hcw_0 person +GmUFocQWPTo_1 boat +Gmdxq1glmKY_1 dog +GmeGRg8XZ5M_0 person +GmvKmbIHKHM_1 person +GmvKmbIHKHM_0 person +Gmww9V50JtU_0 dog +Gm9BnQSZlxk_1 person +Gm9kb3zHsLA_0 cat +GnFoElm_rrw_0 dog +GnGd8Q_cSHU_0 person +GnGd8Q_cSHU_1 person +GnO2sxJNWjk_0 elephant +GnRp7QHoAr4_0 train +GnkSrEpnmRo_1 person +GnmgLr5p-r8_0 bus +Gno0JyFsjGk_5 knife +Gn0av9LV5FU_0 elephant +Gn3AqY6vUyU_0 elephant +Gn7B_MiLuhA_0 skateboard +GoEBr-GbeCk_0 elephant +GoEcYxqxcZ8_1 bus +GoEy1J3s8Xs_0 cow +GoRGaOgttBU_0 horse +GoUjZ5wJ2do_0 car +GoWyqQorqOY_0 cat +GoXlqK766lk_0 person +GolDzhH16vg_0 train +GorfZ7y-Jw8_0 skateboard +GosFitiV7as_0 person +GotzQ9ecvkM_0 person +GoubTEJzKUI_0 person +Go16BKYvDSs_0 horse +Go5M-oyC28A_0 elephant +Go8BM-B0ML4_0 skateboard +GpCjTjkSw3k_0 train +GpCjTjkSw3k_5 train +GpCjTjkSw3k_3 train +GpCjTjkSw3k_4 train +GpCjTjkSw3k_2 train +GpDilZGSveI_0 person +GpJmJforKzo_0 person +GpPbMduP_3Y_0 cow +GpProJiVxa4_0 bear +GpTPDl3MzZw_0 cat +GpVy_gD1slw_0 dog +GpY4Nw8LLy4_0 bird +GpkftB3rq5g_0 dog +Gpn_kF1lXuc_0 bicycle +Gpn_kF1lXuc_8 bicycle +Gpn_kF1lXuc_13 bicycle +Gpn_kF1lXuc_14 bicycle +GpzE4RQTM1Y_0 airplane +Gp3g6UYBBzw_0 person +Gp3g6UYBBzw_1 person +Gp70TnjZRfU_1 train +Gp70TnjZRfU_2 train +Gp70TnjZRfU_0 train +GqZeX-EEEL8_0 person +Gqc_LkQvKak_2 horse +GqjVd_dRiB8_0 person +GqjVd_dRiB8_1 person +GqjoBpwsgUc_0 person +GqjoBpwsgUc_1 person +Gqntj1GoicU_0 bus +GqzN0dyl5p4_4 truck +Gq-mMFeLCyo_0 person +GrG-ipHg_4w_0 person +GrK4qEJjeKE_0 airplane +GrNDwiO4kdI_0 airplane +GrQ0zJbkeXE_0 person +GrXOOtPiIGw_0 zebra +GrYsw9-Skqg_0 person +GrZvWtxffXE_0 person +GrpvM1_CRqI_0 train +GruxXrzWzjk_0 airplane +GruxXrzWzjk_2 airplane +GruxXrzWzjk_3 airplane +GruxXrzWzjk_5 airplane +GrzyUDtV-Ug_0 person +Gr6be_D6d9Q_2 skateboard +GsFDHyoPppk_0 person +GsGHB19iuE4_0 person +GsKJMkVSeV4_2 airplane +GsL7VYYWhu0_0 person +GsOgw9XtlWc_0 airplane +GsOgw9XtlWc_1 airplane +GsTlT_7Zb1Y_0 train +GsVvc55IHn0_0 skateboard +GshXL9V-lrM_1 person +Gsj4aXqBPHM_0 truck +Gsn06D15nmk_0 motorcycle +GsrSyK5ymQo_0 boat +GsrenPacLW0_1 person +Gs67R7prarI_1 motorcycle +Gs7J9Yo-uF0_0 cow +Gs7J9Yo-uF0_1 cow +Gs79ZsyWm74_0 person +GtAKWYvc9kY_0 elephant +GtCbEqqQgqY_0 person +GtCbEqqQgqY_1 person +GtD2m1EXxjc_1 bicycle +GtKaIcQJZcc_1 person +GtLYNeredOY_0 boat +GtVrmoeEcMM_0 knife +GtZPw5ftw88_0 person +GtZSRodviU8_0 person +Gta1hcIAAE0_0 elephant +GtiiYqVQ2Kw_0 person +Gtmp8y8APfQ_1 skateboard +Gtnqm4SnEXo_0 horse +Gtnqm4SnEXo_1 horse +Gtnqm4SnEXo_2 horse +Gtnqm4SnEXo_3 horse +Gtnqm4SnEXo_4 horse +Gtqcx01NTTw_0 knife +Gtsvc9lA7hs_0 airplane +Gt33VfmFDWw_0 person +Gt6q9b3QUvE_0 bicycle +Gt6q9b3QUvE_2 bicycle +Gt7thmVY6aQ_0 person +GuQvGMFuhu4_1 car +GuQvGMFuhu4_3 car +GuXelRN3wMo_4 bear +GuaD24NfCe0_0 person +GuawwNMbfBI_0 person +Gue43DvNTGc_1 train +Guf15LHosg8_0 person +GugU0nZdPJU_0 bus +GuhfGduN9v0_0 person +GulmsZq-VsU_6 boat +GulmsZq-VsU_0 boat +GulmsZq-VsU_3 boat +GulmsZq-VsU_4 boat +GulmsZq-VsU_5 boat +GusEs8RA4_o_0 motorcycle +GuwTG6RtcFI_0 person +Gu4MWCc2Wws_0 bicycle +Gu-vFv_w9Vo_0 person +GvFmkdxnKyI_0 horse +GvIj2sMkJwM_0 person +GvNhgCGtUOQ_0 truck +GvQvyfTNykM_0 truck +GvRM_UnjJoE_2 horse +GvdMRPX4KR4_0 train +GvdMRPX4KR4_1 train +GvdMRPX4KR4_5 train +GvoIcT-hFek_0 person +Gv9mTaerVLc_0 person +GwFrSa-YwfI_0 bear +GwFrSa-YwfI_1 bear +GwIn1NaaEwE_0 bus +GwbpMG2B14Y_0 truck +GwgaNLd1f7s_0 truck +GwlNXPuUvXM_0 person +GwnBP9a07RE_0 person +GwnBP9a07RE_3 person +GwnBP9a07RE_4 person +GwnBP9a07RE_1 person +GwnBP9a07RE_2 person +Gwx1ad4lW1Q_2 person +Gwyl7djxZkg_0 cow +Gwy4ODXAAU8_0 person +Gw5YyHT1Nt8_0 person +Gw9Vi_Io9DM_0 person +Gw_Tiv72jms_1 horse +GxANCkxq7Ng_0 motorcycle +fLCd0DDhfBk_0 person +fLEUT0rTkv0_0 bird +fLJniCJFPTg_3 elephant +fLPHwVvk6K4_0 person +fLPHwVvk6K4_1 person +fLWW1YWO26Y_0 bird +fLdMmSIfseM_2 person +fLdMmSIfseM_0 person +fLe279fKywo_0 dog +fLsDTJxlsW8_0 person +fLwrxElzLZs_0 person +fLyNbq9v6kg_0 person +fL1w15qwbqE_0 person +fMOnb4P7tww_1 person +fMOnb4P7tww_0 person +fMO1J7ojQqk_0 dog +fMTosfHKy2I_0 dog +fMi6lVyCOHw_0 boat +fMwCpOTv9RY_0 bus +fM-puV4uyzs_0 person +fNAZ9IDLZy0_0 person +fND_OguW0MM_1 elephant +fNIdPhAsjiM_0 cat +fNJSPU5r3sc_0 person +fNO_o1D0kvY_0 person +fNdRm3HWQmo_1 motorcycle +fNgr2EBEDCQ_0 car +fNgr2EBEDCQ_1 car +fNg3y0FHjgg_0 person +fNhDT1fwzKM_0 person +fNhDT1fwzKM_1 person +fNh54BNEJBQ_0 cat +fNw9dDcM4ms_0 bear +fN-FYknWOSk_1 person +fN-FYknWOSk_2 person +fN-43XPvLwg_0 motorcycle +fOLR2dvBtqo_0 cow +fOO1pHvrPWQ_0 person +fOatLQK_AyQ_3 bicycle +fOcPVX4sAxg_0 horse +fOjKgQf86dk_0 horse +fOkrLuGKDvk_0 person +fOkrLuGKDvk_1 person +fOkrLuGKDvk_2 person +fOsd2aWzfBo_0 cow +fOtnatCU7_Q_0 person +fOuV2101nEo_0 bear +fOv8ocd2xhA_2 knife +fO30fgQYdT4_0 bus +fO8Do_0RQXU_0 person +fO9GgD7GqE0_2 bus +fPBIIZV6fuU_0 person +fPMNtuJztSA_0 person +fPVn9Wxf_HQ_0 person +fPVn9Wxf_HQ_1 person +fPrhiYslRjA_0 person +fPzDDdztZNk_0 horse +fPzQyo7caqU_0 person +fPzqpL90owQ_6 bear +fP5AyxuGIS8_0 person +fP8x_x2_k5g_0 person +fP-DMm3u5n4_0 cat +fQEGEb4W3IE_0 person +fQNyLEXwnn0_0 person +fQOjoYB5hPQ_0 person +fQOjoYB5hPQ_1 person +fQOymYsdTtU_0 person +fQdA_-549Dk_0 dog +fQh5RtZzYzo_0 bicycle +fQlChBB42M0_0 person +fQoJWcmQmsU_1 person +fQo0G2i1QjY_0 person +fQt3g_9u1RQ_0 airplane +fQyE_yIAu_0_1 skateboard +fQ26oO2Y5NM_0 bicycle +fQ4H6UmTepU_5 giraffe +fREDiuJlBf8_0 person +fREDiuJlBf8_1 person +fRFF0xtrWhI_0 elephant +fROdeQpu88o_1 knife +fRS5rhYP7LM_0 person +fRXDSh8gr0c_1 person +fRZ7Wze7ATs_3 knife +fRcegyxH0Is_0 car +fRhNtVu6anA_0 dog +fRjCbO3MyU8_0 person +fRmnBvuwZlU_0 dog +fRmnBvuwZlU_1 dog +fRrLguORoeU_1 umbrella +fRrLguORoeU_2 umbrella +fRrd-Z2R-Gs_0 person +fRtzYh_gGgI_1 cow +fRwzMPH6Kvw_0 person +fR1zDIeBHFg_0 person +fR6FrFNXUxY_0 person +fR-JNy5hccc_0 umbrella +fSA7T5svJ-o_0 bus +fSBe_a8ZkZU_0 cat +fSey4VJgLM0_0 person +fSfKYTVt7V8_2 bird +fSfX4Z6SR2U_0 horse +fSj-h8lAhWw_0 cat +fSoqM6oq2AA_0 train +fSoqM6oq2AA_2 train +fS0098HnnhM_0 person +fS3KL3nj7FY_0 person +fS73PiHaNi8_0 person +fS8_byjM-1M_3 zebra +fS8_byjM-1M_0 zebra +fS_6fgFOiPU_3 train +fTFLfGUcgMs_0 elephant +fTFLfGUcgMs_3 elephant +fTFVwPKxUHE_2 elephant +fTP9YgSJZg8_2 knife +fTVb5uxWnsI_0 person +fTVb5uxWnsI_1 person +fTgirzB_QLU_0 person +fThV1JtaTJg_0 person +fTkIm1nb6qg_1 bird +fTkIm1nb6qg_2 bird +fTnnG_WcLYY_3 knife +fTnnG_WcLYY_4 knife +fTwiavhNzxs_0 person +fUB-cH8rjW4_1 person +fUB-cH8rjW4_0 person +fUF__EdDFVs_0 skateboard +fUISEtXSRYM_0 person +fUU4R6RP4ek_0 motorcycle +fUXpqgf4jUA_0 bus +fUd8LjmonBM_0 person +fUetaCH3tZk_0 person +fUg6JULdTnU_0 person +fUonzpmV18o_3 bird +fUqVKgWVVNY_1 person +fUqVKgWVVNY_2 person +fUwzXH9i0yQ_0 person +fUx60fl9UkU_0 person +fUzsVWD48bA_0 person +fU3o6Frqdww_0 truck +fU4DzirdCVE_1 airplane +fVAmI93Yb6E_0 cat +fVAsOuag4vY_1 giraffe +fVHZEHosow0_2 person +fVH3n0aghP4_1 person +fVH3n0aghP4_0 person +fVH7PpDqlPE_0 boat +fVIVas1R1tk_0 cow +fVOy449KQlY_0 person +fVX7qR-o-9I_0 cat +fVZfWzDBb-c_0 person +fVZ_9hWIGpA_2 truck +fVdrMKHN9WY_1 cow +fVq7Of0Tr-s_0 person +fVr3XVUzJaA_0 train +fVv5EqFYsAY_0 person +fV80H_L3AN8_1 motorcycle +fWLqbV7Z7Go_1 person +fWLqbV7Z7Go_0 person +fWb_-8hhubg_0 person +fWmJ9tUUCwg_0 person +fWpdcmgr5r4_0 horse +fWxgjNDC4OQ_0 car +fWxgjNDC4OQ_1 car +fWxsOgW3P6U_0 person +fW1Z_Mx1RaA_0 person +fW4fh_WBiMY_0 train +fW7yPljMFRc_0 person +fW7yPljMFRc_1 person +fW_HPaNBsDE_0 cat +fXCFktk2xdc_0 person +fXLB02IH0G4_0 person +fXLB02IH0G4_1 person +fXOdZ0uKuBc_1 dog +fXWqvRfBWto_0 person +fXX7K6CQfBw_0 airplane +fXYn01Cgmqs_0 dog +fXY7h0cc6tw_0 cow +fXbnEKMaIoM_1 boat +fXbnEKMaIoM_0 boat +fXka5y708fI_1 person +fXowuJDXhhU_0 person +fXyBm7_EDVc_0 skateboard +fXzIQASqygY_0 bird +fX-kSrf_K8w_0 horse +fYDgPdRtmjU_0 train +fYLtnvuW_VI_0 motorcycle +fYMA0fLN8sI_0 horse +fYN5ZIicl_k_0 car +fYmfHE2mONE_1 person +fYnsIFGQfT8_0 person +fYql4FiApLQ_0 horse +fYtm_pGBWkU_0 person +fYu5ChRgapY_0 motorcycle +fYw5KVCsg_4_0 person +fYyI8x0tNAA_1 bear +fY4-6vsjmD8_0 person +fY82KLfOpbk_0 person +fY82KLfOpbk_1 person +fZCdkf9VQzU_2 cow +fZEFEAYBlGE_0 cat +fZFYdgZbSBg_0 person +fZFYdgZbSBg_1 person +fZJOS8BlA-w_0 person +fZOtury_J_w_0 person +fZTIKbSjOhk_0 airplane +fZTJH_9Pqvg_0 person +fZTJH_9Pqvg_1 person +fZWP75nltcM_0 bird +fZXzEYFmZ_8_0 person +fZXzEYFmZ_8_1 person +fZiiYH3WfD8_0 skateboard +fZnbOFaSEQc_0 person +fZnbOFaSEQc_1 person +fZp_UgW_xZU_1 motorcycle +fZp_UgW_xZU_0 person +fZu7wEVEuX8_0 person +GxHmm60dKvc_0 skateboard +GxLI4BFLrps_0 person +GxPYf4SAQvE_0 person +GxPYf4SAQvE_1 person +GxWuAfBV300_0 person +Gxg0Pt_9bIE_0 person +GxwwTXW-DdQ_2 train +Gx1zPI3b2oc_0 person +Gx3xtKPwlz0_1 horse +Gx4ryd6AGl4_1 train +Gx4ryd6AGl4_2 train +Gx4ryd6AGl4_3 train +Gx4ryd6AGl4_0 train +GyGdlCtDdJc_0 person +GyIKdb5KDHk_1 train +GyPRnKI78iA_0 person +GyU8x9urAxE_0 motorcycle +GyVDsnuS5jU_0 person +GyXlgRxQ1jo_0 train +GyXlgRxQ1jo_1 train +GyZHiIEOBos_0 cat +Gya_TrOGXpo_0 person +GyhjyC5aJ8U_0 bus +Gyjb_P1W7TA_2 bus +Gyn_wSuRB3w_1 truck +Gyzaf_gaIYY_0 motorcycle +Gy9JueTT4XU_0 person +Gy_XuBCvbUc_1 dog +Gy_XuBCvbUc_2 dog +GzB9OTV44PA_0 person +GzHy2xjKB_8_0 person +GzLmftr6tl8_0 person +GzRkvFxVlx0_0 person +GzTDLPCsgSM_0 person +GzVj8bI0bSk_0 skateboard +GzVj8bI0bSk_1 skateboard +GzcgYGEqOlY_1 horse +GzesZ0laH2w_0 motorcycle +GzizYdL25ZY_0 person +GzjkTrnmEnU_0 airplane +GzjkTrnmEnU_1 airplane +GznFDBDT2c0_0 truck +GznFDBDT2c0_2 truck +Gzrgq_nWH_Q_0 horse +GzujCDTak_4_0 horse +GzujCDTak_4_2 horse +Gzy_PnFtEpM_0 person +Gz3Np50b9q4_0 truck +G0DQ6VdMp-U_7 car +G0DQ6VdMp-U_0 car +G0DQ6VdMp-U_1 car +G0DQ6VdMp-U_2 car +G0DQ6VdMp-U_4 car +G0DQ6VdMp-U_5 car +G0DQ6VdMp-U_6 car +G0FSe53KN-w_0 person +G0WsFATo9RQ_0 person +G0dXxEbeJnM_1 person +G0d44YoKXX4_0 person +G0kDhLojiI4_0 giraffe +G0leBoTgEx4_0 person +G0rwWyFSsYE_0 train +G0r2tR6EcF8_1 person +G0urH-9ytbc_0 horse +G01Xi8VMxgQ_0 person +G03JTuHY_RM_0 knife +G1AIHF-KITc_0 person +G1AtN7CvCXw_0 person +G1EnmuHlxig_0 person +G1P_XnEL4dc_1 person +G1P_XnEL4dc_0 person +G1TS-PvdREA_0 person +G1TS-PvdREA_1 person +G1ThERK4a8E_4 airplane +G1ThERK4a8E_0 airplane +G1UoN56m5DM_0 person +G1YNrrT9-z8_0 bird +G1YNrrT9-z8_1 bird +G1cY71JK5_E_0 motorcycle +G1c0-CTyZ3I_0 person +G1dKhZZARDk_0 airplane +G1z6RMtKkbM_0 bird +G1z6RMtKkbM_1 bird +G11cHAnx17E_0 horse +G13ARgckI9w_0 person +G17Kpx1bgXM_0 horse +G1_R_EJpLZU_0 cow +G2FXcVDezv4_0 truck +G2HOmWxj5gg_0 person +G2LNQIwbLHE_0 person +G2S4rwP6qJY_0 bicycle +G2V6wliL2AA_0 knife +G2g4Z-Syzi8_1 dog +G2lFYYEolz4_0 train +G2lFYYEolz4_2 train +G2x5gACWSwA_0 cow +G2z7yjdCUuI_0 airplane +G23Q_C35Uqs_0 bear +G24yJOgl9t0_1 person +G25iisvOYhA_0 cat +G2-v9IBlnTs_0 person +G3AuCS7s68w_0 bird +G3IID08lWos_0 person +G3P-Vvra2GU_0 horse +G3SowFCFa0g_0 person +G3VeVH6pbdE_1 person +G3a0EYtnqHA_0 person +G3cazaory7w_0 person +G3f8bIoGGZ0_0 dog +G3kNB0zhHQc_0 person +G3pT4MJrpDI_5 umbrella +G3pT4MJrpDI_6 umbrella +G3pT4MJrpDI_4 umbrella +G3vP7_U6yXU_1 cow +G37Dm4oy794_0 bicycle +G38EbyEOITE_0 horse +G38SrxcVYWs_1 person +G39ryVtNnhQ_3 elephant +G39ryVtNnhQ_8 elephant +G39ryVtNnhQ_9 elephant +G39ryVtNnhQ_11 elephant +G4PD_RAK48Y_0 person +G4VPBDOgq54_1 skateboard +G4VpcUuXgRs_0 person +G4VpcUuXgRs_1 person +G4ckSGXUGts_0 person +G4fbkcKiZVg_0 person +G4nRZ4PHvC4_0 dog +G4rJejZ9FIM_0 car +G4r0UJvtDXs_0 cow +G4xFWKKoN0M_0 motorcycle +G47wnMA6RVE_0 bus +G4_xR7lZIPo_3 bear +G5D1cAo2D6s_1 person +G5JwolS0D1M_5 elephant +G5QgL60_yfc_0 knife +G5SlrQeATlc_0 bus +G5SlrQeATlc_2 bus +G5hG8j0KxBI_0 person +G5ixkqq66VA_0 person +G5rBbx_kODY_0 person +G5ztukDN_Qg_0 zebra +G51fdi_hG_0_0 train +G52uuPWcC3M_0 umbrella +G553b8ZAd3Q_0 person +G58FuwBYL-0_0 skateboard +G5_UJ1wEKh4_0 person +G6OttGznP9E_0 person +G6OttGznP9E_1 person +G6QMME1QbK8_2 car +G6Qmm4T-cd0_0 bus +G6WiR4W4WWk_0 person +G6b9lySVCCY_0 person +G6eAvUHoDkc_0 person +G6fvYSH13nI_2 train +G6iVTjyPM04_1 horse +G6sFOs8MgGU_0 bird +G6sFOs8MgGU_3 bird +G6sFOs8MgGU_6 bird +G66e5ltBFoI_0 person +G7DhRPK7pwc_1 bicycle +G7F-ufxEXPY_0 knife +G7H7fQ_Q1Ec_0 person +G7H7fQ_Q1Ec_1 person +G7ID9RdMSkE_0 person +G7MvPG8Qv84_0 giraffe +G7TezoE9Cmo_0 person +G7WblvVQPF0_0 person +G7Z01jmMzlI_0 bird +G7krBQa_KLc_0 person +G7p90FBQk_0_0 truck +G7slUshqPvY_0 elephant +G74HXSqYO-A_0 motorcycle +G75uQAEuUkE_0 person +G766vinfuBw_5 bicycle +G766vinfuBw_9 bicycle +G77KKnCpwWY_3 skateboard +G8EC6svgwKU_0 person +G8NIqmq7YdE_2 bear +G8V2UsTc1Ik_0 cat +G8V33bTVNII_14 bicycle +G8V33bTVNII_1 bicycle +G8V33bTVNII_2 bicycle +G8V33bTVNII_6 bicycle +G8V33bTVNII_9 bicycle +G8XX8bkx6Ek_0 person +G8hStuDYwH0_2 airplane +G8kDZAPbUe8_0 person +G8kDZAPbUe8_1 person +G8k84FwnW2k_0 motorcycle +G8lDrK3u3r0_2 elephant +G8lfwRN3Iew_12 boat +G8lfwRN3Iew_0 boat +G8lfwRN3Iew_8 boat +G8lfwRN3Iew_9 boat +G8lfwRN3Iew_11 boat +G8sDCWad2Bg_0 cat +G8s2n3jAKW8_0 cow +G8tbj2R0iso_0 person +G80DOuBBH_Y_3 airplane +G8--2JpJa6g_0 person +G9DdsOO1mZo_0 horse +G9FQJdIxjsk_0 bird +G9YPEOrV5UU_0 person +G9YPEOrV5UU_1 person +G9YPEOrV5UU_2 person +G9ZKH_DS9DU_0 person +G9gsnqhd_Sw_0 cat +G9hPaEx7Ci0_1 knife +G9i66tUOspc_0 dog +G9juxPad3zY_0 person +G9nlPUwJQB0_0 person +G9nvXjuig6s_0 person +G9qCl1NZelo_0 cow +G9rxIfeUWVo_0 airplane +G9vDsElCKAY_0 dog +G9zd0G8dIt0_0 person +G93PAKTtVpM_0 horse +G97UC0qtVDw_0 person +G97YtHMd2hw_0 person +G99rEXOdlC8_0 horse +G9_TgGWQQi8_0 person +G-Sr-qmWZNo_0 cow +G-YYtvCU7qY_0 dog +G-d6o3nTBFA_0 zebra +G-nFiFb0Xos_1 knife +G-nbiqZuFdc_2 horse +G-qCe2DK3Tk_0 motorcycle +G-u_ThqhoJE_0 train +G-yCRlVSs6w_0 person +G-3kOsn1fPY_1 person +G_ADLUKVq8Y_0 boat +G_LtPKO6be4_0 horse +fZ1GVGZmTRA_0 person +faJuqm4umTQ_0 person +faSv8ijeKeE_0 person +faVBgge6xkE_0 person +faW2tWwuCMg_1 person +faW2tWwuCMg_0 person +fahs60oGhLU_0 train +fatTPMeG5Pc_1 bear +fa-rHhFEloA_1 truck +fa--elcQpd4_0 elephant +fbDYKST2P-I_0 motorcycle +fbFVM0UM5V0_0 person +fbM5MhIve5s_0 dog +fbM5MhIve5s_1 dog +fbiXTCkCkqY_0 skateboard +fbmZZXaRkak_5 horse +fbmZZXaRkak_6 horse +fbmnWcE_64U_0 skateboard +fbsyvHQPZZk_1 dog +fb3Iq9yQ1VY_0 person +fb3WxEfe8l8_0 motorcycle +fcCb2W4HMLk_0 person +fcD6n99azfw_0 person +fcGNPf6n7Ws_0 bear +fcWegrm8wCE_0 person +fcbcnvGoWLs_0 car +fchtQi7-OD4_0 horse +fclxNO1L-rY_0 cow +fcpGNeDgpDI_0 person +fc1qNL5u2wg_0 person +fdCTLMd6wEY_0 cat +fdQaoSZKA_s_0 person +fdRULl8YSnU_0 cow +fdYvCuft5zQ_4 elephant +fdYvCuft5zQ_5 elephant +fdYvCuft5zQ_1 elephant +fdYvCuft5zQ_2 elephant +fdZBeWyKON0_0 person +fdbvWvUoFW8_1 bird +fdbvWvUoFW8_2 bird +fdbvWvUoFW8_3 bird +fdkrZ9uL854_0 person +fdlDkbbDniw_1 elephant +fdmV18YEDKM_0 cat +fdnBDcIwPBA_0 person +fd3ea86gmJI_0 motorcycle +fd3ea86gmJI_1 motorcycle +fd8Ba2cZgxI_2 bear +feAexE1IYq8_0 person +fePU3BlF4Zc_0 person +fePU3BlF4Zc_1 person +feQX_1dqh9g_9 bicycle +feQX_1dqh9g_1 bicycle +feQX_1dqh9g_3 bicycle +feZfxIunWHo_0 person +feZoXB7I6wE_0 person +fedmeW-WImw_0 train +fegJtwcNo5c_0 bicycle +feh4XVzjQdI_0 cat +felt48AIbIs_1 person +fenYF-k-y4c_0 skateboard +feqLG8n4nDE_1 person +fe05wKXl2cI_0 person +fe05wKXl2cI_1 skateboard +fe5_49oxMwc_0 person +ffIQZZ_P3ck_0 cat +ffOeGlw8_C8_1 cow +ffZoY75S_-k_1 bird +ffZoY75S_-k_0 bird +ffbSaNikNF4_1 elephant +ffeYBfcgF3s_0 person +fftSD6UfvEA_1 person +ffttXyArNGc_1 knife +ffvXiSjPp6c_0 horse +ffwk_8ycQiA_0 person +ff1PHzfARZk_0 person +ff5MH6QQuJk_6 knife +ff5MH6QQuJk_2 knife +ff5SaJnQg5M_0 person +fgEpQHGYIjc_0 person +fgFy8l-b1iI_0 motorcycle +fgJJxPEHVZQ_0 person +fgPShysxuQM_0 cat +fgQE-9shdmQ_0 elephant +fgUjCKe_e_Y_0 person +fgWtwTKCtMQ_0 person +fgfizI4AnVs_0 person +fggT4HM2Uy4_0 person +fgsaC375d38_1 bird +fgvUj1mCqio_0 train +fg1ISXcyb10_1 dog +fg5mCaScLE4_10 umbrella +fg5mCaScLE4_0 umbrella +fg5mCaScLE4_3 umbrella +fg5mCaScLE4_4 umbrella +fg5mCaScLE4_6 umbrella +fg5mCaScLE4_7 umbrella +fhHLCLuQAdE_0 bird +fhHLCLuQAdE_3 bird +fhHLCLuQAdE_4 bird +fhHLCLuQAdE_1 bird +fhHLCLuQAdE_2 bird +fhQN_vhNmgo_0 cow +fhan95LbdqQ_1 knife +fhmsHcZfBC4_0 person +fhutr5rLQN0_0 person +fh5lB6U-7Wk_0 person +fiGa0nIEYbw_0 person +fiKecNhAgFU_0 motorcycle +fiS0pY80kkU_0 dog +fiWtkuDUFvM_0 elephant +fiZAhg2twZs_0 person +figjWJDEn1c_0 person +fijO0rB1rfY_0 airplane +finRU64JVRU_1 bus +fi2s2k_aamk_0 person +fi46OpYa89I_3 bicycle +fi46OpYa89I_10 bicycle +fi46OpYa89I_2 bicycle +fi6gdEVUAUc_0 cat +fi8YGUm_6x0_0 person +fi9GleMDHIc_0 person +fjF31Mh-tNQ_0 person +fjKXALm76kI_0 bus +fjXufPzimEQ_0 person +fjZ4J-BZX2U_0 person +fjaHYcaE7-w_0 person +fjaHYcaE7-w_1 person +fjnR81fSTeI_0 umbrella +fjnxqBnMZzs_0 person +fjtn0lRVX_4_0 truck +fjwgdNBSCFc_0 person +fjwgdNBSCFc_1 person +fj29rB34ea8_0 person +fkERi_ma2UE_0 person +fkERi_ma2UE_1 person +fkHiDyuUaWA_0 person +fkIfLHGu_CQ_0 person +fkQEEtG6Tbg_0 person +fkSf5a3q6oY_0 boat +fkSf5a3q6oY_3 boat +fkUDB0V3UXc_0 horse +fkUDB0V3UXc_1 horse +fkVSILZPyXg_0 bear +fkaKyYrWPpQ_0 person +fkfnbZ2MSXk_4 bicycle +fkfnbZ2MSXk_0 bicycle +fkfnbZ2MSXk_6 bicycle +fkx0e2gvPYA_0 truck +fkyM4LNUCck_0 person +fk0v7vZDpgU_0 person +fk10mtIF_Hs_0 horse +fk8yMMO1gRA_0 person +fk8yMMO1gRA_1 person +flADy--Uwx8_0 truck +flERyzHjhzQ_0 skateboard +flMijcdhRAU_0 person +flgTyT4DB7E_0 bear +flgaLcoSjb4_0 bear +fluEronPyZk_0 cow +fl6-NRwVy10_0 person +fl7Q9yxFoOs_2 person +fl95IAyDN-s_0 skateboard +fmERtylbqN4_0 person +fmGJj0qYc6g_1 person +fmGJj0qYc6g_2 person +fmLKgz4DQhQ_0 airplane +fmL66yeOiI8_0 person +fmRfUvIIvT8_0 person +fmYELQL9Cs0_0 bus +fmbEAdugI3Q_0 person +fmbb6SQ6qiI_0 person +fmbb6SQ6qiI_1 person +fmbu89zGN4Y_0 person +fmdem4Z9BHI_0 bird +fmfg5yyhjkA_1 person +fmiq_EhaURY_1 person +fmiq_EhaURY_0 person +fmtIa6nxUd4_0 train +fmuzrZHZYis_0 skateboard +fmwC1khd3BU_2 person +fm3zFVlJw4k_1 person +fm-ScTLdSL8_1 bus +fm_bcsJYhu4_0 dog +fnAGderLxPg_0 elephant +fnAGderLxPg_3 elephant +fnDP4B5jpSY_0 person +fnFMQ2VFlEc_0 person +fnOL3ZL61u0_0 person +fnOkwsmzdaI_0 horse +fnRq5X91IV0_0 person +fnZR6FD_eZ8_0 boat +fnZR6FD_eZ8_1 boat +fnbSgwO8v0c_1 boat +fnbsAmTQJOs_0 bicycle +fnbsAmTQJOs_1 bicycle +fniJ36z0_Pc_0 cow +fnj1YtAaztU_0 person +fnkHdQf9H3w_0 knife +fnmuFbydHek_0 person +fnpjkwiPkSY_0 skateboard +fntRlkYDiD0_1 person +fntZVzkwhz4_1 person +fnvst-Sk4MU_0 umbrella +fnvst-Sk4MU_1 umbrella +fnz6gTPuInQ_0 dog +fnz6gTPuInQ_1 dog +foAoOCF4rE4_0 car +foI1jEbg9uA_0 train +foJs0wXX1O8_0 truck +foaFgrzsPOY_0 person +fobJTCY7ifQ_0 bus +fodsoLtLzqI_1 cat +fojRgMUsu3c_0 person +G_RgJ0t0Cbo_0 person +G_aU-_2ZiSw_0 dog +G_lOQAV6xWs_0 cat +G_poofS7HD0_1 person +G_poofS7HD0_0 person +G__VTazZtp0_0 elephant +HARRnedV05U_0 car +HAVUursfTOI_1 zebra +HAtu6frOH1k_0 person +HA1TDbNot8E_0 person +HA-iE7bcfT0_0 car +HA-iE7bcfT0_1 car +HBI13CpuAmI_0 knife +HBLJbCs1mSg_0 truck +HBMah_r3E1g_0 person +HBOqQBe7rhE_0 person +HBO6G57uhXA_0 person +HBY4_6b_sRY_0 cat +HBiSuZWtb4E_0 boat +HBmaJJ0nTAo_0 person +HBwjWdXrpPA_0 dog +HBzYVphfmRQ_0 person +HCA4jkg9HTY_1 person +HCA4jkg9HTY_0 person +HCEjNJewxbw_0 person +HCJ1EYfF8qg_0 elephant +HCKZ7kihdaM_2 airplane +HCMBgpQ2z18_0 cow +HCSbzHGXxmA_0 cat +HCczjWUmlW0_1 truck +HCczjWUmlW0_0 truck +HCg0k7LnfkY_1 cow +HCg0k7LnfkY_0 cow +HCiRQdh20qg_0 dog +HCm-B3JjzhY_0 cow +HCpxRBja8lE_0 person +HCp6gYC9NFE_0 cow +HC72_Yrigik_0 person +HDN4DqO_KLg_0 dog +HDQEWwETuU4_0 person +HDRKiYaoEnA_0 person +HDSw0KM8cSs_0 person +HDkI156rPRA_0 person +HDmK6y86kYM_0 person +HDmK6y86kYM_1 person +HDnYEdh7xG8_0 person +HDqUvaFm_R0_0 skateboard +HDr5if6Mb_4_0 person +HDziFGwpXmg_1 car +HDziFGwpXmg_2 car +HDziFGwpXmg_3 car +HDziFGwpXmg_7 car +HD1tKnKT1Dc_0 motorcycle +HD7QKzuFNas_1 person +HD7QKzuFNas_0 person +HD_alEnCVhM_0 truck +HD_alEnCVhM_1 truck +HD_wYO2_O8k_0 person +HD_4ZJr68p8_1 horse +HEIjtOJze90_0 person +HEfIJ3wMKRI_1 person +HEmv-biWoEA_0 airplane +HErkHysJd-M_0 person +HEr_leMW1zE_0 bear +HEr_leMW1zE_3 bear +HEr_leMW1zE_1 bear +HEyY4zEX-no_0 person +HE-4YEdBwuw_0 dog +HE-4YEdBwuw_1 dog +HFDK_y7kibQ_0 knife +HFE9ujNILoA_0 cat +HFQFlm1jWiE_0 person +HFQFlm1jWiE_1 person +HFRCZSouOn4_0 bird +HFWQl2JJfic_2 person +HFa18pRSsXU_0 train +HFlanXHBGHg_0 person +HFuw8C2bQ6g_0 person +HF07qDRPgrw_0 horse +HF1xhyTtWLk_0 motorcycle +HF3Nn3KqXOk_0 person +HF3Nn3KqXOk_1 person +HF4PefI86r0_0 person +HGFcsJmjWHs_0 elephant +HGFcsJmjWHs_9 elephant +HGFcsJmjWHs_4 elephant +HGFcsJmjWHs_5 elephant +HGFcsJmjWHs_7 elephant +HGLC_YFRxPY_0 skateboard +HGLLnmQiCU0_0 person +HGLLnmQiCU0_2 person +HGLLnmQiCU0_1 person +HGLdrgf2e2c_0 person +HGVNoha70iA_0 truck +HGZDROOjAY4_1 person +HGZDROOjAY4_0 person +HGeCBN48g9o_0 person +HGm4OftDlT8_2 horse +HGnIxotAPOU_0 person +HGnegc2CRTM_0 person +HGvXva6SUvE_0 person +HGw4URr4QUs_0 person +HG1zQzSX2rU_0 person +HG8oY2Ac4-M_0 person +HG_JAnXBzJQ_0 skateboard +HHGq5gd6w1g_0 skateboard +HHPW65GVeoA_0 person +HHRUnCEVnAo_0 cat +HHc5mD1TxGQ_1 knife +HHe9m9BOi3A_0 person +HHgC0pkNiIA_0 person +HHgC0pkNiIA_1 person +HHi26rWtC38_0 person +HHx5E8VfnkY_0 person +HH0OILx6PKY_0 person +HH1JApHMx2I_0 dog +HH148v63a5o_0 person +HH9wMNMJ2sE_0 elephant +HIBd79qG-XQ_0 person +HICJGOFvwoc_2 bird +HIHX1rpDx_I_0 cat +HIIQ917jPqg_0 train +HIJGcmgyEcg_0 knife +HIJGcmgyEcg_1 knife +HIKyhRtWQ4c_2 horse +HIK-Z8wXFug_0 person +HISWMgqg80E_0 skateboard +HITf8extnnk_0 person +HIXuU8Z0N9o_1 motorcycle +HIgiF2bkOys_0 person +HIgiF2bkOys_1 person +HIiu2EVu5H8_0 person +HIqhXDkhHsc_0 person +HIqr0-BB8Xo_1 knife +HIrcAjP1fDs_2 bird +HIz27dqnl20_0 bus +HI3L38NCy0A_1 boat +HI3L38NCy0A_0 boat +HI_h7HfFDVw_0 boat +HJGPBeom3y4_1 umbrella +HJSiTzkFpHk_0 person +HJVpMFJT2LU_0 person +HJVpMFJT2LU_1 person +HJg7wtoy2vk_0 person +HJhZhn0zf1s_0 person +HJi1L5HxuLo_0 skateboard +HJi1L5HxuLo_1 skateboard +HJi1L5HxuLo_2 skateboard +HJq4kVvdeRg_1 skateboard +HJrd3kpvjh0_0 person +HJr5BOgO9XY_0 person +HJ6BZjeSHTY_0 boat +HKFJzdCsRfA_0 person +HKGK0FLN9vA_2 zebra +HKGK0FLN9vA_3 zebra +HKIwynmyQp4_0 person +HKWELXwIVvI_0 person +HKqHmDjxF6Y_1 person +HKsVn1IWaas_0 person +HK28Vb__IfY_0 person +HLAEqFEcR90_4 horse +HLAEqFEcR90_0 horse +HLAEqFEcR90_2 horse +HLAEqFEcR90_3 horse +HLBgSJD-3lg_0 bicycle +HLL_j-CQKqQ_0 umbrella +HLaiRkL4gFA_0 motorcycle +HLhbGKVR4mE_3 dog +HLy3UUDhaJY_4 giraffe +HL06bx_HNg0_0 cat +HL6dNcrAEoM_0 person +HL8fh6O6iUA_1 train +HL9F68y-0kY_0 horse +HL9F68y-0kY_1 person +HL9o2Vs9d8s_1 person +HMF0KrAf0iI_0 person +HMIGIwIcNq8_0 person +HMJerOjZn4I_0 person +HMQQrRvzwiM_0 boat +HMUBbUP6Ko8_2 boat +HMV7H81wz84_0 train +HMb-pPTMZ5I_0 umbrella +HMxMledcSVE_0 person +HMyUpcpZGdM_1 bird +HM4hJE0Db2Q_0 person +HM4zY3uzwOQ_0 person +HM7sD8YClkI_0 person +HM_3ck6yooo_0 person +HNGh3Rvn6Sw_2 knife +HNGh3Rvn6Sw_3 knife +HNRwM8zXMTM_0 person +HNXQ_dkhX-Y_0 truck +HNdRITK9TGE_0 person +HNeVOXPyunw_2 person +fo9SmkQa35Y_0 motorcycle +fo9SmkQa35Y_1 motorcycle +fpM1eiK3iok_0 truck +fpNLFTgOciY_1 umbrella +fpRq9BsaPzs_1 horse +fpRq9BsaPzs_2 horse +fpVZYKlsFsU_0 boat +fpdUwZ8Gnd8_1 cow +fpeYfCUzvDY_0 cat +fpkxYBJDTtI_0 person +fpkxYBJDTtI_1 person +fpmtNez1u0o_0 bus +fpnTZF4bvk8_0 person +fpomSxrdTyE_0 person +fpo2kf1idyo_0 person +fpp_41AxRNI_5 giraffe +fpp_41AxRNI_1 giraffe +fpp_41AxRNI_4 giraffe +fqQL3QPq-lo_0 train +fqXvzEGxSak_0 bus +fqcie5yyOxA_0 cat +fqfHWT5hjkY_0 cat +fqkVB4qZbgw_0 person +fqlWb2OJg3Y_0 bus +fqnioIm10xY_1 train +fqpMhE5qOKk_1 person +fqxGN6r9oIY_0 zebra +fq5Zh2Lo9GQ_0 elephant +fq959dAMasM_0 truck +frFSlwby-0k_0 train +frFrggXiJZY_1 person +frItg4I9oEQ_0 person +frItg4I9oEQ_1 person +frJtciauQQw_0 person +frRHj0FPzVQ_1 person +frW5BpQ3-Fw_0 person +frXxZevI11c_0 person +frXxZevI11c_1 person +frY6tIPR-Co_0 bicycle +freW9Vk3GhU_1 person +frfLZ70XIXI_1 dog +frgCmAtYao4_1 boat +frh4LMyWaQw_0 person +frn-rfqmGVs_0 person +frx5Uv7-1zw_0 person +fr3S3gEtDS0_1 person +fr616yExbeg_0 knife +fsD7pYdfrpg_0 person +fsE0DlVODpY_1 person +fsFtKjirvM4_1 person +fsFtKjirvM4_0 person +fsOoFz6I_js_1 person +fsOoFz6I_js_0 person +fsVlTdh13Lk_0 person +fsXVGaRpUNg_0 person +fsd-DhcH5gE_0 person +fsd-DhcH5gE_1 person +fsh-wcyuPM0_0 person +fs3oXXx75XA_0 person +fs6L5bmf4pQ_1 person +fs6Rgfl4CtI_0 boat +fs6p-qaLswQ_0 cow +fs7RdtNY3Ck_0 elephant +fs9uDpde9ig_1 elephant +ftG2YflDq_E_0 knife +ftH3_awR5ZA_0 person +ftIp5PyaGNc_1 knife +ftNSK_rSs98_1 airplane +ftSUBEOhdck_0 cat +ftX9ErOmiAE_0 car +ftX9ErOmiAE_1 car +ftcnCvd4yeU_0 person +ftlmGO0CnHk_0 truck +fuHAM8D3ros_3 bicycle +fuO2QMXiDMU_0 motorcycle +fuPtCtdvowQ_0 person +fuSxdcdxe70_1 person +fuSxdcdxe70_0 person +fuh4-mC5fvg_0 car +fuklviv_MRE_0 truck +funKReksXEQ_4 horse +fur41mRCURs_0 cow +futBuKCP9zw_0 umbrella +fu5d7x7pORY_0 horse +fu_f4n_bYPU_0 person +fvAislzoQVU_0 person +fvDUF-aukF4_0 person +fvH1bolPY2U_0 person +fvKg6ReEigA_14 bicycle +fvKg6ReEigA_2 bicycle +fvKg6ReEigA_3 bicycle +fvKg6ReEigA_4 bicycle +fvKg6ReEigA_5 bicycle +fvKg6ReEigA_8 bicycle +fvKg6ReEigA_11 bicycle +fvKg6ReEigA_15 bicycle +fvKg6ReEigA_16 bicycle +fvKg6ReEigA_17 bicycle +fvKg6ReEigA_19 bicycle +fvLauezWx5g_1 skateboard +fvLkNgA4N0k_1 person +fvZYmQ6SJrQ_0 person +fvcIpyJFuQA_0 person +fvdoipKMj4g_0 person +fvfb_kQCs-I_0 horse +fvhVuqonUHg_0 person +fvhVuqonUHg_1 person +fvlGWjjirUQ_0 person +fvqWMyJJqog_0 person +fvqWMyJJqog_1 person +fvtTggVCkFk_0 person +fvzbC9c98ik_0 dog +fv42-nzlEsY_0 train +fv8F7gjL7Js_0 airplane +fwCUjUa0cHQ_0 person +fwG8C9CEISw_0 person +fwLL8mlHf0I_0 bicycle +fwL9zu2j3rk_0 person +fwQMFtFdERs_0 horse +fwQMFtFdERs_1 horse +fwTB5tDP4cU_0 person +fwT-VIjQCa8_0 person +fwop4msktdA_0 cow +fwv2gGVEi6g_0 person +fwwOICMutXc_0 dog +fxFzCD192K4_1 bird +fxHZn2FXRGk_0 horse +fxHZn2FXRGk_1 horse +fxQYhMoNR9I_0 person +fxQY5tnybxQ_0 skateboard +fxWwYiT8yXk_0 person +fxWyDyUmxuY_0 horse +fxbNI1vTtq0_0 train +fxbjh88g3Vw_0 person +fxcDLsblNhs_1 bird +fxdVSYuYJOE_0 person +fxhuSOpUuGs_0 person +fxr4HpTRNS0_0 dog +fxxjK3mjCF0_1 person +fxyg5GQk8H8_0 airplane +fxyg5GQk8H8_2 airplane +fxyg5GQk8H8_3 airplane +fxyg5GQk8H8_4 airplane +fx07mGL1WQY_1 train +fx2_nahpAfE_0 person +fx4HT1nuEg4_1 person +fx4HT1nuEg4_0 person +fx9TwmuIYCY_0 skateboard +fx9fckiExps_0 person +fx_zN3FWeJ0_1 bus +fx_zN3FWeJ0_3 bus +fx_zN3FWeJ0_0 bus +fyE4_usnxHc_0 person +fyE4_usnxHc_2 person +fyOZZ_u9Jm0_0 person +fyOxr6iISdI_0 elephant +fyRO8_b4wJU_0 person +fyTzI2wuC0M_0 person +fybHaZZmAzE_1 train +fydZoAN9JpI_0 person +fydZoAN9JpI_1 person +fydZoAN9JpI_3 person +fyhSoeveW3I_0 train +fyyLjISjzvM_0 person +fyztN8okJkU_0 person +fyztN8okJkU_1 person +fy5GdRFHsLs_0 cat +fzFR54WdDEU_0 person +fzV_Z79golE_1 truck +fzaNjkWQtW0_1 skateboard +fze3woUbt0w_0 dog +fzh-lO5lQhQ_1 bird +fzoZsW3AMTU_0 bird +fzp3cT3c5Wg_0 person +fzp3cT3c5Wg_1 person +fzp3cT3c5Wg_2 person +fzqX7N7ICQw_1 person +fzqX7N7ICQw_0 person +fzrGdIi_J9k_0 person +fzr9mWLJM6E_1 person +fzr9mWLJM6E_0 person +fzvrWQX908c_0 person +fz1PTzziIcg_0 person +fz1kPSLo_p8_1 train +fz8emqnbleQ_1 boat +f0BJ56Dn3D0_0 cat +f0E5mPnVSSU_1 person +f0JOvKbLwTQ_0 person +f0LbneUbWUk_0 cow +f0TYLMAZLpA_0 person +f0XZTHcpmZY_4 elephant +f0XZTHcpmZY_2 elephant +f0XpDJO5Tw0_0 person +f0XpDJO5Tw0_1 person +f0Z8cmobjWs_0 truck +f0Z8cmobjWs_4 truck +f0Z8cmobjWs_7 truck +f0Z8cmobjWs_8 truck +f0mYYISWwxo_1 person +f0mYYISWwxo_0 person +f0o0SmB2JAE_1 cow +f0o0SmB2JAE_0 cow +f03_N__tWuI_2 elephant +f1ASjw4-yL8_0 person +f1Da4qa1SIw_1 person +f1EKnOQEf5g_0 boat +f1GkfW2mOlE_0 person +f1G2DlbJqyI_0 person +f1HKyLr8nL0_0 person +f1JCS5F-LuU_0 person +f1KEvGLqqwI_1 umbrella +f1O6FYMq5zk_0 person +f1XB0uA4Dvo_0 bus +f1Z1HedJzos_0 skateboard +f1fEuZwBkDQ_0 person +f1nxCdtYwdQ_0 horse +f1sTzp9ahWM_1 person +f1sTzp9ahWM_0 person +f1uaPSveXCI_0 person +f2ADBeQ0Vys_0 person +f2ADBeQ0Vys_1 person +f2EbBSZ8osI_0 zebra +f2EbBSZ8osI_1 zebra +f2HKs4L6fwE_0 person +f2HKs4L6fwE_2 person +f2HKs4L6fwE_1 person +f2MDAAk-Euo_1 person +f2ULSb7lIAo_0 cow +f2ULSb7lIAo_1 cow +f2ULSb7lIAo_3 cow +f2hfKAL0ZoA_0 umbrella +f2hfKAL0ZoA_4 umbrella +f2hhMTSObNY_0 skateboard +f2p2YcmHn8c_1 bicycle +f2s4nNZ_qew_0 boat +f2ypHkP1WUg_0 person +f3EOdxK13SU_0 giraffe +f3HU85Jx7m0_0 cow +f3JkzQkcdVM_0 horse +f3Kxw7yBcW0_2 person +f3Kxw7yBcW0_1 person +f3Np8rGlxOE_1 person +f3VJKfFdBW0_1 truck +f3aufQBTMME_0 boat +f3bk60UZpqE_0 truck +f3bk60UZpqE_5 truck +f3bk60UZpqE_9 truck +f3kQ_6EG8cM_0 person +f3spBT1AGyw_0 person +f31ePv3WlNc_0 person +f33OpHIFMWA_1 elephant +f33OpHIFMWA_3 elephant +f33OpHIFMWA_0 elephant +f33OpHIFMWA_2 elephant +f35syqOsqSo_0 boat +f38P7AlhP5g_0 person +f39rc-7_QQc_0 person +HNr7Ed0_pQY_1 bus +HNtUUtLCSDY_0 giraffe +HNtojLNWnKQ_0 person +HN6XGq0aRx4_0 person +HN84N_vu_hw_1 person +HOAbQ4r1tzM_1 knife +HOA47mRJ9B8_0 person +HOOwNsMTi9g_0 person +HOSMm-4fUVM_0 dog +HOZcbA0OPF0_0 person +HOkS1ljUX4s_0 bear +HOmzECHFah4_0 dog +HOxzSXuj0O0_0 elephant +HOxzSXuj0O0_3 elephant +HO6yeFgs7Hs_1 bicycle +HO7Uf5Enr1U_1 person +HPAa3KI1Z30_1 dog +HPDws9wJu40_0 train +HPIdRNu7STU_0 dog +HPIxVE3OLG4_0 person +HPPTr0Mpe0A_0 bicycle +HPRp9F-4ts4_0 dog +HPSJZXcOiEc_0 person +HPjcp8hS6vs_0 person +HPjcp8hS6vs_1 person +HP0RUfuvfx4_0 person +HP4O8FbEpEg_0 bus +HP6ROW7ahtU_0 person +HP6YRIGqiI4_0 horse +HP62suxiDNw_0 bicycle +HP62suxiDNw_2 bicycle +HP62suxiDNw_3 bicycle +HP62suxiDNw_1 bicycle +HP9u4FmRvbw_1 bear +HQBhagraDwo_0 cat +HQIxUlu7xSY_0 person +HQKVBNWD_ls_0 person +HQM9aDN7Tf0_0 person +HQZVUknJ0lw_1 person +HQZVUknJ0lw_0 person +HQePQ1mfzKw_0 person +HQePQ1mfzKw_1 person +HQhnj0h9OyA_0 person +HQhnj0h9OyA_1 person +HQjXFK_0sFo_0 person +HQxihmm6sSs_0 person +HQz_At1F0Yk_2 bicycle +HQ4ZWia0f1E_2 cow +HQ9gmrJ6Bm4_3 airplane +HQ9gmrJ6Bm4_4 airplane +HQ9gmrJ6Bm4_5 airplane +HQ9gmrJ6Bm4_1 airplane +HRCOvhALHv0_0 train +HRUX75Ve2aQ_0 person +HRVMd5SmF8Y_0 umbrella +HRl1VhUfhok_0 person +HR1wffFOaEw_0 elephant +HR4ExP8Ompc_0 horse +HSKpu2UmvBo_0 person +HSKpu2UmvBo_1 person +HSN6tO3rh-c_0 person +HSVWpwFagLg_1 person +HSdyrMzM64w_0 cow +HS3WVWEFHm8_1 person +HS3WVWEFHm8_0 person +HTAnAeW5Bhs_0 bird +HTS20hgMcFQ_0 bicycle +HTTz78R4i0c_0 person +HTehrgCQAPo_0 person +HTgldgqci04_0 person +HUFGafskCjw_0 person +HULASsoz03U_0 person +HULASsoz03U_1 person +HUPxNiCgjn0_0 knife +HUfwe7j7IBE_0 person +HUgX2V1AkVw_0 person +HUiMyxUEC_A_0 person +HUv2tT_n5Bo_0 person +HUy4cHFX-04_0 person +HUz7znJTRNg_1 umbrella +HU_HuNQ4TDw_0 cow +HU_HuNQ4TDw_1 cow +HU_HuNQ4TDw_2 cow +HVEmUm86PBo_0 motorcycle +HVI1w93kCfo_0 person +HVOWKezX_bo_0 horse +HVOWKezX_bo_2 horse +HVYf36PFglw_0 dog +HVY9hWgMujc_1 truck +HVeqzrLyVtk_0 person +HVkFV2q27S0_1 person +HVkQkPaQbrw_0 person +HWAW-J3ZpIs_0 cow +HWA45moBwMo_0 horse +HWEI24n2tHY_0 person +HWItJuo6DSM_0 bus +HWXgDvYdlHE_1 person +HWZSmtWVH54_0 person +HWZenKFJqkY_0 person +HWZenKFJqkY_1 person +HWZenKFJqkY_2 person +HWfpkRSnZp8_0 train +HWfpkRSnZp8_2 train +HWjaeLf99dU_0 bear +HWr9Kqi0B2A_0 person +HWsTMfZok5E_0 person +HWtKIjJacjk_0 person +HWtyII4CMWg_0 car +HWtyII4CMWg_3 car +HW7FTNqTKhs_0 train +HW7yQK_j65g_0 horse +HXARJhNURSs_0 person +HXH_F5SX6FU_0 truck +HXH_F5SX6FU_3 truck +HXH_F5SX6FU_1 truck +HXKnqbEGfVw_0 bird +HXKnqbEGfVw_6 bird +HXKnqbEGfVw_1 bird +HXKnqbEGfVw_2 bird +HXKnqbEGfVw_3 bird +HXLA3nbxgh4_0 person +HXWoqdza4oA_0 dog +HXaAJtjX1mE_0 bicycle +HXaAJtjX1mE_2 bicycle +HXaAJtjX1mE_1 bicycle +HXa-0NlFTP4_0 person +HXcSrTLsF9c_0 train +HXhYYfE4uN8_0 person +HXvgiezvrYI_0 truck +HXx4tRTfGRM_1 dog +HX0kjr3XYHI_1 bear +HX7P1ipPByA_0 dog +HX-gTvdUaOE_2 motorcycle +HYLAdzbqvC0_0 person +HYWEWmMMrsU_0 cat +HYW3dAv02gE_0 cow +HYW6VucwAEg_0 person +HYXFGMzivds_10 truck +HYbuNzqXmyY_0 person +HYiN6skKjfY_0 knife +HYoonHvZXCc_0 motorcycle +HY1aAYxxlQo_0 person +HZC5bba_V4Y_0 knife +HZJ-JQkt590_1 bicycle +HZKExvpKLQ8_1 person +HZLdGfto2mI_0 car +HZSPPN3TMx8_0 bird +HZZadt4SIl0_0 dog +HZceU_BV2GM_0 person +HZceU_BV2GM_1 person +HZceU_BV2GM_2 person +HZd4rCCsNMs_0 skateboard +HZd4rCCsNMs_1 skateboard +HZd4rCCsNMs_2 skateboard +HZkmrVeoUV4_0 person +HZscUISrdww_0 person +HZ-tGW__JOI_0 cat +HaE1N8Q1b7s_1 train +HaMpIMApSi8_0 person +HaO3z-4gcBs_2 train +HaRliuOtm7s_1 person +HaiLotzzEXk_1 elephant +HaiLotzzEXk_2 elephant +HaiLotzzEXk_0 elephant +HarW34izH-M_1 person +HauA239AM7I_0 dog +HavxbX8tng0_0 person +HayoEz1x5Ks_0 person +HayoEz1x5Ks_1 person +Hay4Nx9S5-k_4 bicycle +Hay4Nx9S5-k_1 bicycle +Ha8XGRvxQxs_0 person +Ha_OuYxLXIs_0 person +Ha_w-xJsHAY_0 zebra +HbBCtCXKIEE_0 person +HbH7DpR0WUw_0 person +HbJufGCjdSE_1 person +HbKh31cncOI_0 bird +HbLoxqqdYsQ_0 cow +HbQu1mfGg4c_2 elephant +HbQu1mfGg4c_3 elephant +HbQu1mfGg4c_0 elephant +HbQu1mfGg4c_1 elephant +HbcyjRGbMBY_0 dog +HbcyjRGbMBY_1 dog +HbhmBauZqxE_0 horse +Hbq35QImz2w_0 person +Hbq35QImz2w_1 person +HbuCy2fsJk8_2 knife +HbyKQdGpxhA_0 boat +Hb3INTcuOVk_0 person +Hb5zCzD4J_E_1 train +Hb5zCzD4J_E_2 train +Hb5zCzD4J_E_3 train +Hb5zCzD4J_E_6 train +Hb5zCzD4J_E_7 train +Hb5zCzD4J_E_8 train +Hb5zCzD4J_E_11 train +HcBQXS22BDs_0 person +HcJTaK6Q9P8_0 person +HcXN4Pwnaeg_0 horse +Hcfxwdbwk8c_0 person +Hchet3FQwII_0 person +HcxL3_INS_0_0 person +Hc5ZM6UWTbY_0 person +f4OI46BYh08_0 skateboard +f4Oj9uMeFdI_0 elephant +f4PgAt4YpfE_0 cat +f4P-R7h_gTU_0 person +f4QyVWC6yrw_0 person +f4XkIcezAd8_0 person +f4XkIcezAd8_1 person +f4Y2tjwOV2k_0 cow +f4Y2tjwOV2k_1 cow +f4bys9o_Z2M_2 bird +f4s0cImpNBM_1 cow +f4xLPprxm30_4 knife +f49BXPlU-iI_0 knife +f4_Mfc9Ccg8_0 truck +f5BIXG_nLok_0 bus +f5HsrI3Codk_0 bird +f5J7yrE24eY_0 person +f5LuupUslCU_0 person +f5Q2iD7VUx8_0 skateboard +f5W37dv91tU_0 person +f5apNjAecEc_0 person +f5bVoAXze0Q_0 motorcycle +f5d1IXK1Tz0_0 bird +f5rzpIRd4wA_0 train +f5wHsLucnf8_0 person +f5zEWaDr1jg_0 cat +f50eMXA_-bM_1 person +f50eMXA_-bM_0 person +f53Jmsa7Jkc_0 person +f6AcbdJ77A4_1 train +f6E2ODGGF28_1 person +f6Px5vjTeRI_1 elephant +f6Px5vjTeRI_0 elephant +f6Px5vjTeRI_3 elephant +f6Px5vjTeRI_5 elephant +f6UBVcEIt3I_1 person +f6cXiuO-MvQ_1 truck +f6dVANLzPTY_0 person +f6dVANLzPTY_1 person +f6o6ukW_Qog_2 bear +f65c6sEDtkE_0 person +f7A6AOC8fOg_0 person +f7A6AOC8fOg_1 person +f7ExsvPto-E_1 motorcycle +f7Fs7-jGglk_1 bear +f7GJgMh9xt4_0 person +f7WvltLziTI_0 boat +f7cI-B4pJso_0 cow +f7kLnCuNTQo_0 cow +f7lmZQGcfBA_3 elephant +f7lmZQGcfBA_4 elephant +f7lmZQGcfBA_0 elephant +f7lmZQGcfBA_1 elephant +f7oBEoL94vw_0 person +f7pnt1rB9kI_0 person +f7x074oihas_0 person +f73BEqi2_DM_0 person +f7-S_iQAyKU_0 car +f7-htlH5qd4_0 bird +f7-htlH5qd4_2 bird +f8A1o9Nbs64_0 skateboard +f8BXIJnggCI_1 boat +f8BXIJnggCI_3 boat +f8BXIJnggCI_4 boat +f8Dp8Yvyr_0_0 person +f8PVrlhAIV4_0 person +f8T4DHNu6MY_1 truck +f8ZxXHSqC_8_0 boat +f8cW6kw6240_0 person +f8mzzGhPBaw_1 car +f8q3fKwf5PY_0 knife +f8yFyIwDCQ4_4 giraffe +f8zLCa1oGOE_0 horse +f8z83D9vGPo_2 knife +f80hjE6vabs_0 person +f80hjE6vabs_1 person +f84ypk41ULc_0 elephant +f9H0LrBLc9Y_0 person +f9H0LrBLc9Y_1 person +f9H0LrBLc9Y_3 person +f9H1bUagACA_0 horse +f9H6UaPUITk_0 cat +f9LOlCLfsJs_0 person +f9N4Jxt-kUs_1 knife +f9N4Jxt-kUs_2 knife +f9TCFTluRIc_1 bus +f9e12AC1jXM_0 bear +f9oWC3kSP1M_0 motorcycle +f9ovukmKaq4_1 person +f9sPt8HIN0w_1 skateboard +f9sj-0ZFV6E_0 person +f9sj-0ZFV6E_1 person +f9v2ONFCiwQ_0 person +f91XzUXz11U_0 person +f96d9EwxAB4_0 person +f9-IyW9tVLY_0 person +f-FxqFk0TdM_0 person +f-JXaNm7TBw_0 person +f-J7SQBHRN4_0 truck +f-Yei4idfG8_0 airplane +f-dhfS-geuI_1 elephant +f-dhfS-geuI_2 elephant +f-h9L-PN1ZM_1 bird +f-iLJUDdrD8_0 person +f-niuVrgiIc_1 person +f-rp_CghH-E_0 skateboard +f-s-4lM4qPA_0 truck +f-w51BH60RQ_0 person +f-1WVe76te0_0 cow +f-4EyKUawVo_0 bear +f-7ZEGsCz9U_0 person +f_GKi-DGmzM_0 person +f_Gf2hpt7y4_0 giraffe +f_GudF8uST0_0 person +f_NsA6enCZE_0 person +f_OOyDOAAOU_7 elephant +f_QhMhkyUSY_3 truck +f_QhMhkyUSY_1 truck +f_QhMhkyUSY_4 truck +f_Us8TvJMUQ_0 person +f_VwDCt9HTc_0 dog +f_WQIaZ5PjY_0 boat +f_bXOtZjzfo_0 person +f_b0IaRqtbs_0 person +f_jLGz53IpQ_0 person +f_jLGz53IpQ_1 person +f_mo54sXCc8_1 person +f_mo54sXCc8_0 person +f_rC1JIAMBU_0 person +f_wk-NOqceY_0 horse +f_yMF9tkk70_1 car +f_yvJuTzFHc_0 motorcycle +f_yvJuTzFHc_2 motorcycle +f_2I0S-EYu8_0 dog +f_3x9qJXCjA_0 person +f_49EFLQ02I_0 person +f_8S2hHC2rc_0 bicycle +f__fXHkVh5E_1 cow +gAKFUl9e_kg_0 person +gAQ92hISW6g_0 person +gARNWQDyaYM_0 boat +gAYbqApcfGs_0 person +gAdIZN7_0SM_1 airplane +gAeHmfC6t5s_0 cat +gAetQXcftXM_2 dog +gAnOylz1kDY_0 person +gAnmF0EFcB4_2 elephant +gAorjWC_59o_0 cat +gAo9Rsd6xwg_0 cow +gA2FDYNulg8_1 person +gA22uEcTAuY_1 dog +gA84cp5Keqk_0 horse +gA_a2Ajm7B8_1 horse +gBFsvbfVaLg_0 person +gBJgWZcXu9o_0 person +gBK7NwUcSoY_1 person +gBOpan7nm6M_0 horse +gBOpan7nm6M_1 horse +gBPipHCII3M_0 bus +gBRc8zqsL78_0 dog +gBUOzZPs_o4_2 person +gBUOzZPs_o4_0 person +gBYqrtFnN_Y_0 person +gBYqrtFnN_Y_2 person +gBeaBC0u9cQ_0 person +gBhKhiEJUCM_0 horse +gBiq_BH15FM_0 dog +gBoebgAjbVw_0 person +gBoebgAjbVw_1 person +gBs3hPLJTGs_1 horse +gBwCej92lKg_1 person +gB0wConR2VI_1 skateboard +gB2QHXkiiHs_2 elephant +gCDBnQV_G3c_0 cat +gCDBnQV_G3c_1 cat +gCGtBmntCiI_1 motorcycle +gCHegjuq0os_0 person +gCHegjuq0os_1 person +gCI1E3Hezdo_2 cow +gCI1E3Hezdo_1 cow +gCTp3CdMHCo_0 person +gCT0VAdPm98_0 cat +gCuOoA6aZ5U_0 cat +gC7K3OeQFHo_3 bird +gC7XtkA9y_Y_0 dog +gC-xUbdM-tU_0 person +gC-xUbdM-tU_1 person +gDAPPFBC9Gw_0 train +gDEpD9ek-O8_0 skateboard +gDGLrPPl_PU_0 cat +gDMsKJ61KPo_1 skateboard +gDOGAHsBM_o_0 person +gDTs0BOj8Fw_0 cat +gDU0hHsqtbU_3 knife +gDU0hHsqtbU_5 knife +gDU0hHsqtbU_0 knife +gDVGs8wTXCQ_0 cat +gDkDXOm8z5Q_1 cow +gDkDXOm8z5Q_0 cow +gDk-zDBsv7g_0 dog +gDnSIxaiPzk_0 person +gDn3-DCSgNg_0 train +gDsBFuJE6D8_2 dog +gDvOoWXI3yg_0 person +gD2GATPADlA_0 person +gD5_x_Bz1z4_0 person +gD5_x_Bz1z4_1 person +gED4_ImWufA_0 truck +gEE_GCrAqF0_0 person +gEJi9Jawk2A_0 person +gEOxDCDD97k_1 horse +gESEn7ZZELM_0 person +gESEn7ZZELM_1 person +gEai3uMvvFg_0 airplane +gEai3uMvvFg_3 airplane +gEai3uMvvFg_4 airplane +gEhLmQnM720_0 car +gEu4mV0DWRQ_0 person +gE0ZQD1rCy8_0 person +gE0mBxOEwRI_1 skateboard +gE0mBxOEwRI_3 skateboard +gE8ErAnVuzY_0 bird +gE8ErAnVuzY_2 bird +gE-GVN9ErhI_0 person +gFEnoylVci0_0 person +gFac0jUOjCE_0 horse +gFcIMdm4qtI_0 train +gFdHQTLSmnc_0 airplane +gFfVZSPVYmY_0 person +gFiSl9m-w0k_0 person +HdBc9ySq76E_1 bird +HdCyMGZFJhM_0 person +HdFYXjdN5_8_0 person +HdO2lmXvENQ_0 horse +HdR6VoZEwAU_0 cat +HdSXU0fhHbM_0 person +HdT_9pXdxuc_1 person +HdbZzqJGLo8_1 cow +HdcXcqUlgI4_0 skateboard +HdhKF0UWx4g_0 person +Hdh3nOzwVW8_0 person +HdjbDB8UvCY_0 person +Hdo3_NQiVKw_0 knife +Hd85XlwoOMc_0 person +Hd-wT5OTZDE_0 person +Hd-wT5OTZDE_1 person +HeIrGQnIMOE_0 dog +HeLNz5XJe08_0 person +HeTGT7JfvB0_0 person +HeUD1Hrzswg_0 bird +HeYNsU-PKJs_0 cow +HeYNsU-PKJs_1 cow +HedUVNznPK0_0 car +HedUVNznPK0_1 car +HeoyKd78htI_0 person +HeoyKd78htI_1 person +HewdFRJAXH4_0 person +He08dewEgbY_3 motorcycle +He08dewEgbY_0 motorcycle +He1OQxCPk_w_0 person +He5cucK-e48_0 person +He6bAMDkCss_0 elephant +HfDHvE46LYU_1 bird +HfDzCPRQ2nw_1 elephant +HfEXlJ0dOhU_0 person +HfEZYvYqq_Y_0 cow +HfHNi93ZHoo_3 cow +HfHNi93ZHoo_1 cow +HfOcLeLWchM_0 person +HfZ871F0xSo_0 cat +Hfnnbr4CeTg_3 bus +HfqI5BIpp0s_0 person +Hfq3_YJ7BpY_0 motorcycle +Hfq9JFmquE4_0 person +HfvJc2dxUR4_0 boat +Hf1Iyyz2DMY_0 person +Hf1Iyyz2DMY_1 person +Hf8JWsbSYYk_0 person +Hf8-8h45g-g_1 elephant +Hf8-8h45g-g_0 elephant +Hf8-8h45g-g_2 elephant +HgDimNCaxF0_1 bear +HgFCKM4ndEc_0 car +HgMYuCtsOwc_0 person +HgMYuCtsOwc_1 person +HgO57Npp9Yg_0 train +HgexaoNeZJk_0 person +HgiYmNrxUzg_1 person +HgkeptGXNt4_0 motorcycle +HglF9x-ORXU_0 person +Hgr5__oevds_0 person +Hg2vqnLAc8I_0 dog +Hg4DJ-x85Dw_1 elephant +Hg-R_RMIEN8_0 airplane +HhASNiFpJlw_0 truck +HhF6cAtp7Xs_0 knife +HhGGJNmwWHk_0 person +HhVSLU0A-wk_0 car +HhcMy4KZ9mY_0 skateboard +HhfSUB2LOTU_0 person +HhiUVwHWmwM_1 person +HhiUVwHWmwM_2 person +HhiUVwHWmwM_0 person +HhjGAeK-XWg_0 person +HhoRf1Ovlf8_0 person +Hhvq-cwBJgo_0 person +Hhwzl9x_m34_3 cow +HhxV27YhiqI_0 skateboard +Hh1xD0M0N8Q_0 person +Hh6x850teNQ_5 airplane +Hh6x850teNQ_7 airplane +Hh6x850teNQ_8 airplane +Hh6x850teNQ_9 airplane +Hh6x850teNQ_10 airplane +HiBUWbOyqcQ_0 person +HiGZ2EdJh2o_0 person +HiMItbtVHcY_0 cat +HiMItbtVHcY_1 cat +HiNt0G1AIO4_0 motorcycle +HiTE5nqzjBw_0 zebra +HiUz61ffgHA_0 person +HiZDjdREbmc_0 umbrella +Him7gJ7sArU_0 person +Him7gJ7sArU_1 person +HinGUsliCKc_0 truck +HirBTVnhNls_0 cow +Hi4ITByGP0Q_0 person +Hi4mzrYdRBQ_0 horse +Hi4mzrYdRBQ_2 horse +Hi4mzrYdRBQ_3 horse +Hi8Ey0o5mCQ_1 person +Hi-7ZtG_JWI_1 person +Hi_YHp3Jz48_0 cow +HjAtN_MbguE_0 person +HjLLTWwaCB8_0 horse +HjNfykX021M_0 person +HjNfykX021M_1 person +HjgdNiVfO9M_0 skateboard +HjlX9nu9Vf4_0 person +Hjo13y8dFy4_0 motorcycle +Hjt_y0CW-dY_0 person +Hjt_y0CW-dY_1 person +Hjxd2cno65M_0 skateboard +Hj0J8FVxBjg_2 person +Hj0J8FVxBjg_0 person +Hj0J8FVxBjg_1 person +HkApyQz8MTY_1 horse +HkQ4tzUFCUU_0 truck +HkW_wLkAKpg_0 person +Hke6h3Sv5bA_1 bicycle +HkzYNIDq0q4_0 train +Hk45sdCRh9g_1 bear +HlEkgK08UfY_1 person +HlTQbPXnzu8_0 dog +HlWsih27OmA_0 bird +HlaPVZM-53c_0 person +HlfpirtC6oQ_0 person +HlmuHGoCGAI_0 cow +HltyUzvtugM_1 bicycle +HlurUBv4bh0_1 giraffe +HlurUBv4bh0_3 giraffe +HlurUBv4bh0_4 giraffe +HlwSaYwFLRE_0 horse +Hl3qik9GRX4_0 person +Hl5MXwWiXWM_0 person +HmDDLtJcD5g_0 person +HmORePbYJkk_0 skateboard +HmPvsdwo_fY_0 dog +HmRm2phIiGo_1 bird +HmY8zwmIiac_0 cow +HmaGylwEFxw_0 person +HmbTCfB3Vkg_0 person +Hmk4dZnPtRY_0 bus +Hmn3xf-zqWI_0 person +HmqV_7hAxdw_0 person +Hmr0jbygomI_0 giraffe +HmwxDK0zo6U_0 person +Hmyj1zKgToA_0 person +Hm0kxS31F_U_0 person +Hm0kxS31F_U_1 person +HnNJeASG0-M_3 person +HnNJeASG0-M_4 person +HnNJeASG0-M_2 person +HnNzkYDhWks_1 person +HnNzkYDhWks_2 person +HnNzkYDhWks_0 person +HnP7iXcgg8g_0 truck +HnSHJ_iCdi4_3 truck +HnSHJ_iCdi4_1 truck +HnUrGKpAsOk_0 cat +HnbNOJpzYPE_0 person +HnjhdtM8qSI_0 skateboard +HnptRKjBUF0_2 boat +HnwYRWj3fk4_2 knife +HnxaJbaAiUI_0 person +HoH5exlgIxk_1 skateboard +HoLifxKZUpI_0 person +HoLifxKZUpI_2 person +HoLifxKZUpI_1 person +HoNs_4V1pNs_1 bear +HoNs_4V1pNs_4 bear +HoP_nMgAxAk_0 boat +HoeeRkyNozc_0 cow +Hon64st5_6g_0 train +Ho2ixBE8dzE_0 giraffe +Ho5TcUOlb3Q_0 motorcycle +Ho5o7aBqNAc_0 person +Ho6N0OgD-1M_0 person +HpBBda_pbf8_0 motorcycle +HpGr16tW9dk_1 person +HpQ90KkREGo_0 person +HpUPD5_WMYI_0 train +HpZ3IzUfsGg_3 bus +HpbQsLdUHN4_0 boat +HpjyvLHus3Y_1 skateboard +HpkTeQdQ03Q_0 skateboard +Hprw9lNWGGs_0 person +HptcjVcfzgY_0 cow +Hpwk73qvroU_1 elephant +HpzTTAS6Qt8_0 person +Hp0SQy5w9Q4_0 person +Hp-eaTbVfLY_1 bear +Hp-2Gb7Fwns_0 cow +HqxhhM71S2g_0 horse +Hq1KLztJBrE_0 person +Hq6tGHLzg4Q_0 person +Hq814Tfrblw_1 airplane +HrHPBJOnFgg_1 train +HrHPBJOnFgg_0 train +HrHPBJOnFgg_4 train +HrHPBJOnFgg_6 train +HrdVu5J3rZQ_0 person +Hr-keYNRBhA_0 train +HsLZwGFHYUg_1 horse +HsNcZZ6iwHQ_0 person +HsOiHc1moVk_0 person +HsOkCwZLv_w_0 bus +HsOkCwZLv_w_3 bus +HsOkCwZLv_w_1 bus +HsOkCwZLv_w_2 bus +HsR2xk4I1as_0 person +HsVKw_8AQtM_0 person +HsZgeesgCZQ_0 person +HsjVUPs3XB4_0 boat +HslbDMoiABY_0 car +Hslld67XdsY_0 person +HswufOfUGyk_0 truck +HsyscFWIPZs_0 bus +Hs0HRqYcYqA_0 car +Hs6bVSOu98U_0 dog +Hs_vQr20HdQ_0 skateboard +Hs_vQr20HdQ_3 skateboard +HtErHV_tZqs_0 elephant +HtIbfC8DDos_0 truck +HtNaGNO6nnc_0 person +HtRiNzzfakk_0 person +HtUPhgHKN9c_1 boat +Hth8t7jhKPs_4 horse +Hth8t7jhKPs_7 horse +Hth-I5KYVsI_0 cat +Ht054jKgWfE_0 person +Ht9C8ABsxrg_0 person +Ht_bczKGV-0_0 person +HuNIgJEUelo_0 person +HuNIgJEUelo_1 person +HuOzcY9ybpo_2 dog +HuVl7peYYF8_0 person +HuVoecmBgpM_2 bird +HuVoecmBgpM_1 bird +HuZPTuSe7Zw_0 person +Hue6Q5JKEKw_0 cow +Hun4T6fv3cs_0 person +HuqC6CX9uRA_1 person +Huyd-7WlWWU_0 person +Hu3xpcZqwRg_0 person +Hu9DGxLcg2c_0 person +Hu-VYy60p64_0 person +HvHJi-EkL8c_0 skateboard +HvIubGltpPY_0 dog +HvLq5xDKM6E_2 bicycle +HvP4rcOll6k_0 person +HvQGnFuiwtg_0 cat +HvTvaPx2hXw_1 train +HvhkLhJ4YFQ_0 person +HvuLPfhVT3s_0 person +HvyIg5RMLbU_1 person +HvyIg5RMLbU_0 person +HvyzpBvy40o_0 person +Hv5sH0eTE_M_0 dog +HwSP55CmiCk_0 person +HwS3weg4aQc_0 dog +HwS3weg4aQc_2 dog +HwY6kiQlICc_0 person +HwdEYJ2bZkg_0 airplane +HwdyzravQpY_0 cat +HwfLycybCD0_0 motorcycle +HwgmR0Qlm_I_0 person +HwipRH29Hr0_0 bus +Hwnqezsko-Q_0 person +Hwnqezsko-Q_1 person +HwxnH--ot8o_0 car +Hw0JhQaRYcA_0 cow +Hw2Bhz2SkUI_0 person +Hw2Bhz2SkUI_1 person +HxMniz8r1x4_0 person +HxP056QWsGY_0 person +HxP056QWsGY_1 person +HxaFZyog34E_0 person +HxaFZyog34E_1 person +HxgU1Dh8wMs_1 person +HxiBpvG82Ys_0 motorcycle +Hxq1wNRv5Yg_0 person +Hxv6y6I4mvE_0 horse +Hx19D3w4xGI_0 giraffe +Hx_Z9TOIV8U_0 motorcycle +HyJgfYNotwk_0 truck +HyUY7bqdm9Q_7 dog +HyUY7bqdm9Q_0 dog +HyVLne6RE-A_0 person +HyXjUWAQ970_0 skateboard +Hygs9OBUgg4_1 person +HyuQCu-z558_0 motorcycle +HywSTw3dtgs_0 person +HywSTw3dtgs_1 person +Hy4E2NZEc34_1 train +HzAOQnmw_bo_1 elephant +HzAOQnmw_bo_2 elephant +HzCClfShiwM_0 person +HzCClfShiwM_1 person +HzDzb9xxc6o_0 person +HzESeh3ZV4g_0 person +HzHWWeZEU6E_1 skateboard +HzJgpBBIk1o_0 cat +HzLm3QfIx9w_0 person +HzLm3QfIx9w_1 person +HzXBY-SJECY_0 horse +HzYY4-iAvrk_0 cow +HzdSxrJ2oBw_0 skateboard +HzkmlCJwvqo_0 horse +Hzlcc_lAGVo_2 skateboard +HzqIVSJNXAU_1 person +HztbwJhPXyk_0 person +Hz6I6jLi4NA_0 dog +Hz8qayZDGpU_0 person +H0Adt_c6kJo_2 elephant +H0EEB1bPOjE_0 person +H0VjOJvg49Q_0 bicycle +H0Ym6NE2ny8_0 cat +H0gWl9KRbHo_0 person +H0k2WZec6aA_1 train +H0k2WZec6aA_3 train +H0k2WZec6aA_4 train +H0k2WZec6aA_0 train +H0u061QsnHw_0 cat +H0yhw97jkkY_0 person +H0z8VqDW-vg_1 airplane +H01F2fhFpr0_0 elephant +H097WsXpask_0 person +H097WsXpask_1 person +H1C2ZZeeVs0_0 cow +H1Hd5Japfbc_3 train +H1Hd5Japfbc_0 train +H1Hd5Japfbc_1 train +H1Hd5Japfbc_2 train +H1JIvu1dbbk_0 person +H1JIvu1dbbk_1 person +H1MTfTrQrE0_1 person +H1d68B_jDjI_0 person +H1hg-0_AS9A_0 cow +H1xBJoYM7rE_4 truck +H1xBJoYM7rE_5 truck +H117IshzypA_0 knife +H144B0rpQh0_0 person +H144B0rpQh0_1 person +H1-_3CvKDzc_0 bird +H2Q-46IlKEc_5 truck +H2Q-46IlKEc_6 truck +H2RoEMwxEAk_1 person +H2TqEPsubdM_0 bear +H2iTxNLOK1Q_2 motorcycle +H2iTxNLOK1Q_0 motorcycle +H2iTxNLOK1Q_3 motorcycle +H2vkpfO2yqU_0 person +H22P5Z4GfkE_0 person +H29Xe5gG_-s_0 person +H3A2DSw_xNU_1 elephant +H3GcVWKTVd4_2 truck +H3NrFrjQlfc_0 person +H3exbzmmPQY_0 person +H3jC0oToDjU_2 person +H3jC0oToDjU_3 person +H3jC0oToDjU_0 person +H3o1VsopVFM_1 bicycle +H3o1VsopVFM_2 bicycle +H3pifBCagTI_0 person +H30IPtBzf_s_5 skateboard +H30ifg3HO_I_3 dog +H33IRr1Z3-w_1 train +H36UOsilz4M_0 person +H4Hp-UJYZ_g_0 bicycle +H4JiUp8EH3s_0 zebra +H4VZD26aqe8_0 skateboard +H4VZD26aqe8_1 skateboard +H4bN1hcXw9Q_1 person +H4dTHFeYa30_0 motorcycle +H4eE_LAeWXQ_0 person +H4eE_LAeWXQ_1 person +H4gxLA7vTo4_0 person +H4lBmXOi3Uc_0 dog +H40G2dsVha4_1 train +H41XJMKpfFM_0 bus +H42hQSjU97o_0 knife +H5NqMNaMEiM_0 bird +H5YO56LD_dY_0 elephant +H5YO56LD_dY_1 elephant +H5iHzuWmtDw_1 dog +H5sijKl_Xi4_0 cow +H50EXfjT2O0_2 airplane +H50EXfjT2O0_0 airplane +H50EXfjT2O0_1 airplane +H50-_mqAU14_1 cow +H55Ru4hgats_2 elephant +H55Ru4hgats_3 elephant +H6OhYxXS1So_0 cat +H6UwkC3sYic_0 cat +H6ZHYEOcjCI_0 bicycle +H6ZHYEOcjCI_1 bicycle +H6Z8sZ34ZGw_0 motorcycle +H6dXJIZnH-k_2 train +H63oHdGMBAs_0 bird +gFunUi36tVM_0 horse +gFunUi36tVM_1 horse +gFvhLM1k-IY_2 truck +gFwCuQBtZiU_1 umbrella +gF7IM-CiOdU_7 bicycle +gF7IM-CiOdU_0 bicycle +gGBEKYXUhbE_0 truck +gGMxVO2zmP4_9 bird +gGMxVO2zmP4_1 bird +gGMxVO2zmP4_2 bird +gGMxVO2zmP4_5 bird +gGMxVO2zmP4_8 bird +gGSCGkm00jM_1 bicycle +gGYN2hnw1SQ_1 elephant +gGdKtY4p1E0_0 airplane +gGt9CVOzJOI_3 knife +gGzaN_8PxZw_0 skateboard +gG8tfb-eSuo_0 train +gHC3HqRbW6g_0 elephant +gHF9PM2MVuw_1 train +gHvzU7dfBU8_0 giraffe +gHyK46CyQtA_0 cow +gH0LLPcn-H8_0 elephant +gIBZr7Mh05k_0 bird +gIMq_fnjtSM_0 cat +gISy0wedyW4_0 boat +gInHAdlbB60_1 skateboard +gIsXFCo7Nt4_1 dog +gIxuS1GwPPo_0 train +gJV63DGM7Ew_1 car +gJa0yNDBFio_3 person +gJa0yNDBFio_0 person +gJa0yNDBFio_2 cow +gJfD9eHnos4_1 elephant +gJn5fXk7dCs_0 airplane +gJuZGVWuQQ8_2 bicycle +gJ-k_oHkqYc_0 cat +gKHR68FmKE8_3 airplane +gKHR68FmKE8_0 airplane +gKHR68FmKE8_4 airplane +gKmF78OWCUc_0 motorcycle +gKqUwiPYSh8_0 motorcycle +gK7dud30V7k_0 giraffe +gK_K33gm3SA_1 motorcycle +gLQWgnWqQ1Y_0 bicycle +gLRU7lXCgNw_1 dog +gLRexWYaW_Q_0 skateboard +gLbADp0AlZU_0 bird +gLtnBhTBpkA_1 boat +gL3uBv5NWJU_1 bus +gL7JySv9H4I_0 bicycle +gMAW4Am5_pc_0 cow +gMBTewi9VZg_0 cow +gMCCgBzug_U_0 knife +gMFgEtqbTXs_0 boat +gMJuszEOURk_0 cat +gMMJH4UYboM_3 bus +gMXt8X-xC_g_0 dog +gMlNev_l4Yg_0 bus +gMlhd1gczF4_0 airplane +gMsGe7w79Hg_1 car +gM9tFNvc1xw_0 cow +gNDSQ2l9FYg_1 elephant +gNMkDmfkZ1E_0 motorcycle +gNcGXjn7g9o_0 skateboard +gNwKVPIi010_1 skateboard +gN2aKPpTpzQ_1 dog +gN7-cLfUlt8_4 giraffe +gN7-cLfUlt8_6 giraffe +gOOB0RZmnUA_0 cow +gORdlzUa3nQ_1 bird +gO48FZrUm88_0 skateboard +gO-8RNI2Puc_1 dog +gPhcXlQLLRU_0 horse +gPrWvEE7yjw_0 cat +gPteWZyyJeo_0 cow +gP3SQErTTOg_1 motorcycle +gQBW4py4GhY_0 skateboard +gQEGmIhhEQ4_0 train +gQEGmIhhEQ4_1 train +gQEGmIhhEQ4_2 train +gQFqppfDRRk_0 umbrella +gQLZ5H-n0Uk_4 knife +gQVlREJXkik_0 knife +gQWTTEHj5Hs_0 cat +gQeqE3dgZoM_3 airplane +gQe5gykuyi4_1 train +gQpWY94Fx5E_0 motorcycle +gQpuEhphXHk_0 car +gQpxfwrF7Sc_0 bus +gQ6AUvEXuaQ_0 bicycle +gQ9HhxeKI4A_0 motorcycle +gQ_SF2MtsUc_0 elephant +gRFcteFGpLM_0 skateboard +gRJGd_HzC-8_0 knife +gRJpf6JwJeU_1 giraffe +gRNKgw2D_mE_0 knife +gRVrvJioWZ8_1 train +gRoGrhv1ebI_0 elephant +gRsOR1tKh8U_0 truck +gR3ihf3rch0_0 car +gSXDTJjj1jk_0 train +gSi2fNTUsy8_0 horse +gSlT3ALqvTM_0 skateboard +gS0DTbVQ2x8_1 knife +gS25yLrNO98_0 bear +gS2-SAccVh0_0 skateboard +gS7U-6Z8M2g_1 knife +gS_9D3OWXAk_0 airplane +gTqgARR0BBQ_1 boat +gT27MQBhatA_0 skateboard +gUDoTzwZlso_0 dog +gUL0-NbHvuA_0 motorcycle +gUMLascwbtU_0 train +gUNCDmbzxq8_0 train +gUbc_OUTnOs_0 airplane +H7ONEeAkBFo_3 motorcycle +H7ONEeAkBFo_2 motorcycle +H7YUH_GBWdQ_0 train +H8B-3STVp6E_0 cat +H8LitQV6pNM_0 cat +H8SccYIiPs8_0 zebra +H8coORJpR80_1 skateboard +H8k1E1i7AvQ_0 knife +H9AQUC0N1zI_0 horse +H9JfwPhdCjg_0 boat +H9KjlXZYxJU_0 train +H9KjlXZYxJU_8 train +H9TUml4LflE_0 cow +H9UTvMwaoRg_0 cow +H9bbSssKl2o_14 umbrella +H9eutGBn3zw_0 motorcycle +H-C6EBylvh4_1 cat +H-IoiGsEU5Y_0 train +H-QKbNwtoH8_1 car +H-gh485Om10_0 bus +H-gh485Om10_1 bus +H-kkRVEs3Bg_0 motorcycle +H-uiufHSb3s_0 knife +H-uvqjsUCLc_0 dog +H-uvqjsUCLc_1 dog +H-5Ynjv0dQI_1 train +H-62b99sK_s_0 train +H-62b99sK_s_1 train +H_Ei1gRODpw_0 dog +H_KMZLSAxMw_0 train +H_iI201Iqws_1 truck +H_iYHl4pFuQ_0 horse +H_mRfG30Gzo_0 skateboard +H_1O-OBZ3BA_0 horse +H_6vxd3ckIY_0 cat +IADSsAb2KSo_1 umbrella +IADSsAb2KSo_2 umbrella +IAFApeJ5FvM_1 motorcycle +IAOiNYVeqzE_0 bird +IAaINtcnO7A_0 bicycle +IAcbsZcN_pM_1 motorcycle +IAkSntQ2Aso_0 horse +IAlz_evs7fU_3 car +IApV0rfD9oQ_0 dog +IAsXYmK1baI_0 motorcycle +IAwKojHnvtU_0 train +IBD9tJNb9_o_0 train +IBFp5y96q78_0 motorcycle +IBFp5y96q78_2 motorcycle +IBKLgBXZFzw_0 motorcycle +IBYJQU6-nGg_2 cow +IBYg-hMbb04_0 knife +IBm1C4qJtTg_5 umbrella +IBm1C4qJtTg_8 umbrella +ICQbVnaJL_0_0 bus +ICZ4tinBQZg_1 knife +ICZ4tinBQZg_2 knife +ICZ4tinBQZg_3 knife +ICg3W1-Prhk_0 elephant +ICnAWjPDzRw_0 cow +ICtLhp-qveM_0 boat +IDCBO7W7xpo_0 cow +IDNvFEra8mc_5 horse +IDNvFEra8mc_1 horse +IDNvFEra8mc_2 horse +IDNvFEra8mc_3 horse +IDNvFEra8mc_4 horse +IDO6jw3u3_w_1 airplane +IDcxChwEqDs_2 horse +IDeGA2EV3WY_0 airplane +IDeimFOIbVc_0 train +IDmwsXLZKUs_0 cow +ID1faW2L3rM_0 cat +IEOg-ZulFR0_1 bird +IEPYJyHfP2E_1 elephant +IEYC-aYAQ40_0 boat +IE5qZDd7tWw_0 elephant +IFGohfPURX4_0 person +IFfS7hatV0s_0 truck +IFkUMGE7bbc_1 elephant +IFkUMGE7bbc_0 elephant +IFrHlldbUdQ_0 cow +IFvO1O-6vqk_0 truck +IHQvg9gYLjw_0 dog +IHSCfRs-J38_2 skateboard +IHY0eeHfBcY_4 truck +IHjI35oW0T4_0 car +IHxX0fKU9iM_1 skateboard +IH3E7RS6Hn8_0 cat +IH9BmEg26Cw_0 person +IIBN7FGNNEs_1 train +IIBN7FGNNEs_2 train +IIBN7FGNNEs_3 train +IIBN7FGNNEs_4 train +IINTapIzzes_2 skateboard +IIw0KKAeBeQ_0 skateboard +II0JbbQq-Sg_1 bird +II61z65eDCY_2 cow +II61z65eDCY_0 cow +II94vSsb4Uc_0 car +II_okDlDaO0_0 cat +gUt0vA8_1Ow_0 airplane +gUvZ3RC9tEU_0 knife +gU3SNUS1_ng_0 bicycle +gU4mBoB-b7k_1 train +gVAp7rt84ic_2 bicycle +gVCrRXledlU_1 boat +gVCrRXledlU_0 boat +gVV-5JdLuXk_3 car +gVXzT_h1SFI_3 horse +gVXzT_h1SFI_4 horse +gVXzT_h1SFI_2 horse +gVaB7hwBhTA_0 cat +gVjL5txcFMI_0 knife +gVrTFXdPWJ8_0 elephant +gVxqk8tLXL8_0 truck +gV27xS9pqNQ_0 train +gV3Xmwy3RKo_6 train +gV3Xmwy3RKo_13 train +gV9A5NfFexQ_0 car +gWcacGgcxYU_4 bear +gWlmYVY4kW4_1 bicycle +gWnhQi-zfEE_0 skateboard +gWpNWuo7vio_2 elephant +gWpNWuo7vio_3 elephant +gWsOR7UiwDs_0 airplane +gWz5ZMzC58s_0 car +gXBIzdmmHbA_1 bird +gXEHUZgPCGg_4 bear +gXFmghAzaVg_1 motorcycle +gXGvO4k4xQY_0 truck +gXHsyuynhso_2 knife +gXW33K91X7c_0 bicycle +gXn0Y5X5MJE_1 zebra +gXn0Y5X5MJE_0 zebra +gXt0u16Y6ZY_0 boat +gY_Ey8Ps_ZE_0 cow +gZhsGXSn5bU_0 motorcycle +gZqGyIMgMbs_0 bicycle +gZxcxQBlx0s_0 cat +gZzmloffFW4_0 bus +gZ8kZt451Ww_3 horse +gZ92ZDty9wI_0 skateboard +gaCEAVQd1-M_1 bird +gaS7x3F3gpk_0 bicycle +gaS7x3F3gpk_1 bicycle +gaS7x3F3gpk_2 bicycle +gaS7x3F3gpk_3 bicycle +galykATgRC0_0 cow +gaqS-4IaQ5c_2 bus +gbA3ItatxL8_0 skateboard +gbE0vzWpHj0_1 knife +gbE0vzWpHj0_4 knife +gbGl_-TnPjk_0 bird +gbI95ZXEUz0_0 knife +gbTTJah5oMw_0 elephant +gbTTJah5oMw_2 elephant +gbgbqiiEKVs_0 giraffe +gcBaPcA_1_0_0 train +gcExbr9FO94_0 giraffe +gcJ7XqXHPwM_0 elephant +gcT_dy3neEk_8 bicycle +gcXhYL06Acs_5 bicycle +gcYBNx0fUg8_0 truck +gchz9HDvVDk_0 train +gc80cGOHyKM_0 knife +gdCpPYwBVlY_0 knife +gdEBkAYaDPw_1 elephant +gdELg0NrkdA_0 dog +gdvUXfsBMIk_0 train +gdzzJI7xjBg_0 train +gdzzJI7xjBg_1 train +gd2O-Z5dOIk_0 airplane +gd4r5aA8jeg_0 bird +gd4r5aA8jeg_1 bird +geBwGOC-lX4_0 train +geBwGOC-lX4_1 train +geBwGOC-lX4_2 train +geBwGOC-lX4_3 train +geQCe6Cq5MU_1 elephant +geQCe6Cq5MU_2 elephant +geWChvEotKU_0 train +gefGPLN-abw_0 person +gfGsOzQ7gto_0 bear +gfS7FJH6Vkk_0 bear +gfUC20NWtjU_0 motorcycle +gfVlQhN0BBU_0 bicycle +gfuVNdXffSs_0 airplane +gf1mvdt9kbI_0 horse +ggIyqAThI1g_0 bird +ggPHtWoCcKs_3 umbrella +ggTFLaNIJck_0 train +ggVLptkmsys_0 truck +ggpz03j1REI_0 bus +gg3sG7O2P-g_0 bus +ghEfyxUaVGs_1 cat +ghIGC_DOfuk_0 horse +ghqqgJWnVEU_0 knife +ghyp-SKVuC8_0 motorcycle +giVGzMF1Yo4_0 skateboard +giVGzMF1Yo4_1 skateboard +gipHWMPB-W4_3 bear +gipHWMPB-W4_1 bear +gitOEvGnoYk_0 airplane +gi9bnW7uLkE_0 cat +gjGlUXCT9A4_1 knife +gjK5A6cIEnw_0 dog +gjRhqzTAkWw_0 cow +IJFaomtLVDE_0 cat +IJNUwvacbKY_0 cow +IJVUMGoBSQs_4 cow +IJXVtb2GeJ4_0 train +IJdYiBYP31A_0 motorcycle +IJlBmhH72m4_1 cow +IJ6g4ZRBksE_0 cat +IKLj0LJIMKs_4 airplane +IKLj0LJIMKs_5 airplane +IKLj0LJIMKs_2 airplane +IKftyV_zwkE_0 skateboard +IKqmWAu3GF0_0 dog +IK7Mnvty4VY_0 person +IK8IJWsxg3M_5 airplane +IK8IJWsxg3M_6 airplane +ILAGhYr9yts_1 motorcycle +ILLYlwlFTzA_0 elephant +ILmTjHZqkCo_1 truck +ILqxie6aqXg_0 bicycle +ILqxie6aqXg_1 bicycle +ILqxie6aqXg_2 bicycle +IL1HokSKOyY_0 cat +IL9r35lU8So_0 skateboard +IMD3U_DzO3E_0 motorcycle +IMD3U_DzO3E_1 motorcycle +IMde-053G78_0 horse +IMulJdQXZvM_0 train +IM7vwh5qua4_0 cow +IM8dlwNTjXU_0 cow +IM8v82x7ovA_2 train +IM8v82x7ovA_1 train +INFs2lfikXE_1 knife +INULdzdrdys_0 horse +INXkuJ9WvIU_0 train +INZhGblywrk_0 bus +INkhg9y4asY_0 bear +INtj4nfjRA0_1 bear +IN2TGHJrQEg_2 skateboard +IN2TGHJrQEg_0 skateboard +IN2TGHJrQEg_1 skateboard +IOPYEZzmeqg_0 car +IOPYEZzmeqg_1 car +IOQuWawPM3k_0 bird +IOfUvlEkN7g_0 bus +IOiqrNof90k_1 knife +IO3Z-ebx_f8_5 bus +IPI2_GXx1tI_0 bird +IPWixEFBDOY_0 horse +IPfYf-nFKic_0 airplane +IPfYf-nFKic_1 airplane +IP1CH8MMir0_0 knife +IQOfCy4FW8w_0 skateboard +IQXAYnslAnc_0 car +IQoVuUTZILY_0 airplane +IQsV_hTCyMA_1 bicycle +IQwk7Ge6Apk_0 truck +IRK6-ixyaVI_0 elephant +IRSbjN-mnJI_0 skateboard +IRZBnQJoKiU_0 skateboard +IRztQZ4bigY_0 car +IR9A3u83crI_4 elephant +IR-PGdIPgcE_0 skateboard +ISAnMprDgCk_0 skateboard +ISJW4GuahWg_2 dog +ISSTEs8xDWk_0 umbrella +ISYwpUKxHJU_1 elephant +ISYwpUKxHJU_2 elephant +ISYwpUKxHJU_0 elephant +ISud5E9hZxU_0 train +ISud5E9hZxU_1 train +IS9s3kJzTcA_0 airplane +ITCcMWC_RW8_0 umbrella +ITbwhPVxFv0_0 umbrella +ITrisbHlaJw_1 truck +ITzBy7T7_fI_1 umbrella +IT6TArZww6A_0 cat +IT8VqGbdH_A_0 horse +IT_zQ44PPOo_0 dog +IUH4PYmObvU_0 dog +IUO1sDZgGHs_0 bird +IUdyfRMOyX8_0 elephant +IUdyfRMOyX8_8 elephant +IUdyfRMOyX8_1 elephant +IUdyfRMOyX8_2 elephant +IUdyfRMOyX8_3 elephant +IUdyfRMOyX8_4 elephant +IUdyfRMOyX8_5 elephant +IUdyfRMOyX8_6 elephant +IUdyfRMOyX8_7 elephant +IUf7a2WuoBw_0 train +IUgkMOA3siY_1 bus +IUlDlS2KD-k_0 bicycle +IUlDlS2KD-k_1 bicycle +IUzpvnXep7M_0 bear +IU7x7I53cng_0 elephant +IVFq204Rr9c_0 airplane +IVHx3I13xdQ_0 boat +IVSJSu0PlsI_0 train +IVVFeaTw6IE_0 bicycle +IVjCZS2Fo7k_0 bird +IVpmCnL5cE8_1 giraffe +IVrBPzhFMi8_1 motorcycle +IVrBPzhFMi8_2 motorcycle +IVzxeeJEtiY_1 bear +IV6EMw4XYco_0 skateboard +IV6EMw4XYco_1 skateboard +IWCZ1PDW99k_0 motorcycle +IWVIIKxipc8_0 motorcycle +IWVIIKxipc8_1 motorcycle +IWn16DCfLbc_1 knife +IWumeAEXWVo_1 boat +IWu47p4l06Y_5 umbrella +IWu47p4l06Y_6 umbrella +IWu47p4l06Y_3 umbrella +IWu47p4l06Y_4 umbrella +IW1cFMDjPUk_0 bear +IW2mFJ8iw6Y_0 bird +IW4ZnmQeNtA_1 elephant +IW4g0kfA3GE_0 truck +IW5Vgh3SE-I_4 elephant +IW7TwQ-hY7I_0 motorcycle +IW7TwQ-hY7I_1 motorcycle +IXTgztKfRQU_0 skateboard +IXVCCLG3_cw_0 bird +IXyV2vpIEA8_0 dog +IXyV2vpIEA8_2 dog +gja4H3sGrqQ_0 car +gjdlZhmnGbk_0 airplane +gjfdI7hO92E_0 bird +gjquLAxFRWw_2 umbrella +gjx4xu1TyWU_1 cow +gj7W2zjQApw_3 knife +gkEoTLpAw7g_0 airplane +gkLRnt1OCH4_7 horse +gkRqNmGQbPI_0 skateboard +gkXKCuc0Moc_0 skateboard +gkXKCuc0Moc_1 skateboard +gkb4Ya5QW9M_0 bird +gkb4Ya5QW9M_1 bird +gkf0Bcsuhlc_1 car +gkf0Bcsuhlc_3 car +gkf0Bcsuhlc_4 car +gkiUpdrObXo_1 elephant +gkz49y5qcvc_0 horse +gkz-LCZcGtc_5 bird +gk1x_qYyDl4_0 cat +glNWqIolkq8_0 skateboard +glOskJOtnTU_0 knife +glOskJOtnTU_2 knife +glSdaND81E8_0 person +gltHxIp_ma8_0 bird +gmCT9tUPTB4_1 giraffe +gmdxOMQMgnw_0 airplane +gmnvPoB2cNY_0 motorcycle +gm53_sbr85Q_1 bird +gm53_sbr85Q_2 bird +gm9M-m4mCZ4_0 car +gm9M-m4mCZ4_2 car +gnA9QVNkmTU_1 knife +gnD6mU9A2oo_0 elephant +gnEttGTQqQ4_1 train +gnEttGTQqQ4_0 train +gnF9YJM1jaE_1 cow +gnGvXHS4UDs_0 airplane +gnM9SRiFh7M_0 truck +gnM9SRiFh7M_1 truck +gnPrHGB85WY_0 bus +gnTj3krZROI_4 boat +gnVo44q-XDI_0 knife +gnb1N_MLdcY_2 elephant +gnwCzU63_YY_0 person +gn2XuCFK-hE_0 truck +gn2bME2rmGw_0 truck +goIfg0C9kmM_0 dog +goOIZE0j6DM_0 bicycle +goSyNORcJ00_0 airplane +gok9kHQ77dY_0 skateboard +gollBTymf8I_1 bus +gomnpeJd5zw_0 boat +gonzAOezSOQ_1 train +gonzAOezSOQ_2 train +gosq350N9dI_2 skateboard +goyIWrU1Lbo_0 cat +gpBoXY6MM5E_0 dog +gpEiPRMcPwo_4 bear +gpY-o8xPA3w_0 bicycle +gpa4WfWCLa0_1 elephant +gpa4WfWCLa0_0 elephant +gpa9p4XNeKc_3 bear +gpbdiDEPd-s_0 skateboard +gpjqG97-SyQ_0 horse +gpmdLMUX53k_0 bear +gp2SDJHMADo_3 horse +gp2SDJHMADo_0 horse +gp2SDJHMADo_2 horse +gp9q0jvTKo0_0 bird +gqNgT7LxZSQ_1 bus +gqOfm9XTr6M_3 airplane +gqOfm9XTr6M_0 airplane +gqOfm9XTr6M_1 airplane +gqOfm9XTr6M_2 airplane +gqbDkeOx0mA_0 motorcycle +gqgQpw4DWZA_0 giraffe +gqhweewmNn8_0 skateboard +gqkLzCkKKtE_0 skateboard +gqucExXpPys_0 car +gqxvRzuWcrI_0 bird +grBVFo1wSjs_1 bird +grFPTYaKb7Q_0 bus +grI0uf6IwBw_0 bear +grNkPqf-ySE_0 dog +grWw42izM6M_1 train +grWw42izM6M_2 train +grWw42izM6M_0 train +grbP7mKMX_A_5 airplane +grbP7mKMX_A_1 airplane +grbP7mKMX_A_4 airplane +grdEE264TwM_0 motorcycle +grdIYaNewv0_0 motorcycle +grhIgcHgpOw_0 bus +gsCvhqZCWX0_0 dog +gsUrGSN-k00_0 horse +gsbJ13WiSvE_1 horse +gsfIYIQ1siA_0 skateboard +gsvn88OsH_8_3 knife +gsv7RJk7dtY_0 dog +gs_C12A8Wq4_1 bicycle +gtFIMtVrAGk_0 bicycle +gtNJSexRjxE_0 car +gtNdVTTd0tg_0 bicycle +gtNdVTTd0tg_2 bicycle +gtOa6rSatLA_0 cow +gtQ_uFTKEck_1 horse +gtii5vwjSTY_1 dog +gtuj1cOmYSs_1 train +gtuj1cOmYSs_3 train +gtz5ClHTSVo_0 cat +gtz5ClHTSVo_1 cat +gt_WHCkauOA_1 knife +guVl_gp0sJE_0 bus +gugP5f2JRJ0_1 bear +gugP5f2JRJ0_0 bear +guh1OUkdIGE_0 horse +guktzkv1els_0 boat +guv5reh2NH4_0 boat +guxRXiegac0_4 bird +gvNxDnFriAI_0 skateboard +gvcioONBIcE_0 train +gviQTbs7dIk_1 bird +gvjcggbLXRo_0 elephant +gvjcggbLXRo_1 elephant +gvjcggbLXRo_2 elephant +gvk0hzlYu9E_0 umbrella +gvraCN0RYko_0 dog +gvtY3fwbgdc_0 cow +gvuBfR3HXac_0 elephant +gv4sQFTuJ-k_0 elephant +gv7qY66lOhs_0 giraffe +gv8pF9t1zYM_0 elephant +gwKq56_M6Kc_0 horse +gwN_p_IRuoo_0 horse +gwP-6gOPn2c_0 motorcycle +gwTc-69C_P4_0 knife +gwTyjJwBgRk_0 horse +gwy7eePYryM_1 boat +gw9MjutMhLs_1 airplane +gw9MjutMhLs_3 airplane +gw9MjutMhLs_0 airplane +gw9MjutMhLs_2 airplane +gxKnyBP8_cs_0 elephant +gxejG9D0guY_1 person +gxgZg6BU3ds_0 dog +gxgZg6BU3ds_1 dog +IX4HjI_9vLY_2 dog +IX4IwgbTdCk_0 dog +IYBF45M9nTc_0 skateboard +IYBzvotFEYo_0 motorcycle +IYZZ-K_Ygpo_0 bicycle +IYdXz1cOCWc_0 giraffe +IYukRQKxhFI_0 person +IYukRQKxhFI_1 motorcycle +IZESZPVT0zk_3 bear +IZGady38Nh8_0 bird +IZIPpBl_h0Q_5 truck +IZIPpBl_h0Q_0 truck +IZIPpBl_h0Q_6 truck +IZJ1PO3Fkuw_0 umbrella +IZLMXYU4A-0_0 airplane +IZLMXYU4A-0_2 airplane +IZTfd31H0AI_0 bicycle +IZUO1x0QT1I_1 elephant +IZ2nFUgP-Pw_1 elephant +IZ2nFUgP-Pw_5 elephant +IZ2nFUgP-Pw_6 elephant +IZ2nFUgP-Pw_3 elephant +IZ2nFUgP-Pw_4 elephant +IaAPZOFgclo_1 elephant +IaG7siKVlak_0 giraffe +IaxZJVx5ptw_0 truck +IaxZJVx5ptw_1 truck +IaxZJVx5ptw_2 truck +IaxZJVx5ptw_3 truck +Ia0DjYXcBWc_8 elephant +Ia0DjYXcBWc_4 elephant +Ia0DjYXcBWc_5 elephant +Ia0DjYXcBWc_6 elephant +Ia0DjYXcBWc_9 elephant +Ia0DjYXcBWc_10 elephant +Ia0DjYXcBWc_11 elephant +Ia0DjYXcBWc_12 elephant +Ia0DjYXcBWc_13 elephant +Ia0DjYXcBWc_14 elephant +Ia0DjYXcBWc_16 elephant +Ia0DjYXcBWc_18 elephant +Ia0DjYXcBWc_19 elephant +IbEpwiOUFEI_0 dog +Ib15GlTvqTQ_2 skateboard +Ib2u6u-j2vk_0 skateboard +IcEs4vbIcDM_0 umbrella +IcSumCpVOy0_0 skateboard +IcZ2D-MawSg_0 truck +IciJuq7ZY6o_0 elephant +IckUkdfRndY_1 knife +Ic1cufihs-0_0 elephant +Ic1cufihs-0_1 elephant +IdSlvHXTrmE_1 skateboard +IdXPNOQD97w_0 motorcycle +IdabN3kTjSk_0 skateboard +IdrTVVio1U4_0 dog +IdvQme2elLk_1 truck +IdvQme2elLk_2 truck +IdvQme2elLk_3 truck +Id6HsaEvZ0k_0 person +IeB4Nf3h7T4_0 bus +IeENvG3Qtk0_5 elephant +IeFUkGY1b4Y_4 elephant +IeXb8CHr4ms_0 train +IefPtlA5ebA_0 motorcycle +IehTemq8EYc_27 bicycle +IehTemq8EYc_28 bicycle +IehTemq8EYc_0 bicycle +IehTemq8EYc_6 bicycle +IehTemq8EYc_11 bicycle +IehTemq8EYc_15 bicycle +IehTemq8EYc_17 bicycle +IehTemq8EYc_19 bicycle +Iejh8w6egIA_0 umbrella +Iek9nAfsymA_0 bus +IewJcdqOzCY_0 train +IewJcdqOzCY_1 train +Ie4Ct_HRDNw_1 dog +Ie5lfGQndBs_0 airplane +Ie8dc7EO7VI_0 bicycle +Ie8dc7EO7VI_1 bicycle +Ie8dc7EO7VI_2 bicycle +IfBft2ltqqE_0 skateboard +IfBft2ltqqE_1 skateboard +IfFnkz6EUno_1 horse +IfGZXa16ZnQ_0 knife +IfTrYE-Ox50_0 cat +IfZDLHBP_qk_0 bus +Ifpbe7xlKp4_0 truck +If4WPZY4LIY_0 elephant +If8EotoXQVQ_1 truck +IgO9_kN8D5I_0 cat +IgRs6nmhv2w_0 cat +Ige9Idj8fDw_3 cow +Ige9Idj8fDw_2 cow +Ig0Luv6UlkE_1 bicycle +Ig1JdzucmLI_0 boat +Ig9jZPM0n2A_0 car +IhR6ePM1wRw_0 bird +IhXAXy3VAqA_0 cat +IhdGvFfk3Ks_0 bird +IhlRPxknT9E_1 motorcycle +Ihp3YZGcRjM_0 horse +Ihp3YZGcRjM_1 horse +Ihsr3gT-u00_0 cow +IiBzrow5m9w_0 cat +IiH0f7VOXTY_4 airplane +IiH0f7VOXTY_2 airplane +IiH0f7VOXTY_3 airplane +Iie6uM_sdLE_2 truck +Iie6uM_sdLE_5 truck +IiscR53FEz0_1 airplane +Iiy_W2tIOWI_0 boat +Ii9URMIXJjc_0 dog +IjHqTBt-tzY_0 horse +IjMLYR0bH6g_0 cow +Ijf2ZMTxDUs_0 cow +Ij57BoIbMws_0 train +IkOG3ZnCvY4_0 cow +IkVifrtYlcI_0 skateboard +Iklc7ijgOtA_0 horse +Ikl-nlqwUJA_2 train +IkqFTjEXf4g_0 motorcycle +IkrKcORoFLI_0 cat +Ik4UxtlIrw0_5 airplane +Ik4UxtlIrw0_13 airplane +IlJT6oek8KQ_0 dog +IlNV-gFlp3Q_0 umbrella +IlshSY2CGU0_0 cow +Il1TKTSRPO4_0 train +Il7GtfxmBlQ_0 skateboard +ImCV4d0kYxY_0 skateboard +ImEKl15Aipo_2 bear +ImOLHl6gwLE_0 giraffe +ImO7oG_YuSU_0 train +gyBWGyhFuWg_0 elephant +gyBWGyhFuWg_1 elephant +gyBWGyhFuWg_2 elephant +gyBWGyhFuWg_4 elephant +gyBWGyhFuWg_7 elephant +gybSfaDRdVA_2 airplane +gy3zF39Y7B8_0 airplane +gzQrsNwx8MQ_1 truck +gzTHA0tMocM_0 bird +gzUj7KfvRPY_0 train +gzVdw-5l3sY_5 bear +gzWwT4ufwFY_0 bicycle +gzwzd6nOPoI_3 bear +gz13nfjIblU_0 skateboard +g0Jq0uIY3i0_2 knife +g0LufqNJtss_1 elephant +g0LufqNJtss_2 elephant +g0SdZmm5Mm0_0 horse +g0W6U-p-T2c_0 horse +g0om0nrfC4w_5 airplane +g0om0nrfC4w_1 airplane +g0tXovGqqSE_0 cow +g0zcJWO1MbU_1 airplane +g02OQmAgfo4_0 train +g02OQmAgfo4_1 train +g04xUjb4z0w_0 bicycle +g05TJKB5TL0_0 elephant +g05TJKB5TL0_1 elephant +g05TJKB5TL0_2 elephant +g1HtoWJ3NjA_0 airplane +g1UUBEfyzJ4_0 horse +g1UUBEfyzJ4_1 horse +g1ZtaoEqtjI_0 bus +g1j_9A4-PL4_0 cow +g1n74kWqKFM_0 truck +g1vq3JO3eH0_0 skateboard +g12DCVqfKjM_0 airplane +g13JzTyNCPY_0 truck +g17hrSF1YN8_1 bear +g2Hh_97o7jY_0 person +g2KeNy_WECo_0 bus +g2MUK80Ht8k_0 horse +g2MUK80Ht8k_1 horse +g2MUK80Ht8k_2 horse +g2MUK80Ht8k_3 horse +g2MUK80Ht8k_4 horse +g2cCr0rRIeo_0 motorcycle +g2vRpfpQuNE_1 motorcycle +g2-SNBvYdNc_3 car +g2-SNBvYdNc_2 car +g3DAFznLlXw_0 elephant +g3e6vDSvpN4_0 skateboard +g3g7M2Xv3JY_0 zebra +g3ytRwjgoMI_2 horse +g3ytRwjgoMI_3 horse +g30xOR9j3_A_0 skateboard +g30xOR9j3_A_1 skateboard +g38MDXW9ndc_0 elephant +g4BX8_C-NeQ_1 dog +g4KzjuhixSo_0 motorcycle +g4KzjuhixSo_1 motorcycle +g4R5jZXlnl4_0 truck +g5OKbEXlegI_0 cow +g5SIvfoi7tE_2 bird +g5S-76eh6vs_0 car +g5ztjA03q5k_0 horse +g55_MKVNAE8_0 motorcycle +g57hZ17etp8_0 skateboard +g5-55T7AzUE_1 skateboard +g7Qk-cV3IFs_1 car +g7YvJasRFj0_0 skateboard +g7fZhFRdYJs_3 zebra +g7oMLF6ZfT8_0 horse +g7oMLF6ZfT8_1 horse +g8aScpqmhVU_0 umbrella +g8iDSRkz_go_1 boat +g80ZYUNhRME_1 dog +g9Am-b3OqbI_0 truck +g9RM9VSJPIY_0 knife +g9WrMIn5AkI_0 skateboard +g9sD-4RBa3Y_0 motorcycle +g9uOEJm7wdw_0 elephant +g9yESRreg5k_0 boat +g9zLmd4IZ78_0 bus +g91mK1sMiSI_1 elephant +g9-6tclIBcc_0 motorcycle +g-Dfzs3HQ8w_0 boat +g-EVS_QxLxA_0 horse +g-F4Eig_Rxc_0 motorcycle +g-F4Eig_Rxc_2 motorcycle +g-F4Eig_Rxc_1 motorcycle +g-JTM0dCFFA_0 cow +g-SJXmYYHqI_0 truck +g-SlOveVnAs_0 cow +g-Z7CA3qr1A_0 skateboard +g_B2r70EsjY_2 horse +g_XW0YLzND0_0 motorcycle +g_XW0YLzND0_1 motorcycle +g_XW0YLzND0_2 motorcycle +g_dN59QhubM_0 person +g_jq8Uy4P2s_0 truck +hAHsYyTOJoI_0 cow +hAIBcR5MAVE_0 boat +hAUD4Cy2GiM_0 cow +hAUD4Cy2GiM_6 cow +hAUD4Cy2GiM_1 cow +hAUD4Cy2GiM_3 cow +hAUD4Cy2GiM_4 cow +hAUD4Cy2GiM_5 cow +hAVbFSsRfOY_0 airplane +hAcx9u12Rd0_1 cat +ImZcOQCdJng_0 skateboard +ImiKNikVSsM_0 horse +ImqKWexMOEA_0 bird +Imuhe4E1pxo_0 car +Imy4SpqoC4k_0 cat +Im3ooIguQHk_4 train +Im3ooIguQHk_5 train +Im3ooIguQHk_6 train +Im3ooIguQHk_0 train +InEZSi4Zz08_4 train +InEZSi4Zz08_1 train +InEZSi4Zz08_2 train +InTq6s23Ygc_0 cat +Inn1lo0hbX0_0 train +Invv-JPzV-0_0 elephant +In_dBFPRoso_1 airplane +IobdPoAtEB0_0 bear +IoqRCAQzibw_1 skateboard +IoqRrAswOwY_5 bear +IoqRrAswOwY_4 bear +Io5wOOkpkdE_0 skateboard +IpOFHasyloc_0 cat +IpQQ9QabgiU_0 bear +IpVCKTRou10_1 truck +IpVCKTRou10_3 truck +IpVCKTRou10_4 truck +IpYZmcVrqdQ_0 cow +IpnTUQCHioc_0 giraffe +Ip0c_3xCHRA_2 horse +Ip-N_PYIqhA_0 motorcycle +Iqv9963BN8w_0 cat +IrAxUS0aBTQ_0 bird +IrDY9nE1V2I_1 motorcycle +Ir4CkmTmSXQ_0 cow +IsSCjgdAQiE_0 dog +IslqPZDUBHI_0 motorcycle +IssSzh7Z-vo_0 umbrella +IsxRqs7KcbQ_0 cat +Is2E8gFNBWo_4 bear +Is2E8gFNBWo_1 bear +ItL-C-szpU8_0 truck +ItiAXqRQm3A_1 knife +ItkxwET4PNc_0 dog +ItzhXkBVmEY_0 car +ItzlBA8cl3c_2 airplane +It_dJluX63g_0 cat +IuN_risviek_0 giraffe +IuZ6JD-k2nM_0 dog +Iuk4W5KJbQ8_0 bus +IuwJz5d-8J4_0 umbrella +Iuw0f-Y8t6I_0 airplane +Iuw0f-Y8t6I_1 airplane +Iu26NyEUoGY_2 boat +Iu5GqI9oVnk_0 motorcycle +IvJLhgaveaw_0 skateboard +IvMiQ2e-5hQ_0 bus +IvMiQ2e-5hQ_1 bus +IvX1MeQN-e0_0 cat +IvZSk33MtAc_0 motorcycle +IvZqPTK9DEQ_0 motorcycle +IvZqPTK9DEQ_4 motorcycle +IvZqPTK9DEQ_3 motorcycle +IvfWyYn_ifg_0 elephant +IvjNeTpV6hs_0 horse +IvyftS2bPuo_10 airplane +IvyftS2bPuo_0 airplane +IvyftS2bPuo_2 airplane +IvyftS2bPuo_6 airplane +IvyftS2bPuo_7 airplane +IvyftS2bPuo_9 airplane +IwcC1J_ImAs_0 car +Iwd7i4kvS5c_0 car +IwfpNUPSvpw_0 motorcycle +IwgX5DfmIQo_0 bicycle +Iwhf27USDD4_0 motorcycle +IwmwVP_e5Ag_0 bus +IwxmbUX4fcg_0 cow +Iw6-0LYvEmQ_0 bird +Iw6-0LYvEmQ_1 bird +Iw7zBsW9W5Y_0 train +IxLbLqfxrhg_1 boat +IxNA0hdkWGg_0 cow +IxObyCZ6OfY_4 giraffe +Ix8eS24W75g_4 airplane +Ix8eS24W75g_5 airplane +Ix8eS24W75g_0 airplane +Ix8eS24W75g_1 airplane +Ix8eS24W75g_2 airplane +Ix8eS24W75g_3 airplane +IyNmzxdv8-Q_0 bird +IyQlh0wdd9I_8 boat +IyQlh0wdd9I_7 boat +IyU3NizvZuM_0 horse +IyU3NizvZuM_5 horse +Iyj9D6cwI5o_0 bicycle +Iyk9-k1RP-M_0 car +Iyk9-k1RP-M_1 car +Iyk9-k1RP-M_2 car +Iys_rL0bPcc_4 boat +Iy4SrujSLuQ_1 elephant +Iy4SrujSLuQ_5 elephant +Iy4SrujSLuQ_6 elephant +Iy4SrujSLuQ_3 elephant +IzC8vjFriRE_0 horse +IzPS29ghTxo_0 knife +IzQjjBqimYw_5 elephant +IzQjjBqimYw_10 elephant +IzQjjBqimYw_11 elephant +IzQjjBqimYw_0 elephant +IzQjjBqimYw_1 elephant +IzQjjBqimYw_2 elephant +IzQjjBqimYw_3 elephant +IzQjjBqimYw_4 elephant +IzQjjBqimYw_6 elephant +IzQjjBqimYw_7 elephant +IzQjjBqimYw_9 elephant +Iz4_9EtiVXc_0 motorcycle +Iz8cco4VLow_0 cow +Iz8gKIZcfqo_0 bear +Iz8uzZuBiXs_0 bird +I0eY-kKi2FM_0 umbrella +I0iEaW1Qg_o_1 bear +I0oVkr613Rw_0 skateboard +I0voLEPKkG8_0 horse +I0voLEPKkG8_1 horse +I0voLEPKkG8_2 horse +I0voLEPKkG8_3 horse +I0voLEPKkG8_4 horse +hAplCSSZqAs_0 airplane +hAplCSSZqAs_1 airplane +hAteY2rkmVg_8 bus +hAteY2rkmVg_1 bus +hAuFEp75jVo_0 train +hAzefhyFMN4_0 truck +hAzsdnh5Iq8_0 elephant +hA_YzyjSVZM_0 bicycle +hBDc0K6CvHg_0 bus +hBDvdp2RCCw_1 airplane +hBDvdp2RCCw_2 airplane +hBDvdp2RCCw_3 airplane +hBDvdp2RCCw_5 airplane +hBDvdp2RCCw_7 airplane +hBKuHV_S8lM_0 skateboard +hBOhA_sljfE_0 umbrella +hBcYx5Uc-vw_0 car +hBcZZeXsCaw_0 bicycle +hBgxILtRUIc_0 cat +hB23PCerELA_0 skateboard +hB-M9w3C_Tw_0 boat +hCB731pKdcg_1 train +hChqLLLAmF4_1 bird +hChqLLLAmF4_0 bird +hCkn4pJxSkk_0 bear +hCrrYhe3x9Q_0 train +hCsCAXkiQ4Y_2 train +hCynNRrrTKI_0 cow +hC5Wac-AzgM_1 elephant +hC5Wac-AzgM_2 elephant +hC5Wac-AzgM_3 elephant +hC5augWtBcQ_1 bicycle +hDAv3aPvZjc_1 truck +hDLAKS4hCfc_0 car +hDM4sCvlRoA_1 airplane +hDVx_yYysaA_0 cow +hDXpSU7bq44_0 bicycle +hDYV-Vz3xwA_1 dog +hEAQZIsaIew_1 train +hERCXzHI2nA_1 elephant +hERyFpl4aDk_0 dog +hEWJZ4dCcIY_2 cow +hEZt4InN7Eo_0 elephant +hEZt4InN7Eo_1 elephant +hEZt4InN7Eo_2 elephant +hEdpC8HEa-A_0 motorcycle +hE04tUrJzXo_0 truck +hE7N0N5vik0_0 bird +hE7N0N5vik0_1 bird +hE-VIrAVcBA_2 bus +hFFrC0_rJYA_0 airplane +hFTTcrUxPeg_0 cow +hFTTcrUxPeg_3 cow +hFdi9yxVkys_0 motorcycle +hFdi9yxVkys_1 motorcycle +hFixbos35O4_0 truck +hFnKIVp-Dcc_0 cow +hFnKIVp-Dcc_1 cow +hFzR4bgxihU_0 bicycle +hGH72iljdzU_0 bear +hGRdOlSIQRU_1 train +hGRdOlSIQRU_2 train +hGRdOlSIQRU_0 train +hGiCVP3Z8l0_0 umbrella +hG6vW_xUZgA_0 train +hG6vW_xUZgA_1 train +hG959XPTh_8_0 bear +hG-quo0MZM8_0 elephant +hG-quo0MZM8_1 elephant +hHEIEEdrXYE_0 cow +hHIyy4Vda6M_0 cat +hHjzciM78AA_0 cow +hHtOM5_wiWM_0 truck +hHtqPiAg32Q_0 umbrella +hH_akvS98jo_0 skateboard +hIH6LuoXbpE_0 cat +hIXTbG6ho4E_0 person +hIXTbG6ho4E_1 person +hIXTbG6ho4E_2 person +hIz3ONvP-Bo_0 zebra +hI3P4BxIr-o_0 bear +hI3eGFKYRuc_1 horse +hJP8qg-kSZA_0 cow +hJTl4NJ0qIs_0 person +hJhBQsD0_hw_0 bus +hJkgoq_T4Pk_0 train +hJmxsYAKHdc_0 umbrella +hJtloiw4D-M_0 car +hJ_uvoDrzkI_0 giraffe +hKJQH8VbGk4_0 airplane +hKJQH8VbGk4_1 airplane +hKYJZqP-44M_0 airplane +hKYJZqP-44M_1 airplane +hKgtNPTirdc_2 elephant +hKgtNPTirdc_3 elephant +hKlKPyuUYps_0 bus +hKtHZYDaoXA_1 train +hKtHZYDaoXA_2 train +hKtHZYDaoXA_3 train +hKtHZYDaoXA_0 train +hK6w0B1cu-I_0 cow +hK7VoN3cI74_0 cat +hLGnjjoilbo_0 skateboard +hLHaPstpghQ_0 motorcycle +hLKzDOp8XLc_1 zebra +hLNcuJAwfDo_0 cow +hLVZsqfElxI_0 dog +hLX1LeVKgi8_0 cat +hLjDO37EQ60_2 dog +hLjDO37EQ60_1 dog +hLscdjfkeho_0 cow +hLte0Y4VWR0_0 knife +hL_QAgWBkJ4_0 cow +hL_noZA6D8E_0 truck +hMGVdq71lME_1 horse +hMLkMrqUtA0_0 horse +hMRIDt-1dY4_0 train +hMgp2oyTB80_0 cow +hMjke9g_Ysw_0 horse +hMuO0MHPIOQ_0 elephant +hMuO0MHPIOQ_1 elephant +hMusKbJqZDY_0 skateboard +hNHGh8N1XGg_0 knife +hN_-56Oxma0_0 dog +hOJJ65CVNuM_0 bird +hOOwQSSrFVc_1 cow +hOid-qo2Ozw_0 cow +hOky3qIMxRY_0 skateboard +hOpJoO7UciM_1 bicycle +hOrAXl-jATo_0 airplane +hOxMkI1d3oc_1 airplane +hOxMkI1d3oc_3 airplane +hOxMkI1d3oc_4 airplane +hOxMkI1d3oc_6 airplane +hOxMkI1d3oc_7 airplane +hOxMkI1d3oc_9 airplane +hPEsz5u87CI_0 bus +hPIDFIwLI8c_0 car +hPWhKQfDoXg_0 airplane +hPWhKQfDoXg_1 airplane +hPW2NpCU668_2 elephant +hPW2NpCU668_0 elephant +hPW2NpCU668_3 elephant +hPW2NpCU668_5 elephant +hPW2NpCU668_6 elephant +hPW2NpCU668_7 elephant +hPW2NpCU668_8 elephant +hPa5hUze91s_0 elephant +hPa5hUze91s_1 elephant +hPb_Rq2yKRA_0 cow +hPo5Wd-otbY_0 dog +I0yz1LGLl08_0 elephant +I1Ejpa2UWSk_1 bird +I1Pdo-p11tI_0 motorcycle +I1Quuhyu2UI_1 motorcycle +I1YfOiyQW_8_0 truck +I1wfW86V8So_0 dog +I1wfW86V8So_2 dog +I14JWDgkllE_0 truck +I14JWDgkllE_1 truck +I19kQsgjFRA_0 bicycle +I2IfiPw2aKE_0 elephant +I2OQlELjXvU_1 truck +I2OQlELjXvU_2 truck +I2OQlELjXvU_3 truck +I2hmFe1pYes_0 horse +I2o_4OyrJlI_0 horse +I3DSZk-7nG8_0 train +I3JCCqGY3c8_0 truck +I3KJj6GQ5QE_0 cat +I3OWw4AK0MI_0 dog +I330kG5lk5A_0 knife +I3-xBh-IrIo_0 airplane +I3_lU2I_AaU_0 bicycle +I4BMptNse7c_1 train +I4BMptNse7c_0 train +I4CMNv-VRDo_0 bird +I4Gi7kq5XAs_0 horse +I4HuQ8DDxoM_0 skateboard +I4WNAfBvm5E_1 skateboard +I4z-3IGHMW4_0 dog +I5KNdt1NT8g_0 skateboard +I5QNP3-QHLw_0 cow +I5SA8N1JKwM_0 cat +I5WNgPfoaZQ_2 motorcycle +I5pU9zWz4Fg_0 motorcycle +I6fJWB7DpAM_0 bus +I6oT6dLeq7A_0 motorcycle +I6wEvIOC-Pk_0 train +I7GbkWE2A0M_0 bus +I7aUrrDieE4_0 cow +I7bKlZxD6Fs_0 bicycle +I7xOURJQUps_0 train +I7xOURJQUps_1 train +I7x_od8h4iw_0 cow +I7-iLB-NVGg_0 dog +I8FoWQrnHGY_0 bird +I8Ms0rXjfXU_0 skateboard +I8Ms0rXjfXU_1 skateboard +I8Ms0rXjfXU_2 skateboard +I8Qx-qd0eLg_0 boat +I8Qx-qd0eLg_1 boat +I8UlumMtAG8_0 horse +I8Vr0DzHV9U_0 cow +I8rww3UUjYI_0 person +I9AGRokco_M_0 train +I9FPkgdc-5E_1 cow +I9XcFcBW-HM_0 motorcycle +I9oAq_x5pqg_0 bus +I9yrFs_JpWc_1 skateboard +I94qZUJmKP8_1 bicycle +I94qZUJmKP8_2 bicycle +I-SRTsDkhLM_0 cow +I-TshjRdh74_1 knife +I-blRAakQjM_0 boat +I-h3cTJlsRc_0 dog +I-nb60BTO_g_0 train +I-raj-aLy8s_8 horse +I-ywD5MDZZ4_3 cow +I-ywD5MDZZ4_4 cow +I_LhSNsRHMs_0 elephant +I_kI39ZHymk_0 horse +JAEzOCIew2Q_0 airplane +JAEzOCIew2Q_1 airplane +JAb3p7VYLzI_0 bear +JAb3p7VYLzI_1 bear +JAcHxxzG1vA_0 motorcycle +JAf3nC1hYS4_0 dog +JAp2_UJfFao_0 person +JAqAH7n-3lA_0 bus +JAzD-VzDxfc_2 bicycle +JAzD-VzDxfc_4 bicycle +JAzD-VzDxfc_5 bicycle +JAzD-VzDxfc_8 bicycle +JAzD-VzDxfc_11 bicycle +JAzD-VzDxfc_13 bicycle +JAzD-VzDxfc_17 bicycle +JAzD-VzDxfc_18 bicycle +JAzD-VzDxfc_19 bicycle +JA2PLZmRABc_1 umbrella +JBGewEMeWIs_1 dog +JBGewEMeWIs_5 dog +JBKG_tl08RU_0 cow +JBMhOrDLcho_0 cat +JBYr3VbJLoM_0 person +JBkymGnh5mA_1 bicycle +JBkymGnh5mA_2 bicycle +JBkymGnh5mA_3 bicycle +JBkymGnh5mA_4 bicycle +JBlCFCV4sdw_0 horse +JBlCFCV4sdw_1 horse +JBxFgwl0To8_0 cow +JB0SELYSRXA_1 bear +JB-hzl-gILo_2 truck +JCIJbwBevro_2 bird +JCSRBZQpYCw_1 bear +JCSRBZQpYCw_5 bear +JCTYAwT6ppk_0 motorcycle +JCTYAwT6ppk_1 motorcycle +JCTYAwT6ppk_2 motorcycle +JCciDn0O6X0_0 airplane +JChsfz-p2KI_0 cat +JCuE5X37xIE_3 boat +JCuE5X37xIE_4 boat +JDJWapHD_kM_0 boat +hP8Jfo1RaSk_0 elephant +hP8Jfo1RaSk_1 elephant +hP8Jfo1RaSk_2 elephant +hQWcyTkfPeU_1 dog +hQZDg__nxQA_4 bear +hQZ5lNlAXBI_0 truck +hQe3_1EvqIY_0 cow +hQfYabI9_ec_0 bird +hQkbXGwGwyg_0 skateboard +hQve0ugvy6s_0 motorcycle +hRAbtgVJiWI_0 bear +hRJ0Qk_qdAY_0 airplane +hRS45wmOq9c_0 elephant +hSR-ZVA-vMU_0 dog +hSWyYOzvh0g_0 dog +hSf3uEm8r9M_0 bus +hShwtMLieCc_0 boat +hSiozs1nz7o_1 motorcycle +hSzgOCvRfq4_0 bear +hS-h8AUEibc_0 cow +hS-h8AUEibc_1 cow +hS-h8AUEibc_2 cow +hTHBMsKC5ZI_0 cat +hTZr7OF0VuY_5 dog +hUJMSp4rMrc_0 train +hU0EbblT2vQ_2 airplane +hU388mZGPGg_0 cat +hU9B31AVZNg_0 bus +hVJjOdU5-yQ_0 car +hVNKN_qFEUA_0 bicycle +hVOImOLBY1g_0 skateboard +hVdb-Q3aJ9E_0 dog +hVhNOzZA40E_0 cat +hVnD8rlLRgM_0 bird +hVq6NOrBwlM_1 motorcycle +hVsAAQqAHyI_1 skateboard +hWHUct-PLfY_1 motorcycle +hWHUct-PLfY_0 motorcycle +hWNyVxx4a94_0 cat +hWn0ddeHF0I_2 zebra +hXAQH1xVKB8_0 cow +hXWQ710-JZQ_0 motorcycle +hXagj4A6N-s_1 elephant +hXbMo03RQWk_0 train +hXflTk4WVAA_1 bear +hXf7dimd2bo_2 cat +hXhtGcCMf5Q_0 airplane +hXsCNMb3eTc_0 bicycle +hYD7HKMKa3k_0 elephant +hYFW5XhMxyg_1 knife +hYIPy3eyC9k_0 cat +hYQBaiC8d6Y_0 horse +hYTIV5X87S4_0 horse +hYgzs0gDiiU_0 elephant +hYkPL7spYMo_1 elephant +hYlmhAuVVh8_0 bird +hYtFyx0799o_0 boat +hY0vkwEtjLM_1 bear +hZAOhuPJTho_0 horse +hZAXlQqCmCI_2 train +hZCGOP3PHOM_2 knife +hZHjTTvcQ88_2 bicycle +hZOhuOcxTP8_0 skateboard +hZPYHGzIYh0_0 cow +hZeekc0i_b8_0 motorcycle +hZiXqP-WaQk_3 bird +hZiXqP-WaQk_0 bird +hZiXqP-WaQk_1 bird +hZiXqP-WaQk_2 bird +hZygBhv-nDg_0 motorcycle +haC0TZbvBEU_0 cat +haMtzn-TnOQ_0 boat +haTl-PeSssc_0 dog +hakWXvIYvzo_1 dog +hanKUxPHFbA_1 car +hanKUxPHFbA_0 car +haxabA27SnU_0 horse +ha3C2hPzaiw_0 dog +ha8hX-68TqI_0 bear +ha8hX-68TqI_2 bear +hbKjt5OBryI_0 truck +hbKjt5OBryI_2 truck +hbKjt5OBryI_1 truck +hbfiyMHycSs_3 knife +hbvJ3t9lpUo_0 truck +hcXtsyICD30_1 skateboard +hcpMT5qGQ0U_0 bus +hdZkNo0t6wg_0 boat +hdbKePdCemQ_0 cow +hdqiOcfXejc_1 zebra +hdwZF4C-vYs_0 cow +hd_yXL53Z9E_0 elephant +heQRV9di86s_0 train +heTgOW6o1ho_0 zebra +hedgcDGNngs_0 bicycle +heucaATRtbI_0 cat +he_j-GZdCNs_0 person +hfCbKe627p0_0 airplane +hfEl_mnX9X4_0 skateboard +hfGEkaEADUw_0 motorcycle +hfGEkaEADUw_1 motorcycle +hfGEkaEADUw_2 motorcycle +hfcKFLBuJ_g_1 dog +JDcAM9ieTp8_0 bicycle +JDe9ulv2Nmo_0 elephant +JD_njBej6V0_0 truck +JD_njBej6V0_2 truck +JEU2rZzAxRU_0 skateboard +JEbIHUJTFsM_0 airplane +JEdl8GROiQM_0 truck +JExlAUEYZwc_0 cat +JE8SV6FOlC0_0 truck +JFH3n9kI6aA_0 boat +JFO_Qz1y8-s_4 elephant +JFQ_GztsLs0_0 cow +JFQ_GztsLs0_3 cow +JFZG_ebR2mk_0 elephant +JFZpmduYfv4_0 motorcycle +JFfYNQ2FmHU_0 cow +JFk4Qyn58CY_0 train +JFvQ7wc6c0o_0 airplane +JGDf9kSc-v4_13 dog +JGDf9kSc-v4_15 dog +JGDf9kSc-v4_17 dog +JGDf9kSc-v4_19 dog +JGDf9kSc-v4_1 dog +JGDf9kSc-v4_2 dog +JGDf9kSc-v4_6 dog +JGGj1z6Kujc_0 dog +JGGj1z6Kujc_1 dog +JGMfEFj5PVM_1 truck +JGWBjvjqVhw_4 skateboard +JGanm9yGTJk_0 truck +JGanm9yGTJk_1 truck +JGanm9yGTJk_2 truck +JGmHpQtJzic_0 horse +JGn6Ifa5bWI_0 bird +JG0B4rV4KEI_0 dog +JG6H3R9rErg_8 airplane +JG6H3R9rErg_0 airplane +JG6H3R9rErg_1 airplane +JG6H3R9rErg_2 airplane +JG6H3R9rErg_3 airplane +JG6H3R9rErg_4 airplane +JG6H3R9rErg_5 airplane +JG6H3R9rErg_7 airplane +JG6sceNvlnI_3 boat +JG6sceNvlnI_2 boat +JG872iaucFc_0 umbrella +JHBhDpq4HNs_0 cat +JHBtawKoltc_0 car +JHTt9PSzrhU_0 elephant +JHb8IVsjgMs_1 bus +JHdc9jvf4qA_0 motorcycle +JHmG34eTWow_0 train +JHr57YE7IRs_1 airplane +JHy85i0So5U_1 dog +JH0Jzb0wOXw_3 elephant +JH0Jzb0wOXw_4 elephant +JH0Jzb0wOXw_2 elephant +JISA50Bfj4U_0 boat +JIamGji7w9U_3 bird +JIiA0pG-MKk_0 skateboard +JI6MyG7aTvM_0 bird +JJSp2fu3lk8_4 dog +JJSp2fu3lk8_3 dog +JJq7YAYUado_0 umbrella +JJx7GdAuDQY_0 skateboard +JJyJR7TlQ7o_0 motorcycle +JJ0Ja1ju2ec_1 horse +JJ0NBly53IU_0 cat +JJ8Vv2hiCCA_0 cow +JJ8Vv2hiCCA_1 cow +JKBJuICyV50_1 train +JKBJuICyV50_0 train +JKCFS8k_Qis_3 bus +JKGV5hbm5g8_0 skateboard +JKJQPHspLBs_0 bird +JKJQPHspLBs_1 bird +JKNRKGSvtsQ_0 elephant +JKYPluJPL7c_0 dog +JKa7rPKrAwY_0 train +JKgPYc0K_hI_4 car +JKgPYc0K_hI_1 car +JKuhG9WLM2k_0 airplane +JK42K36SYLs_0 bird +JLE_jNuNoA0_0 cow +JLHP-3UxtMU_0 boat +JLb2dnuNhqs_0 bus +JLoS7DZH_ik_2 airplane +JLoS7DZH_ik_1 airplane +JLsEcZUU7FM_2 truck +JL64rU6Jvmw_1 giraffe +JL71b_9Cy9I_1 umbrella +JMDFSes_w0E_0 cow +JMMmrEdfRbk_0 boat +JMPKtdq9b0Y_0 train +JMR4IvE2sDo_0 bus +JMaahZTxRLk_6 boat +JMgbgNPBIJI_0 bird +JMnp6FLLbtw_0 horse +JMnp6FLLbtw_4 horse +JM1jSU4FEPw_2 airplane +JM4yr2pj-zg_0 airplane +JNDZBgXZBU8_0 knife +JNDZBgXZBU8_3 knife +JNDdt_ZPl1s_3 elephant +JNNbk6jVfB4_0 cat +JNZDx8Ro_mM_0 truck +JNe7ZednqQc_2 horse +JNkz_3Qtdfc_0 horse +JNnnm9ixKrM_3 car +JNnnm9ixKrM_4 car +JNnnm9ixKrM_5 car +JNpuJeqVFxk_0 motorcycle +JONF8-3gEoY_0 giraffe +JONF8-3gEoY_1 giraffe +JONF8-3gEoY_2 giraffe +JObYghNlZas_6 train +JObYghNlZas_7 train +JOmeD6G33Dc_1 horse +JOoNVY1C6qI_0 train +JOoNVY1C6qI_2 train +JOqHfu-WVu8_2 horse +JOuB1UkVvKI_0 airplane +JOue8LphKc4_0 truck +JOztmtwKz-k_0 cow +JPAjGBsi-rE_0 bird +JPMFXg-BXDE_2 car +JPTFJk9f2nM_0 dog +JPevMGnX92M_0 airplane +JPiSmPAIpOI_0 knife +JPlZOEew4wg_0 elephant +JPuDmwlAXzI_0 skateboard +JPwUpTvlZDA_0 person +JPwUpTvlZDA_3 horse +JPw4R6t-0j4_1 bird +JQDX7gVR0qM_2 knife +JQDX7gVR0qM_0 knife +JQKDDMvCtt8_1 horse +JQNsIqNLn40_0 truck +JQRxu6RVGMg_0 car +hfwhbInEJAk_3 train +hfwhbInEJAk_2 train +hgFfz_RTcx4_0 truck +hgFfz_RTcx4_1 truck +hgxvhMjH_68_0 motorcycle +hg6Z6JIwRMU_0 elephant +hg6Z6JIwRMU_1 elephant +hhM2TSF2GhA_1 horse +hhNlkY3SS6w_1 bus +hhYOJb0v5Yw_0 cat +hhlt4dfZmFE_0 horse +hhyzKC353Jo_1 car +hiJ-OdPj_8c_0 bird +hiPDdAi1Qs8_0 motorcycle +hiUH1zOfsfo_0 cat +hiZLv2E5zI8_0 elephant +hjBLAHakI9c_0 boat +hjRlztwK-vg_2 bicycle +hjhbMbrRUWI_0 truck +hj2P25O-nIk_0 skateboard +hkR10EU8YPI_0 train +hk0cDE4A_b0_0 boat +hk7M3PGcOhw_0 train +hk-IVoljyKE_0 elephant +hk-IVoljyKE_1 elephant +hlFPCpe8Akk_0 airplane +hlLrYrrOcY4_0 dog +hlNOQO4BIHg_0 train +hlnNVsSGjxA_3 car +hlnNVsSGjxA_1 car +hl4yLAJiWjQ_0 elephant +hl7z1gnPPW0_0 knife +hl_YHwW5mrM_1 bird +hl_YHwW5mrM_0 bird +hmThCl2HK8E_0 skateboard +hmThCl2HK8E_1 skateboard +hmdH0Olcbx4_0 bicycle +hm98pilx9dE_5 horse +hm98pilx9dE_1 horse +hm98pilx9dE_2 horse +hm98pilx9dE_3 horse +hm98pilx9dE_4 horse +hnJ2wDmXD6w_1 bicycle +hnbZY12P-7g_1 elephant +hne72NMSPuc_0 bird +hnffUBbBFoQ_1 horse +hnrSBT9miTE_1 bird +hnvbE27mWwI_2 train +hnvbE27mWwI_0 train +hn19XaR_wIs_0 knife +hn7ollCkAy4_5 bicycle +hn-1W1O8kZs_0 boat +hoLnPrkJ6sE_0 horse +hoLnPrkJ6sE_3 horse +hoNPAcq_5Ac_1 bird +hoNPAcq_5Ac_0 bird +hoYDTU50MTk_0 cow +hoe88GhFhq0_0 truck +homQXuwbe04_0 cow +homx5sSuNr4_2 bear +hoozxxjd57c_1 bus +hotrXXenVAk_0 cat +ho5YZstr1XE_1 cow +ho7yo7nJk3o_1 elephant +hpG2eG_hduA_0 motorcycle +hpRxBuFhZ4M_0 train +hpRxBuFhZ4M_1 train +hpRxBuFhZ4M_2 train +hpRxBuFhZ4M_4 train +hpkXlhfYZfw_2 motorcycle +hpkXlhfYZfw_1 motorcycle +hpmC3OjLnZM_2 boat +hpmC3OjLnZM_0 boat +hpo-lwBTbFw_1 dog +hp3aTxzS9ms_0 skateboard +hqGhmP1u07Y_0 elephant +hqoQm68UbGo_3 airplane +hqoQm68UbGo_2 airplane +hqsoIR9v8IY_0 motorcycle +hq7f1_o4eFg_0 airplane +hrLkVz3_xGw_2 bus +hrW-pkK9osE_2 bicycle +hrW-pkK9osE_3 bicycle +hrgh69NXZqw_0 cow +hrj6I8n8nAc_0 bicycle +hrj6I8n8nAc_1 bicycle +hrrpTPwLZHA_0 bird +hrtiCeqnqLg_0 cow +hrziTee4b2c_0 airplane +hr5Q08OMeAU_0 train +hr7wUBMikww_0 zebra +hr7wUBMikww_1 zebra +hsMptx7tOLo_0 elephant +hsMptx7tOLo_1 elephant +hsMptx7tOLo_2 elephant +hsM1eKbrqLs_0 cat +hsPK4wlNtI8_0 cow +hsYL355Fzio_0 truck +hsfS5oT1y5M_2 boat +hskEM8GUmDE_2 train +hsmxUKxzapo_2 skateboard +hsmxUKxzapo_0 skateboard +hsyCfsJx7DI_2 skateboard +hsyCfsJx7DI_1 skateboard +hs2foQ_Xo8A_0 skateboard +hs-OEgnsLZs_0 train +htDilkoPA-M_0 airplane +htSBZwTBX98_0 horse +hteze9Fz1dc_0 knife +htkybhLm0uk_0 umbrella +htwBHgatd9c_2 horse +htwBHgatd9c_3 horse +htwBHgatd9c_0 horse +huCxpuVT4GI_0 dog +huDCqh-KRy4_8 bicycle +huDCqh-KRy4_2 bicycle +huDCqh-KRy4_3 bicycle +huDCqh-KRy4_4 bicycle +JQnf7j7HpKY_0 cow +JQpJv-SOMS0_0 dog +JQ9LtiJVsd8_0 cat +JQ_dyIlBnGM_0 cow +JQ_6xcOuEfU_4 cow +JQ_6xcOuEfU_1 cow +JRA3LCwRGu0_0 knife +JRBLFsevgg0_0 train +JRJjI6mFa6s_1 skateboard +JRJnSf2qOXA_0 airplane +JRT0FH2KEsc_0 cow +JRcTFvzRC10_0 bird +JRcTFvzRC10_1 bird +JRsNcoTJJjE_0 cat +JRsn1likB7c_0 boat +JRyc_lxMJzs_0 skateboard +JR6JAx7xdGg_0 cat +JSA0JWvQbJg_2 train +JSdEdTcUHHI_0 knife +JSfXE4ExZ1U_0 bird +JSfXE4ExZ1U_2 bird +JSs6Sa8zR6c_0 horse +JS2cbpFwahY_0 skateboard +JTE0ABGzb30_1 skateboard +JTE0ABGzb30_2 skateboard +JTJgZcBM93k_1 knife +JTa9HkbXfSw_0 cow +JThBohLxRSc_0 cow +JTi4Oy6v9mM_1 horse +JTi4Oy6v9mM_2 horse +JTtjfwrK4Ls_0 dog +JT5zUQio3B0_0 bus +JUHMTmjUswE_0 knife +JUVHXeFTe3Q_0 horse +JUVHXeFTe3Q_3 horse +JUbPqBVbGQQ_1 truck +JUpxTW6_BAI_0 cow +JUtd4FLjXio_0 horse +JU1N1nqXjII_0 train +JVKkxo7adX8_1 knife +JVQ6Gx2hGxs_0 airplane +JVTIzApj2UA_0 giraffe +JVVtcOIACz0_0 giraffe +JVg62b0T408_2 train +JVg62b0T408_0 train +JV2A3zWMRj8_0 umbrella +JV3Tbp30yp4_2 motorcycle +JV3Tbp30yp4_1 motorcycle +JV3Tbp30yp4_3 motorcycle +JV-OfjEsQDs_0 umbrella +JWKZlCk_cts_0 train +JWXSXvHgoo4_0 car +JXEyPb4Nzro_0 skateboard +JXP_CNg8grg_0 cat +JXi5KrVPz0M_1 bird +JXj_lj5QUp8_0 person +JXmBBTT0YXQ_0 cat +JXobiO1_7Ts_0 train +JXwfPpl53Fs_0 dog +JYYAwimr2XQ_0 truck +JYi7bWDL5os_0 person +JYsWtLH_mjM_0 bus +JYsWtLH_mjM_1 bus +JYsWtLH_mjM_2 bus +JYvBo5FwjSg_0 elephant +JYvBo5FwjSg_2 elephant +JY2d1dohCDs_0 elephant +JY3rSX-blgA_0 cow +JZBJ35lKlXw_0 truck +JZOZuTiifHM_2 boat +JZXr-dGLkpU_0 boat +JZcy1T--d4M_0 skateboard +JZ_ri3awsso_0 cat +JaI9UR2n7ZE_0 horse +JaLswoS3xO8_0 knife +Jaumrq8clZY_0 truck +Ja9rAQpB2_M_0 cat +Ja_ofQ1ynAc_1 airplane +Ja_ofQ1ynAc_2 airplane +Ja_ofQ1ynAc_4 airplane +JbA11YWHpW0_1 skateboard +JbBxvvoOvpg_0 bear +JbK17NE3dvk_1 train +JbK17NE3dvk_0 train +JbK17NE3dvk_2 train +JbK17NE3dvk_3 train +JbPP4AwiNEc_0 cat +JbSkoHG6Vq4_0 airplane +Jbfzd9wIyi4_0 cat +Jbw0KUJqWpE_0 train +Jb03yqEB5WI_1 bus +Jb03yqEB5WI_4 bus +Jb5lFDvKqXA_0 bus +Jb6FIuynIuw_0 bicycle +Jb-q7z_Mygg_0 truck +JcJKjdDKuc4_0 train +JcRvhoBwgNg_0 cow +JcU-cdQmKV8_3 bus +JcU-cdQmKV8_1 bus +JcixSQRUnY4_1 elephant +JcmTLrQZ7sE_1 cow +JcmTLrQZ7sE_0 cow +Jcwl0kCsUTw_0 umbrella +Jc5PS0Ejejw_1 elephant +Jc8eE1ayaX8_0 cow +Jc9PdqC1rpg_0 train +JdUehtxAfys_1 bicycle +JdUehtxAfys_7 bicycle +JdwSAFvKg74_0 car +JeAykU3MiKg_2 airplane +JeET8zb_gPQ_4 knife +JeNu9WVQOHY_4 bicycle +JeNu9WVQOHY_1 bicycle +JeNu9WVQOHY_7 bicycle +JeYCd0VP5EY_0 horse +Jeb4SSyyZD8_0 dog +Je_fuH6-34I_0 skateboard +hujF3CEgAXI_0 skateboard +hulFEZUNu10_0 train +hutTW7ORN8g_0 bicycle +hutTW7ORN8g_1 bicycle +huy9NXPynro_0 cat +hu6nRmzUcAw_0 train +hvWHb1kiV5g_0 dog +hvWs1FhyQlw_0 umbrella +hvhWoRQZMUU_0 cat +hvjNVTle8bQ_6 airplane +hvjNVTle8bQ_0 airplane +hvjNVTle8bQ_1 airplane +hvjNVTle8bQ_2 airplane +hvjNVTle8bQ_3 airplane +hvjNVTle8bQ_4 airplane +hvjNVTle8bQ_5 airplane +hvkIo-dZUUY_1 bird +hvlXyPikLUY_0 bus +hv49V2RzgHw_0 horse +hv7b1I-cRvI_0 truck +hwOL2G-Lo54_0 umbrella +hwPkgOB1mEU_0 cow +hwTVAkfjjCY_0 cat +hwikEC2Jc0c_1 horse +hxC7dFDqfXo_0 car +hxUn2A7Ko2g_0 cow +hyMlfx_ZEeI_0 train +hyMlfx_ZEeI_1 train +hyX6rKHZcLs_0 person +hyb_qBoKG9Y_0 train +hyjjdUcyanE_1 dog +hyj8BJ_PMgQ_2 elephant +hyrBL1wMHts_1 truck +hy9Ml-3zAtM_2 knife +hy9jrpamopE_0 umbrella +hzBqPVIC7IQ_0 train +hzUTA7mGyKE_0 bicycle +hzeHyMcUmO4_0 motorcycle +hzeHyMcUmO4_1 motorcycle +hzz9JBRYjFs_0 bicycle +hzz9JBRYjFs_1 bicycle +hz5anqtArdI_0 train +hz5anqtArdI_1 train +hz7PXI6R6DI_0 train +h0IiMbTwz1Q_0 truck +h0IiMbTwz1Q_1 truck +h0hIpf9O0Vg_0 bus +h1MxYGy1SBc_0 dog +h1XtVmXF7CQ_1 elephant +h19z0Ap_5Pc_0 bus +h2R46pcCEVg_0 cow +h2SNrfK0yQQ_2 bus +h2X0to3hDA4_0 bicycle +h2b9t_pnnNA_0 cow +h22FyeO_lyE_0 umbrella +h23R8X1WKjU_1 horse +h24uuiI34yI_0 skateboard +h27DK_oMwYY_0 dog +h3FnAKBB9Xc_1 elephant +h3Lz61ficjc_2 motorcycle +h3aEao1bRIY_0 cat +h3aZGHTjBwc_0 elephant +h3o5ZykGOxI_4 elephant +h3o5ZykGOxI_2 elephant +h3o5ZykGOxI_3 elephant +h3qOwaRYAi8_1 bear +h3uPELFKoCc_3 knife +h3uR99WtOh4_4 bear +h3_cWsxi4Qw_1 skateboard +h4CySJb83XI_2 elephant +h4KXG16xA_Y_0 dog +h4LE2YVwHL0_0 motorcycle +h4jU8ZrDZd8_0 skateboard +h4kmvN6NmyA_3 train +h4kmvN6NmyA_2 train +h4wsDcj7kcE_0 cow +h45-zE2gKFA_2 person +h45-zE2gKFA_3 elephant +h47dExP6oXQ_0 elephant +h5C2RKknWfg_3 bicycle +h5C2RKknWfg_5 bicycle +h5C2RKknWfg_6 bicycle +h5KSLdybLIE_5 bicycle +h5KSLdybLIE_1 bicycle +h5KSLdybLIE_3 bicycle +h5dsU3N4joc_0 cow +h5hkvWWp7Qg_0 knife +h55Exp2rpSM_0 knife +h6FtP-5VnYM_2 cow +h6FtP-5VnYM_1 cow +h6McnZDPX3I_12 elephant +h6McnZDPX3I_1 elephant +h6McnZDPX3I_2 elephant +h6McnZDPX3I_6 elephant +h6McnZDPX3I_7 elephant +h6McnZDPX3I_9 elephant +h6McnZDPX3I_10 elephant +h6Mvzt5e_eE_0 horse +h6jGPQLkE48_0 person +h6ztcoDHYaY_0 cat +h62bO9Mfl9Y_0 cat +h64dmoPNWw0_0 car +h7OZUnDKWbA_0 truck +h7cXxMNxlcY_0 horse +h7uwd7opKjI_0 motorcycle +h7uwd7opKjI_1 motorcycle +h8BDqFH8e_w_0 train +h8BDqFH8e_w_1 train +h8BDqFH8e_w_2 train +h8EHrA_OM7c_0 person +h8LiHNo4904_4 airplane +h8LiHNo4904_5 airplane +h8LiHNo4904_6 airplane +Jfb3XGdt6VE_0 cat +JfdoYsRxF5k_2 knife +JfnHVMyUT0E_4 bicycle +JfqHeWyD5DQ_0 skateboard +JgLXpgcnjAA_0 cow +JgQbvDmM2Nk_0 bird +JggJWWHhlc4_0 umbrella +Jg8FXSKMvTQ_1 elephant +JhDNC6XRVG8_0 cow +JhDNC6XRVG8_1 cow +JhFvJHfP_NY_0 car +JhPLC0PS9I0_0 knife +Jh87zKRgN68_2 boat +JiMyZFGmGgM_0 dog +Jifa2spqYV8_0 airplane +JijtEhm-Dk8_0 bus +JikSLpJ2xKw_0 cow +JinIHVE4_MI_1 bear +JioS9DumyIM_1 car +Jixd9HKGzWA_0 train +Ji6bpPIPScI_0 umbrella +JjIvWQ-198c_0 knife +Jja500M50Yw_0 cow +Jja500M50Yw_1 cow +Jj4KvC3TXro_0 car +Jj4KvC3TXro_1 car +JkC1Udoysk8_1 cat +JkC4nV8LcTE_1 bicycle +JkH8ZtuvzDQ_0 dog +JkpQkpiRpVI_0 bird +JkzNUiOu1GI_0 bus +Jk28bpr063o_4 airplane +Jk28bpr063o_0 airplane +JlJQlaoy3ec_0 cat +JlrPaJIAP9k_1 horse +JluvPpeI2DY_0 train +JluvPpeI2DY_1 train +JlzsUphxgIY_0 truck +Jl1bEdoRG9I_0 cow +Jl6gTtZcQH0_3 horse +Jl6gTtZcQH0_0 horse +Jl6gTtZcQH0_2 horse +Jmblo1iMURo_0 motorcycle +JmdMhGsyZvk_0 boat +JmvNubLPYGo_0 bird +JmxixgKAKzc_0 truck +Jm0S-kE2yVc_0 truck +Jm3dtu8GTos_0 dog +JnAaSoaN3FI_4 boat +JnHUNCeHEDc_0 bird +JnMkFSGB6Vw_0 truck +JnXmNI53DWE_0 person +JnrrNu9udj0_0 bear +JnvIx5y-ijs_1 umbrella +Jnysuevt_4A_0 train +Jn1gvGhxU5U_0 bear +JocAgPv-ZJo_0 skateboard +JohmecnKktI_0 boat +JopGEGMo-DQ_0 dog +Jo50LBwjHIk_0 bicycle +Jo50LBwjHIk_2 bicycle +JpDOBaNBwkc_0 truck +JpFiApmpoHA_0 cow +JpL4Mv-uFi4_1 dog +JpRMc6MtCH8_0 truck +JpWh1yQThRo_0 train +JpZwF6hOCDg_1 truck +JpjAxQ_vsZw_7 bicycle +JpjAxQ_vsZw_1 bicycle +JpsOsewgXAg_1 bird +JpuCWzsE35k_1 bird +Jp0GKZ9vA0c_0 airplane +Jp1tvS1y4eI_0 boat +JqCaTxH5Ovk_0 motorcycle +JqC81ViWFeE_0 bear +JqPkaGRIz6c_2 elephant +JqT_Bx4fd1Q_0 cow +Jqauh1bsJy4_0 bear +Jq2ml2xQkHg_0 cat +Jq8D628IlV8_1 skateboard +Jq8D628IlV8_2 skateboard +Jq8OMvgG6wc_0 cow +JrAvVMnkKEo_3 bear +JrKxxhHGR7E_0 giraffe +JrZTstVj2wg_0 horse +JrbrXXDuxnc_0 horse +JrmyPAW-ItI_0 dog +JsNQXxg1PvE_0 person +JsPtP21j3f8_3 bear +JsPtP21j3f8_1 bear +JscnB4QfAhY_0 train +JsiSPt3nv1Y_0 cow +JsiSPt3nv1Y_2 cow +Js2ZDfWZWtc_0 cat +Js69iFgcic0_2 bus +JtMMD0aJnPI_0 train +JtMMD0aJnPI_1 train +JtQzeWNt8IA_0 umbrella +JtQzeWNt8IA_2 umbrella +Jtfp49L4LHg_0 train +Jt1zVsUQGhI_2 elephant +Jt1zVsUQGhI_3 elephant +Jt8ikZGW768_0 bicycle +JuGusvu6Z7o_0 skateboard +JuKJKHykMKM_0 horse +JuKgukJ63eM_4 skateboard +JuME8_jaVdE_2 car +JuME8_jaVdE_3 car +JuMNRsOc0nU_1 cat +JuMNRsOc0nU_0 cat +JuNubQtCvrU_0 bird +JuNubQtCvrU_1 bird +JuO7qvp2GBs_0 knife +JuXqLoCgK4o_0 bear +h8OcTR0Z4yo_1 airplane +h8OcTR0Z4yo_2 airplane +h8OiIYhIPTs_2 train +h8PJps4Sj1E_0 airplane +h8PmDAKiKVc_0 dog +h8oTFl4XWTc_0 bus +h8ysn_L9udY_0 train +h8ysn_L9udY_1 train +h9FtsOFR3p8_0 cat +h9veoEpzRH8_0 cow +h9w20ChZ_7Y_0 bicycle +h9w20ChZ_7Y_1 bicycle +h96rR-VkJZA_1 bear +h96rR-VkJZA_2 bear +h966cxQyjvc_1 airplane +h-PS5v6ZTBY_0 truck +h-VSmS49g5M_0 skateboard +h-npKkPbHSA_0 boat +h-qRpUteJV4_0 bird +h-vGllteZnI_0 train +h-1NdCqoxdU_1 bird +h-2DBPzbKUM_0 cow +h-27oWBBirE_0 dog +h-9WCj8sB6o_7 airplane +h-9WCj8sB6o_8 airplane +h-9WCj8sB6o_10 airplane +h-9WCj8sB6o_11 airplane +h-9WCj8sB6o_12 airplane +h-9WCj8sB6o_0 airplane +h-9WCj8sB6o_1 airplane +h-9WCj8sB6o_3 airplane +h-9WCj8sB6o_5 airplane +h_DH9wUjJZA_0 cow +h_Ey7gQJCSc_0 cow +h_KKvY3cK4o_0 cow +h_KKvY3cK4o_1 cow +h_XHdrNdD98_0 bus +h_tQ-ZVYe1M_0 bird +h_6GMOpsIOk_0 cat +iACKPRGNEOU_0 bus +iADpOEGdwQI_3 bird +iALubFRPBXQ_1 knife +iAL5KD5BwGQ_0 horse +iAuV09oxF_c_0 bus +iAzvkn-2C9s_4 horse +iA_tYzSGuVg_0 dog +iBDVD9if3VA_1 bear +iBDVD9if3VA_3 bear +iBDVD9if3VA_4 bear +iBF1Cfv7RpE_2 train +iBF1Cfv7RpE_3 train +iBO6oNBr4hM_2 train +iBmHl4vB2p8_0 boat +iBmHl4vB2p8_1 boat +iB2e_0wI6Cs_1 bird +iCA5LKIvUak_0 horse +iCUmfkHj2MM_0 elephant +iCWBysiT4fE_0 airplane +iCoklLBZGi0_0 truck +iC-r2odD6Ss_0 dog +iDBWSSj3Yag_0 bus +iDMMfw0zrvQ_0 cow +iDy5BzJGt50_0 skateboard +iD0ptJ7ucww_0 horse +iD0ptJ7ucww_2 horse +iECVUNZOPOM_0 cow +iEIRSDANY7g_0 bird +iEcsL-BdEp8_0 skateboard +iEeZD9_-mw4_1 train +iEe9Qed4A6w_0 elephant +iEfRHR6In04_1 dog +iEnwhpHkWPA_0 dog +iErN5WNQuZ8_1 bear +iFLG6c3XcMw_1 knife +iFgR4_OYpgU_0 boat +iFk_jNFfItI_0 car +iFsAXsW8t-8_1 bus +iFsAXsW8t-8_2 bus +iGB1OkMGELk_1 elephant +iGE04YY7P68_0 motorcycle +iGE8oPBzavo_0 airplane +iGKh6_bzEe8_9 airplane +iGKh6_bzEe8_5 airplane +iGWCy-zysHU_7 horse +iGWCy-zysHU_0 horse +iGWCy-zysHU_2 horse +iGWCy-zysHU_5 horse +iGf0rCvWhZE_1 bird +iGivgJkDWVo_0 elephant +iGivgJkDWVo_4 elephant +iGivgJkDWVo_5 elephant +iGivgJkDWVo_1 elephant +iGivgJkDWVo_2 elephant +iGmHR-MYdts_2 skateboard +iGtwAlGgpuQ_0 motorcycle +iG3IZAIpSos_0 cat +iG4w2A16Qy0_3 boat +iG4w2A16Qy0_0 boat +iG7OG-yAmkg_1 boat +iHNSjj9GO9k_0 horse +iHZNqzCjd7k_0 train +iHbirUiASog_0 skateboard +iH0SvXt_QEE_0 cow +iH9qrmQO5wg_3 horse +iH9qrmQO5wg_1 horse +iH_5naROy0I_0 motorcycle +iIYyUq4tPbc_0 cow +iIZw5oU3kz4_0 dog +iIa2i3Fyyp8_0 cat +iIgi9EuB83A_0 train +iIlu4DSMMwM_0 skateboard +iIoEhVh0sac_0 bird +iIoEhVh0sac_3 bird +iIoEhVh0sac_1 bird +iIwKnWnoXd0_0 skateboard +iI66ySv1M1E_0 bear +iJcYkYS6CgE_4 airplane +iJcYkYS6CgE_0 airplane +iJcYkYS6CgE_3 airplane +iJqRpAI5q0M_0 cow +iJ0Pe8-N6i4_0 bus +iJ5fEZLxnPw_0 knife +iJ5fEZLxnPw_2 knife +iKLuvvisn6Y_0 airplane +JvHU5ncnmtc_1 cow +Jvkp32eVZyc_0 cat +Jvm2k8MgJ5k_0 cat +Jv1ayezpka4_0 bird +Jv6b9zItltw_3 bird +Jv6b9zItltw_0 bird +JwNWcW7nUBE_0 elephant +JwNWcW7nUBE_2 elephant +JwaPyA7kWhc_0 cow +JwnMWPlx6KU_0 cow +Jw_nc2U4pKs_0 skateboard +JxKJB-QdFUA_1 umbrella +JxRKwF7KNOA_0 bird +JxSYbvgXcT8_0 car +JxVoSlh710g_2 bird +Jxc3ArJpyuY_0 motorcycle +Jxc3ArJpyuY_3 motorcycle +JxdIZhohCtg_0 cow +JxlB8wLncYc_0 elephant +JxzCLy2VyJA_0 skateboard +Jx03EEph0bw_1 truck +Jx2PgBxlrLY_3 airplane +Jx6xyX5sPMk_0 cat +JyKJFochwIQ_0 truck +JyLFLF4shyY_0 airplane +JyLqTlaGOww_0 knife +JyM0FDmoMyQ_0 airplane +JyePA4nzTx8_0 truck +JyhAOfW608o_0 cow +JyliijVyyUc_0 elephant +JyliijVyyUc_1 elephant +Jy1hmMPCNks_0 dog +Jy1hmMPCNks_1 dog +Jy37u1dt8Qc_0 dog +Jy_3PqINBss_1 bird +JzGkRevP9mU_1 truck +JzNvJYTN1Pw_1 bus +JzNvJYTN1Pw_0 bus +JzNvJYTN1Pw_2 bus +JzNvJYTN1Pw_4 bus +JzNvJYTN1Pw_7 bus +Jzm0H_o-LyA_1 bicycle +JzwF2_O5qho_0 cow +JzwF2_O5qho_1 cow +JzwF2_O5qho_2 cow +J0Gb34OfhGs_0 airplane +J0m2haAO_Pg_0 truck +J0uOEHqVD0g_1 elephant +J01a05fNHz8_0 airplane +J05eYTq5pFE_0 cow +J1BVFlR3Pzc_2 bicycle +J1VVax1uIGc_0 elephant +J1YSacTJR64_0 bear +J1YqrkAsUIs_1 truck +J1YqrkAsUIs_2 truck +J1YqrkAsUIs_3 truck +J1rYOpOlNqs_0 cat +J1reV7ZinzE_2 truck +J1sQZHaGRVY_0 cow +J1uF4oCMmtU_0 car +J10PTSVhLnQ_0 car +J10PTSVhLnQ_1 car +J10PTSVhLnQ_2 car +J142X1ly-gY_0 cow +J17uKo2HgxY_0 bird +J2R5C_XNnek_0 train +J2Sh2XKvWOA_2 horse +J3EToJg72Es_0 horse +J3d48McH1L0_0 elephant +J3gk0p9Hm0o_0 knife +J3hgEqlUzpg_0 bus +J3hva1l0CWM_1 horse +J3jOAuADP44_0 boat +J3sMC-99CWs_1 cow +J3zIT2YwDdY_0 bicycle +J315ju7gD8Q_2 train +J4eK5nQv9E0_0 motorcycle +J4hu4X1Hr7k_0 bear +J4ithFdbyKY_0 train +J4mDzsuGR1M_2 bear +J43AWiRkRAI_0 skateboard +J46c4FEAjQ8_0 horse +J46c4FEAjQ8_2 horse +J5CA6t8d7uA_0 truck +J5JNgpMvPks_0 horse +J5Ss-cEKg9o_0 skateboard +J5TS-1YKlWE_0 elephant +J5TS-1YKlWE_1 elephant +J51qDcGqOV8_0 airplane +J5-O6tDEZO0_0 horse +J5_8xLaPuIU_0 cat +J6AHeX1RqWk_0 bus +J6nRLSf9kms_1 dog +J61MSyhI5Xg_0 bird +J68NptJ9oRE_0 skateboard +J7h1DaonvHY_1 horse +J7jTtirQ85g_0 motorcycle +J7vNGyyYQ30_0 dog +J73WpGWHEuE_0 giraffe +J73WpGWHEuE_15 giraffe +J73WpGWHEuE_1 giraffe +J73WpGWHEuE_2 giraffe +J73WpGWHEuE_14 giraffe +J79qVoBV6TM_0 car +J8Akt0d4r_k_0 train +J8Akt0d4r_k_1 train +J8dIP05jqRw_2 truck +J8dIP05jqRw_5 truck +J9SzI8MQm6Y_0 airplane +J9ZGJucbLiw_0 airplane +J9mX4rrWQto_0 knife +J9n9_-FSk4Y_0 dog +J916-YD5Qms_0 elephant +J-sHEYA-20k_1 giraffe +iKjaiW6gHPQ_1 elephant +iKjaiW6gHPQ_0 elephant +iKlCbkZsFzE_1 cow +iLeUN6d8Aew_0 giraffe +iLeUN6d8Aew_1 giraffe +iLk3v-m1Z0U_0 horse +iLvLOw8Jigg_0 motorcycle +iL0GMZ7iO3c_0 dog +iL5OOut4Jek_3 bus +iL9TAERxS4A_1 bicycle +iL9hLZ_cXaI_0 person +iMfVd5_HBcE_0 bus +iMqYyOcO4Fw_0 umbrella +iMtt9-ROv_o_0 dog +iMukpec9Vmo_0 airplane +iMukpec9Vmo_2 airplane +iMxzNRMiKMA_0 truck +iM3tOs60qxk_1 airplane +iM8Lua_zTug_2 train +iNQNSmu2BD8_0 skateboard +iNWrFmCCfXw_1 bear +iNa2jg_1Vyc_0 cat +iNghTa86iWY_0 cat +iN-bJwlR2i8_1 bicycle +iOEuAB0dIs8_0 dog +iOH00pYaMhY_0 cow +iOJiYp298qc_3 airplane +iOJiYp298qc_1 airplane +iOd4NCiEBLw_4 airplane +iOd4NCiEBLw_2 airplane +iOgScMDTX_I_0 skateboard +iOvWAp7U61k_0 cow +iOzYv5IpFng_0 horse +iO7wHeFO6Js_1 cow +iO7wHeFO6Js_2 cow +iPWL6FSzmS8_0 umbrella +iPbg6G7tUVo_1 horse +iP98M3c1PJw_0 elephant +iQB9bgZJCwA_0 motorcycle +iQPn_3iB6aU_0 umbrella +iQYiakvHwnk_0 bicycle +iQZ1QN-A3JQ_0 elephant +iQfs0MyXA-s_0 airplane +iQxGihgbiM8_0 cow +iQ_2xA5J-Zg_4 bird +iQ_2xA5J-Zg_5 bird +iQ_2xA5J-Zg_1 bird +iQ_2xA5J-Zg_2 bird +iRI3AkfYykI_0 knife +iRLMFxqd6Vk_0 bear +iRTTlG8M9FE_0 car +iRTTlG8M9FE_2 car +iRTTlG8M9FE_1 car +iRWWnw104cE_0 bicycle +iRklgBUz8ME_0 bus +iRk0aHyYWdM_0 bird +iRlBKC_jfE0_1 horse +iRlBKC_jfE0_2 horse +iRlBKC_jfE0_4 horse +iRmfa0b6jJk_0 car +iRpibBNFoiY_0 knife +iRv5dyfU3ZQ_1 car +iRv5dyfU3ZQ_2 car +iRw-TCiikqw_0 horse +iRw-TCiikqw_1 horse +iR3sRTxVGtg_0 airplane +iR4rImxKjK0_0 car +iR4rImxKjK0_1 car +iR5Zew8NcYU_0 truck +iR5Zew8NcYU_1 truck +iR5Zew8NcYU_2 truck +iR5Zew8NcYU_3 truck +iR5Zew8NcYU_4 truck +iR5Zew8NcYU_5 truck +iR5Zew8NcYU_6 truck +iR5Zew8NcYU_7 truck +iR5Zew8NcYU_8 truck +iR5Zew8NcYU_9 truck +iSCFoiWm7Xk_0 bear +iSLNkNnHOXQ_0 bicycle +iSYNvKIuAXc_0 motorcycle +iSbXpgu-7qA_0 bicycle +iSeR1wQ4sl0_0 train +iTF1bWOtrew_1 bus +iTF1bWOtrew_2 bus +iTWyYCJO0FI_2 truck +iTbEmIOM3Bg_2 car +iTbEmIOM3Bg_0 car +iTbEmIOM3Bg_1 car +iT3LIkn9wh4_0 car +iT5clmXCTEc_0 elephant +iUDGzAPkGLI_1 airplane +iUEEnhAvRoY_0 cow +iUSZKTFqatw_0 airplane +iUX8ST-BSFg_1 bus +iUZnCaGp148_0 dog +iVH9ehKyau0_0 giraffe +iVRs9h04NcM_0 cat +iVzRc0RW_Y4_0 bird +iV4UGeMqQeY_0 dog +iV8NpvUXve4_0 elephant +iV8NpvUXve4_1 elephant +iV9CFIQTmfs_2 bicycle +iWP_wo9OSe4_0 bird +iWo66ztRt0o_3 boat +iWtj7if5cK8_1 boat +iWv1rxdhH1E_0 bear +iW1aIV39PQo_0 motorcycle +iW2g2j2VhbM_1 skateboard +iW2g2j2VhbM_2 skateboard +iXKQX0UfOqA_0 cow +iXKQX0UfOqA_1 cow +iXKQX0UfOqA_3 cow +iXh4-KWp9S4_0 horse +iXl114K8Y1E_0 car +iXxi1CQpbBk_2 cow +iXzEoHyipJM_0 truck +iX7b9tWhoKg_0 giraffe +iYGSi3t8Do0_2 cow +iYO5SD120r4_0 elephant +iYYdiX4oGjM_0 skateboard +iYjiqdn7fVk_0 bird +iYsgKLWI96c_2 knife +iYtDe_tT_wo_1 train +J-6KxfbaI6M_2 cow +J_HdQVHBeco_0 motorcycle +J_l7W4IMhJo_0 dog +J_n_3-KXet0_0 dog +KAGadYR0_LM_4 bird +KAGadYR0_LM_6 bird +KAGadYR0_LM_8 bird +KAKn8JmKESU_0 train +KAjM8ENV-F4_4 skateboard +KAxsc-ratJ4_0 horse +KA1A0hH1nVQ_0 train +KBIGw8UrUG8_0 cow +KBKaaEaIPRc_0 cow +KBNqKcj0xoc_0 train +KBP3moB3vz4_0 bird +KBRkCaaDjxU_3 bus +KBRkCaaDjxU_0 bus +KBe3_8RL_MI_0 person +KBoY6Pa8f_M_0 cow +KCbzyGKBwC8_0 train +KCdR8nTa3p4_0 skateboard +KCipBL5_e5M_0 horse +KCy-RKy_KN0_0 bicycle +KC1md4Q_DlQ_0 skateboard +KDSxlGW6eRc_0 umbrella +KDZsS4MjllY_0 motorcycle +KDaVTe3RbUY_0 horse +KDyYkCLIImM_0 knife +KD0Qm4z53a0_0 truck +KD0Qm4z53a0_5 truck +KD5LwDdfw0o_0 horse +KD9qqVSiPu0_0 train +KEGLFAbfrxs_0 motorcycle +KERo3bKldwM_0 elephant +KEW0fAHE_74_0 bus +KEW0fAHE_74_2 bus +KEagowlFwzI_0 cow +KEll3gbyIsk_0 truck +KEll3gbyIsk_1 truck +KEll3gbyIsk_2 truck +KExfLNe3IbY_0 airplane +KE2StZtSBfk_0 airplane +KE3O7h2RC-s_1 train +KE_UJpQulNU_0 horse +KFEorB8NRcE_0 boat +KFFTHBaYcbw_0 bear +KFJtVwXfusI_0 boat +KFRZOFB41Jk_0 train +KFk_7p6X-zI_6 car +KFk_7p6X-zI_1 car +KFk_7p6X-zI_2 car +KFk_7p6X-zI_4 car +KFk_7p6X-zI_5 car +KFnvvsS8eIE_1 knife +KGYrelsyNbk_0 airplane +KGbYHbiOfd8_0 giraffe +KGwEL4VozSA_0 boat +KG8zBA9Gudg_0 knife +KHBsJZVKzks_0 truck +KHG1hZsfjwQ_0 train +KHHyhgm1jZ0_3 skateboard +KHSjivlhX30_1 bear +KHcEC33udEg_0 cow +KHgLQP4XH9Q_0 skateboard +KHsYYKcSCSI_1 cow +KH0F1sJXKss_3 elephant +KH0k5jfUZGg_0 bicycle +KH8QlsYIT1M_1 bear +KIPptA8AzYg_0 horse +KIjf6QGqdsw_0 truck +KIjf6QGqdsw_1 truck +KIqePeskBSk_0 truck +KIy2LK1jsQ8_0 person +KI8Arf5-ekw_1 truck +KI8Arf5-ekw_4 truck +KJIBdy7_10k_1 bus +KJIBdy7_10k_2 bus +KJJBVXnnqIw_0 zebra +KJcXjJ5S9yA_1 dog +KJrPyuVxWRg_0 airplane +KJrPyuVxWRg_1 airplane +KJvAK-5ExwY_2 truck +KJ30mU3h4f4_0 bear +KJ7PQiJAKRM_0 elephant +KKKiTv_k23A_0 giraffe +KKO1QGoVQYU_0 elephant +KKpwJEMQYv8_0 dog +KKsKKMjHYGM_0 horse +KK06xbUhklk_1 bus +KLC8OgkQnNQ_0 boat +KLEKnTRMmo0_1 cow +KLGAT1GQYGA_2 bird +KLMz6_P5QmA_0 horse +KLNmQqyAs54_0 cow +KLUTy4pqLZ0_0 bicycle +KLVZqPfRuTg_2 bear +KLVZqPfRuTg_7 bear +KLlN4H-eGYI_1 skateboard +KL6-Iu09-C8_0 cat +KMNaWZZK2Os_0 skateboard +KMOOcO5yE9E_1 horse +KMXuGjMAt7k_5 bicycle +KMXuGjMAt7k_6 bicycle +KMXuGjMAt7k_3 bicycle +KMajGvVnol0_1 airplane +KMajGvVnol0_4 airplane +KMajGvVnol0_5 airplane +KMajGvVnol0_6 airplane +KMajGvVnol0_7 airplane +KMiZgk_f50g_0 dog +KMlZbzTdutw_1 car +KMlZbzTdutw_2 car +KMsL64iYfOA_0 car +KMtu1xThH2k_2 elephant +KMyoO6YYfZk_0 elephant +KNaoNUMT7m0_1 car +KNg4K_bbY5Q_0 train +KN5hxi96gW0_0 cat +KN-_uhPPfoE_0 cow +KOKdrC_foXo_0 airplane +KOOd5IO8seo_0 boat +KOSUWuFIQjQ_1 airplane +KOVZk2ixqc0_0 truck +KOgmgqcT21Y_1 bird +KOl1EDiK2e8_0 motorcycle +KO6T6QdloiM_0 bus +KO7Ncyx1-9c_0 train +KPJDHcE-qeQ_0 bicycle +KPYtlDJa43o_0 skateboard +KPfbBNvFcmA_0 skateboard +KPj_wrsubOE_2 bear +KPkzyHL7IPg_0 cow +KPmvpNEHsPk_0 skateboard +KPzWIuvRlr0_1 skateboard +KP4ApNQiIEI_0 cat +KQB-ZyriFmI_0 boat +KQg6eO2jr_Y_0 umbrella +KQ5mchVgTXo_0 truck +KRCLiP-JUsc_0 truck +KRCLiP-JUsc_2 truck +KRCLiP-JUsc_1 truck +KRW0HyqDLg8_0 dog +KRjN1nx8mcE_0 airplane +KSDxU99SF6g_0 motorcycle +KSHVle4SAM4_0 elephant +KSZ7nkMWOsU_0 skateboard +KSZ7nkMWOsU_1 skateboard +KSj7hZ7oO18_0 cow +KS1ge4vlv64_0 bicycle +KS4vsIYGaCM_4 truck +KS4vsIYGaCM_0 truck +KS8UAlyHoCg_0 dog +KS_fak2guWU_1 dog +KTAMaZKxpF8_2 train +KTDhNtr8XF4_0 airplane +KTDzrCvIVQs_0 dog +KTQQtbUbWbA_0 airplane +KTZ2Jsj6_ig_0 truck +KTdzxOjJNgI_0 car +KTsTGNqrFuE_0 umbrella +KT7YiBWXqNk_0 airplane +KUZxnRyU2e8_0 cat +KUbSnz1yWxc_0 knife +KUc8Kw30V1Q_2 truck +KUc8Kw30V1Q_3 truck +KUc8Kw30V1Q_4 truck +KUgY_2bsBC0_1 skateboard +KUhzqYZoYCI_0 cow +KUkcrqulhqg_0 cow +KUlpA-cpCpM_0 horse +KUumLype4AE_0 elephant +KVFlTVdKQVw_0 horse +KVJCkQzQbMs_0 person +KVmS-yiYu2c_0 bicycle +KVzW5MPT25A_0 airplane +KV0o55FO4XA_0 skateboard +KV3jtdzXA9U_0 dog +KV__RQ75-vw_1 cow +KWJiCsomGTA_0 cow +KWLl4vVumIs_0 truck +KWSDQebY3dA_0 cat +KWwbFKgHqW0_0 car +KWxd8IQ9_a0_0 cat +KW10UlO19uo_0 bus +KW4ovUCg7uU_0 bicycle +KW4ovUCg7uU_1 bicycle +KW5S4gsTVaQ_0 knife +KW7gAr7kgow_0 dog +KW_6RyjLGPI_3 horse +KXCQuD9phb4_1 bird +KXENib5sk78_0 cat +KXLWiz5ZUh0_1 train +KXLWiz5ZUh0_2 train +KXdF5__0yVQ_0 cow +KXf6k7PrX7E_1 elephant +KXf6k7PrX7E_2 elephant +KXrQkw1WPnk_0 bird +KXzu3MDaZn8_0 car +KYK_Wg8JlTg_0 skateboard +KYK_Wg8JlTg_1 skateboard +KYTRCD2p-8Y_0 motorcycle +KYZzKKYD7Yc_1 horse +KYaB_EEk344_0 cat +KYc__uUZkwc_3 bicycle +KYd6wCR0jVc_1 horse +KYd6wCR0jVc_0 horse +KYs4hm9X1Rg_1 bicycle +KYvXJXEbUMg_0 bird +KY0x7p41Q_A_0 cat +KY04L4VTsXc_1 airplane +KY04L4VTsXc_2 airplane +KY7D2Y5MQSo_0 horse +KZAf2uPS-us_1 horse +KZAf2uPS-us_0 horse +KZFniGi-fes_0 dog +KZJcgoY3r3U_0 airplane +KZSLQpdbGps_0 motorcycle +KZYe6pqrLaQ_1 dog +KZhX7tDfYIA_0 bus +KZl_XArvSXk_0 horse +KZ4OuA1t3ZY_0 elephant +KaUGkf-3N-4_0 horse +KaiX3d83DWA_0 zebra +Kaj5B4nrWJU_0 skateboard +KapwOqVyzUk_0 cat +KaqToIfNxMY_1 bicycle +KauPg8P2kC4_1 airplane +KazepPKQz1M_1 cow +KazepPKQz1M_3 cow +KazepPKQz1M_4 cow +Ka978At0k0Y_0 airplane +Ka-4ZfE0GMQ_0 motorcycle +KbA6UDJg1LE_0 train +KbA6UDJg1LE_1 train +KbGl5jqOQ7o_0 cat +KbRIbBeLBsM_3 motorcycle +KbosOWR7ZSg_1 boat +Kb3lxArGO8Y_0 bicycle +Kb3lxArGO8Y_1 bicycle +KcDpzG8kKho_0 cat +KcL-zz1sb6I_0 dog +KceqMsKO-zc_0 cat +KcpGWNCD-uk_0 cat +Kct9k6Q2YM8_0 car +KcuEc9WwYSQ_0 cow +KcuEc9WwYSQ_1 cow +KcyLR4RxylE_0 cow +KcyMYgt62Go_0 horse +iY5Sh73Lem0_0 bird +iY6eEC8uY4E_2 train +iY6eEC8uY4E_1 train +iY9QlFmEBFY_0 motorcycle +iZsSK_iIOoA_0 horse +iaGO2mTgoPo_1 bicycle +iaGO2mTgoPo_3 bicycle +iaWSU1ISWXQ_2 airplane +iaWSU1ISWXQ_0 airplane +iaflfMXT7QQ_0 boat +iamGAsKNRhY_0 train +iana0Lz1gs0_1 motorcycle +iasZRb9p3lg_0 motorcycle +ia1XmqAwn7M_0 bus +ia6R3fqdlnE_0 bear +ibcBDIGpMfo_1 bus +ibd-Wxcr_x4_0 horse +ibpj369yzbw_0 umbrella +ibxmk7cGhTQ_3 horse +ib5fWzJWV5A_0 cow +icDyRH3P-nM_0 airplane +icGjENlINL4_3 skateboard +ich9rXZWjGY_0 car +icic9NkCnf0_0 cow +icnuBKQZNBg_2 bus +icnuBKQZNBg_0 bus +icnuBKQZNBg_1 bus +icxOfJQ-l9I_0 car +icxOfJQ-l9I_1 car +icy3pC1Q0eA_0 cat +ic7k8fkUDXs_0 cow +idnOwkwaCm4_0 horse +idnSzg_rV_k_3 bicycle +idoGYHCXGJs_0 elephant +idq0Jqw8Oa0_2 elephant +id1yzZ3HkTs_1 knife +ieCL4lz7IJw_1 boat +ieOpqoYhMOQ_0 truck +ieOpqoYhMOQ_1 truck +ieOpqoYhMOQ_2 truck +ieULzTIs9ls_0 cow +iedgnWefCA0_0 airplane +iedgnWefCA0_2 airplane +iedgnWefCA0_3 airplane +iewlg5CteEs_1 airplane +ie8gkh6nQcA_0 train +ifKKR-gCLSk_0 cat +ifRQKBKIRSI_0 dog +iff3KW8leKw_0 airplane +iff3KW8leKw_1 airplane +ifghH4Jo8D8_0 truck +if31ci9xz_8_4 bicycle +if31ci9xz_8_1 bicycle +if31ci9xz_8_2 bicycle +igGtS-jZCQM_2 car +igGtS-jZCQM_0 car +igLVqNKw-yE_0 bird +igMWvnK1jEE_0 giraffe +igMWvnK1jEE_3 giraffe +igMWvnK1jEE_1 giraffe +igQUACDrluw_0 horse +igU61tmxeE4_2 skateboard +igWsPt0nelg_1 bus +igcpSvypduQ_0 truck +igcpSvypduQ_1 truck +igdqmLfZ_cw_0 airplane +igjBIRwjlko_1 dog +igm6X4CZLmk_1 bus +ignREcFRyaQ_7 airplane +ignREcFRyaQ_8 airplane +igwghbZYjgg_0 airplane +ihMDaxeTpZs_1 horse +ihTjIMWOjuQ_1 motorcycle +ihUpF22zo4M_0 train +ihUpF22zo4M_1 train +ihWWle00xEE_0 motorcycle +ihh0J0AaWBs_0 train +ihh0J0AaWBs_2 train +iiA0hIRwwJA_0 train +iiSWvRk3YfU_0 bird +iiextKoe48U_0 cat +iigPPpoo0W8_0 knife +iiiOUcmwJPw_0 cow +ii0PDMs-a0o_2 car +ii2ghwDAI3w_1 airplane +ii_sG2SkeXM_0 cat +ijB2Yh71VIg_2 bear +ijJAWtORd2w_0 truck +ijJAWtORd2w_1 truck +ijVpcnt8HN8_0 bus +ijXmwWOLvpM_2 horse +ijXmwWOLvpM_1 horse +ijdipMmraWc_0 truck +ijwhkKzyWE8_0 airplane +ij0zLKtr0sA_0 bird +ikGzd6ivk64_0 motorcycle +ikKFRS8Hivk_0 bear +ikVu6XfZ3_A_1 bicycle +ikafEc8p6rI_0 bicycle +ikafEc8p6rI_5 bicycle +ikafEc8p6rI_1 bicycle +ikafEc8p6rI_3 bicycle +ikafEc8p6rI_4 bicycle +ikfmjumoUlM_2 train +ik868nOtrZo_4 bus +ik-jgdZW4Ek_0 horse +ik__zZ1HZNg_1 giraffe +ilKErQ8ojz0_0 umbrella +ilKErQ8ojz0_2 umbrella +ilKErQ8ojz0_3 umbrella +ilKW98Qvobg_0 skateboard +ilvsheh1Cqs_0 dog +ilxXSgvtFgw_0 cow +imEWC_Q-BSg_1 car +imcRxs0K7H8_0 bus +immhpBi8eWw_6 skateboard +im_FneG303c_0 dog +inEZ7ZLAS7s_5 skateboard +inJLKInP5kw_0 dog +inZmM8c-9NI_3 horse +inedUh-74-A_4 truck +inodVLfFogA_0 train +inynAJrGhVU_0 motorcycle +in061qZJjWI_0 dog +Kc8WMzLKvvk_0 cow +Kc-f3X7O-pw_0 cat +Kc-x73DCumI_0 truck +KdGgVhM0Ihg_0 bird +KdKlI0ZN6qo_0 airplane +KdQQqsAuU7o_1 bicycle +KdUSJz6UWLQ_0 giraffe +KdXRnPKKeTU_0 bird +KddQJwFfv9s_2 skateboard +KdjMgSuON5w_5 bear +KdpUjVhfjG0_0 person +KdyadP7Y1nU_0 car +Kd9Em2ABfN8_0 cat +Kd-jTE5-2uE_1 motorcycle +KeMITKdjHtk_0 cat +KenV2bIQf1o_0 bicycle +KevYmLAAigc_1 train +Ke3R9FrGLcY_0 dog +KfJU66erPWo_2 knife +KfMO45jz-68_0 boat +KfS_UKkbQAA_0 bird +KfTV1TFY2b8_0 bird +KfaTw0euPQA_0 motorcycle +KfjmKiZzSlY_0 cow +KfjmKiZzSlY_5 cow +KfkKe7q45KA_1 motorcycle +KfkKe7q45KA_2 motorcycle +KfkKe7q45KA_3 motorcycle +KfpCncLoqOw_0 cow +KfwbVpPI0nU_1 motorcycle +KgAFD_JvgrQ_0 cow +KgD3H0APDy0_0 bear +KgNS5HwFF_c_1 elephant +KgVEQYicksA_0 cow +KgY5OrVnzv4_0 cow +Kgo7SWtDdz4_1 dog +Kg3xuyjNU7w_0 umbrella +Kg7Qk4Gx9n0_0 motorcycle +KhKZwdKiqms_0 cow +KhKcHaH_ALo_0 horse +KhPKq8O30VM_0 bicycle +KhPKq8O30VM_2 bicycle +KhPKq8O30VM_4 bicycle +KhuC9snWfpI_0 cow +Kh7rAO7jCGc_0 airplane +Kh_KwBHfGQ8_0 cow +KiHy8IMQ6zA_0 airplane +KiaUDlPLxzk_1 bear +Kixl-Wmj3kg_0 motorcycle +Kjaag6B-MIQ_1 skateboard +Kjca1u6P3NE_0 cow +KjiI2E3l3Mk_1 truck +KjiI2E3l3Mk_2 truck +KjqaJ25GUBI_0 bus +Kj3dRtd4xQI_1 cow +Kj3dRtd4xQI_0 cow +KkD23XYUG9c_0 umbrella +KkMNGzvNkg4_9 bird +KkNYBz9ZaVA_0 bird +KkNYBz9ZaVA_1 bird +KkPf9AB1HZo_1 elephant +KkRq1ogJq-4_0 skateboard +KkXTT9C4xfc_0 cow +KkdSKHS7P50_1 skateboard +Kks6eJqnZLQ_0 dog +Kks6eJqnZLQ_2 dog +Kks6eJqnZLQ_3 dog +Kks6eJqnZLQ_4 dog +Kks6eJqnZLQ_5 dog +Kk6BgYl9OjA_7 bicycle +KlEK-vv3DVo_0 bear +KlENnLskuCU_0 cat +KlG0czACle4_1 cow +KlG0czACle4_0 cow +KlG0czACle4_2 cow +KlG0czACle4_3 cow +KlqbHICh4G4_0 train +KmJhshcviXA_0 knife +KmbMzgXFdKs_1 airplane +KmbMzgXFdKs_2 airplane +KmbMzgXFdKs_0 airplane +KmfmqwmQneM_0 bird +Kmr5uVYVSDo_0 car +KmuV8XfAjvw_0 horse +Km3GmgNJlL8_0 train +Km3GmgNJlL8_1 train +Km3GmgNJlL8_4 train +Km7w520V5vs_0 airplane +KnIxVxIho9w_1 bird +KnN2yDre-aM_0 boat +KnTu6keaGs0_2 elephant +KnTu6keaGs0_0 elephant +KnXPxa1RzmU_0 cow +KncYvkV6rwc_0 boat +Knql8E5Khc8_0 elephant +KnuD87lrS8w_0 skateboard +KnvGRqLQ5iM_1 train +KoA6bPmALeA_0 cat +KoXgGmdVCBM_1 bicycle +KoXgGmdVCBM_10 bicycle +KoXgGmdVCBM_2 bicycle +KoXgGmdVCBM_3 bicycle +KoXgGmdVCBM_4 bicycle +KoXgGmdVCBM_5 bicycle +KoXgGmdVCBM_6 bicycle +KoXgGmdVCBM_7 bicycle +KoXgGmdVCBM_8 bicycle +Kosi26dm76A_0 horse +Ko5wlBGl200_0 horse +Ko_Nx24OGxM_2 airplane +KpDzoM2xtwc_2 truck +KpDzoM2xtwc_3 truck +KpDzoM2xtwc_5 truck +KpHFaYsgWrg_2 elephant +KpHFaYsgWrg_1 elephant +KpVflkpC7d4_3 bus +KpVflkpC7d4_5 bus +KpVflkpC7d4_0 bus +KpVflkpC7d4_2 bus +KpXxo2n6AYw_1 motorcycle +Kphl0WRacss_0 knife +KqAvXx4bN5k_0 cat +KqQgFUEAS-M_0 train +KqavxpR698k_6 dog +KqavxpR698k_0 dog +KqavxpR698k_1 dog +Kqfo6_qcthc_0 car +KqjhaIJMY5U_0 cat +KqnqyAczaqs_4 bus +KqqyldSpJh4_0 horse +KqqyldSpJh4_1 horse +KqzkADa-Lqw_1 train +Kq1x16QvM1g_0 dog +KrGJjt0yq-s_1 bus +KriNb3dhqVQ_1 skateboard +in9LFcixPXo_0 skateboard +ioEMtB2bP6o_0 bird +ioESr4H79KY_0 boat +ioGc_R8NJow_0 cow +ioKahF3aFWw_0 horse +ioKahF3aFWw_1 horse +ioOHxrHumIk_1 airplane +iobYquCNk5k_0 cow +iojaZ646ie8_0 skateboard +ipLnwxta1Jc_0 boat +ipOJVFLMLIk_2 bird +ipOJVFLMLIk_0 bird +ipgB9KXnzK8_0 horse +ipg_y1T2OsM_0 cow +ipg_y1T2OsM_1 cow +ipqQlNsINy8_2 airplane +ipt6gWgCgis_0 truck +ip5xVRJOpP8_0 umbrella +ip8BFE94TKo_0 airplane +ip8BFE94TKo_2 airplane +iqDJJqLVBBk_1 elephant +iqExYW2fPfc_0 bear +iqicuLBaF_g_0 truck +iqlKzflOl00_1 bus +iq1FaWFylpI_0 motorcycle +iq6izTYp-DU_0 motorcycle +irBsER6ITHw_2 skateboard +irDs_vWExnM_1 bicycle +irDs_vWExnM_2 bicycle +irU_BJXoU9I_1 cow +irWY8s-JuBs_3 airplane +irWY8s-JuBs_0 airplane +irWY8s-JuBs_1 airplane +irWY8s-JuBs_2 airplane +iramP9ihj_w_1 bird +irgacv6LobE_0 motorcycle +iri1MtEgOjQ_0 bear +irs2O6YOB5I_3 elephant +irs2O6YOB5I_5 elephant +irs2O6YOB5I_1 elephant +iruY-BU0rpg_4 elephant +irzcPf--6uQ_0 train +irzcPf--6uQ_4 train +irzcPf--6uQ_5 train +ir4EYn7Fz5A_0 dog +ir5E9O2Tonk_0 boat +ir7Dq5dPxOQ_0 horse +isPplb7aotI_0 boat +isPplb7aotI_3 boat +isU4229ndXM_0 cat +isfwmnXNmeM_2 cow +islz_HxqOnI_0 bird +isvvRHvNuIw_4 umbrella +isynk11V9s8_3 airplane +isynk11V9s8_1 airplane +isypXPZMgns_2 boat +isypXPZMgns_3 boat +itKyPMv5z0Y_0 umbrella +itKyPMv5z0Y_2 umbrella +itc-A2zwSGM_0 dog +itrvgHryhIY_0 train +its4C4ty2oA_0 skateboard +ittQcsrECUE_1 bear +ittQcsrECUE_2 bear +it1EatlrBkg_0 cat +it3KS-r39EQ_1 knife +it3hCzfmyfs_0 cow +it6DtEGdhas_0 cat +it8Fid-mqRQ_0 truck +iuEbY8B4Qo4_0 cow +iuEbY8B4Qo4_1 cow +iuFmdispR2U_0 bicycle +iuRmu4BN6bw_0 train +iumTd9IGDho_0 train +iusgUMlrYFA_0 airplane +iutdZMWA8f0_0 person +iuumrgHW8zM_0 umbrella +iu3sd1qnr8g_0 car +iu9Av4HCmiw_0 knife +ivDeIaJYIlE_0 truck +ivT103z2bwc_0 giraffe +ivdfO5VqKo4_0 cat +ivgTXhIqccY_0 cat +ivi1frbFnGw_1 giraffe +iwFO7lcVjKc_2 cow +iwFO7lcVjKc_0 cow +iwFO7lcVjKc_1 cow +iwX4cgfQn5s_0 bird +iwczN64AC9Y_0 bus +iwp5aVOXWaM_0 airplane +ix8S6CRuUFg_3 bear +iyAvqfMVOeA_0 cat +iyLZZlL-B80_0 cow +iyMbIICjtcg_0 cow +iybJfH6iVdU_0 bus +iygW3-Ovcic_0 cow +iyn1OZFmvXE_2 bird +iyz9Lq13Mcg_0 cow +izbTUTqkG7c_0 cow +izx70OqPYBc_0 dog +iz9-Vl4e9po_0 train +iz9-Vl4e9po_2 train +iz9-Vl4e9po_3 train +iz-BT0NAs6k_1 knife +i0Eg02B3JoM_0 elephant +i0Ez1KT7sTo_0 horse +i0ZE0kXl5oU_1 skateboard +i0eMgZ0riHI_2 bird +i0gg-mJNKlU_0 cow +i05OPAsrmJI_3 elephant +i05OPAsrmJI_1 elephant +i05OPAsrmJI_2 elephant +i09cuoC14q4_0 bear +i1DfyWe0Jh4_0 cow +i1DfyWe0Jh4_1 cow +i1NfFxZmBSA_0 bus +KrvsSuIgrJQ_4 horse +KrvsSuIgrJQ_1 horse +KsT2_VxPkb4_0 knife +KsXzFCpHMPU_0 giraffe +Ksyud0_i1zI_0 bus +KtINrfbQSXk_0 knife +KtV59qZg7BU_0 truck +KtX4x9k3J2A_0 train +Kthi3i2WM3s_1 skateboard +KtkN77asAj4_0 horse +KtplZx6_ecU_1 knife +KtqvSap6uig_0 skateboard +Ktxb4OmaAjA_0 car +Kt3uQcxNltk_0 zebra +Kt9neWWjkHM_2 bear +KuBa9tep8xk_0 bear +KuQgP71vfZ0_0 train +KuYBJ90zNYw_0 umbrella +KuYjBUvU-ws_0 umbrella +KuYrzelSfIw_0 car +Kulks153IS8_0 truck +Kulks153IS8_1 truck +Ku0XhH2YeG4_0 bear +KvH6JyHG3H8_0 motorcycle +KvH6JyHG3H8_1 motorcycle +KvLXxaGooPk_0 cow +KvPLPO4A5R8_0 knife +KvRsu4xefwo_0 person +KvcxzJxNkkU_1 bird +KveRZ7dBNGU_0 boat +KvgupPBw5rc_0 cat +KvjDDIthDDM_0 cow +KvkOTtqxJlo_1 cat +KvsaKWirK7Y_0 skateboard +Kv0ui3mEWGE_0 horse +Kv0ui3mEWGE_4 horse +Kv0ui3mEWGE_1 horse +Kv0ui3mEWGE_2 horse +KwkcPYl8Lv4_0 cow +Kw7t6l8h2Ns_0 bear +Kw7t6l8h2Ns_1 bear +Kw8037OwDjc_0 truck +KxWI3M2FGOw_0 horse +KxZXot9AIY4_0 truck +KxflrYttp20_0 bird +KxlTxdqDDzo_0 cat +Kxuqb_htGwY_0 giraffe +Kxuqb_htGwY_2 giraffe +Kx40to29YnE_0 skateboard +KyDXCruNNj4_0 horse +KyUM64yfNCA_0 horse +KyWUn_bj5rM_0 motorcycle +KyZWWIsQUbg_0 skateboard +KyZWWIsQUbg_1 skateboard +KyaKfhOfKhE_1 bird +Kyt325n06oI_0 cat +KywHhzvsm3Y_0 bird +KyyS9PYJ9Zo_0 truck +KzK3iwncxbY_0 bicycle +KzK3iwncxbY_1 bicycle +Kzc17TzutkM_0 skateboard +Kzc17TzutkM_1 skateboard +KzyD-e7N2D4_0 train +KzyD-e7N2D4_1 train +Kz3zulHzEE4_1 train +K0CwoXVMp0M_0 bicycle +K0L3_2UquEY_0 boat +K0Zt-EcXkj8_1 airplane +K0cgwgX_8fo_2 boat +K0xs4bH65_Q_1 motorcycle +K02fUURwCiY_2 car +K02fUURwCiY_0 car +K02fUURwCiY_1 car +K1Qbgm__2iE_0 cat +K1ccfBgR_kg_0 truck +K1-s4sk63R4_0 horse +K1_J3d_yH64_0 motorcycle +K2F6TCgVfR0_0 boat +K2hV4KVruLc_0 airplane +K2my8qWjyn4_0 cat +K2yjgwFV15k_1 motorcycle +K2yjgwFV15k_0 motorcycle +K26jSjClwaQ_0 skateboard +K3Cgw_EFdbw_1 motorcycle +K3DniaFnn9E_0 cat +K3KhxEuf8mY_0 horse +K3KhxEuf8mY_5 horse +K3Ov5rPJ2LE_1 horse +K3XsEMr7Qt4_0 person +K3qgW4Y3yrk_0 motorcycle +K30LSGFu6hs_0 motorcycle +K4RE7AZWGv0_0 car +K4U_AmqQFDY_0 bear +K4VnWy2-8xQ_3 car +K4ec2MqDkPw_0 train +K4fCUNjbdf8_0 motorcycle +K4wp52Zn5d4_0 horse +K5NooGgwD1E_0 horse +K5NooGgwD1E_1 horse +K5pBkPv_1sg_5 car +i12y-zJl-nA_0 cat +i17EaDmRPCg_0 umbrella +i2Yjl6kF8iY_2 airplane +i2Yjl6kF8iY_0 airplane +i2cujNbMSKc_1 skateboard +i2diIHrCsbk_1 bird +i3AK_cujBxY_1 motorcycle +i3BpSeFJdgo_0 cat +i3HeGqUyibM_4 bicycle +i3HeGqUyibM_9 bicycle +i3HeGqUyibM_12 bicycle +i3LFAemLFW0_0 horse +i3Z5pFF2dH0_0 bird +i3a4U770GtE_0 person +i31nG3E36WE_0 knife +i32p4KoRD2o_0 train +i33S_D8TBc4_0 dog +i35wpbpl8qY_2 boat +i38dpYWvJN8_0 umbrella +i38dpYWvJN8_1 umbrella +i4CFI7MtlRs_0 cat +i4ExemfAEO8_0 bicycle +i4IpgDIqTrs_0 boat +i4RZtd1cCw8_0 umbrella +i4bRNqQ32MI_0 cat +i4clJpNvw4M_2 bus +i4hqN47R0oU_1 train +i45JoRzDdI0_0 cow +i46jok5cjyY_0 horse +i5GJ6mIp8zc_0 boat +i5G6RkcL4m0_0 cat +i5OdBE4QG6c_0 train +i5g87UeVkBU_0 horse +i5g87UeVkBU_1 horse +i5sT2ifoPyM_0 knife +i6MF-PGtJiE_1 train +i6WTNPwIjW8_0 cat +i6aJqhBh5wg_0 skateboard +i6j6P7ITxYg_0 cow +i6vwTWezXmU_1 boat +i66Gsq6zzqI_0 motorcycle +i6-YQ6rSnDI_0 cat +i6_oBTD2-YA_5 bird +i7P2tq4TS_4_2 bus +i7UQGL5uxvw_1 skateboard +i7WeV3CfJV8_0 knife +i7a8sQcVRgE_0 truck +i7umCLnxVXw_0 cat +i791If0qoBU_5 knife +i8KQCu2cMAc_2 bicycle +i8KQCu2cMAc_4 bicycle +i8bVI1667K4_1 truck +i8hjK42sseE_0 motorcycle +i8lG7Ux3wlc_0 dog +i8nbuADJjmE_0 car +i8nbuADJjmE_1 car +i8nbuADJjmE_2 car +i9PUn4sF30g_0 motorcycle +i9T-NwSBqPE_1 knife +i9VWkuQHBls_0 horse +i9nmvkDiFGc_0 cow +i9sP7mWuQ_8_2 motorcycle +i9sP7mWuQ_8_1 motorcycle +i9u4vsQUBTQ_0 horse +i90TDb7evCY_0 truck +i9_FG4-2VIM_0 skateboard +i-CQVFq1JI8_1 bicycle +i-CQVFq1JI8_3 bicycle +i-T9Q2g8xbk_0 airplane +i-kodOT_ufM_0 cow +i-nP7aFTZb8_0 bird +i-xdWDN7Eys_2 knife +i-3aAuwOmxc_0 truck +i-8W-K4y3nY_0 train +i_HHc85mP4Q_0 train +i_h0vOCrd_U_0 airplane +i_h0vOCrd_U_1 airplane +i_iXTMX4Vls_0 cat +i_nZ8ImBf18_1 bicycle +i_nwFUP7QJM_0 knife +i_4c71HPXOI_0 giraffe +i_-PIEIGkQE_0 horse +i_-PIEIGkQE_1 horse +jAH-80rHWKY_3 bear +jAW8iLGAgdQ_1 bear +jAW8iLGAgdQ_0 bear +jAh4oBD0Bsw_0 train +jAnV_6fFGnI_0 cow +jAy3VhkJauE_2 knife +jAy3VhkJauE_5 knife +jA6aZl1f4Wg_0 bicycle +jBMmFLPc7nA_6 bus +jBMmFLPc7nA_0 bus +jBMmFLPc7nA_3 bus +jBMmFLPc7nA_5 bus +jBTJgbVspOA_0 airplane +jBl50J7bOEw_1 airplane +jB1IT1aBj-Y_0 dog +jCDFU72N7Mc_1 skateboard +jCJGjjNBSk8_1 airplane +jCJGjjNBSk8_0 airplane +jCMWNtCzuqU_0 knife +jCUnLxCoYMA_0 motorcycle +jCY67ybfyqU_1 cow +jCZx5dn_4KA_0 bear +jCcW1MW6PTE_0 truck +jCcW1MW6PTE_1 truck +jCiwgfC1uN0_0 dog +jCtFgJ1qhJE_0 bird +jC5Px208OVY_4 horse +jC5Px208OVY_5 horse +jC5YGckTiIU_2 train +jDFqxB4rC7M_0 cat +jDJNC5fzvfA_1 motorcycle +jDYks7hSKbg_0 truck +jDbHjQZ5R70_0 airplane +jDbHjQZ5R70_1 airplane +jDdFavN2eWY_0 dog +jDgpggXdBIc_1 motorcycle +jDgpggXdBIc_2 motorcycle +jD2RjyxG6ow_0 motorcycle +jD4621IQz3w_0 dog +jD4621IQz3w_1 dog +jEASZOuNSS0_3 skateboard +jEASZOuNSS0_0 skateboard +jEASZOuNSS0_2 skateboard +jEEOkCjU9y0_0 bear +jEJZ76_xhog_2 bear +jEQDhb_Zewo_0 cat +jEYG-qIv34o_1 cat +jEYG-qIv34o_0 cat +jEfwj-JzFXo_0 person +jE1Rq_Ot02M_0 dog +jFAm4tikj6E_0 horse +jFSIX_KuRK8_0 horse +K5p31PQkx3I_1 horse +K5q4FoXnLwI_0 train +K5sQWplX-D8_1 skateboard +K5sQWplX-D8_2 skateboard +K6JHTga6VU8_0 airplane +K6SFafS3Zv8_0 car +K6SFafS3Zv8_2 car +K6jf51to7dU_0 horse +K6jf51to7dU_1 horse +K6sKjN_MOsE_1 bear +K6srgkSvZdw_1 skateboard +K6srgkSvZdw_2 skateboard +K6vEY0vOlSg_1 train +K66dqG9OJuo_1 dog +K66dqG9OJuo_0 dog +K6_WEh-eizw_1 airplane +K6_WEh-eizw_2 airplane +K6_WEh-eizw_4 airplane +K7uSHqISah0_0 train +K702Tx5vkp4_0 horse +K78iEUHTTZc_1 cat +K8aa-7brUTs_0 bear +K8vGdEhh_jU_0 bicycle +K81vEhukX4U_0 motorcycle +K9LhqtvfZ10_0 dog +K9LhqtvfZ10_3 dog +K9LhqtvfZ10_4 dog +K9LhqtvfZ10_5 dog +K9TPOifKCmU_0 motorcycle +K9hTkmr_71A_2 car +K9jCx7G3_Mw_0 knife +K9kNamc2c5Y_1 dog +K9kNamc2c5Y_0 dog +K9wE7VzJD00_0 train +K-Dz6gr96Lo_0 dog +K-s8RPMLRw4_0 bird +K-s8RPMLRw4_2 bird +K-x3x3kGGqg_0 dog +K_PGa9Eo6mo_1 dog +K_VS3tyB-Cc_0 person +K_Z28TO4stg_0 bird +K_h1L3P_j1M_0 bird +K_pO-MBS7lI_0 dog +K_qFWKniImU_0 skateboard +LAKF499FHX0_0 train +LAKF499FHX0_4 train +LAKF499FHX0_1 train +LAKF499FHX0_2 train +LAKF499FHX0_3 train +LARRHwtW8fE_1 dog +LAZoyKF7lbQ_0 truck +LAZoyKF7lbQ_2 truck +LAZoyKF7lbQ_3 truck +LBJEbJfzvW4_1 skateboard +LBOXDMZvtBY_1 train +LBnsLkuQ8kE_0 person +LBwm49n5rKo_0 motorcycle +LB6fi4oTKvQ_2 dog +LB8Wc8hU4Hc_0 airplane +LCGZmNGyPhM_0 boat +LCghaNtVeM0_1 knife +LCjQb5zLTCs_0 train +LCoIwiCBlW4_0 dog +LCxiwbrpEFI_2 bus +LC5Qly11BZs_0 train +LC5q2G2pxT0_0 bus +LDEju5sQWOU_1 bear +LDH_eiO0aFE_0 boat +LDJ9xB-n5Sg_0 dog +LDJ9xB-n5Sg_1 dog +LDQiOOCMhs4_0 truck +LDQqhsLKyjs_0 train +LDYFndJjRGA_0 skateboard +LDgpZlJ_QYM_0 boat +LDh-8GoBSLw_0 bear +LDlR_gDbVFk_0 airplane +LDvN2rB8p44_0 train +LD-8yzPoOIQ_0 car +LD-8yzPoOIQ_1 car +LD-8yzPoOIQ_2 car +LEH61oMv2So_1 train +LEIkLV_S5yA_0 cat +LEP6ZOl5iw0_0 horse +LEUCQjNIm9E_0 knife +LEYBNQUwruU_0 dog +LEiolk6i9RI_0 horse +LEmU61Tdqxs_1 motorcycle +LEverFsHygc_1 airplane +LE2ks85I17U_0 bird +LFDqskJozig_1 skateboard +LFMUePhHPAk_1 car +LFZYYpjP3FA_0 knife +LF4xVBfV5SI_1 bird +LGRkVRP-RTs_0 car +LGgzD_ng3aA_1 bear +LGrMlBi0l6Y_1 boat +LGuSLUeKcTo_0 bird +LG0w1oTdXgY_0 bird +LHEuYW96FG0_0 bear +LHEuYW96FG0_4 bear +LHbVe_bjGp0_2 dog +LHbVe_bjGp0_0 dog +LHbVe_bjGp0_1 dog +LHmvAqv6kYE_0 zebra +jFneoJr36o8_0 car +jGCw13fkf0Q_2 motorcycle +jGPtq4pO8Ug_0 car +jGTNsTUkNUw_0 cat +jGTr1LSaGGw_1 bicycle +jGTr1LSaGGw_2 bicycle +jGTr1LSaGGw_0 bicycle +jGlNsqDOz8Y_0 horse +jGqRX9IwGI0_8 bear +jHK3JYa_Ypg_0 umbrella +jHM867g1K8k_1 horse +jHM867g1K8k_0 person +jHy5deaCjQE_0 dog +jH_YxkU_JwE_0 motorcycle +jINuUqU6sJI_0 dog +jIP9FdmB0_E_0 train +jIbmC5sed8I_1 airplane +jIjEX8I5SHo_1 bird +jIjEX8I5SHo_2 bird +jInMbuzvtiQ_0 umbrella +jInMbuzvtiQ_1 umbrella +jI0xgoZ8QDA_0 boat +jI1Swlwj_wc_0 horse +jJMefDe4r9w_1 skateboard +jJR-emvmi9s_0 bear +jJR-emvmi9s_1 bear +jJf_N_p-Gjo_1 skateboard +jJnz3tS1uME_0 motorcycle +jKBU4c1AdSQ_0 cat +jKv6Q1RRxVM_1 boat +jLBSOa5iDgE_0 horse +jLR7LmbNekc_0 motorcycle +jLXuZdAveV0_2 boat +jLXuZdAveV0_0 boat +jMNaKigE1eI_0 truck +jMNaKigE1eI_1 truck +jMVeJ3RbcH4_0 car +jMaYIgpjxlk_0 dog +jMmjaxXWaUk_1 bus +jMo01X2mBq0_0 bus +jM79QETqts8_1 horse +jNCq29f3J8Y_0 airplane +jNE_FcqbQN8_0 motorcycle +jNJJgAg79KA_1 airplane +jNJJgAg79KA_0 airplane +jNKO9msLe34_1 airplane +jNKO9msLe34_0 airplane +jNSTcIQwl_g_3 train +jNSTcIQwl_g_1 train +jNSTcIQwl_g_2 train +jNllRQ66Re4_3 dog +jNn7v2MFg_U_0 truck +jNsEePln1_U_0 bird +jNsEePln1_U_1 bird +jNt8Vn-WKRI_1 horse +jN-BXoM15Qs_0 cat +jOQ0W0Z_-Uo_0 dog +jOl4m5QdOZQ_0 bus +jPaVdR2IRu8_0 airplane +jPiVFMGvHbM_0 train +jPiVFMGvHbM_1 train +jPrY_Xz0CDM_0 knife +jP5RhcwO4E4_1 dog +jP7mwBStU3w_0 dog +jQBc1CqjGOk_0 skateboard +jQCrA8Bjbp8_0 bird +jQXYSlXk7_c_3 bear +jQXYSlXk7_c_1 bear +jRIy_wUojcs_0 car +jRR6sU59uTo_0 airplane +jRTkny0bdY0_2 motorcycle +jRTkny0bdY0_1 motorcycle +jRh5WphQGDI_0 horse +jRqdnQ8HlwQ_0 airplane +jR7eq8CAmbs_0 airplane +jR-Cbp3qBJI_2 horse +jR-Cbp3qBJI_0 horse +jSS6b2iz2hk_0 knife +jSk-3X-hjyg_1 knife +jStwl7WfsVE_0 skateboard +jTAz5HO8mQw_0 cat +jTHDoLyfTLc_0 dog +jTQ5A95TKw8_0 cat +jTYsK4JKns8_0 giraffe +jT1mDaHStHU_0 train +jUDnkkvVKNo_0 airplane +LIw68irBLtE_3 airplane +LIzgqx7Ykxw_0 airplane +LI286rLHd0I_0 bird +LJGQA810BtE_0 bus +LJJuw5mLJ4Q_0 skateboard +LJhCGLht3Rw_0 train +LJhCGLht3Rw_1 train +LKe9a7L3vkk_0 bird +LKhjmARDv7k_4 bear +LKhjmARDv7k_6 bear +LKoaXogFTbc_0 dog +LKyQ2fBNVmw_3 skateboard +LK2-EMocZQs_6 dog +LK2-EMocZQs_1 dog +LK2-EMocZQs_3 dog +LK9zoUrrEHc_0 skateboard +LLJiqe0d06I_0 train +LLOwSRx9hxo_0 bird +LLVr7tG42kw_0 motorcycle +LLW1jx3S-Hw_0 train +LLjDNseEw0c_0 skateboard +LL_DiAJ71rc_0 bird +LMGo4BXG4Yw_8 knife +LMRH29tlDrM_0 cat +LMrDuKEYJ3k_0 truck +LM1djNtENzA_0 cat +LNQHybwdHRk_0 airplane +LNX244qUx7M_0 dog +LNntRLW2bHA_3 skateboard +LNntRLW2bHA_0 skateboard +LNntRLW2bHA_2 skateboard +LN6DT1DOaTg_5 skateboard +LOBD9yc5YPM_1 skateboard +LOMTlGqGyHc_0 motorcycle +LOjc-npcSjs_0 airplane +LOjc-npcSjs_2 airplane +LOjc-npcSjs_4 airplane +LOjc-npcSjs_9 airplane +LOlUKQgr7Qg_0 boat +LOosqz3z8Xw_0 train +LOzh9vxSHPg_0 dog +LPQv6LdOZHo_2 motorcycle +LPQv6LdOZHo_1 motorcycle +LPZjxIqs8Uw_2 airplane +LPd_Y8gk5uI_1 train +LPgmaebC-L0_2 boat +LPtcpZXDhHw_0 knife +LPvsAAlZI_8_1 bus +LP3a2L1ZCyg_2 dog +LP8dyCxmCrI_2 train +LQAF34GzpMY_0 airplane +LQO68Aj4ons_0 car +LQRuelaTZd4_0 bear +LQRuelaTZd4_1 bear +LQT4GnnPhA8_1 dog +LQbQVeZrwEk_0 motorcycle +LQdP4gNX9Aw_0 bird +LQjzonTrY2o_0 bear +LQr5vK-X1fQ_0 cat +LQ2EDJSNIN0_1 dog +LQ2EDJSNIN0_3 dog +LQ4z96EA6co_2 bird +LRSii99-QIo_1 zebra +LRgsl5_TJVg_2 skateboard +LRgsl5_TJVg_0 skateboard +LRgsl5_TJVg_1 skateboard +LRtLr32oPAw_0 skateboard +LR7IHIbXtrE_0 bird +LSE0KHhFxps_0 train +LSMKaXjXnhE_1 boat +LSi1i5lSUjA_0 dog +LSqIpguEI04_0 motorcycle +LSqIpguEI04_1 motorcycle +LSvVMD-SF48_1 bus +LS8qQoB3Uw8_0 dog +LS8qQoB3Uw8_1 dog +LTEyQSswTVI_0 bus +LTQPc_WVFOw_0 airplane +LTQPc_WVFOw_1 airplane +LTQPc_WVFOw_2 airplane +LTQPc_WVFOw_3 airplane +LTaExiLK2S0_2 bear +LTaExiLK2S0_3 bear +LTaExiLK2S0_4 bear +LTaExiLK2S0_6 bear +LTaExiLK2S0_7 bear +LTjSA_-Q5DU_1 knife +LTkuM5IoNV4_0 motorcycle +LUCDeZOOhlg_0 cat +LUUYKUhaYZs_0 bus +LUjqWGI9KSo_2 truck +LUphe242a5g_0 train +LU4-QjhixQU_0 motorcycle +LU4-QjhixQU_1 motorcycle +LU__7PPUMTo_0 skateboard +LVCMA3LXlkc_0 airplane +LVfXvn7elFI_0 person +LVfrWLnu7T8_0 train +LWHshdXjBCY_0 truck +LWQhidgjZno_0 motorcycle +LWRXboX1o5Y_0 motorcycle +LWTYrbFCPl0_0 dog +LWY9Y2YVtHA_1 truck +jUQUg-qsfgI_0 motorcycle +jUWm1Mc1Tno_0 airplane +jVEM2JpS4sE_0 truck +jVZhyibQ31g_0 cat +jV9-Lr_rsf0_0 bicycle +jWCpff7m0LE_1 airplane +jWCpff7m0LE_8 airplane +jWCpff7m0LE_0 airplane +jWCpff7m0LE_2 airplane +jWCpff7m0LE_10 airplane +jWGulD3X0qw_0 car +jWIFscsXRmo_0 skateboard +jWLv1BQ4PsA_0 bear +jWawsbm6dCc_0 bear +jWfItNlOURk_0 motorcycle +jWfItNlOURk_1 motorcycle +jWruD-mHxrQ_0 cat +jW4VRs_uVZw_2 airplane +jW4VRs_uVZw_5 airplane +jW4VRs_uVZw_0 airplane +jW4VRs_uVZw_4 airplane +jXBBnV6cop0_0 car +jXDxesHRKAc_0 umbrella +jXLUgu4rET0_1 cat +jXkzrsfYgbs_0 dog +jX84bwkb-r0_3 bus +jYBgSw-woGw_2 bear +jYIWAGlIq9c_0 skateboard +jYZmjlzKhL8_1 skateboard +jYhAd9FFxqI_0 umbrella +jY37CiJCKJk_0 cat +jY9ihstGQwU_0 cat +jZWITYFghgA_0 cat +jZZBR49_vR0_0 motorcycle +jZiuOZwq7gQ_0 motorcycle +jaS19NIXdrk_0 motorcycle +jaVgyhuxK_4_3 skateboard +jaVgyhuxK_4_0 skateboard +jalIqFA40pI_1 motorcycle +jalIqFA40pI_2 motorcycle +jaoXgM9c7u4_1 car +jaovVHNORuA_0 cat +jauLT1ElBPc_1 train +jauLT1ElBPc_2 train +jbN4y-wz5-s_13 giraffe +jbN4y-wz5-s_1 giraffe +jbN4y-wz5-s_4 giraffe +jbN4y-wz5-s_5 giraffe +jbN4y-wz5-s_11 giraffe +jbhxM5eNgO0_0 train +jboQE0Z0280_0 truck +jbrhKjPDzhE_1 train +jbwSKNFH66s_0 dog +jb23jXcxaHE_1 train +jb23jXcxaHE_2 train +jb23jXcxaHE_8 train +jb23jXcxaHE_9 train +jb3uct7NumU_0 train +jb4crk58m88_0 skateboard +jb4672rSRIs_0 dog +jcLbvoEUbj0_0 airplane +jc2fijpD8vI_0 bicycle +jc-IKl7He7U_0 knife +jduOxfYHRGQ_0 person +jeBcjSSkUhw_0 cat +jeFFdyPLUts_1 boat +jeWf_4ARan0_1 bicycle +je8cw_bajbc_1 cat +jfENtrpYNKE_2 bear +jfENtrpYNKE_1 bear +jfixAXjax5I_1 motorcycle +jfixAXjax5I_2 motorcycle +jfixAXjax5I_0 person +jgAt3qPg7A8_2 truck +jgD77Vh-X28_0 motorcycle +jgGLyRuFOdk_0 bus +jglg4qcOpWw_0 skateboard +jg7I2TXyQ2Y_2 bus +jhQ4iIJ42Yw_0 cat +jhSH0EjNy0k_0 car +jhjKdc7FtE0_5 airplane +jiAVTB1keAQ_0 bicycle +jiCp6fAMISg_0 cat +jiJWjndM8hI_0 knife +jjDZnXMMhEA_0 train +jjKsYbTw1qk_0 truck +jjNxX05CDNc_0 bird +LWv0LbGIDi8_0 car +LWxkJ4fux_I_0 knife +LWy-Lhb3YEk_0 bear +LWy-Lhb3YEk_1 bear +LW3bZPt1qrw_5 boat +LW7XQWZjBIw_0 dog +LXLI-Bzcsf4_2 knife +LXLmpEVYE5E_0 train +LXgItdZ5DXo_0 airplane +LYLuXQRCIJ4_0 car +LYXMPTRr40M_0 dog +LYXMPTRr40M_2 dog +LYmsSNBP634_0 knife +LY-hwswMG4g_0 cat +LZJjKCpcAWA_1 knife +LZ_qufxYP3I_0 cat +LaA51BrvHGw_1 truck +LaA51BrvHGw_2 truck +Lam8oTdJids_0 car +LanX2twvMmw_1 airplane +LanX2twvMmw_0 airplane +Lan3os3aUl8_0 boat +LbC7nqh0Uyg_2 train +LbEPmGgzUIE_0 truck +LbvEMq_DQTU_1 train +Lbv8FZelQCM_0 truck +LcD_I0Lkw3k_0 train +LcD_I0Lkw3k_2 train +LceJwFxs3q8_0 dog +LdEeXsYfzE0_0 car +LdLtHx09mII_0 skateboard +LdL-cFGaJqU_0 bird +LdRX8-r4Cpc_0 car +LdggIc_gAew_0 motorcycle +LeAl87F6eS0_2 umbrella +LeOCD9rZsSI_0 bird +LeX-zqgzN3k_1 bird +LeljDmw2CGU_0 skateboard +LfAbAKrmMq0_6 giraffe +LfAbAKrmMq0_7 giraffe +LfAbAKrmMq0_1 giraffe +LfatUu2cH3Y_0 car +LfbQRAjsucU_0 cat +Lf5ebV_NH78_0 train +LgVi03EiPlQ_2 train +LgVi03EiPlQ_0 train +LgZrI3dxws4_0 motorcycle +LgrPr2OxWcw_0 giraffe +Lgyj-vOk72M_0 umbrella +LhdXtQ8SbGE_1 bird +LhgyObbNmLI_0 bus +LhhzzaKmVO4_2 motorcycle +Lhm6JF_1lQg_1 train +LhnNboAgtNg_0 cat +LhtrfEijGHU_0 airplane +LiMriWExmQM_0 boat +LiZxvVZfUdU_2 umbrella +LiwliE18fA4_0 motorcycle +LiwliE18fA4_1 motorcycle +LiwliE18fA4_2 motorcycle +Lizh5Kae5Nk_2 knife +Lizh5Kae5Nk_4 knife +LiznFL6_r2A_0 motorcycle +LjLWamF9HyA_0 giraffe +LjjGe9bnQ3Q_0 train +Lj0zBxRWoIU_0 skateboard +LkFbAjpWRAw_1 giraffe +LkFlT3d8MuQ_0 airplane +LkmioXgRyo4_0 cat +Lk7Z-AUDCuQ_0 cat +LlA5ioDqRns_2 bus +LlA5ioDqRns_1 bus +LlNCPsiSjOU_0 airplane +LlS3_VvB4Nw_0 truck +LlfRY71K2AU_0 truck +LliRBHO1A_E_0 train +LlplZ9JJtQw_0 dog +LlplZ9JJtQw_2 dog +LmFx-lJ6-_M_1 truck +LmR0Ur4owgw_0 bicycle +LmT8BFH5c7k_0 umbrella +LmYKmKucl28_0 truck +Lm4mghtFu-I_0 train +Lm5GStt7KBw_0 truck +Lm5GStt7KBw_1 truck +LnGeYd1AsoA_1 bicycle +LnKLql5jAXo_0 train +LnLlD-mNTtE_0 bear +LnPyjqgA37I_0 giraffe +LndUw9o_3ME_0 skateboard +LnhmeU6oRBE_0 bus +Lntuuj_mi9c_3 knife +LnyfbZ7-fP4_1 umbrella +LnyfbZ7-fP4_0 umbrella +LnyfbZ7-fP4_2 umbrella +LnyfbZ7-fP4_3 umbrella +Ln_tNsQVuwc_0 dog +LomkA_DJyEM_1 bird +Lo2GqBe8-Qc_0 bus +Lo8Q0MdVi9A_1 bear +Lo8ZEKusM1o_0 dog +LpXfY3oQDIc_0 skateboard +LpXfY3oQDIc_1 skateboard +LpnkxmohHZ8_1 airplane +Lpt6bE36Uuw_0 train +Lpt8i9V2MK0_1 train +Lp88aaB29zE_0 zebra +LqOv_DqIWEk_0 boat +Lqf8Q1pPNFg_1 knife +LrIVNsObdso_0 bird +LrKKU5rjq38_2 zebra +Lr-9DI7T7JE_0 bird +Lr-9DI7T7JE_6 bird +LsdHOclMPh4_0 dog +LshP_zqoBc0_0 knife +LsuQhEjteSE_0 dog +LtGXT385l_I_1 dog +LtabCE1oaCw_0 bird +Ltt24ke9SIA_0 bicycle +LtyHCo5uPrQ_0 umbrella +LuA9aRIic7s_1 bird +LuM1ie5yy70_1 umbrella +LuM1ie5yy70_3 umbrella +LuQiLJ7-B-8_0 cat +LuQxQm7FqD0_0 cat +Lua1id9drCA_1 giraffe +Luv05fYUS1Y_0 skateboard +Lu6WLASNWIM_0 truck +Lu6rn2EQSEM_0 motorcycle +Lu6rn2EQSEM_2 motorcycle +LvPDEznT9Yo_1 bird +LvgprOdn070_2 truck +LvhxnDPWfXw_0 knife +Lvv3Ei45X_4_1 knife +Lvz3fP96sew_0 dog +Lv7JaIYWXV4_1 dog +Lv8u2aPVHmc_2 bird +LwChAirlUno_0 skateboard +LwMepJ25LgQ_0 bear +LwPB4qPCelk_2 car +LwPB4qPCelk_0 car +LwgyjrFlc5M_0 bicycle +LwiTfwL3bCs_0 car +LxAhZAbzn7k_2 bird +LxjlAGLccRw_0 motorcycle +Lxlu3NusDCM_0 bicycle +Lx0IybSITTc_0 boat +Lx25sZ_GeqA_0 motorcycle +LyOo_B0KLAs_0 car +LyReFCR-oq8_1 bicycle +LyReFCR-oq8_0 bicycle +LyiT3ute8W0_0 bird +LyiT3ute8W0_1 bird +LyiT3ute8W0_3 bird +LyiT3ute8W0_4 bird +LyiT3ute8W0_5 bird +Ly-uIzZCdn0_1 bus +LzMxggGTH1I_0 motorcycle +LzP0t153jKw_0 skateboard +LzY_TxIbKpw_0 train +Lzk6uj8FMsE_0 cat +Lzp-Yej0-7E_1 bird +LztNNlg_fXs_0 knife +Lz0Gxxs0FUE_2 bus +L0IXFlnu6Qg_0 motorcycle +L0US3Aiu1q0_0 truck +L0kRKO8zzsI_0 bird +L0kRKO8zzsI_3 bird +L0kRKO8zzsI_1 bird +L1EZ_RVwD8E_0 cat +L1LQOPj7NBs_0 truck +L1U2YrjRao0_0 bear +L1VgJBGpBz8_0 bird +L1iiOGDSByA_0 motorcycle +L19ZzBwAHrU_0 knife +L1_86Xd176w_3 knife +L2Efv5kJpc0_0 skateboard +L2FE5Lr0wnY_3 bicycle +L2FE5Lr0wnY_4 bicycle +jjZl3tMuO6w_0 dog +jjcoVigCzgg_0 skateboard +jjk9P9gQq3E_0 bus +jj-p0K2XoQY_0 boat +jj_pv9SFrnU_1 umbrella +jj_pv9SFrnU_0 umbrella +jkGvuOC8azU_0 motorcycle +jkGvuOC8azU_1 motorcycle +jkKU7T0wpj4_0 bus +jkdEq1MRNws_0 cat +jkkk9vsCYVA_0 car +jkqKyvow-ww_1 skateboard +jkqKyvow-ww_0 skateboard +jk2gGx6dIWA_0 train +jlA3_oF9j-Q_0 motorcycle +jluiJgeyCa4_0 truck +jluiJgeyCa4_1 truck +jlu4Ry8dDus_0 cat +jmXmA9egY4s_0 bird +jmXmA9egY4s_1 bird +jmeVwD4p83w_0 umbrella +jm8AZ0aSF0U_0 motorcycle +jnD_9KMnzpk_2 skateboard +jnD_9KMnzpk_1 skateboard +jnQYikiCbAM_0 bicycle +jnQgVTaiaXk_0 train +jnSm3vCtu1k_0 dog +jnu28BEM2j0_0 bird +jnwQHd-sNW0_0 cat +jous_VGiSK0_0 bicycle +joxEhiwL-qg_1 skateboard +jpBcdceCHgY_0 skateboard +jpCdMdRzmuY_0 cat +jpuFdyVJJwQ_0 motorcycle +jpuFdyVJJwQ_1 motorcycle +jpyidnScqNQ_0 umbrella +jpzKefnhMA4_0 train +jqHtlrHk5Cw_0 dog +jqO4FvS_v54_0 boat +jqRXcc7rPaY_0 cat +jqWXHWqSVX8_0 train +jqu6Gjc1hCE_0 person +jq9ZPuTO7Rc_0 umbrella +jrAyEPgy1LM_1 truck +jrLRiCFtlvY_0 skateboard +jrNGiQLJ0ug_1 train +jrg8oKSN6bk_1 bird +jrg8oKSN6bk_0 bird +jsJprPZCPvA_0 boat +jskm6kDOao0_0 cat +jslKL8yQ7v4_0 bird +jslKL8yQ7v4_1 bird +jsp_sWu7g7Q_1 bear +jsx0cE948y8_2 train +jtQGgQPHofk_0 boat +jtWerSK0atA_0 umbrella +jtqUFmuGnVs_0 person +jtx5yVxuLzA_0 bicycle +jtx5yVxuLzA_2 bicycle +juC5lVOX-R8_0 bear +juC5lVOX-R8_1 bear +juMoEfLbbI4_11 bicycle +juUIMSiDGm0_0 umbrella +juownJlkGfA_0 train +ju08Y0j4rAI_1 car +jvKKm9UbcbE_0 cat +jvKqk7Yfq5Q_0 truck +jvdYM-W5Kmo_2 bear +jvxjOOQa_JQ_3 truck +jwxSjxJVyOc_0 dog +jxIyftPYPsc_0 cat +jxIyftPYPsc_1 cat +jxlDJ0D2Tec_0 bicycle +jxn5iX8buaE_0 truck +L2XOsdnKegA_0 dog +L2bV5Mh6tLM_0 dog +L2e6nVyZ33k_0 car +L2gSKheIL48_0 dog +L2zsyBTtcqE_0 bird +L21bM4j4bEc_0 motorcycle +L21bM4j4bEc_4 motorcycle +L21sWlIIkHA_1 skateboard +L28I6_ASmq0_0 motorcycle +L3F2ir5MPj4_3 skateboard +L3Q42kZ8Ap8_0 bus +L3oyk4iYySM_0 boat +L3urWJiuom8_0 bear +L32hlxmCYZU_3 bicycle +L32hlxmCYZU_6 bicycle +L32hlxmCYZU_7 bicycle +L32hlxmCYZU_14 bicycle +L4NZ3vAx87A_0 boat +L4kK9gTKA3Q_2 bear +L4w-P2UsvBE_0 bird +L5VC4bXm6Kc_0 dog +L508o9A8028_0 bicycle +L52ZiKJ5NLM_0 truck +L5499EWzDaQ_0 motorcycle +L6QaXTuDftA_0 bird +L6vLixMpRZg_1 dog +L6vLixMpRZg_0 person +L63p00d7BPY_0 car +L7TR8yCVhN0_0 cat +L7ZTQMPeHYo_1 knife +L7iHAg6bHw4_0 bicycle +L7rQQ4IVPrU_1 skateboard +L70Zv9DFAhc_0 skateboard +L71JgB-L1mA_0 motorcycle +L779-Nw9GV4_0 cat +L780lAoEC2M_0 giraffe +L780lAoEC2M_1 giraffe +L8H_7qqaEOM_1 motorcycle +L8SF7xF6Ucs_8 bird +L8h9dw2kYRA_2 knife +L9EAUBlNvLU_1 truck +L9LWOPIuvcE_0 train +L9L-OlYNdL0_6 knife +L9Tx4-RNDqo_2 motorcycle +L9Tx4-RNDqo_3 motorcycle +L9Tx4-RNDqo_1 motorcycle +L9Vt1klujtA_0 dog +L90g72YGdVA_0 cat +L97eqv7bBCE_0 dog +L985IUAQ8u8_1 skateboard +L-S4CNhlvlM_0 cat +L-w35NTF7vA_0 car +L-0JgkugTvw_0 giraffe +L_AcMGC96O8_0 motorcycle +L_ZdaWupJcU_1 boat +L_xPWB4viT8_1 dog +L_xPWB4viT8_0 dog +MAJonEdmXNA_0 truck +MAVqUxAjlbg_0 skateboard +MBAPF4RVq7E_0 car +MBLHIupmPNk_2 truck +MBLHIupmPNk_5 truck +MBl4bkFRZUY_2 truck +MBl4bkFRZUY_0 truck +MBuwlS32gjE_0 dog +MC8Lal5Lp5Y_0 cat +MC-KkFD07Ts_0 dog +MDxAuy6D1ks_0 skateboard +MD5P0EFFnUQ_1 skateboard +MD8RTKTEaM0_1 motorcycle +MEi_ikuUJoQ_0 skateboard +ME0CETCuaK0_0 boat +jyY5W5HiWUQ_1 cat +jyeqCulSuVM_0 truck +jy_Dr_R-svo_1 umbrella +jy_Dr_R-svo_3 umbrella +jzRWRRcWffo_0 skateboard +j0BXwDs11NY_0 train +j0OALCZbAJQ_0 bus +j0ii12pbeag_0 knife +j0yk2O6HAHA_0 bird +j0_9iwi_dm8_0 dog +j1CQLHBLwew_0 car +j1NePJe1agU_0 bird +j1XwtnPy1Ik_1 bear +j1rU13Z_fxc_0 bicycle +j1utZs4pDTc_0 bicycle +j10ev-4-0Fg_0 motorcycle +j11_jPnp4Pc_0 cat +j2-VEpDwbyo_0 dog +j3X6elDpZ-Q_0 bicycle +j4K9kM9p16o_1 bear +j4Qv6RH4lPk_1 bird +j4U8EcQ8K34_0 umbrella +j4daTphUuBw_0 cat +j4mpJ3QE8VU_1 cat +j4ofs57G2Uk_0 skateboard +j4rMKhohDps_0 bicycle +j4zZbJTAcC4_0 train +j4zZbJTAcC4_1 train +j5EP2UNErRE_0 dog +j5Evt1HJ2ck_0 skateboard +j5ayq3AbImg_2 bird +j5uxE5IUOhk_0 dog +j6GdrMPrcNU_0 train +j6P1j6Ed1Hg_0 boat +j6Ybo1yk-lE_0 motorcycle +j7v1htyJtdo_1 boat +j7v1htyJtdo_2 boat +j7xvqf1mrUo_2 bird +j707fRdtbEE_0 train +j8jip_gthjs_0 train +j8s5sMFYoiM_3 train +j8s5sMFYoiM_1 train +j82ZCaABxl8_0 truck +j8-maioFCxo_2 boat +j924hdZilyY_0 cat +j-MwElKg8Tw_0 cat +j-VN0PFvkDg_0 train +j-a26pZGsKA_5 bicycle +j-r3lQdwYeI_0 boat +j-r3lQdwYeI_3 boat +j-x8lbwsObQ_0 motorcycle +j-0kVn7sEvQ_0 motorcycle +j-0-IDS-OD4_1 truck +j_DE_vsqSZg_0 motorcycle +j_D7oxUpZqs_0 bicycle +j_D7oxUpZqs_1 bicycle +j_FCzH1rLDw_0 train +kABwo7h7ILg_18 bicycle +kABwo7h7ILg_13 bicycle +kANh1n3sh5M_0 giraffe +kANh1n3sh5M_3 giraffe +kAekmn2pgpc_0 skateboard +kAekmn2pgpc_1 skateboard +kAhVhIYl-GE_0 motorcycle +kAhVhIYl-GE_1 motorcycle +MFw-_3fTBzA_0 bicycle +MF06s9T8iJA_0 skateboard +MF06s9T8iJA_1 skateboard +MGFx6Irt70E_0 knife +MGMJ6ocyKXQ_2 boat +MGQw41RhBfc_0 motorcycle +MG9MouhNLjY_1 knife +MG96iokcNoY_0 car +MG96iokcNoY_1 car +MHIEOK-O3Q4_1 bird +MHT9BbNzNJo_0 knife +MHqZCkvaub8_1 car +MHsxwUMk-_s_8 umbrella +MIHg2KAYh5c_0 train +MIHg2KAYh5c_3 train +MIHg2KAYh5c_1 train +MIKCpSFDh4M_0 bear +MIKCpSFDh4M_1 bear +MIKCpSFDh4M_2 bear +MIKCpSFDh4M_3 bear +MInom2mFpwg_0 skateboard +MI2d7Rd8_Zs_9 bicycle +MI2d7Rd8_Zs_10 bicycle +MI2d7Rd8_Zs_2 bicycle +MI2d7Rd8_Zs_4 bicycle +MI2d7Rd8_Zs_5 bicycle +MJOztUhgARo_1 bear +MJvPtT5tzRI_0 motorcycle +MJ3I-JfOG48_0 train +MJ6b6iOY7CI_0 car +MK2aqzY-UTQ_0 cat +MLXY5iff2rU_0 truck +MLZ5bpXr5fk_0 bicycle +MLrWgAcIumk_3 knife +MLrWgAcIumk_1 knife +MLtRUMzqhDk_1 dog +MLwCW5HBfWQ_0 bicycle +MLwCW5HBfWQ_1 bicycle +MLyrsP65yc8_0 cat +MMGw177uo60_8 bicycle +MMGw177uo60_11 bicycle +MMGw177uo60_0 bicycle +MMGw177uo60_1 bicycle +MMGw177uo60_2 bicycle +MMGw177uo60_4 bicycle +MMGw177uo60_6 bicycle +MMX4my6X-xg_0 car +MMfLN7_khoc_0 skateboard +MMwk9bxedYo_1 bird +MMxfwNbWaxc_0 bus +MMxfwNbWaxc_1 bus +MMzNcR3qtX0_0 knife +MM9D2A52FM4_0 cat +MNBfv2S-yco_0 dog +MNDWyaUDfAM_0 truck +MNKwR4IK04k_0 bus +MNnYExmY67E_0 bus +MNnYExmY67E_3 bus +MNuhuq3FP5Q_0 motorcycle +MNuhuq3FP5Q_1 motorcycle +MNuhuq3FP5Q_2 motorcycle +MORtJq8MelU_2 dog +MORtJq8MelU_3 dog +MORtJq8MelU_0 dog +MORtJq8MelU_1 dog +MOR6ErlJIp8_0 giraffe +MOcTGHSkER0_0 car +MOgN13g3SzU_1 motorcycle +MOxIwc0MqZ0_1 car +MO5aNU1mc1s_2 boat +MPQqmw9gvF0_0 dog +MP8ETGMyhnU_0 dog +MQAJWDp31ag_0 cat +MQimJolkMRI_0 cat +MQ5mTW70Ebs_1 train +MRzphcX41T8_0 umbrella +MSWR-YqRwqk_0 cat +MSjYJFNM2HU_0 boat +MSjYJFNM2HU_3 boat +MSonF1662RI_3 skateboard +MSp3-aHmNP4_1 truck +MSp3-aHmNP4_2 truck +MSvmSEk-UJ0_0 bicycle +MSxdHgV7e6o_0 car +MS7Emoy0Foc_1 boat +MTDl42dubw8_0 bear +MTr54KYSQBw_0 person +MTvLNcYmHhQ_0 car +MT-VkX2ZUYs_1 bear +MT-VkX2ZUYs_2 bear +MT_GWiXfC2k_0 knife +MUAuC-rgc9Q_0 dog +MUPAcFVQjlE_0 zebra +kAkZoxVhM3I_4 train +kAkZoxVhM3I_1 train +kAkZoxVhM3I_2 train +kAkZoxVhM3I_3 train +kAmtMpdj5F8_0 dog +kAsA28fm6YM_0 dog +kBZZqBNk68M_0 cat +kBg_1xTx4Dw_0 car +kBsc-5sxeTw_1 knife +kBsc-5sxeTw_3 knife +kCWupS0PNHk_0 car +kC0y-y4Y9zQ_0 knife +kC4_7iM24Uw_0 truck +kC7fdR62Lto_0 person +kDU_m-Zhi-I_2 bicycle +kDsGVRUxg9s_3 bicycle +kDsGVRUxg9s_4 bicycle +kDvYbh9_fvY_0 dog +kDwVR3eWyA4_0 train +kD0shq5M7Xw_1 skateboard +kD_zeOiIsTM_0 train +kEw-F2KrxLQ_0 train +kE3cb1gtxpM_0 person +kFihVzuPlGI_0 truck +kF9uWuyPP8g_0 skateboard +kGB7yQn8jpQ_0 bicycle +kGkvBOa6Ao0_0 motorcycle +kHCbADkGOsE_0 skateboard +kHEfe-TDtS0_0 motorcycle +kHkZCi873e4_1 motorcycle +kH2Vmad_zzc_0 train +kH9YVTvwmpM_0 bicycle +kIGuIdHDwIw_0 truck +kIasEX-cJb8_0 cat +kIqavvGxvh0_0 bird +kIyZZm3zk5M_0 train +kIyZZm3zk5M_1 train +kIyZZm3zk5M_2 train +kI14RuB6ab4_1 boat +kI9E5m5l4Uo_2 bird +kJFQOFR0l0w_0 motorcycle +kJJuX1cGFYg_0 truck +kJJuX1cGFYg_3 truck +kJR59i4f5HA_0 train +kJR59i4f5HA_2 train +kJR59i4f5HA_4 train +kJR59i4f5HA_1 train +kJUDpKKsNQ8_3 boat +kJYZ-XE8ZEQ_0 cat +kJuBcbws_zM_2 car +kJuuymSuBLA_3 boat +kJ2eEJ07dR8_0 cat +kJ4rlYx4HDQ_0 motorcycle +kKJAqMzsMHo_0 train +kKOKJLrWCro_0 motorcycle +kKSyjiL5foc_0 skateboard +kKTvKA8cd-c_0 bird +kKTvKA8cd-c_2 bird +kKeaUBfwuG4_0 dog +kKfiOXnjX0E_1 bird +kKtawdL8xDU_0 umbrella +kLL_YMFYoQw_1 car +kLL_YMFYoQw_3 car +kLgtAl-xGI0_0 bus +kL3r_JUstGU_0 bus +kL7sfsNuNVw_0 giraffe +kL7sfsNuNVw_1 giraffe +kL777xHctO4_0 truck +kMMe5H6THlA_1 boat +kMuQLvHlZM8_1 skateboard +kMuQLvHlZM8_2 skateboard +kM3Ml3gsG1g_0 boat +kM3yM5qONQc_0 person +kNNLDq_wPc4_0 dog +kNQYLVUS5ag_1 train +kNQYLVUS5ag_0 train +kNTqRDpy6Jg_0 bicycle +kNVh6uD0bMs_0 car +kNlVF3ROFLs_0 dog +kOOlwQ0DrQU_1 cat +kOjjXFA4JLo_0 bicycle +kOksVTxs6S0_0 truck +kPEf41FB6w4_2 bear +kPH88UubFMg_0 bird +kPLn0enV644_0 motorcycle +kPPya6oadAk_0 truck +kPSuwjI94G8_1 bus +kP4KkSrY81s_0 motorcycle +kP4KkSrY81s_1 motorcycle +kP7xV2Efw9c_0 car +kQBqt_vvAUc_0 truck +kQHn-cRLiDk_1 cat +MVG65Om9g1k_0 cat +MVG65Om9g1k_1 cat +MVPQRjLFz6E_0 boat +MVRf770zXL0_0 bus +MVZinfPagDI_0 bicycle +MVhsNNsDFWo_0 knife +MVxJBHYueGI_0 boat +MVxJBHYueGI_1 boat +MV5174rsbEY_0 bus +MV-CnX4Gf7A_0 truck +MWGRoXhqRgQ_0 boat +MW78cTfzq0c_0 cat +MXGO41E37k0_1 train +MXVOVBJlezc_1 train +MXW5J8Fq8aw_0 bicycle +MYW0loI0g8M_0 dog +MZJtj9J3P2w_0 knife +MZU8lpmJhxg_0 bus +MZaYMDyaATI_5 skateboard +MZaYMDyaATI_0 skateboard +MZfxKiKSuFU_0 train +MZfxKiKSuFU_1 train +MZfxKiKSuFU_2 train +MZr4cAj7j28_0 motorcycle +MZtheeh470g_0 car +MZxz9C8nBdA_0 bus +MZ4A6ItKCn0_2 knife +MaApAnpbJwE_0 motorcycle +MaNGPVuxXqo_0 bicycle +MaUrOzoC1qE_0 motorcycle +MaV9LY8Yf7c_1 skateboard +MaeWb_sv_KU_9 bus +MaeWb_sv_KU_10 bus +MaeWb_sv_KU_1 bus +MaeWb_sv_KU_7 bus +MaeWb_sv_KU_8 bus +MalEpweFuSM_0 motorcycle +MarA93dcZrA_0 train +MbCJqlLjY_o_2 knife +MbK94OERQUw_1 bicycle +MbK-28LCQ1g_0 boat +McV3_FGrKNw_1 boat +MccB4r2uPG8_2 bus +MctKaOAWQ2g_0 skateboard +Mc_qufFsRZQ_0 train +MdP8tqMgy-c_0 boat +MdcfoMlgxyI_0 boat +MdcfoMlgxyI_7 boat +MdcfoMlgxyI_6 boat +MeGIovLiBUs_0 cat +MeNT1BqRoSk_0 skateboard +MeR6T05EfeY_4 train +MeR6T05EfeY_5 train +MedPaDPXclw_0 train +Me6y3gzfhGA_1 cat +Me7wQZBbtkw_1 truck +Me9X6zA_WSI_2 car +Me9X6zA_WSI_3 car +Me9X6zA_WSI_0 car +Me9X6zA_WSI_1 car +MfEA9RwWf8s_1 car +MfKpwmhyptQ_6 knife +MfQe_WreL6U_0 cat +MfVLnZLXmvw_0 boat +MfYYHsKxgn0_0 cat +MfYYHsKxgn0_1 cat +MfaYiIkR0D8_10 dog +Mfe3mmOd7co_0 skateboard +MflUSzEyPQA_0 dog +Mf1njOx66R4_0 knife +Mf1njOx66R4_1 knife +MgR0ON5CM-E_1 dog +MgR0ON5CM-E_0 dog +Mg7Ve43Durw_0 zebra +Mg9oRrgGKv0_0 skateboard +MhFgGvNvIPU_1 motorcycle +MhOdsv74XK4_0 bicycle +MhPIl5JGvTQ_2 dog +MhdkxaMWwb4_0 dog +MhfYe7VajGQ_1 train +MijD0ZqMorA_3 bear +MijD0ZqMorA_4 bear +MixmJ2mkl18_5 motorcycle +kQhvp8FqRRI_0 motorcycle +kQ0WAbN3uvE_2 bicycle +kQ0qYUhkgXE_0 zebra +kQ0qYUhkgXE_2 zebra +kQ27FYyayCg_0 umbrella +kQ9C8T343Bg_0 umbrella +kQ97WPM3Qw4_0 skateboard +kROqNf1kadg_0 bicycle +kRWaghM9Bng_4 knife +kRYejzNzz-k_0 bird +kRYejzNzz-k_2 bird +kRYejzNzz-k_5 bird +kRtAJBnrb0o_0 cat +kSnUCbQ4k4c_1 giraffe +kSxPGqWydhQ_0 car +kSxPGqWydhQ_1 car +kTBAPJCn4AI_1 car +kTNOY900Hbk_0 cat +kTVuc-2UjPI_0 umbrella +kTbS3XR-Xhc_7 bear +kTdT3aGZVmo_0 train +kTm1R3GaJzg_1 umbrella +kTyJyGREDR8_0 boat +kUX28ytNCwc_0 car +kUcErGH2rjs_0 dog +kU8IsLpAlXg_0 motorcycle +kU8IsLpAlXg_1 motorcycle +kVCic6S6ITo_0 knife +kVmUxntjOEk_1 skateboard +kVxw5-K9zZk_0 motorcycle +kVyJVrTWLwo_0 cat +kVzNGKIHA44_5 giraffe +kVzNGKIHA44_2 giraffe +kVzNGKIHA44_3 giraffe +kVzNGKIHA44_4 giraffe +kWHw0OdDAes_0 boat +kWHw0OdDAes_1 boat +kWo2PlJB2Nc_0 motorcycle +kWxJX4oVzMo_3 train +kXKTNNclCns_0 dog +kXOYPLKJDdI_0 knife +kXOYPLKJDdI_2 knife +kXVHu_jzgek_0 knife +kXj4YpwnHVs_0 car +kXliGVQWoAE_0 motorcycle +kXwzICrP2CA_1 dog +kX-rqtb_n5w_0 boat +kYAGyQOUOAw_5 train +kYAGyQOUOAw_6 train +kYAGyQOUOAw_9 train +kYRvBDpWk_0_0 skateboard +kYd1dxkZ7Q8_0 dog +kYh89aM71_c_0 bicycle +kYie2clM8Jg_0 motorcycle +kYjiRbFWFuE_0 umbrella +kYwzLhWdjYc_0 bird +kY1mYWiL24M_2 train +kY1mYWiL24M_11 train +kY1mYWiL24M_0 train +kY1mYWiL24M_1 train +kY1mYWiL24M_3 train +kY1mYWiL24M_4 train +kY1mYWiL24M_5 train +kY9lrTOcuxY_1 knife +kZNZbhh6P3g_0 cat +kZrG7mMww7I_0 truck +kZrgKUm3pUs_0 boat +kZ1L8FBg_P4_0 cat +kZ3A6bY6RHo_0 motorcycle +kaKhLfdT3z4_0 truck +kaNpALWiNSQ_0 car +kadq7fGv_zg_1 motorcycle +kao854-T3zw_0 bear +kaxFMN_9CfM_0 bear +kaxFMN_9CfM_1 bear +kazbC0JbsUY_1 boat +kazbC0JbsUY_0 boat +ka1HMN9Mxho_1 car +ka8YGdEujsQ_0 motorcycle +kbEenS2dRTc_0 cat +kbF3h-YQ7m8_0 skateboard +kbuWFd9Vthc_1 umbrella +kb2LQHXd2zk_0 car +kb-A8wbnvQg_0 bicycle +kcBIvi6fhUo_1 bus +kcTwHA-N1cg_0 bird +kcip1032v3E_1 skateboard +kco1LYK4z_w_0 person +kdIBzH30zKA_0 dog +kdIBzH30zKA_1 dog +kdP5V_afg7E_0 skateboard +kdRLqCUbWts_0 bird +kdUrK5I-cNo_0 car +kdU-XJEwZsQ_1 bird +kd3DLyL1JMw_0 bicycle +keGrBBWcGE4_1 bus +keGrBBWcGE4_0 bus +kePvCa53REA_0 giraffe +kePvCa53REA_1 giraffe +kea2UOTXlhs_0 cat +kea4eM8Blz8_0 dog +ketFGT3U5D0_0 bicycle +kexKkPOprms_0 cat +ke3yWKL94kE_0 skateboard +Mi4HJYsPBPk_0 skateboard +MjGAi_5coGY_0 bicycle +MjGAi_5coGY_7 bicycle +MjGAi_5coGY_5 bicycle +MjGAi_5coGY_6 bicycle +MjxkMQcgRss_1 car +MkF-jfvzRJU_0 bus +MkGLvilh-P4_2 dog +MkIK8kdqU2I_0 motorcycle +MkQzgwai9zk_0 zebra +MkYtT0L4_3A_0 truck +MktDGOflp1w_0 truck +MktDGOflp1w_1 truck +Mk82qF_xfzI_1 motorcycle +Mk9tGnGNkkE_0 bird +MlLHwysBUiY_0 knife +MlVr20XSJMY_1 dog +MmQIeOEPu9g_2 skateboard +MmQIeOEPu9g_0 skateboard +MmQIeOEPu9g_1 skateboard +MnE1EjTWbTA_2 skateboard +MnGGl7pusvI_0 motorcycle +MnGGl7pusvI_1 motorcycle +Mnd7aZxjoEg_0 bird +Mnvqegl_fME_1 car +Mnvqegl_fME_3 car +Mnvqegl_fME_8 car +MnyV8-43fRY_0 bicycle +Mn2Nul_w66I_1 motorcycle +Mn2Nul_w66I_3 motorcycle +Mn2_fRbVluE_0 knife +MoHDZuwBO4E_0 cat +Mog-qUf6B1c_1 cat +Mo6Q7lGmAw0_0 skateboard +Mp42DoVxbWY_0 motorcycle +Mp91b_edytM_1 dog +Mp91b_edytM_0 dog +MqAlMygAZto_0 cat +MqPKFAIxZpE_0 dog +MqlxERdGjdg_0 motorcycle +MqvfJOEW4oE_0 cat +MrsXy6DL4DA_0 truck +MrssB6CtGrM_1 giraffe +MrvbaDZm6gY_7 knife +MrvbaDZm6gY_8 knife +Mrwi7WoPJSs_0 cat +MrxYHk0ghfM_0 boat +Mr1A4et0ESg_0 bird +MsFvL8N-3ds_0 umbrella +MsQJkEOyREY_0 bicycle +MsY_zz2OeKU_0 motorcycle +Ms8x8pjN7Fw_1 bicycle +Ms8x8pjN7Fw_0 bicycle +MtIjkcXspsU_2 motorcycle +MtfpgvzOlW8_0 person +MtiQjguNpH0_2 boat +MtiQjguNpH0_0 boat +Mt_4bFjyYuU_0 cat +MuLk_dOouJY_0 knife +MuOG8PoK21o_0 bus +MuVtFYK_nH0_0 bird +MuYixry0epc_2 motorcycle +MuYixry0epc_0 motorcycle +MuYixry0epc_1 motorcycle +Mu51W-lkSEc_0 car +MvIYOnRinSo_0 bicycle +MvxRpbl0BBk_0 bus +Mv6v4w7VDFk_1 car +Mv_9l8fWiP4_0 truck +MwAM4o2GCuM_0 car +MwHQb6ZryRA_0 skateboard +MwIKOqSMRwk_0 cat +MwLnGflxcqc_2 zebra +MwNsM6f6fNY_3 bicycle +MwNsM6f6fNY_5 bicycle +MwN7iYEim6k_0 bird +MwW14_GuwLg_1 bus +MwdX3PbgC34_0 giraffe +Mwjq136uMe0_0 car +kfInF5cUU98_0 motorcycle +kfInF5cUU98_1 motorcycle +kfLnoXlGBvU_0 dog +kfhspLhCU5Y_0 cat +kgDOVDDZ9eQ_0 cat +kgONObiF8Hg_0 cat +kgT-NsRkv1c_0 car +kgco3sZv7BY_0 cat +kgi1KajW_ZU_0 truck +kglv-2P5ow4_4 bus +kgrFzgXO9Q8_0 skateboard +kgsyAMgjuL4_0 bus +kgxQ03-tSek_0 bear +kg6RFppR4MM_0 knife +khUURgtFYBY_1 bicycle +khUURgtFYBY_0 bicycle +khVST8w3Zzw_0 skateboard +khlqzkfBCfc_0 cat +khpJlBWPPr4_1 cat +kimZApwsJEY_5 bicycle +kimZApwsJEY_6 bicycle +kimZApwsJEY_0 bicycle +kimZApwsJEY_2 bicycle +kimZApwsJEY_3 bicycle +kimZApwsJEY_4 bicycle +kizrM5CZzPk_0 truck +kjBdTAkRijw_2 bus +kjM0hJl-L44_0 skateboard +kjtOW8OAIeY_0 motorcycle +kkC5lqQb0t0_0 umbrella +kkR7pnou7hc_0 knife +kkeBMT1ixs4_0 boat +kkkc9xwKGp8_1 skateboard +kkvU3dvMkSI_0 truck +kk4KuU5X6Lk_0 car +klGHWdeD-qw_2 bear +kldR5yJFeOo_1 bicycle +kldR5yJFeOo_3 bicycle +klgANznh5x0_1 bicycle +kl2buVrYbX8_0 skateboard +kl3_w8_h6ts_0 skateboard +kl4RYG6OCIY_2 knife +kmZFQEGncaI_2 bicycle +kmZFQEGncaI_0 bicycle +kmllekf2nKc_0 cat +kmoaGUqL6bI_0 skateboard +kmvCtYXRUhM_0 truck +km7aR2fTJlA_2 knife +km-3wnNLVYY_0 boat +knDRZU9u-Lw_1 boat +knVcB-GeINU_0 car +knqi3OAHNO8_0 boat +koOxoaMnXZc_0 skateboard +koOxoaMnXZc_1 skateboard +kphV7yVMBOQ_0 bicycle +kphV7yVMBOQ_2 bicycle +kqDbbFz-XQQ_0 bird +kqDxyoQKFfE_0 cat +kqVaHPJzEro_0 dog +kq4tOnX3m2Y_3 bus +kq4tOnX3m2Y_0 truck +krSKV36ocSs_0 bear +krvyahlS1z4_0 bus +kryv5em-VHk_2 bear +ksB15ebtJeM_0 umbrella +ksCempldLAA_0 skateboard +ksCempldLAA_1 skateboard +ksCjOk8r4rU_0 person +ksSVtTRXRyI_1 bicycle +ksk5uCVKU7Y_0 skateboard +ksxTUcFqlZw_0 knife +ksx219-g47A_0 cat +ktHzii2XMh4_0 boat +ktPLKpH7-mk_5 dog +ktcodoKjIvE_3 bicycle +ktcodoKjIvE_4 bicycle +ktcodoKjIvE_5 bicycle +MwtWyQiagOk_0 bicycle +MwvYg837DFU_0 motorcycle +MxEjkI5fRh0_0 dog +MxHBWltYQX0_0 boat +MxKuZbSiZ4s_0 skateboard +MxK1dXmYQU8_0 knife +Mxr-1toRi3s_0 skateboard +MyS7UVUc55M_0 car +Mybir4gfQaU_3 bird +MzB160hQlFE_9 giraffe +MzB160hQlFE_2 giraffe +MzB160hQlFE_4 giraffe +MzB160hQlFE_5 giraffe +MzB160hQlFE_6 giraffe +MzB160hQlFE_7 giraffe +Mz9ZTHPYJxk_0 dog +M0Ga521uzoA_0 dog +M0qQQArQdTU_0 bird +M088XJeXBS0_0 cat +M1UsEMPrCc4_0 knife +M1cuEQppjNk_0 bus +M1p1DBTuqmk_3 bird +M1p1DBTuqmk_1 bird +M1xxFVktlzw_1 bird +M1zDeqozcU4_1 bus +M2R_9l38IUQ_0 bus +M2uSqd8ohUk_0 bus +M3CUpLmpRBo_0 cat +M3OhLKUgQho_0 cat +M3P38sLk0pc_0 dog +M3tK5YBjyKI_0 truck +M3tK5YBjyKI_1 truck +M3tK5YBjyKI_2 truck +M4CENhQ5vWo_0 cat +M4Hqq89bZiE_1 dog +M40QOQPocV4_1 car +M45MyaeogPU_0 car +M5BEqJFfJYw_0 skateboard +M5NRM7UQv5c_0 cat +M5bLnqKDa1U_0 bear +M5kj9SEKNAo_0 bus +M6POMFHs-ec_0 bus +M6bin6X9FSI_0 knife +M6eRY9q89aQ_2 truck +M6tXmkLy-2Y_1 bird +M7465rUWBzY_1 bicycle +M8Lhm-CgqH4_0 cat +M8cFdveIy4g_0 cat +M8drJLCDOL8_0 cat +M8ea7gWeDQ0_0 bird +M8f0VhN1ZnY_0 umbrella +M8i-DGTEw9M_3 skateboard +M8i-DGTEw9M_1 skateboard +M8sMZ15CLIU_0 skateboard +M9McwXGtZnI_0 cat +M9QtHKxypyI_1 knife +M9UrZSSK1MA_2 motorcycle +M9eiVambl5s_1 dog +kuRfhOqyXeY_0 umbrella +kuzyHmE3SI0_1 knife +ku68PhgE8bk_0 bird +ku7gA5ZLk1Q_0 cat +kvFSzJHIsVg_1 knife +kwDNLBoEQq8_0 skateboard +kwDX0_2B3A0_0 umbrella +kwGGXvXtsjI_0 truck +kwY370WQYUg_0 car +kwbt-wHLPkY_1 car +kwlcEg9G1bE_0 knife +kwsp30ykR4U_0 boat +kxeSYfuQl-I_0 bird +kx1bCqhLcbY_0 bus +kx5tIvM-9dE_0 knife +kyAEyX8zMWQ_0 truck +kyPXCwNh7Rg_0 cat +kyW_f8sv5iw_1 giraffe +kye1Q_k-_Gc_0 bicycle +ky1FAcaT3UE_0 dog +ky6uivneqIg_0 bird +kzblQQcpTdk_0 skateboard +kzblQQcpTdk_1 skateboard +kzfxn1c7_xc_10 bicycle +kzg7y0rERTY_0 bicycle +kzi3zDJR9Bc_0 dog +kzpJkBQxgE0_1 bicycle +kzp3UEwOkJA_0 knife +kzw5a8z9cXs_0 bird +kz6HYpF3pLo_0 dog +k0cUZwgJzB4_0 umbrella +k0uDHQea9sg_1 dog +k00mpKYHsuU_0 skateboard +k1F_TFA3Bbk_0 bicycle +k1LrJEfFKag_0 motorcycle +k1NVg8uaPE4_1 skateboard +k1Q5wms4euk_0 bird +k1TOwPACsvY_2 giraffe +k1TOwPACsvY_3 giraffe +k1vz1ZSBSoo_0 bicycle +k2O0XiVn5kw_0 skateboard +k2QiX8c3t50_0 bird +k2SEBRgras8_3 car +k2Z0W54JwB4_0 skateboard +k2bQG12smw0_0 cat +k2imYphEfo0_0 car +k2ocqQxARpQ_0 skateboard +k2yx7C__3wY_1 cat +k3HKP8CV3CY_0 bus +k3LnBcn5zlU_0 boat +k3QuANDFgVQ_2 boat +k3QuANDFgVQ_3 boat +k3QuANDFgVQ_5 boat +k3fZgTTMj1g_0 giraffe +k3fZgTTMj1g_1 giraffe +k3im7HEvSCI_1 bear +k4D-Ql4Fg7c_1 bird +k4PWQfz5NGo_0 motorcycle +k4U1AP6KV4E_1 skateboard +k4c6D3ZsdL4_0 truck +k5Pp6BYXono_3 bear +k5R3cUyyyWo_0 car +k5nvWBLlS2c_1 boat +k5nvWBLlS2c_2 boat +k5vlZTySXDk_0 knife +k5yJqWnvZzg_1 bus +k5yyV32-nOM_0 motorcycle +k5yyV32-nOM_2 motorcycle +k55nlQZwGz0_1 boat +k57rVPEq54k_1 bear +k57rVPEq54k_2 bear +k6Bwd6af64Y_2 bear +k6gc4du1FqU_0 truck +k6l0hwjaeMA_0 motorcycle +k6l0hwjaeMA_1 motorcycle +k6l0hwjaeMA_2 motorcycle +k60P5osD0rU_0 bus +k64DU45ej5M_6 car +k64DU45ej5M_0 car +k64DU45ej5M_1 car +k64DU45ej5M_2 car +k64DU45ej5M_3 car +k64DU45ej5M_5 car +k640Wtpq-mU_3 umbrella +k640Wtpq-mU_0 umbrella +k640Wtpq-mU_1 umbrella +k7TCyTff1aM_0 truck +k7uTiiG-Ez0_0 bus +M-8Zbj9mU9U_0 boat +M_miIFgy1Ro_0 bear +NAGKrEjU7Sk_3 bird +NAGKrEjU7Sk_2 bird +NAkFaQBgOvo_0 truck +NA9hxGtSLCM_0 bird +NA_DgxP18c4_2 motorcycle +NBE97NAHACk_0 giraffe +NBdhmPgSS2o_1 motorcycle +NCNgKQCU8BM_1 bird +NCP6Cna8jtY_0 skateboard +NCQ5340WhY8_0 car +NCSygygs2Dw_0 skateboard +NCWp95If4uM_0 motorcycle +NCazYWutlOc_0 boat +NCoJmkRt2nE_0 bicycle +NDUhlmH9Rz4_0 cat +NDYT9jTE54Q_0 bus +NDYT9jTE54Q_1 bus +ND_GyhH6zgI_0 motorcycle +NEQIR06VuP4_1 giraffe +NEQOLn6QBuE_8 bird +NESQ70PhJU0_1 boat +NElB9jKqhLc_0 dog +NFjb4XxSoHI_0 skateboard +NFye-cUktCg_0 bicycle +NFz_zzAU_Hc_2 skateboard +NFz_zzAU_Hc_0 skateboard +NFz_zzAU_Hc_1 skateboard +NF_o01qBrtI_0 skateboard +NF_o01qBrtI_1 skateboard +NGCjiEfG4C8_0 skateboard +NGM0enFRa7E_0 car +NGO_7sJEeyk_0 bus +NGRBYn2OatE_0 motorcycle +NGU-5KGKEJ0_0 bear +NGmJtkXyJpc_0 cat +NGmKyRRNL_E_0 bird +NGw5-auup1k_0 car +NG7FgzWn8Gw_1 giraffe +NG9SIDqXvic_0 knife +NHlayOfSZJc_0 dog +NHlsNDcNZqU_0 cat +NHmxckr22ws_0 skateboard +NIPnaoHgzdU_0 bird +NIPnaoHgzdU_1 bird +NIPnaoHgzdU_2 bird +NIvYcbJIYdA_0 cat +NI_YQKOQEvM_1 bird +NJeNAw2RnNc_0 bus +NJeNAw2RnNc_1 bus +NJeNAw2RnNc_3 bus +NJeNAw2RnNc_4 bus +NJ0O48Pkn2k_0 bird +NJ9DpLHaGl8_0 skateboard +NKLemqoJ_hA_0 cat +NK4942wyYgk_0 bus +NLKK4VUbuuI_5 bear +NLp8voZylqM_1 knife +NLsGPrwnRug_1 bus +NLsGPrwnRug_2 bus +NL3CG8KGwis_3 giraffe +NL5j52SH-yQ_0 bus +NL9o4JgV25A_0 dog +NMJB2K_UOLc_0 dog +NMJLv-oYyNc_1 truck +NMJLv-oYyNc_0 truck +NMecCV-gtK8_1 dog +NM7OVTITkaA_0 cat +NNCjf9Qu2RI_0 bear +NNHOtBx0FOY_0 motorcycle +NNkLZRrMEv4_6 boat +NNl4nD5_b_o_0 skateboard +k8NHRbiB2Dc_0 dog +k8OEoDpqSLk_0 truck +k857sWPtmcs_0 cat +k9BuU6A21DQ_0 skateboard +k9HxprAZods_0 umbrella +k9KmR4MNI7o_0 cat +k9KtLV0IMgI_0 dog +k9PCp-8PFZ0_0 dog +k9PX9l8Fnlw_8 bus +k9PX9l8Fnlw_0 bus +k9PX9l8Fnlw_2 bus +k9PX9l8Fnlw_4 bus +k9PX9l8Fnlw_5 bus +k9VDPqCbqj0_0 bear +k9VVUD9wVxk_1 boat +k9zLR7VKKpE_0 skateboard +k9-PLHxxGHc_0 car +k-DOe-pD_MY_0 dog +k-Nl-39bZnw_1 skateboard +k-SqR4BEw3s_4 motorcycle +k-SqR4BEw3s_1 motorcycle +k-izgq4Wj4E_0 dog +k-izgq4Wj4E_1 dog +k_X3oj841SQ_1 motorcycle +k_e_YVhclfg_4 truck +k_e_YVhclfg_3 truck +k_iI2BJQpqo_0 cat +k_jXopyxdo0_1 boat +k_sLp7QKSu8_0 boat +k_tkXRmI_O0_1 skateboard +k_tkXRmI_O0_0 skateboard +k_vnzrtDfAw_1 cat +k_5e1d-vpBU_3 umbrella +k_5e1d-vpBU_4 umbrella +lAA5eXeYwpo_0 cat +lAFonTk_uSA_1 bear +lAI9mfwKMM8_1 dog +lAQxdRz4PlQ_0 bear +lA3btp7QIxg_0 bus +lBH0KOGRswc_0 car +lBXWSN3ciPY_0 motorcycle +lBsOiAR5dAk_2 bird +lBsOiAR5dAk_3 bird +lBsOiAR5dAk_4 bird +lBsOiAR5dAk_7 bird +lBsOiAR5dAk_8 bird +lByHH7yvxpA_0 boat +lB7j8Z4gGtQ_0 car +lB_bnqdnexA_5 bird +lB_bnqdnexA_1 bird +lB_bnqdnexA_4 bird +lCYwepuY9qY_0 truck +lCZry6FRpsk_0 bicycle +lCf6uL_GkYw_2 bear +lC0yidNH6B8_2 bear +lC4BoFWvHs4_3 bear +lDLYtKqlr5M_0 bus +lDf9b9Kr-24_1 truck +lDgzFjqokik_0 boat +lDqk6pRbY3M_0 bus +lDybC3N70so_0 car +lD63JOjqTDg_5 bear +lD63JOjqTDg_9 bear +lD63JOjqTDg_10 bear +lD63JOjqTDg_0 bear +lEG4DGADyEU_0 bird +lEIbERGmlJw_0 umbrella +lEWOScSt-Ks_0 dog +lEaMfPfi9wI_0 truck +lEwJRP_FRW0_0 dog +lFYONMOuW_o_0 truck +lFqrTC4j9AU_0 cat +lF3vWAJRnek_0 motorcycle +lGPyv8wlqaw_1 knife +lGaQV9YhOac_0 motorcycle +lGrVM91Cav8_0 person +lG5xlt4odEs_0 truck +lHKKhuJtJ9A_0 knife +lHXHAD73KC4_0 motorcycle +lHX5VdjDPMg_0 knife +lHuiaqmISAM_0 motorcycle +lHyHQQF-8K0_0 car +lIE0SbW_gCY_0 dog +lIH_in2H5ds_0 knife +lIrvgqkirS4_0 car +lIrvgqkirS4_1 car +lI6hnnAL_54_1 skateboard +lI7VzYQQ8DY_1 bus +lJBeZTzXuSk_0 umbrella +lJJU-pzIbgs_0 boat +lJKxeHgRugQ_0 bicycle +lJa2bLMFljk_0 knife +lJa2bLMFljk_1 knife +lJa2bLMFljk_2 knife +lKC5LtWPL6s_0 boat +lKEgqjR4HeU_0 bicycle +lKEgqjR4HeU_1 bicycle +lKJZ4AYoO9g_0 car +lKJZ4AYoO9g_1 car +lKJZ4AYoO9g_3 car +lKJZ4AYoO9g_4 car +lKJZ4AYoO9g_5 car +lKJZ4AYoO9g_6 car +lKJZ4AYoO9g_7 car +NOEix5l-1TE_1 bear +NOVqPOoUWiM_2 bear +NOmc38WuhVA_1 zebra +NOmc38WuhVA_2 zebra +NPX9qxaZXGQ_1 boat +NPc_EhpqV9I_0 cat +NPlhHkKnD-o_3 bird +NPlhHkKnD-o_1 bird +NPnIcXU4TO4_0 truck +NPnJoNuZw64_0 bicycle +NP2YBNp1eMo_0 bus +NP8MrtR7UMQ_0 skateboard +NQRWmK2DAwo_1 skateboard +NQ7XVf2jPCk_1 bear +NRBtrgg-ACI_0 umbrella +NRGqiXyM4H0_0 bus +NRRxMVw0Fv0_0 umbrella +NRV62o4HAaI_0 dog +NRkeO8cWvlY_0 skateboard +NSEdAs2W7io_1 bus +NSrCO0JVjrQ_0 bus +NS6Z7neTE58_2 bear +NS7vapDr5vE_0 dog +NTJsuoSzIX0_8 boat +NTi-7LowE5E_4 bicycle +NTi-7LowE5E_0 bicycle +NTurL251ndw_0 bird +NTyAmrmpD-w_0 cat +NUOXJlGoyJk_0 motorcycle +NURGtF3McGo_0 knife +NUU3df9bDmc_0 motorcycle +NUhIeMVykto_0 truck +NUkuVMR_rDA_0 truck +NUkuVMR_rDA_1 truck +NUo3_VxkQWs_0 truck +NUo3_VxkQWs_1 truck +NU5WfPjxGO4_1 cat +NU60EZnPyy8_0 bird +NVAF-TWNge8_0 boat +NVeRtjaMVVM_0 car +NVz1RXwlQQM_0 skateboard +NWOVEKbfu_M_2 cat +NWwoSS6oanE_0 bus +NW6ZEfS5YY0_0 dog +NXHWi70uXME_0 motorcycle +NXU1Yxq08KQ_0 skateboard +NXe33k8YYzQ_4 truck +NXe6DkOAbbo_0 cat +NX2FQE2RlgI_0 dog +NX2FQE2RlgI_1 dog +NYBxFsoPtLU_7 knife +NYBxFsoPtLU_2 knife +NYVtLPBMGDA_1 dog +NYVtLPBMGDA_2 dog +NYpkdx_Wzos_0 bicycle +NYrd2o8DQhw_0 bird +NYsYKDH1T0Y_0 bear +NYs9voRwmTk_2 motorcycle +NZGyAc3mNmM_1 skateboard +NZOBtVvtpfo_0 bird +NZoU9njpjBc_2 bird +NZoU9njpjBc_1 bird +NaOwM5jaBb0_0 bear +NaTP9E6Ee6k_0 motorcycle +NahvbbnqXN0_0 knife +NaszpQMnSmM_0 skateboard +NbXn5vr55Ik_0 motorcycle +NbnAyKWQOgU_2 truck +NbnAyKWQOgU_3 truck +Nbz45at2suY_0 bird +Nb1nL_IG2Tc_0 umbrella +Nb4FhqzK_80_0 bird +Nb9Ee0cdc90_4 knife +Nb9Ee0cdc90_0 knife +NcD7EzR9VKc_0 cat +NcODwqAl8wA_0 bird +NcODwqAl8wA_1 bird +NcnPt-ksZkA_0 motorcycle +Ncnr9xhL4RE_1 bird +Ncnr9xhL4RE_5 bird +Nco2IqVnrXc_0 cat +lKiN4UeEuCQ_0 car +lKrgSHU_lF4_0 motorcycle +lKrgSHU_lF4_1 motorcycle +lL9OwfLG-LQ_0 skateboard +lMPus-gGijc_0 train +lMw3GHYr5nI_3 bear +lM2lr9vONXE_1 bird +lNDNEdNtW4w_0 umbrella +lNLvw0Ga8IY_1 skateboard +lNLvw0Ga8IY_2 skateboard +lNLvw0Ga8IY_0 skateboard +lNShteFjBFI_0 bird +lNh4Dhf0JC8_0 truck +lNj5zp4Gbsw_1 bird +lOGti3Hfk6A_2 bird +lOglyCevyZo_0 motorcycle +lOzlZJwo_U8_0 motorcycle +lO0DJaFrguw_0 motorcycle +lO0Nas9ogL0_0 bird +lPG5xsRX0U0_0 bird +lP3Jv00bEG8_0 bear +lQf2-zTERI8_0 motorcycle +lQ8AFjrjX64_0 umbrella +lRSTcmXYwzM_2 knife +lRyY7rtPGJ0_1 dog +lRyY7rtPGJ0_0 dog +lR-HPtCgbFY_0 car +lSefRz_ad2I_0 person +lS7IFw-rHNE_0 car +lTNivynkdBQ_0 bear +lTNivynkdBQ_2 bear +lTW53YPXtYw_0 umbrella +lTgxSRoCADM_1 boat +lTgxSRoCADM_2 boat +lTgxSRoCADM_3 boat +lTgxSRoCADM_0 boat +lTyeSMENfFI_0 dog +lT1oYaEt3l0_0 skateboard +lT1oYaEt3l0_2 skateboard +lT1oYaEt3l0_1 skateboard +lUEz6tmtuxs_0 dog +lUQr1JtEFAM_0 cat +lUSPy6WOhvw_1 boat +lUk_G-9RjSE_0 bird +lUq042i-r3E_1 dog +lUq042i-r3E_2 dog +lVCS7_AhLDg_0 cat +lVKT0DahELk_0 bus +lVKT0DahELk_2 bus +lVOqUh5DjZE_0 bicycle +lVWFKjMWyF8_0 truck +lVWFKjMWyF8_1 truck +lVWFKjMWyF8_2 truck +lVoO_SiGxpw_0 cat +lVohP88BOwU_1 giraffe +lWDh4SPr76A_1 train +lWGBmSVTvwo_2 skateboard +lWLYqz3RhXs_0 truck +lWkC8ABD6YI_0 knife +lWnVG1WyzTQ_0 dog +lW8axrSg7EY_0 dog +lXJGVOcVinA_1 truck +lXkkzYM416M_12 knife +lXkkzYM416M_8 knife +lXkkzYM416M_11 knife +lXshoTSoReY_0 motorcycle +lXshoTSoReY_1 motorcycle +lXshoTSoReY_2 motorcycle +lYC47pEoyKc_2 skateboard +lYEiGk0pa9w_1 dog +lYP4KB7dANc_0 truck +lYcCLy33mJA_0 truck +lYcCLy33mJA_1 truck +lYrLCKi7wHw_0 knife +lYrvoVOM7i8_1 truck +lYrvoVOM7i8_2 truck +lYzirpo9X4Q_2 knife +lY38gkpHWQA_0 dog +lZWg3rt2bp4_0 truck +lZWg3rt2bp4_1 truck +lZWg3rt2bp4_2 truck +lZgIg28WsqA_1 dog +Ncs0SIaAZjk_0 skateboard +NdDPhB7JjOc_1 car +NdFMcVN8fkc_0 skateboard +NdFMcVN8fkc_1 skateboard +Nd2smOOuPs4_0 truck +Nd5Cyi1P2AQ_0 person +Nd5Cyi1P2AQ_1 motorcycle +NesRw9JE-bc_4 dog +NesRw9JE-bc_0 dog +NesRw9JE-bc_1 dog +Ne_T9PyoaOA_0 truck +Ne_T9PyoaOA_2 truck +NfQ_F7iyFT4_0 bus +Nfoq-vLwXMs_0 cat +NfuM3ceM9Lg_0 bird +Nf4iPszryRI_1 truck +NgA6Mi5Qj6Y_1 car +NgHJhpedfLw_0 cat +NgfJ42fUH10_0 skateboard +NglZtOBkn1M_0 boat +Ngp2Yvug4N4_0 skateboard +Ng7YPssESZs_1 umbrella +NhDdHfwovA0_1 truck +NhHYQ1QBPq4_0 cat +NhJWY87UJGA_0 motorcycle +NhKgTGZXrk4_0 motorcycle +NiN42Yupn8k_0 motorcycle +NiQLFJ_8gI0_1 bird +NifFA8VfbMY_0 truck +NjPnw9Ofph8_1 bicycle +Njr2CQDoQ0w_2 boat +Nj1tu2uzjf8_0 umbrella +Nj4IqLuQBd0_0 car +NkHiSqSViG4_3 truck +NkSVC1QmlzA_2 boat +NkXF30FQWUs_0 bicycle +NkajkrLx-Pg_1 giraffe +NkdGD4jRmVk_2 skateboard +NkdGD4jRmVk_3 skateboard +NkdGD4jRmVk_4 skateboard +NkvfxcYCIfg_0 person +Nkxm_Grldgg_0 boat +NlKX0Q_a4qM_0 bicycle +Nl2e8ERoEYk_1 skateboard +Nl27zjpvGZk_0 cat +NmCxdejUxjE_2 umbrella +NmGnWjSHIGc_1 dog +NmGnWjSHIGc_3 dog +NmGnWjSHIGc_0 dog +NmHo6hH22gY_0 cat +NmRjRjuwWGU_0 umbrella +Nmm4H7xWWeE_0 giraffe +NmnOIU5yzmo_0 truck +Nm3Wkz8ClY8_4 bicycle +Nm3Wkz8ClY8_0 bicycle +Nm3Wkz8ClY8_3 bicycle +NnQubFQHcUU_0 cat +NnSwVsUnfj8_0 dog +NnV7SskfNiQ_1 bicycle +NnYCP4YouSI_0 skateboard +NnYCP4YouSI_1 skateboard +NncDYgsTFic_0 motorcycle +Nn1fsXlRDQg_7 bird +NoKz0p_h8xA_0 car +NoRnxJ4D8OY_0 motorcycle +NoglbvaRxAM_1 car +NoglbvaRxAM_2 car +NopFymjXZBE_0 car +NosN0T3He9Y_2 knife +NowQILLv6pM_1 motorcycle +NoxncYznLDw_0 motorcycle +NoxncYznLDw_2 motorcycle +NoxncYznLDw_3 motorcycle +NoxncYznLDw_5 motorcycle +NpbXizTCNgs_0 motorcycle +NpciaYlS9Bs_2 skateboard +NpptiWtuy7U_1 bird +Np0p_ITfRiE_0 boat +Np0p_ITfRiE_2 boat +NqA0sKGQZbc_0 bird +NqD8w0_R9y8_1 motorcycle +NqLEhuNiS-A_0 knife +NqzZbJJl3E4_0 truck +NqzZbJJl3E4_2 truck +Nq-mC-BLk1c_0 bird +NrGByfXIMJc_0 dog +NrGHtOFFLxU_0 motorcycle +NrJIz8M3oNM_0 boat +laSVNAwUDQc_0 giraffe +laiFgjfWMS8_1 bird +lajujsJ1J4k_0 bird +lajujsJ1J4k_1 bird +lauIpA9lVMo_0 skateboard +la0ygpbR6t4_0 dog +la0ygpbR6t4_1 dog +lbCW72FyaQ8_0 umbrella +lbC8rsjkZ8Y_1 truck +lbDdPmkMwnw_0 motorcycle +lbSldeZXn6I_0 skateboard +lbZo-rTovyc_0 skateboard +lbod3X-5Z40_4 bus +lbod3X-5Z40_5 bus +lbzHPZpNNjg_0 dog +lcSqXrVIbwo_0 motorcycle +lcWTw6rAYfI_0 cat +lcv8jXnPWQU_0 cat +lc6jM9I3ffc_0 motorcycle +lc8hZxMLAr4_0 truck +ldjVc4u8LUc_1 motorcycle +ldqpSPYa-3U_1 bicycle +ld5g39_bixY_1 skateboard +ld5g39_bixY_2 skateboard +lew1kgMUujc_0 car +lfPmXUBRa-k_1 bird +lfVb7VtGUAI_0 person +lfYoLXfvmyo_0 bus +lf29DRtjGcY_1 truck +lf29DRtjGcY_2 truck +lf4Xwro4NOQ_5 bus +lgLHq8p_CnA_0 truck +lgVXhalKM3w_0 boat +lgne-5wGRTg_4 bird +lgwnVArDAa0_2 bear +lg3udJdBBoI_0 dog +lg_4H9FLVog_0 dog +lhBsZjQzf8Q_0 motorcycle +lhEN_T9FduQ_0 knife +lhoMpa49rvU_0 umbrella +lh1Brsyb0aE_0 bicycle +lh21_LSx_G8_1 dog +liDzsyAmMJQ_0 motorcycle +liThgzeBkVY_0 cat +lite73A-c3o_0 bicycle +li8IvNy_DW4_1 bird +ljrwXgV0j9o_0 motorcycle +lj3DWkRI_HM_2 bear +lj3mqLiqSRw_0 knife +lj5bI1M_0ZA_0 skateboard +lj-BTMsCDdY_0 dog +lj-BTMsCDdY_1 dog +lkOFpGLmX9s_0 cat +lkYuyUsRfWE_1 dog +lkg_nXf_W88_0 bicycle +llBtQEKaglQ_2 bird +llFPEcbP7m8_0 car +llWG8M6Fsrg_1 skateboard +llu7uI6yzns_0 motorcycle +llu7uI6yzns_1 motorcycle +llu7uI6yzns_2 motorcycle +lmCsOrgM7zE_0 cat +lmVNyKFiuQw_3 knife +lmVNyKFiuQw_2 knife +lm-deiNDAW4_0 motorcycle +lnFmVwj7oMg_1 cat +lnk0OtCMbBc_0 cat +ln5IAoaoPHc_0 dog +NrX1AnOpS98_0 bus +NroEppStyZI_0 bicycle +NrvQhlD_Fuw_0 dog +NrvQhlD_Fuw_1 dog +NsCdsMqUNFc_0 bicycle +NsaAbiSbaCc_0 cat +NsdCvelNA0g_0 motorcycle +NsgZVfgUWco_0 skateboard +NsgZVfgUWco_1 skateboard +Ns78CA77Hmk_0 bird +NtHFEE2Ii0o_0 knife +NtQSi_L3_e4_0 bear +NttRY9GKNOE_1 car +Nt38ikEgqJg_1 dog +Nt-UKy4Uq0o_0 car +NuOq_HSf26I_0 boat +Nucr0ksCppE_0 dog +NumUCmB1MLA_0 bus +Nu6g6OfLbKU_0 zebra +Nu6g6OfLbKU_1 zebra +Nu-gGh3BQo0_0 skateboard +NvDafPMMZtg_1 cat +NvDafPMMZtg_0 cat +NvFUKJ9Y500_0 bicycle +NvTRLNn1Tk4_0 cat +NwC3jHQ65I0_0 bear +NwG3zY4-qHs_0 skateboard +NwHv08KS8WU_0 truck +NwHv08KS8WU_2 truck +NwgEA2yRlYk_0 bird +NwgEA2yRlYk_5 bird +NwlCLmmFUzM_0 truck +NwoCpDkRUOc_0 skateboard +NwzkWW45Qx0_6 bird +Nw1pLrkHm1E_1 cat +Nw8ZySxnzIA_0 cat +NxPgLux4spk_0 motorcycle +Nxgst3FR84g_0 car +NyOC1kV5fqc_2 knife +NyOVnxlZw44_0 truck +NyQlYlDdA1Y_2 skateboard +Nyg0BliJTCI_2 umbrella +Ny14oMm9C9k_6 skateboard +NzIOn70DDCU_0 bicycle +NzfwqHNApI8_0 bear +Nzqr9pq3W0g_0 bus +Nzwcia0dVls_0 bear +Nz5AnTEPNKY_3 bird +Nz_Dn60wY8c_0 dog +N0p_wrAammI_1 bird +N0wFxDTDhrA_0 truck +N0yYt90fBGo_0 boat +N049Vl1eC9E_0 truck +N1C5Wk1HQEk_0 cat +N1jUvtD_RyY_0 umbrella +N1xm5YdzSfQ_0 bird +N13r5ZKqAZI_1 boat +N2GiHfyj2sY_0 knife +N2Y3LmbOWhM_1 cat +N2Y3LmbOWhM_2 cat +N2e24fXBD58_0 boat +N2u1zVHzrfc_0 cat +N3D5PnaCpHs_1 knife +N3D5PnaCpHs_2 knife +N3Iy7f2RrrQ_0 motorcycle +N3OIM_qi7dY_0 cat +N3VKNNdiRhs_0 umbrella +N3ZGT5VDX7A_0 dog +N3vCQPsPb7k_0 cat +N3x4Fw8PZ04_1 bird +N4BazwxnEJU_1 umbrella +N4T6B8WAeyw_1 bear +N4bUNLwIt-I_0 bicycle +N4gBOlxfYUI_0 giraffe +N5T8bgYdTg8_0 bird +N5cC5-506Yg_0 motorcycle +N5uwMT9YWA8_2 umbrella +N6FCEWFj0vc_0 truck +N6XH-20xsPk_0 bus +N6Xl8e3GRcY_0 bird +N6gcbwR93B4_1 motorcycle +N6rvYTX52x4_0 car +loFhsa4OXsA_0 zebra +loFhsa4OXsA_1 zebra +loFhsa4OXsA_2 zebra +loS5Iy7HDhY_2 car +loyp0oi9idU_0 cat +lpPnun9oDq4_1 boat +lqEgRMyazN4_0 dog +lqi9uYhr1lU_3 boat +lqybkPUTuGk_4 bird +lqybkPUTuGk_0 bird +lqybkPUTuGk_1 bird +lqybkPUTuGk_3 bird +lrbJ-8myxJA_1 skateboard +lrd8TXYq2Co_0 zebra +lrgLAWtIFbQ_0 bird +lrk-LSpxnaQ_0 bus +lrsspehYW2Q_0 cat +lrusc_A2xpY_1 skateboard +lsQ4p_XwS3U_1 skateboard +lsW8rve_6F0_0 bird +lsslg2HK3as_1 bird +ls7K9Ga_TDo_0 cat +ls8cJ6QPPdI_0 truck +ltfbVFmlGNs_0 motorcycle +ltfbVFmlGNs_1 motorcycle +lti3EMrk6hA_0 bird +ltyDB0DzJ4o_0 bear +luZpSqhxjzc_0 skateboard +lujnNrfylcM_0 truck +lu4gOMv2LmA_0 dog +lvW9JvQnv_U_0 cat +lvXow0J0_Z8_5 boat +lvpmaJx7Ydo_0 motorcycle +lvxwGSPs5eo_0 truck +lvxwGSPs5eo_1 truck +lv79L0E9KbU_0 cat +lv8ApAxhQxg_9 dog +lwIzp1ny_cc_0 bicycle +lwqQ1SyQ6oc_0 bird +lwu1229kxGE_0 umbrella +lw-_X5H5dsA_1 skateboard +lxfLak4qc0w_3 truck +lxxazO-lUhg_0 skateboard +lxz5eN6gYvE_0 skateboard +lx4WDd9A1jM_0 cat +lyBbm0su2N8_0 dog +lyDsv_jEl3M_0 motorcycle +lylbDiRYA18_0 skateboard +lym5pBjKK44_1 boat +lyx_DnTpBx4_0 bird +lzAGCQoeAug_1 boat +lzISnRATBZY_0 motorcycle +lzrv6Lmaqhc_0 bicycle +lz9wsaAdD3g_0 dog +l0HBjPE-vp4_0 bicycle +l0LztA4KLq8_1 umbrella +l0TccajPnLs_0 cat +l0YyZLT2r0Q_0 dog +l0dbu61iEXU_0 cat +l0kogcjKlvI_0 bird +l01YbT30Uzw_0 car +l1PoAFZPnAI_0 cat +l1cfghmMFfA_0 motorcycle +l1dkS9dCOZs_0 truck +l1eSoNjG7g4_3 car +l1smSqKCK4k_0 person +l1wXtZDVtTw_0 bear +l120CJB_tWI_0 car +l2Cytaq3_MU_0 bird +l2d3stMmMjs_0 cat +l2pGQEcySt4_0 giraffe +l23teWgsK_Q_1 skateboard +l23teWgsK_Q_0 skateboard +N7HX62OM1Jo_1 car +N7WtVRWgYEs_0 bird +N8RE_7TdVGo_0 skateboard +N8wDSOXX8q4_0 cat +N9TwNh9IZug_0 truck +N9TwNh9IZug_2 truck +N-bSoL4tlX0_0 cat +N-ehGzRtoj8_0 bird +N-4XvHMsGCk_0 person +N-9RtI_ifsk_0 motorcycle +N_MWs_Dxjio_0 knife +OAJTjsjrFlQ_0 cat +OATLx4-34zQ_0 dog +OAtOdcwMjgs_0 skateboard +OBDA-yKAC_k_0 umbrella +OBDA-yKAC_k_2 umbrella +OBLc4YWkCqU_0 motorcycle +OBYJdeMHD3g_0 motorcycle +OBlj7XKW4lc_1 boat +OBlj7XKW4lc_0 boat +OBti9g_xdjg_0 bus +OBuDg5pF8EM_0 motorcycle +OBvMQQZSs6Q_0 truck +OCEGSfdedcM_1 dog +OCYvV1-sQQQ_1 truck +OCYvV1-sQQQ_0 truck +OCijTz38zrU_0 truck +OCpuPcuJN68_1 car +OCp5hNHBPpU_6 knife +OC3VHGBHbMY_1 dog +OC3VHGBHbMY_2 dog +ODXPmCSXZDc_1 truck +ODXPmCSXZDc_2 truck +ODbUQUd4jSU_0 skateboard +ODdK6tzKWWs_2 bicycle +ODdK6tzKWWs_3 bicycle +ODlDtYOtoQs_0 truck +ODo-zlQ_GB0_0 truck +ODp6c6uSvaU_0 giraffe +ODuka2U9fkA_0 bird +OD4XXIos2Zo_0 dog +OEJox-XKatw_0 knife +OEJox-XKatw_1 knife +OEMh8A9j_pg_3 bear +OEQV-Uetx8M_0 truck +OE0tYMQn8GU_1 bird +OFA22Poj7lQ_0 bicycle +OFA22Poj7lQ_1 bicycle +OFbK3M6Z_QU_2 dog +OFbK3M6Z_QU_1 dog +OFdr0zUfrlE_0 bus +OF2H-LBDSPk_2 bird +OF2H-LBDSPk_1 bird +OF6Up9vV9Qc_3 truck +OGMTfwEYzHA_0 knife +OGNQnbR2jAw_1 bear +OGVemy4LnsA_0 truck +OGbVuwjdEDU_0 motorcycle +OGnQhL7HZyI_0 bus +OGsEC0i33BY_0 knife +OG7Gqq0yNXc_0 skateboard +OHWx9W6ECl8_0 giraffe +OJ0c10BvtRY_0 dog +l3U_T7n5YD8_0 bicycle +l3YBS5nRxUY_0 truck +l3lkSnsgzx4_0 umbrella +l3qhbFnoRvI_0 car +l31h7cMiU1I_0 bear +l4LQx_ua4m0_0 bus +l4MLa-2lkQI_0 bus +l4dzsbhTXr4_2 bird +l4lv0qkvs10_6 bear +l43lNQ5Vq_s_0 bird +l4-nRuAZNyY_2 car +l5FUU1e4Y60_2 bicycle +l5ecq1OhBsk_1 skateboard +l5ecq1OhBsk_0 skateboard +l508a0nbyQI_6 bicycle +l508a0nbyQI_13 bicycle +l508a0nbyQI_14 bicycle +l508a0nbyQI_18 bicycle +l6NgJ2NHnt4_1 bear +l6S8h_QnD7U_0 cat +l63MzTHehFQ_0 cat +l7p6AfqPX2Y_1 motorcycle +l7p6AfqPX2Y_0 motorcycle +l8-hpsjvPaw_1 truck +l8-hpsjvPaw_2 truck +l9PH4iTXdYs_0 skateboard +l9ZtaPU3mB8_0 knife +l9j2X0rGhIY_0 bird +l9qm2_xBYHQ_0 cat +l9urEyEnxnU_1 knife +l96fQdjYlLs_0 knife +l-MCmCPjH7k_0 bicycle +l-QCC522u8A_0 car +l-eNrq-WUQo_0 boat +l-98mL8hxMY_0 bicycle +l-98mL8hxMY_8 bicycle +l_DmnPQxj7k_0 zebra +l_scPJDEOuI_0 bird +mAE8hqG3eSk_0 bus +mAPlm5rMa-w_0 motorcycle +mA5ZTSfwetI_0 truck +mBEMpccxmBw_1 motorcycle +mBEMpccxmBw_0 motorcycle +mBTsr9NKqos_0 dog +mBTsr9NKqos_1 dog +mBTsr9NKqos_2 dog +mBivNgtX2dc_1 skateboard +mB2K7Cqy5sA_0 knife +mB2K7Cqy5sA_1 knife +mB2K7Cqy5sA_2 knife +mCA3YMqp59Y_0 truck +mCVUS1SHxdc_1 bicycle +mCaHiS25d_c_0 bird +mCipOiHzL24_0 car +mCnfYEJ7_nM_1 boat +mCplUoipq_M_0 umbrella +mCshfLJNDZc_0 truck +mC9gh-poTgc_1 bus +mC_yfZI-Kfw_0 car +mC_8_BVmM48_0 bus +mDOnks0KH3c_0 bus +mDO2Jg5oyPM_1 umbrella +mDTcvH2cBAk_0 truck +mDTxktaf2Z0_0 cat +mDio2Blh76Y_3 knife +mDio2Blh76Y_0 knife +mDio2Blh76Y_2 knife +mDoksuME2bk_0 knife +mECu0xa8vxM_0 bird +mEFIkGBIFT4_0 umbrella +OKHhm13mZYw_0 bicycle +OKJlHLunIJ4_5 truck +OKL9IGXZDqg_0 cat +OKOBYUJfsW0_3 bus +OKVeF8WX7nM_1 dog +OKXlOHWMVYI_0 bicycle +OKXlOHWMVYI_2 bicycle +OKniUxVle4E_0 dog +OK1lt5Hbk8U_0 bird +OK1lt5Hbk8U_1 bird +OK72g05p_nY_0 bird +OLWhwdr2s3U_0 motorcycle +OLqz23zKUZ0_0 skateboard +OMJA4N9BRjk_0 bus +OMJA4N9BRjk_1 bus +OMROj6nJzNU_0 umbrella +OMscf19CmfE_0 cat +OMszUYfxt-k_0 dog +OM7YDn8Aj8U_0 cat +ONQt1uMKjzM_0 cat +ONQ7_XR_YoE_0 car +ONvq-WMS04Q_0 bus +ON25DCtbtZI_0 bird +ON25DCtbtZI_1 bird +OOOsedHMhFE_0 dog +OPFx79LTPYQ_0 knife +OPFx79LTPYQ_1 knife +OPNrGuEJKfQ_0 cat +OPRxB1VUSzc_0 bus +OPZI6LUwe80_0 truck +OPny4vHo5EQ_1 motorcycle +OQWmlKTZbJA_1 boat +OQh45xm5OzM_0 car +OQlHcCttP0Y_0 motorcycle +OQ5Q0IvSVJw_0 skateboard +OROW-2FDArE_0 knife +ORjDIPVlrpY_3 boat +ORyOEpNkmQU_0 bicycle +ORyOEpNkmQU_1 bicycle +OR1UJ2WJswk_0 umbrella +OR8th1OG-XE_0 umbrella +OSia7sePfOs_0 dog +OS2Ga4W91oU_0 boat +OTGZvd8HEBs_6 umbrella +OTGZvd8HEBs_1 umbrella +OTGZvd8HEBs_5 umbrella +OTK2nAcxHMw_0 truck +OTSLZbr15Rk_0 truck +OTXkN6YTPBY_2 bear +OTvtQllL8ho_0 giraffe +OT1tUDnxHUY_1 bird +OT1tUDnxHUY_0 bird +OUDo6Wi3Mx0_0 bicycle +OUaP4Qe7K_k_0 skateboard +OU9OQRs4Ff4_3 truck +OU9OQRs4Ff4_0 truck +OVBUoFuLqko_3 boat +OVBUoFuLqko_4 boat +OVBUoFuLqko_5 boat +OVBUoFuLqko_0 boat +OVBUoFuLqko_1 boat +OV8AfAYiWos_3 truck +OWe4Ah3rUkU_3 truck +OWe4Ah3rUkU_4 truck +OWwYp5TMtyo_0 dog +OW09PhbCZ2c_0 cat +OW9poTV3Pw0_0 motorcycle +OXDBegRD_hY_4 bear +OXleFWP00RU_0 skateboard +OXn_z6r4tTM_0 bicycle +OX46gFmob50_0 boat +OYAOM3GxoFs_0 umbrella +mEhLlaG7ivE_0 car +mEyJVUti9TA_0 bird +mFCrAjplP-s_1 truck +mFQSD32phtQ_0 motorcycle +mFoVk3mdfVs_0 boat +mFpufihJP34_0 truck +mF3uYMbMsrA_1 truck +mGAgv6gfUIA_1 giraffe +mGP0JfjwxXU_0 car +mGP0JfjwxXU_1 car +mGwC1aGK8EQ_1 motorcycle +mGwC1aGK8EQ_0 motorcycle +mG6Uz7wciew_0 truck +mHNOyEXbwsg_4 bear +mHORHQS-7WE_0 motorcycle +mHPMxlukQ30_0 motorcycle +mHfy3z8lzZY_0 bus +mHicqYMm5B8_0 bird +mHicqYMm5B8_1 bird +mHtWCmdt2ck_0 cat +mHwCC0jnHbI_0 bear +mHwgF2IQCd8_0 motorcycle +mIn-Tkvx0xg_0 truck +mIx7ZeZ2Vv8_1 truck +mJ0xD-4leB8_0 cat +mKRUuWYJC2k_0 motorcycle +mKRUuWYJC2k_1 motorcycle +mKRUuWYJC2k_2 motorcycle +mKRUuWYJC2k_3 motorcycle +mKWmMLNNRAQ_0 zebra +mKgld1efJss_0 bus +mKu97ivRVSM_0 knife +mKu97ivRVSM_1 knife +mLDjtK6d-W0_0 knife +mLGU-BL1agI_1 cat +mLG8EyllDhA_0 car +mLIp-YLvQaA_0 zebra +mLgNPTUe_XI_0 cat +mLmtVR-AGCk_0 bear +mLpoizHo-v4_0 dog +mMG1DT2mUAo_0 skateboard +mMUflfP_ZMY_0 cat +mMXGos8VYQI_1 dog +mMt-gdadsY4_1 dog +mNFkEphgV18_1 bicycle +mNdM6zfb6FA_0 cat +mNeHO27e_i4_0 bus +mNeHO27e_i4_1 bus +mOMvL5XuAZs_0 truck +mOVza6TV55E_0 bicycle +mOcxsTLCyfM_0 umbrella +mOjLK3sW2lA_0 skateboard +mO3CzDojFYs_0 dog +mO8cYs6iJlE_0 cat +mPCBb4ndGx0_3 car +mPCBb4ndGx0_2 car +mPPaPa0iD_c_0 dog +mPV3eyH3uiY_0 bicycle +mPW-nXWaC4U_0 cat +mP223OT32Rc_0 knife +mP223OT32Rc_1 knife +mP553XrHpVs_0 motorcycle +mQD1eeRC1Q4_0 knife +mQf2FppJTEM_0 bird +mRFdLfB4a1s_3 bear +mRI6bXmeH0U_0 knife +mRMc_QxifPU_0 truck +mRMc_QxifPU_1 truck +mROsO1LIGpo_0 truck +mRYB4i5ld-k_0 dog +mRkf0ciWPgI_9 bird +mRl54j1LWx8_0 person +mRyO8jtjseY_1 car +mRyO8jtjseY_2 car +mR0m08J8B08_4 boat +mR0m08J8B08_0 boat +mR0m08J8B08_1 boat +mR0m08J8B08_2 boat +mSTIz-CdXqU_0 truck +mSf7pQlzXuw_0 giraffe +mSgbTXZAzDk_1 umbrella +mSvLPzkZzps_0 knife +mSxrYqw4oqg_1 umbrella +mSztwZ01Pck_0 bus +OYIPropF-hA_2 knife +OYTwB7sOFYE_0 bird +OYa8DOvcJkU_0 cat +OYf6rSUrwxc_0 dog +OYnjEcx19SM_0 cat +OZBLMb8bGX8_0 zebra +OZcS8vrufig_0 dog +OZeialzVvBQ_0 bird +OZqsh8FFeFo_0 truck +OZqsh8FFeFo_3 truck +OZqsh8FFeFo_4 truck +OZstdGSfBBw_0 bird +OZ2Xf6zzI5Q_1 skateboard +OZ2Xf6zzI5Q_0 skateboard +OaR_KKoBRYA_0 boat +Oai5vIFRADY_0 truck +Oaxb1TjNF5A_0 boat +ObG3TG10dF0_0 dog +ObLBCGg01UY_5 skateboard +ObLBCGg01UY_1 skateboard +ObLBCGg01UY_2 skateboard +ObLBCGg01UY_3 skateboard +ObLBCGg01UY_4 skateboard +ObMci_3wRII_0 boat +Obmxs3FqVc0_0 truck +Obol9FzC6qw_0 boat +OburzWcRnbc_0 skateboard +Ob5o_Ufzxvo_0 umbrella +Ob6-UrKFrTY_5 boat +OcFGISpeAn0_0 skateboard +OcQBa7E9-AI_1 car +OcZG24cCgsU_2 boat +OchOHb4q-iE_0 bicycle +OcmRyP_n53E_0 truck +OcuYOC6GylA_0 car +Oc1tfJzLD3o_1 bus +Oc1tfJzLD3o_2 bus +Oc1tfJzLD3o_0 bus +OdGHHAUYow4_0 boat +Odl4k8y8GfI_1 skateboard +Odo1ZvyEbqs_3 bear +Odo1ZvyEbqs_6 bear +Odo1ZvyEbqs_7 bear +OeJet0TZ0Ns_0 cat +OecO1BnSygU_0 umbrella +OecO1BnSygU_1 umbrella +OepCeq6zNOc_0 umbrella +OevlneuqSNg_0 skateboard +Oe3qCUtDCoI_0 bear +OfD7c6vcSKc_0 motorcycle +OfFZrl_Ltoo_0 dog +OfQ3Y3DEgNI_0 skateboard +OfZ9wyeuMaU_0 skateboard +Ofcr6xsiMGY_1 knife +OfmW_n1WB-0_0 bird +OfpLj-uw2VM_0 skateboard +Ofv2SMoyg_8_0 boat +OgG3xES-A9s_0 bicycle +OgG3xES-A9s_1 bicycle +OgtTZgAAtrk_0 bear +Og77fxfsfzI_0 skateboard +Og83XjWPr30_0 bird +Og_sRGRP2fw_0 motorcycle +OhQqfPIVR_o_0 truck +Ohh5X9j8-P4_0 skateboard +OhvnlA9rzUA_0 umbrella +Oh4vuNdjqGg_1 boat +Oh4vuNdjqGg_3 boat +Oh79QNRx0m0_0 bus +OiHa7vhbW0g_0 umbrella +OiT0hP6IU_0_1 car +OidiasYmhhk_0 dog +Oiuo__vi77s_0 motorcycle +Oi3BJVuj3f8_0 bus +Ojst9j_7TPs_0 motorcycle +OjxLYDs9O2w_1 skateboard +Okd1qAIUuZo_0 skateboard +Okd1qAIUuZo_2 skateboard +OlO9xdVfniA_0 bus +OlPObAsvFRE_0 bear +OlQykWy5_d0_0 skateboard +OlVZS0O7Xcc_0 bus +OlVZS0O7Xcc_1 bus +OlVofey46c8_2 giraffe +OlVofey46c8_0 giraffe +Oldv3-_fn3E_0 motorcycle +OlufwgkC9nA_0 cat +Ol3C5MWakic_0 bus +Ol63TPS0wjE_0 skateboard +OmTHe4jPR30_0 umbrella +mTnSFF649v4_0 motorcycle +mTtOhVJYmco_0 bicycle +mTuXb1mo6ms_1 motorcycle +mTwbZIC2mjs_0 umbrella +mUllN4tCjhg_0 car +mVWf8BrbbQc_0 skateboard +mVZVZPz-0uk_0 knife +mVztYl0hyR0_1 bird +mWOuUa5VTIU_4 bird +mWSWZi7ef2Q_0 bus +mWULzZ-r0BE_10 bear +mWULzZ-r0BE_0 bear +mWULzZ-r0BE_1 bear +mWULzZ-r0BE_3 bear +mWULzZ-r0BE_6 bear +mWULzZ-r0BE_7 bear +mWULzZ-r0BE_9 bear +mW85x5O3sQM_1 bus +mXYQlH9le8Y_0 dog +mXt-xLcVJTM_0 knife +mXuPzw4I-wQ_0 dog +mXu238CeGfQ_0 motorcycle +mXu238CeGfQ_1 motorcycle +mX3SlrHHN8A_2 knife +mX3SlrHHN8A_3 knife +mYFsdZ6ZiHg_0 skateboard +mYYLIkI65fA_0 cat +mYgcUWeYKeE_0 cat +mYhujznmuic_0 motorcycle +mYtEL2P4G64_2 truck +mYtEL2P4G64_0 truck +mY6M_QMVm6A_0 dog +mY6M_QMVm6A_1 dog +mY6M_QMVm6A_2 dog +mY6M_QMVm6A_3 dog +mZEPBKLKQLU_0 skateboard +mZStBRJGz0o_0 bird +mZWugKrC8fs_0 truck +mZ0LxtaLk9s_0 bicycle +mZ0LxtaLk9s_1 bicycle +mZ1ae3QtMqY_1 skateboard +mZ6SXifL_5I_0 cat +maANeKOpibc_0 bus +maATqEbCdmA_0 boat +maOsv3Gen0Q_0 motorcycle +magDXuphf6E_0 truck +mavzqjj21eQ_0 motorcycle +mbFrW58khSM_0 motorcycle +mbtyAyprPhQ_0 motorcycle +mbuozxoOynA_0 bus +mb9G4GF56RA_1 umbrella +mb9G4GF56RA_2 umbrella +mb-nes45JeE_1 bird +mb-nes45JeE_0 bird +mcCOvhuC86Q_0 cat +mcxoHsKM444_0 cat +mc0A1NsuIBI_0 bird +mdDoBuc7jag_0 boat +mdZbK8mOA5Y_0 motorcycle +mdxbRZzm2Fo_4 truck +mdzJDnEx5AI_2 boat +md8Xi01GJ0Q_3 bird +meRJPfPZTpw_3 bird +mebu5O8auic_1 bird +mehKWfZTJQE_0 bird +mfPFvq57cxM_0 skateboard +mf4LyMZ6wyY_0 skateboard +mgEZVZrBkrg_0 bicycle +mgEkK74q1Lo_0 motorcycle +mgTCPe8eM00_1 umbrella +mgVB0o0U17w_1 skateboard +mgVB0o0U17w_0 skateboard +mhSSgOcQwd8_0 cat +mhqhGszzAR8_0 cat +miC3NPxHofU_1 bird +miQyhDocW3I_1 dog +Om1q-9YbJu0_0 bus +Om-NvWZY9XM_0 bear +OnKqSIvDmuM_0 skateboard +OnemsYazBrQ_0 truck +OnemsYazBrQ_5 truck +OnemsYazBrQ_1 truck +OnemsYazBrQ_2 truck +OnemsYazBrQ_3 truck +On3Yd3AHFp0_0 dog +On3b0cn9QYE_0 bear +On-GcAXLGZ0_0 motorcycle +On_5UKUJi7U_0 car +OohVLB8HrmU_0 bear +Oo2Ux9rWYGo_0 skateboard +Oo8VLA_C0ho_5 bicycle +OpAPsb8a7ck_1 bicycle +OpD07kt9gdg_0 motorcycle +OplcFe9OOMA_0 boat +OplcFe9OOMA_1 boat +OpqmXBQU87o_0 truck +Op3764NveuQ_1 bicycle +OqKwAAWtANM_0 cat +OqPOCcEAHqk_0 skateboard +OqbhEJlCp48_0 skateboard +Oqc407hvhn8_0 skateboard +Oqjbl3c9LYU_0 bear +Oqo2P7az_Jw_2 motorcycle +OrhDfcZqq1E_0 cat +OrhipZ8lZHo_2 bird +OrhipZ8lZHo_3 bird +OrhipZ8lZHo_1 bird +OrmkaB0vrG8_0 dog +Or-E2m2p4X8_0 motorcycle +Or--toMjK3I_3 boat +OsvYa6TnsFI_2 car +OtIV8clF1-o_0 bird +OtIV8clF1-o_2 bird +OtKIh5W3Uro_0 bird +Otw43WNrlsM_1 bicycle +Otw43WNrlsM_2 bicycle +OtyYn5vEHbM_2 skateboard +OuBzZzA9Q7o_0 bicycle +OuJMq2UqA-s_0 dog +OuVznEsiyyA_1 motorcycle +Oui9ZgfJiJE_0 skateboard +Ou1yCmmAuSY_0 cat +OvEJdKYqvF4_2 dog +OvEJdKYqvF4_5 dog +OvZguhO8UVQ_1 bird +OvlqAWflXBs_1 bus +OwQktS0dM3k_1 truck +OwUWoVRKf7E_2 zebra +OxADHlAb7dM_0 boat +OxInmNOeLHY_0 bicycle +OxInmNOeLHY_1 bicycle +OxInmNOeLHY_2 bicycle +OxInmNOeLHY_3 bicycle +OxInmNOeLHY_5 bicycle +OxInmNOeLHY_6 bicycle +OxInmNOeLHY_7 bicycle +OxZdEZCJtcw_1 motorcycle +Oxkx4bWzOMo_0 skateboard +Oxp9w62kg0Y_2 knife +Oxp9w62kg0Y_3 knife +Ox1idrJvs2E_0 cat +Ox_8K3szIs0_0 cat +OyGSbm149i8_0 boat +OzBFCX0vpiU_0 motorcycle +OzCvvptC7o8_1 bicycle +OzHYG5kpMbw_0 car +OzItTAjpb9U_1 knife +OzwlwZq46z8_3 bus +Oz89_rVdBV0_0 knife +Oz89_rVdBV0_1 knife +O0JwQIk5pZY_5 knife +O0Xl3AF_T0s_0 dog +O0dforbCqKM_0 cat +O0lfImzhCM4_0 dog +O0p5eAP2AyA_0 boat +O0rSIIipDT0_0 truck +O02oVGyCZDI_0 motorcycle +O0_GC-1pCYk_0 bear +mj155rqWO3k_0 motorcycle +mj5oMHI4Ch0_1 skateboard +mkPWdHTd5X8_0 bear +mkVYY1EvetE_1 bicycle +mkZA72VL1oI_0 zebra +mlAzMb61fYU_0 cat +mlJYoZVHztc_0 bear +mlT2XD9k5Ro_2 bird +mlophh4mK4A_2 bicycle +mluR2OjQTmU_0 car +mlwpiHjyzIA_1 motorcycle +ml4BVi7cCV4_0 bird +mmnFugXdqlQ_1 truck +mmnFugXdqlQ_0 truck +mmojCWiaNYI_0 cat +mm_Udf1FG0s_0 cat +mnB2hBuySsI_1 bear +mnB2hBuySsI_2 bear +mn_cuBRZu8M_0 cat +moZR-AtZJnI_0 cat +mobg7uEQTmo_0 umbrella +mogyHm8Jiok_0 bird +moh4TWSe9Fc_0 umbrella +motFo9G-GLs_0 skateboard +moyxRLHHeiI_0 bus +mo5ZpMFELUQ_0 motorcycle +mpO9dBwTeW4_0 bicycle +mpYAM0x6L5M_0 motorcycle +mphFmT6TzLM_1 knife +mphFmT6TzLM_2 knife +mphFmT6TzLM_3 knife +mp25XfIJhQY_0 cat +mp8USuQKinc_0 bird +mqUyhzbCpig_0 motorcycle +mqjilBZByTI_0 skateboard +mq5DqmYGVM4_0 person +mrJAakc7Fj8_0 bus +mrOsDCuEdRQ_1 dog +mrY8gIFiUhE_0 car +mrhfyNpFMq4_1 truck +mryDGEujJno_0 motorcycle +msNXnb1a02o_0 knife +msbOXFTsSVU_0 giraffe +mszokIKsdUk_0 bus +ms0_k1aLULU_0 truck +mtITgRv95Sw_0 dog +mtU7bHAsI8Y_0 cat +mtZHgLGJiu4_0 skateboard +mtmzPf2AZuI_0 skateboard +mtnURpE0wyE_0 bicycle +mtnURpE0wyE_1 bicycle +mtnURpE0wyE_2 bicycle +mtpTPJtG8F4_0 motorcycle +mt_LZ5UsG_w_5 knife +mt_LZ5UsG_w_1 knife +muKQy-1p4fg_0 truck +muWIt0X4pKQ_0 dog +muZ7xPF8odU_2 bicycle +mueRS6nKTdA_0 bicycle +mujGcuAzOdo_1 bear +mujGcuAzOdo_4 bear +mulQIomc988_1 bicycle +mulQIomc988_3 bicycle +muoqLEyrhhI_0 dog +mursOuNatdc_0 boat +mu65YolQZds_0 knife +mvEcWlHP6u4_0 bicycle +mvYBfdZkCe8_0 dog +mvb5jVJeuGE_0 person +mvhEFfQeFCY_0 bear +mv2FHxOHSR0_1 truck +mwAPVTEbZGM_0 skateboard +mwAPVTEbZGM_1 skateboard +mwBKrjOpxkY_0 skateboard +mwIroQ9RbXA_0 bird +mwrxbdZraRk_0 car +mw5fQZ8EB5I_0 knife +O1KrpGSvXAY_0 knife +O19Mlhhzqgc_2 bear +O2ZR7HPYZCo_0 cat +O2u5126JYpY_2 motorcycle +O3DA7qzf2s8_1 bus +O3DA7qzf2s8_0 bus +O3y2taxKvCA_2 boat +O4CfuT5BDcc_0 skateboard +O4VQQaJ07zY_0 cat +O5b3XcEGZ4M_0 car +O54XRvo6VU0_2 motorcycle +O54XRvo6VU0_0 motorcycle +O59A3lMogSo_0 giraffe +O59A3lMogSo_1 giraffe +O6BXRuq_YcE_0 dog +O6BXRuq_YcE_2 dog +O6EtCByhFZI_0 truck +O6Jf2yxCTuI_0 cat +O6Uln7GkqDA_0 skateboard +O6b3a--pX3E_0 bird +O6kqsEuKhis_0 bird +O69gCmR0LvA_2 motorcycle +O69gCmR0LvA_3 motorcycle +O7ReHsig5IQ_1 knife +O7Wrpfzb8_g_0 bear +O7lvzdzmX5k_2 bicycle +O8BNclEPo5w_2 dog +O8BNclEPo5w_1 dog +O8f0Dhn1as0_0 umbrella +O8sB46kfM28_7 umbrella +O8sB46kfM28_6 umbrella +O8sB46kfM28_13 umbrella +O9Duu2Un8AE_0 skateboard +O9Duu2Un8AE_1 skateboard +O9Duu2Un8AE_2 skateboard +O9EqKcj_CPs_0 umbrella +O9iWg3ZqLcU_2 bear +O-NZJ4-eoQ8_0 bus +O-ZUr1bQzp4_6 umbrella +O-kJ078YJq4_7 truck +O-2S79hisI8_0 zebra +O-4CV4-x7Tk_0 dog +O_D7M00pmjQ_0 motorcycle +O_PCiV3NICw_0 dog +O_bAX_ruSNQ_0 skateboard +O_fZm7Mblgg_0 knife +O_mRo8YLc50_0 umbrella +O_3VssPsSVQ_5 bicycle +PABLxf3U8qc_2 bicycle +PABLxf3U8qc_4 bicycle +PABLxf3U8qc_1 bicycle +PASMcbnOtUM_1 bird +PAZBEMKPQEw_4 boat +PAbB9I6MC_o_2 boat +PBD1IW-vA6Y_0 dog +PBD1IW-vA6Y_1 dog +PBQjiKBWtao_1 bicycle +PBQjiKBWtao_3 bicycle +PBqIT1T_Tl4_2 umbrella +PByJb40LNJ4_28 bicycle +PByJb40LNJ4_30 bicycle +PByJb40LNJ4_3 bicycle +PByJb40LNJ4_13 bicycle +PByJb40LNJ4_18 bicycle +PByJb40LNJ4_22 bicycle +PB8sWVNFkDw_1 motorcycle +mxA8JbJ0Do8_0 car +mxFga0703Mc_0 bird +mxMCBmJ5owQ_2 truck +mxXH5aZCSJ8_0 truck +mxYl5Y1KAiY_0 dog +mxZgNkjbyxk_1 knife +mxeuMHAWMxo_6 knife +mxeuMHAWMxo_7 knife +mxeuMHAWMxo_9 knife +mxsTfEQlVgM_0 motorcycle +mxvG6gSVYuo_0 bicycle +mxwmtm7rKF8_0 car +mxxiqhZzhEE_0 motorcycle +mxyHDUSMhLs_0 cat +mx2i3CYeEEE_0 bear +myRelcztkqo_1 knife +myWzn06fmDI_0 dog +myY1Ijlbknw_1 bicycle +myY1Ijlbknw_4 bicycle +myY1Ijlbknw_5 bicycle +myY1Ijlbknw_2 bicycle +mymtiyldysk_0 truck +mzGmbowEFfA_1 knife +mzMgXA_v8q4_0 motorcycle +mzYPSSUS--w_2 boat +mzYPSSUS--w_0 boat +mzdD_0CKekQ_0 motorcycle +mzfrEqAhHeY_0 bus +mzm_D3J8zqQ_0 umbrella +mzyu28WsuFs_0 motorcycle +m0MVwwL_0MM_0 bicycle +m0gukhoxW0Q_0 skateboard +m0gukhoxW0Q_1 skateboard +m0gukhoxW0Q_2 skateboard +m08CnM1FBR0_0 cat +m0_tPmnque0_0 bicycle +m0_tPmnque0_1 bicycle +m1Qhj9jYohk_0 bus +m1pFyDGuVzk_1 skateboard +m1pFyDGuVzk_2 skateboard +m2StZDAc1yw_0 bird +m2uQowbhYDc_1 bear +m3AM4AQLDo0_0 zebra +m3AM4AQLDo0_1 zebra +m3RCOnTUyMY_0 boat +m3RCOnTUyMY_1 boat +m3SOT8NCOEY_0 bicycle +m3cgfDs0_G8_2 dog +m3fctWcU4as_0 motorcycle +m3sztS1QC3s_0 cat +m3uDjNrfbD8_1 bear +m35CwgXROHw_0 car +m4qZSrgBZkc_0 bird +m4qZSrgBZkc_1 bird +m6NemUzZQFc_1 motorcycle +m6NemUzZQFc_0 motorcycle +m6S6MEQgo2E_2 motorcycle +m6S6MEQgo2E_4 motorcycle +m6hQABEUkQQ_4 boat +m6z3sbKYwcc_3 bus +m6z3sbKYwcc_4 bus +m669S-54lMc_0 motorcycle +m669S-54lMc_1 motorcycle +m7djLwb_a5k_0 car +m7k5fJXTZPI_5 bird +m7xUarlXKEw_0 umbrella +m7xUarlXKEw_4 umbrella +m7xUarlXKEw_1 umbrella +m7xUarlXKEw_2 umbrella +m8B-pb1I7nc_0 cat +m8YA8dXocmg_2 boat +m8t6gPBCxr8_0 truck +m9HGLakPqSo_1 bear +m-NEL2Jq0nQ_2 car +m-dKTMwfPqo_0 truck +m_JHW_eCKY0_0 umbrella +m_dOsn1chuA_1 bus +m_dOsn1chuA_2 bus +PCC9sJ4Gdxw_0 car +PCeoeGBYrJU_0 dog +PCqa_yHJ32g_2 bicycle +PC2plr6JdQg_0 umbrella +PC_wbEzLNLQ_0 bicycle +PC_wbEzLNLQ_1 bicycle +PDU92To89cE_1 bird +PDlKUKo06lI_0 knife +PDvSiH5Pf_0_0 bus +PEC7E1t79A8_0 car +PEJFRzyvIBc_0 bird +PEJvGdLGOjU_0 zebra +PEY59JrOz5I_1 bird +PEY59JrOz5I_0 bird +PEfpmwboH3w_0 bus +PEtsR4S5Zzg_0 bicycle +PE_zE5T1ayo_0 cat +PFJiRWGaPaw_0 car +PFJiRWGaPaw_1 car +PFa_RCiQVjA_0 skateboard +PFjuIzuDmJs_1 knife +PF8HAptOIC8_1 car +PGEM0ys1sGE_0 knife +PGMimFwsl54_0 cat +PGP0PEOv3zw_2 bear +PGP0PEOv3zw_0 bear +PGipyYSRHso_0 bicycle +PGn623RKWNA_1 car +PG8bMx6DuSo_0 knife +PHeQ1xoUBgg_1 boat +PHmnvFIAtHo_0 bus +PHxuey2u6UE_0 skateboard +PIDvuyKFIJ8_0 cat +PIT2XsuODRE_0 bird +PIa767e6xuQ_0 cat +PIkhnCxrF9g_0 cat +PInIdEVTPn0_7 truck +PI5ROW9ewOg_0 cat +PJoSJpMWo0Y_3 skateboard +PKTJIVIuSFw_0 truck +PKZXF6Hj0kw_0 bird +PKZXF6Hj0kw_2 bird +PKZXF6Hj0kw_1 bird +PKtfgOMwx4A_0 dog +PK-4bXZDtlA_1 skateboard +PLO2xY76oh4_0 motorcycle +PLVEvFhXHAE_0 truck +PLVEvFhXHAE_1 truck +PLd8HlO4HYo_1 cat +PLd8HlO4HYo_0 cat +PLwQ0AHwZgg_1 skateboard +PLwQ0AHwZgg_2 skateboard +PL2FcMREy_0_0 bicycle +PMRnsvlMF4A_0 skateboard +PMUqAknVm2Q_0 motorcycle +PMXmKup8jy4_0 boat +PMkiPjm9XdY_1 motorcycle +PM028PEyjv0_4 bear +PNpDnymoq8w_0 truck +PN6PB668zV4_0 truck +PN86cQumWDU_0 motorcycle +PN_b6R9HxwQ_2 cat +POQalChDjmU_0 skateboard +POW6F8MZMTQ_1 bird +PO-OnjGHjDk_0 bus +PPI6aG2QFaM_0 bird +PPdV273cZC8_0 skateboard +PPhYyYHNaQ4_2 boat +PPhYyYHNaQ4_3 boat +PP5_L_EZsmE_0 bird +PQI2zG7I8jI_1 bus +PQjM0fGHXds_0 bird +nARlDpJ1mzQ_1 dog +nAmX6FEKmTg_0 truck +nAsHFcuT16U_0 skateboard +nAsHFcuT16U_1 skateboard +nBLWjCuzp2g_0 dog +nBPhMvA4QIs_0 dog +nBXKLM2hLN0_1 car +nBtF1BDR8wE_0 motorcycle +nCKBmlhUPYg_0 cat +nCPhfqQsjIQ_0 motorcycle +nCPhfqQsjIQ_1 motorcycle +nCe_XQHu77g_0 truck +nCgjbB7wxoE_0 bus +nDsb271W8XU_1 car +nEFtdboPB2w_1 bear +nEIawnnD8V8_0 truck +nELgP3wAnm8_0 dog +nEM7mY_k1_4_0 boat +nEVFHD_9xCw_1 bird +nEtqWL5nz_U_0 bus +nEtqWL5nz_U_1 bus +nEyJKW3bMCc_0 dog +nE6lY5G16lE_1 bicycle +nE6lY5G16lE_2 bicycle +nE6lY5G16lE_0 bicycle +nFQvQPqMjpk_0 car +nFZrdv6K4pg_0 motorcycle +nFa5TGw-b5Y_0 bicycle +nF28ACSGHM8_0 boat +nF444n6UUJE_0 bear +nF444n6UUJE_4 bear +nGQ3Hq6P5tM_0 car +nGnDoylbNm8_1 bear +nHAF0LI8CPk_0 truck +nHAF0LI8CPk_1 truck +nHAF0LI8CPk_2 truck +nHApjxTb0fI_0 umbrella +nHAt_MmKZtA_0 dog +nHRioXgb-Fo_0 bird +nHbHOfTnrtg_0 dog +nHbHOfTnrtg_2 dog +nHe8j-osZck_0 dog +nH9AXssn9vw_0 umbrella +nIIQLgiJpz4_0 motorcycle +nIqnT8pJFz0_0 knife +nJF2wWsJCd8_0 cat +nJuhir_bIpw_0 cat +nJ6iwd_XQso_0 umbrella +nJ6uR6SE01w_0 bicycle +nKM_iCO6bKs_0 bus +nKS1tzA_Hrk_0 skateboard +nKUBzJ38GgY_1 boat +nK-2zxkNCuA_0 cat +nLED5Us6rMo_0 motorcycle +nLL3PMe48dQ_0 boat +nLXX8_SfZs0_0 cat +nLn2LN33uxg_0 cat +nLx78Uv2dmc_3 skateboard +nMbLyO3605c_0 knife +nMo_-oHL7bU_0 knife +nMtxrG4hH5M_0 skateboard +nMyhi847s6A_0 knife +nNNF1j89RS0_0 bear +nNScwJL6ym0_0 motorcycle +nNeaR2o9KMY_0 boat +nNwEBFJZT8U_0 bird +nOe7o_AaOUs_3 skateboard +nOfyHwhf35s_0 bus +nPBFLS60OYk_5 truck +nPhpYRGfHlw_0 bear +nP5wigEk-3A_3 knife +PQsHE_w_Q5I_1 knife +PQuYVLwcT7k_0 skateboard +PQ4gPP2l3RY_0 bus +PQ9ZEkeKIzs_0 skateboard +PRIJbfolHpE_0 umbrella +PRIw6kIS_oM_0 motorcycle +PRg6CE_exgE_2 dog +PRoAGpjxUIQ_1 dog +PSdh0lzfg3M_0 bus +PSrvUaBxbgU_0 motorcycle +PS_CABKe3Yk_0 motorcycle +PTKnZd28Sac_2 dog +PTORa3OCyoU_1 truck +PTxm2ZRQbNg_0 skateboard +PTxm2ZRQbNg_5 skateboard +PTxm2ZRQbNg_1 skateboard +PTxm2ZRQbNg_2 skateboard +PT2XxI2FufM_0 bus +PT3felQmrwU_1 bear +PT6KXLLxhes_0 bird +PUFo51ngpe8_0 bus +PUeS5CCMoa4_1 zebra +PUgpXWoI6nw_2 bird +PUiSf8EuinE_2 bear +PU3x1IpbndQ_0 knife +PU5v_AtaKKw_9 bird +PU5v_AtaKKw_2 bird +PU5v_AtaKKw_3 bird +PU5v_AtaKKw_4 bird +PU5v_AtaKKw_5 bird +PU5v_AtaKKw_7 bird +PU-lRdkaqdg_0 cat +PVV-saboi8Q_0 truck +PVXtjPyNMms_0 dog +PV6mXKbH058_0 skateboard +PWIWGwJZENs_0 dog +PWQGxn3c5iQ_2 knife +PWQGxn3c5iQ_0 knife +PWs7zuWiKZo_0 bus +PW7XGdRhgKI_0 cat +PW97rAj3_84_0 truck +PXb9PHJghpA_0 cat +PYH5FxLfm3M_0 bus +PYOwGQUBJXY_1 boat +PYWfE8WhDKk_1 knife +PYohJALR7DA_1 motorcycle +PYohJALR7DA_2 motorcycle +PYsiftgJNrs_0 motorcycle +PZEun35Hcoo_1 dog +PZNXXWorkrY_0 motorcycle +PZSGccVPUm8_1 bird +PZjQiLyqHkw_0 truck +PZoM9dv8P3A_1 bear +PZuGSUZ1N2w_0 skateboard +PZz86aIvTWU_0 skateboard +PZ3PfRXk2rQ_0 cat +PZ9YkHds_00_0 dog +PaVPMVUQwtM_7 boat +PaVPMVUQwtM_2 boat +PatPjxyHqvY_0 boat +PbPu-cnEMqo_0 cat +PbUb1IktyM0_0 motorcycle +PbdnWP3AnKQ_1 person +PbhIhdwp7nI_5 knife +PceERP83N7g_1 dog +PceERP83N7g_2 dog +PdER58jIvPg_0 cat +PdRRvS5p7TM_4 bicycle +PdRRvS5p7TM_0 bicycle +PdRRvS5p7TM_1 bicycle +PdgOy1B6ByE_0 person +PdgOy1B6ByE_1 motorcycle +PdkRSALRJOE_1 truck +Pdne4jISJMk_0 bird +PeXODrjPJpU_0 motorcycle +PecvaJstdYE_0 knife +Pejvg4LHBXw_1 skateboard +Peur7tMeMNc_11 bicycle +Peur7tMeMNc_12 bicycle +Peur7tMeMNc_20 bicycle +Peur7tMeMNc_21 bicycle +Peur7tMeMNc_5 bicycle +Pew5sug67ao_0 dog +PfKS2L_bxBc_0 cat +PfOYq_uyVF8_1 bird +nQPFPYvmWtU_0 skateboard +nQd33JTaurM_0 bird +nQd33JTaurM_2 bird +nQmH_VIOI4o_0 cat +nRG70FCdevw_0 bus +nRP28gcIe5Y_0 bird +nRP8SwdbUGw_1 bear +nRr5gMvJ77k_0 skateboard +nSgcLfwMJu4_0 dog +nSvaQz0i9i8_1 skateboard +nSvaQz0i9i8_0 skateboard +nSz_BdDSYsk_1 bear +nS_SY6iDJ2U_3 bear +nTjbCPXR408_1 truck +nTjbCPXR408_2 truck +nTjbCPXR408_3 truck +nTjbCPXR408_4 truck +nTz3LA23B4U_0 skateboard +nUBgjOAcKBw_0 truck +nUDvay-MfVs_0 truck +nUVSuT7wfDs_0 motorcycle +nUdbTm-FW0I_0 bus +nVAOU6r15Ww_3 knife +nVTMM3F16j0_1 boat +nVi9QbrUrjE_0 motorcycle +nWvR8fiLxGw_0 truck +nXD-zvpjC50_0 car +nXG_fwbJQ-E_0 car +nXjIIWFPSd4_0 cat +nXlSVy8CmMk_0 truck +nXpq0p9VBXc_0 boat +nXqE-XROi78_0 bear +nXqQPuJmTZo_0 cat +nYYFquwhxeI_0 cat +nYqRuOF_Uao_2 car +nYqRuOF_Uao_0 car +nYqRuOF_Uao_1 car +nYut3zBSbuM_0 bear +nY0xtzTME34_1 cat +nY2XarSrm7Y_0 boat +nY2XarSrm7Y_1 boat +nY3BS_3Mq6o_0 motorcycle +nY3fRfvoh9w_4 bear +nY3fRfvoh9w_0 bear +nY_icz32gn8_0 cat +nZHGbmVkhrE_0 cat +nZn4xAbcGSk_0 cat +naE1svJuCTw_0 truck +naE1svJuCTw_1 truck +naR-9rNf5fE_0 skateboard +nalqTKM6890_0 umbrella +nalqTKM6890_1 umbrella +nalqTKM6890_3 umbrella +nbCix4zvF_E_0 umbrella +nbcH6NfapD0_0 boat +ncuqh0iglYU_2 skateboard +ncu8gbqMkMc_0 cat +nc9aHs1_xzs_2 motorcycle +ndBPYFAVIiM_0 bird +ndJ2_mPZktw_2 bear +ndJ2_mPZktw_1 bear +ndMfXyYPfAM_0 bird +ndNs3q8tY9U_0 bus +ndO2b-r-Krs_0 motorcycle +ndO2b-r-Krs_1 motorcycle +ndj7VTH_PhE_0 bird +Pfi9ZEQtgjY_0 knife +PfnFeL4ArA8_0 skateboard +PfpTZKfKeKY_2 truck +PfpTZKfKeKY_0 truck +PfpTZKfKeKY_1 truck +PgBMaMqbYqA_0 motorcycle +PgE6BAQmVQQ_0 umbrella +PhFFfxYo2_o_1 dog +PhJOcszed6A_1 car +PhJ5rQ5VmeY_0 skateboard +PhjPRYTcJwQ_1 car +PhyQoxFlTMU_0 truck +Ph8Vag9VxRU_0 zebra +Ph8Vag9VxRU_4 zebra +Ph8Vag9VxRU_1 zebra +Ph8Vag9VxRU_2 zebra +Ph8Vag9VxRU_3 zebra +PiO6F4X8k_M_1 truck +PiO6F4X8k_M_2 truck +PiRy-T8d0gQ_1 skateboard +PiRy-T8d0gQ_0 skateboard +Pi_aEuQD5gA_5 umbrella +Pi_aEuQD5gA_8 umbrella +PjAWqdid4rw_1 umbrella +PjBOLvrlicY_0 car +PjBOLvrlicY_1 car +PjBOLvrlicY_2 car +PjTtsfl7KZ4_0 cat +PjjO6IaSiuo_0 skateboard +PjjV-pCjgqc_1 bird +Pjk0d9eP2gI_0 dog +Pjm-ptGWuWU_0 dog +PjpGwiZ8mK8_0 bus +PjuUsIXzSzQ_0 truck +PjwfhUvbBNI_0 skateboard +Pj9588RHCHM_1 car +PkktNSL9IjE_0 bird +PlKRGU_XIzs_3 boat +PlfCXfMXcs0_0 skateboard +PlfCXfMXcs0_1 skateboard +PltDcKetGYw_0 knife +Pl6ja9eNHzE_3 skateboard +Pl6ja9eNHzE_4 skateboard +Pl6ja9eNHzE_1 skateboard +Pl6ja9eNHzE_2 skateboard +Pml224S87BE_0 bird +Pm_2At7P8Yo_0 bus +Pnt2XmUpT8Q_1 bear +Pnt2g-tHwK4_0 truck +Pn1VFdKk5vQ_0 truck +PoL9E8Yc2vo_0 car +PoL9E8Yc2vo_1 car +PoUPC9WCdiE_5 dog +PoV7Wn66UTo_0 bird +PolaH6r1Qds_4 truck +PolaH6r1Qds_2 truck +PpI7DZdWcfc_0 person +PpZHxI0N3Wo_1 motorcycle +PptqwylntWQ_1 boat +Pp6vch1kMqE_0 cat +PqJOWTjp0ww_0 cat +PqKlF5nnOFs_0 motorcycle +PqNDvGH2-iM_0 truck +Pq7tfwAqhIM_0 motorcycle +PrV4kyVAwWE_0 bear +Prynn7mNQdQ_0 knife +PsVhOsDIopI_0 umbrella +PsfddppUmSk_0 skateboard +PsgPXqr-N7A_0 skateboard +PsvVwYAeKEc_1 boat +PsytJKFxV8c_0 boat +PszGWhekz-Y_0 umbrella +Ps9ReRjYLVk_0 bird +Ps9f-iFqX4M_0 skateboard +PtL5k4ew4q0_0 car +PtR7vRI9mn0_0 motorcycle +PtVUPVUYld8_1 skateboard +PtnFOxat4hE_0 bear +Ptq7-B4P9Bw_0 skateboard +Pt04IRhfVFk_0 boat +Pt1vVuKH3fk_1 skateboard +PuV7SV-FwOU_1 skateboard +neA0T50G8TU_0 car +neA0T50G8TU_1 car +neA0T50G8TU_3 car +newqX6GTbrA_0 car +ne8K6jHnOT8_0 boat +nfnKsQItZjE_0 skateboard +nfxMe31pjec_4 truck +ngAKsr62ACQ_0 knife +ngOtFD7Fxd4_2 boat +ngZtMG--t4I_2 bear +nga4aEZQhJw_0 knife +ngslQPG3kEI_1 bird +nhI3C5y85gw_0 truck +nhdMHfvazLY_0 umbrella +nhoO0Evj7OQ_0 umbrella +nhoO0Evj7OQ_2 umbrella +nh56dQ3T3Mc_2 boat +nh56dQ3T3Mc_3 boat +niBK6HGH16U_0 cat +ni3trEPOXck_0 bird +njBEUyoUzlQ_0 bird +njK1OLFCvv4_0 cat +njMC5HAlnMU_1 umbrella +njnGmGuXNdE_1 knife +njn4TkIDn0k_0 truck +nkJxMYiG9Ho_0 bus +nkSvwnLvBmw_4 motorcycle +nkSvwnLvBmw_0 motorcycle +nkSvwnLvBmw_2 motorcycle +nkVPvJ3Smrg_0 cat +nkZ6NDOt4r4_0 cat +nkv5eof4q_M_0 knife +nlAePf94uwk_0 cat +nlupdJzbyKs_1 bird +nl83jp96h9s_2 knife +nmmeE-Dfds8_0 bus +nmwFYDopqBc_0 dog +nmwFYDopqBc_1 dog +nnIGNFEnlw8_0 car +nnNkJ09YO9M_0 motorcycle +nnUkcXbXbFM_0 umbrella +nnhUxSjBHP8_0 umbrella +noCrLkdGSXw_0 bus +noGmFOxKIr0_0 person +noIHydna8tw_3 truck +nonoyrFpKVA_1 zebra +nonoyrFpKVA_4 zebra +nonoyrFpKVA_5 zebra +nonoyrFpKVA_0 zebra +nosbeVXMgAk_0 knife +nqN2uJfit8o_1 car +nqPkd_Quci0_0 truck +nqWs5hqd8Ps_0 bus +nqbsnsBZULc_0 truck +nqnjh-NO9go_0 bus +nq8oHNlU_BQ_0 truck +nrJURcGigjE_0 motorcycle +nrlcROgdPlI_1 cat +PumbYcoJ5zE_0 truck +Pu8rYMOC0Iw_0 dog +Pu_KMtdCGZY_1 truck +PvSzSsQ4YCY_0 cat +PvuGk2XhJW8_0 bird +Pv77ig8kBgE_0 cat +PwBNm2_oKbQ_1 zebra +PwE-w-S8nQc_0 cat +PwRb6q11-rw_7 bear +PwRb6q11-rw_0 bear +PwRb6q11-rw_3 bear +PwRb6q11-rw_4 bear +PwRb6q11-rw_5 bear +PwgxDMnN1SA_0 truck +PwmBtcc64nM_0 zebra +PwmBtcc64nM_1 zebra +PxN14d54as8_0 truck +PxOYpOxjFFc_0 cat +Px02MS-Ywo0_0 knife +PyevrWYsc8k_0 motorcycle +Pyr-sHCH2wc_4 truck +PyvyP3J13FI_0 knife +PyvyP3J13FI_2 knife +Py6rKt-beyk_0 knife +Py-bAIGcQ1Y_1 boat +PzZ-Jr7jMk8_0 bus +P0S7eBa6_S4_0 dog +P0e6zPkZO5s_1 knife +P1_bfvyTku0_0 truck +P2NRNopueuo_0 umbrella +P2SgXG0mMWU_0 truck +P2Wv0vXNCqQ_0 zebra +P2kLj1DZq3I_1 bird +P2kLj1DZq3I_0 bird +P2ldC-_7nrs_1 boat +P256TqMIJZk_0 dog +P3MLJSbWlpg_1 motorcycle +P3jB1tXpVMw_0 bird +P3q6jIrZyo4_1 dog +P4jpdzY2as8_0 dog +P43doVXj3y0_0 cat +P5DcP_VLnP4_0 bear +P5Gd_8k2O5s_0 truck +P5VAaJj-1Rc_0 dog +P5kFeiFmPxw_0 person +P5xsJqm2v6c_1 motorcycle +P5xsJqm2v6c_2 motorcycle +P5xsJqm2v6c_0 motorcycle +P5yrLRVD86M_0 dog +P6Qm9u9GIE4_0 motorcycle +P72vKWjKtik_0 truck +P741OzHLvig_0 dog +P8BX8WSWRm8_0 bus +P8K2yXmSMwY_0 bird +P8MCMBcqM00_0 motorcycle +P8MCMBcqM00_1 motorcycle +P8h9iD7kPRQ_0 bear +P80sglFzhRI_0 bear +nsS9iSqNMew_1 bus +ntO6br-N89w_0 cat +ntVDuucoRIk_0 cat +nuVxM9m1nb8_0 motorcycle +nuVxM9m1nb8_2 motorcycle +nvIi1SvX-sU_0 dog +nvXKI_MhTTE_4 knife +nvYTcYLFUvc_2 dog +nvdIoQ5mj64_0 knife +nvxwnGRXwZY_1 dog +nxJkhdCqhc0_0 dog +nxUe9yoeHvs_0 bear +nxYGMvfgi8g_0 person +nxj_aavOM50_0 boat +nxmr9gg0ses_1 bear +nx9Uisdggps_3 knife +nx9Uisdggps_0 knife +nyOaHbw3DLo_0 cat +ny2pC-BfLT0_2 dog +ny2pC-BfLT0_0 dog +ny2pC-BfLT0_1 dog +ny3nZLL4cQ0_3 motorcycle +nzGPh9yFDTI_5 truck +nzQqdKnkQ9I_0 zebra +nzppX26-51c_0 boat +nzytVTFaYvs_0 knife +nzytVTFaYvs_1 knife +nzytVTFaYvs_3 knife +nz9DMQ9cPrw_0 cat +nz_YTLNErSY_1 truck +n0P8wVonqY4_0 motorcycle +n0T51DP8868_0 bird +n1VbuQk_3JY_0 bird +n1ZrqU8VSBA_2 bus +n2Xd8e_vz0w_0 cat +n2Xrvmq2r2I_0 cat +n2jvWkboChM_11 bus +n2jvWkboChM_10 bus +n2jvWkboChM_14 bus +n3EKpxnV5U8_0 car +n3bFZVLqNvI_0 umbrella +n3iNRmzhO1U_0 motorcycle +n3pRNFU0ovc_0 bear +n3pRNFU0ovc_1 bear +n38NmPI7Sss_0 boat +n4cdQF8d8UI_0 knife +n4mWuEmbbEM_0 bird +n5J7UxAi_70_5 car +n5J7UxAi_70_1 car +n5J7UxAi_70_3 car +n5J7UxAi_70_4 car +n5i5aZXPgok_1 bus +n5ojrsEczYM_1 truck +n5wZ3Zin9uQ_0 bus +n5wZ3Zin9uQ_1 bus +n6cpTMT-Ci0_1 car +n6sMWDd_j1c_0 cat +n6wMhru1Mx0_2 car +n7HaOXaXWJw_2 truck +n7NWTiq_W-c_0 boat +P9sfOBt9FI8_1 bird +P95Pyq4kglE_0 knife +P95Pyq4kglE_1 knife +P-EecPZ9zV4_0 motorcycle +P-JbMZ89Hac_0 car +P-SIr3rYBzg_0 umbrella +P-lf6syyjAs_0 cat +P-tXkGlSa_8_0 motorcycle +P_A56tkbbmk_8 umbrella +P_A56tkbbmk_1 umbrella +P_A56tkbbmk_7 umbrella +P_un1_qBDWo_0 umbrella +QATQMMA9vo4_2 motorcycle +QATjEG1LPL0_0 bear +QA4LOoc1Crg_0 truck +QA__knfzZZM_0 bird +QBZUbx6SUyU_2 bear +QBbAz7q7E9c_0 bus +QCDUv9KNiWQ_2 dog +QCKzW_uA3vY_0 motorcycle +QCl4OGNJdos_1 bus +QCqvd4xHZLs_0 cat +QCzgTA2cABU_0 boat +QDQgSF9ciHk_4 knife +QD4ioxu8LAk_0 cat +QEMoyw7o_f8_0 dog +QEQfoQOU_F8_1 bird +QFB5gDukoqg_0 bus +QGDhzG35q8c_0 dog +QGDhzG35q8c_1 dog +QGDhzG35q8c_2 dog +QGDhzG35q8c_3 dog +QGFSTul5MDQ_0 knife +QGcd6O1NAkY_1 bus +QGcd6O1NAkY_2 bus +QGv8jcDgmBY_0 motorcycle +QG25-t2CqY0_0 bus +QG5tLrHw5Hk_0 cat +QHVkPy7f680_0 car +QHVkPy7f680_2 car +QHhXgNBSjV0_0 umbrella +QH2Vo_5h-x8_0 car +QIe7ky6mJO8_0 bear +QIqf221MKYo_0 bird +QItwshU9sAQ_0 car +QI65w7sMLtA_0 cat +QJIgRLU_fU8_0 motorcycle +QJfS9bR2S4I_0 cat +QJsyPZ31U-0_0 cat +QKG7PXh0UoU_1 bus +QKG7PXh0UoU_5 bus +QKG7PXh0UoU_6 bus +QK9WWQe1WQU_0 bus +QLTztdEJ8Ts_0 motorcycle +n7dIhGKEzWM_2 boat +n7hFNcaW9rw_0 knife +n77hlwjlW_Y_0 dog +n8IsRKE9S6k_0 motorcycle +n8kFOAqnMao_0 motorcycle +n9RozRHi7iI_1 knife +n9RozRHi7iI_3 knife +n9xiuvCd5Lw_1 bear +n-fT4fcLulk_0 bear +n-fT4fcLulk_4 bear +n-gEIxTHjBk_3 bear +n_EpRXVan0M_0 cat +n_J23TUQdl0_1 bear +n_PRUX4zrLw_0 car +n_bIC-prc2E_0 motorcycle +oARh23g1-LA_0 cat +oAhYK7brhk0_0 dog +oAhYK7brhk0_2 dog +oBDdj5mkGyc_1 knife +oBraEPvaSi0_0 bird +oBuzx2dwA_Q_2 knife +oBzhDbxL57k_0 bird +oCUkN7ySpf8_0 motorcycle +oCZ3WCK5BZU_1 motorcycle +oCf-LgXx6Dw_0 bird +oDHO9J7vFwI_0 boat +oDUJYHwNuS8_0 bus +oDsRL8dvgLA_1 bus +oDsRL8dvgLA_2 bus +oF81nMQlA-4_2 umbrella +oGMlnXjD9R0_0 bird +oGuIyQiDsy0_2 boat +oGuIyQiDsy0_0 boat +oH-XJADp0FM_1 bear +oH-XJADp0FM_2 bear +oH-XJADp0FM_4 bear +oH-XJADp0FM_5 bear +oI5l1By4H7U_0 car +oI_peuU5xk8_5 motorcycle +oI_peuU5xk8_0 motorcycle +oI_peuU5xk8_3 motorcycle +oJD17uQnW_o_0 dog +oJK_TUb7HoQ_3 knife +oJLVcOe7CEU_0 motorcycle +oJervxxOCvY_0 dog +oKTgwWf3FKA_0 dog +QLxMt8F3oYA_0 cat +QL4uK4sZxIU_0 cat +QL-hkYCV0BQ_0 motorcycle +QMEIKO8LcEU_0 motorcycle +QMGNMAZLRFY_1 knife +QMGNMAZLRFY_0 knife +QMHCb6-qyQE_4 bird +QMHCb6-qyQE_0 bird +QMHCb6-qyQE_3 bird +QMJHMIdkS0w_0 boat +QMVKAdAOrNY_0 dog +QNUGl2q9luk_6 dog +QNVeq1dY-gY_0 bus +QNV_xE7TePM_0 umbrella +QNV_xE7TePM_1 umbrella +QNaFT-Ch0Oc_1 bird +QNgnQe-MASw_0 bus +QNgnQe-MASw_2 bus +QNibPLG3_Q0_0 dog +QNibPLG3_Q0_1 dog +QNibPLG3_Q0_2 dog +QNrg73bCl7M_0 bus +QN5joVuigKw_0 dog +QOCUHjNieAs_0 cat +QOGKQmMhYE0_2 knife +QOQU7N2vIdQ_0 dog +QOcPhbRnGh4_0 bird +QOm8zog21wI_0 bear +QOp31EvHfRU_0 cat +QOs2s2r3hpY_2 bird +QOs2s2r3hpY_3 bird +QO1T0Gc_cJk_0 bird +QPwnbNFbZyY_0 motorcycle +QQAQLPTkDwg_2 bird +QQAQLPTkDwg_0 bird +QQh4Cpr7tpM_0 bear +QQ7EaN8ArmM_0 motorcycle +QQ-MUe-ni48_2 motorcycle +QRXtuZBCXtA_0 umbrella +QRZ_xQK1gx8_0 bus +QRZ_xQK1gx8_1 bus +QR3BO_SYrpQ_0 bird +QR5EuXvYbms_0 car +QSK1oOt_5R4_0 knife +QSld_dZQvpY_0 bear +QTPAOir-oYM_1 knife +QThuW0gGa20_0 dog +QTlzTtcPjwk_3 car +QT0-oUhQtbk_0 dog +QT17xRXmBGA_0 umbrella +QVCd5pTgbds_0 boat +QVRM0OueKFY_0 dog +QVXv0Z1FCdg_0 motorcycle +QVXzwEenImE_0 bus +QWBwnViynQA_0 motorcycle +QWFR4XdQv2Y_0 umbrella +QWPkooq95So_1 knife +QWPkooq95So_2 knife +QWSsyFwwdO8_0 dog +QWl839SnUOs_0 dog +QW1BlOtH1bo_0 cat +QXAw2xD7Sgc_0 motorcycle +QXB7sLTVqfM_0 bear +QXIGeVZ6Uqk_0 bear +QXVQ8S7aUB4_0 knife +QXjfaOwHSFo_1 motorcycle +QXwh-lAa3Pk_0 knife +QXwh-lAa3Pk_4 knife +QXwh-lAa3Pk_5 knife +QY2pVib4cZE_0 motorcycle +QZOPux7sysI_1 dog +QZOPux7sysI_0 dog +QZhaeUKdGYk_0 motorcycle +QZpfX1aipco_1 car +QZui5buTy7k_0 bus +QZ3FD2qszF8_0 motorcycle +QZ3MWq6qwJI_0 bus +QaGjoVfIWLQ_0 motorcycle +QaM6ny5gEFQ_0 cat +oKY-KsLfJe4_0 bird +oKY-KsLfJe4_1 bird +oKbCNTwLJoI_0 dog +oKe3Rcvn_TU_2 cat +oK9TjDSQdSs_0 cat +oK9erjaiRq4_0 bus +oLRDfgRIJ-A_1 bus +oLSjl-qN4M8_0 dog +oLrou9S3K-0_1 motorcycle +oM_FQGUvPIk_1 motorcycle +oNFmLa8pU3A_0 knife +oNLkf1j-v6Q_0 cat +oNZOg6XoSrY_1 dog +oNbWPkOIdxg_5 car +oNbWPkOIdxg_4 car +oNyfqJGJhrY_0 motorcycle +oPhE3ECqxf0_0 bear +oPlhh62giKI_0 car +oPrG5_acHVU_2 bird +oP0yHq-dlRY_0 motorcycle +oQV827pXDXA_0 motorcycle +oQXdls5ffZc_2 bear +oQXdls5ffZc_0 bear +oQXdls5ffZc_1 bear +oQ7ARK51eHE_1 dog +oQ7ARK51eHE_0 dog +oR-7d677bYw_0 motorcycle +oSPVZs6_Bd4_0 motorcycle +oSVes8uNT5E_0 motorcycle +oSao8txZd7A_0 motorcycle +oSb17xrITtY_0 motorcycle +oSqq5UHBveo_0 bear +oSxoAvNHNB0_0 motorcycle +oS60CV9BFs8_4 bear +oTYr-qD5JOE_0 bird +oTj1e8RI67A_0 boat +oTlwKNdm3rE_0 dog +oTuVBf1jiPM_3 bear +oTuVBf1jiPM_0 bear +oUHa0FV0wwM_1 dog +oUVJrf3WBrs_1 bus +oUVJrf3WBrs_3 bus +oUuQYVAvtgs_0 bird +oVUE-0XhhsQ_0 car +oVUE-0XhhsQ_2 car +oVUE-0XhhsQ_3 car +oV1vhE0ypUE_0 cat +oV6wthYHnKA_3 knife +oWFO_yss01s_0 cat +oWI2O83zUJk_1 car +oWI2O83zUJk_0 car +oWYSJgX0THI_1 dog +oXMW3YjDAqQ_2 boat +oXaieymppqU_0 cat +oX4YRc-No7Q_0 dog +oYY_svQfTs0_1 boat +QahJqWjC1v0_0 motorcycle +QakBz4K6hqw_0 umbrella +QbHAXTRKk8w_0 knife +QbHAXTRKk8w_1 knife +QbNU92uEUSc_0 cat +Qbk_YIfY5q4_7 knife +QcLZ-b-0PxY_0 boat +QcU2S6m_GJk_0 dog +QcuHNJWb-AY_0 car +Qc0kbcpophI_0 car +Qc5ZW-ni9ZQ_0 boat +QeRfpcI_TTQ_0 bear +QebJi8pjWkk_0 car +QeeG_4eNyg0_0 dog +Qe1-M3oVaFs_1 knife +QfOdxYnCAKc_0 bear +QfOdxYnCAKc_2 bear +QfaVCQOGlMM_0 motorcycle +QfgJh_s9H0I_1 bird +QfgJh_s9H0I_2 bird +Qfr5Fc1k7Ic_0 knife +QfwCa3YapRg_0 cat +QgRbpAz8TuI_0 bear +QgRbpAz8TuI_5 bear +QgRbpAz8TuI_2 bear +QgXjMUMIe4Q_0 cat +QhbwOw5dHPg_0 cat +Qhc3Bb_6Uq4_1 motorcycle +Qhc3Bb_6Uq4_0 motorcycle +QhnEXqWFBuw_0 bird +Qhxv39Tkzbs_1 dog +QiHJ2uYByjM_0 motorcycle +QjV-g1D6Be0_0 motorcycle +QjV-g1D6Be0_3 motorcycle +QjV-g1D6Be0_1 motorcycle +QjV-g1D6Be0_2 motorcycle +QjdGUh1FtN4_1 bus +QjqhhoIx6nQ_0 boat +Qj4Mfd45GOE_3 bus +Qj4Mfd45GOE_0 bus +QkPH2LBso5c_0 umbrella +QkPLEWaH1bo_0 cat +QkkuZ_G7t48_0 boat +QkwI5-_QspU_0 cat +Qk6G7eAHlCs_0 dog +QlcaO8pkzd4_0 bear +QliTvc637Yk_2 boat +QlieDL9xPyU_1 motorcycle +QlxQKy1yzyI_3 motorcycle +QmP4xj9S0mQ_0 motorcycle +QmR3bvWDA1s_0 boat +QngGa73C1G8_0 cat +QnnV6lKKIgI_1 knife +QnuD7a8BM30_0 dog +Qn9CU5O4FHU_0 bus +Qn9Z0LVIxbo_0 car +QoTopiP9k2o_2 bus +oZLdU13R4uU_0 motorcycle +oZoTyJNjCJI_0 bus +oZ6Py8Tx-sA_0 dog +oZ9qkN9Q1X4_1 bird +oaXGm1MdDoA_0 cat +oajaYAOs_oI_1 knife +oa_73oVbH38_0 bird +oa_73oVbH38_1 bird +obbzKGrHOP0_0 bird +ob70dcN35yg_0 bird +ocNVbpQhB5g_0 cat +ocPgZeXuFqs_0 car +ocj3mV2T-ls_1 bird +oc4RRoFoUo0_0 boat +odsCgfz0yM8_0 motorcycle +oeIBPeBAEv8_0 dog +oeVUkEvC3To_0 boat +ofDmsqy24k0_0 car +ofJOKOICGco_0 motorcycle +ofvHImJKiAg_1 bear +ofy3Sid451s_1 bear +ogIewcLFxLo_0 dog +ogLOXI-Kvcg_0 knife +ogzWVQ5TC80_0 cat +oh7uEf_YE40_1 dog +oiItk_51540_5 motorcycle +oiKC4SxYNJE_0 bus +oiRnmB7WQjQ_0 bird +oiu_53B5AAc_0 motorcycle +ojFBoKltgfQ_0 bus +ojFBoKltgfQ_1 bus +ojFBoKltgfQ_2 bus +ojQfL_XgMM0_2 boat +ojz2xLrH-Ts_7 car +okKrvzNb9IU_0 car +okiIzmV8YLw_0 cat +okiIzmV8YLw_1 cat +okzrd8v1G-w_3 boat +omGx_muz0SY_1 boat +omngVtTFM1I_0 umbrella +oms2XkgghV8_0 boat +QoqeX-W0RFw_0 boat +QoqeX-W0RFw_2 boat +Qo0mxFOMVGc_0 dog +QpAWeYA1pc8_0 car +QpDm5g1dELc_0 bus +QpD7CVh2Z_c_3 knife +QqdW9IMDHgs_0 boat +QqdW9IMDHgs_2 boat +QqdW9IMDHgs_3 boat +QqhZnuITXs8_2 bird +QqhZnuITXs8_3 bird +QqkblYN1YOg_0 bus +QrEjYyinITM_0 car +QsQFhUd04jI_0 motorcycle +QsQFhUd04jI_1 motorcycle +QsV9BTogrKc_0 knife +Qt78_24lkeM_0 boat +Qu8xNQ6Vd04_0 cat +QvgmjwKuAeM_0 umbrella +QvqNodq3NxA_3 bear +QvsjDkJ_oho_0 cat +QwALBOsUby0_1 knife +QwYxgsacjx0_0 knife +Qw9UvjSO9_Q_0 bird +Qxx3WjrGmtE_2 bear +Qyc0xSSPT1E_0 dog +QzCvBtKWPjg_0 person +QzPFEeJYDcE_0 umbrella +Qz1R2sk37qg_3 bear +Qz1R2sk37qg_5 bear +Qz1R2sk37qg_6 bear +Qz1R2sk37qg_7 bear +Q0HX6Jfnnb8_0 bird +Q0J1QbF_Vis_0 bird +Q0KhMTnvbxM_0 bus +Q01P6P7bm7E_0 motorcycle +Q0-7SsSXMV0_0 knife +Q0-7SsSXMV0_2 knife +Q1RqyDERgxM_1 bird +Q1VXWNHzPqI_1 cat +Q1VXWNHzPqI_2 cat +Q197NAaQodY_0 dog +Q2Sop28spdM_0 knife +Q2bha73kLKM_0 motorcycle +Q2vBCDtNAGI_0 motorcycle +Q2zRXVl7bLI_0 motorcycle +Q3ZxsgPKTGY_2 bird +Q3ZxsgPKTGY_3 bird +onoO4tamBlA_0 knife +onpRejbK_VE_0 umbrella +ooJg7-nxmUw_0 motorcycle +opOHceUyoXk_0 cat +opb_qoqO05s_0 bird +oqUbqkDsSzI_1 knife +oqvnxRx-0J4_1 bird +oq4KPP5PYAo_1 motorcycle +orQkUDPfTg8_0 boat +orTFjuPHzxU_3 dog +orcE_uPKO_c_0 bird +ormZXNXni-U_0 dog +osYgSn6yOG0_0 cat +os3H6KzvGEg_1 knife +otHFt4YAKeI_2 dog +otvQKWvIXAE_0 bus +ouFwG2YU59c_0 motorcycle +ouNsmVT6GRU_0 car +ouqFEe0ud_U_0 motorcycle +ovHCJGK35r0_0 knife +ovHCJGK35r0_1 knife +ovQY7VA36gU_0 bird +ovRBelXjQ-A_0 bird +ovaFSf6jda4_1 boat +ovnkb_MuAlg_0 bus +ov9yaGUtSEw_0 bear +ov9yaGUtSEw_1 bear +owKiuZVov4U_2 dog +owaIraEDvqI_0 umbrella +owaIraEDvqI_1 umbrella +owb-43QL8Dc_0 cat +oxKhcqfQV7k_0 umbrella +oxZ42ECABUo_0 motorcycle +oxdCJK5GPS8_0 dog +oxyS9oNIBaQ_2 boat +oy52khlb79k_0 cat +oy885M8rmDM_0 bus +oy_Efqu_Zhk_0 knife +o0CsAQaDp1k_0 boat +o0VArHW9gpE_2 dog +o0yyk1GchoE_2 knife +o06poedEjtM_2 knife +o1RqDbHx0IA_0 umbrella +o12Lc5yZNco_1 bear +o2E2ypLvzOo_1 car +Q34_kBWh3QU_0 motorcycle +Q4IH3ZOVKFQ_5 bus +Q4TELEHdcjA_0 motorcycle +Q4YD_lW8JFE_1 knife +Q4afI-fku0A_0 knife +Q4d0z-q-UXQ_0 bird +Q4jZeoLzZXs_2 bird +Q5DrYh7pcTg_0 cat +Q5RabF9bK3o_0 car +Q5cY3mt9NHI_1 car +Q5cY3mt9NHI_3 car +Q6Lg4c8W2XQ_0 bus +Q7SXsNoT9cc_1 boat +Q7TDTHQoPGc_0 bird +Q7TZ3TlDNzI_0 bird +Q7V8JjnLW_A_0 person +Q7a4tWAU7-o_0 dog +Q8gHTSzR6h0_0 cat +Q807ZgwscUk_0 cat +Q9LvGsq1Mas_2 bird +Q9fbeFbARPY_0 bird +Q9qA-2ofuFc_0 dog +Q9qA-2ofuFc_1 dog +Q-JQokKqXZM_0 motorcycle +Q-STF8c8RSE_0 motorcycle +Q-S6ypfxn4w_1 bus +Q-VqbNMPAjE_0 dog +Q_a7bRv2dM0_1 cat +RAQAfTprH5s_0 cat +RAc8MyscjAA_4 bear +RAc8MyscjAA_0 bear +RAc8MyscjAA_3 bear +RAqMmf5FS_Y_0 dog +RBNNklw-NjE_0 car +RBNNklw-NjE_1 car +RBdpxD5mMy8_0 cat +RBssHo0ygdI_2 car +RBssHo0ygdI_1 car +RBvocl1t9qM_0 car +RBvocl1t9qM_1 car +RCzBVv_Vddo_0 dog +RC444E40nLY_0 cat +RC_ckl7o7sc_0 dog +RDq9wvYEiSI_0 umbrella +RD8OUO8u7oQ_0 person +REBpFtJosSc_3 bear +REBpFtJosSc_4 bear +REBpFtJosSc_0 bear +REbm5i5vhcQ_0 umbrella +REbm5i5vhcQ_1 umbrella +REiwqNPkmew_4 bear +REiwqNPkmew_3 bear +REjT99mHV_g_0 cat +RFIE-agz3SA_0 dog +RFUZkHtGWvg_2 bird +RFUZkHtGWvg_1 bird +RFZG72_XG3U_0 motorcycle +RFcz2p3w1oc_0 bus +RFhEq5WF9Io_0 motorcycle +RFqSKdzXQFQ_0 bus +o2z2zu4L1Ho_0 cat +o3OdAgJnYlw_0 umbrella +o3TpeQ7mhIQ_0 bear +o4It_gqHKoM_0 bus +o4It_gqHKoM_4 bus +o4It_gqHKoM_5 bus +o4bpCoFINtY_0 bird +o4yKF7ZQge8_0 cat +o4yxnKhoWrQ_0 cat +o49yvv0vmJQ_0 knife +o5TWf69h978_0 motorcycle +o5bJmNSZmGE_0 cat +o6vw6_1pc_g_1 person +o6x94jhuMEw_0 cat +o7UXYGmFww0_0 knife +o8BqJTsAjnI_0 boat +o8BqJTsAjnI_2 boat +o8Gr9wZzcA0_0 knife +o83uI_tdkrE_2 car +o9UpoUWgJWw_1 motorcycle +o9YqiVSTBVs_0 motorcycle +o9qB9kYt9Bc_0 motorcycle +o9vRwcqz30w_2 bear +o98cAmKOAtk_2 truck +o_BpJHlv8bY_0 cat +o_NYHfqWzBw_0 cat +pAP3j2UmTAA_0 car +pAuz372kMrs_0 boat +pAvBjM_cSCk_0 umbrella +pA_f-DZ2FdI_1 bus +pBj4KFDTwGg_0 cat +pCPwOGObTcs_0 umbrella +pCXmnj6vY7o_1 knife +pCa3Tf27TcY_3 bear +pCdwcy8npiE_2 bear +pCfA0E-TIXo_0 motorcycle +pC9mu-CQ9fg_0 cat +pDjjH1_G6Z0_1 motorcycle +pDjjH1_G6Z0_0 person +RGT-FumEK7I_0 car +RGXgv5gqM8k_0 umbrella +RGiE9-CME30_0 motorcycle +RG6y27UUUMI_0 knife +RHHOcUqVF80_0 knife +RHSfZLRz95o_0 boat +RHrnX__15lI_0 car +RIBigSX5_90_1 bear +RImslgwYbYk_2 boat +RIwUvnURoqs_0 cat +RI14PaJgb7E_0 umbrella +RJ95URcz63g_1 motorcycle +RJ95URcz63g_0 motorcycle +RKZ4YVnDywQ_0 knife +RKa1tJXFTAw_1 cat +RK8ZJaF2QHQ_5 bear +RK8ZJaF2QHQ_6 bear +RLP9M0bfpWo_0 umbrella +RMapunE2wEc_0 boat +RNPKsQSr2o8_0 knife +ROfxuPZWET8_2 bear +ROkJ79Y9T7s_0 motorcycle +RPJ0SJeC5ck_1 car +RPJ0SJeC5ck_2 car +RPWms_VL6wY_0 bus +RPhdhEKBBAM_0 motorcycle +RP81F6rIP4w_0 motorcycle +RQ5liX_fOJw_0 umbrella +RREV1E0Mbhs_1 knife +RSXIvkOJQq0_1 knife +RSq71vJH9yc_0 bus +RStmsJCm7mo_1 car +RSztnKS1IYI_0 car +RTTysK1hBpg_0 boat +RTvVXaA35DI_0 motorcycle +RT0tTVP14XE_1 umbrella +RT0tTVP14XE_4 umbrella +RT0tTVP14XE_6 umbrella +pFCVfOX_UJ0_0 umbrella +pGJMt9Jmk_Y_0 car +pGnZDXcCjSc_0 bus +pHC850dBc-E_1 car +pHf0EP0QU9Y_0 cat +pHueI1IUqzg_0 car +pIhqwiD8cks_0 bus +pJXxn2DRWyI_0 bus +pJYetmKuiE0_4 bear +pJj28cMLcZc_0 knife +pJl14EZ6-Mc_0 umbrella +pKPRv5lL_DQ_1 motorcycle +pKz_g-J2O-A_1 bus +pK1umZxS4nE_0 knife +pLEV-uFmv6I_0 cat +pLI_HgRsRow_4 bus +pLQDtquQaSE_0 bear +pLp7vmowqNs_0 motorcycle +pMHRlQ2NxeA_1 boat +pMaT7qWMaV4_1 bear +pMg2xwjkfVc_4 umbrella +pNHKmiurxTg_0 knife +pOCvwILBOCY_0 boat +pOjuNMevoaM_0 car +pOq6RrgrXWY_0 motorcycle +pPyL4U8gYpM_0 cat +pP22coNl6r4_0 bus +pP5q-Bszfh0_0 motorcycle +pQMkOOTP0Lk_0 cat +pSJypg6az1w_0 bus +pSjKd_x9ycU_1 boat +pSz961UYSrY_0 motorcycle +RVvfyYc8jws_0 umbrella +RXAW31Vm7pU_0 motorcycle +RXQ-E6_Y__c_1 car +RZAlTTj0Z4o_0 motorcycle +RZAlTTj0Z4o_1 motorcycle +RZL2H_-y3vE_0 umbrella +RZrAehHE8aA_2 knife +RZrAehHE8aA_0 knife +RZ0yQkyeSd8_0 boat +RaZy_JiiJ3E_0 motorcycle +Ra48MJPLmUw_2 motorcycle +Ra48MJPLmUw_0 motorcycle +Ra48MJPLmUw_1 motorcycle +RbQTcoldE8M_0 bus +RbRqkcC6l_A_0 knife +Rb5tGSqtlFU_1 motorcycle +RcSm0O0Ylc0_0 cat +RdNjlTlNbEA_0 bus +RdP6hW5p6ys_4 car +RdUjywh70lM_1 cat +RdlWUo9fYmA_0 motorcycle +Rd4TvDZNwHs_0 umbrella +RfNyu5aooJs_0 car +RfrtTbza00c_0 boat +RgBWTOo9hqo_0 cat +RgC0rdZCy2c_0 motorcycle +RgFR8z8IzAQ_0 cat +RgUwlXzmX4Q_0 boat +RhYw3jSi0xY_0 bus +Rhqz5maRjNs_0 cat +Rh0zI8vpRWk_2 knife +Rh7Y69j41EY_0 bus +RiCptCjnrqk_0 cat +RiOw5wO0xTg_3 knife +Rid6twPtgIo_0 cat +pTGbMPGsbCU_0 car +pTSbrP23T0s_0 motorcycle +pVCT-jEaSPE_1 bear +pV8hPodV-zY_0 motorcycle +pXBltXzZZe0_0 car +pXcoix_wq4E_0 cat +pZC4kceO-0g_0 bus +pZJDlV5VS3Y_0 motorcycle +pZ7RohF8JgE_1 knife +paF1hQf-YFk_0 boat +palM4nIm6GU_0 motorcycle +pba0HVNnmbc_1 motorcycle +pcOsY0MSbh0_0 bus +pcb_jPcg_U8_0 bus +pcpHHo_gp-Q_0 cat +pc2aHxzJDtQ_0 cat +pdDVE4LsX54_4 car +pdDVE4LsX54_0 car +pdDVE4LsX54_1 car +pdDVE4LsX54_2 car +pdDVE4LsX54_3 car +pdDVE4LsX54_5 car +pd0IEWCwpUY_0 bear +pd1BZjvbFNI_0 knife +pgKdcFb2680_1 motorcycle +pg4m5Fi0Mhc_1 car +Riq87Q_unPU_0 cat +RjDo0UDX9Ws_1 knife +RjItZnZQBKk_0 car +RjqDxu3wf5o_0 cat +RkSzsg-k14I_0 boat +RktoQu-Wk0M_0 cat +RmFxIMl1tSU_0 bear +Rmpv0oMhUCc_0 bus +RnEWcQNxWGY_0 motorcycle +RnPY8wgKxj4_1 cat +RnQ-v8AJQbc_0 motorcycle +RnjU70B_0cU_0 bear +RpTRF_oB1-I_2 bear +Rpn1EcI_ESo_0 knife +Rp8euBdhkR0_0 motorcycle +Rp8euBdhkR0_1 motorcycle +Rqs856i0jbs_0 umbrella +Rrj0e5VSIgY_0 car +Rsw947loMaA_0 cat +RtSEfWF3PdI_1 knife +Rtng6SCToEM_0 car +RufUHX-TjyM_0 bear +RvHvTQC9Kr4_0 bear +RwC5kkt5VDU_1 person +RwC5kkt5VDU_5 motorcycle +RwVgY7zgnYM_0 knife +RwVgY7zgnYM_1 knife +RwYiNSlAYcE_0 car +RwpY0u7t3vE_0 umbrella +Rwp_dTfFI28_4 boat +Rwz5T35lNgY_0 cat +Rw5dzv79c-M_1 motorcycle +RxLwy_iZqKg_1 bear +RxWhDOyHYNo_0 cat +phJS1iN6HFo_0 umbrella +phTyZcbKeQw_5 bus +pihR4mhfwxM_0 motorcycle +pim0lzR8i1g_0 cat +pix5Cxt_fUM_3 knife +pjgi60dJalw_0 car +pjgi60dJalw_1 car +pjhNnA0142Y_0 motorcycle +pmszdloBDwA_0 bear +pmszdloBDwA_2 bear +pmszdloBDwA_5 bear +pnMd28rPX7M_0 motorcycle +pncTBxEM4WM_0 bus +pnjPhdpuKGc_0 motorcycle +pn0ZChK2ASs_0 bear +ppAj6dnl62Y_0 knife +ppAj6dnl62Y_1 knife +ppJXGy7snUw_1 knife +ppwjIgwParM_0 boat +pq1swOh85gc_0 boat +pq1swOh85gc_2 boat +pq1swOh85gc_1 boat +priwWNrQnkI_1 bear +prwglbuvyZ8_1 knife +prw0IWDYBUM_0 cat +pr3LOwTWNnk_1 bus +psOuOLCJNk8_0 cat +psTqTt0np_I_11 bear +psTqTt0np_I_3 bear +psTqTt0np_I_6 bear +psUASBNRwIE_0 car +psUASBNRwIE_2 car +psUASBNRwIE_4 car +ptCx-L_n2Yg_2 bear +ptNC5ou_rOQ_1 motorcycle +puZUIBS4Ceg_0 cat +puw9BfAKOHU_0 bus +RxiBbfFH3is_0 knife +RxiE2beIvjQ_0 bear +RyWLXS1Vrco_0 knife +Ry4q0UokRjo_0 motorcycle +RzWczJnyzmg_0 cat +RzWdM4_lg2c_4 bear +Rzj5xv434WA_0 bear +RzrQOptkjFM_0 motorcycle +RzrQOptkjFM_1 motorcycle +R0hj1kAnMgs_0 car +R0w6j1wmwo0_2 knife +R0w6j1wmwo0_3 knife +R1Fkwaa8CxU_0 motorcycle +R2FlyNrjZBQ_2 boat +R2FlyNrjZBQ_1 boat +R2Fps165H9g_2 knife +R2XiIC1qbAM_0 bear +R2YmjDNC8oo_0 bear +R2duXYQhnFA_0 car +R2sy6qbPc4c_0 car +R23ZSmBA2Rg_0 knife +R3zhr1iboG0_0 bus +R4ktPNCb564_1 bus +R4vLajpLSMk_0 cat +R5CBlOfUL4w_0 person +R5cIoEcqZ9E_1 knife +R5r3AIx_BoU_1 knife +R5r3AIx_BoU_2 knife +R6PuHPDiwPs_1 car +R6f_t-MqO_s_0 bus +R6tsNuvoTus_0 car +R6uZ5JpxQ88_0 cat +R6wk6JHQSeI_0 knife +R6wsV6cYN_w_1 bus +R7w-mdDyhG8_2 knife +R8TV702EIqs_0 knife +R8j0mjQR4lI_4 boat +R84Bj4PKOvE_0 bear +R84Bj4PKOvE_1 bear +R9LK4x3pO0Y_0 cat +R9L1I9EEE0g_0 motorcycle +R9zDzUslz9g_0 car +R9607CioN3U_0 car +R99fGQRB6rM_1 car +R-UGxl6KGoo_1 bus +R_LEKDTlVvs_5 boat +R_NxqXdz3RA_0 car +R_UPR78XIvA_0 knife +SAFptHT-UpM_1 boat +SAFptHT-UpM_2 boat +pvrO7c2imos_4 car +pwgqJO3yKHI_0 cat +pwwdlKxLCqQ_1 knife +pxBtDlmwesI_0 car +pxIlEGkEw5U_0 cat +pxwl3iVkx08_0 boat +pyAuY2v2U0I_0 cat +pyTXP2GZRuM_0 knife +pyTXP2GZRuM_1 knife +pyTXP2GZRuM_2 knife +py0K3KEYfjA_2 umbrella +py0K3KEYfjA_4 umbrella +pzZvI_g1S8M_0 motorcycle +p03u2BJIvyE_0 bear +p03u2BJIvyE_1 bear +p1p9QUFIi_8_0 bus +p1_thBtA2-g_1 bear +p2pRN03gXFk_0 cat +p26eBX5AGCo_0 boat +p3MF-uxvtWk_0 bear +p32jOqTS5ec_0 cat +p4MmW7gFlLI_0 motorcycle +p4MmW7gFlLI_1 motorcycle +p5NxEAfgmro_0 motorcycle +p5bLvlU8ua0_0 motorcycle +p5lUPYsz-HE_0 cat +p5vt7l9pW-0_1 motorcycle +p5vt7l9pW-0_0 person +p5_O08ZNK_c_0 motorcycle +p6GkhJZsCi8_0 cat +p6Rtu645O08_1 motorcycle +p6Rtu645O08_0 motorcycle +p6dBx3tBRr4_5 bear +p6dCoZRaQOA_0 boat +p6dCoZRaQOA_1 boat +p6dCoZRaQOA_2 boat +p7OlEbiu5to_0 cat +p7WwUD62qfY_0 motorcycle +p7gjVQyX07A_0 cat +p7pnYAaDqPI_0 umbrella +p7sHze5SC0g_4 bear +p8MEDllYMKg_0 cat +p8RUtiaGu5U_0 cat +p8ZUCNMnKpE_0 car +p89fuT8e_zk_0 cat +p8-8JqAgtv0_0 motorcycle +p9XjLjpQX-8_0 cat +p9by0qLqHOQ_0 knife +SAkHT1Ozg1c_0 motorcycle +SAkHT1Ozg1c_2 motorcycle +SA1Tb1XbngU_0 cat +SB1UBp1PVf4_2 bus +SDKsL-L7GbI_0 knife +SDbe9JVnITk_0 knife +SDk3Y3jzalg_0 knife +SEp92WMharw_0 bus +SExW2mVb1Mc_2 car +SExW2mVb1Mc_0 car +SExW2mVb1Mc_1 car +SE5Rg8Qpb8c_1 knife +SFB2FGuZb6w_0 motorcycle +SFMc-UCkcT8_0 cat +SF8c7EeFPPk_0 motorcycle +SHcJfBJBQe4_0 bear +SHxyKRdKRc8_0 cat +SHxyKRdKRc8_1 cat +SH1noq6GrKw_0 knife +SISqo1FBefA_0 bus +SIbLAYX2J_A_0 bear +SJAZnOnRtag_1 bear +SJsxWsiEuTg_0 motorcycle +SKNl4frouUY_1 knife +SLEOr8bmm2w_0 motorcycle +SLEOr8bmm2w_1 motorcycle +SLzqvins4p8_0 bear +SMYpv_Ea3w8_0 person +SM6BtnyDz5w_0 cat +SNZ0xGGmZvU_0 knife +SNhnfqJHoI4_0 motorcycle +SNl4Gq_2aVQ_0 bear +SNrosAtwG2k_4 bus +SOYkQc-toMU_0 bear +SOYkQc-toMU_2 bear +p-J0yyoF0lU_0 motorcycle +p_C9Zwt3N5c_0 umbrella +qAJSLnflSrQ_0 cat +qA5rC8MxCoA_2 bear +qCzILENpEWk_0 boat +qCz4ft26CAw_2 knife +qDobzjbo_aM_0 cat +qEcNn2_TQC8_0 cat +qEei5YCRiHA_0 car +qEj3r8dtvKg_0 boat +qE5fKHWTLMw_1 bear +qFR-yuWiHVk_3 knife +qFR-yuWiHVk_4 knife +qFwugOO0pC0_0 knife +qGjYX-iNrPE_0 boat +qGohF2oMPS0_0 motorcycle +qGxfRwBmBEc_0 motorcycle +qGxfRwBmBEc_1 motorcycle +qHKwI-35nNU_0 motorcycle +qIIu-MIIYIE_0 boat +qINDYDOlPLA_0 motorcycle +qIPydTwqwmI_3 car +qIPydTwqwmI_0 car +qIPydTwqwmI_1 car +qIPydTwqwmI_2 car +qIkNPwKd6ag_0 knife +qIkNPwKd6ag_1 knife +qInP3tWVtWE_0 cat +qJMxoAbx9YU_0 boat +qKxQVpaLChg_0 bear +qLfa8e4ffQY_0 bus +qL6LVXg4Vt4_0 cat +qMEMl1FFVIM_2 umbrella +SPRByN4TiFg_1 boat +SPsOjXxZymk_1 boat +SQ_ChhUwWng_0 bus +SRUB2kzDBTk_0 person +SSFOqr1ARgI_1 umbrella +SSaN8vntuYs_0 bear +STTRwCtQ8_8_0 boat +ST6aA292Pos_0 motorcycle +SUMc-5fiNzQ_0 motorcycle +SUnPNgAE_ho_2 boat +SUyRs3xvc9c_0 cat +SVBc-W37yW0_0 umbrella +SVSMGxy8Z6I_0 cat +SVXaBPnNWO0_0 knife +SVXaBPnNWO0_2 knife +SVt7vQ8LYZU_0 bear +SV70cwNA6o8_0 knife +SWJyq_mITbE_0 boat +SXmy9BLHr84_0 bus +SXvXN3waFWs_6 bear +SYCg5NuWc60_0 motorcycle +SaHw7yyoeJg_0 cat +SaSgclGWGwE_1 motorcycle +SaSgclGWGwE_3 motorcycle +Sa1iRLR4d_c_0 bus +Sa4L2rdyD10_0 knife +SbWCXCuXBqY_1 bear +Se3XbBA4N4o_3 knife +Se3wtx4DzwE_5 bus +Se3wtx4DzwE_1 bus +Se3wtx4DzwE_2 bus +qMlYXZy1Tow_0 bus +qNfS9Y5zs-Y_0 car +qOaABf_zb9U_1 boat +qO7qHolBYj4_0 bus +qO8D0E7MjOI_0 cat +qPGkJRPae6A_0 bus +qPMDgkgSTnA_2 motorcycle +qPaox7otsVI_0 knife +qPwAWEtJBqA_2 motorcycle +qPwAWEtJBqA_0 motorcycle +qPwAWEtJBqA_1 motorcycle +qPyR7CpZ6l0_0 knife +qP88t7GfZc8_0 knife +qQaIW7IjCZo_3 motorcycle +qQaIW7IjCZo_0 motorcycle +qQaIW7IjCZo_1 motorcycle +qQdtuBd-SgI_0 knife +qQlsMjenbfE_2 knife +qQ5tf8s7KrE_0 bus +qRO6U_tg6SE_0 cat +qR4kw8rf-FU_0 motorcycle +qSQGG-K89mg_1 knife +qSgOYqBt_8k_0 bus +qSnoKy6T22k_0 motorcycle +qTKtODdEZIg_0 cat +qTut_O_LppA_0 bear +qT00uOC9JpQ_0 car +qUuTEKdKNNg_0 car +qU7DT4ipQHw_0 cat +qVSnhT0Luh8_0 cat +qVyAlx4rMTo_2 bear +qV7U9CRjZGI_0 cat +qWN8i7sJyVg_4 umbrella +qWcXQWy7yw8_1 bus +qW-zRq8VTV0_0 boat +qX8RcjE0tjs_0 motorcycle +qX-YEHlu0Kg_2 knife +qZWxhCk8AX0_0 knife +qZf1fw737A8_1 car +qZyxILyLOv0_0 knife +SfZLu5uG7mc_0 car +SgDdyLB3fFo_1 motorcycle +SgHH9KN_nkY_2 motorcycle +SgOvlqqKbEI_0 bear +SgSsk-eeClA_0 cat +ShHLzcBozxo_1 boat +ShPl28Zw1kU_8 car +ShPl28Zw1kU_3 car +ShPl28Zw1kU_7 car +ShPl28Zw1kU_9 car +ShaLoFJZv-M_1 knife +ShhC84AwZ04_0 bus +Sh6uHJRUnP4_0 cat +SiSP3Kko4VM_0 bus +Si3psXQA46c_0 bus +SjLNVLIdpbc_0 cat +Sj0pcvct_3k_0 motorcycle +SkLwUmczAMo_2 knife +SkLwUmczAMo_1 knife +SkVIH0IZI1I_0 motorcycle +SlBZM22tlSU_0 knife +SlIzgQZ63h4_1 knife +SlWmnHWeqIE_0 boat +SlYqzpZkWho_0 bear +SmCvuBfyU5o_0 motorcycle +SmCvuBfyU5o_1 motorcycle +Sn8nb_cv5K4_0 motorcycle +Sn8nb_cv5K4_1 motorcycle +So5dCmgNRtU_0 bear +So-dFj7N07Y_0 car +SpGfQe7sWIQ_0 motorcycle +SpuAy2Z1ejE_0 boat +Spx8fHkY0Ac_0 bear +SqUzKvBRVmQ_0 cat +SqkoepvLN3c_0 motorcycle +SqkoepvLN3c_1 motorcycle +Sq-LvVdVwhc_4 bear +SrBwCHcEe4g_0 cat +SrPgW-L7Gps_0 bear +SrTxMAryank_0 knife +SsQb12lMU_w_1 car +SsQb12lMU_w_2 car +qZ0egYy10zs_0 cat +qaKYHGIZ8tU_0 cat +qantWNz3Z-k_0 bus +qc1U41zjMfI_0 knife +qeSfa-Xin3s_0 bear +qfZHHSjai5Q_3 motorcycle +qfZHHSjai5Q_5 motorcycle +qfZHHSjai5Q_0 motorcycle +qfZHHSjai5Q_4 motorcycle +qfZHHSjai5Q_6 motorcycle +qf4dZ323eu4_0 cat +qf5FQP-vjpY_3 bus +qgYBD0GBerg_0 knife +qglTXvFe5vw_0 motorcycle +qgr1pdkQkKM_1 knife +qhTOaoL2B54_0 bus +qhgQ0_y6Jr8_0 motorcycle +qhyihSkbubs_1 bus +qiW4cUVZCJA_0 motorcycle +qjfkIHC3sNA_0 bus +qj1y76m_WFg_1 car +qklXdTo1CKQ_0 truck +qlGmmBY7ITI_0 cat +qlGmmBY7ITI_1 cat +qlfCKWLj_xU_0 boat +qlvwUVksAC4_0 cat +qnaQOGGmyhI_1 motorcycle +qo2tG-wOpLI_3 car +qpBRU2SONe0_4 bear +qpNPlLO7Wdo_6 bus +SsWwZCQR8pA_1 bus +Ss6lM7iutJ0_2 boat +Ss-ENa079_Y_0 car +Stg0xs4yv5A_3 bus +Stg0xs4yv5A_1 bus +Stg0xs4yv5A_2 bus +StoHoHg6XHo_0 motorcycle +SuoVrAXkHsM_1 boat +Sv-Xsjm8Seo_0 boat +Swfda4hcQzo_18 umbrella +Swfda4hcQzo_0 umbrella +Swfda4hcQzo_3 umbrella +SwrxLGIVuNg_1 bus +Sw01FqLPH0o_0 motorcycle +SxxBAhDGWzU_1 car +SybtH9db7tI_1 boat +SybtH9db7tI_6 boat +SybtH9db7tI_0 boat +SybtH9db7tI_4 boat +SybtH9db7tI_5 boat +Syk5Jc9_tQA_1 boat +SywBQoMh8Q8_1 car +SzD0AW8MKxY_1 car +Sz3ay4xexe0_0 motorcycle +Sz3oWSS6V3s_0 bus +S0AoM2Xz64Y_0 motorcycle +S09dKnW798o_0 cat +S12WKCebYHg_0 boat +S2YoTKzOHW8_0 umbrella +S3O_xjPQToU_0 knife +S4lNN0zJE4A_0 cat +S49Hdfpc-SI_1 boat +S5VjgUVKjV0_0 cat +S5Z4g_SORHc_3 knife +S5Z4g_SORHc_4 knife +S6crKzUWKYI_0 umbrella +S6ksiMdECu8_0 umbrella +qp11ZgRmeck_1 motorcycle +qqd7FMwn5Ks_0 cat +qqmk0BKAubw_0 boat +qqo83uqRldw_0 motorcycle +qqumKQ_igJQ_0 motorcycle +qqumKQ_igJQ_1 motorcycle +qrHPEAVq_yE_1 boat +qrJljeVBE-k_0 boat +qrJljeVBE-k_2 boat +qrTOqXRwHqM_1 bear +qrTm-7zA5FM_1 motorcycle +qrU7MAMf42A_0 motorcycle +qrfZoDvW7wI_2 bus +qsFkwL9ikBE_6 umbrella +qsFkwL9ikBE_0 umbrella +qsbpGZepU_4_0 motorcycle +qs4ACjrDQvo_0 cat +qtEJPGYfmb0_0 motorcycle +qtQNJD43Z30_0 knife +qthVtX1KeJY_0 cat +qtmXJD337Sg_0 cat +quMSh4JZfSE_0 bear +quSzbk4CkBE_0 car +quZjkqmOTys_0 cat +qvAPzGCqVG0_0 bus +qvAPzGCqVG0_1 bus +qvCVL7reF8g_2 bear +qwBsDRYIhwg_0 cat +qwI3fCK486I_0 cat +qwZ_bpVY018_1 bear +qwcgkEVHQS4_1 motorcycle +qxwgvTIA0Oc_0 umbrella +qykj452YYlU_0 boat +qzjG5RMNfB0_0 cat +q0tjDTtHr00_3 knife +q1LbqldHuM0_0 knife +q1QElQCedrc_0 umbrella +q15Lr3-V3qI_2 motorcycle +q2K3ctdaVGU_0 knife +q2MasRNKQxI_0 bus +q2NfowB59fs_0 motorcycle +q3J7hUfBGGQ_0 cat +q4EXWy685Wo_0 person +q4EXWy685Wo_3 motorcycle +q4EXWy685Wo_6 motorcycle +q4EXWy685Wo_7 motorcycle +S7SEfKdokC0_1 bus +S7-k1XdAR7Q_0 cat +S8BbQRnxfqY_0 cat +S8WFgIrdEyI_0 car +S9LooqaA-VA_0 cat +S9wDiwQMla8_0 person +S9wDiwQMla8_1 motorcycle +S9wDiwQMla8_2 motorcycle +S9xCWTCFhNc_0 motorcycle +S-T-e07Bgys_0 motorcycle +S_K_nwYUS2o_0 cat +S_09gd9e0zE_0 boat +S_5w6lmw0DI_0 knife +TAzjOrAfzFM_0 cat +TA1NbMN7gNo_0 motorcycle +TBvuwl0phUE_0 motorcycle +TBy---hD-FA_0 bear +TB9qJG8A-H4_0 car +TCS6svwO2AE_0 boat +TCVj-PtxnsQ_0 bear +TDSmQkKnGFU_1 car +TENive2WCAw_0 cat +TFUV5Dy2MvE_0 motorcycle +TFu5bNUW02Q_0 bus +TIZr3Y-PLQM_1 knife +TIpoS2Jymv8_2 knife +TJJgVPay9LE_0 bus +q4zFevdC3-w_1 knife +q5D67534lFM_0 motorcycle +q5ESvcujAps_0 person +q5wOimcVyaI_0 cat +q6YyhMSTSjg_2 bus +q6YyhMSTSjg_3 bus +q65QzEDi_jo_1 motorcycle +q8nG4OvfGhY_0 cat +q8oKL5zvWZw_0 cat +q9QycGD31Co_0 cat +q9ZSVLXRUx8_1 cat +q9p4QZdwQ0I_0 boat +q-Sw3Dx1Xb0_0 knife +q-lbxXK_UY8_0 bear +q-nt9k61jqQ_2 boat +q_NnyABqOFg_3 boat +rAcvNOp95pA_0 car +rApBsMx8ZjU_1 umbrella +rAtKVQ_h94Q_1 car +rBLqbf-KdaY_0 car +rBjCxCwLz84_0 car +rBl7T312SPQ_0 cat +rBnSmzTRsqE_0 car +rCAA1xoobto_0 car +rCOxllaoO64_0 bear +rCrQRhaJeAA_0 bus +rDEW_AdTSH4_1 cat +rDEdeXsgOdU_0 umbrella +rEL7A7rKARs_3 knife +rFF0purpqAU_2 knife +rGgvqpRsaew_0 bus +rGlpoWppAfU_0 car +rG4cDTukyNw_0 car +rG4ld81Rxt8_0 car +rHHUlsaTde8_2 bus +TKCXvzTT2ws_0 umbrella +TMyv9XNlPGQ_0 bus +TQWq_YDrKc0_2 knife +TQm0C-2ersM_8 boat +TQm0C-2ersM_10 boat +TQm0C-2ersM_1 boat +TQm0C-2ersM_5 boat +TQm0C-2ersM_6 boat +TREARdQ16GQ_0 car +TREARdQ16GQ_1 car +TSQwlIeADdw_0 bear +TSQwlIeADdw_1 bear +TSQwlIeADdw_2 bear +TSpUcayboiM_0 car +TS7UuEszy9E_0 car +TTQQky-HcCs_0 knife +TTdbV_lHq_s_0 cat +TUrnPZr3eXs_0 bus +TVjvTR7CrNE_0 knife +TVvo40ERO9Y_0 cat +TW6cU7OYa60_1 cat +TXrnNVUe53o_0 boat +TXsQGHJjWhI_2 knife +TX2BAlXe5IA_0 boat +TX2BAlXe5IA_2 boat +rIUepAhKVnM_0 cat +rIc3ZEnqjQA_0 umbrella +rIezbmq7N9U_3 bear +rI79TJwwnW4_3 knife +rJGGo2bI150_0 bear +rJGGo2bI150_1 bear +rJGGo2bI150_2 bear +rKiQjOPzf0s_0 cat +rKs2bGgU29k_0 cat +rLm1866Q28U_3 umbrella +rLm1866Q28U_0 umbrella +rLm1866Q28U_1 umbrella +rNlm7i1BcaQ_0 cat +rNw1jiERG4I_1 car +rOtd7pdh-zY_0 cat +rO0qo7r4TTc_0 cat +rPCOxxRwiTM_0 bus +rP6vb-cxVcI_0 bus +rQBwAWkz3Ao_2 boat +rQBwAWkz3Ao_0 boat +rQBwAWkz3Ao_1 boat +rRL4f466oNQ_0 umbrella +rR9vwlyXtYs_0 bus +rSNfdcbzEhE_1 boat +rSNfdcbzEhE_2 boat +rSNfdcbzEhE_3 boat +rSNfdcbzEhE_6 boat +rSNzuWEgSeg_0 cat +rSWYvSf29vQ_1 cat +rTM-3OYHQZA_0 bear +rTM-3OYHQZA_9 bear +rTreVVS3XVg_0 umbrella +rUcsGq10bCk_0 umbrella +rWLG9njOx1k_0 car +TYuoW3gezZ4_1 car +TZFETDh9bQo_1 bear +TZFETDh9bQo_3 bear +Tain2YW14ok_0 umbrella +Tb943q0WnTY_0 car +TcfdUbzZcIc_0 knife +TcnKT-jCrxQ_1 bus +TcnKT-jCrxQ_0 bus +TcnKT-jCrxQ_4 bus +TdmeXkKeGmE_0 knife +Tdxsosl1CIk_0 umbrella +TeF2gxyzjF8_4 knife +TeM8oPJR8nM_2 bus +TeM8oPJR8nM_4 bus +TeM8oPJR8nM_7 bus +TeSMF-Tw8b8_0 bus +Tf8ZmK4GZYU_0 bus +Tf9piH7b4Js_1 bus +TihSkV4th6I_0 umbrella +TimXSaV1u4M_2 bus +Tjs55_3zB_o_0 knife +TjvHNNlcym8_0 knife +TjvHNNlcym8_4 knife +Tj-U_ZtaHe0_0 boat +TkmEiKe_Uto_0 boat +TkuUMAPSGiU_1 car +TnN1RBRfLnE_0 umbrella +TnN1RBRfLnE_1 umbrella +TnXDBpRvE_U_0 bear +rWw_OZqgPk8_3 bus +rYlL6avPERw_0 car +rZDchhWp8lc_1 bus +rZ7XejB4nyk_0 boat +rawi3Ka9Oew_1 car +rawi3Ka9Oew_0 car +rbONk59p13Q_0 bear +rbWOxoprQ2M_0 bear +rbXmAC9QV2A_0 car +rbjK97ECn_A_0 boat +rcrE_BJU-n4_0 knife +rcrE_BJU-n4_2 knife +rfksy8z9X40_0 car +rgWglS6-TTw_1 knife +rhIa7DWBXUM_1 car +rjVLfZDg-1g_0 boat +rk9SO8fR7-0_1 bus +rk9SO8fR7-0_4 bus +rlBfiB0epGw_1 knife +rlLJTjn9vkk_0 umbrella +ToclpwxGMe8_0 bus +TpKpXHgy7yw_2 knife +TpKpXHgy7yw_5 knife +TqPnQuSGm2Y_0 bus +TqZZfXdm7D0_0 car +Tqnj4qeawHg_0 boat +TqsQOw3CqXo_0 bus +TrXkieSIkII_0 boat +TsfcgwFff0k_0 bear +TsrQwMo3niY_1 bear +Ts8Wofx6QYY_0 car +TusmYht5g7o_0 bus +TvbiwdoAnv8_0 boat +TvvBAOBoHFU_1 umbrella +TwEihF94LGQ_0 umbrella +TwSkZlbuaEU_0 bus +TxUm-m-jFQM_0 knife +TyV9inNHHAE_0 bus +Ty_FDwb_nLY_2 car +T0Mp-gJmMlU_2 bear +T0Mp-gJmMlU_3 bear +T0tT7l2X1_g_0 bus +T1Zywya-PcI_2 car +T1Zywya-PcI_3 car +T1Zywya-PcI_1 car +roNPRQwafcU_2 bus +roNPRQwafcU_5 bus +roW8_xIYVAk_0 knife +roXQ3vv08_A_0 bear +rqA8P346qIQ_1 boat +rqDqbsbIcc8_0 bus +rq5jwk8hqYA_0 bus +rq5jwk8hqYA_1 bus +rriv5ZJYcJI_1 knife +rsMmhzkVg_0_0 boat +rta_HO-3L_A_3 bus +rwH7x0MR_38_0 boat +rwS5mEyV7Go_1 knife +rwS5mEyV7Go_2 knife +rwcVAIM0TvE_0 bus +rwcVAIM0TvE_1 bus +rwu0xKkvzvA_0 knife +rxRxMZ6DIjw_2 umbrella +rxSJHCdoi0c_0 bear +rxm15TcjWqQ_0 knife +ryBGF3WFvsY_0 bus +ryBGF3WFvsY_1 bus +ry0Pnb8VkxU_0 bus +ry0Pnb8VkxU_1 bus +ry0Pnb8VkxU_3 bus +rzDa9eW_dpg_3 car +rzDa9eW_dpg_5 car +rzOhM6n6Amc_0 boat +T21Uim3jGuo_1 bear +T3wZwUQ_7q4_0 umbrella +T5ZgfFcAd94_0 bus +T6QiKZd4bH0_0 knife +T7h2fJLtABk_0 knife +T8C-sLfGg3A_0 boat +T-5AESRu0pM_0 car +UAptbKXXoJI_1 bear +UBk45sVKl_o_0 umbrella +UCnTA86V3o0_0 knife +UDmjHWk8iRk_1 bear +UE1kUiVy7LA_1 car +UFPrfB6_TJY_0 bear +UFQmHju3MrM_0 bear +r1JK0UIvyoM_0 bus +r1YNttJqXjI_1 bear +r2GN4IDacgM_0 boat +r2GN4IDacgM_1 boat +r2GN4IDacgM_2 boat +r2GN4IDacgM_3 boat +r2sw-3mWNEQ_1 boat +r4U8cMe6_Uo_0 umbrella +r4cneWcmGJc_0 bear +r4cneWcmGJc_1 bear +r43KKtRQNxw_0 knife +r5c09tdbF3U_0 knife +r6HzXMpwuOg_0 boat +r7V8M9vMX8I_0 boat +r8oV5neCRZc_1 bear +r-Wqqn-oS_0_0 bear +r_squ5DWzV0_0 bus +sAa0aLc0rvM_0 bus +sAo-z30biYY_0 car +sAqB_9DrpiU_0 boat +sCGJB9oAeHo_0 car +sCX1zbdQvbE_0 boat +UHvwjd6eSDY_0 car +UH6GKx07mu0_2 bear +UIlo6WvfABM_0 boat +UJ7xasCu9yw_0 knife +UKdl8BrKy4g_0 knife +ULTTzu_-eQI_2 bus +ULgPda0ny1Q_0 boat +ULxGPhbhuwI_0 umbrella +UMQ6fAZTiLo_0 umbrella +UNfKxOwP1V8_0 bear +UNyq1SNbNPk_1 bear +UP2WXifDFc0_0 bus +UQdjo1v_Hv0_0 car +UQrP0Wa7bfA_0 bus +UQ90qkTMSes_0 umbrella +URiNDCZBU7E_1 car +URmMAndDPfQ_0 boat +USYudaDNkeU_2 knife +USYudaDNkeU_3 knife +UTx1Fw7nQcQ_0 bus +UVGq9IRroYo_0 boat +sDSmkWE8qw4_0 knife +sEnhkLttWlw_0 bus +sFgXir9g_Os_0 car +sF2EQhRNlQc_0 umbrella +sGpQTqemybM_0 bear +sGzXdAI4YSQ_0 bear +sG_AruJlxiw_0 umbrella +sJA7-N7htNo_0 bear +sJL716urwpY_1 car +sJL716urwpY_0 car +sJTLB7bgb0k_1 knife +sJsEpKneYMs_1 bus +sMm8f8vBx7c_0 umbrella +sOQWtx6GiR4_1 umbrella +sOQWtx6GiR4_0 umbrella +sOvnHbg6d_8_0 umbrella +sPDY-ey2kNA_0 umbrella +sPDY-ey2kNA_1 umbrella +sQEBpH647Mw_0 umbrella +sQJr7LooP_s_1 boat +sQftML4HXiU_1 knife +sQvi3OxMoKU_0 bear +sQvi3OxMoKU_1 bear +sQvi3OxMoKU_2 bear +UWJIq_1uAnA_0 boat +UXDmIQTthAE_0 knife +UYRhIhbuh34_0 boat +UanzlUcmoJY_1 bus +Ubj2t-7KcJk_2 car +Ub5O76sDojg_0 car +UcBLQsI3Dzs_0 car +UcKyiCjpXoA_3 bear +UdFEBlYt9tM_0 umbrella +UdaAkO2f_pU_0 bus +UeQLdrnbe8E_1 bear +UeQLdrnbe8E_3 bear +UgHNBgeg9cY_3 knife +Ugh33I0Qxi4_0 umbrella +UgkXJsrPys0_0 umbrella +UhgJaZWsdCQ_0 knife +UhupGJ7k3Q0_0 knife +UhvhrEMHY0E_0 boat +UhwOdFtF8os_0 bus +UiZ3tYMpOic_1 umbrella +UjTdR_85bTo_0 umbrella +sSPe9VqmSuU_2 bear +sS-GtompdcQ_1 boat +sUhpJsSmrzA_4 boat +sU-mmzCCGmg_0 bus +sVbrxAG6jtA_0 car +sVkPUjUh0UQ_0 knife +sV9ymK-zZ8A_4 bus +sV9ymK-zZ8A_6 bus +sWfQh6SsvG0_1 boat +sW7n8r3vvl8_1 knife +sXwrjhXbAwA_0 umbrella +sYE45Xnof5I_3 bear +sY1i3-cQv70_2 boat +sY3G5eOlysI_0 bus +sY_jGNxKdYw_0 knife +sY_jGNxKdYw_2 knife +saBAx3Xw2PE_0 bus +sbR26E99_A8_0 bus +sbmsWqsHD9M_0 bus +sb1unJ1sby8_0 knife +sb1unJ1sby8_4 knife +scFiRRTU5jg_1 bear +scJFbu3WboQ_1 car +sc-BJ-WirDo_0 bus +sdHNJK0mfWQ_3 bus +sdd5ViCUDwY_1 bus +sfVwMcMm77E_1 umbrella +sfVwMcMm77E_2 umbrella +UjxwNRWfxBo_2 bear +UkBlnrNOssQ_1 bus +UlLwBfXpz4A_1 bus +UmAOVqCB6UM_0 bear +UmBxMf5cHV4_0 knife +UmewKWpE2qE_0 car +UrRiUQPaxic_0 umbrella +UrxeEW4FBq4_1 umbrella +Utvo55GUNyg_1 bear +UutgI7H2EPc_0 bus +UutgI7H2EPc_2 bus +UutgI7H2EPc_4 bus +UutgI7H2EPc_5 bus +UutgI7H2EPc_6 bus +UvsMOU9XGYk_0 car +Uvsup5BdpLM_0 car +Uwlk3sF-l38_0 knife +UxD-6ScNF1U_0 bus +Ux3oyD0wLig_0 boat +Ux_-m16Ntqs_0 bear +sgDzqYTo0GI_0 car +sgDzqYTo0GI_2 car +sghMPNg9wB0_0 bus +shgKQ2FcjfM_1 knife +siNixoeB9Ew_0 car +si8Uk6frpqI_3 knife +sjBWnj8kKVs_1 bear +sjESht-PXb0_2 bus +sje-nlCBYAk_0 bear +sk5gj6VnXds_0 boat +slGCyLNlI3w_0 umbrella +slgsRri0IUU_0 bus +sli0aHrS-l4_0 knife +soPkYPTLD-Q_1 boat +soe3qmwZTEE_3 knife +soe3qmwZTEE_4 knife +splTIYA-rtY_3 knife +srUGXKwzLf0_0 bear +U0G9nt_JMp4_3 knife +U1jXflUgiSo_2 knife +U1p1HQ3ZsUo_2 car +U1tGGfRyOzY_1 car +U3BQYG5-Koc_0 bus +U3pwXnANDgk_0 knife +U3pwXnANDgk_6 knife +U4nccTmpY0A_1 bus +U7N--AsibJc_1 knife +U7fW1r0kRYw_1 car +U7-_NQlr8l0_1 bus +U8EGQyjwfEQ_0 car +U85wCYoCIZ4_0 knife +U-B7Xkx_rF0_1 knife +suQJeplwaco_1 bus +svZPjH3EGcI_3 car +swj8kdhr03w_0 bus +swkyfcVE17I_1 umbrella +syJ4LBRPwjs_1 knife +syY8MaSUvJI_0 car +syfJEZrVzqA_0 bus +sy9XCn-ebrE_0 car +szClXDUETvQ_0 umbrella +szW2Gonojss_0 knife +szXVjlTlt3w_0 bear +sziUCgMKvrM_0 bus +sznHM_K2obc_1 bus +sz6Zoh7MfnA_0 bus +s0ABooHpZjo_0 knife +s09Dr7gZ5G8_0 boat +s1t73kIOSQU_2 bus +s2BVmX4vImY_0 knife +s2gkrcGsOxU_1 bear +s2nioy3J4RY_3 boat +s2nioy3J4RY_1 boat +s2nioy3J4RY_2 boat +s2qgkHBVQxo_0 bear +s2qgkHBVQxo_1 bear +s3lwoM0rD2U_2 boat +s3-sF0tSY8w_0 umbrella +s6BicsP9eBk_0 knife +VA3OWlsrD28_0 umbrella +VBPWsv5FfbU_0 bus +VBPWsv5FfbU_1 bus +VBr3P_OGawE_0 knife +VB6eUS7LSfM_1 boat +VCCevTa32Ng_0 car +VDz1RZU6x5c_0 bear +VESEWamKy10_0 car +VFv1UuT7klg_2 knife +VGAYYimByOM_0 car +VGwSM3IXcJ0_0 boat +VG_OHq6R1AE_0 bear +VHiMLGyNYgQ_0 car +VIASAf569_k_0 car +VIxj6BV3kgM_0 umbrella +VJZpavOgVEo_0 umbrella +VLaCK3u84vI_0 umbrella +VMLuyFD54AQ_2 boat +VMXrHUjXjyQ_0 boat +VMXrHUjXjyQ_1 boat +VMi5mAdZyZI_1 knife +VMs0jemUzI0_0 knife +VNuYRPiFrus_0 bear +VN-BCqBlrhs_0 car +s8vzssNUlOA_0 knife +tAOx6NFDD9I_0 knife +tAxbjy_edDI_0 umbrella +tBOSPNFbuv8_0 umbrella +tBQRfKeIYZc_2 bear +tBgtSnOMOwM_0 bear +tBh6HxQHmrs_0 knife +tCZLl-MZJp8_0 car +tDYPtg0At_Y_0 bear +tE42n_1PW6w_0 bus +tFfqpeBbvr0_0 umbrella +tFjlTZqwoWI_0 bear +tGycfa97LVU_1 bear +tIX4eIYzfD8_0 knife +tIX4eIYzfD8_1 knife +tIs05U9pd04_3 knife +tIs05U9pd04_1 knife +tIs05U9pd04_4 knife +tIs05U9pd04_5 knife +tJXbZyaUOD4_0 car +tJhfshKvRmE_1 bus +tJhfshKvRmE_4 bus +tJ01Y3R3Qmg_0 umbrella +VOcplsa6Gq4_2 knife +VOcplsa6Gq4_5 knife +VPI_Nm3GHHc_5 bear +VPI_Nm3GHHc_2 bear +VP0u_E6FOsY_1 car +VR_V9WaFYn0_0 umbrella +VSj9dXwt7zI_0 bus +VSxoLvaJN2Q_1 bus +VUcCABjVSO0_0 car +VU2lUX4NdkM_0 knife +VU2lUX4NdkM_1 knife +VVg7sbsw9vY_0 bus +VWpm6_Uhis0_2 boat +VX9TPrjMcOg_0 knife +VX9TPrjMcOg_4 knife +VZ5r0BHRf84_0 boat +VaW7Go5pX-c_0 umbrella +Va50KanUO94_0 umbrella +VbA0B1JcpNY_2 knife +VbeIRLOQ5pI_0 bear +tKCjJuulqx4_2 bear +tKCjJuulqx4_3 bear +tKCjJuulqx4_4 bear +tKN3Qo0oUoc_3 knife +tNvGTzks1yw_0 car +tNvGTzks1yw_1 car +tO0igm1AwqU_0 bus +tPae9uGqDog_2 bear +tPzWEC_9_H4_3 knife +tQpyrprwwc0_0 umbrella +tR2sDFGND7g_0 bear +tSEneDiCrqg_0 bear +tTFTWquOTi8_0 bus +tTjbx39rZMk_0 bus +tT2pUZ0W33A_0 bear +tUHf6Ynx_vI_0 knife +tVJE-0uNX1s_0 boat +tVTkAh80t5I_0 umbrella +tVuL82POt-I_1 car +tXMBGjGduCM_2 knife +tXsMGHCKw7U_1 boat +tXwfqREzEtI_0 boat +tYGp2PFiAUE_0 knife +tYas1z25M_4_2 knife +tYcNeSisfpI_0 bear +tYdhIaTDwiE_1 knife +VdLohVQNC5Q_0 knife +VdLohVQNC5Q_1 knife +VdLohVQNC5Q_5 knife +VdLohVQNC5Q_6 knife +VeUIJlyGjkY_0 car +Vekx17G8mkk_0 bear +VfBqMWT6aRM_0 knife +VfKgW5eSGsk_0 umbrella +Vhmj1OGGQuc_1 bear +Vhn-8bCU70s_0 bus +Vh21adwevRU_0 bear +ViXmx_D5BAY_0 knife +ViXmx_D5BAY_3 knife +VizxeIzWEFw_0 car +VjF-G6FQooU_0 boat +VjS5w2pc0tA_1 boat +VjvpOU349zY_0 bear +VkDn2-1H23o_0 umbrella +VkDn2-1H23o_3 umbrella +Vk43AD4O_hc_0 boat +Vnrw6Fjmj8I_0 bus +VnwwgTO4w_k_0 umbrella +Vn4aKSlYXX4_3 bus +VppPgMZqfEQ_0 boat +Vp0kah4_m6w_0 boat +Vp0kah4_m6w_2 boat +VqHSuVVKfjs_0 bus +Vqo2RiAzLnU_1 car +Vrnm_kf7OCs_0 boat +VsDgOcOWqXw_0 bear +tYofvh4_3K4_0 bear +tadYkEU5suY_1 knife +tbIUesoKv9Q_1 bus +tb_hKPkH2co_0 knife +tcFQ5kE3PKM_0 car +tcFQ5kE3PKM_1 car +tcSHrlGTFJc_0 knife +tc912gGdckQ_0 boat +tdjDSO8NFx4_0 knife +tdpAPPsHlDQ_1 bear +teJyM5tywno_1 bus +teQkZqDa1lw_0 knife +teb83RDwop4_0 bear +tgSfan8G7wo_0 car +tgVXG7H_acI_0 umbrella +ti3J-8aWPcw_0 bear +tjldcvPuif8_0 bear +tj4mnSXX2DM_0 car +tm2bmSBR4uE_0 knife +toiMoCxSyKY_2 boat +tos1ELGZH0M_2 umbrella +Vs3Mi3Ch_EQ_0 bear +VtHzTaDh4WM_0 bear +VtHzTaDh4WM_1 bear +Vt8DAmG3nHs_0 car +Vu4xkIEs6U8_0 boat +VvXxRawsOCs_1 knife +VvXxRawsOCs_4 knife +VwYEgB5HOD0_1 bus +VxdUG7Sinyw_0 car +VyDNhpvCuc8_0 bus +VyfIuIcelhc_0 umbrella +Vz3wJsLA_gI_0 bus +V0NnR8HLSbo_0 umbrella +V0o8kxcOZRc_2 bear +V1a9QcSegdw_2 umbrella +V1dqjmHNyIY_0 boat +V23vmoZYoVw_0 bear +V4o7I9cLp-g_0 bus +V6nKvvfzWpg_0 boat +V64pvhB8sKU_0 car +trAReSHvUdQ_0 car +trAReSHvUdQ_5 car +trAReSHvUdQ_6 car +trAReSHvUdQ_1 car +trAReSHvUdQ_2 car +trAReSHvUdQ_3 car +trAReSHvUdQ_4 car +tsNhgDUKwHw_3 knife +ttdTnGOIBmA_0 umbrella +ttdTnGOIBmA_3 umbrella +tvVLkJ0HTQQ_3 car +tvew-P2UPL4_0 umbrella +twiEfNprSoE_0 knife +twiEfNprSoE_1 knife +tw7jf9U2-kM_2 bus +txpIIsM1T8U_0 bear +tx2dZF1Ckxk_0 knife +tx5tKODiGuo_0 knife +tx5tKODiGuo_1 knife +tyO37NBAS1Y_0 bus +t1UtwxOBGvE_1 knife +t1vrE0cEB80_0 bus +t10FRgv9o5M_0 bear +t10FRgv9o5M_4 bear +t14PUW9SINk_0 knife +t31z17N5skw_0 knife +t31z17N5skw_1 knife +t31z17N5skw_3 knife +t31z17N5skw_4 knife +t33TQH8-7tg_2 boat +V9UCv2qhsxc_0 car +V9ulnUIQGJU_0 bus +V9ulnUIQGJU_6 bus +V-KNIu_PsaQ_0 bus +V-NvBHig1i0_0 bear +V-tMggTxBu4_0 knife +V_Bb7A55f-c_0 car +V_dJ2KuqfOA_0 boat +V_dJ2KuqfOA_1 boat +V_t8pbEf8bA_1 boat +WB7fT2tI7Pg_5 car +WCSEuwFm7KU_1 car +WCfc8YGLu1o_1 bear +WCfc8YGLu1o_3 bear +WDgLmrXq4vg_0 umbrella +WHLIJlNh3TQ_1 knife +WHQXE5tuTXk_0 car +WHUaoqVF57g_0 car +WIdj4ovuDWQ_0 bear +WIdj4ovuDWQ_1 bear +t4oaGCoTBZc_0 car +t42tnyTtYWE_0 boat +t7OKXKxjHls_6 bear +t8X-x_7pv94_0 car +t_-dK1Xhg90_0 knife +uAjqm8B-aio_0 knife +uB_Hurzj4s0_0 car +uGEDuDcqqvU_0 boat +WJ2A2XRRTw4_1 bus +WJ_vIH7FJsQ_0 car +WKDhXr_5mbI_0 knife +WKKFM7oRSd0_0 bear +WKS6aq75gk0_3 knife +WKV4j8-G1Nc_0 knife +WKfQfA_YQTY_3 knife +WKubVTrND7s_1 knife +WKzUT3zOIU8_0 knife +WLxzHH6iJlk_4 boat +WMSu-XOQe5w_4 bus +WMSu-XOQe5w_0 bus +WMgP1z0x0Io_0 bus +WOVTnN-HcZ0_1 bus +WOxTA78OlZU_0 knife +WPqEyeVtih8_0 bus +WPuItCUuEkY_1 knife +WQAr1enuPKw_1 bear +WQX6ptTAKHg_0 knife +WSc0kYKLGTg_0 bus +WStgEyiPBBE_0 car +WSvHn5XJq0Q_0 knife +WS0DayzAv80_1 boat +WS0DayzAv80_2 boat +WTXytzbF5lU_0 umbrella +WT69VoU2Hps_0 car +WVx9vOoutGo_0 bus +WWKuCF2FuYk_0 car +WWm9iMkKk-g_0 knife +WW7ib8XAVz0_0 boat +uHqj6xQGOYg_3 bus +uHqj6xQGOYg_4 bus +uHqj6xQGOYg_6 bus +uHqj6xQGOYg_7 bus +uIKZlXUoHOc_0 bear +uJMFDY-BKiQ_1 bear +uJMFDY-BKiQ_4 bear +uKdOuLYJjrg_0 knife +uK-zcpEE8nE_5 boat +uLdXkXRsHok_0 umbrella +uMK6b2TG8rc_0 bear +uMV37U-DNUQ_0 car +uMciOwjd0GU_0 car +uMciOwjd0GU_1 car +uMd1DmjxAZQ_1 car +uMj3V0s7mUo_0 bus +uM_jxm7bFp8_0 boat +uNDkbmlEYeQ_0 bear +uO7OtV3J1AY_0 bear +uPE1o5dCYDc_0 bus +uQhMkVrdghM_0 bear +uRLAyu-3l0A_0 knife +uStpLanz0fU_0 car +uTAqzBGMDOc_0 bus +WYwRW_t4jb8_0 car +WZK5IqBtpGE_3 knife +WZgxjIvc2nk_0 boat +WaEyVBSggwQ_1 bear +WaaW6bElWCM_0 car +Wb20JaIrr8M_0 knife +Wb20JaIrr8M_2 knife +WcNlbTBZM64_0 umbrella +WdIATjW74Pc_0 boat +WdYFXDv4TEo_1 car +WdgTHJurLx0_0 umbrella +Wd0xTEH2d9k_0 boat +WejCws8AoxE_1 knife +WejCws8AoxE_2 knife +WejCws8AoxE_3 knife +We4_tuFKyGE_0 knife +Wf6hHpxRW_Y_4 knife +Wgx6hhiRLoA_0 potted plant +WjiMUA6_CkY_0 boat +Wlm2mLKCMlM_1 bus +WlsN6HURFTc_0 bear +WmFqo8n67Ok_0 bus +uWi9-84kTFQ_1 bear +uXHJHV0bwUk_2 bear +uXe9WOlTFcs_0 bus +uXe9WOlTFcs_1 bus +uZgcOYmazsw_0 bus +uaJ1g0xJ4QY_0 bus +ual32V7-KJo_0 boat +ua_5GosOa-c_1 bear +ubFoUAh6d4g_1 knife +ubOiomYqbNs_2 knife +udSE-6UkgwM_5 umbrella +ue1CIlwhPEs_0 umbrella +ufFT2BWh3BQ_0 bear +ugWs4v6DbUw_0 bear +ugsJ5cOmFTg_1 boat +uhXcL98XNCY_5 umbrella +uhXcL98XNCY_1 umbrella +WoxbRmDfLeI_0 umbrella +WoxbRmDfLeI_1 umbrella +WpCyx-QCMec_0 bus +WplsTumdQf8_0 boat +WqFFUvf-YJk_0 knife +WqxU9aIFmNY_0 umbrella +Wr5BjrtC4Ts_1 knife +WsEiHZFGeFs_3 umbrella +WsaP8FyRUCc_0 car +Wses8y3NyJ4_1 bus +Ws9V_B7mqJI_0 knife +WuTHL7GtG-8_3 knife +WvGzCV5ICZM_1 boat +WvuZRZqhxk4_3 knife +WvuZRZqhxk4_5 knife +Wvv8cOXaAZI_0 bus +Wv-Weuc4E1A_0 umbrella +WwLtxfDC7ok_0 boat +WxWXB9hf7n0_0 car +W0kDpFkg6xU_0 boat +W1z3EAv-eJw_0 bus +ujnUCtI7gzI_0 bus +uj4TRH5r_ww_6 bus +uklsFjegS-w_0 bus +ulzto7-Hl64_3 bus +ul__w-oqHrw_0 bus +umjU9X1kuYg_2 car +umjU9X1kuYg_4 car +umjU9X1kuYg_1 car +uoGBYfJo5Xg_0 car +uo1J9BUgQmk_0 boat +urRNkZvzuHI_2 knife +urmSoxyi9Vo_0 boat +urmSoxyi9Vo_2 boat +utmsGeHFdvI_0 boat +uuBKDGoTmGY_1 car +uu-UptVYr_A_3 car +uvV7cblR4qc_5 umbrella +uvZOzZjBKXY_0 bus +uwL5LYln0EM_3 bus +uwL5LYln0EM_4 bus +uwL5LYln0EM_5 bus +uwL5LYln0EM_6 bus +uwx7UKo4jcg_1 boat +uwx7UKo4jcg_0 boat +uwzHiGF1YMM_0 boat +W2z3SxorVnI_0 knife +W2z3SxorVnI_1 knife +W38vB3cw2fA_2 boat +W4Is7CI2Sfo_1 umbrella +W47ZA0onzb4_0 knife +W5dSTfMCj-U_0 boat +W5zIkmZyS18_0 bus +W51Spbo8SQQ_0 knife +W6YCv9ZVVOc_3 boat +W6uCEMEi7_E_0 bus +W7JkNuRYNr0_2 knife +W7JkNuRYNr0_3 knife +W7JkNuRYNr0_4 knife +W7JkNuRYNr0_5 knife +W7yqHDA_RMU_0 knife +W8EKt6cG0E8_3 bus +W8EKt6cG0E8_7 bus +W8EKt6cG0E8_1 bus +W8xqW-QD_B4_0 knife +W87M2lQeWNk_0 bear +W87M2lQeWNk_1 bear +W-ZpC_K7Df8_0 car +W-x__78AyrI_0 boat +W_Wc7lFraRg_0 bus +W_v5wpcibRM_0 boat +W_2LqiQ_ico_1 knife +XAa2L1v8iJM_1 umbrella +XBAOFn8KXFo_0 bear +XBn6P-IKuis_0 person +XBssw3bqXL0_2 bear +XCZv_AjZo08_0 knife +XCu0Ea4zHuQ_2 bear +XDtfr902CVM_0 bus +XD1OYmmeKic_0 umbrella +XD1OYmmeKic_2 umbrella +uxFX6p61oPY_0 knife +uxlDad59mFc_0 boat +uyWVUOcgZHg_0 bear +u1OhTXTmuWM_5 bear +u1TvbkpmEbs_0 car +u1vMDzyFxzI_0 bus +u2BVfAFQ1zU_3 knife +u2BVfAFQ1zU_2 knife +u2EDuPJijZ8_4 boat +u4K3jRl7Gag_0 car +u4S9mlFpt0s_0 bear +u4uwaq4uf54_3 car +u4uwaq4uf54_0 car +u6XGBXhCJ18_1 knife +u7STs8FCy_g_0 bus +u-1HZJXwFHo_0 umbrella +XF8B5xjRCF0_0 car +XF8B5xjRCF0_2 car +XF_oHXRGd1o_0 boat +XGRZLrZC9zY_0 boat +XIlybSpq0mg_0 bus +XJmn9i57K3g_0 bus +XLvSaN_M6lE_0 car +XL0B2niNRCw_2 bus +XMlEA_yRojM_0 knife +XMyio1ZckJc_0 bus +XQBtgwUzEL0_0 car +XQX5y5BQykU_0 bus +XQ6u2yTbu_0_0 car +XQ7UbbPjnDo_1 knife +XRenv5AHI_8_0 boat +XRpgkCuziGY_0 umbrella +XSI7M8s2Tc0_0 bus +XS4ow1Wcaro_0 car +XTm-jN1RVHA_0 umbrella +u_YKLGqrMKQ_1 knife +u_gN-dXNRHI_0 knife +vARZcTna8NU_0 boat +vBEaeqdPsho_4 car +vBEaeqdPsho_3 car +vDT-DShjnjU_0 umbrella +vEMHY2cT6kA_0 bear +vEi5gkcTDGY_0 bus +vE9zapt1WdI_3 car +vFSRrtT5AL8_0 bus +vGbt_XsSaVk_0 knife +vGi-DjriLLs_0 umbrella +vHAlsHYE3mo_3 car +vHAlsHYE3mo_0 car +vHXM9IJdVcM_0 umbrella +vIQAK-4lMOc_0 umbrella +vIgmRBC2ayQ_0 umbrella +vJl9QkAbpc8_0 car +vKxCl7DzJjI_0 knife +vK8dgvZ5B6A_0 umbrella +vLA-mHM7MAQ_0 knife +vL-6uNdrCV4_2 knife +vN54ADSnJmE_0 bus +vOKH_DIjvAU_3 knife +XUkTknKOdrs_4 knife +XVa23hmwe-E_0 umbrella +XVrNN52RTEs_2 car +XVrNN52RTEs_3 car +XV694aCXY8Q_0 boat +XW6BQWpl3bI_1 boat +XZl5Luzj6v0_6 bear +XaSsc3noeLs_0 boat +XbHWOyNM3Bw_0 bear +XbHeGzyGejE_0 bear +XbWrCVe09YA_0 boat +XcLl0qSs9bU_1 knife +XcifNE0anDo_0 knife +XcifNE0anDo_1 knife +Xc1jzGFyrnE_0 car +Xc5LW1FIVE0_2 knife +Xc5LW1FIVE0_3 knife +Xdu-98BUgmA_0 knife +Xd7VbtoAdb0_0 car +XeOwt5KeVfA_2 car +XeR1DgyOa9o_0 knife +XekvrqFtazY_0 bus +XeplLROyXyA_5 umbrella +XgBTEQN_ZxA_2 bus +XgBTEQN_ZxA_4 bus +XgBTEQN_ZxA_7 bus +XhSmPb3cA_A_1 knife +XhSmPb3cA_A_3 knife +XiEeY5R56EQ_0 knife +vOy0N09kGEE_0 umbrella +vO56uCHmSjg_0 umbrella +vPVpX6GPY5Q_0 bus +vPVpX6GPY5Q_1 bus +vQ_8ry_dx68_3 boat +vRhGvmXk2js_1 boat +vRzpk-thwA0_0 bus +vTvjeXsP7TM_1 car +vTwSeYRU_WQ_0 car +vTwSeYRU_WQ_2 car +vUKk9LqKVpA_0 boat +vUKk9LqKVpA_1 boat +vUg2Sr7Jl-Y_0 umbrella +vVKZzTBvsF4_1 bear +vVNCUA8hss0_0 boat +vVUbZCrCqEU_1 boat +vV72xGim-is_5 knife +vWMiT73g5-k_0 boat +vWO0tyaGuaM_0 umbrella +vWUAzQ_EEJ4_0 knife +vW_aJr-PSvA_0 bus +vW_o48lG_0I_0 bus +vXX9FmlwVlk_1 bus +vXX9FmlwVlk_6 bus +vXX9FmlwVlk_0 bus +vXX9FmlwVlk_2 bus +vXX9FmlwVlk_4 bus +vXaLFnwvrX4_0 bear +vXvR0RiGzj4_1 car +vYROjLzMqvY_1 bus +vYROjLzMqvY_2 bus +vYROjLzMqvY_3 bus +vYwdLoOa0Rc_0 umbrella +vYwdLoOa0Rc_1 umbrella +vY1sAfu99Es_2 bear +vZznldYVwGA_0 boat +vbfWHUjHR2k_0 bus +vcdEtOGEEcU_1 bear +vcdEtOGEEcU_0 bear +vcdEtOGEEcU_2 bear +vch6R3EO9Ec_0 knife +XjHJiHO6onE_5 bear +XmVv2wQSvjs_1 car +XoJahpK73EM_0 boat +XoqPCnlpymI_2 knife +XpDVw5mS058_0 boat +Xp591jCTBOA_0 bear +XqfkP1lAkyE_4 bus +XqfkP1lAkyE_5 bus +XqfkP1lAkyE_2 bus +Xq-5DHWJ1pk_1 bear +Xrh68BP53Gw_0 car +XriRhjtrlLE_0 car +Xu-ZZl_L38Q_2 boat +Xv9eEVcD2P0_0 bus +XwvKtur_QEk_0 knife +XxHnDkI1NdQ_0 bus +XxHnDkI1NdQ_1 bus +vfzGrdk_Mxo_0 bear +vhrRnvGSMMY_2 boat +vhrRnvGSMMY_5 boat +vhrRnvGSMMY_6 boat +vhrRnvGSMMY_8 boat +vh4BHzMwVT8_2 boat +vh4BHzMwVT8_3 boat +vi4ktD0dAD4_0 car +vkfdn7gkQh8_1 umbrella +vknUR0K4MqM_0 bus +vlNLyHxz1TY_0 boat +vlaeAly1nZc_0 boat +vmr5UiZekic_1 bear +vo0WWdM7UCs_0 bus +vo6Uzhx2fcw_0 boat +vpItyB8epmQ_4 boat +vp8NiaEmk2M_0 bus +vqeybXtIwxE_3 umbrella +vrK5lDQJnmc_0 car +Xy1w-6sjVS0_0 bus +Xzj_w2QkjRg_0 umbrella +X0iu2HmUYfY_0 umbrella +X0nevXM5278_0 car +X1drOgA68EU_0 bear +X2zWe7ayseQ_1 bear +X3ST-FA3VS0_4 bear +X4YaqObAEns_1 bus +X4kxk4G-BOs_0 bear +X4kxk4G-BOs_1 bear +X6Y6e6qsVOc_1 bear +X6tuO-hL1cg_0 boat +X6z7yGyP3UY_0 boat +X7AJSe6kUz4_0 boat +X7PChwjgRog_0 boat +X7mkuAPcpg0_0 bus +X8Wc00FiJn8_1 bear +X8lHVX9uGm4_0 car +X9dNz1MhFTM_0 car +vtOaPYxGauU_0 boat +vwp5f1sTcOM_2 boat +vxEizaWVZ2E_0 car +vx7S4ISNz90_0 bear +vzKEVGD3E3w_0 boat +vzKEVGD3E3w_1 boat +vzmWbtFBxb0_0 bus +v0DjGmLiuao_0 car +v0P7DOSAooM_0 boat +v0Uh3fazz7A_4 bear +v4CWziKFAvg_0 boat +v4CWziKFAvg_1 boat +v4TWD1hSObU_0 umbrella +v4TWZQM-t_M_0 boat +v4wheqJ7qmw_0 car +v4-PEShPpKo_1 car +v4-PEShPpKo_0 car +X_1xeuzdJII_3 bus +YAI5kxAVlag_0 bus +YAS9QgwaKuA_3 bear +YAacEL8GB8Y_0 bus +YCTBEauAnvs_0 boat +YCT0ue2AdNE_0 umbrella +YC0SWC1thDM_2 car +YDxjfXnUsjA_0 bus +YFb4IgdgsQI_1 boat +YGm0A03QK-0_0 bus +YJklsCjPlRE_0 car +YJrYjEZ4Hfo_1 bear +YLNAOu0nAaM_1 bus +YMWEbvBeA2k_0 car +YNOl5XssrmA_0 car +v6RTPFSqVAo_0 bear +v6d52nxP9CI_0 boat +v6d52nxP9CI_6 boat +v6d52nxP9CI_2 boat +v7R5EfiWsMU_0 boat +v7mxF1u1eJA_0 boat +v74SVFcInoY_0 bus +v77um2oiCmw_1 bear +v8vdjpigkqA_3 bear +v9EO_34zhPY_0 bus +v9dJjyyqJ14_0 bear +v-_nfHjdDrM_0 car +wAJI2wAjCLA_0 car +wAktmcUSj0Q_0 bear +wAsEbrNlx-Q_0 car +wBEyQdKDniA_0 bus +wDOuWmULTDo_0 bus +wDwRfk2Ka7A_2 umbrella +wFuYr5TAoA4_0 car +wFuYr5TAoA4_2 car +wGqMuP3z6nY_2 bear +wHdnCnPBax4_0 umbrella +wHrdTEho0Do_2 bus +wItLJ3GVPHo_0 umbrella +wIzhSLqL-4M_0 boat +YPR6uiSn_PI_0 bus +YPR6uiSn_PI_2 bus +YPWoY6sseHw_2 bus +YP9HVTyFrM0_0 umbrella +YQRaUcLNZjw_1 car +YRmCe16K5EI_0 umbrella +YRxTciapqLc_0 bear +YSFyOBQNQzc_1 umbrella +YSOeyn1SUIc_0 bear +YSx79S6HsRE_0 boat +YSx79S6HsRE_1 boat +YVueKFH38pQ_0 umbrella +YWAY2hVlXwU_1 boat +YXC4y1_fd5M_1 boat +YYjM_RIWUWk_0 bus +YY-G2b46dbU_0 bus +YalvFPYggIo_0 bus +YbsAJsBizWo_0 car +wJbu3nAVmh8_0 car +wJ-qeIIyve0_1 bear +wKlqztWBWCE_0 bus +wLXsUww1z0Y_1 bus +wLXsUww1z0Y_2 bus +wMW3eYDAmiM_0 car +wN6DTQLhQo0_0 boat +wOAtMDJ1DIU_1 bus +wOqLqQhPKNs_2 bus +wPCVya7FjXI_0 bear +wPcWihBU6Fc_0 boat +wPjzhuBuZ_E_0 car +wPrTnHfCQy0_0 bear +wP83jrOriho_5 boat +wP83jrOriho_1 boat +wP83jrOriho_3 boat +wQY4K0ZN5RY_0 bus +wQY4K0ZN5RY_1 bus +wQY4K0ZN5RY_3 bus +wRJ_foSdk2g_0 umbrella +wRs7_Un28R0_0 bus +wSaf-OQyJzM_0 boat +wSkaSUiYB60_0 boat +wUG-UKf5xOM_2 bear +wUtwwmbus0k_0 bear +wVI9BeWuM68_0 bear +wVX6wPj2U5M_0 bus +YcrP36sQwVc_5 bear +YepGVMeHePw_1 boat +Ye3mi53K_Oo_2 boat +YgouPUMM7w8_0 bus +YhZT5GU-dEY_0 bear +YiDVwrN1Djs_3 bus +Yi8XHxZACGY_0 bus +YlGg5v-AWZc_2 umbrella +YlnMI5yk7FU_0 boat +YmRfW-9QwH0_0 car +YodCYpx5p8o_2 bear +YogxE9OtHGE_0 car +YogxE9OtHGE_2 car +YozOMrrhBWk_0 umbrella +YozOMrrhBWk_5 umbrella +Yo8IaFdsDHQ_0 umbrella +Yo8IaFdsDHQ_1 umbrella +YpGGnhGqqkc_0 car +Ypv2bwSbJbg_0 bus +YpyrD-P9emk_1 bus +Yq3H6FwjqwQ_2 bear +wXg6MT7--Ms_1 bus +wYO_Z3tO-P0_0 car +wYO_Z3tO-P0_1 car +wYO_Z3tO-P0_2 car +waGAoKeMDbo_2 bus +waZHoBhYNXM_2 car +wan2A1Zp9pg_0 umbrella +wa4LKNmoGCI_0 bus +wbBafnofeHM_1 bus +wcLRQ5lDklc_2 bus +wcRJMRP7TtY_0 car +wcUHhJA9ynY_0 umbrella +wcUHhJA9ynY_1 umbrella +wc6z479m8VU_0 knife +wePYCAT9VWI_0 boat +weUGYN9mO8M_0 car +we9P1H3yM9s_0 umbrella +wgn5GA4Kt_w_0 bus +wioe2rgDFxQ_0 bus +wi_60seXhMg_0 umbrella +wkCC1-6dZZc_0 bear +wkRF61CxvWQ_1 boat +YsJGlSMV6fc_0 bear +YsKpyV6dNVU_0 umbrella +YsKpyV6dNVU_6 umbrella +Yukb6C-FiPs_0 bus +YyqN8OKq7-k_0 car +Yy9Cj5ayVow_4 car +Y2esC00COVs_0 umbrella +wkhiKomfWwo_0 boat +wku7FWw9zok_6 bear +wmN3gF7czBE_0 boat +woB4lneU8v4_2 boat +woB4lneU8v4_5 boat +woB4lneU8v4_3 boat +wonqKYd_Hkc_0 boat +wulomSbG8Ww_0 boat +wwHyMOLjtHw_0 car +Y8gjbHlOSpg_1 car +wz-CYTAvpJA_0 car +wz-CYTAvpJA_1 car +w1xC4CowaVk_2 bear +w2d7ZPHVRsQ_0 car +w4QoeqK4vN4_0 boat +w5KKrxi32ZU_0 boat +w5RAGrRh6N0_0 boat +w85PvG-O3JQ_3 bear +w-RoxIo67S8_0 bear +w_dzHMbP1wk_0 car +xAdflusGMAM_2 bear +xAdflusGMAM_1 bear +xBQVhJr5tn4_0 car +xBQVhJr5tn4_1 car +xBW2dB1aHqE_1 bear +xE-fIbBizEc_0 boat +xIjuSe8NERE_0 boat +xIr-46lqsbs_4 boat +xI3wdcR9GOU_0 bear +xJaqlEqJIsg_0 car +xKUjAAXXark_1 car +xKjnn1lJsUE_0 boat +xLl8JlHPals_0 bear +xL0aucx8LjA_0 car +xM1N_JeMAns_0 car +xNfYVO0HOWA_0 bear +xNfYVO0HOWA_1 bear +xNqzZtEMt6A_1 car +xOQ_zqhFFoQ_0 car +xOQ_zqhFFoQ_1 car +xOQ_zqhFFoQ_2 car +xPgexGqlrpM_0 boat +xQ2ursLiV78_0 boat +xVl7ISxNOBo_1 boat +xWfIV6ykSZU_0 umbrella +xYRbcgZcjTo_0 boat +xZdiy-peZpE_0 bear +xcC48didfYg_0 car +xds7aav_WA0_0 umbrella +xeEFpaZutxQ_2 car +xeEFpaZutxQ_0 car +xemv_TG3nHo_2 boat +xf7e7HpnDAI_2 umbrella +xhLH-f-e2Ds_0 bear +xhLH-f-e2Ds_5 bear +xhLH-f-e2Ds_1 bear +xhLH-f-e2Ds_3 bear +xhLH-f-e2Ds_4 bear +xhYRRVSUjcI_0 bear +xh6_xD0_FUY_0 umbrella +xi1l0PNYmVU_0 car +xi1l0PNYmVU_1 car +xk-PCxxgLyQ_0 car +xlSq_r-1VZI_0 car +xlTBS98u4Xk_1 boat +xl03KNG3qcY_2 bear +xl03KNG3qcY_3 bear +xmXEOSj-QR8_0 umbrella +xm61skXJVHY_0 bear +xm7yMjZR_HM_0 car +xniXqwdU3rM_1 car +xn_6GQGdyww_0 bear +xoL1TWqV2UY_8 car +xoL1TWqV2UY_3 car +xoL1TWqV2UY_4 car +xoL1TWqV2UY_6 car +xo93ACxVFCE_0 car +xu3hCCY1M98_0 car +xvJ-vgSlRFQ_1 bear +xyUFBTV5sfA_1 boat +xyUFBTV5sfA_5 boat +xzFwd6rktG8_1 bear +x1PZyiPtcD0_2 bear +x1PZyiPtcD0_0 bear +x2MUZI0ckUs_0 boat +x51qh-jbh2w_0 car +x8bgasvRg_0_0 car +x_PtUMz2m3g_0 umbrella +x_yZa__92dU_0 bear +yE9ySV90e2U_2 bear +yFdbcjv2scY_0 bear +yFwt2mHmJQw_2 umbrella +yFyTQPoWKrg_0 car +yGYLwBmuRVI_0 bear +yGYLwBmuRVI_1 bear +yGq_wX2hSms_0 car +yHFbPuIOGec_0 boat +yMVPEp44IcU_1 car +yNYzTl3zuSA_0 car +yOeQRz1L-6w_0 boat +yPx8JYuB8jo_5 bear +yTEPer0Bvnk_0 boat +yTr7cqNxVw8_0 boat +yVwePYmRfaA_2 boat +yVwePYmRfaA_0 boat +yV3gYczZGSU_0 boat +yWKpg3C3HRA_0 umbrella +yWQT0KUXmZs_0 car +yXA2s-Ylkx4_0 umbrella +yYt1-j5ltQg_0 bear +yZOWsBbP8Dw_1 boat +yafgzvvEBsk_0 car +ygqn0Cw0cJg_0 boat +ykAF4z2vPRI_1 car +ynSIMn0mh5Q_0 car +ynuXudWT-jg_1 boat +yqDO3G8QSxs_2 boat +ysudb_DYv1E_0 bear +ytzy45KRs4k_0 umbrella +yy-1Eaz2SGI_4 boat +yy-1Eaz2SGI_5 boat +yy-1Eaz2SGI_6 boat +y26dbfVQaAI_0 car +y3HDa7ZvWW4_0 umbrella +y5rlUzgK0z4_0 umbrella +y6l_Xj3A7dU_0 bear +y6nMm6sNieE_0 bear +y6oa4gTfIaw_0 boat +y7_Teuq-Jd4_0 umbrella +y-J-zu3KYKk_0 boat +y-lv7_3azcQ_3 bear +y-lv7_3azcQ_1 bear +y-lv7_3azcQ_2 bear +y_Kbef75lDk_0 umbrella +y_OvZEh5PxQ_1 umbrella +zA7rl-0pCw4_1 bear +zBCRUfv1YVo_0 car +zBomR9gjgg4_1 car +zCnqglOaM40_0 boat +zC1J8hrm_FI_0 boat +zGOI3Uds1-A_0 car +zGvuvfZeouY_0 car +zHwK-Ov5Dn8_1 bear +zIGdWP0BOPc_0 car +zIoLntgax_4_0 car +zIrTQvy-DtU_0 umbrella +zKN-t-wHfVw_0 car +zOxKFs0x_-M_0 car +zPUoexM4GJg_1 bear +zS4G-dKS3dg_0 car +zUYNrm52mG8_0 car +zU9O4EpnP8g_0 boat +zW4j5HFdFCE_1 bear +zW9G9_luulU_6 boat +zW9G9_luulU_8 boat +zX70EOhK1IA_4 boat +zX70EOhK1IA_0 boat +zX70EOhK1IA_2 boat +zX70EOhK1IA_3 boat +zYNSRTs7wcI_0 boat +zZMZCzV930Y_0 boat +zaXvp0LSorI_0 umbrella +zcIJlqUAlyQ_0 boat +zcdpKM2gDkA_3 bear +zdWOfDZyRWg_0 car +zdp6LbsF3Fo_0 car +zdp6LbsF3Fo_1 car +zglydzoqdNw_1 car +zhSMuVKY4jM_1 boat +zhgbbZA2jZo_0 car +zj0QGbLx2Ek_0 umbrella +zkC1ygaZUL4_0 car +zkFlovQ2F80_2 umbrella +zkFlovQ2F80_4 umbrella +zkFlovQ2F80_0 umbrella +zkYqOEAbTTE_0 car +zk5BFmxsRfQ_1 car +zmXJ3VmO_yQ_0 bear +zmXJ3VmO_yQ_1 bear +zn_LOCSgnBI_0 car +zobMJDgPWmM_0 boat +zpW9Kjtbu7g_1 boat +zp4-YNYr-l8_0 car +zqDdt_wpfcM_0 bear +zqyhnAN5qnA_0 car +zq-AjPBQb3w_0 umbrella +zsszkZnE24M_0 car +zsszkZnE24M_1 car +zwKNqBmI95k_0 umbrella +zxfyvjQQ0QY_0 car +zxuleRJc5Pw_1 boat +zySbpWHTUUI_2 umbrella +zzDlzbpuFUg_1 car +zzOYV3PIwDo_1 car +zzljeIZDjM8_0 car +z1CT7NYPStE_0 boat +z1CT7NYPStE_2 boat +z1DFtYFOfsQ_0 boat +z1GcDqMXI5U_0 bear +z1WPNBklZbo_0 bear +z3V1O449zY8_0 car +z3V1O449zY8_1 car +z3V1O449zY8_2 car +z32BNdijIPo_0 car +z4C0C5AtXd8_1 bear +z4Nk6je-k5E_5 bear +z4Nk6je-k5E_6 bear +z4Nk6je-k5E_2 bear +z4Nk6je-k5E_4 bear +z4YdhKjeNQk_0 car +z5PqRVPhGGo_0 bear +z56C-TtwATI_0 car +z6Bzk_B2FVo_1 umbrella +z6gL7THeOz4_0 car +z8GzZUKj04k_0 car +z8QYapjsTBo_0 bear +z8WzXJMRLkg_1 bear +z9CJpzFuqHU_0 boat +z-gqhqI7U10_0 umbrella +z-n_qZEuRko_0 umbrella +z_CWMOiNpzY_1 boat +0Ah0DHbJ6Uw_0 bear +0B-l9QmJK3I_0 car +0DHXMcNUn60_1 umbrella +0EEILwHA4Dg_0 umbrella +0FRiwnN3Wv8_0 bear +0FUPhsPv9vs_0 boat +0FUPhsPv9vs_1 boat +0GR555fb7uE_1 boat +0GR555fb7uE_3 boat +0Gal36CHm94_0 car +0Hf-spRN8iA_0 bear +0H81H-1s398_0 car +0JkwSF_s82I_0 umbrella +0JxUW6X6VTA_1 car +0JxUW6X6VTA_2 car +0LY3jcKxA2E_0 boat +0NN0x0UcFVI_0 car +0NgLxOGQPPM_1 car +0Nh6NERAbQM_0 umbrella +0NyneL4SB78_0 umbrella +0O2cDoxCAhA_0 car +0PqvPOqRHik_0 bear +0ROl0QaHTgU_0 boat +0ThOYMXH3Mw_0 umbrella +0TyHCEslM-4_0 boat +0UGD0u7LEPY_0 car +0UVJn4oJR3I_0 car +0Vu78K6ZsOk_2 bear +0XETGtPrUR0_1 boat +0XrWsyRsBYs_1 bear +0YWXAZlIFZE_0 car +0YWXAZlIFZE_1 car +0YaZ8lrPQJc_0 boat +0YaZ8lrPQJc_2 boat +0YaZ8lrPQJc_5 boat +0ZJeQYZxfGQ_7 bear +0ZJeQYZxfGQ_6 bear +0agrBEPe_w4_2 bear +0bx9mbPU7zo_0 umbrella +0c5dV9e0rL0_1 car +0hafN9Sygek_1 bear +0jL3xw-Gfq8_2 boat +0kyg-HgBo7o_0 boat +0lXT8w6Nvz4_1 car +0loh5Nhb32w_0 bear +0lyjvzKFjn0_1 bear +0lyjvzKFjn0_2 bear +0mIwwe5irHk_0 car +0mSZED2I97w_0 car +0mSZED2I97w_2 car +0mSZED2I97w_1 car +0oHtf7nx8m0_0 car +0oHtf7nx8m0_1 car +0peaciSDgqg_0 boat +0rIli5nmkus_0 car +0sAim6AJwgY_0 car +0sAukk-qZs8_1 car +0sWjMW4aW_Y_0 bear +0sbXLfSaBvk_0 umbrella +0tapt-cyoSY_12 bear +0vC1j_r-gPc_1 boat +0vun54M7U5c_0 umbrella +0wXgXCqnblk_0 umbrella +0wzUHyuc5JE_0 boat +0zKI3bZagm4_2 boat +01aEu9jy-zA_0 car +02AiKGZAu3k_2 bear +02bMGGTZE_M_0 boat +04FPpXq4qHc_0 umbrella +04FPpXq4qHc_5 umbrella +04jEe0lfdos_0 car +04p58ydbAvM_0 car +05VoMpLo7Cc_2 boat +05rSMaVX3yA_1 boat +06kAyBeWx5c_1 umbrella +08Fj_YF5X8Q_2 bear +0-Jhv9dONP4_0 bear +0-zDto8pBU4_0 bear +0_ByJ0bAD70_1 bear +0_P-fui2MeI_0 boat +0_soacANAc8_0 umbrella +0_2dsK8nudw_0 boat +0_2dsK8nudw_1 boat +0_2dsK8nudw_2 boat +1EIBn1zqhJA_0 boat +1Fv0cFr9B_Y_0 bear +1Gd-hUsNAsQ_0 bear +1Gd-hUsNAsQ_5 bear +1HhUsmUQmRY_0 boat +1KnTTBiP4ig_0 umbrella +1LKTvGMlL60_0 bear +1MVBovgEi4s_0 bear +1OvseXyo27E_0 umbrella +1PYMTwN-dl4_0 boat +1REcM5EtrZg_0 boat +1REcM5EtrZg_1 boat +1SQF7Tb6pUA_2 bear +1T4c050qGWo_0 boat +1UGqDCwd0TU_2 bear +1VziogDsYAs_1 bear +1WOfnEUurGM_0 boat +1YelAl0OQQg_0 bear +1anH_WthXTc_0 umbrella +1anH_WthXTc_1 umbrella +1avrrmB_Q5s_3 bear +1cbY1pGpdhM_0 umbrella +1cy1p57Z49c_0 boat +1dmbrwAgFuc_0 bear +1fPDeE9SwYI_6 bear +1gbd0C2wJrI_2 bear +1huEYUsV2ng_0 boat +1iD7yA3Elk4_0 umbrella +1iLq0PGfeCs_1 boat +1irtTU-RM8g_0 boat +1lCEFERcEKg_1 boat +1lSGhF2K_lM_3 bear +1l-NcYZKF8w_0 umbrella +1miy1sfneCI_0 bear +1qIgbCRt2C4_0 bear +1qknV5a5WQA_5 bear +1rt4XRA4RHE_0 bear +1rt4XRA4RHE_3 bear +1v8UDwaLZOk_1 boat +1yym4MiYTrs_0 boat +1yym4MiYTrs_1 boat +1zGry9uSuEs_0 boat +10oedSsXbw0_0 bear +14R96gxvKtU_1 boat +15ImffljXUs_1 umbrella +16BnXZheZE8_0 boat +18XvETJJDqA_0 bear +19ID_DbSclo_1 bear +19vhT11oPv4_0 umbrella +1__PWUxtAJI_0 boat +2Da3689mFHo_0 boat +2DimBSzdfPw_0 boat +2Fo-71zWO5Q_0 bear +2F9aM3isFOg_0 boat +2HDMk0mGW_w_0 umbrella +2IWPUKQEQc0_0 boat +2Irm_qCNQ_g_10 bear +2Irm_qCNQ_g_2 bear +2Irm_qCNQ_g_4 bear +2IyAOD0OkOg_0 bear +2I_k7e8QpWI_1 umbrella +2LWxx48-zmY_0 boat +2OYJuEnLK_w_0 umbrella +2O-9dVZBFm4_0 umbrella +2PL1rgU3jQ4_3 bear +2Pxvoh1PnpM_0 umbrella +2QOthN0H0jo_0 boat +2UBlre798kQ_0 boat +2U7mw3Z_nrI_1 bear +2ZeSJRQEIDg_0 umbrella +2huYkh1UAa8_0 boat +2j5p2kIFnF8_0 boat +2kAmyrOg2is_0 umbrella +2l4-4yNg4uM_0 bear +2l4-4yNg4uM_1 bear +2nWt5S5AcdM_0 bear +2oAbMVTBupI_2 boat +2olUVemt4wc_0 umbrella +2rbAoA6KuZ4_0 boat +2rzjzIvxob0_0 umbrella +2sDjXjM3vuk_4 bear +2sgrwTqPz-Q_1 umbrella +2vC56ILIWK0_1 bear +2w5-fxqKaR0_0 boat +2xzgP87zGDM_0 boat +20nMgEiCqVs_0 bear +223bkVsFvUg_0 umbrella +23-uEh5ygBE_0 boat +24kbYgf2_xM_0 boat +27Yd0qtplBs_0 boat +2_VfwSLic7o_0 boat +3EBKN0vh_8Y_0 umbrella +3EQ8WatEGfM_1 bear +3FBfwZ1vctY_0 boat +3GXWmiQHAA4_0 boat +3Hc48OCKEaQ_0 bear +3ICqGhWY-HU_0 bear +3IOrKwocmOM_0 bear +3KUAz0bb87g_0 umbrella +3KqDceVP3xg_4 boat +3MqGpNqj-fo_2 bear +3M5VwMaIzvc_0 bear +3PN8pPy1PLc_1 bear +3PN8pPy1PLc_4 bear +3PuByhkRjdA_0 bear +3P8-bKeMTDU_0 bear +3P8-bKeMTDU_1 bear +3QQYEFonITE_0 umbrella +3SJI7j-hBwU_0 umbrella +3SbQY-gSjTI_1 bear +3SofVK5wM1k_0 bear +3T5iqGlQLn8_0 bear +3T5iqGlQLn8_4 bear +3UJ24QWw0js_0 bear +3UUo8exclHk_0 umbrella +3VZuzA8i9tI_0 boat +3ZWFSRxFKp8_4 umbrella +3ZwOfZ6mdTE_0 umbrella +3cBiXmqHBLE_0 umbrella +3eH1SNLDT7U_1 boat +3fiWerkBy1s_0 boat +3fm54fM2fh0_1 boat +3kOuqiigfhM_0 umbrella +3khbnSUKCjw_0 umbrella +3khbnSUKCjw_3 umbrella +3khbnSUKCjw_5 umbrella +3khbnSUKCjw_1 umbrella +3leEAIEn6wg_1 bear +3oFuTv4g5QE_0 umbrella +3oFuTv4g5QE_2 umbrella +3ohEBnBnt7o_2 umbrella +3pli8lLuPF0_1 bear +3qGBc-85DMI_1 bear +3q0pJjI8W5o_0 bear +3v6DRHFQTz0_1 umbrella +3yct6bNJF9c_1 boat +3zhjI0Cn1AM_1 bear +3z0lIa162ps_0 bear +31PMTcBL5-o_1 umbrella +31PMTcBL5-o_0 umbrella +32GDx70-6cQ_2 boat +351brnq0Ryk_1 boat +38Tbojzrw80_3 bear +3__l885Wkz4_0 bear +4A-5QKpDBFE_0 bear +4A-5QKpDBFE_1 bear +4BbVz6UbHFY_1 bear +4GTfq2m-SnY_0 bear +4K0agSc78Js_0 umbrella +4K0agSc78Js_1 umbrella +4MUu-MomyB0_1 bear +4N85gqVvlWU_1 boat +4OQGDsYtfSg_0 boat +4QdM0aAdf4g_3 bear +4Qf9iJ-IMDg_0 bear +4R5HjEAW6Y4_0 boat +4ViaowUogyA_1 bear +4ViaowUogyA_3 bear +4VxP7VQ-WtQ_0 bear +4XCmBo2k6Hc_1 boat +4h2kJG8rDAk_1 boat +4h8E8d4P5ms_0 umbrella +4iktvQjNLS8_6 boat +4lyoTIuPa9s_0 umbrella +4rxmIDjvHvo_0 umbrella +4td5npVxACw_0 boat +4td5npVxACw_2 boat +4td5npVxACw_3 boat +4td5npVxACw_1 boat +4u8RQi7_xUQ_1 boat +4zYtj8BG_ZA_0 boat +4z3XNRP4Qvk_0 boat +40Ogw6O8g2M_0 umbrella +42-2FjqvBRw_0 boat +44nxZjEYqLI_0 boat +45HOGdlAVq0_2 umbrella +45HOGdlAVq0_3 umbrella +45HOGdlAVq0_6 umbrella +46Sp7L3iKK4_1 boat +47mMBnGHuOE_7 boat +48IdCSlEHlM_0 umbrella +48pGfV-z-x0_0 boat +5AhKWEjMmUw_0 umbrella +5AzSuHB6_jc_0 umbrella +5Ce6X4i25i4_4 umbrella +5Ce6X4i25i4_0 umbrella +5EaEfiCIEcA_4 umbrella +5EaEfiCIEcA_3 umbrella +5FZykf07mxY_0 umbrella +5FZykf07mxY_1 umbrella +5FviZXBOPWk_0 umbrella +5H6nBOIIziQ_0 umbrella +5IdOF-nnOkU_6 boat +5I2hW9gRRwU_1 boat +5JubFWZKmZc_1 umbrella +5Kf5KxsLCmI_0 boat +5PxBf16_oMg_0 umbrella +5WUSwyO4k7A_0 umbrella +5XWfGTUYLbQ_6 umbrella +5Y3Lrgpl6s8_0 umbrella +5dL3vGF_-ug_0 boat +5e9luwmv6mU_0 umbrella +5g_ugz2HmKM_2 boat +5iYpaHYUElI_0 boat +5iYpaHYUElI_3 boat +5iYpaHYUElI_5 boat +5nMhK15X4R8_2 boat +5rT33oH7aV4_0 boat +5srF-BzF_go_0 umbrella +5suoa4TFYd4_0 umbrella +5vMpwDm27VM_0 boat +5vyqdnOWivc_3 umbrella +52m9SGVaiW8_0 boat +521jpaMoQ58_2 boat +537tF6-uRB4_0 umbrella +561s-m-0mqU_0 umbrella +561s-m-0mqU_2 umbrella +561s-m-0mqU_3 umbrella +582V5-HF4yg_0 boat +582V5-HF4yg_1 boat +597l2xVl9Tc_0 umbrella +6C42Di7bIpE_1 boat +6FG49plD8TQ_0 boat +6FQz5w7HaKg_0 boat +6JGioFiqwww_0 umbrella +6JLdACYt7D4_1 umbrella +6MVLpYA1t8E_1 boat +6MVLpYA1t8E_3 boat +6OEFFwKhAFw_0 boat +6PVjXDW7JlY_1 boat +6Sxb0d7xIys_0 boat +6Ug54vSsrio_0 umbrella +6WP3KFUYTrM_0 boat +6XrW8Yjd16I_0 umbrella +6c0RAJO-AGg_0 umbrella +6inTfRLx_58_0 umbrella +6it-xMMovj4_2 umbrella +6khDUjxTmdo_0 boat +6mvP_NKlIHg_1 umbrella +6qpeBvh9pqs_0 boat +6rowMK5ERz8_2 umbrella +6sN56W9U7tY_2 boat +6tLtEuKyj1E_1 boat +6tQrO26kwOY_0 umbrella +6t0mbpnPPdg_0 umbrella +6t55VfdtMWE_4 boat +6t55VfdtMWE_7 boat +6t55VfdtMWE_8 boat +6t55VfdtMWE_0 boat +6uM7MFSH15g_0 umbrella +6uvJft-l1R0_3 boat +6yCsWwj87QI_0 boat +6zxrdodJut0_0 umbrella +61RreGvIPOk_1 boat +66WmMvvZOxI_0 umbrella +68C7HGRrJ8o_0 umbrella +68kx9VUVhzE_1 umbrella +6-Nh0bY1nUk_0 umbrella +7HD-o1yj47U_0 umbrella +7NXmDbHoJn0_3 umbrella +7NXmDbHoJn0_5 umbrella +7NXmDbHoJn0_6 umbrella +7RcyfoxqADA_0 umbrella +7WKzOMuf3Cg_1 umbrella +7a_nsGmUZNU_0 umbrella +7kSyhlnimb8_0 umbrella +7kaTL52xbiY_0 umbrella +7tlbytb63z4_0 umbrella +7uR1cEVdMDo_0 umbrella +7ydX3wCeOgk_0 umbrella +71k1TftUiYE_0 umbrella +76ljAryU9Bw_0 umbrella +78lA-eJGUn8_0 umbrella +7-ugeb_4vqE_0 umbrella +7_k6DM-PlXg_0 umbrella +8AZtNaOO_8A_1 umbrella +8FhIv4h9D3E_0 umbrella +8FhIv4h9D3E_1 umbrella +8H88MFohrUM_0 umbrella +8SuTrZ6xu2E_0 umbrella +8d_Vt2SWIvg_0 umbrella +8fsRltS2ul4_0 umbrella +8nReKSsSgGE_0 umbrella +8oOer9PS53g_3 umbrella +801xOkfqjkM_0 umbrella +84Ber6V3IrA_0 umbrella +84zKfCKtsDo_0 umbrella +9CGTYEUn-mo_2 umbrella +9JFicuESmEA_0 umbrella +9JiMiflDI68_0 umbrella +9J4O20b9qnY_0 umbrella +9S2mGfudahk_0 umbrella +9UVLb_-RbfA_0 umbrella +9bFrwgSSAkQ_2 umbrella +9bFrwgSSAkQ_4 umbrella +9bFrwgSSAkQ_0 umbrella +98OOq0Wh904_0 umbrella +99uO6qHrhsU_0 umbrella +-PaNPkpeFdI_0 umbrella +-PaNPkpeFdI_4 umbrella +-Z3_Ixwl1YY_0 umbrella +-bA7JdKB0LA_0 umbrella +-d9Vg5j5vZU_1 umbrella +-eJmt-GItyI_0 umbrella +-k8FuC01N5E_0 umbrella +-0y7A0GDVY8_3 umbrella +-0y7A0GDVY8_5 umbrella +-0y7A0GDVY8_7 umbrella +-3TIfnTSM6c_1 umbrella +-3TIfnTSM6c_2 umbrella +-98I0B3kkqw_0 umbrella +AAVVg5xx0p8_0 person +ACB01WGxOSM_0 skateboard +ACDc6tGnXXQ_0 elephant +ADWNgv6trag_0 person +ADznOfGgfj8_0 person +AEEVGgiuS5c_0 person +AEHbOzlbmOQ_0 dog +AEJTsQNMkME_0 bus +AFlkSTJ-mF0_0 dog +AGRV17_1OS0_1 bus +AHsZ4FTQ8Ew_0 truck +AIViQtfacts_2 horse +AJBtOVA1KSw_0 person +AJbQP-rIwCY_0 person +AJ9ODXcnhVo_0 person +AJ9ODXcnhVo_1 person +AKBq0oH8IOM_1 train +AKBq0oH8IOM_3 train +AL9dFpjFlLM_0 horse +AM-TjLTvBSU_5 bear +ANA-pgSAzGI_0 horse +ANVnK2HmZno_1 airplane +ANVnK2HmZno_7 airplane +ANeOKwjvX7w_0 dog +APP17gURiBU_0 bear +APP17gURiBU_1 bear +APTYyEYJfOY_0 bird +AQD8YBCTSPs_0 umbrella +ARaILMtc8fs_1 person +ARsokXpl07Y_1 boat +ARsokXpl07Y_2 boat +ASPK-ZSB9Ts_0 person +ASfv8cmreoA_0 person +ASfwyHCtnIU_0 person +AS5LvQT9rrQ_0 person +ATy91FTiYvU_0 person +AVF8lCKe6os_2 umbrella +AWRcJpWTPwQ_0 person +AWtY9Y2mPso_0 motorcycle +AWwDsm1WnKE_1 knife +AXjDlIFY7ww_0 boat +AYAkMpj_MHA_2 bicycle +AYAkMpj_MHA_5 bicycle +AYAkMpj_MHA_6 bicycle +Aax6L0Qqgio_0 bird +AcYd7y_-V74_0 person +AdY55Q3qVK0_2 elephant +AgbIDWiOXQ8_0 person +AgsYgmA19z4_0 person +AhWU-QUzOOA_0 person +AiqGEAjF6QI_0 train +Aiu6EH4a8v8_0 train +Aiu6EH4a8v8_1 train +Aiu6EH4a8v8_6 train +AixV6QSGqto_5 bird +AixV6QSGqto_6 bird +Ajj7WZLukdw_0 motorcycle +AjpbAriY8rU_0 person +Alab3dEYXM0_0 person +AoAoH9yb6zY_11 bear +AoAoH9yb6zY_6 bear +Ao7Sa2afCb4_0 person +ApDgLQUsEqc_0 bicycle +ApakHefqWv0_2 airplane +AqIG0zk2bpg_0 person +AqTXLh7DtcM_0 person +AqTXLh7DtcM_1 person +AqdoD9jkBFc_0 horse +Aqj7VnXQt4s_0 cow +Aq4dBqb2SbQ_0 person +ArgYRdhvlc0_0 skateboard +AsPXe7qUyuI_0 person +AuLrPQqrKV4_0 motorcycle +AuY8vITQrsE_0 cow +AvBm7iHiDdI_2 boat +AvSgTHXgSXQ_0 cow +AwVdVzh1Eh0_0 person +AwvDMOeS7no_0 person +Awzt30r0OLQ_1 bus +Aw2t3AalW4s_4 elephant +Ayh_2ithjCE_0 cow +Ayh_2ithjCE_1 cow +Ayh_2ithjCE_2 cow +AylQiap7dj4_2 bear +AylQiap7dj4_3 bear +Ay9QToaaTGc_1 truck +Ay_a2OkcdEk_0 person +AzVvPUazPYk_0 motorcycle +AzzlFx32dQs_1 boat +A1RSx6j_ra0_9 elephant +A1RSx6j_ra0_4 elephant +A1RSx6j_ra0_6 elephant +A27YZAfJmrc_0 knife +A27YZAfJmrc_1 knife +A3E72P24pf8_0 person +A3cgW1rDOcI_0 person +A32Fi06yKpU_0 horse +A5U6AHe9_4A_0 train +A5pUgLCQq9k_0 elephant +A5pUgLCQq9k_2 elephant +A5pUgLCQq9k_3 elephant +A63BoLTUNAM_0 horse +ZBzVnA8zj6Y_0 person +ZB45YyN1WUM_0 bus +ZFYGhJKiw5w_1 giraffe +ZGfOCwbu-PY_0 person +ZHTMfW1eaW0_0 cat +ZHURcze8rOI_0 person +ZIJUWQKzzsQ_0 person +ZJgwacILoAw_0 person +ZMgP2kxv5E8_1 person +ZM3wX5zgKOA_0 person +ZNXnJahaXIY_0 person +ZOc4wfLX2Jo_0 cow +ZOnuSLp6asQ_0 train +ZPQNucbAjBM_0 cow +ZQITHWk17a0_0 bicycle +ZQxmb_nVoH4_1 cow +ZRUXj8o10Po_0 person +ZSnP5B6NiI8_0 train +ZTqDuCZVTmM_1 airplane +ZTqDuCZVTmM_5 airplane +ZU3AYv2eU74_0 motorcycle +ZU4XQbNaYQc_0 knife +ZVZWEWzZg50_1 bird +ZVjep3tDJjU_0 person +ZWL6CshdsuY_1 cow +ZWogXn8xs7E_0 motorcycle +ZXU4Uua3l0E_0 car +ZYOUZjfZMhk_0 cow +ZYS0h2pAK6M_0 horse +ZYm5iVw0YdE_0 truck +ZY8pG-I5Ax8_1 bicycle +ZZBBcTBPmis_0 person +ZZpckGIvGTI_1 boat +Zana4yKDGxY_3 skateboard +Zana4yKDGxY_1 skateboard +ZbnxzLt8FJk_1 dog +ZbnxzLt8FJk_0 dog +ZcXtrHkjobw_0 person +ZelRUJyMMkw_0 person +ZeqhN6ndscE_0 person +Ze8cOn59rW4_0 person +Ze8cOn59rW4_1 person +Zj1TAkYHlQo_0 person +Zj7GzCIi_9c_0 person +ZlEiOICCDdc_0 person +ZlH8Hd961FM_1 knife +Zl30Oy50PfQ_0 person +ZmXKvpkfHZA_0 train +ZmdvunyqJB8_0 bus +ZqTkqkEbXEk_0 cow +ZrPn3BODZJM_1 person +ZrPn3BODZJM_0 person +ZuBD3A8Vecs_0 bird +ZuEbZKmjxaA_0 train +ZuEbZKmjxaA_1 train +Zu7udgxuUkk_5 airplane +Zu7udgxuUkk_6 airplane +Zu7udgxuUkk_1 airplane +Zu7udgxuUkk_2 airplane +Zu7udgxuUkk_3 airplane +ZvadVS1LnQU_0 bus +ZvadVS1LnQU_1 bus +ZvadVS1LnQU_2 bus +ZwLvs9JUsFY_0 person +Zw4-vF-vOMk_0 person +ZxO4Gd5fhOg_1 train +ZxO4Gd5fhOg_2 train +ZxX6DBopv30_0 skateboard +ZyEA24Ud3EM_0 person +ZyM24-ekpz8_0 person +ZzBvzlzuw4M_0 person +Z03ZC9qmwDc_0 zebra +Z1N0xBj_H3E_0 bird +Z1ns6XidhT8_0 elephant +Z2S6XnfE5vI_0 person +Z2kb4LiQJUU_0 train +Z2zB-gtDgOM_1 elephant +Z22DSYtblFo_0 bicycle +Z5rHikLjARg_0 person +Z6XKceRI1bE_0 bus +Z6XKceRI1bE_3 bus +Z6XKceRI1bE_6 bus +Z6XKceRI1bE_10 bus +Z6qQE2_jsIM_0 skateboard +Z68yTt3upjk_0 motorcycle +Z8SxFPbnptI_0 person +Z8pujku9bPw_0 person +Z9vZk0io0fw_0 truck +Z9vZk0io0fw_1 truck +Z-R7-Ww03t8_0 knife +Z_kKBbIzdXM_0 person +Z_pwMCnOdk4_0 knife +Z_pwMCnOdk4_3 knife +Z_0227AsAvk_0 bus +A_a1H0EO64s_0 person +A_a1H0EO64s_1 person +A_pc9ov1cT4_0 person +A_weMKVolQM_3 bear +BBC4Jmlky4Y_0 horse +BBHBoewIXhw_1 umbrella +BBHBoewIXhw_3 umbrella +BBHBoewIXhw_4 umbrella +BCKR989ZYyM_0 car +BCKR989ZYyM_2 car +BCpaJ-tEv-0_0 car +BFP7MT8RM8U_0 elephant +BF7cTjrTSwY_0 cow +BF8d91cJS3o_0 person +BGcAVF0Zi_o_0 person +BGzetX8Dz-M_0 cow +BHurVVjld8Y_0 person +BIUeggZa3SU_2 person +BIUeggZa3SU_0 person +BIUeggZa3SU_1 person +BIfedkd3HEg_0 boat +BJaAlMv6b_U_1 motorcycle +BKKSiAed9CI_0 horse +BKtAnbXVk1E_0 person +BLCEb_seyUs_0 airplane +BLCEb_seyUs_1 airplane +BL8o-tdhlxs_2 train +BL8o-tdhlxs_3 train +BMhmY9_ltFc_0 person +BO7KZKb9bkQ_0 cow +BQRwIXopDJw_0 person +BQRwIXopDJw_1 person +BQswg--xiy8_1 horse +BRd8dUMN0a4_0 knife +BRmtavy2ZEo_0 person +BR0NNg6gLLo_0 person +BSo8wjoZ7zc_0 skateboard +BTSUQrxC6l4_1 bus +BUHULgt_7DA_2 elephant +BU3iU3zJnDI_0 person +BU8sEPifL08_0 person +BVTVHHm7vkA_0 boat +BWNTXqGixw8_0 bird +BZUE0vDhMvk_1 knife +Bb2fkGYxp2E_0 person +BckXjb2o93U_0 person +BdHNtn10UKE_1 horse +BeXziIDAJDc_0 person +BgHV_87CxNI_0 umbrella +BgXr-bSqMIo_0 train +BhO0SwB8Ee4_0 person +Bh4m74dLZaM_0 person +BlYWgnhwvkM_0 elephant +BlYWgnhwvkM_2 elephant +BmZNFBFj-ws_0 person +Bm2yaWXwgjY_0 knife +BpXhq5Awd3U_0 dog +BrC6VbCzRGc_1 knife +BrHslMc3UMQ_0 truck +BscLJpi3AJc_0 person +Bv8WeZ_zrJc_2 bear +BzEC1EEC2ts_0 person +BzXWK-LODVo_0 person +BzbzymdK_TM_0 person +Bz6Od4GfW6A_0 truck +B0DRHTdmeK4_0 knife +B31JkzyQDkg_0 bear +B5GVudI81dM_0 dog +B6nArbkcRek_0 motorcycle +B6sR2aqScR4_1 bus +B7IP-2uNuWs_0 skateboard +B7yxjI6dz4s_0 motorcycle +B8iZGZlQcsg_0 person +B8opNd6uzmY_1 person +B9GQwzI2Eqk_0 dog +B92X9Xn1P2s_0 person +B-CJ8miJKPs_2 cow +B-n15EytPtQ_0 person +B_WnXKd-oZk_0 person +CADW3z8x4AU_0 skateboard +CADyh6laNA0_0 motorcycle +CA3wWkrNnRs_0 person +CBSNFKeTnpA_0 bird +CCyZAt2Js0U_0 car +CE-LfFDfGKQ_0 person +CE-LfFDfGKQ_1 person +CFN40hxKxM8_1 airplane +CFPhXPCobFg_0 person +CGg2FXjvvOA_0 person +CH3phgDW5Fc_0 person +CINfsd8LiOU_3 horse +CINfsd8LiOU_0 horse +CINfsd8LiOU_2 horse +CIqkbJoJhBI_0 train +CKmnpW6gboU_1 boat +CKmnpW6gboU_0 boat +CLtQxCqTzcY_1 knife +CMgYFnnxQUU_0 horse +COcbSVCp4ig_0 bicycle +COcbSVCp4ig_3 bicycle +COcbSVCp4ig_4 bicycle +COcbSVCp4ig_5 bicycle +CRF7PcgB2yQ_2 bus +CSnhpel7FTA_0 person +CSriNtLepLs_1 skateboard +CVmBocpXeTc_0 bus +CWCfCeYh2bA_1 train +CWvjAYt5eR4_0 bus +CW9n8Gahfgg_0 cow +CXT98GHNtRU_0 person +CZ-Sh-SXaRQ_0 person +Can5eao1S3Y_0 bus +CbB-71R_n9M_1 motorcycle +CbpAv8c2Vsg_2 car +CbpAv8c2Vsg_3 car +Cb3iufTFMEU_0 person +Cc2vs8vuPmU_1 bird +Cc8E7aTdEVM_0 person +Cdain96L-q0_0 bus +Cd7g3ZoA5tQ_0 bus +CeN22koBQRM_0 person +Ce2jOHHBDLk_0 motorcycle +Ce7IPtXkNcs_0 person +CfqkbrB0Yy8_0 person +Cf2jOSj7eRg_2 train +CjbhKc3Vjpo_0 person +CkEVvGqgVkQ_1 knife +Cl13SbLP0hE_2 horse +Cl13SbLP0hE_3 horse +Cl13SbLP0hE_0 horse +Cl13SbLP0hE_1 horse +Cl-lB_jS8Wg_1 bear +CnMMdc6syXM_2 umbrella +Coxzc_S3ID0_1 knife +CpLMLRdeJJ0_0 train +CpN-qOO6Qm4_2 airplane +CpyK9j001RY_0 person +CqNEwP8PwS4_0 bear +CqNEwP8PwS4_1 bear +CqYiAanNpo4_0 person +Cqbu8vOsszI_0 cat +Cr5p4NYIR44_0 person +CttKQip6B2E_0 person +CuGu45Z4lt8_0 knife +CvszgVrLsgA_0 person +CwYG2Hf6-NY_1 cow +CwvR1fjMeSU_1 horse +CyuollntwZ8_0 dog +C1dCZ9W6WIM_0 person +C2x3rdWMAyg_0 dog +C3lwMd_rlG0_0 person +C5MrhYouFTc_0 cow +C5SKibJTnR4_0 cat +C6dANICzCcg_0 person +C6xJeHO8XSE_0 person +C7NXymSnEFw_0 bird +C8ExRKjU1vY_0 truck +C8V2-wEjv5A_1 cow +C8sUABBP0Jc_1 bicycle +C8sUABBP0Jc_2 bicycle +C80bmA0XrjM_0 person +C886JwUWvxw_0 skateboard +C-Tal1XUc8o_2 person +C-zp91eJqtk_3 bird +DApDao4fUqQ_3 horse +DApDao4fUqQ_1 horse +DApauH43Ivo_0 bicycle +DBArY7gHuoY_0 cow +DBsBTVJNxS8_0 dog +DBsBTVJNxS8_1 dog +aCNvyXSuG6w_0 person +aCVmJCtuPeg_0 bird +aCVmJCtuPeg_1 bird +aDMk7CwLIxM_0 train +aERiDkn_gkY_1 elephant +aEwD6TC8S4w_1 bicycle +aFEOvm-1KvA_0 horse +aHM4Dj-2y8o_0 airplane +aI0y0wY4LQw_1 person +aI0y0wY4LQw_2 person +aJAd-MiEsfk_1 person +aJWETVChAE8_0 person +aJoKSWtqs0g_0 truck +aLYtaO_J2_U_0 person +aLbjxTwAV7o_0 person +aMDD0PenhaM_0 cow +aMgj1BUBexw_0 person +aNgAUBTbUUM_0 person +aNmgrcJxdw8_0 motorcycle +aN2a-rDAYDQ_0 dog +aN2a-rDAYDQ_1 dog +aOhumbyx05c_0 cat +aQcTwMVs1Zk_0 skateboard +aQcTwMVs1Zk_1 skateboard +aQx68fklEXA_1 dog +aSGod2MJ5ww_1 horse +aSq5ZqH_K7E_0 truck +aTAXvSNkuvc_0 bus +aUFxg301s68_1 skateboard +aUsTtvWAzAc_0 person +aV8S5HLSI_o_0 person +aWHaR4ExDpk_0 truck +aWIZBHwtII8_0 motorcycle +aWgH9T2sGkE_0 boat +aWmC8Tbgy9A_0 train +aXa5YE_AmKg_0 person +aYAuay_bTaw_0 cat +aYVEZrX4mE0_2 bear +aZRYQJd-5CQ_0 train +aZRYQJd-5CQ_4 train +aZRYQJd-5CQ_3 train +aZRYQJd-5CQ_6 train +aaZxOcHxPec_0 person +ab_RTkwBG_4_0 person +acy4aJnh9SU_0 person +ac68trlkEnw_1 horse +adsmRxlAJo4_0 dog +afE4YqgaPlw_0 skateboard +afU2vHgUvaw_7 train +afU2vHgUvaw_2 train +afU2vHgUvaw_3 train +afkiqhwTeRQ_0 person +aiOHs3hApm0_0 skateboard +aiOHs3hApm0_1 skateboard +aij190b9wtM_4 bear +akWe9oXeKzA_0 person +ak1XT_Nl7VU_0 airplane +ak4CfFF9Bpk_0 person +albeyJBtKD8_0 person +alp0ImrbacI_0 dog +al12VKid_P8_0 person +amyr6d2Ns6M_0 horse +amyr6d2Ns6M_4 horse +amyr6d2Ns6M_6 horse +ao9LHpxNCqY_0 horse +apLT3-LKJgE_1 truck +apXNcHROKyY_0 horse +aqp_quyEngw_0 airplane +aspR9ca28CY_0 person +as3DGRDezaA_0 person +atElNgnFvlk_0 person +at-Ex-CnRX4_0 airplane +at-Ex-CnRX4_1 airplane +au_kgqsZlMU_0 truck +avRC7M3_kuA_0 bird +awnORAEMUIg_0 person +aytqFnOdBLA_0 person +azLbVm88Dzc_3 airplane +azLbVm88Dzc_2 airplane +azXlb1cxVGQ_1 elephant +a1qoB1eERn0_0 person +a2-lZhKXx9E_0 truck +a3In51YCqMg_0 dog +a3T8T1R2wAc_0 bear +a45XOJQaDQI_0 person +a5dffDLeZsI_0 airplane +a7hjIfPGJqI_0 cat +a74_tj_B-YA_2 knife +a74_tj_B-YA_1 knife +a8v0k4Bz_QA_0 person +a9jgDU5THOU_0 person +a97S4U5ezQw_0 truck +a97S4U5ezQw_1 truck +a-M2_3j67qI_4 knife +a-M2_3j67qI_5 knife +a-M2_3j67qI_6 knife +a-NeSgN26Zo_0 bicycle +bAKQZ0F7LFw_0 person +bA10PjxgV3w_1 elephant +bBPKh_BPJ50_4 bear +bBPKh_BPJ50_1 bear +bBW4swLrEHE_0 person +bB6tIraYEaI_0 skateboard +bCDw1dn7M1Y_0 car +bCDw1dn7M1Y_1 car +bCWM39xLsYs_0 skateboard +bDFkztSgMko_0 skateboard +bD6xZhJfhMU_0 truck +bFnzGS_doNQ_0 person +bGFRHhc7zUI_1 person +bGZtGWULlF0_0 skateboard +bGZtGWULlF0_1 skateboard +bIOpYFVLesY_0 person +bJviDDrUSwA_0 motorcycle +bKB6ESqkOic_1 truck +bKRAinEnagU_1 motorcycle +bKRAinEnagU_0 motorcycle +bNXcPzWMXsw_0 car +bN43crdYDJE_2 bus +bOL9YHt5u-o_0 skateboard +bOL9YHt5u-o_1 skateboard +bOofbwD246U_0 person +bPKew4jsGkE_0 truck +bPRVRL4x5T0_0 truck +bQkneVc9gaA_0 airplane +bQ64JFsWSf0_0 bicycle +bRWbXGRwlVY_0 person +bS1Z1k6laqY_0 person +bUqFsPoDKBE_0 train +bVP58EONEm4_0 cow +bW4nHswGFPo_0 motorcycle +bW5IvSesbV0_0 elephant +bXR-iz0NfrA_0 cat +bZDsNeqNn9I_0 car +bZDsNeqNn9I_2 car +bZDsNeqNn9I_3 car +bZDsNeqNn9I_5 car +bZIU-ajwk6Q_0 bicycle +bZIU-ajwk6Q_1 bicycle +bZ6Tq0KWSsU_0 truck +bZ6Tq0KWSsU_2 truck +banaB07Fu9c_0 bear +bcKUeyEaRPw_6 bicycle +bdhq0SKEqe4_0 person +bd3b9R30l-E_0 person +beDuTpy1tg4_2 horse +beDuTpy1tg4_0 horse +beLkXAaP78Y_0 train +be30TAE-gq4_0 person +bfQSyBsTmE4_0 umbrella +bgSSzKax51E_1 motorcycle +bgSSzKax51E_0 motorcycle +bhoUxK8FSqc_0 person +bhuPA9toCGY_0 person +biIFNnX2Nl4_0 skateboard +biu2ssO3dRg_0 bus +bjRPge2oFgU_0 knife +bjV04dzuqhk_1 elephant +bjdIG6B5zn0_0 person +bjdIG6B5zn0_1 person +blPLp16K1XY_2 bicycle +bmJ_QDIRS2U_1 train +bmJ_QDIRS2U_2 train +bmJ_QDIRS2U_3 train +bmLsrJHQQ14_4 knife +bnBORorLvmk_0 person +bnBORorLvmk_1 person +bnVGsydNrg8_0 airplane +bnVGsydNrg8_1 airplane +bnZbj1dD0qs_0 umbrella +bn0I2aJB5Ps_0 horse +boMU1mjUSDw_0 skateboard +bo8M-OTk4J0_0 person +bpw3BCxYYU4_0 horse +bqoDChNwIYY_0 umbrella +brJqQ_iH2VE_0 person +brMVhyEZLfo_0 person +bs5AY2jipno_0 train +btL-vruELoA_0 person +btq7gMuqMuo_1 person +btq7gMuqMuo_0 person +bvEJDHpRNoI_0 elephant +bvVfFv57gN4_0 bus +bvVfFv57gN4_4 bus +bwhPTEvGmIo_0 person +bydgNyGwoys_0 person +bziUK-7O0lY_0 dog +b0Z6qKhuldo_0 skateboard +b0sKQDUFTos_0 person +b1s-jYD36GQ_0 person +b4Wua_98Y9U_0 person +b4d_9Yc0MwY_0 bicycle +b4qC2fctnLU_0 horse +b4zSrjPtOfs_0 bicycle +b5CJtpeG1Lc_0 train +b5CJtpeG1Lc_2 train +b5CJtpeG1Lc_1 train +b5mOcLykYeQ_0 cow +b9VOmo_86Ds_1 person +b_W4BWH1i_A_1 person +b_W4BWH1i_A_0 person +cBxo9bPINJc_0 skateboard +cCEImigNo38_1 train +cDHZtfsI_gM_0 train +cDHZtfsI_gM_1 train +cDmkhESohro_0 boat +cEcTernKOqU_0 person +cEcTernKOqU_1 person +cGJLuwZIG5s_0 giraffe +cGJLuwZIG5s_1 giraffe +cGJLuwZIG5s_2 giraffe +cGwjfCPO-7k_0 car +cH0sXpOxvy0_2 bird +cH9u1pCWp2U_0 person +cH_SL9CR8y4_3 dog +cIxdxFkZ7y8_0 dog +cIxdxFkZ7y8_1 dog +cJvh4GqZn-s_0 person +cKQQVTnOzBk_0 horse +cLULEYFoBPc_2 cow +cMdjRuUhBIs_0 motorcycle +cMdjRuUhBIs_1 motorcycle +cMwa9cC304w_0 cow +cMwa9cC304w_1 cow +cNDYJRBsIOY_0 dog +cPlqWSd2TUc_0 person +cP-p4R-JZxY_1 bird +cRBw9lx-EKA_1 bus +cR2-4m174EM_0 bird +cR-AWpc5zTs_0 person +cTujx-TutbA_1 horse +cUrajeQPzpQ_0 umbrella +cUrf-ZwPzxI_0 person +cUwPVOboe0k_0 person +cVng1vleWNY_0 person +cVrxfV0w29w_0 person +cXZ7JY7YQmE_3 bird +cYdqN1oPRdY_0 person +cagT3K3Ep3s_0 skateboard +cagT3K3Ep3s_1 skateboard +ca8rEbHYMXg_0 cow +ca-ko46j2fQ_6 airplane +cbL66gVAa5Y_0 cow +cctYyTO8OtU_0 person +cc3mBIHi-GU_0 elephant +cdNz1OLa1tU_0 car +cf_U0G5W8BI_0 person +cggX7PRYUh0_0 person +cg_5uaJjLHk_0 person +ch_23jXJ_vA_2 dog +ciCfkv5831Y_0 airplane +cih9W0SPGYA_0 bird +ciwNB-l9a88_0 person +cjHlHkhg0z0_0 person +ckFwzL1Ot94_0 truck +ckV9ay1lm7A_0 airplane +clZo-o5v1EA_0 elephant +clvCQPta7y0_2 bird +clvCQPta7y0_0 bird +clvCQPta7y0_1 bird +cmTPsZ9x3PE_0 cat +cmW0Y4KGI7g_0 giraffe +cnhhgh_z5NU_0 cow +cnqT4u0k3sM_0 umbrella +cpK8K6JD_GM_0 airplane +cpK8K6JD_GM_2 airplane +cprvb4cW5x4_0 motorcycle +cqd8PRxMakA_0 truck +cqvjKRFEi8M_1 car +crys7VEeUgU_0 person +cskBHjsDXEs_0 cow +cso6B_84BFA_0 horse +ctm9x2MaZuk_0 cat +cxu1qpzXobY_1 bird +cxu1qpzXobY_12 bird +cxu1qpzXobY_0 bird +cxu1qpzXobY_2 bird +cxu1qpzXobY_4 bird +cxu1qpzXobY_5 bird +cxu1qpzXobY_6 bird +cxu1qpzXobY_7 bird +cxu1qpzXobY_8 bird +cxu1qpzXobY_9 bird +cxu1qpzXobY_10 bird +cxu1qpzXobY_11 bird +czO8IPcAO1A_0 person +c1FBptbYp3I_0 person +c1FBptbYp3I_1 horse +c2T3VDriTaY_0 knife +c39xfJcSlxk_0 dog +c4kbPHdCIE8_1 elephant +c43mnrjx2MU_0 bus +c5fPKbV5cAM_0 person +c53j9l_w3Cg_3 dog +c7gnf6G7Jpw_0 skateboard +c7oqQy2Fvlw_0 truck +c8JhzKh1i7s_0 person +c8JhzKh1i7s_1 person +c8gBv0b5g9w_1 elephant +c8iU4McayiU_0 person +c8iU4McayiU_1 horse +c8u5Y95o7jE_0 skateboard +c84BjBiic4s_0 motorcycle +c93WuBjZeRk_0 person +c-nMPinePds_0 cat +c_aupqZy-14_0 airplane +c_o91IPAB-c_0 umbrella +dAHCPltzogA_0 bird +dAP6fuArseQ_5 elephant +dAtQR4dHPgE_0 person +dA0WQ_RubaI_0 truck +dBzXNQJRzls_0 cat +dCJFMDQBPb4_0 boat +dEIuy8LjAxc_0 car +dElaQ10vYqg_1 motorcycle +dHMFcv4UnmU_1 bus +dIP3FoGUXDQ_0 person +dJYqTnxujb0_0 person +dJnLznNE29w_0 train +dJnLznNE29w_1 train +dJ9qJezt6do_0 car +dJ9qJezt6do_1 car +dKmrUcJ9rJY_0 person +dKmrUcJ9rJY_1 person +dK3_HiQMH4o_0 dog +dMFsGGvkSVU_7 airplane +dMFsGGvkSVU_0 airplane +dMFsGGvkSVU_3 airplane +dMFsGGvkSVU_5 airplane +dMFsGGvkSVU_6 airplane +dNByeKh4gnA_0 person +dNJ0q9QKzmY_0 boat +dNQYo7REyBU_0 person +dOkb5WhLZGU_0 person +dO0uu_fVUVI_0 car +dO0uu_fVUVI_1 car +dO4Jxsf987s_0 bus +dO-OrWse3dA_0 car +dPCSntP-29E_0 person +dPCSntP-29E_1 person +dP7je2qU_QA_0 dog +dQIlnQxMIKo_0 train +dQIlnQxMIKo_4 train +dQIlnQxMIKo_5 train +dSAlTJeDlfQ_0 person +dTvJyUKKshw_1 person +dTzaYePj1gY_1 cow +dT5gXQAE-Qk_0 train +dT5gXQAE-Qk_2 train +dT5gXQAE-Qk_3 train +dUpoYuxpKPM_0 person +dVTCCi__Z4Y_1 person +dVte44AGoEE_0 knife +dW4RjdpTaJo_0 person +dXYYgzjwm8w_0 person +dXf-d5rkqdA_0 horse +dZv4xXpV6js_0 boat +daeBFAZFQhU_0 person +dbXKW9_L9sE_0 bird +dbwBzQuj1uA_0 person +dc5oaWIkfwg_0 cat +dc-iaCwezlU_0 train +deO0aj59T8o_0 person +dfU8DcWDX8U_0 horse +dfU8DcWDX8U_4 horse +dgcW3TkPLmk_0 boat +dilCe3bivVk_0 bus +di59PG3l25w_0 bicycle +di59PG3l25w_1 bicycle +djsh1r_W6ko_0 person +djt1lzJn7ak_2 bird +dlYwqfTRqoo_0 person +dl-bg8WPGZs_0 person +dmk3Cedj6g0_0 person +dn006hdarCg_5 elephant +dn006hdarCg_4 elephant +dn006hdarCg_6 elephant +dn006hdarCg_7 elephant +dn006hdarCg_10 elephant +dn7iBi1t7UI_0 cow +dn83BrM71W4_1 boat +doOsOyiHItw_0 person +dpqVH2tgA3E_0 person +dqlk6F07Cxw_0 motorcycle +drohCN_vwC8_0 motorcycle +ds7JGeImFXo_0 horse +dtsLwaO2des_0 train +dt5TzAZByk0_0 person +duROYI-AZlk_0 person +duROYI-AZlk_1 person +dutryxrzRjE_0 umbrella +dvDxOc2VWhc_0 person +dvP5Dsp8EZA_2 dog +dvTIkEA7rOc_0 person +dvvoKcQ5OOQ_3 bear +dvx9-0cVEYc_0 person +dwQuyR9XFVM_0 skateboard +dxcnKYynkEY_1 cow +dxmxpyj3WVk_0 knife +dxmxpyj3WVk_3 knife +dyUVa3ZQVFg_0 horse +dzitRPrX410_0 cow +dzpcdtcQLfY_0 motorcycle +DEnqBEwPykc_0 person +DFCqlvY5OFY_1 bus +DFXptvzN9V8_3 umbrella +DFqSvoSh-qA_0 cat +DHEtea1hPBc_0 person +DHwUCu0rrvc_0 boat +DJ_neeMWAuw_2 dog +DLsYDXqthiY_0 skateboard +DMBbH5HyOME_0 person +DMn3ruRAObI_0 person +DMyjVWCLbes_0 person +DM6e1vEjYeM_0 bicycle +DM6e1vEjYeM_6 bicycle +DND0C3XD7mQ_0 horse +DOQilAKERwk_0 umbrella +DOmE1dA6CoQ_0 person +DQJ4cPhVhFg_0 airplane +DT895n1nqqY_5 bicycle +DT895n1nqqY_4 bicycle +DUO7S4ma320_1 cow +DUO7S4ma320_0 cow +DU9GDCN25lI_0 person +DV4bDUzPAIU_0 train +DWxidp6TWlg_0 airplane +DXhV8uXKo7w_0 cow +DXxF81ZJ_Jo_0 cow +DX1_rKFVugE_0 dog +DYBLqnRCo7g_0 cat +DZ2-5rYAUVk_0 train +DasqUqgdRv0_0 dog +DbNVb8C-Au8_0 person +DbcdvAsVI48_0 person +DcZSisTgSJs_0 airplane +Dc9pWTcUNXY_5 bear +DeVQ3mr19Sw_2 skateboard +DeYmal3wAoE_2 dog +DeYmal3wAoE_0 dog +DfOuxNA9lro_1 giraffe +DfXOTMc9IyM_1 dog +DfbPDcLTZEo_0 airplane +Df89T9IxDvc_0 person +Df93ocrYlyY_0 person +DgBuwqAbIkI_0 skateboard +DgBuwqAbIkI_1 skateboard +DhA0S7lPFVw_9 elephant +DhA0S7lPFVw_0 elephant +DhA0S7lPFVw_1 elephant +DhA0S7lPFVw_2 elephant +DhA0S7lPFVw_4 elephant +DhA0S7lPFVw_5 elephant +DhA0S7lPFVw_6 elephant +DhA0S7lPFVw_7 elephant +DhA0S7lPFVw_8 elephant +DhEO4MuDBOc_0 dog +DhJAQCycHJs_0 elephant +DhU-e-L13WM_0 person +DhU-e-L13WM_1 person +DhU-e-L13WM_2 person +DiLGyNCykDE_0 skateboard +DjQx_qEnXko_0 airplane +DkMltyvC5l4_0 person +DmPTbBo32qI_0 bear +DmzlB4KBLN4_0 bird +Dm-XQKFA-BQ_0 truck +Dni4lPw5oH0_0 person +DnzZd_9JlAA_0 cat +DoB18AvtSxQ_0 train +DofzMEokur0_0 person +DonLBf92rMc_0 dog +Dpp4k_BzZY8_1 airplane +DqcEAexhJ10_0 car +Dr6LfvQ_qKo_0 car +Ds_4eRyQDPo_2 boat +DuLk58XzeyA_0 train +Duv1XrdytdE_0 cow +Du4jlCLKZds_0 person +DvjMMfcCq3U_0 person +DvuTkGshMjA_2 cow +Dvx0WVMuXVw_3 boat +Dw4--8weqIA_0 person +Dx0LbiFgvPI_0 truck +DyY1MPuGf5w_3 dog +DzUJVl_Pej0_0 person +DzV-LWU5GoY_0 person +D0b7xYmwl-M_0 skateboard +D0fhKhpAhJM_0 zebra +D0jRA5TKT-o_0 person +D1vTDW7YDTk_0 person +D2hRnCm0JtM_0 person +D2oV8BC0iq8_0 person +D21mLV716vI_0 person +D32GncZb51Y_3 truck +D4Jcg1u1Z-o_0 person +D5maMxzZBe0_0 person +D5m40zCfU8E_0 person +D6E0xgBBquU_0 person +D68oMT6tpc4_0 person +D7H1UQbgDOw_0 cow +D9RGgV3fKds_0 bird +D_a5TQmLY-Y_1 person +EBJ5jExrVqY_0 cow +EBLJ9v0QSrU_0 car +EBUmagxsoV8_0 person +EC8ftAGy2qA_2 skateboard +EDBDHaRqToc_0 dog +EEZKnzcn-v0_0 cat +EEfiTwozdM0_0 cow +EExHYyuWa-o_6 bird +EExHYyuWa-o_2 bird +EExHYyuWa-o_5 bird +EFRywDKULxc_1 train +EIl3WAxkNwc_0 train +EJJXpIiBEuw_0 cow +EJrj49l1N8k_0 airplane +ELPjTNVxWfM_0 person +EL-2TiSSQJg_0 bear +ENPh0zyq2wo_0 motorcycle +EOAADsR4IpM_0 cow +EP3xfG5_2i8_0 cow +EQN5hODdb6o_0 skateboard +EQ09ewMQn8Q_2 bird +EQ09ewMQn8Q_0 bird +EQ09ewMQn8Q_1 bird +EQ9vXT_IFYQ_7 bird +EQ9vXT_IFYQ_3 bird +ESxRPsxVX-U_0 car +ETxRky6I39w_0 person +EVD8F2ZOBbI_0 elephant +EVYb5simSY0_0 umbrella +EWOehvvAvqU_0 person +EXK2mcPIoBI_3 skateboard +EXK2mcPIoBI_0 skateboard +EXK2mcPIoBI_1 skateboard +EXK2mcPIoBI_2 skateboard +EXeKX_vOTvc_1 car +Ed-cfsA3BsU_0 horse +EeQOKiPASgY_0 person +EfAYg1FMY-4_0 bear +EfAYg1FMY-4_5 bear +EfAYg1FMY-4_4 bear +EfSd4ucOXKs_0 truck +EfbKwoMA6Kk_3 horse +EgpujPNldhs_0 train +EhQXwVQsngU_0 boat +Ej0A86Eu1p8_0 person +ElHgkP_L8Eg_0 airplane +ElTbW5itOAs_0 car +ElTbW5itOAs_3 car +ElTbW5itOAs_4 car +ElTbW5itOAs_7 car +EmvEUer4CVc_0 umbrella +EnIkH0jrzaI_0 skateboard +En6a3Ed7fvk_0 person +Eo5s8ykuzbU_0 person +EpBZ77zmngM_0 horse +EpPw2JoHiTQ_0 person +EqPK8xdf8hQ_0 person +EqdBE21XAks_2 umbrella +EqdBE21XAks_3 umbrella +EqdBE21XAks_4 umbrella +Eqz3xG4mWTs_0 person +ErN8-oTPkq0_1 person +Er-RnWQrUac_0 cat +EsvPqOf-zEA_0 person +EtIj5IUtn-g_0 airplane +EtIj5IUtn-g_1 airplane +EtIj5IUtn-g_2 airplane +EtMlgBveP58_0 dog +EtMlgBveP58_1 dog +EtkDITl8mEM_0 person +EwlCKB77dYo_4 elephant +EwlCKB77dYo_2 elephant +EwlCKB77dYo_3 elephant +EwqkMKutzBE_1 knife +Ew-67eGgZAI_1 motorcycle +ExRpjMcFoBY_0 dog +EzRrohN-4ss_0 skateboard +EzZW0lM284U_0 skateboard +E2DbbyoqLg0_0 person +E2DxfZPPu5Y_0 horse +E2DxfZPPu5Y_1 horse +E2DxfZPPu5Y_2 horse +E5erp1mhTzk_2 bear +E7CsRpWElOo_0 horse +E76rAl8oksk_0 dog +E9ARkaJcz2M_0 person +E9J03vUxTZQ_0 truck +E9w2-Y4d3MM_2 truck +E9w2-Y4d3MM_0 truck +E-ea5keAG3Y_0 person +E-jpkZw_MdU_0 motorcycle +E_cxlc0vrMg_0 horse +FBA18EyY2eI_2 boat +FBQpWJPC5pQ_0 person +FBQpWJPC5pQ_1 person +FBo954IqOlo_1 bicycle +FBo954IqOlo_5 bicycle +FBo954IqOlo_0 bicycle +FBo954IqOlo_2 bicycle +FBo954IqOlo_3 bicycle +FCICeCD4dKc_0 person +FCypWBdHWb8_0 elephant +FDKvBZH5LZE_0 horse +FD89Oq7BclA_0 skateboard +FETKMmV7P70_0 motorcycle +FETKMmV7P70_1 motorcycle +FEbVjS5-4ps_0 person +FEsMY2y49d0_0 person +FFuW_UWBVpU_0 train +FHRrYqTZExQ_0 person +FID77dKUAU8_0 cat +FITKtv4tf7w_0 cow +FIi2mEV5dfQ_0 skateboard +FIi2mEV5dfQ_1 skateboard +FIvujc5oqIY_0 train +FJDKoEDLbNc_0 airplane +FLsLXPchOx0_0 knife +FMV_-mdKV8U_0 horse +FNNrfAuIQmo_1 horse +FNpd4DJ9LBA_0 horse +FPrcQJh9INg_0 person +FQMXzPIoL14_2 bird +FQ-_p0lM-FM_1 elephant +FRxSISi7wV4_0 bicycle +FSFW4QxV8-0_1 truck +FUlVrltDAOk_0 bird +FWNxjmydNdU_0 person +FYVNE1zYmyA_0 person +FZrXRU5CxC8_0 boat +FaG9RreeG6M_6 bicycle +FaG9RreeG6M_2 bicycle +FbF-nKQx0WI_0 person +FcP50mFdaYM_0 train +FdPApnQkBVQ_0 bird +FdPApnQkBVQ_1 bird +FdlDAmvsrR0_0 horse +Fd1uYmMhzPE_0 horse +FedOlGadIYU_0 bird +Fgd7fHxPhBs_0 truck +FhQLl40AANQ_0 bicycle +FhvdS8wJkrI_5 bicycle +FhvdS8wJkrI_1 bicycle +FhvdS8wJkrI_2 bicycle +FhvdS8wJkrI_3 bicycle +FiCIZpT08B0_0 cow +FiD6UZuDr1M_0 person +FjFwrTEJK1U_0 person +FjmcQfLBpvQ_0 person +FkSfwpb1Gss_0 person +Fkhru_XyPSU_4 bicycle +Fkhru_XyPSU_1 bicycle +FlOaA91Qa2M_0 cow +Fm7Z44jVp_A_1 person +Fm7Z44jVp_A_0 person +FnIpAhpGTps_0 person +Fn0IWwSVPlk_0 person +Fotm2Ewrdr8_0 dog +Fphk_JpP4JY_2 bus +Fp2WKSG1qGw_0 person +FrFv1rYtAws_0 train +Fr298zXE9O8_0 umbrella +FshCFVUSBXY_0 person +FsiLiUl9I10_1 dog +Fs0LVU4qKSs_0 skateboard +FtEi5TPqRiA_0 dog +FuWY9thbtxw_0 airplane +Fu9EsTmh8z0_0 person +FvCCkxW3sv8_0 person +FvDNYPmcXjQ_0 bear +FvDNYPmcXjQ_5 bear +FvDNYPmcXjQ_1 bear +FvDNYPmcXjQ_3 bear +FvHW0PyfZ_Q_1 skateboard +FvHW0PyfZ_Q_4 skateboard +FvHW0PyfZ_Q_5 skateboard +Fv542o8y6aE_0 person +FyEliJtlQIY_0 person +F0PPPvVTNnE_3 bear +F3iJ9TqS-lE_1 bear +F3iJ9TqS-lE_0 bear +F39H1yTLerI_1 train +F4xCJHUMGsE_1 elephant +F47hXNWC3K8_0 cat +F48wdm2YukQ_0 bicycle +F48wdm2YukQ_5 bicycle +F5Cc5wQJvhI_0 person +F5Tm5BM0oaM_0 train +F5unbOiULNM_0 motorcycle +F5unbOiULNM_1 motorcycle +F9B5cLZb3T4_4 bicycle +F-OWsiGzRg0_0 person +F_bZObIr47Y_0 bicycle +F_bZObIr47Y_1 bicycle +F_dg4Hi5ZU0_0 car +F_xLwEhMPdY_0 person +F_8rnxkAIgQ_0 person +F_88eTR1pKU_0 train +GAMoEnodBZ8_1 bicycle +GAZx8145Hkk_1 person +GAZx8145Hkk_0 person +GCW28zxN9vk_0 person +GDM2ctXPkmg_0 person +GD5lsE86vOA_0 car +GE2nS7Zbkrc_0 airplane +GE6JO6nrE2A_0 person +GF9unI6hEMI_0 airplane +GGULYyv3_eY_0 elephant +GGULYyv3_eY_1 elephant +GGVYYc0KNWc_0 truck +GHTZcjImEqk_0 person +GIJMEjX04dI_0 person +GIM6FHDMp0A_0 person +GJTjlO1FJpo_3 bear +GJTjlO1FJpo_5 bear +GKyxtLTjXUU_1 motorcycle +GLG6II1JYko_0 bird +GLpNrOwqNXc_0 person +GLvmwdOjsHE_0 cow +GOEqT5_bhls_1 elephant +GOVFUFYsINQ_2 elephant +GOfP3fxCTvw_0 person +GPPKPFCI-Kc_0 person +GPSXltbv0f4_0 motorcycle +GP5anr-xMfw_0 person +GRluMAZzu8c_0 airplane +GSlWcX28sLk_0 person +GUMAgiab8bg_0 person +GUQmoD1aWhw_0 truck +GUS7BLoHHPk_0 airplane +GVNmuLeQ6pA_1 airplane +GVNmuLeQ6pA_2 airplane +GWBEjzdOLjI_0 giraffe +GWBEjzdOLjI_1 giraffe +GWBEjzdOLjI_4 giraffe +GXMBH6OujvQ_0 person +GYM460lVV-k_0 horse +GYQO-VevHpI_0 person +GYYxgR_VGFQ_0 dog +GZSlxtl9bj4_0 horse +GZSnngz0VX4_4 dog +GZhWdIsibfs_2 bear +GaierMnR4Xk_1 elephant +Gbe74-OWIo4_0 person +GbwJhzDrFtI_0 airplane +GceLsS4AwH8_1 horse +GcjSF4Uyl74_0 person +GdoD65Qn6kE_0 cat +GeOos0BFCSY_0 bus +Gf_4plKc8tw_7 horse +Gk8oy0G3dRU_0 person +GlAH7-Rf8gc_1 truck +Gm9yMiay9Is_2 skateboard +Gm9yMiay9Is_3 skateboard +GnTFmN4UNrI_0 motorcycle +Gn6ltyIKgcs_0 person +GoXxeDaopwo_1 person +Gokzf7T4oVU_0 cat +GpE5cmO_2kQ_0 skateboard +GpE5cmO_2kQ_1 skateboard +Gq7NQWGviWU_0 train +GsLJXtf6RC0_0 person +GuMiw_OwxlM_0 knife +GubE6GTKTVc_0 person +GubjV1tFrVA_1 umbrella +GvRQ4QZHPGc_8 bicycle +Gvjv4DJftts_1 cat +Gv5P6ORl-1M_0 person +GwAGS0xPZDQ_0 person +GwY5WqLjTcM_1 cow +GwY5WqLjTcM_0 cow +G0C4XEsjKGU_1 bird +G0i_9qeBwm8_0 airplane +G0sAxRZi6m4_0 car +G1doEZFbv70_0 airplane +G1gPj-UK_gw_0 cow +G107tKapVcQ_0 giraffe +G16fmAfdp9A_1 zebra +G16fmAfdp9A_2 zebra +G2gyuboBt-E_0 elephant +G2gyuboBt-E_1 elephant +G3jqix8WiYE_0 person +G5jg_wMMXmU_0 person +G6iN1OKj_eE_0 elephant +d0G8DzwenzU_0 person +d2ugQO5Z8M8_0 airplane +d3_3kfZ7rkc_0 boat +d3_3kfZ7rkc_2 boat +d4cTjVsUbIA_0 person +d44bp_UDYOQ_0 cow +d6vOtyrW2eQ_0 motorcycle +d6vOtyrW2eQ_1 motorcycle +d6vTXY--7zw_6 truck +d6xRfIz84Og_1 cat +d8GWgCsv0fo_0 person +d8kSiPkTvek_1 bus +d9IW6kCjfmA_0 knife +d9IW6kCjfmA_1 knife +d9YRdtwcTOo_0 motorcycle +d-CkujEJl24_0 zebra +d-6-T4gkBTk_1 cow +d_eu3LZxECY_0 motorcycle +d_eu3LZxECY_1 motorcycle +eBIZSQg7pV8_0 airplane +eBSijengaq4_0 person +eBVE2h6i3Do_0 person +eByIZzEh-DA_1 dog +eByIZzEh-DA_2 dog +eCzDpCe6xvc_0 horse +eDUR6UTxYhk_0 person +eFXZRDC38No_0 bird +eGVUtZXFcmY_1 cat +eJn0yGDjytc_0 cat +eKcJ2alScW8_0 cow +eL4uMBEG4gE_0 bus +eMsvM8G2Z0s_0 truck +eM0KTbh6EZE_0 person +eN0JRkzxVPw_0 elephant +eOeuY4ZbTt8_0 bird +ePiG-qPeJ6c_1 elephant +ePiG-qPeJ6c_3 elephant +eQEBmp37ZMQ_0 person +eQ6zyKVuU2s_0 person +eROdacH1GEk_1 horse +eRsf1_omRf4_2 elephant +eRsf1_omRf4_5 elephant +eRsf1_omRf4_6 elephant +eRsf1_omRf4_9 elephant +eRsf1_omRf4_12 elephant +eRsf1_omRf4_13 elephant +eRsf1_omRf4_14 elephant +eRsf1_omRf4_15 elephant +eTfXd1DQ6mc_0 dog +eU_B2dXyBkI_0 elephant +eVAEQdogSqk_1 person +eVLFX7RZOJM_0 person +eVnnuxmvpM8_0 person +eVnnuxmvpM8_1 person +eVnnuxmvpM8_2 person +eWU6Kk9K6lI_0 airplane +eWZHute7e6Q_0 person +eXAJwsjltWs_1 airplane +eXAJwsjltWs_7 airplane +eXvofXrEuU8_0 person +eZFqrD8MAKk_0 horse +eZFqrD8MAKk_1 horse +eZc2BPYt4rU_0 person +eZ9Qy0zfLb8_1 dog +eaoH4_TdTt8_0 person +ea2xP5nm53M_2 knife +ea_yr_40TRY_0 airplane +ebc-oEY_eDM_0 cow +ecksf6PLvhw_1 dog +edx1TW6jRFg_0 person +ee6Zcz8Pyfk_1 cow +ee6Zcz8Pyfk_2 cow +efczZtAK28w_1 dog +egbQbEuLDlE_0 cat +egfoTu4gtZo_0 bicycle +egg1WCEyuTw_0 person +egmCEe7OgiE_0 person +ehxHGWKtaAg_0 person +eh9YpbAcMZE_0 person +ejRwmx3kUI8_0 person +ej0xIcEXWiU_0 horse +ekfKlK5w3Lg_0 person +ekwoV0dpRwI_0 person +ekwoV0dpRwI_1 person +ek7bnCHGZq0_0 skateboard +elB6RfDJA6M_1 dog +eljiGrMEYiQ_0 person +eljiGrMEYiQ_1 person +emISA6YzHZ4_0 bus +emISA6YzHZ4_2 bus +eoIk6xjgQ-4_3 bicycle +eomNxgG_ivE_1 umbrella +eomNxgG_ivE_2 umbrella +eomNxgG_ivE_3 umbrella +er7oQRfciJ8_1 person +euESct6MMNg_0 person +euU-dtl6yyA_0 person +evyGgkwoEpU_1 horse +ex_t3nR28rg_0 bird +ex_t3nR28rg_1 bird +ex_t3nR28rg_2 bird +ezrZuVfbOPs_0 person +ezyFfdIkCCQ_0 cow +ez5RcUDpMoI_0 bear +ez5RcUDpMoI_4 bear +e0cc8KmRgDE_0 person +e0cc8KmRgDE_1 person +e1VJlGQGYTA_0 umbrella +e37RxtyP9nk_2 person +e37RxtyP9nk_1 person +e5Q4wIVJR40_0 person +e5a3Z_wlpUU_0 person +e6FwS_DOE-U_1 horse +e6FwS_DOE-U_0 horse +e6xVrcpMa9Y_0 cat +e8Bc9zwTFnE_0 person +e9G1bOd8GlA_0 car +e9QeTOo4XBE_0 person +fBYtizIh0wc_0 cow +fCVsRanBID8_0 person +fDWKYttA3fM_1 umbrella +fEA-xCaKqfI_0 train +fEWxV64teMY_0 dog +fEpH1AFdSqs_0 person +fFGF5gVW6UU_2 bicycle +fFGF5gVW6UU_0 bicycle +fFGF5gVW6UU_1 bicycle +fFIVNddMFuc_0 person +fFT1LpdsEhQ_1 cow +fFmghP5NQVA_1 horse +fFw23dFiBDs_0 person +fGJKT5ttUQw_0 person +fHFCYOUh3vU_0 truck +fJJuwfeoaWI_0 cat +fJnC2nKYQVQ_0 motorcycle +fMl60_fkMfc_0 knife +fMu0OmctSTI_1 airplane +fNTptXtpsoo_0 cow +fOyaDea7Al4_0 person +fPA_KgXi5v8_0 bird +fPA_KgXi5v8_2 bird +fP7EpJzJt0A_0 horse +fQRAi5pN1Fg_0 bicycle +fQRAi5pN1Fg_1 bicycle +fRB4jD1Uecw_0 person +fRSu9-lyuaU_0 truck +fRoEX_9tHtM_0 person +fSB_aY8HhJI_0 person +fSFjxB1XU2E_0 person +fTd-8VbsXus_1 airplane +fUNAhHKf_OA_0 cow +fUva5AKNiPE_0 person +fUva5AKNiPE_1 person +fU8NxbaMKu0_0 bus +fWD8TEXWtek_0 bear +fYBeigFqN7Q_0 train +fYBeigFqN7Q_1 train +fYWFh5BSEyg_1 cow +fYup3iPmtHc_0 person +fbAOGfYPur0_0 person +fcFwbcMNdUo_0 bird +fcFwbcMNdUo_1 bird +fdMa18fwj14_0 person +fdQFJz9IOso_0 umbrella +fd73v3-Qjqk_0 knife +feMxoQY38A8_0 person +feMxoQY38A8_1 person +feNEI7bD5HI_0 bus +feO8Ip4MOn4_0 cat +ffQKiGKTDaA_0 bird +ffr6_q8liAc_0 person +ffr6_q8liAc_1 horse +fhVVVY5XhDI_1 knife +fhWE0XDoxjM_0 airplane +fh9tibERtYI_0 person +fiKs6mdtsmM_0 cow +fiVKh-Q-iY0_0 motorcycle +fkGWb9_HVsA_0 elephant +fk85Ace_-LM_0 dog +fmE9seWSDfs_0 umbrella +fmosIu7__Wc_1 person +fmrqs2YvNCQ_0 person +fm4syrPib5M_0 person +fnKNDlQq-JY_0 person +foWPkPNDqyU_0 bird +foWPkPNDqyU_1 bird +fojim3ViD7Y_0 person +fpI0N9Lv5V8_0 horse +fpv4fALQXpQ_0 person +fqWa-DUPAGw_0 person +G8IUU0gjlEI_3 boat +G88QbXTQ6LI_0 skateboard +G9Sdd3czaTk_0 dog +G-kF2D98oms_1 elephant +G-2yXvawYec_0 person +G-5iXA4ERtM_0 train +G__uy4I0Kzw_0 person +HAOmPeNNjNc_0 bus +HBUeO1WOFFk_0 motorcycle +HBbWtsju37w_0 boat +HBw-J_3WlCY_0 cat +HF8ZrMgnyo8_0 dog +HJYmTdBHVvU_1 elephant +HJYmTdBHVvU_2 elephant +HJ08tJU-IIA_0 dog +HKNkm0t39B4_0 cow +HKRKZksEGro_0 person +HMfFCe-og9A_1 bus +HMt7kgP0MC0_0 person +HM8XKdebDvI_0 boat +HNBF7AppAQQ_0 dog +HNheLARZ64w_0 bicycle +HNheLARZ64w_2 bicycle +HN-3LaZVuCs_0 car +HONOO3gmDec_1 person +HP6UlpPulc8_0 bicycle +HQ3nHqG24O0_1 cow +HRF40e3Tbvw_0 bicycle +HRF40e3Tbvw_2 bicycle +HRRhkyr7U5E_2 train +HRcVM9md3Xg_0 cow +HTrUPWOXlvI_1 person +HTrUPWOXlvI_0 person +HULLjmpSRUI_0 cow +HUssZ9c2Qvs_0 truck +HW8Z7IdfuIg_0 person +HYCFQjnuXBI_0 truck +HY4XBjJWJYg_0 truck +HY9NQ2zNtGc_0 cat +HZVvEd_Tg_g_0 person +HZngEEoQWDA_0 person +HaMmo5SdpUo_0 person +HaVnQ_P5HdQ_0 train +HacYwonTy6w_1 skateboard +HbWinZWeK2U_1 dog +HbhmAMorGaw_0 person +HeOWa0NNB0g_0 person +Hg0fRYqZQ3U_0 person +Hi384VDSwXw_1 bird +Hjo95Vo38qU_0 person +Hksncw-BlKU_0 giraffe +HlWb7xQHFKI_0 dog +HmH4hitBoc4_0 person +HoSTe-9VUJA_0 cow +HpdyNV4GqbM_0 person +HpdyNV4GqbM_1 person +HsGPGwN7vSk_0 person +Hugie4Q6leo_0 bicycle +HvKC4fLwUYw_1 person +HvKC4fLwUYw_0 person +HvOisoEmjKg_1 airplane +HvU4Jz4Gd1k_0 cow +Hv_d6KPoSgA_0 skateboard +HwZUDp7yxxk_0 person +HxPskaUPSXg_0 cow +HyHQRrpWhpk_0 boat +HylH7-rD0wA_0 bird +HzEm2GlGzhc_1 truck +HzTD_opfrqI_0 car +H0QTCKxJmLY_1 train +H1Oxjm0NqCg_0 person +H2GwgpAKbzY_0 dog +H3HrWs1HITE_0 cow +H3S_DkPBWtw_0 elephant +H3S_DkPBWtw_7 elephant +H3S_DkPBWtw_1 elephant +H3S_DkPBWtw_2 elephant +H3S_DkPBWtw_3 elephant +H3S_DkPBWtw_4 elephant +H3S_DkPBWtw_5 elephant +H3S_DkPBWtw_6 elephant +H3XF5rAtuJA_2 person +H3XF5rAtuJA_0 person +H3a-C6RRYyo_0 person +H5mmSHRHeOA_0 person +H6TuJxifX64_0 train +H6w4nf5H4U4_0 bird +H6y9C6Ndy2A_0 bird +H6y9C6Ndy2A_1 bird +H7XZ5716KnI_0 person +H7z05uOIPRM_1 train +H92s5sHsotk_0 airplane +H-4EZAh3ZiE_0 bus +IA1FFP5WN-4_0 bear +IA1FFP5WN-4_2 bear +ICj693xC5DY_2 airplane +ICj693xC5DY_0 airplane +ICj693xC5DY_1 airplane +ICxHfkE0XCo_0 person +IDx8_34ETTQ_0 person +IEyymbAxp24_0 dog +IFS0QSfnbaM_4 knife +IFS3ILjlHkY_2 truck +IF_auR-0fxM_0 knife +IGv9j-RQi0k_0 dog +IG0UmL5bvEo_0 cat +IHFF7DOpF4Q_0 motorcycle +IHmYV5ymU08_0 cow +IKEUMXjIyTQ_0 car +ILZvGBKYYrE_4 bus +ILZvGBKYYrE_0 bus +ILZvGBKYYrE_1 bus +ILZvGBKYYrE_3 bus +IMTbwAOJNIc_1 train +IMh4AHUZ2HQ_0 person +IM4EBlgTTOg_0 bus +INlrdk7hgl4_0 knife +IOQt3fFTSVc_0 horse +IO7-lFsWvl0_0 bicycle +IO7-lFsWvl0_2 bicycle +IPEJs-vLCV4_0 truck +IPEJs-vLCV4_1 truck +IRpgjSP4pLI_0 person +IUJGm3Iu0Bs_1 bicycle +IUgsoj74aWQ_0 person +IVlnjlVA5rc_1 bicycle +IXP1ML1tdZQ_0 bus +IXRxjnkOJeo_1 motorcycle +IXenlPUsqrc_0 person +IZvOv7tCr00_1 train +IcRjjKSX5uc_1 person +IcRjjKSX5uc_0 person +Icnle27cmMM_0 bicycle +IdVZJW1HC9E_0 airplane +IdVkEz2IF7w_0 car +Ieb9oZ9eB8I_0 dog +IfWSlkR8DbU_0 horse +If1zPOV0idg_0 horse +If1zPOV0idg_1 horse +Ih2gG0269H8_0 bus +IjQXXK4uYVY_0 dog +IlMHPX2VcGw_0 elephant +IluTkrIqsVg_1 elephant +IluTkrIqsVg_3 elephant +IluTkrIqsVg_6 elephant +Io7bj1jNpPU_0 car +IpjQJZ42zyQ_0 elephant +IpjQJZ42zyQ_1 elephant +IpjQJZ42zyQ_2 elephant +IpjQJZ42zyQ_3 elephant +IpwI5VTWHLc_0 horse +IpwI5VTWHLc_2 horse +Iqy4PPX-Tlc_0 person +IsHTpd2cnvI_0 train +Ithz7KSWCxU_0 bus +IudK7ch_IIg_1 airplane +IvRDw_IA0_s_0 cow +Iwve-3lTmMk_0 person +IyLshk4jlyo_0 cat +IygCvE4_amo_2 bird +IygCvE4_amo_3 bird +IyjFl1Hhk3Q_0 person +Iz4XK2zNDUU_0 person +I1wuUCQbXLc_0 umbrella +I2DkTg8wPnI_0 person +I2WoCDTXONA_0 person +I2WoCDTXONA_1 person +I2lh579NY2s_0 bird +I45pfwCBczo_0 person +I6ESaCg4z_8_0 person +I6TvXxQTtZQ_1 horse +I6TvXxQTtZQ_0 horse +I6TvXxQTtZQ_2 horse +I8OfOokt6YU_0 person +I8XhyDacLtU_1 bird +I8m0QjcQlSo_3 bicycle +I8m0QjcQlSo_4 bicycle +I9ivT_P5G18_0 person +I_k5qXHxb0Y_2 knife +I_k5qXHxb0Y_0 knife +JBkwLPruJe0_0 person +JBlDwXJFbQc_1 umbrella +JDZiLsus2es_1 skateboard +JDvfPX9cFDg_0 dog +JEpTSJRO3co_0 person +JG2tVzjxhao_0 bird +fsAEg5w8xTg_0 person +fsCwAYYI4js_0 person +fsKTO8ksQ90_0 person +ftMQOwvHDF8_1 car +ftns38_MSTM_0 cow +fvxc7ruCiYk_0 cow +fvxc7ruCiYk_3 cow +fv8aFklHmko_0 skateboard +fwEvL-luHlw_0 airplane +fwEvL-luHlw_1 airplane +fwt8LzF8Mic_0 person +fyZImQFj_Y8_0 cow +fycK7kJWV1I_0 umbrella +fzr3kw3BDDo_1 airplane +fz6ONSUlvNY_0 person +f0i5E4DOFc8_0 bus +f2SctRCBZQc_0 car +f3Z5d9I7rIw_0 knife +f4fxmsxPzrg_2 elephant +f5LEkr56Efg_0 person +f5Uz-TuMQ0Y_0 horse +f5ZpGBYuJ7o_0 boat +f5kAHBPObsw_1 cow +f6fZjMRJgoM_0 horse +f63aow5BRAI_5 bus +f65rTlprptk_0 horse +f7yNS6ltUFk_0 person +f8H7Ns8cw-c_1 train +f8rXEKktSCg_0 elephant +f_VqZJyJ4GM_0 motorcycle +gAHcWn06srk_0 person +gB0-eGpMj50_0 person +gB2asNpe3zY_0 person +gB7jSQgkcMM_1 horse +gCDC8R7IB7k_0 person +gCwe-o1nqBc_0 motorcycle +gCwe-o1nqBc_1 motorcycle +gC9z8IzG83s_2 bicycle +gDEk1TWuZug_2 person +gDG5Xr2p2y8_0 elephant +gDHnBnqogX0_1 airplane +gDHnBnqogX0_0 airplane +gDbZj1O36VU_0 airplane +gDihz5aZLyA_0 bus +gDihz5aZLyA_2 bus +gEkiX2yFQm0_0 cat +gEnLlmMhxfE_0 person +gGNmKI2M8i4_0 person +gGd6hYCKdEs_0 bird +gHMCfvdZzMM_1 person +gHYzGPx8f_4_0 zebra +gHYzGPx8f_4_1 zebra +gIx12Q8A3p8_1 person +gJwtAwSqEow_0 train +gKAPbj9esXI_0 skateboard +gLqb3YuVttM_0 umbrella +gMRigFNGMeY_0 person +gNfQargrILo_1 car +gOFgWsujZaI_0 cat +gOWc7VBEwMo_0 car +gPEMf91dil8_1 horse +gPSB23kv5Uc_0 person +gPhL52Mj1_A_1 motorcycle +gQ1qmNZzaTo_0 boat +gRDFlfzM_iI_4 elephant +gRDFlfzM_iI_6 elephant +gRDFlfzM_iI_1 elephant +gRDFlfzM_iI_3 elephant +gRMJhsEuiAc_0 motorcycle +gRMJhsEuiAc_1 motorcycle +gRMJhsEuiAc_6 motorcycle +gR29_U82QeE_1 horse +gSJbrV0vy8M_0 person +gSz16yrF9yA_0 person +gT0yjYUmf90_0 cow +gUGlSiBvfOs_1 motorcycle +gU8s5nxyBDk_0 airplane +gU8s5nxyBDk_1 airplane +gV3CcNeVZcY_0 elephant +gV3CcNeVZcY_1 elephant +gWkTSRUqxoo_0 person +gW6HdCsty0U_0 knife +gYLohMps12s_0 elephant +gYLohMps12s_3 elephant +gYLohMps12s_4 elephant +gYLohMps12s_1 elephant +gYLohMps12s_2 elephant +gaKGYmLxJVU_3 bicycle +gagJEV--3Pw_0 person +gdAVi92ZfSc_0 horse +gdx96NpU6BY_6 train +gd4UfPes3YI_0 cow +geEXytMwfq0_0 person +gePAI8wYSdw_0 person +gfTVuceAzNs_0 elephant +gg8YzsSulrQ_0 truck +ghciPMerSc0_0 truck +giWDg00GIDw_1 skateboard +gig9B4ecK3w_0 person +giy_SOmkBY8_0 umbrella +gjnyg97XwnA_0 person +gk-cycr3xjo_0 person +gmVDmxVI7n0_0 elephant +gpV4Qlx6YrA_6 bus +gqLSqmK3m74_0 motorcycle +gqZYY0m_TuM_0 motorcycle +gsrvWcnpNP4_1 motorcycle +gsrvWcnpNP4_0 motorcycle +gtVr7urU8c8_0 person +guDQk0hVgU0_0 bird +guFTeFvjr9Y_0 bird +gu3DTnVjNQM_0 knife +gwXwH2Cs3BY_0 knife +gxHGnBrpPZs_1 airplane +gxHGnBrpPZs_2 airplane +gxKuLTUNhp4_0 horse +gx7PFNpHd_A_0 person +gyaP7qiRxfY_0 cow +g1OZWFLSspQ_0 motorcycle +g1rQZNA6yyo_6 cow +g1rQZNA6yyo_0 cow +g1rQZNA6yyo_1 cow +g1rQZNA6yyo_2 cow +g1rQZNA6yyo_3 cow +g1rQZNA6yyo_4 cow +g1rQZNA6yyo_5 cow +g3HXJNMlAsM_0 airplane +g3oqxu4AhBw_0 person +g3swsx-acTI_1 dog +g3swsx-acTI_0 dog +g3vbaqnLXn8_0 cow +g4bayrAEhIU_0 umbrella +g5rUJOptHXQ_0 horse +g5ty_7So5Dw_0 cow +g51pzrSssl4_0 person +g8M5d--ghFM_0 person +g8vKB3IU1JY_0 horse +g8wHQVpij-I_0 person +g9eN0FHn4-E_0 dog +g-EAZ6gVcic_0 motorcycle +g-pVcRyPQG8_0 cow +g-yHAyCA2KI_1 horse +g_C47ek7TmI_1 knife +g_C47ek7TmI_4 knife +g_C47ek7TmI_5 knife +g_QHWoQgmFQ_0 person +g_QHWoQgmFQ_1 person +g_Tk-SESaYI_0 person +hBHt6mnfUeo_0 bus +hBMZHx3_cTs_0 train +hC69bGTvLBo_0 skateboard +hD3Bn03GXNQ_1 dog +hFNAxcRpGBM_0 skateboard +hFSygfNIY_Y_0 skateboard +hFex_TS-aUo_0 person +hGnscWmehTI_0 car +hG9efPyerw4_1 horse +hHdBCtElIQg_0 boat +hHlqyr11RiI_0 person +hIWM6v4zcSM_0 elephant +hKoGkl1wyCU_0 person +hON0t9Dzay4_0 motorcycle +hP1ViN_WadY_0 cow +hR-utsUhYSg_0 person +hSAUbt6-Yjc_0 knife +hSAUbt6-Yjc_1 knife +hSeHymINF98_1 bus +hTaEY4YCVqM_0 airplane +hUjzfhyM30Q_0 airplane +hUjzfhyM30Q_4 airplane +hUxguQsLvcs_4 knife +hUxguQsLvcs_5 knife +hUyAVmRxAzM_0 person +hU_dAA1A0X0_0 person +hU_9cs_qw1w_0 person +hVjyHhYH6Ss_1 airplane +hVjyHhYH6Ss_2 airplane +hVowH5-Ss4I_0 train +hV4tEsm-F5s_0 airplane +hZdxBk4cjmg_0 bus +haiW7jpl3wY_0 person +hcJBaxNIvE4_1 person +hcJBaxNIvE4_0 person +hcV4RZPeRbo_0 airplane +hcuLD1cn9GA_0 person +hdUc4uUYh0E_0 boat +hfWfYFG2O94_0 person +hgagtwzScGQ_0 person +hhFOwnYOLl0_0 giraffe +hhLyE41H8nE_0 motorcycle +hhNlg3Ws9Dc_0 person +hhyVc2wsXVk_0 horse +hhyVc2wsXVk_1 horse +hh432zDMgPo_0 train +hiKbm0rqEb4_3 skateboard +hiN_kULL84o_5 umbrella +hiN_kULL84o_4 umbrella +hkEV_E85Jzw_0 car +hkSv_YxmN7w_0 person +hlZDJrpJzPU_0 person +hljwk2WbXGY_0 person +hmSeUlyLLak_0 train +hnZvUHrA3CY_0 person +ho6sg-47RD0_0 airplane +hqNhKf3a69Q_2 truck +hqYyvTeOvas_0 bear +hqaNlwG0DNU_1 person +hqrmbVw_EwQ_0 cat +JIuyqZCU5zY_0 cow +JKiG_pk4lSE_0 person +JKmvEldBeEQ_0 cow +JKsodtdUW-o_0 boat +JMLFZcONQAs_2 skateboard +JMLFZcONQAs_5 skateboard +JMMci7hryUQ_0 motorcycle +JMMci7hryUQ_1 motorcycle +JMMci7hryUQ_2 motorcycle +JNUhCGqPlFg_0 bicycle +JPHPd13gaL8_0 car +JQrDalAaP4w_0 person +JQrDalAaP4w_1 person +JQz6IarIr4E_1 person +JRAVv2LgiGo_0 skateboard +JRUvqZtBMrM_1 knife +JR0QfXOOmaA_0 person +JSml3dguiUk_0 motorcycle +JTFT_iJGFUE_0 person +JUdUxjC2LRE_0 bus +JWU6vdEt_OU_0 person +JWgjcmMh62o_0 train +JWgjcmMh62o_3 train +JW0-hEA4v9A_0 person +JXIh3fJ4Jv0_0 person +JX8ODdMUi7g_0 bird +JZC15tOV-eg_0 horse +JZMOzYwcTA0_0 person +JasH0KtinHY_0 airplane +JasH0KtinHY_3 airplane +Ja5jdE_8qio_0 person +JbyTZ-esDXM_0 truck +JbyTZ-esDXM_1 truck +Jb93SMKg5-k_0 person +JcVOyLTTvKA_0 person +Jc18AfXzLZU_0 person +Jc18AfXzLZU_1 person +Jd7uOTcPvY8_1 car +JeWRfjjRMQk_0 person +JerVzlWZwac_0 bus +Je-lnjK_8fk_0 person +JfjkltN0lZc_2 horse +JfobA6aKaas_0 dog +JftQEHHdO5w_0 truck +JgaE8KDwg7k_1 bird +JgaE8KDwg7k_2 bird +Jgc2PQ8Swbo_0 cow +Jgkj9pj3-tc_1 horse +JhdyYrqxn_g_0 motorcycle +Jh7o2iR-lRg_0 person +JijsSnHthXE_0 train +Jio_xBodQxY_0 person +JjQ8bdq_eXk_0 person +JjtkwX4npyw_0 person +JlG7Wzz4uU8_0 car +JlG7Wzz4uU8_2 car +JmkUuTj-Nks_0 umbrella +JmtuhGXlqmY_1 airplane +JnNJksYeB18_0 car +JoKod4XDE6o_3 bird +JoKod4XDE6o_0 bird +JoKod4XDE6o_2 bird +Jp6_g7oF2lQ_0 cow +JqEprl56N4I_0 skateboard +JrIoaRmcs6o_0 cow +JrNq6Z5YSoc_0 person +JrUHo8zVwpo_0 bus +Jsjz8hiE_iU_0 person +Jt7Ojtx0TMs_1 car +Jt7Ojtx0TMs_3 car +JwBYrXUHdZ8_1 horse +JxTKws5Dx_8_0 cat +JxjXZYfiem4_0 dog +Jx9mLWFxpnc_0 dog +JyYBZBogBvs_1 boat +JyduNnkZOiY_0 person +JyrP5u2MuSo_0 motorcycle +Jzcc0pjgA5c_0 person +JzjRC1xYwy8_0 dog +J02u46SlewE_0 person +J1GtEDNcsHQ_1 horse +J2JOoOxaJdw_0 person +J2bB5BgR-5Q_0 bus +J2hdK_vuyyw_0 motorcycle +J2ycUTr0lJQ_0 cat +J4T_QA6J7kw_0 boat +J4T_QA6J7kw_1 boat +J4T_QA6J7kw_2 boat +J40neYxbEYA_0 skateboard +J5-Z9tNISPw_0 car +J6klPNMhLKc_0 cow +J7I-QXddTIk_0 person +J7hnNI0jtws_0 person +J8ITxacusCI_1 person +J8ITxacusCI_0 person +J9-8Qe3BWoI_0 bicycle +KARqX_agLpU_0 knife +KAgU6SrQTlQ_0 umbrella +KAgU6SrQTlQ_1 umbrella +KArVkjxSGpM_0 person +KBCIbwknDew_1 bicycle +KCeuwWEv3ZU_0 person +KCi4f4Hp6oA_0 airplane +KC5ECqMiTLU_0 skateboard +KD84e88aqHU_0 person +KD84e88aqHU_1 person +KEpHRYH8r28_0 giraffe +KGdIJzBVugY_0 truck +KHqFOBeHCwU_0 boat +KIOilXstQLY_0 person +KIOilXstQLY_1 person +KJ2kEj3C5HU_0 airplane +KKWUDcCI6yU_0 cat +KML2msVr5mE_2 elephant +KMNAnjpGqv4_2 truck +KNIVWRv3awA_0 truck +KOmUta2sIgk_0 person +KOsm1GUs46s_0 motorcycle +KOza4PGcE0M_1 bear +KPLDdfk8hIg_0 train +KPLDdfk8hIg_1 train +KP7RzxyTTAU_1 airplane +KRKxqkfpetI_0 person +KRNWPLnvZz4_0 person +KR7Ah1hw5gA_0 person +KS8S3STq2W4_0 bird +KS8S3STq2W4_1 bird +KTkhMglNlCE_0 person +KTpwnsz498Q_4 horse +KTpwnsz498Q_6 horse +KWYD2iyUmgk_0 horse +KXIJLUzQi5Q_0 person +KXMlBQiVeEg_0 train +KXPGShfFlU8_0 person +KX9MjIikBU8_3 bicycle +KYc-vKtN0DI_0 person +KY4mXNDM8I0_6 elephant +KZdOpoUJ3Nk_0 person +Kcg7gY3WD7M_0 person +Kcg7gY3WD7M_1 person +KeJWqAV0EgA_4 umbrella +KeJWqAV0EgA_6 umbrella +KedkADy9tBc_2 knife +KedkADy9tBc_4 knife +KgDguip9mZM_1 horse +KgDguip9mZM_2 horse +Kg0XH4mez1A_0 cow +Kho8jpdZzTs_0 skateboard +Kjd7D98QULc_0 airplane +KkdLE8EkzQ8_0 cat +Kkw7ZPCEz5w_0 person +Kk-2ajLfeh8_0 cat +Kk_LtYOgQXA_0 boat +KmLYFD7xykY_1 car +Kmwqg1uRPRE_0 person +KnQuff1ffzM_0 skateboard +KoRqIzHBQks_0 train +Koq5YYiN1tc_0 train +KpHpGcL_jEc_4 bird +KpHpGcL_jEc_3 bird +KpfTioA2qKw_4 elephant +KpfTioA2qKw_5 elephant +KpfTioA2qKw_0 elephant +KpfTioA2qKw_1 elephant +KpfTioA2qKw_2 elephant +KpfTioA2qKw_3 elephant +KppX5i4QRZ0_0 umbrella +KqsBJAhU_Dc_0 cat +KrRVwTPG26w_3 dog +KsE43Lli_3U_2 horse +KsE43Lli_3U_3 horse +KskL-dN784o_0 airplane +KtfQRtfJQ8s_2 skateboard +KxDh7a8_AmU_0 person +Ky4ahEexJUc_0 airplane +KzDLvBPcQew_2 knife +KzMFSHS4xVs_0 bird +KzOxVUsduDY_3 knife +Kzt2eSUr1rY_0 dog +K0IvSLIQbgQ_0 bird +K0SktTNMXQU_0 motorcycle +K2WsSTHs45g_1 elephant +K2WsSTHs45g_3 elephant +K2oIvJd-d-A_0 person +K4IN8pNA--U_1 person +K5C2Y3JvXCU_0 skateboard +K7TOmJ6RB_8_0 skateboard +K89ScUqJx5E_0 person +K8_u8_NkoAk_1 train +K9L-BYQcepo_0 bear +K9pgB6KH-EY_0 cow +K-laAofNBgs_0 horse +K-xigT3f2VA_0 horse +K-0pug6xNEI_3 train +huFyV9NBOBY_0 person +hua1XfGRDoc_0 horse +hulGMGXPaBE_1 elephant +hvXgMKsetW8_0 elephant +hxBjbg6s174_0 person +hyNwXcKelY0_1 train +hyNwXcKelY0_0 train +hzUpr73wZz0_0 airplane +h0jkFTI3qmI_1 horse +h1Hv9HnMe70_0 car +h1zuISckIeI_0 bus +h10iwpJO4pQ_0 train +h2vHhQ7_MT4_0 skateboard +h3Fo82UBMRY_0 dog +h3IHNdoTXT0_0 person +h3PBWibdVUc_0 train +h3RgUc0oY-c_1 knife +h3RgUc0oY-c_2 knife +h3t75PNg778_0 person +h3uSlke3koc_0 motorcycle +h4qpt2FEbC0_1 elephant +h5JnAInpuSo_0 motorcycle +h5JnAInpuSo_1 motorcycle +h7_4qHh7Vas_1 truck +h8TnGCoSVeQ_0 airplane +h8fKxUGKz8k_0 motorcycle +h8fKxUGKz8k_1 motorcycle +h-pm7wD31Ss_3 train +h-pm7wD31Ss_0 train +h-pm7wD31Ss_1 train +h-pm7wD31Ss_2 train +h_VG9OpleKc_0 motorcycle +h_VG9OpleKc_1 motorcycle +iAZV9nCf3RE_0 motorcycle +iA7evYzMygE_2 knife +iDBpYSvahjE_0 person +iDHjOnhAKA8_1 skateboard +iE75sptNwbs_1 truck +iE75sptNwbs_2 truck +iFVwtlc6IYE_0 horse +iFdOAHM4xDg_0 person +iFwPDZE4778_0 skateboard +iG4PvtWoxG8_3 cow +iH6Vlg0k330_3 dog +iH6Vlg0k330_5 dog +iH6Vlg0k330_6 dog +iIWFuFa7Z4M_2 person +iIWFuFa7Z4M_0 person +iIWFuFa7Z4M_1 person +iIzXR3qRt48_0 person +iI08dGJAOMs_4 elephant +iI08dGJAOMs_3 elephant +iJcf4PhS_SQ_0 person +iKzpo0D7b_8_0 cat +iK-7fByPADo_0 person +iMdJ5Xlz0hU_0 knife +iMeNXU67sVg_1 skateboard +iNiiX6P-kqA_1 dog +iOxVi3Tq4ts_0 train +iPlXCYJ6F7w_0 skateboard +iQ-tckw9_uk_0 truck +iRzm-CyyW-E_0 person +iSNNmpWe3LA_0 person +iS7wej_vrvM_0 person +iVBDQ5wm-0w_4 airplane +iVTAxc633DE_0 person +iXrLhQgf8HM_0 elephant +iXrLhQgf8HM_1 elephant +iX4gVag7ShI_0 person +iYL_l0MxgMY_0 bird +iYlgi1z6nYI_0 truck +iavLgJ3_05c_3 horse +icVQnqL0xPI_2 boat +idkGZQeYvJ0_0 skateboard +igbftnGj4-o_0 bicycle +igg-y1toBvA_0 truck +ihkqhIpO_hw_0 person +ijbDg16cIC8_1 bus +ik4t0sIEmTI_0 person +iltKgr5JKI0_0 person +il5UMLzlQts_0 bus +imDfH3So8XU_0 car +imDfH3So8XU_1 car +im4bCIqpJns_1 bicycle +im4bCIqpJns_2 bicycle +im4bCIqpJns_0 bicycle +ip1Y5qjDYfQ_0 airplane +ip_oGEZ6zMw_1 person +irvGAW8bqAw_2 bus +isbtQ06yVM8_0 truck +itNqceL9dLM_0 cow +iuii5XHcAYA_1 dog +iulQVUJanzg_0 skateboard +ivGBks6evlo_2 dog +ivSQWqs_u1I_0 bear +ivpPLs-cqxA_0 car +iwHJDgGVuCA_0 airplane +iwHJDgGVuCA_1 airplane +iw7zrlRPMo4_2 horse +ixgGTHdobNI_0 person +iyDedQNhiYI_0 cat +iyaI71EqLsg_0 person +izHN9JUwtJ8_0 boat +izQ74nq9zh4_0 cow +i0QLe6YR7yo_0 person +i1OlP2Sq0a0_2 truck +i1xqjStfSsc_0 person +i2SgjtgmsE0_0 person +i5DfO7_n0q8_0 cow +i5GkqX44npg_0 car +i5JWZKdNOac_0 motorcycle +i5JWZKdNOac_1 motorcycle +i6mzD2HGWOA_0 airplane +i6sR2IY4-Ck_0 cow +i8JA178zd0s_0 cow +i8Z9-KSMCTA_0 bicycle +i8syjc7Erco_0 motorcycle +i-EijejS9Oc_0 person +i-eCNLw3hVU_0 bird +i_l48nIXjxw_0 horse +jBYa-gqwSeY_1 cow +jCiTA9oIryk_0 elephant +jCuDdMn9sYA_0 person +jDGrgBt83DU_7 car +jD33e45nuRw_0 bear +jD5K1zGLtvc_0 skateboard +jEE_ZlDJ4cc_0 cow +jEzxW8ylxK8_5 airplane +jEzxW8ylxK8_1 airplane +jEz3EToUAg8_0 person +jGCLsWhdTds_0 umbrella +jHhJLxyr960_0 bicycle +jIqTFAgBLpc_0 dog +jJkZrKOehcQ_0 person +jKD0oOyMl2g_0 person +jLO5kFd36OY_0 bird +jMLgjCQWQY0_0 person +jMmH8xfY1kw_0 cow +jMyxNu6YkEQ_4 boat +jN5jdXmBv2Y_0 bird +jN5jdXmBv2Y_1 bird +jN5jdXmBv2Y_2 bird +jN5jdXmBv2Y_4 bird +jN5jdXmBv2Y_6 bird +jPouarzO-e4_0 cat +jQPz-9OfXRM_0 zebra +jRQuCIsXz1c_0 airplane +jRUeQo3V1bk_0 person +jR366TYYsuo_0 person +jSkwPkAAiFM_0 person +jTNzSUl_zOQ_2 elephant +jUzhGHE_jgE_0 person +jVYzDs5YRM4_0 cat +jVoxxEKEOFo_0 motorcycle +jX_taNw8FFg_0 skateboard +jY4Dh-UAAaY_8 skateboard +jZBMDKFS5D0_0 person +jbp8mHJfHGI_0 person +jcYNP_FWkA0_0 person +jcne18p2r2c_0 cat +jdttJqwg_3o_0 motorcycle +jfSY_UCtq-w_0 motorcycle +jfTXT98Naic_0 cow +jgQiUggCu7A_0 cow +jjTgUBAd4D0_0 cow +jjq2PAHcLiA_1 person +jjq2PAHcLiA_0 person +jlBGbg_CJz0_5 train +jlBGbg_CJz0_6 train +jlOOUqYlNNY_0 motorcycle +jlgECDznb0g_0 bear +jl7oYVm0X34_0 bird +jnU2n55I_LU_0 dog +jouq30Wmqxg_0 motorcycle +jouq30Wmqxg_2 motorcycle +jo6o9BwKsUQ_1 elephant +jqPPsrUULY8_0 horse +jtWUSSp-JiY_0 truck +juS7DvjMPoo_0 person +LCzQs5ybibU_0 horse +LDwE_VIc9Zc_0 cow +LEL3OcoqV8k_1 knife +LEPsxGhXYxY_2 truck +LEPsxGhXYxY_3 truck +LEXpJRLTRak_1 bear +LFWlRG2B-w0_0 bus +LFWlRG2B-w0_2 bus +LFWlRG2B-w0_3 bus +LGvjU4PVcC0_0 boat +LGvjU4PVcC0_1 boat +LGvjU4PVcC0_2 boat +LIC3D63R3HU_0 person +LIhhU9j6MI4_1 cow +LLD46pbwbiU_0 person +LLiy-k-4-OM_0 train +LLvpoIlozKU_0 horse +LLvpoIlozKU_1 horse +LO0IsJZeXhU_0 elephant +LO0IsJZeXhU_1 elephant +LPzXMvYB97A_0 person +LTh-XAE8m3M_2 train +LURSawdSS9k_0 dog +LUsb9vk1q6U_0 knife +LU539OYJ_z8_0 person +LXHO99b-uAQ_0 horse +LXHO99b-uAQ_5 horse +LX0HL9qztic_1 umbrella +LYPeAbFVTQw_0 person +LZCq31MG3yY_0 person +LZEMKs6H53w_0 person +LZNlxXE0_2s_1 skateboard +LZNlxXE0_2s_2 skateboard +LZNlxXE0_2s_3 skateboard +LZ3S39QfkKA_3 bicycle +LbHrVQR9f24_0 cow +LcvMMvrPIug_1 cow +LdNi4yjT3yE_0 person +LdusiqJFR6I_0 person +LesCJsHdAU0_0 cat +Le2725PKYQk_0 dog +LfUSKsg8JoQ_0 cat +LfhPiqIDAcI_0 person +LgbwFATbwhs_0 cat +LhF7TJOwt8o_0 motorcycle +LhOMGvkzP28_0 person +LhOMGvkzP28_1 person +LhkFN7f676g_0 airplane +Lh1QrEwtBxU_0 skateboard +LiS31CevvvA_0 person +LiS31CevvvA_1 person +LjRWmJThZrA_0 person +LjyZ7Djyq1U_0 person +LkP8lgpmCJc_0 airplane +LkfML7bjGg8_0 person +LmCzQ6WrePM_0 bus +LnYz8cQsrWk_0 cow +LpTBcxby8_U_0 cat +LpT4VBLapqM_0 car +LpjbdSyW__A_1 truck +Lqm0JTDlIaU_0 truck +LtIW9sP55N4_0 person +LuC8ON_75l4_0 person +LuRLF2TroVk_1 airplane +LunFMJp3_Uc_0 cat +Lup2fypzuD4_0 person +LurlbycI8WQ_0 person +Lvd7WBHnDpk_0 truck +Lwxi57QRroE_0 person +LyPkKroSsaU_0 bird +LyPkKroSsaU_2 bird +LyPkKroSsaU_7 bird +Lz7uf7cmfAU_0 horse +L0Y9j9DtU1o_0 dog +L0mqjqU7pmw_0 person +L1C1GJZuI6U_0 horse +L1TihVYcfII_0 bear +L1xr5gaSzeQ_0 bicycle +L2lJenTKrLU_0 truck +L2lJenTKrLU_3 truck +L2lJenTKrLU_5 truck +L22pyXEUjv8_0 bird +L22pyXEUjv8_1 bird +L5px8rMqxRY_0 motorcycle +L8Q0lJgaUi4_0 zebra +L-3-1978GvI_0 knife +L-6R2vuKWhc_1 truck +L--TMS61Zvw_1 boat +L--TMS61Zvw_5 boat +L_dOv3wd1ZM_0 person +L_nI4_2RbTU_0 knife +MAmHLoJdmc8_0 cow +MENNFokPNbU_0 airplane +MG8-IGrKVxc_0 truck +MG8-IGrKVxc_2 truck +MG8-IGrKVxc_3 truck +MG8-IGrKVxc_5 truck +MH1GdFqE_lo_0 horse +MH1GdFqE_lo_2 horse +MH1Kct5RCRg_6 airplane +MH1Kct5RCRg_10 airplane +MIkxezmilfY_0 person +MI6x6FrXJqs_0 knife +MI9BIgkOBjI_0 horse +MJ9vJFTTV5c_0 person +MKiCrBXtflw_0 cat +MK8Jm3I4In4_0 dog +MK8Jm3I4In4_4 dog +MMiSt9MNne8_0 train +MNve0XPgcGA_1 bird +MN1A5E3jNSE_0 horse +MPJu68gBGfI_0 person +MPMudxdiIds_0 train +MPfgu6-snaM_0 bird +MQ1o_7gpp5E_0 person +MQ1u8IEmFSA_0 person +MQ3HhLmsCik_0 person +MRNJmLLkjPc_1 motorcycle +MRNJmLLkjPc_2 motorcycle +MRqfEOhWW48_0 person +MSItPvVCUN8_0 cow +MSd5Ecl5-W0_0 person +MSnEnQ0psW8_0 car +MV6MGXhQwFQ_0 cat +MWbnSN-7WG0_0 cow +MWt4P6HWxMM_0 horse +MXEcQSFwng0_0 cat +MXTzea4MeHc_1 car +MXoVDyewPBE_0 person +MYFPnJIKK5k_0 person +MYpdq9KvK8o_1 umbrella +MasaNQLCMGE_0 person +MbRvEKuvR04_0 skateboard +Mb6r1es0AbU_0 cat +Mcdl3s6oQrc_3 bear +Mcdl3s6oQrc_1 bear +Me-clc6PGkA_2 horse +Me-clc6PGkA_3 horse +MfYpMzLWST8_0 cat +MgFhoihDD1U_0 person +Mkmpoid1BvA_1 train +MokOHR3wImM_0 cat +MqBTk3ITQ8c_5 elephant +MqBTk3ITQ8c_3 elephant +MrWZEUtDBq8_0 dog +MuyIuhdszH0_0 person +MuyIuhdszH0_2 motorcycle +MvKMtFVP5NU_0 person +MvbZEiffy8s_0 person +MvuGj1qR4Ic_0 motorcycle +MvxUj_Du2IY_0 horse +Mw6Cu1mPanU_1 cow +MxtJwd0GBkA_0 airplane +MzTsjMauBH8_0 truck +Mzrv2OCC2GE_1 person +M0TTCr9jjgc_0 horse +M12KvkF1Nec_0 person +M40gbbuNuL4_0 truck +M5p7jyvEgPk_1 knife +M52oDxJEXk4_2 horse +M52oDxJEXk4_0 horse +M7Kcv9fUrhA_0 cow +M9CCnnc8m8k_0 giraffe +NAInb4dMC_E_0 airplane +NAInb4dMC_E_3 airplane +NAsDBYDNhwY_0 cat +NDxs_vxhhME_1 person +ND-VrJY7mU0_0 person +NEsCBcZFajg_2 airplane +NEsCBcZFajg_5 airplane +jvlyXCBSuCk_0 person +jwYviTYbJYs_0 cow +jxL3F-iB2S8_0 bus +jxmsNv20V50_0 train +jyrY4oyyA7M_0 person +jzNOBsi5TtQ_0 cow +jzeFDGEt_iQ_0 person +j4UJ80q_s3c_4 skateboard +j4UJ80q_s3c_5 skateboard +j4t-Otp9ES8_0 person +j6XmNyG8nYE_0 bear +j8SM6uLadmU_0 motorcycle +j8aX3NuEnxc_1 airplane +j8aX3NuEnxc_0 airplane +j93wwDC_a2I_0 skateboard +j_tT90ISNnc_0 skateboard +j_6ZWhyOOcA_0 person +kBKG0SaNbdw_2 cow +kBYFlPJJx-s_0 person +kCHOoDF-pXo_0 cat +kCQIRLEi88s_0 person +kCefZaEK9M4_0 person +kCt3G72NjyY_0 motorcycle +kEx2sgiyKpY_0 dog +kG5vclMyg7w_0 skateboard +kHIZAi1E9gU_0 cow +kH3Hwla_MUM_0 person +kI7523l1Tu4_0 horse +kI7523l1Tu4_1 horse +kLwsGbEsMjs_5 elephant +kLwsGbEsMjs_1 elephant +kL52zPMgsXM_0 truck +kMIRREOoSt0_0 elephant +kOqKBgGRd_c_0 boat +kQu7xcJmp6w_0 airplane +kRLl2HLijWc_0 elephant +kRqsESioKVM_0 person +kSWUU8Ef-Rg_0 cow +kSXkd4PYX9M_0 bear +kSm9E8WwGYY_0 person +kTT6onfYUug_0 bicycle +kZcfsku1oJ4_1 bicycle +karZg0Iifks_0 skateboard +kavU8zKXrEY_0 elephant +kbD6iXQ3P6M_0 cow +kb4GuHpwuSw_1 cow +kdPgKSrjVYQ_0 train +kd9Tn_hyeb4_0 dog +keka7aToy_E_0 person +ke2Ap6Zvq64_0 cow +ke2uXJrB9WQ_1 bird +kfL1KEY53AM_0 person +kfMMMSNZWeM_0 giraffe +kgcb2y-aw8s_1 truck +khicinfB1nY_0 person +khr1-lWZOOw_0 bicycle +kixX1ga8yrw_0 person +ki51QTz_6iw_0 bus +kjhcR5ljaDU_0 car +kksfStf04pc_0 person +kk41Jjw-BpQ_0 horse +klxQpVdft5E_1 bicycle +kmIUPZSNl5A_0 airplane +knFBzlhmDMk_2 skateboard +knFBzlhmDMk_3 skateboard +koomOoaIF0Q_0 motorcycle +ko4el3e0QFI_0 bird +kqE2rNzUnvU_0 cow +kqJJ6_2vGtU_0 motorcycle +kqiHy-EzdcQ_0 airplane +kqiHy-EzdcQ_1 airplane +kqiHy-EzdcQ_2 airplane +krD5WtdljCc_0 bird +krR-lFUTXHo_0 cow +ksbdMzGs-gs_0 person +ksbdMzGs-gs_1 person +ktCRlGt6408_0 train +ktcXRj-Vz6c_0 bus +ktcXRj-Vz6c_1 bus +ktvaX1ALzwE_0 motorcycle +kwMNSTE0h8U_0 bus +kwMNSTE0h8U_1 bus +kwyn-eed9l4_1 bird +kx2jH9V7vYM_0 train +kz0gVW9uWkc_0 skateboard +k1C25MTUso4_0 person +k1Y6Y1yocF0_1 knife +k1qT5GtPmQo_0 bear +k2fCUP9H4cw_0 skateboard +k24lvYKkK5g_0 boat +k3hYFu55iGE_0 person +k3hYFu55iGE_1 person +k3pTU4KNdvE_0 train +k4tqy4pdlNs_0 horse +k5MmpG9afSM_2 bear +k5UoGZZb_RY_0 cat +k5oey7bw5kA_0 person +k5-IPGgeCPc_0 person +k5-IPGgeCPc_1 person +k8OboASs470_0 skateboard +k8OboASs470_1 skateboard +k9COlD7u1tI_0 knife +k-tdE0VAFkc_1 person +k-tdE0VAFkc_0 person +k_E-cIymiis_0 train +lAZQZSK_9bk_0 cat +lCc5-WmCZJk_3 dog +lCc5-WmCZJk_5 dog +lDWAsuKkv5Y_1 bird +lFObiVRO-BQ_3 airplane +lGAGodreVjQ_0 train +lGJB2hhw5pI_0 cat +lIbOGzXhSW8_2 horse +lI-A6pFtkLQ_0 train +lI_jxWxWivM_0 dog +lJXfbIuwTIQ_1 cow +lJccP5OJjZ8_0 train +lKBO-dakd8w_0 train +lLyfm0vbHrw_0 train +lL_4QscWdx4_0 person +lM0yKqnWblw_0 person +lNJbOSFK9N4_1 skateboard +lOFTlhNmKD8_0 bus +lOQf3A_3lPI_0 horse +lOWmL3mpSeA_0 train +lOvB2zlHw8w_0 dog +lO-XTKPQb5I_0 train +lPapZHOAdzk_0 bicycle +lP5lgBlsH0U_4 airplane +lP5lgBlsH0U_1 airplane +lP5lgBlsH0U_2 airplane +lQDy9Mri-18_0 person +lQsTpo0uOIw_1 boat +lQuFC-E7VUM_0 person +lQuzpkDKFQ8_0 person +lRuif4Zc7CI_0 boat +lSZa4pAHgV8_0 horse +lS-5gEkB0_o_0 motorcycle +lTTquh-jLwM_0 car +lThBPb6HI1U_0 cat +lVeIr8AFTjY_0 person +lWT2t48q164_0 motorcycle +lYSpeuL7-oo_0 umbrella +lZOTAg9Fofw_3 bird +lZVwQoLPjBU_0 giraffe +lZVwQoLPjBU_1 giraffe +lahDGDRe7X8_0 horse +lcKDCt1eWqg_1 knife +ldQGB8gzRjA_1 cow +ldhdyBduVoU_1 cow +lf_tYVzrap0_0 person +lge9f_bgAOk_0 person +lgzIpgcvPvU_0 person +lhNv9zDa1ug_0 car +lhadIxHkaVg_1 person +lhadIxHkaVg_0 person +lhnQuOIF-2c_1 person +ljLO1myCfoA_1 knife +ljayNZQpp-I_1 horse +ljayNZQpp-I_5 horse +ljeTwRM6DWE_0 person +lkvdy3Hejpw_0 person +ll6gTyUguMY_0 horse +ll6m5MTpf4o_0 person +lmpKSF0cXSc_0 train +lnfEV2dRfm4_0 motorcycle +ln0_FGR8B08_0 person +loVlMj9Dhkk_0 truck +lotZh71qMks_0 person +lpcqEaZD_Xk_5 bicycle +lpcqEaZD_Xk_0 bicycle +lpcqEaZD_Xk_1 bicycle +lpcqEaZD_Xk_2 bicycle +lpcqEaZD_Xk_3 bicycle +lpcqEaZD_Xk_4 bicycle +lqu4tjd3Zg4_12 bear +NE9AhZPTVFY_0 motorcycle +NFF4UemeH8g_0 truck +NFSj66emNbM_0 cat +NGS9BrtLJ0I_1 boat +NGvpnRrWSKc_1 bear +NHLBjlX2jeg_0 person +NHgh88y4e80_1 car +NHpM-oBMIRk_0 dog +NHrjnZsJWOw_0 person +NID_0E0tn_g_0 cow +NJQNZ36lsvw_2 truck +NJm81cIGO98_0 skateboard +NJ22Hynv9s4_0 umbrella +NJ22Hynv9s4_1 umbrella +NJ7MXR2AaoY_0 cow +NKQfFcfr6Ko_0 person +NL1iy1TKtRI_5 car +NL1iy1TKtRI_1 car +NL1iy1TKtRI_2 car +NL1iy1TKtRI_3 car +NL1iy1TKtRI_4 car +NMCijcIa_XU_2 knife +NMhR_Z4Rq7g_0 person +NNbRF02KnGM_1 skateboard +NQiMeD83sMw_0 truck +NQiMeD83sMw_1 truck +NQsnyZmQoPw_0 elephant +NQsnyZmQoPw_2 elephant +NQve9Yujb14_0 person +NRaAEznVIxQ_0 person +NTGqC7kOGAw_1 bird +NTRX6gLV_04_0 bus +NUSnWbhvmQs_0 cow +NVzCor2-ZpI_1 zebra +NV-p8Vp-bdA_0 horse +NWAQ1is2w98_0 airplane +NYIqB-l8eKk_0 train +NZ5OIYTIoYQ_0 person +NaCksn1bbv4_0 airplane +NaCksn1bbv4_2 airplane +NaEokN7Nh-U_2 knife +NadzcUmXDTk_0 person +NbJ2gM5KJTM_0 cat +NbJ2gM5KJTM_1 cat +NdXmkm9jcPA_1 airplane +Nd6ceCmRYBI_0 bird +NeXVfNsggZw_0 cow +NfEzlo6-i_4_0 train +NfEzlo6-i_4_2 train +NfEzlo6-i_4_3 train +Nhi9730yIzM_0 dog +NhskHQ9bqlo_0 cat +Nhvr0y1tqjk_0 person +NiP4AEjiwxs_1 boat +Nio43-cQPh0_0 train +Ni_TSyCk1Ak_0 cat +NjknyzAAQpM_0 person +NlOjGoYPj9Y_0 truck +NlTLvOcpoEA_0 elephant +NlVEu_8kdoI_0 horse +NlVEu_8kdoI_1 horse +NljV4UjnFJc_0 motorcycle +NnRWY12wxUk_0 person +NnVFfTO9-q8_0 person +No84NOV3Pwk_1 skateboard +NpZj-n9_STU_1 bird +NqwxEAASrCo_1 airplane +Nr9t7GeBwQY_2 skateboard +NsbG9FcyTFk_1 elephant +NsbG9FcyTFk_4 elephant +NsbG9FcyTFk_2 elephant +NsbG9FcyTFk_3 elephant +NuKyL_c3YcQ_0 cow +NulXMVhoGhU_0 knife +NuutxSJHULc_1 cow +NvkF9R1HsJc_0 car +NxTnPIBFKdE_0 airplane +Nxjnp7dqCdc_0 cow +NxqGplqsmNk_0 person +NyKq-nq-KlQ_0 person +NzAEnNO5-fo_0 bicycle +NzAEnNO5-fo_3 bicycle +NzAEnNO5-fo_4 bicycle +NzAEnNO5-fo_5 bicycle +N0LEywKxW9o_0 cat +N0e8A9q9tyU_0 train +N1OYtZSKdKQ_0 train +N1OYtZSKdKQ_3 train +N1pTdHcekjU_0 car +N28sspen6dM_3 bird +N28sspen6dM_1 bird +N3ffRSq8s7M_2 cow +N6nP6NLTaG0_0 motorcycle +N7Bv6ZMyBrU_0 skateboard +N9vkS7ish9k_0 cow +N_5Xf4hpanE_1 dog +N_5Xf4hpanE_0 dog +OBQQMo8mWLE_0 person +OCA5rhgrl48_0 person +OCLVaKMFCZg_1 bicycle +ODI8kcB_dSs_0 truck +ODJSlRRM1Uo_0 cat +OD4XsgCwIKk_0 person +OD9vhbbeBAE_0 horse +OEhrO1p2agU_0 person +OGOf9vbNJB8_0 person +OG8Nfns4uh0_0 cat +OHEyq1pCfZ8_0 truck +OIV8ASYsqZc_0 skateboard +OIV8ASYsqZc_1 skateboard +OImLl2ufWqI_0 cow +OJktr2-sJmY_0 motorcycle +OJktr2-sJmY_2 motorcycle +OKbNtRotT5w_2 horse +OKbNtRotT5w_5 horse +OKbNtRotT5w_7 horse +OK-2ALhNWts_0 bird +OLpvIpNUgY4_0 person +OLyGncmosSs_1 horse +OL_lZw3lqE4_0 person +OMm3ReCUyGA_0 person +ONlvohUS-io_0 cow +OOC45SMJl6M_0 bus +OPIxLQwJLaM_1 cow +OPbyoGG-M_E_0 horse +OPm_iAWIO2o_1 knife +OR4OEYlOndk_0 motorcycle +OSRtFznjiro_0 motorcycle +OSUOKZdfiXQ_0 person +OS6SXRjK0rU_0 horse +OUeSqgMRLUg_0 bird +OUrVDMMYK-4_0 person +OWBXMvAtmcA_0 cow +OWqaj3O-u6E_0 train +OWqaj3O-u6E_1 train +OWqaj3O-u6E_3 train +OWvRHFQJ-5g_1 train +OXjc7JlWYwk_1 bird +OXpPVrdEoko_0 elephant +OXpPVrdEoko_1 elephant +OYCDyQPt5rU_0 truck +OYRmTydmqZo_0 cow +OYugCmogPD8_0 bear +OZver3igS6U_1 zebra +OZy-0MSWC7o_0 person +OZ5z2K-vIYg_0 motorcycle +Ob4ur_FS9xM_0 dog +OdLj2La07lM_0 boat +OdnylLd12pU_0 skateboard +OdsXUxBBISo_0 airplane +OePFLxtDg7k_0 horse +OflyVi689KA_0 skateboard +Og9LiinXMtw_0 bus +Ojx6OtSIA3k_0 person +Omdbd0YsB2o_0 airplane +Omdbd0YsB2o_1 airplane +OnRL69PzM4I_0 bicycle +Oo3Uhz6L-cs_0 person +OpEMSVRTyxk_0 dog +OpJl0GUiLQI_0 person +OptQqflXY_g_9 elephant +OptQqflXY_g_0 elephant +OptQqflXY_g_4 elephant +OptQqflXY_g_5 elephant +OptQqflXY_g_8 elephant +OqmbWcekMxo_0 person +OrPfakDZX64_0 person +Orwr1k0mKho_0 person +Orwr1k0mKho_1 person +OtHHLfag4xg_2 knife +OumTAMPogf4_0 person +OvQFDkMjctE_0 person +OyDNx0iCGUM_0 truck +OyKi2PGJERI_0 person +OyKi2PGJERI_1 person +OyhAS52bQMA_1 person +OyhAS52bQMA_0 person +OzORAIgrZOg_1 knife +OzQFkM92we8_1 dog +O0o_u_t5Y6w_0 bus +O2TgLtQU7PI_0 knife +O3GPSL92hYw_0 elephant +O4UhXpMuxJI_0 person +O5PlzlxQuPc_0 dog +O5796OHwBy8_0 bear +O6cWlrockUQ_2 horse +O8s1bsDJrwc_0 person +O9dxeSLiF9A_0 skateboard +O9dxeSLiF9A_1 skateboard +O90WVIgQwww_0 person +O9_riOoIpKo_4 train +O9_riOoIpKo_6 train +O9_riOoIpKo_10 train +O_hypcyZCFo_0 airplane +lryNU4SKncc_0 cow +lrzxlHguluE_0 bird +lr7T4YcCWSU_0 elephant +lr7T9GuNUMY_0 cat +lskWmTPa9Gk_0 person +ls34lS6fGzw_0 person +lt7kXXW5D-c_0 bus +lvdU2uEdpnA_0 boat +lv6aYZguv6k_0 person +lxXwMvanqo4_1 boat +lznoTW8tuLI_0 bus +lznoTW8tuLI_1 bus +lznoTW8tuLI_2 bus +l0J9Km2lk2I_0 person +l0TirY4L7Es_1 horse +l0TirY4L7Es_3 horse +l3yFwpak_LA_1 horse +l38pNVKwDeo_0 bird +l4sdxYUAiJQ_0 person +l4_P74HRriU_0 person +l5GlzRyX39s_0 person +l5GlzRyX39s_1 person +l5WawiGWVxg_0 person +l6cEGnOtFZg_0 airplane +l682n6ZmpNk_0 person +l7Mmo3ow8qo_0 person +l7kq2yqxPQc_4 horse +l7kq2yqxPQc_2 horse +l8r-mOc3-3U_1 person +l9QgZQGtQWI_0 motorcycle +l-4jrxgMGTQ_0 skateboard +mAEnlKe67pQ_0 bicycle +mAhzB1TH8mU_0 truck +mAj62XUNkIM_0 horse +mBgSYaKydZY_0 person +mC5X6MO2y9A_0 person +mDf5zsFFweg_2 knife +mDf5zsFFweg_1 knife +mFbUnWMAreQ_0 person +mGDfepYDRRE_0 person +mHFxPudSk8c_0 motorcycle +mIFnGYdf0po_0 person +mJm2UYBiD8w_0 cat +mJo7aqOfRww_0 airplane +mJ6qCcS_-AQ_0 person +mJ-DsFbUPUg_0 motorcycle +mKBs2L-xwdU_0 person +mLVHfKExUNU_0 boat +mMdGNbPpLKQ_0 truck +mMy70TxInmA_0 person +mNpEoUW_OPI_0 knife +mOFqvrGzJiE_1 elephant +mOFqvrGzJiE_2 elephant +mOkmKyBZoXI_0 person +mP6-RR-Vuv0_3 truck +mR1y0XlZhQ4_0 person +mTeNKWTwFcs_0 person +mU7E6pi9PFU_0 bear +mU7E6pi9PFU_2 bear +mWeNwTJwEmo_0 person +mWhw719wEH4_0 person +mXBKJjrxqmc_0 knife +mXekeIascCc_0 person +mX_4T1I2ux4_0 dog +mYwEvpKN2-Q_0 train +mZ0VxiELg9A_2 motorcycle +mZ0VxiELg9A_0 motorcycle +maiqraHgwgg_0 skateboard +mbZZ48h5pnY_0 person +mboIIChd8tY_0 bicycle +mcR2Fi6wQj8_1 train +mcR2Fi6wQj8_0 train +mciQ3fR1QTE_0 truck +meAfvCGeyyU_0 person +me-WjezBU4U_0 motorcycle +mflX-nwtpzs_0 skateboard +mgSJL9uL49w_0 bus +mgSJL9uL49w_1 bus +mhDnVhRMCHc_5 cow +mhDnVhRMCHc_0 cow +mhDnVhRMCHc_1 cow +mhDnVhRMCHc_2 cow +mhDnVhRMCHc_3 cow +mhDnVhRMCHc_4 cow +mhIULm3ssFk_2 airplane +miJ1b0bNn9M_0 person +miLapj3u_5g_0 cat +miR8Xeb7SM0_0 umbrella +mi4j0PrR-Gs_0 truck +mi4j0PrR-Gs_1 truck +mjSUb46nTjs_0 horse +mj2ClgQE_Q0_3 skateboard +mj2ClgQE_Q0_2 skateboard +mj_R3ENyiKM_0 person +mnOoqy7I3L8_0 skateboard +mns4vFzs4_8_1 skateboard +mns4vFzs4_8_0 skateboard +mnwyrMq92so_0 person +moBNY2JjuEQ_0 cow +moc2yPvW_JU_1 person +mpA3PWbdVWc_1 bus +mp-cHp44pXo_0 bird +mp-cHp44pXo_1 bird +mqI9CDpsCDE_0 cat +mqYD18pFqm8_0 person +mrnDERbyZcM_0 skateboard +mtO9ioY8AHY_0 person +muk5R25UV1A_0 person +mungFWJMSsg_0 dog +mwRNyFvem8g_3 truck +myYMS85ltwo_0 skateboard +myiCWmM3XN4_1 dog +mziKTFuKVco_0 person +mznC1uLm_j8_0 skateboard +m0z25TJV2vU_0 person +m1VAqMAJ-Lw_0 elephant +m2DUDsR4tWA_1 bus +m2Sr_Q8JpcI_0 horse +m2Sr_Q8JpcI_2 horse +m2Sr_Q8JpcI_3 horse +m2-nK6oZ08E_0 horse +m2-nK6oZ08E_1 horse +m3u_pETGaMw_0 train +m4Ozpr8E1EE_1 train +m5mSFt43spE_4 motorcycle +m7VhCUoV_Dw_0 person +m77tPf0Ulb0_0 person +m8THukZrE7w_0 person +m86BSOvJvS8_0 person +m9hdxJE9HQE_2 train +m95nb4Vl_R0_0 elephant +m-Ry10-IgWg_0 horse +m-sLdoVujlI_1 bird +m_25GAJYGHE_1 car +nAO2Y4kF7b8_0 bicycle +nBllCINiO-4_0 train +nF_NlCSUpFo_0 cat +nIO0ZNZi6n0_0 person +nIiXsRSLxZI_0 person +nIiXsRSLxZI_1 person +nJO5eQXPS0M_1 horse +nKfhxWUyc4I_0 elephant +nKfhxWUyc4I_2 elephant +nLUyCQwkCds_1 motorcycle +nMW7WsVKd_E_0 truck +nO14Z3ggnZs_0 truck +nO16C5NBMQQ_0 person +nO16C5NBMQQ_1 person +nPJJOI4j3UQ_0 person +nQAqVHkffhY_6 train +nQAqVHkffhY_7 train +nQAqVHkffhY_1 train +nQAqVHkffhY_5 train +nQrJJZvmF74_0 cat +nRu8IVZXzCU_0 airplane +nR1Ng3PnYoU_0 cow +nSUBF0RYH1o_1 bicycle +nTfgyYqyO_Y_0 person +nTtqkLze7eY_0 horse +nTtqkLze7eY_3 horse +nTtqkLze7eY_4 horse +nW4sAWZ6dHQ_0 bicycle +nXYeq3IDOFo_0 truck +nXgq-W7J6ho_0 person +nYGQy8peDYk_0 person +nYHjMb7HoK8_3 bird +nYIUSRVmY30_0 person +naMdRxX0924_0 train +na6hNW8gSx8_0 bus +nbojUStyLvY_1 person +nbojUStyLvY_0 person +ncZiTQHehfk_0 person +nefS_k9oFMI_0 person +ngE_mlmsaqY_0 person +nh4AR9Mjwmo_0 bicycle +niQ2DNNlBSM_0 person +niUnVyYTszc_0 person +njOQqZ1pBGM_2 boat +njP6uuU-G6o_6 bear +njcuqdNTGfM_0 person +nj8ALe3wC9c_0 horse +nki1SdWtdCI_0 cow +nk6FezKWYSY_0 bird +nmNSM48p094_0 knife +nmRZQdp3xRk_0 person +nn8WcALmZ7c_3 bear +noTnh5A2OHo_4 boat +noTnh5A2OHo_1 boat +noWsAcioI8g_0 train +noe-qNQfJBo_0 bird +no-b9_3kXiQ_1 dog +npAPemisdEI_3 boat +npGL0Kl16f0_0 person +npGL0Kl16f0_1 person +nqZya6Vk3iY_0 cat +PAdHnsQ5png_0 cat +PAi_eJ_z59w_0 skateboard +PBPViL9vBZQ_0 motorcycle +PBS3-SzLV2A_1 horse +PBwR_Jdod_g_0 knife +PCJWOz32Js8_0 person +PDmAbS9Afkc_0 truck +PE8yxnkayr0_0 person +PE8yxnkayr0_1 person +PFKrDvQuKII_1 car +PFb83m0smRg_0 person +PHunbTKqKwk_0 train +PH5VqmGrnXs_0 cat +PIG9w10uliw_0 bus +PIo5FlB1sf4_3 bear +PIzyVPr2kvQ_0 person +PI_spS2t57M_1 horse +PI_spS2t57M_0 horse +PJK-c0HQksg_0 bear +PJUvXC0Eumw_0 airplane +PJsCV-lA78A_0 elephant +PJ0Y1xQ7ZJo_0 horse +PJ2kZmkL25Y_0 person +PKGRn71TQGQ_6 airplane +PKGRn71TQGQ_1 airplane +PKtLlpi00cM_1 skateboard +PK_UdRSa36U_0 motorcycle +PMDSUC0_Ytg_0 bus +PNxobv7rkRU_0 person +POWngj1oBhQ_1 train +POpePYwyHWY_0 bus +POu1oPwNd4g_0 umbrella +PPeaYnqzi9g_0 person +PPjAhD3i-v4_0 bus +PPqkkhaUIdE_3 bus +PPqkkhaUIdE_0 bus +PPqkkhaUIdE_1 bus +PRaq5kZmO2A_0 bus +PRyc4Vp0s00_0 bird +PSyuR_D5C2c_0 cat +PTLtv0VJ0_s_0 person +PTM6VrBcP80_0 dog +PTewrgfas9o_1 train +PT6u63wHOhs_0 dog +PT_tMCTzlSc_0 person +PV_FZhj_0hI_0 car +PWZIO2hdNRU_0 person +PWiyz8b24es_0 airplane +PXxs6Hzx7Pk_1 zebra +PZ3X20r0oVc_1 bird +PZ3X20r0oVc_0 bird +PdPZkfHUOq0_0 person +Pd9bh2hiWAk_0 person +PeA8729U1jg_0 boat +PeJxY7YFBTA_0 knife +PgFIqGCjnc0_0 horse +PgNvdw3Zges_0 umbrella +PgjeF-iHzLk_0 person +PgyVMv-RRL8_0 truck +PiI1e3aKeos_0 person +Pkju9RRBRAU_0 person +Pn01hUEOICo_0 bicycle +PoI-RFl6jqU_0 bird +PoI-RFl6jqU_2 bird +PpX6lJOP6ng_0 person +Pq1kVNudVJo_0 boat +PsPMm45bDZA_0 bird +PskTcGACgjw_0 person +PsrCCNATJd0_1 elephant +Ps9peKxde4U_0 dog +PvCZZzw4FKw_0 person +PvQVqhtqTVk_1 person +PvQVqhtqTVk_0 person +Pv3IqqHid-w_0 airplane +Pv3IqqHid-w_1 airplane +Pw7zlPV9yh4_0 motorcycle +PytUHdEhipQ_0 airplane +P0FylASL6h4_0 person +P06NLpHGLb8_0 truck +P06NLpHGLb8_1 truck +P1FTUN2gJkY_0 person +P3JAtlf2-VA_0 cat +P3MhJa_p-dU_1 truck +P5MpdcJgQrI_0 skateboard +P5NEco_Rqas_0 motorcycle +P5NEco_Rqas_1 motorcycle +P5v3n_5s-F8_0 horse +P7i0pgLo9kg_1 car +P8E7gprJa1s_1 skateboard +P8_7-uFl2Go_0 bicycle +P9dDbodBY8s_2 motorcycle +P9dDbodBY8s_0 motorcycle +P9dDbodBY8s_1 motorcycle +P91LJh-_E0Y_0 cow +P-FrYGR7Bf0_0 person +P-phCIDPeWw_0 horse +P-27cmR3CZE_0 knife +P-_MzAIxz2E_1 knife +QBAxag8dq6Q_0 cow +QBfotDmdDkk_1 skateboard +QBrAST1Q2iE_0 person +QCCt8ooY4qg_0 person +QCjqG8908mY_0 cow +QEDWauqnaSk_0 skateboard +QEGY7Dq2x9s_0 horse +QE0MjXjSFjU_0 boat +QFS35qERdLE_0 person +QFeMKKxurVg_2 horse +QFxep-yih-s_0 truck +QFxep-yih-s_1 truck +QGN2-Iqa4QQ_0 person +QHPYpnJSf2s_0 cat +QHhkx3CSiWk_0 person +QJ1W4Pajbv0_0 person +QLmFsJCZy_o_3 knife +QMRFisCEGQc_0 person +QM9Kddu2XcQ_0 train +QObG-uf4v68_0 motorcycle +QOjAwmQ_7vA_0 person +QPtMbvxzFuE_2 bear +QQC7AIIJg2Y_0 elephant +QQLrVBS8VSo_0 person +QQLrVBS8VSo_1 person +QSTf92HwJS0_1 dog +QSTf92HwJS0_0 dog +QTjiYkMuDGI_0 knife +QTqvJZS8ZNo_0 elephant +QUIxOZH8N8c_0 person +QUUgu5YvS1c_0 person +QU7X6RkjKPE_1 boat +QVUI5ZkkDsA_0 person +QVnam2Ma6mY_0 person +QY1rz6k86s0_1 person +QZS3V-7xnAA_0 person +QZWqiN4OA_A_0 person +QZk1HSA90KA_0 knife +QaUHYb5os4U_0 person +QahBgQXhNfo_0 cat +QbOvfWFyPzg_0 dog +QbOvfWFyPzg_1 dog +QbPvdKEmnrI_0 person +Qb4RNeQYfPc_0 boat +QcLa-GP2ITc_0 person +QcLa-GP2ITc_1 person +QdeUvHCiXwc_1 horse +Qd0chk9vUQ0_0 bear +QeISQLJERxg_0 person +QfJeJLieLew_0 cow +QfJk-eDxmKE_0 person +Qfkb-gc72qg_0 cow +QgPao5AkXFU_0 skateboard +QgiX6-1aN-4_0 bus +QhGx_MwYnWs_0 person +QhIp71nr7Vk_0 dog +Qk_VhG5lt1Q_0 cat +QmRFPW81gZc_1 truck +QmfJmQuF1-I_0 bus +QmuLT1MpdP8_0 person +Qm2yaeiexlI_2 motorcycle +Qrd-Q3XrT3A_0 train +QszBg-eN7F8_0 cat +QtBYK8AxWCw_1 person +QtpKcTyf4n4_0 knife +Qtq2m-MV2q4_0 cow +QvY9ysq30EI_3 elephant +QvY9ysq30EI_5 elephant +QvY9ysq30EI_0 elephant +QvY9ysq30EI_2 elephant +QwJNOYFZ3W8_1 elephant +QwTIODgGfOM_0 person +QxLFtmn_Igw_2 bear +QyyPl-aCFUs_0 cat +QzETtzOBUaY_0 person +Q0HpPvC0bKA_0 person +Q0M_Fog02Yw_1 horse +Q0UrlXLNioY_1 umbrella +Q0tQtb1npx4_0 car +Q0x55aCCNxA_0 person +Q31q8b3CSN8_1 skateboard +Q4rAM1058Z4_0 horse +Q4rAM1058Z4_1 horse +Q5G2n-3zXX8_1 person +Q5G2n-3zXX8_0 person +Q5X1kisU8Qo_0 person +Q6hwtMw2jkU_4 skateboard +Q6hwtMw2jkU_3 skateboard +Q7SViqj0bEg_0 dog +Q83xNK10WK0_0 bear +Q-lTGQgTOEg_0 person +Q_rsZh5VqdY_0 person +RANBJV7BN3k_0 person +RAmxGTzr25A_0 person +RBccU2wq7Qs_0 knife +RBclSX-7rYQ_0 person +RDiehz1pFVA_0 knife +RD7nVPZTGEw_0 skateboard +REBfrgEC_3U_0 knife +REh7f-__WqU_0 cat +RE40E9-qdHE_0 horse +RFO8tA6rfbo_0 truck +RFbhEQ4qN-A_0 person +RIfxXKT-_88_1 skateboard +RJZgo3_JEPs_0 person +RJi5ZRGQb-A_0 person +RJxPTuKUKjk_0 horse +RKFpQfRSYIc_2 motorcycle +RKFpQfRSYIc_3 motorcycle +RKFpQfRSYIc_4 motorcycle +RKFpQfRSYIc_6 motorcycle +RKFpQfRSYIc_7 motorcycle +RKFpQfRSYIc_8 motorcycle +RKFpQfRSYIc_9 motorcycle +RKFpQfRSYIc_10 motorcycle +RKFpQfRSYIc_11 motorcycle +RKFpQfRSYIc_0 motorcycle +RKFpQfRSYIc_1 motorcycle +RLcZcFP03fA_0 person +RN6TzMbUlyg_0 airplane +ROdg8e5a0Fk_1 cow +RPwZjkygYo4_1 elephant +RR-fksDmQTU_0 dog +RSLwmLbf3No_0 horse +RSO2IDZGDus_0 person +RSQ7pHT5sU4_1 cow +RSWyviTCTqk_0 cat +RTAQO62dbRo_0 horse +RTONY5PqRUo_0 skateboard +RT0mh9U0YDc_0 person +RUAbb66fW18_0 bicycle +RUW8xYh84q4_0 dog +RU0u42rf0Hw_2 truck +RU0u42rf0Hw_3 truck +RU_8ryQNxC0_1 bird +RWJfJx1nXNQ_0 bicycle +RWo2zaceWcc_0 bird +RahqzUIhIkc_0 cow +RawtpxzAbmM_0 person +RdZGVs8pH40_2 skateboard +RdZGVs8pH40_1 skateboard +Rdge7lmfdc8_0 person +RfVv6ECZ78Y_3 bear +Rfa2If7RJTY_0 knife +Rfa2If7RJTY_1 knife +RfvNPPjs-bw_0 boat +Ri3O4rz5S2o_0 boat +RoMemRfbKkc_0 person +RoNJ0fP0VUU_0 person +RqAANAYxYz0_0 person +RqqaUsDM-aI_0 person +RrnixlsQyn8_0 person +Rr6AsTlUNKQ_0 person +RspILw0UAM8_0 person +RsyjwcMkRrY_1 knife +RsyjwcMkRrY_2 knife +Rt1reRy5GVY_0 person +RuFIanBmYzM_0 bicycle +Ru9ksAvNYc0_2 cow +RwVTAYsyWMo_0 person +RxWOvD9i9Ig_0 car +RxtS3kGOYoc_0 bicycle +RxtS3kGOYoc_2 bicycle +RxtS3kGOYoc_4 bicycle +RxtS3kGOYoc_6 bicycle +RxtS3kGOYoc_9 bicycle +RxtS3kGOYoc_12 bicycle +Rx9YjtdgOEI_0 person +RyVdNK-PCyg_0 person +RylJTxUTfF0_0 skateboard +RzdsXt87bVE_0 dog +R0biK134LTQ_0 person +R0n9cqLQE4E_0 skateboard +R3rDAaPE_s4_3 truck +R45uCINxuVY_0 person +R7IE_IohaIk_1 airplane +R7IE_IohaIk_6 airplane +R7IE_IohaIk_0 airplane +R8Zg4uo1QpM_0 person +R9d1vlii7cs_8 truck +R9hRCG8pAHM_0 horse +R9hRCG8pAHM_1 horse +R_xLhXpHgp0_4 skateboard +SAeiSpeFynU_1 bus +SBmb0VU07rs_0 boat +SCLi5OFtzQk_0 skateboard +SCaWHsWzxqY_0 person +SC18zgZ9Diw_0 bus +SDCTiDVOdW0_0 bear +SFA4mVjImxk_0 person +SFoil_6CvbI_0 bird +SGsRwH8YxQg_1 airplane +SGsRwH8YxQg_11 airplane +SHSsDGmwywY_0 cow +SIZ3AYCr7PQ_0 person +SIv3Hcq1ge8_0 elephant +SIv3Hcq1ge8_1 elephant +SJkZwyPxUTg_0 cow +SJqduSR9h4g_0 elephant +SJwgIeOkfTM_1 horse +SKoDZimqLV0_4 bus +SMF8aDGwELI_0 giraffe +SNbBUZtngzM_0 person +SNnofRkUk8w_2 boat +SNqtno2pOzc_1 dog +SNqtno2pOzc_2 dog +SQn8ueHVBWc_4 elephant +SQn8ueHVBWc_6 elephant +SQn8ueHVBWc_1 elephant +SQn8ueHVBWc_3 elephant +SQ4tDbbdzr8_0 train +SQ4tDbbdzr8_2 train +SSjgAjilS8g_0 person +SSwA_nC9rr0_0 person +SThjw6JeBnQ_0 person +STuEo8vap08_0 person +SUHEgX-8bo0_0 person +SUwLfCebumU_1 bear +SUwLfCebumU_2 bear +SVUAFI7bHqQ_0 person +SWedQv5UnQo_0 person +SXWo-zKZICs_0 person +SYT4odK3Dwo_1 bird +Sc_CAareVEI_1 elephant +Sc_CAareVEI_6 elephant +Sc_CAareVEI_7 elephant +Sc_CAareVEI_2 elephant +Sc_CAareVEI_3 elephant +SdzIWTR-rkc_0 person +SeBOeRzwqrQ_0 skateboard +SeU_71ydaeA_0 elephant +SehCD9wP-Pk_0 person +Sf9OdV3i3I4_0 person +SgglaVke5lo_3 boat +SgySshdgJrQ_0 motorcycle +Shves64RCp4_0 cat +SiotcXGUwAs_0 person +Sj56u4dFe4k_2 person +SlR9qCk_m9k_0 motorcycle +SlR9qCk_m9k_1 motorcycle +SlZZmtOGyeE_0 airplane +SlZZmtOGyeE_1 airplane +SndDcPzB8Hc_0 cat +Sn2SGmheI-Q_0 person +Sn9gOBw9bf4_0 person +SoiA6jtejG4_0 dog +SpbyBYH0OjI_0 person +Sph2g6B-X2M_0 cat +SpjssmEyc_o_0 airplane +SqHtdCP5Oao_1 horse +SqHtdCP5Oao_2 horse +SqLiHZHzp9w_0 person +SqoR7vKYzCY_0 horse +Sq-Xok-ea7U_0 person +SreiPFJ6vBw_1 boat +SsMS0eIy2Ws_0 person +Sse7vXMMO6E_0 person +Suaush4Da4s_0 person +SvPL8gOREaU_0 knife +SwaILKCtBVA_0 truck +Sw4B_VFic3M_0 skateboard +Sw7L3wImbSA_0 person +SyldRIQbAGU_0 person +SzVyFmQ28Xo_0 car +SzkobSwGTMk_1 bird +Sz2bTIe9kTo_0 airplane +nrEv-Plh45s_0 bear +nt_BXwq_xhA_0 giraffe +nuCdww9iIOs_0 horse +nuMeNIi1MPY_0 person +nuMeNIi1MPY_1 person +nui8beXjUlU_0 elephant +nui8beXjUlU_1 elephant +nvMXQKwroRY_0 person +nvaO13WFhos_0 person +nxBkP48NgKY_0 motorcycle +nxclZ6iCf7o_0 cow +nyogtZp3kIk_1 airplane +nzf12QyuD4E_0 truck +n0tx4V2rF3I_1 giraffe +n09NxJcTEYQ_0 person +n12ITkwyzvM_0 cow +n15n46culQU_0 person +n19nqH4078Y_0 bear +n2F8uNrgh1U_1 elephant +n2daSQR_dTI_0 motorcycle +n3Eb6Cf77Vg_0 airplane +n3aHtfCo_aw_0 person +n3fhSGUvtH8_2 knife +n5alwWwFPb0_0 motorcycle +n5osSY0_BSo_0 person +n5-RrJI-Lxw_0 person +n6I0k52pV18_0 bear +n8xNf-PRHnc_0 truck +n9AUV2KuhLo_0 cow +n9zSAZMj2Mk_0 knife +n-I-WnLfnqE_0 horse +n-QBM6yD7RI_0 bird +n-eDiuWYJUc_0 person +n-1FhryZboM_0 person +n_Cv1LzGol0_0 person +oBixVhXVcmY_0 person +oBjIRWu_BWA_0 truck +oCCV0-mP2R4_0 bus +oDlSzIkDJGM_1 car +oDnobYn8maE_0 person +oDrYXyIN9xs_2 dog +oEcyeE0kNFc_0 horse +oElAgrukyOk_0 person +oE0bjG0z-nk_0 person +oGDp2b_LvDA_0 bicycle +oHu9fCIhAjs_0 person +oIQuiXJzEUI_0 person +oIYCDBqfT6I_1 elephant +oIZHf-r5C3w_2 bird +oI3ETWYxCi8_2 person +oI3ETWYxCi8_1 person +oJAivZwYxDE_0 person +oLTHGMleOxk_0 car +oLTHGMleOxk_1 car +oMZczwLgR1Q_0 boat +oMZczwLgR1Q_3 boat +oMZczwLgR1Q_1 boat +oMZczwLgR1Q_2 boat +oNMf32fzYvo_0 person +oOi9E4se4ww_0 person +oOp7fTxc8qY_0 person +oOp7fTxc8qY_1 person +oQcVQukPVdA_0 horse +oRacxmfNaSM_0 cat +oSwwku39aC0_0 skateboard +oXHr2yBfL3Y_0 cat +oXfOERZ2kMs_0 cow +oXlK1t1qisA_0 person +oYw8UE0VSFk_10 elephant +oYw8UE0VSFk_1 elephant +oYw8UE0VSFk_5 elephant +oYw8UE0VSFk_8 elephant +oY5CyHk-QEo_0 person +oaHCd7KI_Fc_0 airplane +oaK_EfFOb7o_2 skateboard +oaK_EfFOb7o_0 skateboard +oa5NT5mX--c_0 person +oa838tg7QCk_2 elephant +oa838tg7QCk_3 elephant +ocJUmpBIBOo_0 person +oc7XeYj7dOE_0 skateboard +odjK5W70JaE_0 person +oeYHzAMgoQ4_0 skateboard +ofynEJHRTz4_1 person +of1ISNDelz4_0 cat +ogJGxnVqTWY_0 cow +ogNqc-uHzQ4_0 umbrella +ohkrDDXUwjY_0 person +ohrYGLaImow_0 cow +ohxeFH800SE_0 skateboard +oiftoNj28hs_0 elephant +oiwU7UpO9S4_0 person +oi4GfdQBxyc_0 person +ojiIyU5ibT0_0 person +okPcGR4BRQM_0 person +omsmPSC4u3A_0 airplane +onH8ELLteHg_0 motorcycle +oo3eTJKpErU_1 elephant +oo3eTJKpErU_2 elephant +opWm4bW5B9k_2 truck +opYiNVXmySg_0 skateboard +opkxXg1s8ZQ_0 horse +opkxXg1s8ZQ_2 horse +opkxXg1s8ZQ_3 horse +opkxXg1s8ZQ_4 horse +osYXdQYkiPQ_0 person +otKNUa-KgUg_0 car +otKNUa-KgUg_1 car +otOxAXKskbI_0 boat +otU4Zd1n65g_0 bear +otqOLpbz4LQ_0 airplane +ouK26Crplso_1 car +ouSUKHZs1Dc_0 person +ousG5WHZq8I_0 elephant +ouwAzKpUG7k_0 train +ovQiwCBG8Eg_4 elephant +ovZ4In0kLUg_7 bear +ovZ4In0kLUg_2 bear +ovZ4In0kLUg_6 bear +owW-da7Tdls_0 person +owtKQFT_gNk_0 person +ox0mlEooWI0_0 skateboard +oyuMudJ9EM8_0 person +ozRJI9h3tks_0 horse +ozRJI9h3tks_1 horse +ozvxKPrfdo8_0 dog +oz11xvTIbvM_0 person +o0QRA7gPhBI_0 giraffe +o02m7tfad28_0 person +o02m7tfad28_1 person +o09Ks_UmmkY_1 train +o3eHOnTMxnU_0 airplane +o4PVsZPaxOM_0 train +o4PVsZPaxOM_1 train +o4VOx1SeRKY_0 bicycle +o4VOx1SeRKY_2 bicycle +o4VOx1SeRKY_4 bicycle +o4VOx1SeRKY_5 bicycle +o4VOx1SeRKY_1 bicycle +o4VOx1SeRKY_3 bicycle +o7wb_t8x0D8_0 person +o8KS5SYj0GE_6 bird +o8YfQD0GA00_0 person +o9gD7-MVkJ4_1 bus +o-IwJTgdr_A_4 bird +o_sONKO9OMk_0 person +o_7RumsdAcE_0 motorcycle +pAVwx70oxIc_0 person +pAthLZfnXaM_0 person +pAthLZfnXaM_1 person +pBWgDW8f6II_0 person +pB5-haagdS8_2 bird +pEUCkpfCcaw_0 boat +pEtOW-iQZCA_0 person +pE-OFVB2lzo_0 train +pHsAHiqdb-c_0 bird +pIHbW9IMV2E_1 airplane +pIHbW9IMV2E_0 airplane +pINK56mkS-E_0 cat +pJBMnX2HBFo_0 train +pJ6wkaE8-iY_3 elephant +pKFd8IXz4K4_0 boat +pKnRcv--qEI_0 cat +pLvGIJc0ETk_1 cat +pMKMeBQzCC8_0 dog +pMKMeBQzCC8_1 dog +pMgX9KscZSg_1 train +pNG0qeNr-Vo_0 person +pNWXXO380uQ_4 dog +pNWXXO380uQ_10 dog +pNWXXO380uQ_1 dog +pNWXXO380uQ_2 dog +pNWXXO380uQ_6 dog +pP84ZurhiFY_0 umbrella +pQAJTPvkPj4_0 bird +pRArAdUzaKg_0 person +pRVlgxVhtuA_0 cat +pRy6kU2p41E_0 cat +pS5AzmSvRPY_0 horse +pU9s744_T6o_0 truck +pVR9b-qG1Ig_0 giraffe +pVR9b-qG1Ig_6 giraffe +pVR9b-qG1Ig_7 giraffe +pVR9b-qG1Ig_1 giraffe +pXLbIBluyAQ_0 bus +pXfO7xO-99w_0 cat +pYXDml6lcAY_0 motorcycle +pZCCPMu42GA_0 person +pbFuk0oX6a8_0 bicycle +pbFuk0oX6a8_1 bicycle +pbFuk0oX6a8_2 bicycle +pb3p83fw9bg_0 person +pcUV4ja1VRc_0 truck +pceUU6aj_ao_0 cat +pdyhFh6-rCo_0 bear +peBxgn7gXlw_1 motorcycle +peHZd4qdOMI_3 boat +pe00hbvqjDI_0 person +pe_73GR1-NI_1 airplane +pfED6WafVwQ_0 bear +pfpKoO-GjGI_3 truck +pfpKoO-GjGI_1 truck +phXjZ1yxWD0_0 bus +phec6_yC2HY_0 person +phjJhuKxT5Y_0 train +piGT-hRYHHQ_0 horse +piN1RiueJhY_0 horse +pjLei6UAHsE_0 airplane +pjLei6UAHsE_1 airplane +pjZqJuEX1ow_0 airplane +S2FTgueR-80_0 person +S2FTgueR-80_1 person +S3U383sqlRs_0 bicycle +S4UDIyyqmlY_2 motorcycle +S6h6E0IKO6Y_0 dog +S73sRU7b2dk_0 person +S9QmlxGGxGM_4 knife +S9goDsKFXAg_0 person +S-qgaqzenIE_0 person +TBpnes8Z-3s_0 person +TCtRzPGrwls_0 horse +TCycfRWpg0s_0 elephant +TDKDtLliMhg_0 person +TDlLgW8Fjes_0 person +TFcak4kNd2c_0 person +TGFSBSitWNw_0 cow +TISjnLr1r-k_4 giraffe +TISjnLr1r-k_5 giraffe +TISjnLr1r-k_3 giraffe +TJsLSuQcb7E_0 horse +TKadOIk-uPI_5 truck +TK61mJMHqTE_0 train +TK61mJMHqTE_1 train +TLxcXucOpWw_0 skateboard +TMaLrtjFU34_3 cow +TNNXwm3Bt5I_0 bicycle +TOLyNcTSGPA_0 person +TPglVxQN85I_0 dog +TRH4PZkAkiE_0 person +TSl3wSreplo_2 bird +TSl3wSreplo_0 bird +TVuX76wWzwY_0 person +TW9LBSqxNWo_0 bicycle +TW9LBSqxNWo_2 bicycle +TW9LBSqxNWo_6 bicycle +TXD-idarfhU_0 person +TYsJu2G5WVY_2 knife +TZdDUMDyozA_0 dog +TZfFEYUY5_0_0 boat +TZsigdW7Qfs_0 airplane +TaL6ssJD8z4_0 airplane +TalhQQ9B7vc_0 zebra +Ta-JBO0InZk_0 horse +Ta-JBO0InZk_1 horse +Ta-JBO0InZk_2 horse +Tbm_BFLOPic_0 train +TcRl6wotFw4_0 horse +TcR9fR_SWLg_0 bicycle +TeiC-tObc4o_0 bicycle +TgRRY3Mn0Ro_0 person +Ti411VXWtAc_0 dog +TjCiDUNoDi0_0 skateboard +TkktEeCiSAo_4 knife +TkktEeCiSAo_5 knife +TlXSJmmN3dc_0 motorcycle +TnB8G7eZm24_0 person +TnY1qP0YQQ8_0 person +Tnc7CCuk78Y_0 person +Tn4trDBJAqE_0 person +To8VzjtX70s_1 person +To-lnvpzIKY_0 person +TqKcS4Cx7wc_0 bird +TqvuyyM_x4E_0 bird +TqvuyyM_x4E_1 bird +TsM45PkaTj0_1 bird +Ts4iqmKVRy4_0 knife +TtI1W2xFQ5k_0 person +TtI1W2xFQ5k_1 person +TtnuIzV01ek_2 train +TtyfhN-jWcc_0 person +TuEArk4EFWg_0 person +TuEwZSEUe5A_0 person +TuOnAlE6TRs_0 airplane +TubHgt_FxYo_0 person +TufSi0uSU8M_0 person +TvUmQi32j08_0 person +TvUmQi32j08_1 person +TvuhORVyaL4_0 person +TvuhORVyaL4_1 person +TwH6hv5zVIU_0 airplane +TwSnlq5Kma0_0 skateboard +TxV4qpdgJ3Y_0 airplane +TxV4qpdgJ3Y_1 airplane +TyIzjLHGvjo_0 person +TzUMxAOWWcc_0 bicycle +TzVawH7veiM_0 bicycle +T0WCoXgklkw_0 person +T0r5yfzMs4g_1 bicycle +T24d3EHv2GE_0 bird +T406qi8vIlk_5 airplane +T406qi8vIlk_2 airplane +T6XxSbeAl6Q_0 motorcycle +T8e9Qi4dcNY_1 bear +T95G52MuPFU_0 horse +T-PL14w9TV4_0 cat +T-cOBQACeAw_1 bird +T_2A3L49ah4_0 dog +T_2A3L49ah4_2 dog +T_2A3L49ah4_3 dog +T_2A3L49ah4_5 dog +UANkhHNWM-M_0 person +UAnl6TGZhxs_0 cow +UA5VCImEZ2Y_0 dog +UBdNIuCPaZ4_0 car +UBdNIuCPaZ4_2 car +UBsG3-ocU64_1 boat +UE40h6VhUaU_1 bicycle +UF8l_MU2rj8_0 person +UGCPxfU7FKM_0 person +UG5FFY29OV0_0 cat +UHO129a_p0U_0 airplane +UHYwdGF9W-0_1 horse +UHYwdGF9W-0_0 horse +UIvJPTYu6Hc_0 train +UI4IvmmFIPQ_0 person +UKExOybWiRM_0 motorcycle +UKExOybWiRM_1 motorcycle +UKkr05PKrb0_0 bicycle +UKlB9mDIXss_0 person +ULdZGJs5ta8_0 motorcycle +UMsR07JXCYs_0 cow +UM446G0Lud4_0 knife +UOUaveJ_TWA_0 person +UO_zNFtEt3Q_0 person +UPkEE2dnlkU_0 elephant +UPkEE2dnlkU_1 elephant +UQAJPD_gH7g_0 cat +UQDXdgIlpDg_0 knife +UQibn_ZNp9Y_0 skateboard +UQibn_ZNp9Y_1 skateboard +USAjeRaDlJ0_0 person +UTqlz0i9KIo_0 person +UVTPHohbCV0_0 person +UX4dpwv6qWE_0 dog +UYAtAlnvVy4_0 skateboard +UYc0lVVxayQ_0 dog +UcCtmXy5F4g_0 dog +UcbWaG8GwRs_3 airplane +UcbWaG8GwRs_2 airplane +UceYFW8-zZM_0 train +Ucse975FqUA_0 elephant +Uc5PAhXhIzk_0 umbrella +UgsSu7wC28w_0 bird +Uhj0HRMHPXY_0 person +Uhsh3JUb_aI_0 bicycle +UisVwousE8g_0 cat +Ui8yPflhqHs_0 person +UjMTd3LCxyQ_0 person +UjMTd3LCxyQ_1 person +UlFA0xDQcS4_0 skateboard +UlhZSONgFCI_1 cow +UlhZSONgFCI_2 cow +Umvp1XgX6Qc_0 person +Um-FzEOyncc_0 person +UnUlhJaHWlA_0 bear +UnyyMjT0BCc_0 horse +UsCJdEa7tq4_0 dog +UsCJdEa7tq4_1 dog +Usrv7_ONvi0_0 horse +Us6dL_WD7xg_0 truck +UtyaA_QRIrQ_0 truck +Uu9k1VohpvA_0 horse +UvptsJcl_ms_0 person +UwtHiozuyRs_0 person +UxPh-hnwal4_0 truck +U2LvNquzuZ0_0 bicycle +U2LvNquzuZ0_2 bicycle +U4LhReaGH70_0 person +U64eMon0R9w_1 person +U74o2HGsFeI_0 dog +U853uMV0qAY_0 person +U86p5VtUC6c_0 knife +U9YbGyTBb5k_0 person +U99ENpOmVGI_0 airplane +pmrTy1xQ5kI_0 person +prJIAYsv8bQ_0 truck +pramqy_Y1gA_0 boat +prlcpxzCoyc_0 bus +ps-nNC6Equg_0 cat +ptF2Hqj7DGk_1 motorcycle +ptF2Hqj7DGk_0 motorcycle +ptPi712LDq0_3 bear +ptU4EDudgg8_1 bus +pt6v3JZFi4c_0 bird +puifEp7W50E_0 motorcycle +puifEp7W50E_1 motorcycle +pu0G99aVryc_2 car +pu0G99aVryc_0 car +pwFqv42foTM_0 person +pye4y8sPr9I_0 person +py0U90-ZTkI_0 cat +py2dhJjpOaI_0 bear +p19EU6tw9oM_0 person +p2DntTqvGT4_3 car +p2DntTqvGT4_1 car +p2QsmFuYxdI_0 train +p2TTKNDiGv0_1 bicycle +p4pf9W4qt8s_0 person +p40Oqh_akS4_3 bird +p43GludvR_g_0 bicycle +p5F9hHDkbKc_0 train +p7UAl7_bv4s_0 bus +p8KQvF1DyLg_0 person +p8YhfWsz1JY_1 person +p8YhfWsz1JY_0 person +p8gE3VpTAR4_0 person +p84Z-poVaAw_0 motorcycle +p9ixpjYEEag_0 motorcycle +p-J_LbVq7CU_0 person +p-SJ_Ym5pTA_0 cow +p-XasPaki0k_0 cow +p-cJamorAiY_0 person +p-2rgSte1DI_1 bus +p-2rgSte1DI_2 bus +p-6u3d8YV70_0 person +p_YVPahadQ4_0 elephant +p_YVPahadQ4_1 elephant +qDP6_m4bDRA_0 horse +qD8NS4r2Gd8_1 train +qEjyhyeCIR8_0 cow +qEjyhyeCIR8_3 cow +qEjyhyeCIR8_1 cow +qEjyhyeCIR8_2 cow +qGiLjP8-EVQ_0 person +qHYuGyp8_HU_0 bear +qHZsnSLmqEY_0 person +qIJo1R3rHmQ_0 person +qJI7mnjOp0A_1 umbrella +qJOaXM8s-Yo_0 knife +qJOaXM8s-Yo_1 knife +qJugj62heF8_0 airplane +qKqEqxMZHVg_0 person +qM566R4U4Ug_0 bird +qQbEwbtvdRg_0 person +qSR2E4eqjqI_0 skateboard +qSiMwC5e5_I_0 person +qUGXSXCXUbw_1 person +qVCH1ozivyk_0 person +qV9Ll-N_rpc_0 dog +qWpIdTdBIQU_0 boat +qWpIdTdBIQU_2 boat +qWpIdTdBIQU_3 boat +qXaS7daelL4_0 person +qXfnmaLtO-M_0 airplane +qXwXdnrUo5w_0 train +qXx4Vj-HwkU_2 bus +qYf_XBAUa_o_2 elephant +qZFwurCX4DM_0 train +qZH-IY7bBzg_0 person +qZQcY5PTh10_0 cat +qZVUho1xBlo_1 truck +qZVUho1xBlo_2 truck +qZVUho1xBlo_0 truck +qbYjOWN6n70_0 horse +qceiUxIt1VE_0 car +qcjVVDAbHUI_0 person +qcmbCgcy3co_0 person +qdNXPwWD9_Q_1 person +qdzu1EFDYUE_0 cow +qel4U0nmQOI_1 person +qfp7BvAtQa8_0 person +qgKnno5T6f0_0 motorcycle +qguyMwcAj4M_0 person +qhb1bts1fSM_0 bear +qheo-lRVpfk_4 knife +qheo-lRVpfk_0 knife +qheo-lRVpfk_1 knife +qheo-lRVpfk_2 knife +qheo-lRVpfk_3 knife +qhmscyJC8dM_0 elephant +qh8xnvGfllE_1 bird +qh8xnvGfllE_2 bird +qipZi2kaQyA_3 person +qi3hoxEao_g_1 person +qi3hoxEao_g_2 person +qptB3_MZagA_1 horse +qp5tJGAi9h0_0 airplane +qqL9gnwx87g_0 cow +qqL9gnwx87g_1 cow +qq4_m1S3AOI_0 person +qt6FFVa8DGM_0 person +quoX4193twY_0 dog +qvMRVm660LM_0 person +qvZGFb3CbxA_0 bird +qvcNxorHqCc_0 person +qx647iZCsoE_5 umbrella +qyQFBM_7mBw_0 bird +qywYqT8IzaQ_0 skateboard +qz4S2Tn1Jkk_0 person +q2qEXqY43ws_0 cow +q2v3AmGBH-M_4 train +q2v3AmGBH-M_1 train +q2v3AmGBH-M_5 train +q2v3AmGBH-M_6 train +q3TB2Rnymkg_1 truck +q3pYgC4-lrs_0 elephant +q35X7FnaiGw_2 bear +q5BC4AVKV4c_0 person +q6nXZqEmQGQ_0 person +q9MXoyUF-BU_0 person +q9d2hPrip6k_0 dog +q_dqx0-AtKk_0 person +rA595TIyUgY_0 bird +rBko9NgVOX4_0 person +rB2323YW1iA_0 cow +rDQ2hcIWoBY_1 train +rEXtAqxJj8c_0 person +rGVf1BsLfng_0 cow +rHvp_Dghuho_0 person +rH33U6qgd9M_1 umbrella +rIqhuv94Zuc_0 person +rKN5E25jozk_1 person +rKN5E25jozk_0 person +rLbBCTSGdzc_0 person +rOoxhMEKcgc_0 bear +rPEIT9eAAMY_2 bicycle +rPEIT9eAAMY_3 bicycle +rPUzTjaLdkk_0 cat +rPuPm0ctC3s_11 train +rQHtu5_Piv4_1 cat +rQKV6GBQuag_0 airplane +rRH0VLQDJZQ_0 person +rSF1UQ01lZc_0 person +rSSbdX8817Q_3 dog +rSu82skaMJQ_2 skateboard +rSu82skaMJQ_5 skateboard +rTIN784f0CM_0 train +rTIN784f0CM_1 train +rTIN784f0CM_3 train +rTV3ev-xyuk_0 train +rTYmEM2Lhew_0 bus +rT4P9ZJeBG8_0 train +rT4P9ZJeBG8_1 train +rT4crgFLycE_5 bicycle +rUJ7zeax1zY_0 person +rV1Baq6-C6Q_0 elephant +rWyf2iqpfng_0 horse +rXf2T3VO-kI_1 cow +rYkLuW5NLic_0 train +rZi9k9F8S1w_1 person +rZi9k9F8S1w_0 person +rbIYpEELMQc_3 horse +rbIYpEELMQc_2 horse +rbMVAO2mJiY_0 person +rbn7_DeuItc_0 elephant +rcF4-O7o_Qk_0 person +rcF4-O7o_Qk_1 person +rc96rbja6VI_5 skateboard +rc-e_NDrZDM_0 person +rdBSfuG2KBA_2 boat +rdBSfuG2KBA_0 boat +rdQvGZDUDJA_1 person +rdhiEKvYF0w_0 car +rdnDsUHCZSY_1 cat +rePM3_x9tqw_7 person +rePM3_x9tqw_4 person +rePM3_x9tqw_5 person +rfL51BZGldc_6 truck +VCkpd_d1z4U_0 airplane +VE-3PfVw5-Y_1 airplane +VG2QbeXEwec_0 elephant +VIQGgTWrg00_0 person +VIr_rdbfvQQ_0 horse +VJVWk9wyMjI_0 cow +VJmgPBopcB4_0 horse +VJ0by87MRoI_4 bicycle +VJ0by87MRoI_7 bicycle +VLSeTnShp54_0 motorcycle +VLSeTnShp54_1 motorcycle +VLSol2tA9WY_0 elephant +VLcSoFR7qBw_0 car +VMDBBz7G-Pg_0 motorcycle +VMmtrv5OtMQ_0 boat +VMxS4op_OBg_0 person +VNCLtdahLmI_0 bear +VNCLtdahLmI_3 bear +VNHGw5Sj0Qc_0 person +VN8_N7Ceofk_0 cow +VP0WD1miM00_0 horse +VP20LIiI9S4_3 horse +VP20LIiI9S4_7 horse +VP20LIiI9S4_1 horse +VP20LIiI9S4_2 horse +VP20LIiI9S4_5 horse +VQWxUc9QOjU_4 bear +VRtl4gAWELM_0 skateboard +VRt9s3OQPzo_0 person +VSLdNogDia0_0 bird +VSrmwgo-veI_1 boat +VTqoizpYNeI_0 car +VTqoizpYNeI_1 car +VTqoizpYNeI_2 car +VTqoizpYNeI_3 car +VT11p8szxZY_0 cow +VUVAbtGJbuE_0 person +VUh5jCDWj08_0 cat +VUl6vkX7PRU_0 airplane +VVn3XeSqijk_2 motorcycle +VWTes_MfrOc_0 knife +VXNEqQb5C4Y_0 motorcycle +VXT0TH9jfZo_0 elephant +VXZscyYzxqw_1 person +VYYS45KWEgo_1 dog +VYr49ml0uaE_0 person +VZj4RHsnOWU_0 person +VZqdzb_qI2g_0 person +Va81siK4zeI_0 umbrella +VdLqI43E7eY_0 cow +Vd5pCJuOoDM_0 car +VfBrelUfLFg_0 cow +Vgpm6fwLIns_0 motorcycle +Vhc7DKkRHOo_0 dog +ViQIgBdCkh8_0 car +VlBlBgxUa-U_0 horse +Vlq4fYmrr6g_0 car +VmVN4E_qtfM_0 person +Vm9-f0pXycc_2 bicycle +VngapMBo560_0 cow +Vou-Sfzlpu8_2 train +VqdeO4pa_rc_0 elephant +Vqj-Qv5bVyE_0 person +Vr1Wqz5_UA0_1 cow +Vr1Wqz5_UA0_2 cow +Vr1Wqz5_UA0_0 cow +VsAo8VBzDTM_0 person +VsOw_U6hYRY_0 motorcycle +VsOw_U6hYRY_1 motorcycle +Vsyd7-_CUA0_0 person +Vs2JphYinjk_0 giraffe +VtdrYDJFw-Y_0 person +VtkV11WZWEc_0 cow +VuDA6sPAa9U_0 person +VuLf3ZTqniM_0 dog +VuW2wDK-uZI_0 motorcycle +Vv-z9_l8_ms_0 bird +VwdZHZPjlT0_0 cat +Vwkf0U9PZvI_0 airplane +VwppYMiCI1g_0 umbrella +VwvER7iR2YI_0 person +VxG5gvk1mfo_2 elephant +VxH52JoUd0I_0 person +Vxyq13mC_uk_0 person +Vxyq13mC_uk_1 person +Vyf_VJEQ1jE_0 airplane +V0CjVa5_1P0_0 horse +V0sliERbCxI_0 person +V0sliERbCxI_1 motorcycle +V0w_hBBqe-g_0 person +V1ufPW4ictQ_0 skateboard +V25H8smvzbM_0 dog +V56RVnEPG54_0 motorcycle +V6rg5et7Q14_0 cat +V6rg5et7Q14_1 cat +V6_XA2w3sTs_0 boat +V7CVQjk9-Xc_0 skateboard +V8Pv-I4ovPs_0 person +V9m1dMbXxug_0 truck +V9qvycn1a3E_0 train +V-ZKLxW5cuM_5 horse +V-ZKLxW5cuM_2 horse +V-ZKLxW5cuM_4 horse +V-iFCgvAuCg_0 person +WBcYTIQ65Ow_0 person +WB6uQ708AxE_0 bird +WCNpGdfG8nk_0 person +WCZ4ZQ5ohf4_0 motorcycle +WGw94BtHxYE_0 bird +WGw94BtHxYE_1 bird +WG1DuTb70bQ_0 cat +WItuBm7azO0_0 cat +WKpjUNNgKG0_1 person +WLZkZ-4Y9fY_0 cow +WN5u1Y1yGkA_0 airplane +WP5JXCVRe9g_0 person +WP5JXCVRe9g_1 person +WQ603pEp_1k_5 airplane +WTEO_Ywn9AI_0 umbrella +WTw46mBWjOw_1 airplane +WUvTKLEimNw_2 truck +WWcVr4lbq3E_0 person +WXETP4eMyD0_0 cow +WZWh1M3qGAc_0 truck +WbXmf511q4E_0 horse +Wb9i7jssQsY_0 motorcycle +WcUFxXISmb0_1 motorcycle +WcUFxXISmb0_2 motorcycle +WcgQXl6I-Ks_0 car +Wc6RwJ_8yts_0 person +Wc_-Q9ba0zs_0 airplane +Wdh2SMcRQ2M_0 horse +Wdh2SMcRQ2M_1 horse +WfZR-VRmSB0_3 boat +Wfl0LOShC_I_0 bus +Wh9avYClECA_0 person +WixZlWbnBdM_0 person +WkvpcaxQTSg_0 dog +WlFD1z5akJc_0 person +WlK6sU21od0_1 dog +WlP5_pcua1U_1 truck +Wl1vbjfAxeA_0 dog +Wl1vbjfAxeA_1 dog +WmNKtcf5iLM_0 person +WpxEmYBfqSU_0 elephant +Wqb84sv1P68_0 cat +WrClMyPxaDk_0 person +WrSS3nc07hE_0 cat +WsFZj4Bgtwc_0 bicycle +WvGCvwHutAc_1 airplane +WvUiJ8ZRRfc_0 bird +WvUziN47FfY_4 horse +Wwx2Vce-1oM_0 car +Wx0zNFqSUZo_0 horse +Wx1qid26zsw_0 dog +WzCI6AqY7cg_0 bus +WzrI82-Ak4I_1 motorcycle +W1juH0nZ8v0_0 airplane +W1yEDHYLG1Y_0 truck +W14Nt0_EGQg_0 person +W17CFtB5Oy4_0 truck +W1-9iBLd1lg_0 person +W23FACVBLgI_0 person +W3Bv11o03TQ_0 cat +W4cKlmHvXZ4_0 knife +W4gR7_z77A0_0 person +W4iSCn6ILJs_0 motorcycle +W7xlWK7cuEI_1 skateboard +W8U3FkkaVbc_0 person +W8d2hNOMHpQ_1 horse +W8yL4Qnuo4k_0 elephant +W86rN6nrllQ_0 person +W9lLrNUFQ9M_0 person +W975mcNRX7c_0 boat +W-sCMBY47ck_0 horse +W_QxijO2VBw_0 zebra +rftE7M9tNqI_0 person +rftE7M9tNqI_1 person +rhWLgPl3lt8_0 person +rhjcRHB4crY_1 bicycle +riNqBOlFCuw_3 dog +riVZCbT4LDE_2 person +rih7ECmHfRs_1 cat +rkIzABhjHkA_0 person +rk1ByqQSwtI_1 elephant +rlWlgyP-3-s_1 umbrella +rlWlgyP-3-s_2 umbrella +rlWlgyP-3-s_4 umbrella +rlqtE0bF9nk_0 bicycle +rmVxFro55IQ_0 skateboard +rmxx9X1ytcA_0 airplane +rm4XeENehOU_0 skateboard +rn9-fIMYEkA_2 motorcycle +rn9-fIMYEkA_0 motorcycle +roUwF9YU21U_0 person +rsne3z-CaDw_1 train +rtjlk_iOmdE_2 train +rtjlk_iOmdE_0 train +rt4Qm6HPVTY_1 boat +rvBm-SnbjVI_0 cow +rwQl_jKPcyM_0 person +rww5DvtCsG4_0 horse +rwzjQSTLmhk_0 person +ryUMZWWwJUk_0 person +r0P-2rp1Hpk_1 bus +r0vIwhp5RLo_0 knife +r03Za0dP0d8_0 person +r09YKBrwa8M_0 horse +r3PUq_cy6Mc_0 truck +r3cOrAN6BI8_0 train +r3cOrAN6BI8_1 train +r7WW1Fl-s6s_5 bus +r7WW1Fl-s6s_4 bus +r7WW1Fl-s6s_6 bus +r7WW1Fl-s6s_7 bus +r7WW1Fl-s6s_1 bus +r7xw4qHLKIY_2 horse +r7xw4qHLKIY_1 horse +r7yOsosLuHI_0 cow +r8NwODfEuhI_0 dog +r8NwODfEuhI_2 dog +r9LAMeOEcsI_0 person +r9jyOtbfWs8_0 person +r9osF8drSbo_0 person +r-Dva6GT-a0_1 dog +r-tFy30HVCw_0 person +r-0UD9KQhvY_0 car +r_sRdP_5WaM_0 skateboard +sByCUshWhWs_0 dog +sB613NHl89g_0 elephant +sB8zpg-GrRo_0 person +sD_9McrL3UQ_0 skateboard +sD_9McrL3UQ_1 skateboard +sEzZ3JnSzaM_0 bird +sFxTS449nUg_0 person +sG0q9rphsoY_0 cat +sIIFHk89TT0_0 person +sI17jkxX6tE_3 skateboard +sJyknuUaIOg_0 skateboard +sKCW1p03okE_0 person +sKD6TBNqy6s_0 person +sKD6TBNqy6s_1 person +sKJ0JtWZeWw_1 cow +sKJ0JtWZeWw_3 cow +sLZh8XaxoYw_0 person +sLfyo1VrX3g_3 knife +sLfyo1VrX3g_2 knife +sLnYAS4LAY8_1 person +sLnYAS4LAY8_2 person +sMVMaH9aWHw_0 horse +sNV29dtSqYs_1 umbrella +sOfNz788QiQ_2 horse +sP4jeoUjHZM_1 motorcycle +sRb7OHsI6s4_0 bird +sV9L8gpGDmA_0 motorcycle +sWbk2Sw9Rew_0 person +sWfMpwviOCA_0 car +sXSjs2EV61Y_2 knife +sXw73oA1Tq0_0 horse +sX5GCwZG8d8_1 bus +sbkHA-DWPSI_0 person +scyRfbyCzJU_0 cat +sc15m4_lcvw_0 person +sdAAObJErSA_0 motorcycle +sezamC2zGqg_0 bird +sf76JIFYKB0_1 cat +sgHdQYSWPXg_0 car +sgU4wTZ6k5s_1 person +shXeONsfVmU_0 person +shiIdcOonRs_0 person +siFucH6jjIs_0 boat +siFucH6jjIs_1 boat +sj7NOYq8KBA_0 person +skEWWsL6k9g_0 horse +skl1lsZUG4k_0 person +sm346w9J4zA_0 knife +snZjH03fjVk_1 person +soNDR07vxhQ_1 person +soNDR07vxhQ_0 person +sofKbpbuX84_0 person +sofKbpbuX84_1 person +spVw0PNXErs_0 dog +sqLiQtbkEO4_0 cow +sqv-uPhtxwk_0 airplane +sq-wqsIw5hw_0 train +ssspgc75B08_0 giraffe +steKGH-8MZw_0 horse +steKGH-8MZw_2 horse +sts2vAv4BQo_0 person +suERIXWx_z0_1 person +svCBYM2zl80_0 horse +swuFjNkTmQY_0 dog +syZTh043BkQ_0 horse +s0YqBVjRDyU_0 person +s1Pd7evRn0U_2 dog +s2PyqAoOqrY_0 cow +s2x8llFphNY_0 elephant +s3WiR_wFUBE_0 cat +s3ijyNmvxpE_0 person +s4rr5OrSI4k_0 skateboard +s5I219neN7c_0 person +s5jmkD6lkbU_0 dog +s5n7L55KpWE_1 skateboard +s7or9ZhEyXE_0 person +s74eu-v6aqA_0 person +s8W4NK7dWe0_0 person +s83wzR7ySyM_0 skateboard +s9G4llLAJiU_0 skateboard +s9OmvmQH9hA_0 elephant +s94ng_sG6Dg_0 boat +s-Jnbfjkmak_0 skateboard +s-Jnbfjkmak_1 skateboard +s-guJTrtfSU_0 skateboard +s-yjgHx_YWg_0 train +tAGvlfgdOsI_0 skateboard +tAGvlfgdOsI_2 skateboard +tBlPdyu-syw_0 bird +tBlPdyu-syw_2 bird +tBryhvKADFQ_0 dog +tGyP_SbWsVA_0 person +tHA_VdGe90Y_0 airplane +tHA_VdGe90Y_1 airplane +tHcqw8Cejs8_0 person +tHfOMcj62SY_0 zebra +tI2i9_rBdwo_1 bird +tI2i9_rBdwo_3 bird +tKpbcnqu6bY_0 bird +tK0pl2_wbWU_2 elephant +tLJpuELQgxY_0 person +tLa4F5ekKW0_0 cat +tLzUBeOwhyM_1 bicycle +tMojfxB-9zA_0 person +tMp5Y1zucfI_1 train +tMp5Y1zucfI_0 train +tM3FYC5IVPo_0 motorcycle +tNiu2o7-KPY_1 car +tOK5TnF8eHQ_2 bird +tOL0kPV03Uw_0 train +tOlXErF8Z4o_0 horse +tPCRXfE_aGo_0 bus +tQj85vHtmeE_0 bus +tQnUccPTkck_1 truck +tQ_Vy-9pvoQ_0 skateboard +tSlXTInFXss_0 person +tTSVU8IU10c_0 motorcycle +tUdWqmNDeY8_0 person +tUm_oehvEpM_1 person +tVOS6wht6oQ_1 horse +tV17SBx-oqE_0 person +tXBDRj1c-Uc_0 person +tXf9xVs5ZGk_0 train +tYKrjpIMYb0_1 skateboard +tYciFvRQuec_1 truck +tYciFvRQuec_0 truck +tY-4fAv_YRU_0 horse +tY-4fAv_YRU_1 horse +XA65Kh83GmE_0 cow +XA65Kh83GmE_1 cow +XBNPaOqVqds_0 bird +XBUvxtvKWM0_0 cat +XByg_hQRQDM_2 bird +XDNVcbDkafM_2 airplane +XDNVcbDkafM_3 airplane +XDNVcbDkafM_4 airplane +XD0ydIAwgGM_0 cow +XD_iMe4m2vQ_1 person +XGX6SRd3ZkE_0 bird +XHu9PxuBpXg_0 airplane +XIzQLXQTsRo_0 cow +XI3_0lXrnfY_0 cow +XJq9qp3jhq0_0 motorcycle +XJq9qp3jhq0_2 motorcycle +XJq9qp3jhq0_1 motorcycle +XLgI0VgtzEw_0 cow +XL50qkg4qdA_2 elephant +XL50qkg4qdA_0 elephant +XMIsf8xuMh4_0 train +XPi83QmsR90_0 cat +XQliC40rP9M_0 person +XRKZRwdqhNo_0 bird +XSMGAlakHWY_0 person +XS5wfvz6XZI_0 bird +XTWeBFPqdh0_0 person +XT0t6ims_FI_2 skateboard +XVabRVMuX4Q_0 motorcycle +XVabRVMuX4Q_1 motorcycle +XVabRVMuX4Q_2 motorcycle +XVabRVMuX4Q_3 motorcycle +XVabRVMuX4Q_4 motorcycle +XYA6HKrVVQQ_0 cow +XZBFfRl6DkA_0 person +XaVZr4HPh2M_0 cat +XalkAzccT5I_0 person +Xa6tjMVGH2I_0 motorcycle +Xa6tjMVGH2I_2 motorcycle +Xd9tLIFo_7E_0 cow +XeIssB-JkcU_1 bicycle +XeIssB-JkcU_2 bicycle +Xevq2dskQWo_0 truck +XfUIrHPVj-s_0 cat +Xf09qM8SYBc_0 truck +XgDJ16iRhxs_0 elephant +XgDJ16iRhxs_1 elephant +XgDJ16iRhxs_2 elephant +XgFaXb7Vb58_0 elephant +XgxYznR79R0_0 dog +XhOx4rgdI-8_0 bird +XhTWW9CwFzM_0 motorcycle +XiSjHcHG5IU_1 bird +XjXFktrwSOk_0 bear +XkpxlUwx4oc_5 truck +XkpxlUwx4oc_1 truck +XkpxlUwx4oc_2 truck +Xkr3OHSz_CA_1 person +Xkr3OHSz_CA_0 person +XlIxLJTiphI_1 airplane +XlSvIczm3JA_0 person +XlcJsAWbsyA_0 dog +Xmwv-NZZat8_0 person +Xm_CKSNQE3E_0 bird +XnfAvhHnH6M_0 train +XnfAvhHnH6M_1 train +XoWHAeOAXg0_0 motorcycle +XoXMpm6Yxfs_0 person +Xoa_dCJDiTE_0 motorcycle +XocaP_gyqJU_0 person +XopbyM2SJbc_0 bicycle +XopbyM2SJbc_1 bicycle +Xr_3UPISgT0_0 skateboard +XsK5KxttYBA_0 person +XtTLGRBrm3I_0 skateboard +XtVTdegdzvI_0 motorcycle +Xu6xzBcJySk_0 person +Xu6xzBcJySk_1 person +XvvA9Zc1TMA_0 person +XvwOXlVdehA_1 person +Xwqm_wzZDQI_0 cow +XxkkXeLqqu8_2 airplane +XxkkXeLqqu8_0 airplane +XxmNQjB1D_Y_0 cat +XyldpxZmUN8_0 dog +X0CZDjRqcKg_0 horse +X02e7Fj9BLM_0 umbrella +X0-n3maCrZU_1 dog +X2uXOY9J_UU_0 person +X3HCAEcRaW8_0 bicycle +X3qbUW_qT7k_2 airplane +X4SbOXRpo0A_1 dog +X7xm2nZL7jc_0 bear +X79vSvy6SOQ_0 skateboard +X9L-jwA6Ozg_1 train +X9L-jwA6Ozg_0 train +X9a5wEDFXc8_0 boat +X_TnIuY27eM_8 bird +YA4-rm-dcsw_0 person +YA-N841dD-0_0 person +YB1trUAUzhg_0 person +YB2wzBLh7MU_0 zebra +YCU3daBCWsU_0 umbrella +YCXHNoYaQRc_3 skateboard +YCXHNoYaQRc_4 skateboard +YDd_skWNTMs_0 skateboard +YDyc1Yv9j_s_0 person +YEPfw3k3vEw_0 person +YEvBzZ5KBYY_1 horse +YEz7v7toUwM_0 truck +YFQlAc3qTBQ_0 motorcycle +YIHcQxH9e1o_0 train +YIzqB2G1UvY_0 person +YI4lmC3imb4_0 horse +YJiqdRcs_gU_1 person +YKlWROFtcxc_1 skateboard +YKlWROFtcxc_0 skateboard +YKoT-GgRSw0_0 elephant +YKoT-GgRSw0_1 elephant +YKrdwZe1vq8_0 dog +YL97h6yps6w_1 knife +YMbqULxZJpg_1 horse +YMbqULxZJpg_2 horse +YMkOJNatD88_0 person +YNEDPsAWm5I_0 person +YQXwRsP0zvE_1 person +YQgUV8TrYcw_0 person +YRWC7Tdc5oI_0 person +YTD8j8z44qQ_0 person +YTd8Rxtpt1E_0 train +YTd8Rxtpt1E_3 train +YTd8Rxtpt1E_4 train +YTd8Rxtpt1E_6 train +YTd8Rxtpt1E_7 train +YTd8Rxtpt1E_8 train +YTd8Rxtpt1E_9 train +YTzuVYGpDhA_0 motorcycle +YUhgrCNuMGQ_3 bear +YVDCTyDcjjA_1 cow +YWRbi_v93Mo_0 person +YWhwljQ3efA_3 train +YWhwljQ3efA_4 train +YXeaiwTZ3ZE_0 cow +YXz7CDJ11jY_0 bird +YYUo7EkkJeg_0 bicycle +YYUo7EkkJeg_1 bicycle +YZmhYkqgBi0_0 skateboard +YZmhYkqgBi0_1 skateboard +YZmhYkqgBi0_2 skateboard +YZ3kcrHk4N8_1 horse +YZ3kcrHk4N8_0 bicycle +Yax1xdgRbt4_0 person +Ya2zfpe-_ro_0 bus +YcjMrWCSRSA_0 person +YdooYDhKq00_0 person +YeTYMiaLkWY_1 cow +YfvvO_T8j8k_0 skateboard +Yf9jBSXQTLo_0 car +Yf9jBSXQTLo_1 car +Yf9jBSXQTLo_2 car +Yf9jBSXQTLo_6 car +Yf-okdUBk9g_1 bird +YgM058nmMnQ_0 person +YjZoPTjqDGw_0 skateboard +Yj6XWsgomO0_0 cat +YluDona_474_2 bus +YmlQVVQx4SA_0 person +Ym3lE2u4vxE_3 skateboard +Ym3lE2u4vxE_1 skateboard +Ym37vW7b0U0_0 cow +YnZU-Qa6yeI_2 bus +Ynyd8SBB5Wg_0 knife +YoFfsRgrNeY_0 person +Yof6XFKNuNY_2 horse +YorREGtes1I_0 person +Yo9XVrgl_GM_0 cat +YpDsXa1kNZU_0 truck +Ypb0U6Ga5pk_3 train +Ypb0U6Ga5pk_1 train +Ypb0U6Ga5pk_2 train +Yp1kl6xU-Og_0 person +YqvGb_tDI38_1 bird +YrhvCSxifRc_0 car +YtrNZ4mlMw4_0 elephant +YvAlZo3quqE_0 person +YvwW9T4Qpek_0 motorcycle +Yv3YH0nImQI_3 truck +YxRG0JQrpwI_0 person +Yxia21K4O6I_3 truck +Yy0lIDbLxQ8_0 elephant +Yy0lIDbLxQ8_3 elephant +Yy0lIDbLxQ8_1 elephant +Yy0lIDbLxQ8_2 elephant +YzTl0Nf0Kpw_0 cow +YzT_UsE8Mhs_0 airplane +Y0Hz5Hw1AiM_0 person +Y1lKSppJhdI_0 cow +Y16c_yGYw1M_0 elephant +Y16c_yGYw1M_1 elephant +Y2jXJzRVhMI_0 person +Y2x6ow80IkQ_0 person +Y3TtBVfW6gs_0 person +Y3ZDfyDvFi4_0 elephant +Y3c_6Zv0dxg_1 knife +Y3mx4jYyagQ_0 train +Y5Atu2VWemQ_0 train +Y5BEvakwvuM_0 dog +Y64ky0LNHko_2 elephant +Y-YU80ccuXg_0 elephant +ZBJsNXYIQ4o_0 person +taPyucc_cOU_0 person +taPyucc_cOU_1 person +tafdN9GXP0g_2 skateboard +tbLnjlX1xF8_2 bird +tbuu2U3o02Y_0 person +tcOx8KjmHPo_0 person +tc98WTYT-VI_0 elephant +tdIWlg4_01E_1 bird +tgRYkhC-gJU_0 person +thZqLw7IxVw_0 knife +tj2-fSeuMRI_0 bird +tmch--OGZhY_0 giraffe +tmsInTqqzHI_0 zebra +tof4QiBHPQQ_0 person +towJyxwm3wE_0 bird +to8OyPMfkaI_0 person +tpQv6Sn5z3o_0 motorcycle +tpcuQY4eNaI_1 bus +tpeBIe69wr0_1 bus +tpeBIe69wr0_3 bus +tpwUnqxQYjo_0 train +tqy3XprB11s_1 horse +tqy3XprB11s_2 horse +tq9WP-2U1QM_0 person +tsMTiOeM52E_0 cat +tsg-S4Hk2go_0 person +ttzJbLLAR34_0 cat +tvSJKUR21UM_0 train +twewRZpG7Fs_0 cow +twxvNeK9FZo_1 bear +txDhTthoXSk_0 motorcycle +tx0mtmimu0k_1 person +tx2PSvwf7FU_1 cow +tyem40ZMKGE_0 person +tygG1C5DURU_0 person +ty3iURJku9k_0 person +tzH_tvBDeJA_0 skateboard +tzPForR9Ejs_1 train +tzvKjCoHBMI_0 bird +t0TW8zZxCWQ_0 person +t1N1ijCr5NE_0 bicycle +t1N1ijCr5NE_1 bicycle +t4FZmjCINtw_0 bus +t4naVz1a0sg_0 train +t4zuUZQozs8_0 horse +t5B7vIbyRNQ_0 person +t5kzdnId2sI_0 horse +t5s4Fs07WLM_0 dog +t50QLEhcZCE_0 person +t6C6ukC_zEA_1 bird +t6C6ukC_zEA_2 bird +t6C6ukC_zEA_0 bird +t7YFOxuWxtg_0 umbrella +t7YFOxuWxtg_3 umbrella +t7s424DNznk_0 cat +t8MqK7LWqs8_0 airplane +t8mVwobdP40_0 boat +t_qvtoXbLRI_0 person +uAWXGcWWgSU_0 person +uAZF38u6SOo_0 umbrella +uAzws057QjE_0 skateboard +uA1sb8QyXuU_0 skateboard +uCZi19CC7rk_1 train +uCZi19CC7rk_2 train +uCZi19CC7rk_3 train +uE5rIJoAafE_0 bird +uE5rIJoAafE_1 bird +uH0jKXHq7Lw_0 horse +uH35b2DEXFw_1 skateboard +uH9vcwYxL2s_1 person +uIu2jQswp94_0 person +uJcu-YlAtbc_0 bird +uKJqU3gtIWM_0 umbrella +uLPuf056wH4_0 horse +uMAkaCYTDuc_0 truck +uMYGWhLdrlc_0 boat +uMiNpG3NcEw_0 person +uMpufBdwRn8_0 giraffe +uNpHGE63PdQ_2 truck +uNpHGE63PdQ_8 truck +uOmCLzEMPGc_0 train +uRFXE4UfdTE_0 cow +uR8MqB3VgSI_0 truck +uS1QmKXc0uY_0 person +uTsfiR5FPdM_0 person +uT9uk3mtt98_0 bird +uUU-VpxxSiM_0 cow +uVrW8Mm2xGY_0 person +uWyTGtedEqU_1 person +uWyTGtedEqU_0 person +uarSTtaV_Ps_4 boat +ua6Xyj9aWT4_0 bear +ua6Xyj9aWT4_1 bear +ua6Xyj9aWT4_2 bear +ubHgpaAseuo_1 elephant +ubijaVodfKg_0 person +ubijaVodfKg_1 person +ubsr27_dQOk_0 elephant +ubsr27_dQOk_2 elephant +ubsr27_dQOk_3 elephant +ubsr27_dQOk_1 elephant +ucUearjcPHk_1 airplane +ucfXE6fw3go_0 cow +udlyGSCujUU_0 truck +ufB4EORClps_1 knife +ufMXT_CmtK4_0 airplane +uhm0JnSA-kQ_0 person +uiLBqX72k4k_7 boat +uiM-lDuYaeY_0 person +ujoJwRvjEdI_0 person +ujz4u55Tp1U_0 cat +ul47aFS8dQE_1 motorcycle +ul47aFS8dQE_2 motorcycle +ul47aFS8dQE_3 motorcycle +umkNI2_0Lqc_0 person +umxZfostBlE_0 train +um22CD4bkqo_0 cow +un6QDPagbfo_1 cow +un6QDPagbfo_0 cow +up6VT6l38-A_1 skateboard +uqn85v1WM7A_0 motorcycle +urAYVS5Lz7k_0 person +usAsP-m-qs4_0 dog +uuhWeHmlvt4_0 person +uu3KluYuhc0_0 person +uu3pH95cmtk_0 person +uwXhzSsAIJw_0 person +uw9TxuXeiP0_0 train +uxgUbys1eD8_1 bus +uzMFzDPfsws_0 knife +uzsdMqrgiL8_0 person +u14Sp3wCQew_0 car +u2BHvsjQGjw_0 person +u25Jazd2yJM_0 person +u4KPFsw5W5c_0 motorcycle +u4oma0FVycA_8 knife +u69KRu61wXM_0 person +u7xTeWelI-U_3 knife +u8mmwwrdNb0_4 airplane +u8mmwwrdNb0_5 airplane +u8mmwwrdNb0_9 airplane +u80Y4lA5xT0_0 dog +u85tUrDgmOQ_0 bus +u9HkSfjYpnA_0 motorcycle +u9rfXD33UIM_0 person +u9_P9HFh_NY_0 dog +u-_A36Ha04o_0 cow +u_D1eyd8AOM_0 car +vAUSfFO5UI4_1 dog +vFMzMNDlnBs_0 person +vGIYDcnNTvA_0 knife +vHQkxg7kPUk_0 dog +vH0ZiiuSQzU_2 person +vH7sKynwjD4_0 person +vJypzwSdyN4_0 train +vMt5AD41SKM_0 person +vMt5AD41SKM_1 person +vOY2IRNsjYg_1 person +vOY2IRNsjYg_0 person +vQ6eOB8rxUE_0 person +vRjErSbQNNY_0 person +vTa2zdbIyUw_0 person +vT2JpCnT6rg_0 boat +vWqexY1OdWg_1 skateboard +vXbTARLug3M_0 person +vYN_Gy6fUbI_0 bus +vYhPihwivZs_0 person +vaaqJVWoSf0_0 person +vadASNfLl9I_0 dog +vas3iNRcsK8_0 elephant +vas3iNRcsK8_1 elephant +vbLhfzHqEKc_2 horse +vbSnjtc3vIs_0 cat +vcALsxetYU4_0 airplane +vc-_aAQAXs0_0 knife +vdXD-HTzyFM_0 cat +vfeKOPKE6l8_0 person +vf7NtV1T5Jc_0 train +vf7NtV1T5Jc_1 train +vjb_l1_hEXk_0 person +vjojFy4rPeo_3 car +vjojFy4rPeo_1 car +vj_BAwFKqtQ_0 umbrella +vklwqjQis8Y_1 cat +vlPgSny76H8_0 person +vlflI5iuszQ_0 person +vnD3gELVAq8_0 person +vnyBVn70QLY_0 cat +vnzsKpfAS_M_1 horse +vpBxBDjiJxw_1 dog +vvamB_-Z0so_0 horse +vv3gfxFz2zw_0 person +vwe8ZaV-4z8_0 bicycle +vwtokH03eW0_0 skateboard +vwxzh1lJ7iw_5 motorcycle +vxmdsyEpU6A_2 bus +vx0oKJcOQb0_0 train +vx0oKJcOQb0_3 train +vx0oKJcOQb0_4 train +vyLqolkoVIM_0 person +vzBbUEwED60_0 person +vzBbUEwED60_1 person +vzU0GH4cZM4_0 cow +v0tUEeE4RGc_1 truck +v0xTNbrYZY0_0 giraffe +v01IvIxWXTo_0 person +v1iIhTWRjg8_0 boat +v1-PGfS1YCY_0 boat +v3LIQHdveBA_0 person +v4H5VwQyKEU_0 train +v4H5VwQyKEU_1 train +v4QYOX-FHhY_1 motorcycle +v40pc8KBg0I_2 horse +v5YzVj25_hs_0 truck +v5lUHsxx0mc_1 skateboard +v50Qa_KMCzQ_0 truck +v51CdpETaug_0 bird +v6UDfM50GIM_1 truck +v7XVyg16ens_0 cat +v8Kp0jhKsKk_0 person +v8ceKkKdqrE_1 knife +v8hOOgLXRjg_0 person +v8kyeMoFLqk_0 horse +v8rj3jIndSE_0 dog +v8tktR3aE38_0 airplane +v_yEG5_Qm8Y_0 person +wCu6xsT18qo_0 person +wDHRro9mXuM_0 horse +wDcnUJFHguE_0 horse +wE8LYkzcq0o_1 horse +wE8LYkzcq0o_0 horse +wGPW8I8nGmc_0 train +wGWIrs5ja0Y_0 bicycle +wGyJeWBe8VA_0 umbrella +wIapUcRvgTM_0 bear +wIapUcRvgTM_5 bear +wI0a0fzgy3w_0 horse +wJdfgWlSY5M_0 person +wJdfgWlSY5M_1 person +wK7yIg1qfZ4_0 person +wLA244rmq6g_0 cat +wLHLSvMwmjM_0 skateboard +wL0z6-jkCcc_0 dog +wL0z6-jkCcc_3 dog +wL0z6-jkCcc_1 dog +wL9iOnWhckI_1 skateboard +wL9iOnWhckI_3 skateboard +wMShicf3N_E_0 person +wMyAEfVE_u4_1 elephant +wNKWZ43SioQ_0 airplane +wNKWZ43SioQ_2 airplane +wNWW59wDinQ_1 train +wNcjU9-ck10_0 person +wODzPBxcT0A_0 motorcycle +wODzPBxcT0A_2 motorcycle +wOLrGAo0vFo_0 horse +wOSL7OPRBXM_1 dog +wPRCf3v0EfI_0 motorcycle +wQtHgysmmFg_1 boat +wQvPlByUvB0_1 knife +wSSTL6uuM9Y_0 train +wSmVgAahSUw_0 skateboard +wSmVgAahSUw_1 skateboard +wSmVgAahSUw_2 skateboard +wTMj2Gp8wz4_1 bird +wTMj2Gp8wz4_0 bird +wTtXB0Z2eMk_0 car +wV1VMLQfTYo_0 skateboard +wWpNKbsF6q8_0 bear +wa1KdARQXXg_0 truck +wa3jVRzsWGo_2 truck +wbmT4LB3lVQ_2 knife +wb9x3QDpcYA_0 person +wb9x3QDpcYA_1 person +wcOuc6Y3Gek_0 train +wcjnFIBHoc8_0 bear +wdb2-oX7HqU_0 boat +wdhqMpQcsjc_0 dog +wdhqMpQcsjc_2 dog +weH4PvRo2GU_1 bear +wgZbNzu2Mdw_0 person +wguspvl5Ioo_0 person +wg1ZFP15W8U_0 horse +wg6XS3q4Vg8_0 train +wifl75i2zGw_0 person +wiiV9QdYsYM_3 bus +wjfHYr4lXU0_0 cow +wmfJAE6gu7w_0 person +wmjfHsCs1CE_0 person +wmn4YG9rirU_1 bird +wmn4YG9rirU_0 bird +wmx0UeWsPyU_0 person +woEUh2mzEkE_0 horse +wqD1WkfidVw_1 bear +wr5b8Op3LUM_2 bear +wuAwZ_wX7jk_0 knife +wuFVuJjgpLk_0 airplane +wvadJ-1Ls80_0 person +wymDvXB08SM_0 person +wzBmon2jJxI_2 bird +wzlA0qMLDV8_1 cow +wzlA0qMLDV8_2 cow +wzlA0qMLDV8_3 cow +wzuQhwWLllk_2 bird +w0JzCkELpj8_0 cat +w0bfVrI7CPQ_0 bear +w1j-YVcZpfc_0 person +w2WW3bYmA7s_0 truck +w247rqoLoGg_0 bear +w3F_8A8kY7o_3 elephant +w3F_8A8kY7o_5 elephant +w3F_8A8kY7o_6 elephant +w3adXMIxupk_0 cat +w35-xR0Vn_0_0 zebra +w5Pb_ORVLKI_0 airplane +w6A2W9VQeZk_0 car +w6JEUZI5Vh8_2 skateboard +w6JEUZI5Vh8_0 skateboard +w6JEUZI5Vh8_3 skateboard +w7IKxGLuaQA_0 horse +w7g5pDCGteg_0 person +w8zrFmMpPmc_0 motorcycle +w8-ovxjadNo_0 train +w93q7lv9In8_0 person +w-eAEp0TUi0_0 horse +w-eAEp0TUi0_1 horse +w_euwPW5ukA_0 bicycle +xAUupk4sGI0_0 person +xAedjC0r5KY_0 person +xAfxJQL2_aY_0 zebra +xDgoaE-g50s_2 bear +xFnFWM8KXcE_0 person +xFzsK94M68U_1 person +xGbFeCuGypE_0 person +xHOcerZTZxM_0 person +xIUJ8zlr0TU_0 bear +xIizuktSVrM_0 truck +xJ_xdRV9lzo_0 cat +xKd8dHsveKg_0 person +xMiQuC8eKGU_0 person +xMp4dCjzI08_0 cat +xMuQzm__4bo_1 person +xMuQzm__4bo_0 person +xNBT-PZEMH0_0 bicycle +xOLvPvBg-8U_1 horse +xOtxf0cmHyA_2 horse +xPDDIKF9T3A_0 person +xRJNEyms-F8_0 train +xSIjCyHBypw_0 umbrella +xSIjCyHBypw_1 umbrella +xSL4NZUmhW4_0 person +xUB3mR57tLE_0 bicycle +xUtGzUu5Ryc_0 umbrella +xU_2MZdWfxM_0 cow +xVuNCF2vbXs_0 person +xWWnn5OWp4I_0 airplane +xYVriT4YV0M_0 person +xZLHtt1yjYk_0 truck +xZZ_W6fRi8E_0 knife +xbL4hiu8qh0_0 horse +xbQZucd8eu0_0 bicycle +xbQZucd8eu0_3 bicycle +xbQZucd8eu0_2 bicycle +xcY11ewiUMM_1 horse +xd_raY9PCHM_0 bus +xd_raY9PCHM_1 bus +xeAkz6Kg108_0 bird +xeBhbPbmS8w_0 person +xfzxTuJ85A4_0 airplane +xfzxTuJ85A4_1 airplane +xitZyv8gMgQ_1 horse +xjdEiJ_z4T8_0 motorcycle +xj3FKNXP-cw_0 bird +xkKoATbAX0w_0 dog +xkeTuOlBIMM_0 cat +xlT93OXr3uc_0 person +xlT93OXr3uc_1 person +xlfOatU3OyY_0 boat +xljqBqpwIHo_0 person +xl110TqE0kQ_0 cat +xmWAmSXnWCY_0 car +xo54E-kQcoA_1 boat +xpGDfRYqtSE_0 cow +xpcNJG8acpU_0 dog +xp_ShmZCoDw_2 airplane +xqNQIYHzAGk_0 person +xrGm-1D2Zqk_1 train +xsrHSco3Zcs_0 person +xsrNtKa0oZg_1 person +xs1kBHxDpxU_0 train +xs1kBHxDpxU_1 train +xs1kBHxDpxU_2 train +xtHE1-GIP_w_0 person +xtXt8Vm3Qps_2 dog +xuAm_BWnXRc_1 motorcycle +xuAm_BWnXRc_0 motorcycle +xucBFquWbi8_1 bear +xv4fy9zyuNE_0 person +xv6NQvvvIhk_1 bicycle +xxEtEzi7YiY_0 bus +xxcJJA7hCQY_0 person +xxdOVyEU-c4_0 person +xyg1xFLohGI_0 cow +xyyz5QJ7wi8_0 dog +xzC5_r9raeY_0 person +xzFcPnglQf4_0 person +x0RxwpR4wIc_0 bird +x0RxwpR4wIc_1 bird +x0nlchdJVJw_0 bear +x0nlchdJVJw_1 bear +x0q0JMiiw1A_0 cat +x0xsHmQGaB8_0 dog +x1RBYEheBRQ_0 person +x2MJ_zDJY3k_0 person +x2Tfa1fMOyE_0 person +x29EcPsdK1Q_0 dog +x29EcPsdK1Q_1 dog +x4h9pGwdSMU_0 horse +x4r2tx9_9wQ_1 person +x4r2tx9_9wQ_0 person +x4uX_33GiJk_1 truck +x48Ogx7C31g_0 person +x4-I_EckNls_0 bus +x4-I_EckNls_1 bus +x4-I_EckNls_2 bus +x4-I_EckNls_3 bus +x5nImw1YH94_0 person +x6sZc4EoI8o_0 person +x6298plJ-7M_0 cow +x7jo9uCmWA0_0 bear +x8VC2CXIDBI_0 person +x96LXIEQ3SM_1 cow +x96LXIEQ3SM_0 cow +x-2AUxPCkVM_0 person +x-26Z1zy1-E_1 person +x-26Z1zy1-E_2 person +x-26Z1zy1-E_3 person +x-26Z1zy1-E_0 person +x_CImXdwsg4_0 truck +x_XV2Y3pwDA_1 bicycle +x_XV2Y3pwDA_0 bicycle +yCYtcDx1zzE_0 umbrella +yCaJQKIGAjg_0 motorcycle +yCz3VdCGZMA_0 person +yDw-9GLrYj0_0 person +yF0X9hui-Go_0 person +yGD_BY9mQlM_0 boat +yIkwS9Vkq-k_0 elephant +yJOGbyQ8qs8_0 person +yJZU3h3_06M_1 cat +yLFd8GdaqBg_0 person +yLL5Dv2F1rs_1 elephant +yLL5Dv2F1rs_5 elephant +yLL5Dv2F1rs_0 elephant +yLNuhB7I5iI_1 knife +yLNuhB7I5iI_2 knife +yLkMk9nMaos_0 train +yLkMk9nMaos_7 train +yLkMk9nMaos_1 train +yLkMk9nMaos_2 train +yM9_GnJpXsM_0 airplane +yNnOUMUIIno_0 bicycle +yOrqtKYEfNs_0 train +yOrqtKYEfNs_1 train +yOrqtKYEfNs_2 train +yPscRV8ebRg_0 person +yQLGypU_WiY_0 knife +yTZekxz2awI_4 airplane +yTZekxz2awI_1 airplane +yT-tBu_wqEo_0 cat +yVO-nlNYxrU_0 person +yV1EsNcE3kY_0 airplane +yYIY-K1Hk-0_0 cat +yYUnGStTnHE_0 train +yYUnGStTnHE_1 train +yYr5tuCEb3w_0 cat +yY6S-xTKWGc_1 person +yaNT5d8H3ho_0 person +yahVo8Nqxks_0 person +ybCbkJl7tog_0 person +ybt9EtMfrdI_0 person +ydxMYuiOJAI_0 person +ygK39Pz1tKw_1 motorcycle +yhp30idsPKU_0 boat +yiCMaealOnQ_0 cow +yiujj_fUOg8_0 person +yjOTRS1-3Is_0 cow +yjUDTPRe-tg_1 person +yjnR7dP-hxE_1 bird +ykQnvD35jxs_0 bus +ymoggco-rpw_1 elephant +ynHMWKjfsNk_0 car +ynYz6f5FCOk_0 motorcycle +yoTs9WxR0mI_0 person +yo3wwD8VMLA_0 person +yo9gwC7gpEk_0 boat +ypC9L5um-ic_0 person +yp9kACFk9KU_0 car +yqWKo_T-YsM_0 person +ysb6LLJ0t-c_0 person +yssYMx-tQs4_0 horse +yu2v206waMs_0 person +yvDdzmW5jGs_0 cat +yxURDHgvWrs_0 train +yxURDHgvWrs_7 train +yyMtxTJNnUM_0 skateboard +yzE2GgYffew_0 person +y0HZlHGSvHk_0 horse +y0ptIotKNVU_1 horse +y0qGszhFtUc_0 bird +y2BOVk7bg7k_0 cow +y2BOVk7bg7k_1 cow +y2xzls--cC4_0 person +y2_iaWWx-C0_1 zebra +y3VNGZBlDb0_0 cat +y3hSeUaVwAY_0 bus +y34cSfArQnM_0 cat +y6nBJ0OUtDs_0 person +y6nBJ0OUtDs_2 person +y67A9YHKh1U_0 person +y8ib31rVZA0_0 bicycle +y8ib31rVZA0_1 bicycle +y8r2SJltJ1M_0 dog +y9hu6CyRi5s_0 airplane +y_O1AiuRLGA_0 umbrella +y_5uacneFuc_0 horse +zAvoyJ0_PSA_0 cow +zBtuA6r8o0M_0 cat +zCG95maa310_0 person +zCnZg9VP1xw_0 truck +zDs4lXFLJuM_1 horse +zD59UHvdpmY_0 person +zESRFobSQMU_0 truck +zESRFobSQMU_1 truck +zHRsZ9HlcBk_0 person +zIDehNZ1yiM_0 person +zIvzY3cVVbM_0 person +zI5cBWlyAMo_0 dog +zI5cBWlyAMo_1 dog +zJdOWFEL_CQ_0 person +zLflV_7noSM_1 airplane +zMhr8GZ1QeY_1 airplane +zMjW-G29IRA_3 bear +zMjW-G29IRA_1 bear +zMjW-G29IRA_2 bear +zMjW-G29IRA_4 bear +zNFb--FJ2A4_0 person +zNF5YxfaNTk_0 cat +zNfVxQPGrvM_1 elephant +zN8rF-AchY0_1 motorcycle +zN9Tz6jp7AY_0 person +zOLTybhsJ5s_0 cat +zORNq_7nmVQ_1 giraffe +zORNq_7nmVQ_0 giraffe +zOoxYmqzDyc_1 dog +zPvrRc94j6s_0 person +zP2DkEcgJFo_0 person +zP8Recx-KgA_0 boat +zQbeiOf9ljM_0 person +zU0g6JCyxAs_2 elephant +zVVQ63dPpe4_2 bicycle +zWQQBElMPYI_0 person +zX9OX5I2574_0 person +zYvjN5ShZDI_0 person +zYzASiLjHgY_0 person +zZ8f7oFIg_c_0 person +zbtsVe8RQqI_0 person +zb8-yrB5SlI_1 bird +zcgArp_fmjc_5 skateboard +zcsREBhC1Rc_0 dog +zdWtCunlv1c_0 cow +zdqJTtHvwk4_0 person +zd3rNWQ-OUQ_0 person +zgJHKszSf2o_0 person +zgJHKszSf2o_1 person +zgRxry9FvEk_1 horse +zgSx8Y5FaPI_1 knife +zhDC_SqN7lQ_0 bear +zhNNahIXxC8_0 bear +zjQG5PadkFQ_0 person +zj4cs0_VpTk_0 truck +zkSIG3AE7tY_0 elephant +zmDkkM7Buuo_0 cow +zmEU5n2Dy8Y_0 dog +zmdKmfMPuvA_0 bird +znTYxWfU2XM_0 truck +zpEtPFxxD5M_0 horse +zqE3Jnn6_gw_0 person +zqYLN7vCqcw_0 train +zqq508NRpOY_0 person +ztMFfJj7jb0_0 knife +zt3ojCKnIYM_0 cat +zwSnaqQ-5UU_0 person +zxiZnbMo3io_0 motorcycle +zxiZnbMo3io_1 motorcycle +zxzApvuo8Lg_0 person +zx0RzA6ts8U_0 cow +zyXxWBoTuww_0 person +zyXxWBoTuww_1 person +zyftQz018g0_0 bus +zy0lNSoVB0A_0 cat +zzRnX2EiOYU_0 cat +z0Tl2FDG69g_0 elephant +z1kOi92oBDI_0 truck +z1kOi92oBDI_1 truck +z1qQ7Ma5C5U_1 truck +z1qQ7Ma5C5U_0 truck +z18s4h6yW2A_0 bird +z2M6XJGE1QM_0 dog +z2RqakqNnIM_1 skateboard +z29ijVd-dvc_0 airplane +z3rcLKwHCxM_1 truck +z5-nsuFvaR8_0 motorcycle +z7FTg1R3Hik_0 horse +z7mLqljZMP8_0 person +z709zOu3tM8_0 car +z9HO__A5ryw_0 dog +z9wpJN1R63w_0 person +z-iM0zVi7a4_0 bus +z_CQX_gwU_o_0 person +z_w1gsSfZhQ_0 person +0AroA_SBRtQ_0 person +0BUPQDR99KY_0 bear +0DDYOUzExSY_0 person +0DGPzzGhUgI_0 person +0DHLS1VDcnA_1 bear +0EeBXB53BQE_0 airplane +0EnI7ZqJvqI_1 car +0EnI7ZqJvqI_2 car +0GzrKbW6Reo_0 person +0G0mSrzOZ2M_8 bus +0G0mSrzOZ2M_9 bus +0G0mSrzOZ2M_10 bus +0IHYTCKh8HM_0 person +0KWfi9m1uZg_0 horse +0KWfi9m1uZg_2 horse +0KWfi9m1uZg_1 horse +0L0JFDbAEZg_0 knife +0Neg9vT08to_0 cow +0NtpuqPU3YI_0 airplane +0N7yCdf7DPs_0 truck +0ORpOxJZo-Y_1 bear +0OqnKMwSULM_0 skateboard +0OqnKMwSULM_1 skateboard +0Pk8OLmmqrM_0 motorcycle +0Pu-_5lNYZM_0 bird +0QKe3M6GiT4_0 person +0Tu3KWEm4SE_0 cow +0Tu3KWEm4SE_1 cow +0TwpPpqiVQ8_0 cow +0U6SmZC1j40_0 person +0VKozmEWjZ4_0 person +0VaX_g70BaY_0 motorcycle +0ZGdpgF-bGI_0 bus +0ZQ_-4ia7z0_0 person +0c-Cwr5rI_A_0 elephant +0c-Cwr5rI_A_1 elephant +0fyRjxenSfY_0 bear +0fyRjxenSfY_1 bear +0f4alYlvEQw_0 person +0gelRcDsNio_0 airplane +0ghRNQFgHow_0 bicycle +0gl1mPRzCqo_0 person +0h9x35zsnyo_0 bird +0iLR3BtDujk_0 train +0iYm4g4D2wY_0 person +0iv0Xw_u-sc_0 bicycle +0i-Nv28lRT0_0 bicycle +0kZSWqFOr0c_0 person +0kidYsWSVvc_0 person +0mbZJnNhckg_0 person +0omh-B4giqI_0 umbrella +0owf_YERias_0 skateboard +0pAMIiK_RDo_0 person +0pm7YRiUKTc_0 horse +0qVc1Whb3GA_0 person +0qwRoiWnwmQ_0 person +0rQzfr4WVKc_0 cat +0sA23Q_HQr8_2 zebra +0sA23Q_HQr8_1 giraffe +0sA23Q_HQr8_0 giraffe +0sfu67JuBFg_0 person +0ss0_Sgy72g_1 skateboard +0tNuUAe5sNE_1 person +0tNuUAe5sNE_0 person +0txAuEdZYTI_0 motorcycle +0uJKDzuaiys_0 train +0urYbdFc55k_0 train +0utGbb5enqA_2 dog +0utGbb5enqA_1 dog +0vQFT9tfq40_0 person +0viKlMZRKdk_0 person +0v7GMl2k-Sk_3 train +0yCCEL3tl24_0 elephant +0zmzEkQWyps_0 boat +0zraBBQY8ew_0 umbrella +0zyhohOeIM4_0 train +00xcm8_ZTBc_0 person +01CYScp2Yc0_1 horse +01mkUffAvo8_0 person +02zor_ScZfo_1 person +02zor_ScZfo_0 person +03p9Ao9JvpY_0 train +03p9Ao9JvpY_2 train +03u5BWTYiRg_0 train +04Sh9tJvOAc_0 airplane +04UO1jSx2p4_0 person +04gNIg-kFI8_0 person +057f0LfDVoA_1 train +08Nunz5Qngc_0 bus +09jyC-o18uU_3 elephant +09kq3b7cMwc_0 cat +1AcsNm2kiok_0 horse +1BfbSv9ZCu4_0 knife +1BfbSv9ZCu4_3 knife +1BiqFD2BD7Y_0 horse +1C3_qaiKlwo_0 truck +1DHXDdSkk0s_0 bicycle +1DeIbpIRrAc_0 knife +1Dfkbv8bi9k_0 person +1Dz4x50F-RQ_0 dog +1EYL4Mm3dfA_0 bear +1EiH3PTqhLE_0 person +1ExRnJBXYP4_0 knife +1FVN3QOPlR0_0 person +1FVN3QOPlR0_1 person +1GJ0iwyNHIc_0 airplane +1JWHb6FAbmI_0 person +1Knz9s55vjc_0 car +1Knz9s55vjc_1 car +1Knz9s55vjc_2 car +1Knz9s55vjc_3 car +1LmCkh8Dd-o_0 dog +1MmlnQKtd6g_0 umbrella +1M6GhIT94zE_0 cow +1M6GhIT94zE_2 cow +1NThnoBEkmc_0 person +1ONRbj8GKJ4_1 bear +1ONRbj8GKJ4_2 bear +1ONRbj8GKJ4_8 bear +1ONRbj8GKJ4_10 bear +1ONptqLyHxQ_0 dog +1OSa1ptYmzE_0 train +1OSa1ptYmzE_1 train +1Ob23hwFaDg_0 motorcycle +1PSIOY62FBg_1 bear +1Pe9JpKgjGY_0 car +1P8yUGru9R4_0 knife +1RCZCLIZzc4_0 boat +1RGxleB_Ezk_0 person +1RKOWfpa5Dc_0 knife +1RuPxpqNjBI_0 horse +1Tpmsev8onw_0 cat +1TsLUvJiluI_1 person +1TsLUvJiluI_0 person +1UhZKsDTuQs_2 boat +1V-7ErZ83ZY_0 bus +1ZN9xVmQojU_0 umbrella +1ZbSl9tPtbA_0 bird +1Z7CVnRjVT0_0 person +1as5iG4PPas_0 bus +1bFvYEA0U3U_1 elephant +1bveGPhOKuU_0 cow +1cKjzUG0YCQ_0 bicycle +1ceprZO-VEU_2 train +1ecpkwMLabI_0 person +1fOM-kkuRsw_0 car +1ggOn5NDRco_0 cat +1hUe5E9cjiU_0 motorcycle +1iQKKup2m3I_0 truck +1iQKKup2m3I_1 truck +1iSjb4IlqfU_0 person +1i7lugA55RU_0 bicycle +1i7lugA55RU_1 bicycle +1kZMlCvKoe8_0 skateboard +1kZMlCvKoe8_1 skateboard +1kZMlCvKoe8_2 skateboard +1ksBabVqkMY_0 car +1ltK_3kkqfg_4 elephant +1l7LOpfDmXY_0 person +1ohoCoKJLDU_0 motorcycle +1oyjAtaWDZA_0 truck +1sQ3EL13Vqo_0 person +1tK31PAVNJM_5 elephant +1tK31PAVNJM_0 elephant +1tK31PAVNJM_2 elephant +1tK31PAVNJM_3 elephant +1v2enBiUcqA_0 bus +1wIGd0H1CUo_0 person +1xSI36nguW0_0 bear +1xs-ibIaMMU_0 person +1xyKgJUu0lM_0 skateboard +1zVWBQWZxV0_0 person +1zVWBQWZxV0_1 person +1zqpqKWhr1Y_0 person +10la9pvd-pk_0 knife +11kfBYxzlFA_0 person +12f1R5wMVPs_0 person +12_S_8HkAvA_0 person +1462k8mwVB0_0 elephant +15Lx-nGngUo_0 skateboard +18WxVaz5Ue4_1 skateboard +19A2XM5NIWs_0 person +19UmUpkjRbs_0 person +19oZ30mOTkU_0 boat +1-p8vd0PFQ4_0 dog +1_6ymF7z_iM_0 truck +2ASHEEgYHcU_0 cat +2CF0oQ38cBQ_0 motorcycle +2DM1oM4HFjI_0 motorcycle +2FXE_xO8Mb4_0 bus +2FvnQne8he8_0 train +2GTexq12sBY_0 person +2GTtMvLQqio_4 truck +2GZphW1DkS4_0 person +2HvVFwq85n0_0 person +2Hwu-YpHKw0_0 elephant +2H8AZ00ONQE_0 elephant +2IJ4H46ZxEE_0 person +2INYBScuPM8_0 car +2IqEaQ0oyQg_0 airplane +2JN_uMTDa9I_0 skateboard +2KWlj_ZAw94_0 horse +2KWlj_ZAw94_1 horse +2KWlj_ZAw94_2 horse +2K2gLrhP9AU_1 airplane +2K2gLrhP9AU_2 airplane +2K6iDBPdcHk_0 motorcycle +2LBHZoJ5skk_0 person +2L3uwdhZtV0_0 car +2MJHsLxKUBg_0 person +2MiqTBWBlEc_0 umbrella +2NjC1r6v4IQ_0 person +2O-2zfQxbnA_0 person +2PaTs4s2Ybw_1 bear +2PaTs4s2Ybw_7 bear +2PaTs4s2Ybw_4 bear +2Pa1anwpeKE_0 person +2Q3_TaV8vcg_0 dog +2Rc-oAwMJBs_0 horse +2Tp0YJi7JwQ_0 giraffe +2UpHhiQWzD4_0 truck +2VZlkg5HjME_0 cow +2WTwzNufol8_0 dog +2WTwzNufol8_1 dog +2WtNxQ0RBfc_0 person +2ZXlS-GRWAw_0 knife +2Z6wSOr0jLI_1 person +2a5TUccpQ08_0 dog +2a_-AyOXTXg_0 skateboard +2cFRz-musVA_0 airplane +2cFRz-musVA_1 airplane +2cFRz-musVA_2 airplane +2cFRz-musVA_3 airplane +2dZFWL9XGmw_0 cow +2fCH7TpvtlM_0 train +2fCH7TpvtlM_1 train +2fJ1hPXpiQc_3 knife +2fJ1hPXpiQc_0 knife +2gGuKs-4t94_0 boat +2i45n6p8AT8_0 person +2i_wjgk6DiA_0 horse +2lK0mmHTvB8_3 train +2lK0mmHTvB8_1 train +2lqlNq6aII0_0 skateboard +2lxPwFW5YQo_0 umbrella +2l2gnrYWuWQ_0 truck +2l7MPXzF64M_0 cat +2l7TuAfDgO8_0 truck +2mO7-ybapaQ_1 umbrella +2nqGkC9ebf8_0 boat +2oA7J6HSmt8_6 bicycle +2oA7J6HSmt8_9 bicycle +2tSpb14o7SA_0 person +2vF8Va9DGSM_5 bicycle +2vF8Va9DGSM_4 bicycle +2vF8Va9DGSM_14 bicycle +2vF8Va9DGSM_15 bicycle +2vF8Va9DGSM_2 bicycle +2vrbssf2sDM_0 truck +2v808Hn8_do_0 person +2v808Hn8_do_1 person +2yEUVUqYMPc_0 giraffe +2ya3SN5pLyU_0 car +2065vf90oIM_0 person +2065vf90oIM_1 person +21GQbN_4k9M_0 cow +21Hp5g5RrOc_1 person +21Hp5g5RrOc_0 person +22iFltXYCcQ_0 cow +22ztStWwd8g_0 train +22ztStWwd8g_2 train +22ztStWwd8g_3 train +23qU2q5u0OE_6 bird +24Zxq5TuxzI_0 cow +26kWe8Ikgxk_0 bird +28AecePdVok_0 truck +281z-ZLrI3g_7 bicycle +281z-ZLrI3g_4 bicycle +29bWSLuiEl0_1 person +2_R2wz82ugQ_0 umbrella +3A4oCDgMkHw_0 cow +3A-dEIjnmyE_1 skateboard +3Bag9o-z-Ks_4 bear +3DN2iQJzM-k_0 train +3DaASBRARLQ_0 cow +3D8wwibqkYo_0 cow +3EtIKWgGaKY_0 person +3FJ4ZWRq_S0_0 person +3GLXlSuXWcs_1 cow +3GQxmRKhMMY_1 airplane +3GQxmRKhMMY_2 airplane +3GQxmRKhMMY_3 airplane +3GQxmRKhMMY_4 airplane +3GULyU-IOhA_0 person +3HFqP9a97kA_0 bird +3IgOwKkKALw_0 cat +3LruhG4SULI_1 truck +3LruhG4SULI_2 truck +3LruhG4SULI_7 truck +3LxUuC1C4y8_0 bird +3L7LWpMShiw_0 skateboard +3L759GhRx6M_0 person +3MiM8HSul5A_0 cow +3MiM8HSul5A_2 cow +3MiM8HSul5A_4 cow +3M9T5RFr_9s_0 person +3OmdALGspY8_0 person +3O4ynxtRIDk_5 train +3O4ynxtRIDk_2 train +3RLrjX-XB98_0 person +3RhgYReCxjo_0 bus +3S-lQgiUWVU_1 horse +3S-lQgiUWVU_0 horse +3UDEQElT2yQ_0 train +3WhmVhG1ZwU_0 boat +3WrB7zPpcHU_0 cow +3XDvXaNmGpM_0 dog +3XDvXaNmGpM_1 dog +3X29L9uQCqc_0 train +3X29L9uQCqc_1 train +3Y7-acGE4Wc_0 person +3ZBYYBUfT6E_0 train +3Zwa4XoeZcA_0 person +3bSWlbx1o3I_2 bear +3cOMDXFxcOQ_0 cat +3dvUlr2yxz4_0 train +3g4c88ocJ38_0 skateboard +3hMszgfh_qA_0 bicycle +3hR78-EVNEE_0 truck +3jdK8UPhpO8_1 skateboard +3jdK8UPhpO8_0 skateboard +3kdpeeQ1Jnc_0 car +3kd_QEZRUWc_1 truck +3kd_QEZRUWc_5 truck +3lHqsoi5cgo_0 person +3liK-2EflUk_0 car +3mIRDwcY1Lg_1 person +3m5eMVv4z6w_1 bear +3nD6nhJtxIU_1 skateboard +3nbim5nlANI_1 horse +3q6LFZBelUs_0 person +3rSUjqH5Wlw_0 truck +3sEpU7UoQP8_0 person +3sg9txiHCp0_0 bear +3szPqA1S6P0_0 person +3tv_dUR84cE_1 airplane +3tv_dUR84cE_0 airplane +3uG4S1gvMxs_0 bird +3uVS_DAYfvY_3 car +3vuykX663QA_0 person +3wI_ureHDBY_0 train +3xLvnY9w5y0_0 person +3xy8Fz8Nsgk_0 bear +3zV0wmpiS78_0 person +3zccg30U6vs_0 person +30AwDyYIr7o_0 skateboard +325FEWXtOYw_0 person +3293hM-lzx8_0 person +32_1y90B5eQ_0 person +34L4iiCFTXM_0 airplane +34Pma_R21A8_2 person +34jFMRay1zg_0 person +35-MplWeZYQ_0 motorcycle +36zopo-HS48_0 person +38fx_nvlYDE_0 truck +39yxd86tGLU_1 boat +3-ugxoEDuFY_0 person +3_DeqcBRuwE_1 elephant +3_DeqcBRuwE_3 elephant +3_w3NNPGotM_0 person +4ARhlapmEmI_0 dog +4Ac5edN3qIA_0 elephant +4Ac5edN3qIA_1 elephant +4BItGVIP3_w_0 cow +4BItGVIP3_w_1 cow +4BO3P7E3NDE_0 truck +4BO3P7E3NDE_1 truck +4BO3P7E3NDE_2 truck +4Bw4gKDBQCM_1 dog +4C8rmAORSg8_0 person +4Dcg1W7RRmQ_1 train +4ENxW7OPynQ_1 car +4ExA1FWRfMM_0 dog +4FVfzA07rVs_0 person +4FVfzA07rVs_1 person +4GgzQqhrTmA_0 train +4GrMZIyjUdo_0 person +4IUjw1DfTd4_0 cow +4ItJTYAUV3Q_0 cat +4IxmhmTsSRM_0 person +4I72WJJrc1o_0 person +4I72WJJrc1o_1 person +4KFEzxXCjmw_0 car +4KYtNfb0-64_0 person +4KqP6ylUZpI_0 umbrella +4LHOLAPnjV8_0 boat +4LXlXP1epJE_0 person +4MFPOb36tfo_2 bear +4MFPOb36tfo_1 bear +4MZrjdSF01s_1 boat +4Me3lyNuZ7k_0 person +4M9sKAzevzo_0 train +4NI5ycFo2TA_0 airplane +4NI5ycFo2TA_1 airplane +4NKnUR1OMGo_0 horse +4NKnUR1OMGo_1 horse +4Ng6OxFQ9RY_3 bear +4Nx45ho9gSg_0 person +4PNJ3ZV4f8E_0 airplane +4PNJ3ZV4f8E_1 airplane +4PNvdZPZIdM_0 train +4PhakAK74GE_1 motorcycle +4PxLGSy75rk_2 knife +4QOhfEMrhzU_0 airplane +4Q0M6mWNDiU_0 horse +4RhaYtFsnGY_0 person +4SrP2aSHoRk_0 person +4TyWpb19rk4_0 umbrella +4U9sm_eqKTM_1 car +4U9sm_eqKTM_2 car +4Xd_k2REw4I_3 bear +4YRd-9lHLko_0 truck +4ZIgGDQB_R0_0 airplane +4ZYWcd-Fdzg_0 person +4Zxsg6aJ9tA_0 person +4aOWHpM7rOM_0 skateboard +4avaoLry8L0_2 skateboard +4bHGieqZfUk_1 knife +4duFrAfYG8k_0 person +4d6P5umc9j0_0 bird +4fIznTWAFRw_0 horse +4fIznTWAFRw_1 horse +4fIznTWAFRw_2 horse +4f_X4WbQu4M_0 elephant +4hCLCX2lLGk_0 person +4iBMfS5mIt8_0 bird +4ibKNzoA1tQ_0 truck +4igLFns238c_0 motorcycle +4kGNxHIXcUA_0 person +4kLhVZ9UGDE_0 skateboard +4lC7BU1eHxc_0 bus +4l683stlRno_0 knife +4mv1Nx0j3k4_0 person +4nz8CN4XlBE_0 dog +4oWXZIsPnEg_4 elephant +4ofuHARhFlQ_0 person +4pYH5Cm7Vkg_1 boat +4p3JGxvfiNE_4 bicycle +4p3JGxvfiNE_8 bicycle +4p3JGxvfiNE_10 bicycle +4qBYTh0AcfM_0 train +4qIx-9Qs3Zs_0 airplane +4qIx-9Qs3Zs_2 airplane +4qRkIra0ARM_0 person +4rhkfDV0QC8_1 truck +4ry_MJjFDUA_0 cat +4skAfQd8nX8_0 person +4t79zNxVi0Y_0 elephant +4t79zNxVi0Y_1 elephant +4uFHcf-qpkU_0 horse +4uwly-P5oxg_0 person +4uwly-P5oxg_1 person +4u7pm-h8fiE_0 person +4wox28JkSKY_1 person +4w3ykGq-Q_E_0 bicycle +4w3ykGq-Q_E_2 bicycle +4w5q5RdJ5g4_0 horse +4w5q5RdJ5g4_2 horse +4w5q5RdJ5g4_4 horse +4x80RbpjCPM_0 bear +4x80RbpjCPM_4 bear +4yFIyyevEVY_1 airplane +4ycylGSteiU_0 truck +4yjvwunpMKI_0 car +4yjvwunpMKI_1 car +4yjvwunpMKI_2 car +4yw2hFyx47Q_0 person +4y3qJAq5ap0_0 car +40QgDL4dxrc_0 airplane +40deMboVqPI_1 bird +44FNsfkuWOI_0 elephant +44hlNbUHL2c_0 person +44672wUoOwM_0 person +46NXMVbpzZw_1 boat +468w3XkLHwc_1 boat +47Nn3ywWOlU_1 person +47cBD-Sq9mw_1 person +48ujtCaCdX0_0 person +49CwzbRIUpI_1 bird +49a6EgDu-ZU_0 truck +4-GpBan9Z8s_0 horse +4_A8f6NAa3w_0 person +5BHekdOG9JA_0 elephant +5Bw22C4nsb4_0 train +5CPZUe4hn0M_0 airplane +5DS23LkFit8_0 cow +5DVU9wTDzN8_0 skateboard +5DjSsYt5N4Q_0 skateboard +5FAbvaslTQE_0 motorcycle +5FXOzzaKrcw_0 airplane +5Fro7Bo628Y_0 boat +5FxLl3jd7I0_0 skateboard +5F5fgLUXow8_3 car +5F5fgLUXow8_7 car +5F5fgLUXow8_8 car +5F5fgLUXow8_0 car +5F5fgLUXow8_1 car +5F5fgLUXow8_2 car +5F5fgLUXow8_4 car +5GMISyAZA9o_0 horse +5GpziDmwRTc_0 cow +5JPqrGj3CgM_0 giraffe +5Ko6ZHOz4IY_0 person +5Lbguv7FGLM_1 bird +5M7Wx_HJ_XQ_0 person +5Nz4g-YykuI_0 person +5O41yfenxMM_1 cow +5PeDI6XI7is_3 horse +5Qd986abGHo_0 person +5Tza7UHp3xE_0 train +5WTw98UVUCo_1 horse +5WpjuP9uJrI_2 bird +5W8Hg8uhxgQ_0 car +5W8Hg8uhxgQ_1 car +5XEAIdyb_ng_0 person +5XcopMzRch4_0 skateboard +5YbA5Uw-5xQ_0 person +5YbA5Uw-5xQ_1 person +5bIO0Gl25u0_1 boat +5bIO0Gl25u0_0 boat +5dGbxAkTDPM_1 cow +5dRnssv_jug_0 cow +5eRQh3Rv1Lk_0 horse +5eak0nLYZC0_0 airplane +5enKNMe1Dpg_0 person +5eq6WBGMyME_0 giraffe +5eum6r7kxbw_1 giraffe +5eum6r7kxbw_4 giraffe +5e84K5OEIj4_0 person +5fXoyIBk_gI_0 person +5gNgZQ0nDW8_4 knife +5gNgZQ0nDW8_5 knife +5gNhZJMFmis_0 bear +5gNhZJMFmis_1 bear +5gbLo2hItTs_0 person +5geZjQ9qAJU_0 motorcycle +5iDhgUX1kdc_0 person +5iwoWJK4GGo_0 car +5ll8fjNhIzg_0 person +5lv2GCs3_E0_0 person +5l9rlcuS7pE_0 bus +5mocfP3c3JE_0 bear +5mqvNWXtMCU_0 cat +5nAuDbKmWLY_0 elephant +5nC2ZXfE-sg_0 train +5nkh3PK6lBs_0 cow +5of5t38DQL4_0 cow +5okxoIw3cJI_0 skateboard +5ovlgihl130_0 knife +5phhj08_8hI_0 dog +5psIBlFu-yQ_0 person +5rh7nf5z_O0_1 cow +5rkM4mLsQoU_0 knife +5sIj93XnVc0_1 motorcycle +5sjUnvABkko_0 airplane +5s4kqURLLo4_0 person +5toRpAYrY_4_0 person +5uYObEyAbCQ_0 horse +5ukcjpXOopg_0 person +5vPXxAEGTrw_0 airplane +5vUtusnPXXs_0 bird +5vaBUAh4HkU_0 airplane +5yMeqHPiJgY_1 horse +5yMeqHPiJgY_2 horse +5yMeqHPiJgY_3 horse +5yeSANffSRk_0 person +5yeSANffSRk_1 person +5zJuhMtO1F8_0 bird +5zKtWxffw-0_0 boat +51rDJW0FO8w_0 horse +51yQTVmaMXw_1 motorcycle +52UjkVxSSHg_0 person +52VFNDCXUHg_0 person +52pNzl4wrxs_0 person +52wdqvYrGv4_0 person +522wkm19sH0_0 bus +54icMYqqx_w_1 bus +55H1IVgQj3E_0 boat +56BI7lH0z1g_0 person +56bgv0J-cXw_1 knife +56bgv0J-cXw_4 knife +56r2wDCnuQQ_0 horse +57BY7QjcYbQ_0 person +574FA_5qp-s_0 bus +58K_ZPS7U8M_0 person +58gdyHWU6do_1 truck +5802XdQdAkU_0 cow +59JJGcB2jRE_0 horse +59JJGcB2jRE_4 horse +59JJGcB2jRE_2 horse +59cXOQc39JI_1 zebra +5928Zhy26yI_1 giraffe +5-Oeo8tmauc_0 bus +5-Oeo8tmauc_1 bus +5-Oeo8tmauc_2 bus +5-O2xma48Tw_0 bird +5-y_Rrr8shw_2 person +5_njhyGAXdE_0 truck +5_njhyGAXdE_1 truck +5_njhyGAXdE_2 truck +5_2sGSrZblY_0 person +6AD9GHHEVkE_1 boat +6AYkCla5Oak_0 car +6A2LC4_gts4_0 person +6A2LC4_gts4_1 person +6BB65BA-pS0_1 knife +6CKS3WJRpHI_0 person +6C1C-L7L6CE_0 person +6DQ-H73b62Y_0 person +6EHcwJiML3g_2 person +6GlBa-DUEqc_0 person +6HlTwF1ZDkc_0 person +6HrWOx9GfzI_0 person +6JrhpITR8po_1 cow +6JrhpITR8po_0 cow +6KpKxtwB1Ww_0 person +6LiW0KF3fME_0 person +6Meaw8zK8sU_0 person +6M3wDWZDZJ8_0 car +6M4oJG9NsRM_0 person +6Nc1z3BVzlI_0 bear +6OlxDr5vZuI_2 horse +6Ona04rOyZk_0 cat +6PBKPTCkWOo_0 person +6PH-mFChsi0_0 airplane +6PwE6q6pebc_1 person +6QFs4uNsSt4_0 person +6RIFox7kLqY_0 cat +6SBj14dkVPM_0 cow +6SdX0oE9Qm8_0 cat +6SizSdOT9_k_0 horse +6TEQ098RfzE_0 cow +6TQ8X9G4BAY_0 dog +6UQbOOWv_ws_0 cow +6UQbOOWv_ws_2 cow +6XUe2u2YWkQ_2 umbrella +6bJPo4tzJvQ_0 person +6bco275PcUs_0 truck +6bco275PcUs_1 truck +6gwBOlfJ34I_1 skateboard +6gww5ltOLQY_0 bird +6gww5ltOLQY_1 bird +6hAG7632JjA_0 cat +6htKDjHsXPQ_0 cow +6id5A0aiJbE_0 train +6jwTUZocHXY_0 horse +6j07-PcNv70_0 truck +6kjb3q8EygI_0 elephant +6lAxaY4AYB8_0 person +6lPPfWdeBvU_0 cat +6l3SpVgqJY0_0 person +6mYi-vXre4Q_0 truck +6med3JZ2k40_0 person +6miVJWDTBCY_1 train +6n6fVeWD_m0_0 knife +6o61j0KZ9cA_0 person +6pPjKIlVlfY_0 bicycle +6pnenPlFGIc_0 motorcycle +6pnenPlFGIc_1 motorcycle +6pny8Td3Lvs_0 horse +6qRIuIHqJco_0 train +6qSDUh2ES7Q_0 person +6qVpY1VC2hU_1 cat +6qhp1FiVbBQ_0 knife +6rlBtCRp25g_0 cat +6r0rYZCL4Qc_0 person +6r0rYZCL4Qc_1 person +6uMmknjq0mg_0 bicycle +6uSZqFsKMGI_0 cow +6um2PoiKfT4_0 motorcycle +6vAGEaKFuyY_1 bus +6vAGEaKFuyY_2 bus +6vafM_LKdhA_0 umbrella +6vc8u4MPWkY_0 bird +6v_NKAM10sA_5 bicycle +6v_NKAM10sA_9 bicycle +6v_NKAM10sA_10 bicycle +6v_NKAM10sA_11 bicycle +6v_NKAM10sA_12 bicycle +6v_NKAM10sA_0 bicycle +6v_NKAM10sA_1 bicycle +6w-nwNFVYm8_0 motorcycle +6y78kiGuIAk_0 person +6zPET0HFVaM_3 train +6zPgsocp4bY_1 bicycle +6zPgsocp4bY_2 bicycle +6zPgsocp4bY_3 bicycle +6zPgsocp4bY_7 bicycle +6zPgsocp4bY_9 bicycle +6zW1omjPFRs_0 elephant +6zW1omjPFRs_1 elephant +62MEsd3U1aQ_0 person +62PpG0cOcbU_0 person +63vKOQ-SCBw_0 airplane +63_kFJCm2pQ_0 person +64yGcACuF0g_0 cat +64yZxDGH92I_0 person +64-njkqyF7k_0 bus +65u4BXZ10RY_0 dog +65u4BXZ10RY_1 dog +654ylXfWndU_0 boat +66HPgc7Up3o_6 horse +66HPgc7Up3o_3 horse +66HPgc7Up3o_4 horse +66HPgc7Up3o_7 horse +66N_Ju8hg2U_0 knife +665JKK-JrTc_0 person +67kix34dj7A_0 truck +67wgEifQYpg_0 person +68KnEa1hVf8_0 bicycle +6-Z9S0qy8ys_1 dog +6-7x1BQGuQE_0 person +6_nq4o_21CY_0 elephant +7BBHz6wfABM_0 person +7CYm8WQftfw_0 bus +7DIXCjEBWLw_0 airplane +7D-ypPzaTDI_0 person +7GvsFRhnxWc_1 bird +7G2sXxpbA-0_0 motorcycle +7HXox1j1X2A_0 person +7Hthj7LhsoI_1 elephant +7H1AhHiyip0_0 person +7JXhfaNTsUQ_2 bird +7K61aiu3UsM_0 person +7K61aiu3UsM_1 person +7LKG4ReUlZA_0 person +7LTKFUY3Xo8_0 bird +7MQZWaHzUOo_0 cow +7Mb_dcvNENM_7 bicycle +7Mb_dcvNENM_3 bicycle +7Mb_dcvNENM_4 bicycle +7Mb_dcvNENM_5 bicycle +7Mb_dcvNENM_6 bicycle +7NDhXBp57BY_0 person +7NFMDZwqdw4_0 person +7Ng49Wed4Y4_0 cow +7Ng49Wed4Y4_2 cow +7NxvW5DSQrI_0 cat +7O8grUKQopY_0 person +7PeZgsBNi5g_0 car +7QauV6mvt98_0 car +7RxzfGFIxSg_0 cat +7Strg7qJtW0_0 elephant +7Strg7qJtW0_7 elephant +7Strg7qJtW0_1 elephant +7Strg7qJtW0_2 elephant +7Strg7qJtW0_3 elephant +7VQ8QZRnxD8_0 cow +7Vcfkjk--Fc_1 dog +7V5Q7Te4KNI_0 bus +7WZRhdW3Ysw_0 elephant +7XQ-ufhX7gc_0 cow +7XQ-ufhX7gc_1 cow +7YCox5adS-U_0 person +7YQM-nFSHW4_0 knife +7Ya_jh9VO9U_0 person +7aTla4KAK_U_1 knife +7bqlApH5GwI_1 bicycle +7dFEYp-1Hgo_0 person +7e8WNmzDHUQ_0 person +7fF7heSCMTw_0 motorcycle +7fRxyCT-Wao_0 giraffe +7fRxyCT-Wao_2 giraffe +7fSMUG5W8vk_2 bicycle +7g8SI9aAn70_1 umbrella +7hIJP5KExbE_1 elephant +7hjOcuaQm7I_0 elephant +7kPsaqRQBCk_0 knife +7kl1hNW3aVs_0 motorcycle +7k7H9RKhOF8_1 skateboard +7k7H9RKhOF8_3 skateboard +7ledBa3nuVs_0 train +7ledBa3nuVs_2 train +7m98zjjFHbU_0 person +7ntsSm-LFZA_0 person +7ntsSm-LFZA_1 person +7nzY38tPTM0_0 person +7nzY38tPTM0_1 person +7n8C_td0Th8_0 horse +7p4RxRFB_Eg_0 horse +7rE5dIroJwQ_0 person +7rifGM-TuPA_0 horse +7trl2U6nLPc_0 horse +7vyHv7_GxbQ_0 person +7wte1pPBwQ0_1 bear +7w616uMnI_8_0 elephant +7w616uMnI_8_1 elephant +7x8K4JervhE_0 bus +7y0joj813H0_3 bus +7zRaB-2B7B0_0 train +72RzEHZFYtM_2 airplane +72RzEHZFYtM_1 airplane +73Wonc3xnLI_0 person +73Z4KnnAMlU_0 person +74gRlu6vJLY_0 person +747bRdBUPSw_0 person +76LU6w1a7UA_1 airplane +76PIBEC3WVo_0 skateboard +77GychcVDRI_0 person +77dvi_3OU4M_0 person +79MY0qku9uc_1 horse +8AgZqrCi9no_0 horse +8BK44tI3ACo_0 person +8BQJVHpHFsU_1 dog +8BQJVHpHFsU_2 dog +8B3bbakza_Q_0 person +8CJRCoA1Rps_0 person +8ClOgfNAjXs_0 giraffe +8DlXcc1IXlw_0 car +8EwDzFi34nA_0 cow +8FEp5ORJ27g_0 truck +8FyuS809d24_0 dog +8FyuS809d24_1 dog +8GGi0BXLCaM_0 person +8G_vBzM-Ws4_1 umbrella +8HcyzPUv5ag_0 person +8JIpa6tfWzo_0 airplane +8JKJnuN_UTI_0 cow +8JhHIO_7m-0_0 cow +8LGnOH6nDbc_0 dog +8LGnOH6nDbc_1 dog +8Lx004yCltY_6 elephant +8Lx004yCltY_12 elephant +8Lx004yCltY_18 elephant +8MO_kng7L-s_0 person +8MO_kng7L-s_1 person +8NlznvdsNJQ_2 boat +8N8hB2Au4JE_0 person +8Pbd3dd3v5E_0 person +8Pz3xq3KFo0_6 elephant +8Pz3xq3KFo0_4 elephant +8Qr-5_567tI_1 truck +8Q8g9z-DNF8_0 motorcycle +8RZsKbffdqI_0 cat +8Sbz2MGzhp4_0 person +8UcqXCLmq-M_1 elephant +8UcqXCLmq-M_3 elephant +8UcqXCLmq-M_6 elephant +8UcqXCLmq-M_7 elephant +8Ul_lS0g_RU_0 skateboard +8UmKRVMR08g_2 bird +8U7BmrkcgcU_2 truck +8VkbfdMQrR8_0 person +8VzjERSpeS4_1 elephant +8VzjERSpeS4_0 elephant +8WcBoYh-IMg_0 bird +8X27eyH-tx0_0 car +8Zi2bsTpMeY_0 person +8ZmfZDMaVhg_0 cat +8Z1GvAHPEnU_0 cat +8a1bD-UgfKE_0 truck +8bD-aqWPxwM_0 motorcycle +8bE_FhrjBuM_2 skateboard +8bE_FhrjBuM_0 skateboard +8bE_FhrjBuM_1 skateboard +8bypIjdKgEI_0 person +8b5fedIr-WQ_0 person +8cNzCe26dSM_0 person +8cSOpd9gaPE_0 cow +8c8TJ_Jzngk_0 horse +8d6950aGpD8_0 dog +8eK3ktD9j5o_0 horse +8eK3ktD9j5o_1 horse +8ewNcrMhg-w_0 person +8gsiG2Wu3YM_0 giraffe +8hFEJz0GvfU_0 elephant +8hwa44VMdLs_0 person +8h8Cpkugo-Y_0 elephant +8h_eY7zEIqk_3 truck +8iBiHoA_OJk_0 person +8jRFQ8RKZ0s_1 car +8kTREwiI1-8_0 cow +8kn6PJbtsyA_0 bicycle +8kn6PJbtsyA_1 bicycle +8kn6PJbtsyA_2 bicycle +8kn6PJbtsyA_3 bicycle +8kn6PJbtsyA_4 bicycle +8lKXEr2W3yM_0 knife +8lMRKCKyBwk_0 person +8lonNtE99PI_1 person +8l7UmXXnAJs_0 truck +8mlHevSC8cc_0 car +8m-GtOBjbzY_1 bicycle +8nWSGwlJyPQ_0 cat +8nsl-r_i0AI_0 person +8n3A8io4GNU_0 person +8okfUuO0Pvc_1 bird +8poWB-6q4xk_1 bicycle +8p2saqn2kiQ_0 person +8qFJg_AoKeY_0 cow +8qulLm8MYrM_0 bus +8rBxRMDJEFY_0 person +8sOWPIfWpCM_0 horse +8tKto2zQWUg_0 elephant +8uoYlmdJlAo_1 knife +8wdvLn40CTk_5 bus +8wdvLn40CTk_0 bus +8wdvLn40CTk_1 bus +8wv3WJBJmog_1 dog +8yFZUTSjpos_0 motorcycle +8zBx-nHUqBY_0 person +8zUAF30Hu6c_1 train +8zUAF30Hu6c_2 train +8zftjn0I9TQ_0 truck +8zftjn0I9TQ_2 truck +8zjgYuK3nVY_0 person +8z-YLOzAxb4_2 bicycle +8z-YLOzAxb4_4 bicycle +8z-sTr28AWk_0 skateboard +80CcMFD-Rcw_1 person +80CcMFD-Rcw_0 person +81cNVk8boEM_0 person +82lK9rB-e08_1 motorcycle +84P6L_HrN48_0 bird +88N5__h7Zdo_0 bicycle +89a461_gh2o_0 bicycle +89mGhzBokZ8_1 bear +89qfsC77BYk_0 person +8_oUj2cuPdo_0 dog +9A-VO1zCZJ4_1 motorcycle +9BVgbNz-bi8_0 person +9BVgbNz-bi8_1 person +9BpvtvUGG5g_0 person +9DGpFjuUVBk_0 person +9DY0dTRH5xI_0 bird +9D5ORdC7BuQ_6 bus +9ELQq5BMR1U_0 person +9E8VBIYmTGY_1 cow +9E8VBIYmTGY_0 cow +9FAB9BrcQls_0 person +9FTOvdcnzDQ_0 airplane +9GdhKEBm0pA_6 bicycle +9GdhKEBm0pA_1 bicycle +9GdhKEBm0pA_3 bicycle +9HqapwdLVzk_4 knife +9KfdTsjy53o_0 truck +9LHbQA-pT0U_2 horse +9LJRUmW_AII_0 boat +9LOpNoTFWKg_0 truck +9LOpNoTFWKg_4 truck +9LOpNoTFWKg_1 truck +9LOpNoTFWKg_2 truck +9LqExSHe9y8_0 knife +9Ls7gSZQt1w_2 bear +9NsmnTdRiik_0 airplane +9PsezNNV0Jc_1 airplane +9PsezNNV0Jc_2 airplane +9PsezNNV0Jc_0 airplane +9Q3srzApSJU_0 person +9RGlWjTKvE0_0 bus +9RZCK24Shec_0 cat +9ScZtgWAJZA_1 person +9SgrA5Q1d94_0 person +9ShZpsmuvc4_2 skateboard +9ShZpsmuvc4_1 skateboard +9UU2h6M8DJk_2 truck +9UwLiWKOIGY_0 person +9U-tccGetsk_0 knife +9VwSYjCCRYk_1 truck +9VwSYjCCRYk_2 truck +9WDPvYpnrfU_1 truck +9WDt0JjOFIA_0 person +9YVkZ7QxD5E_0 person +9Y6XZFO31JU_0 cow +9ZpZZoTtySo_1 bear +9Z0Jz1tesQ4_4 cow +9Z0Jz1tesQ4_1 cow +9Z0Jz1tesQ4_2 cow +9Z0Jz1tesQ4_3 cow +9aQOAnspXGo_1 bird +9bYPYgMQVjU_0 person +9bzmQFGK8m8_0 person +9dOPPvgyMqk_0 person +9eI_0DoOE08_0 person +9eI_0DoOE08_1 person +9g8o260G10k_0 bird +9hAU80xKWy0_0 truck +9jS5MThAtmo_0 person +9kGuuCx39JA_0 motorcycle +9lsXenPJ-X8_1 bird +9ltdzlYXfp8_0 cow +9ltdzlYXfp8_3 cow +9muklrcigJY_0 dog +9nqU8e9IUPU_0 skateboard +9pEB8cjvPSQ_1 horse +9qamzN9bwxw_0 person +9rvVWyyuud0_0 person +9r1FvK19XV8_0 person +9uhZRDsQKnc_0 person +9yt1if13PHk_0 elephant +9y5txKR57mc_0 bird +9zBCjCtH3Eg_0 horse +9zqk5w8Qx1Q_1 bicycle +9zroWMwZHGI_1 person +907A5I4-LpA_0 motorcycle +91SWvU-5TcI_0 person +92MaWPuO8PI_0 boat +92560YiwSP0_0 person +93gyPa_dPGU_0 truck +946wiAK4Seg_1 person +95CV_olHtcI_0 person +96WWGXa4QrI_0 car +96akJFw5SPU_0 truck +96iqXHgOXKY_0 person +98XiF-Z__aI_0 cat +99Tb7HSFn3I_0 person +9_bFE0FUq_c_1 knife +-A-tBuMjU8s_0 cat +-B4YQQLrOfI_2 skateboard +-C0rYHhL_x4_0 motorcycle +-DYf49hlRSE_0 person +-Ebcfmg0-eE_0 person +-E05a-eQSwY_0 umbrella +-FMaVn21dYU_1 horse +-Fu9coX9J-A_0 person +-Fu9coX9J-A_1 person +-Gk4iMiEMCc_0 person +-LVtIbelA3M_0 horse +-LXr7LdXtrk_0 boat +-LjAFTF5WP4_0 bicycle +-LjAFTF5WP4_1 bicycle +-LjAFTF5WP4_3 bicycle +-MpLPuviQ00_0 person +-M_jT3EYgcc_0 person +-NWvB2g952Q_2 bird +-OZt785bbpY_0 airplane +-P37Y1G6oHk_2 airplane +-P37Y1G6oHk_3 airplane +-P37Y1G6oHk_0 airplane +-QBeUV_OkJg_1 dog +-QQCINzsXpw_0 person +-Q6g2xZ0PxY_1 airplane +-RjxMfaV-Vo_1 knife +-RjxMfaV-Vo_2 knife +-SPHavKGd3M_0 skateboard +-S8L2HACCPE_12 elephant +-S8L2HACCPE_1 elephant +-S8L2HACCPE_10 elephant +-TKKOo1FfAI_0 bird +-VgWHKeRRjs_0 airplane +-VgWHKeRRjs_1 airplane +-WyEyKxdZOQ_0 person +-XWeGpACKwc_0 skateboard +-Xj6MiGVWt0_0 person +-XwZnoNm0FU_0 dog +-ZDO95E0pl8_0 person +-anX-ad_gHQ_0 person +-avz2OsPIq4_2 bicycle +-bJkl4q5f-A_0 bird +-c1b7nHzGn4_0 airplane +-dQnNlBQp3o_0 person +-db_SToBhkg_2 motorcycle +-eZUdm8ERQQ_0 person +-e42Pb0YeOY_0 cat +-fnhznKC3CU_0 person +-f0JLwuyuTM_0 person +-jL0HOXwYls_0 person +-kLIF2a7yeU_0 person +-k1TxEpOgnA_0 person +-l9NS6DuRPI_0 person +-mgNwLW3ODc_0 person +-mwDgqLpu-k_0 skateboard +-nOfuA8B7As_1 bicycle +-nzXunuZac4_0 cat +-oG6YVPhC_I_0 horse +-o28rb1UnYA_0 car +-sJOJNjOCBI_0 motorcycle +-sJOJNjOCBI_1 motorcycle +-sWch1rnO10_0 person +-th9NS9hl6s_0 cow +-uP01llwXFY_5 boat +-uP01llwXFY_1 boat +-u5MNR-9ClU_0 person +-vkMKVuweFA_0 person +-v7FXEhgwtE_0 person +-y652b4w3Ss_0 bird +-zqHD6Jthqg_0 person +-0U1vm6LIi8_0 person +-1je1K1ihbk_2 skateboard +-2iw3MzUP2Y_0 motorcycle +-3OvKcu5P2U_0 car +-3fzr21Ov5w_0 person +-6vJDV8XnWE_0 boat +-7Im8MyvaXU_0 cat +--8shIp3t0I_0 knife +-_iBuJTwjw8_1 horse +-_xag4X_Do0_0 bird +_ATEx5gbBEQ_0 knife +_ATEx5gbBEQ_1 knife +_AcvI8VF5ig_0 cow +_Ae4vmwt8uA_0 person +_Auvs-o5Pck_0 truck +_A8nA25Tq8c_1 person +_C_yvxdjVGA_2 horse +_C_yvxdjVGA_0 horse +_DXAxnPIiBU_0 cow +_D-9w3aSX50_0 person +_GyE3cPQ6U8_0 car +_HN1_MjnjWo_2 elephant +_HYaLoOKE84_1 cow +_IhkqtAQHBw_0 train +_InrHPE8Umw_0 motorcycle +_IpUnYit3Pg_0 dog +_JNG6qK6INs_3 bear +_KzDIvt0cCk_0 person +_K6jYgDC1JU_0 airplane +_NZ4o-omJLE_0 umbrella +_NtOMcyVAp4_1 dog +_OmnjH4t-IY_0 person +_QF0A9B-xB8_0 person +_QRy9nd4kcg_0 airplane +_Q9M8QAjSMk_0 person +_Rd-wEO2r10_0 person +_R6nlDzh6Tc_0 person +_R6nlDzh6Tc_2 person +_T0O1BlYjaU_1 bear +_VegkTdhrQE_0 motorcycle +_WKJaPPBz8Q_0 umbrella +_WcqTpLKkww_1 truck +_Y6_E1l4blQ_1 knife +_ZDU4qi4lcI_2 cow +_ZDU4qi4lcI_0 cow +_ZDU4qi4lcI_1 cow +_ZHmkH59bCQ_0 person +_ZXqLyRe4n0_0 elephant +_ZsogS9uPJQ_0 person +_akq_DieEWE_0 person +_akq_DieEWE_1 person +_bO2sdIelLY_0 person +_dC_upYbxWI_0 knife +_eCb7mFYyIg_0 motorcycle +_egWujmdZtw_0 person +_epdfuB0qRM_0 car +_e5Vvy9DJ9E_4 bear +_e5Vvy9DJ9E_0 bear +_foK5Dvj1As_0 bird +_hryEVGKNuw_0 horse +_iY4AnGfq0Y_0 train +_jBzwdg0QRA_1 bus +_jci9tIBIB4_5 truck +_kdhlRke8uI_0 person +_kfdh_5bI-Q_0 person +_lmD-useijU_0 person +_mJBwuCegJ0_12 truck +_mJBwuCegJ0_1 truck +_mJBwuCegJ0_2 truck +_mJBwuCegJ0_8 truck +_mJBwuCegJ0_9 truck +_oRtPVRmtwo_0 dog +_pEHwWe2seA_5 elephant +_sV1Jd1uiYg_0 person +_tZU1XTOML4_0 boat +_usyDpllGBo_0 horse +_vBAv8cBoqE_0 skateboard +_vV0wdWq0cU_0 person +_xMVx44FbT4_0 horse +_xQn3TupjYs_0 cat +_xy58m6yCko_0 motorcycle +_yQQjARqD1s_0 boat +_yfoe4GCA0Q_4 airplane +_yfoe4GCA0Q_2 airplane +_yv5Cwbm9EA_0 person +_zIDofZkgS4_1 truck +_zQt1CSSKyA_1 bicycle +_0eR2vQAEqE_0 elephant +_0eR2vQAEqE_1 elephant +_17u-cPTYt0_0 car +_17u-cPTYt0_1 car +_2mIWIhbDPY_0 bus +_37U5Elgnck_0 person +_5fE6dP48FM_0 cow +_5sIT4l5izM_0 knife +_6qUuUUYvUQ_0 person +_7zbbqEa3nw_1 train +_7zbbqEa3nw_4 train +_8VTthFkvS0_0 bird +_8iyumFI4sQ_1 elephant +_8iyumFI4sQ_2 elephant +_8iyumFI4sQ_3 elephant +_81FImml2gk_0 dog +_9bypka_Q4c_0 bus +_-CvwC7H730_0 person +_-XcxnQLKPM_0 dog +__Q5A7gExpI_0 person diff --git a/Stark/lib/train/dataset/COCO_tool.py b/Stark/lib/train/dataset/COCO_tool.py new file mode 100755 index 0000000..607f4a2 --- /dev/null +++ b/Stark/lib/train/dataset/COCO_tool.py @@ -0,0 +1,437 @@ +__author__ = 'tylin' +__version__ = '2.0' +# Interface for accessing the Microsoft COCO dataset. + +# Microsoft COCO is a large image dataset designed for object detection, +# segmentation, and caption generation. pycocotools is a Python API that +# assists in loading, parsing and visualizing the annotations in COCO. +# Please visit http://mscoco.org/ for more information on COCO, including +# for the data, paper, and tutorials. The exact format of the annotations +# is also described on the COCO website. For example usage of the pycocotools +# please see pycocotools_demo.ipynb. In addition to this API, please download both +# the COCO images and annotations in order to run the demo. + +# An alternative to using the API is to load the annotations directly +# into Python dictionary +# Using the API provides additional utility functions. Note that this API +# supports both *instance* and *caption* annotations. In the case of +# captions not all functions are defined (e.g. categories are undefined). + +# The following API functions are defined: +# COCO - COCO api class that loads COCO annotation file and prepare data structures. +# decodeMask - Decode binary mask M encoded via run-length encoding. +# encodeMask - Encode binary mask M using run-length encoding. +# getAnnIds - Get ann ids that satisfy given filter conditions. +# getCatIds - Get cat ids that satisfy given filter conditions. +# getImgIds - Get img ids that satisfy given filter conditions. +# loadAnns - Load anns with the specified ids. +# loadCats - Load cats with the specified ids. +# loadImgs - Load imgs with the specified ids. +# annToMask - Convert segmentation in an annotation to binary mask. +# showAnns - Display the specified annotations. +# loadRes - Load algorithm results and create API for accessing them. +# download - Download COCO images from mscoco.org server. +# Throughout the API "ann"=annotation, "cat"=category, and "img"=image. +# Help on each functions can be accessed by: "help COCO>function". + +# See also COCO>decodeMask, +# COCO>encodeMask, COCO>getAnnIds, COCO>getCatIds, +# COCO>getImgIds, COCO>loadAnns, COCO>loadCats, +# COCO>loadImgs, COCO>annToMask, COCO>showAnns + +# Microsoft COCO Toolbox. version 2.0 +# Data, paper, and tutorials available at: http://mscoco.org/ +# Code written by Piotr Dollar and Tsung-Yi Lin, 2014. +# Licensed under the Simplified BSD License [see bsd.txt] + +import json +import time +import matplotlib.pyplot as plt +from matplotlib.collections import PatchCollection +from matplotlib.patches import Polygon +import numpy as np +import copy +import itertools +from pycocotools import mask as maskUtils +import os +from collections import defaultdict +import sys +PYTHON_VERSION = sys.version_info[0] +if PYTHON_VERSION == 2: + from urllib import urlretrieve +elif PYTHON_VERSION == 3: + from urllib.request import urlretrieve + + +def _isArrayLike(obj): + return hasattr(obj, '__iter__') and hasattr(obj, '__len__') + + +class COCO: + def __init__(self, dataset): + """ + Constructor of Microsoft COCO helper class for reading and visualizing annotations. + :param annotation_file (str): location of annotation file + :param image_folder (str): location to the folder that hosts images. + :return: + """ + # load dataset + self.dataset,self.anns,self.cats,self.imgs = dict(),dict(),dict(),dict() + self.imgToAnns, self.catToImgs = defaultdict(list), defaultdict(list) + assert type(dataset)==dict, 'annotation file format {} not supported'.format(type(dataset)) + self.dataset = dataset + self.createIndex() + + def createIndex(self): + # create index + print('creating index...') + anns, cats, imgs = {}, {}, {} + imgToAnns,catToImgs = defaultdict(list),defaultdict(list) + if 'annotations' in self.dataset: + for ann in self.dataset['annotations']: + imgToAnns[ann['image_id']].append(ann) + anns[ann['id']] = ann + + if 'images' in self.dataset: + for img in self.dataset['images']: + imgs[img['id']] = img + + if 'categories' in self.dataset: + for cat in self.dataset['categories']: + cats[cat['id']] = cat + + if 'annotations' in self.dataset and 'categories' in self.dataset: + for ann in self.dataset['annotations']: + catToImgs[ann['category_id']].append(ann['image_id']) + + print('index created!') + + # create class members + self.anns = anns + self.imgToAnns = imgToAnns + self.catToImgs = catToImgs + self.imgs = imgs + self.cats = cats + + def info(self): + """ + Print information about the annotation file. + :return: + """ + for key, value in self.dataset['info'].items(): + print('{}: {}'.format(key, value)) + + def getAnnIds(self, imgIds=[], catIds=[], areaRng=[], iscrowd=None): + """ + Get ann ids that satisfy given filter conditions. default skips that filter + :param imgIds (int array) : get anns for given imgs + catIds (int array) : get anns for given cats + areaRng (float array) : get anns for given area range (e.g. [0 inf]) + iscrowd (boolean) : get anns for given crowd label (False or True) + :return: ids (int array) : integer array of ann ids + """ + imgIds = imgIds if _isArrayLike(imgIds) else [imgIds] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(imgIds) == len(catIds) == len(areaRng) == 0: + anns = self.dataset['annotations'] + else: + if not len(imgIds) == 0: + lists = [self.imgToAnns[imgId] for imgId in imgIds if imgId in self.imgToAnns] + anns = list(itertools.chain.from_iterable(lists)) + else: + anns = self.dataset['annotations'] + anns = anns if len(catIds) == 0 else [ann for ann in anns if ann['category_id'] in catIds] + anns = anns if len(areaRng) == 0 else [ann for ann in anns if ann['area'] > areaRng[0] and ann['area'] < areaRng[1]] + if not iscrowd == None: + ids = [ann['id'] for ann in anns if ann['iscrowd'] == iscrowd] + else: + ids = [ann['id'] for ann in anns] + return ids + + def getCatIds(self, catNms=[], supNms=[], catIds=[]): + """ + filtering parameters. default skips that filter. + :param catNms (str array) : get cats for given cat names + :param supNms (str array) : get cats for given supercategory names + :param catIds (int array) : get cats for given cat ids + :return: ids (int array) : integer array of cat ids + """ + catNms = catNms if _isArrayLike(catNms) else [catNms] + supNms = supNms if _isArrayLike(supNms) else [supNms] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(catNms) == len(supNms) == len(catIds) == 0: + cats = self.dataset['categories'] + else: + cats = self.dataset['categories'] + cats = cats if len(catNms) == 0 else [cat for cat in cats if cat['name'] in catNms] + cats = cats if len(supNms) == 0 else [cat for cat in cats if cat['supercategory'] in supNms] + cats = cats if len(catIds) == 0 else [cat for cat in cats if cat['id'] in catIds] + ids = [cat['id'] for cat in cats] + return ids + + def getImgIds(self, imgIds=[], catIds=[]): + ''' + Get img ids that satisfy given filter conditions. + :param imgIds (int array) : get imgs for given ids + :param catIds (int array) : get imgs with all given cats + :return: ids (int array) : integer array of img ids + ''' + imgIds = imgIds if _isArrayLike(imgIds) else [imgIds] + catIds = catIds if _isArrayLike(catIds) else [catIds] + + if len(imgIds) == len(catIds) == 0: + ids = self.imgs.keys() + else: + ids = set(imgIds) + for i, catId in enumerate(catIds): + if i == 0 and len(ids) == 0: + ids = set(self.catToImgs[catId]) + else: + ids &= set(self.catToImgs[catId]) + return list(ids) + + def loadAnns(self, ids=[]): + """ + Load anns with the specified ids. + :param ids (int array) : integer ids specifying anns + :return: anns (object array) : loaded ann objects + """ + if _isArrayLike(ids): + return [self.anns[id] for id in ids] + elif type(ids) == int: + return [self.anns[ids]] + + def loadCats(self, ids=[]): + """ + Load cats with the specified ids. + :param ids (int array) : integer ids specifying cats + :return: cats (object array) : loaded cat objects + """ + if _isArrayLike(ids): + return [self.cats[id] for id in ids] + elif type(ids) == int: + return [self.cats[ids]] + + def loadImgs(self, ids=[]): + """ + Load anns with the specified ids. + :param ids (int array) : integer ids specifying img + :return: imgs (object array) : loaded img objects + """ + if _isArrayLike(ids): + return [self.imgs[id] for id in ids] + elif type(ids) == int: + return [self.imgs[ids]] + + def showAnns(self, anns, draw_bbox=False): + """ + Display the specified annotations. + :param anns (array of object): annotations to display + :return: None + """ + if len(anns) == 0: + return 0 + if 'segmentation' in anns[0] or 'keypoints' in anns[0]: + datasetType = 'instances' + elif 'caption' in anns[0]: + datasetType = 'captions' + else: + raise Exception('datasetType not supported') + if datasetType == 'instances': + ax = plt.gca() + ax.set_autoscale_on(False) + polygons = [] + color = [] + for ann in anns: + c = (np.random.random((1, 3))*0.6+0.4).tolist()[0] + if 'segmentation' in ann: + if type(ann['segmentation']) == list: + # polygon + for seg in ann['segmentation']: + poly = np.array(seg).reshape((int(len(seg)/2), 2)) + polygons.append(Polygon(poly)) + color.append(c) + else: + # mask + t = self.imgs[ann['image_id']] + if type(ann['segmentation']['counts']) == list: + rle = maskUtils.frPyObjects([ann['segmentation']], t['height'], t['width']) + else: + rle = [ann['segmentation']] + m = maskUtils.decode(rle) + img = np.ones( (m.shape[0], m.shape[1], 3) ) + if ann['iscrowd'] == 1: + color_mask = np.array([2.0,166.0,101.0])/255 + if ann['iscrowd'] == 0: + color_mask = np.random.random((1, 3)).tolist()[0] + for i in range(3): + img[:,:,i] = color_mask[i] + ax.imshow(np.dstack( (img, m*0.5) )) + if 'keypoints' in ann and type(ann['keypoints']) == list: + # turn skeleton into zero-based index + sks = np.array(self.loadCats(ann['category_id'])[0]['skeleton'])-1 + kp = np.array(ann['keypoints']) + x = kp[0::3] + y = kp[1::3] + v = kp[2::3] + for sk in sks: + if np.all(v[sk]>0): + plt.plot(x[sk],y[sk], linewidth=3, color=c) + plt.plot(x[v>0], y[v>0],'o',markersize=8, markerfacecolor=c, markeredgecolor='k',markeredgewidth=2) + plt.plot(x[v>1], y[v>1],'o',markersize=8, markerfacecolor=c, markeredgecolor=c, markeredgewidth=2) + + if draw_bbox: + [bbox_x, bbox_y, bbox_w, bbox_h] = ann['bbox'] + poly = [[bbox_x, bbox_y], [bbox_x, bbox_y+bbox_h], [bbox_x+bbox_w, bbox_y+bbox_h], [bbox_x+bbox_w, bbox_y]] + np_poly = np.array(poly).reshape((4,2)) + polygons.append(Polygon(np_poly)) + color.append(c) + + p = PatchCollection(polygons, facecolor=color, linewidths=0, alpha=0.4) + ax.add_collection(p) + p = PatchCollection(polygons, facecolor='none', edgecolors=color, linewidths=2) + ax.add_collection(p) + elif datasetType == 'captions': + for ann in anns: + print(ann['caption']) + + def loadRes(self, resFile): + """ + Load result file and return a result api object. + :param resFile (str) : file name of result file + :return: res (obj) : result api object + """ + res = COCO() + res.dataset['images'] = [img for img in self.dataset['images']] + + print('Loading and preparing results...') + tic = time.time() + if type(resFile) == str or (PYTHON_VERSION == 2 and type(resFile) == unicode): + with open(resFile) as f: + anns = json.load(f) + elif type(resFile) == np.ndarray: + anns = self.loadNumpyAnnotations(resFile) + else: + anns = resFile + assert type(anns) == list, 'results in not an array of objects' + annsImgIds = [ann['image_id'] for ann in anns] + assert set(annsImgIds) == (set(annsImgIds) & set(self.getImgIds())), \ + 'Results do not correspond to current coco set' + if 'caption' in anns[0]: + imgIds = set([img['id'] for img in res.dataset['images']]) & set([ann['image_id'] for ann in anns]) + res.dataset['images'] = [img for img in res.dataset['images'] if img['id'] in imgIds] + for id, ann in enumerate(anns): + ann['id'] = id+1 + elif 'bbox' in anns[0] and not anns[0]['bbox'] == []: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + bb = ann['bbox'] + x1, x2, y1, y2 = [bb[0], bb[0]+bb[2], bb[1], bb[1]+bb[3]] + if not 'segmentation' in ann: + ann['segmentation'] = [[x1, y1, x1, y2, x2, y2, x2, y1]] + ann['area'] = bb[2]*bb[3] + ann['id'] = id+1 + ann['iscrowd'] = 0 + elif 'segmentation' in anns[0]: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + # now only support compressed RLE format as segmentation results + ann['area'] = maskUtils.area(ann['segmentation']) + if not 'bbox' in ann: + ann['bbox'] = maskUtils.toBbox(ann['segmentation']) + ann['id'] = id+1 + ann['iscrowd'] = 0 + elif 'keypoints' in anns[0]: + res.dataset['categories'] = copy.deepcopy(self.dataset['categories']) + for id, ann in enumerate(anns): + s = ann['keypoints'] + x = s[0::3] + y = s[1::3] + x0,x1,y0,y1 = np.min(x), np.max(x), np.min(y), np.max(y) + ann['area'] = (x1-x0)*(y1-y0) + ann['id'] = id + 1 + ann['bbox'] = [x0,y0,x1-x0,y1-y0] + print('DONE (t={:0.2f}s)'.format(time.time()- tic)) + + res.dataset['annotations'] = anns + res.createIndex() + return res + + def download(self, tarDir = None, imgIds = [] ): + ''' + Download COCO images from mscoco.org server. + :param tarDir (str): COCO results directory name + imgIds (list): images to be downloaded + :return: + ''' + if tarDir is None: + print('Please specify target directory') + return -1 + if len(imgIds) == 0: + imgs = self.imgs.values() + else: + imgs = self.loadImgs(imgIds) + N = len(imgs) + if not os.path.exists(tarDir): + os.makedirs(tarDir) + for i, img in enumerate(imgs): + tic = time.time() + fname = os.path.join(tarDir, img['file_name']) + if not os.path.exists(fname): + urlretrieve(img['coco_url'], fname) + print('downloaded {}/{} images (t={:0.1f}s)'.format(i, N, time.time()- tic)) + + def loadNumpyAnnotations(self, data): + """ + Convert result data from a numpy array [Nx7] where each row contains {imageID,x1,y1,w,h,score,class} + :param data (numpy.ndarray) + :return: annotations (python nested list) + """ + print('Converting ndarray to lists...') + assert(type(data) == np.ndarray) + print(data.shape) + assert(data.shape[1] == 7) + N = data.shape[0] + ann = [] + for i in range(N): + if i % 1000000 == 0: + print('{}/{}'.format(i,N)) + ann += [{ + 'image_id' : int(data[i, 0]), + 'bbox' : [ data[i, 1], data[i, 2], data[i, 3], data[i, 4] ], + 'score' : data[i, 5], + 'category_id': int(data[i, 6]), + }] + return ann + + def annToRLE(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE to RLE. + :return: binary mask (numpy 2D array) + """ + t = self.imgs[ann['image_id']] + h, w = t['height'], t['width'] + segm = ann['segmentation'] + if type(segm) == list: + # polygon -- a single object might consist of multiple parts + # we merge all parts into one mask rle code + rles = maskUtils.frPyObjects(segm, h, w) + rle = maskUtils.merge(rles) + elif type(segm['counts']) == list: + # uncompressed RLE + rle = maskUtils.frPyObjects(segm, h, w) + else: + # rle + rle = ann['segmentation'] + return rle + + def annToMask(self, ann): + """ + Convert annotation which can be polygons, uncompressed RLE, or RLE to binary mask. + :return: binary mask (numpy 2D array) + """ + rle = self.annToRLE(ann) + m = maskUtils.decode(rle) + return m diff --git a/Stark/lib/train/dataset/__init__.py b/Stark/lib/train/dataset/__init__.py new file mode 100755 index 0000000..87ca906 --- /dev/null +++ b/Stark/lib/train/dataset/__init__.py @@ -0,0 +1,11 @@ +from .lasot import Lasot +from .got10k import Got10k +from .tracking_net import TrackingNet +from .imagenetvid import ImagenetVID +from .coco import MSCOCO +from .coco_seq import MSCOCOSeq +from .got10k_lmdb import Got10k_lmdb +from .lasot_lmdb import Lasot_lmdb +from .imagenetvid_lmdb import ImagenetVID_lmdb +from .coco_seq_lmdb import MSCOCOSeq_lmdb +from .tracking_net_lmdb import TrackingNet_lmdb diff --git a/Stark/lib/train/dataset/base_image_dataset.py b/Stark/lib/train/dataset/base_image_dataset.py new file mode 100755 index 0000000..4645e81 --- /dev/null +++ b/Stark/lib/train/dataset/base_image_dataset.py @@ -0,0 +1,92 @@ +import torch.utils.data +from lib.train.data.image_loader import jpeg4py_loader + + +class BaseImageDataset(torch.utils.data.Dataset): + """ Base class for image datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.image_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_images() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_images(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.image_list) + + def has_class_info(self): + return False + + def get_class_name(self, image_id): + return None + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_images_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_image_info(self, seq_id): + """ Returns information about a particular image, + + args: + seq_id - index of the image + + returns: + Dict + """ + raise NotImplementedError + + def get_image(self, image_id, anno=None): + """ Get a image + + args: + image_id - index of image + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + image - + anno - + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/Stark/lib/train/dataset/base_video_dataset.py b/Stark/lib/train/dataset/base_video_dataset.py new file mode 100755 index 0000000..314e604 --- /dev/null +++ b/Stark/lib/train/dataset/base_video_dataset.py @@ -0,0 +1,110 @@ +import torch.utils.data +# 2021.1.5 use jpeg4py_loader_w_failsafe as default +from lib.train.data.image_loader import jpeg4py_loader_w_failsafe + + +class BaseVideoDataset(torch.utils.data.Dataset): + """ Base class for video datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader_w_failsafe): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.sequence_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_sequences() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def is_video_sequence(self): + """ Returns whether the dataset is a video dataset or an image dataset + + returns: + bool - True if a video dataset + """ + return True + + def is_synthetic_video_dataset(self): + """ Returns whether the dataset contains real videos or synthetic + + returns: + bool - True if a video dataset + """ + return False + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_sequences(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.sequence_list) + + def has_class_info(self): + return False + + def has_occlusion_info(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_sequences_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_sequence_info(self, seq_id): + """ Returns information about a particular sequences, + + args: + seq_id - index of the sequence + + returns: + Dict + """ + raise NotImplementedError + + def get_frames(self, seq_id, frame_ids, anno=None): + """ Get a set of frames from a particular sequence + + args: + seq_id - index of sequence + frame_ids - a list of frame numbers + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + list - List of frames corresponding to frame_ids + list - List of dicts for each frame + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/Stark/lib/train/dataset/coco.py b/Stark/lib/train/dataset/coco.py new file mode 100755 index 0000000..7aaa1b0 --- /dev/null +++ b/Stark/lib/train/dataset/coco.py @@ -0,0 +1,156 @@ +import os +from .base_image_dataset import BaseImageDataset +import torch +import random +from collections import OrderedDict +from lib.train.data import jpeg4py_loader +from lib.train.admin import env_settings +from pycocotools.coco import COCO + + +class MSCOCO(BaseImageDataset): + """ The COCO object detection dataset. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None, + split="train", version="2014"): + """ + args: + root - path to coco root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() # the parent class thing would happen in the sampler + + self.image_list = self._get_image_list(min_area=min_area) + + if data_fraction is not None: + self.image_list = random.sample(self.image_list, int(len(self.image_list) * data_fraction)) + self.im_per_class = self._build_im_per_class() + + def _get_image_list(self, min_area=None): + ann_list = list(self.coco_set.anns.keys()) + image_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + if min_area is not None: + image_list = [a for a in image_list if self.coco_set.anns[a]['area'] > min_area] + + return image_list + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def has_segmentation_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def _build_im_per_class(self): + im_per_class = {} + for i, im in enumerate(self.image_list): + class_name = self.cats[self.coco_set.anns[im]['category_id']]['name'] + if class_name not in im_per_class: + im_per_class[class_name] = [i] + else: + im_per_class[class_name].append(i) + + return im_per_class + + def get_images_in_class(self, class_name): + return self.im_per_class[class_name] + + def get_image_info(self, im_id): + anno = self._get_anno(im_id) + + bbox = torch.Tensor(anno['bbox']).view(4,) + + mask = torch.Tensor(self.coco_set.annToMask(anno)) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, im_id): + anno = self.coco_set.anns[self.image_list[im_id]] + + return anno + + def _get_image(self, im_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.image_list[im_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, im_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_class_name(self, im_id): + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + return cat_dict_current['name'] + + def get_image(self, image_id, anno=None): + frame = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/Stark/lib/train/dataset/coco_seq.py b/Stark/lib/train/dataset/coco_seq.py new file mode 100755 index 0000000..bc38982 --- /dev/null +++ b/Stark/lib/train/dataset/coco_seq.py @@ -0,0 +1,170 @@ +import os +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +import torch +import random +from pycocotools.coco import COCO +from collections import OrderedDict +from lib.train.admin import env_settings + + +class MSCOCOSeq(BaseVideoDataset): + """ The COCO dataset. COCO is an image dataset. Thus, we treat each image as a sequence of length 1. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, split="train", version="2014"): + """ + args: + root - path to the coco dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + data_fraction (None) - Fraction of images to be used. The images are selected randomly. If None, all the + images will be used + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + # Load the COCO set. + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() + + self.sequence_list = self._get_sequence_list() + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + self.seq_per_class = self._build_seq_per_class() + + def _get_sequence_list(self): + ann_list = list(self.coco_set.anns.keys()) + seq_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + return seq_list + + def is_video_sequence(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def _build_seq_per_class(self): + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = self.cats[self.coco_set.anns[seq]['category_id']]['name'] + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def get_sequence_info(self, seq_id): + anno = self._get_anno(seq_id) + + bbox = torch.Tensor(anno['bbox']).view(1, 4) + + mask = torch.Tensor(self.coco_set.annToMask(anno)).unsqueeze(dim=0) + + '''2021.1.3 To avoid too small bounding boxes. Here we change the threshold to 50 pixels''' + valid = (bbox[:, 2] > 50) & (bbox[:, 3] > 50) + + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, seq_id): + anno = self.coco_set.anns[self.sequence_list[seq_id]] + + return anno + + def _get_frames(self, seq_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.sequence_list[seq_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, seq_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + + def get_class_name(self, seq_id): + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + return cat_dict_current['name'] + + def get_frames(self, seq_id=None, frame_ids=None, anno=None): + # COCO is an image dataset. Thus we replicate the image denoted by seq_id len(frame_ids) times, and return a + # list containing these replicated images. + frame = self._get_frames(seq_id) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0, ...] for _ in frame_ids] + + object_meta = self.get_meta_info(seq_id) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/dataset/coco_seq_lmdb.py b/Stark/lib/train/dataset/coco_seq_lmdb.py new file mode 100755 index 0000000..9cf487d --- /dev/null +++ b/Stark/lib/train/dataset/coco_seq_lmdb.py @@ -0,0 +1,177 @@ +import os +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +import torch +import random +from collections import OrderedDict +from lib.train.admin import env_settings +from lib.train.dataset.COCO_tool import COCO +from lib.utils.lmdb_utils import decode_img, decode_json +import time + +class MSCOCOSeq_lmdb(BaseVideoDataset): + """ The COCO dataset. COCO is an image dataset. Thus, we treat each image as a sequence of length 1. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, split="train", version="2014"): + """ + args: + root - path to the coco dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + data_fraction (None) - Fraction of images to be used. The images are selected randomly. If None, all the + images will be used + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + root = env_settings().coco_dir if root is None else root + super().__init__('COCO_lmdb', root, image_loader) + self.root = root + self.img_pth = 'images/{}{}/'.format(split, version) + self.anno_path = 'annotations/instances_{}{}.json'.format(split, version) + + # Load the COCO set. + print('loading annotations into memory...') + tic = time.time() + coco_json = decode_json(root, self.anno_path) + print('Done (t={:0.2f}s)'.format(time.time() - tic)) + + self.coco_set = COCO(coco_json) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() + + self.sequence_list = self._get_sequence_list() + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + self.seq_per_class = self._build_seq_per_class() + + def _get_sequence_list(self): + ann_list = list(self.coco_set.anns.keys()) + seq_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + return seq_list + + def is_video_sequence(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco_lmdb' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def _build_seq_per_class(self): + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = self.cats[self.coco_set.anns[seq]['category_id']]['name'] + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def get_sequence_info(self, seq_id): + anno = self._get_anno(seq_id) + + bbox = torch.Tensor(anno['bbox']).view(1, 4) + + mask = torch.Tensor(self.coco_set.annToMask(anno)).unsqueeze(dim=0) + + '''2021.1.3 To avoid too small bounding boxes. Here we change the threshold to 50 pixels''' + valid = (bbox[:, 2] > 50) & (bbox[:, 3] > 50) + + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, seq_id): + anno = self.coco_set.anns[self.sequence_list[seq_id]] + + return anno + + def _get_frames(self, seq_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.sequence_list[seq_id]]['image_id']])[0]['file_name'] + # img = self.image_loader(os.path.join(self.img_pth, path)) + img = decode_img(self.root, os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, seq_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + + def get_class_name(self, seq_id): + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + return cat_dict_current['name'] + + def get_frames(self, seq_id=None, frame_ids=None, anno=None): + # COCO is an image dataset. Thus we replicate the image denoted by seq_id len(frame_ids) times, and return a + # list containing these replicated images. + frame = self._get_frames(seq_id) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0, ...] for _ in frame_ids] + + object_meta = self.get_meta_info(seq_id) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/dataset/got10k.py b/Stark/lib/train/dataset/got10k.py new file mode 100755 index 0000000..a20c961 --- /dev/null +++ b/Stark/lib/train/dataset/got10k.py @@ -0,0 +1,185 @@ +import os +import os.path +import numpy as np +import torch +import csv +import pandas +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +from lib.train.admin import env_settings + + +class Got10k(BaseVideoDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, split=None, seq_ids=None, data_fraction=None): + """ + args: + root - path to the got-10k training data. Note: This should point to the 'train' folder inside GOT-10k + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + split - 'train' or 'val'. Note: The validation split here is a subset of the official got-10k train split, + not NOT the official got-10k validation split. To use the official validation split, provide that as + the root folder instead. + seq_ids - List containing the ids of the videos to be used for training. Note: Only one of 'split' or 'seq_ids' + options can be used at the same time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().got10k_dir if root is None else root + super().__init__('GOT10k', root, image_loader) + + # all folders inside the root + self.sequence_list = self._get_sequence_list() + + # seq_id is the index of the folder inside the got10k root path + if split is not None: + if seq_ids is not None: + raise ValueError('Cannot set both split_name and seq_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_train_split.txt') + elif split == 'val': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_val_split.txt') + elif split == 'train_full': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_train_full_split.txt') + elif split == 'vottrain': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_train_split.txt') + elif split == 'votval': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_val_split.txt') + else: + raise ValueError('Unknown split name.') + seq_ids = pandas.read_csv(file_path, header=None, squeeze=True, dtype=np.int64).values.tolist() + elif seq_ids is None: + seq_ids = list(range(0, len(self.sequence_list))) + + self.sequence_list = [self.sequence_list[i] for i in seq_ids] + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.sequence_meta_info = self._load_meta_info() + self.seq_per_class = self._build_seq_per_class() + + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def get_name(self): + return 'got10k' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def _load_meta_info(self): + sequence_meta_info = {s: self._read_meta(os.path.join(self.root, s)) for s in self.sequence_list} + return sequence_meta_info + + def _read_meta(self, seq_path): + try: + with open(os.path.join(seq_path, 'meta_info.ini')) as f: + meta_info = f.readlines() + object_meta = OrderedDict({'object_class_name': meta_info[5].split(': ')[-1][:-1], + 'motion_class': meta_info[6].split(': ')[-1][:-1], + 'major_class': meta_info[7].split(': ')[-1][:-1], + 'root_class': meta_info[8].split(': ')[-1][:-1], + 'motion_adverb': meta_info[9].split(': ')[-1][:-1]}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def _build_seq_per_class(self): + seq_per_class = {} + + for i, s in enumerate(self.sequence_list): + object_class = self.sequence_meta_info[s]['object_class_name'] + if object_class in seq_per_class: + seq_per_class[object_class].append(i) + else: + seq_per_class[object_class] = [i] + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _get_sequence_list(self): + with open(os.path.join(self.root, 'list.txt')) as f: + dir_list = list(csv.reader(f)) + dir_list = [dir_name[0] for dir_name in dir_list] + return dir_list + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "absence.label") + cover_file = os.path.join(seq_path, "cover.label") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + with open(cover_file, 'r', newline='') as f: + cover = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + + target_visible = ~occlusion & (cover>0).byte() + + visible_ratio = cover.float() / 8 + return target_visible, visible_ratio + + def _get_sequence_path(self, seq_id): + return os.path.join(self.root, self.sequence_list[seq_id]) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible, visible_ratio = self._read_target_visible(seq_path) + visible = visible & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible, 'visible_ratio': visible_ratio} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def get_class_name(self, seq_id): + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + return obj_meta['object_class_name'] + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return frame_list, anno_frames, obj_meta diff --git a/Stark/lib/train/dataset/got10k_lmdb.py b/Stark/lib/train/dataset/got10k_lmdb.py new file mode 100755 index 0000000..7a0a743 --- /dev/null +++ b/Stark/lib/train/dataset/got10k_lmdb.py @@ -0,0 +1,183 @@ +import os +import os.path +import numpy as np +import torch +import csv +import pandas +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +from lib.train.admin import env_settings + +'''2021.1.16 Gok10k for loading lmdb dataset''' +from lib.utils.lmdb_utils import * + + +class Got10k_lmdb(BaseVideoDataset): + + def __init__(self, root=None, image_loader=jpeg4py_loader, split=None, seq_ids=None, data_fraction=None): + """ + args: + root - path to the got-10k training data. Note: This should point to the 'train' folder inside GOT-10k + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + split - 'train' or 'val'. Note: The validation split here is a subset of the official got-10k train split, + not NOT the official got-10k validation split. To use the official validation split, provide that as + the root folder instead. + seq_ids - List containing the ids of the videos to be used for training. Note: Only one of 'split' or 'seq_ids' + options can be used at the same time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + use_lmdb - whether the dataset is stored in lmdb format + """ + root = env_settings().got10k_lmdb_dir if root is None else root + super().__init__('GOT10k_lmdb', root, image_loader) + + # all folders inside the root + self.sequence_list = self._get_sequence_list() + + # seq_id is the index of the folder inside the got10k root path + if split is not None: + if seq_ids is not None: + raise ValueError('Cannot set both split_name and seq_ids.') + train_lib_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(train_lib_path, 'data_specs', 'got10k_train_split.txt') + elif split == 'val': + file_path = os.path.join(train_lib_path, 'data_specs', 'got10k_val_split.txt') + elif split == 'train_full': + file_path = os.path.join(train_lib_path, 'data_specs', 'got10k_train_full_split.txt') + elif split == 'vottrain': + file_path = os.path.join(train_lib_path, 'data_specs', 'got10k_vot_train_split.txt') + elif split == 'votval': + file_path = os.path.join(train_lib_path, 'data_specs', 'got10k_vot_val_split.txt') + else: + raise ValueError('Unknown split name.') + seq_ids = pandas.read_csv(file_path, header=None, squeeze=True, dtype=np.int64).values.tolist() + elif seq_ids is None: + seq_ids = list(range(0, len(self.sequence_list))) + + self.sequence_list = [self.sequence_list[i] for i in seq_ids] + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.sequence_meta_info = self._load_meta_info() + self.seq_per_class = self._build_seq_per_class() + + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def get_name(self): + return 'got10k_lmdb' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def _load_meta_info(self): + def _read_meta(meta_info): + + object_meta = OrderedDict({'object_class_name': meta_info[5].split(': ')[-1], + 'motion_class': meta_info[6].split(': ')[-1], + 'major_class': meta_info[7].split(': ')[-1], + 'root_class': meta_info[8].split(': ')[-1], + 'motion_adverb': meta_info[9].split(': ')[-1]}) + + return object_meta + sequence_meta_info = {} + for s in self.sequence_list: + try: + meta_str = decode_str(self.root, "train/%s/meta_info.ini" %s) + sequence_meta_info[s] = _read_meta(meta_str.split('\n')) + except: + sequence_meta_info[s] = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return sequence_meta_info + + def _build_seq_per_class(self): + seq_per_class = {} + + for i, s in enumerate(self.sequence_list): + object_class = self.sequence_meta_info[s]['object_class_name'] + if object_class in seq_per_class: + seq_per_class[object_class].append(i) + else: + seq_per_class[object_class] = [i] + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _get_sequence_list(self): + dir_str = decode_str(self.root, 'train/list.txt') + dir_list = dir_str.split('\n') + return dir_list + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt_str_list = decode_str(self.root, bb_anno_file).split('\n')[:-1] # the last line in got10k is empty + gt_list = [list(map(float, line.split(','))) for line in gt_str_list] + gt_arr = np.array(gt_list).astype(np.float32) + + return torch.tensor(gt_arr) + + def _read_target_visible(self, seq_path): + # full occlusion and out_of_view files + occlusion_file = os.path.join(seq_path, "absence.label") + cover_file = os.path.join(seq_path, "cover.label") + # Read these files + occ_list = list(map(int, decode_str(self.root, occlusion_file).split('\n')[:-1])) # the last line in got10k is empty + occlusion = torch.ByteTensor(occ_list) + cover_list = list(map(int, decode_str(self.root, cover_file).split('\n')[:-1])) # the last line in got10k is empty + cover = torch.ByteTensor(cover_list) + + target_visible = ~occlusion & (cover>0).byte() + + visible_ratio = cover.float() / 8 + return target_visible, visible_ratio + + def _get_sequence_path(self, seq_id): + return os.path.join("train", self.sequence_list[seq_id]) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible, visible_ratio = self._read_target_visible(seq_path) + visible = visible & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible, 'visible_ratio': visible_ratio} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return decode_img(self.root, self._get_frame_path(seq_path, frame_id)) + + def get_class_name(self, seq_id): + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + return obj_meta['object_class_name'] + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return frame_list, anno_frames, obj_meta diff --git a/Stark/lib/train/dataset/imagenetvid.py b/Stark/lib/train/dataset/imagenetvid.py new file mode 100755 index 0000000..b93074c --- /dev/null +++ b/Stark/lib/train/dataset/imagenetvid.py @@ -0,0 +1,159 @@ +import os +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +import xml.etree.ElementTree as ET +import json +import torch +from collections import OrderedDict +from lib.train.admin import env_settings + + +def get_target_to_image_ratio(seq): + anno = torch.Tensor(seq['anno']) + img_sz = torch.Tensor(seq['image_size']) + return (anno[0, 2:4].prod() / (img_sz.prod())).sqrt() + + +class ImagenetVID(BaseVideoDataset): + """ Imagenet VID dataset. + + Publication: + ImageNet Large Scale Visual Recognition Challenge + Olga Russakovsky, Jia Deng, Hao Su, Jonathan Krause, Sanjeev Satheesh, Sean Ma, Zhiheng Huang, Andrej Karpathy, + Aditya Khosla, Michael Bernstein, Alexander C. Berg and Li Fei-Fei + IJCV, 2015 + https://arxiv.org/pdf/1409.0575.pdf + + Download the dataset from http://image-net.org/ + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, min_length=0, max_target_area=1): + """ + args: + root - path to the imagenet vid dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + min_length - Minimum allowed sequence length. + max_target_area - max allowed ratio between target area and image area. Can be used to filter out targets + which cover complete image. + """ + root = env_settings().imagenet_dir if root is None else root + super().__init__("imagenetvid", root, image_loader) + + cache_file = os.path.join(root, 'cache.json') + if os.path.isfile(cache_file): + # If available, load the pre-processed cache file containing meta-info for each sequence + with open(cache_file, 'r') as f: + sequence_list_dict = json.load(f) + + self.sequence_list = sequence_list_dict + else: + # Else process the imagenet annotations and generate the cache file + self.sequence_list = self._process_anno(root) + + with open(cache_file, 'w') as f: + json.dump(self.sequence_list, f) + + # Filter the sequences based on min_length and max_target_area in the first frame + self.sequence_list = [x for x in self.sequence_list if len(x['anno']) >= min_length and + get_target_to_image_ratio(x) < max_target_area] + + def get_name(self): + return 'imagenetvid' + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_sequence_info(self, seq_id): + bb_anno = torch.Tensor(self.sequence_list[seq_id]['anno']) + valid = (bb_anno[:, 2] > 0) & (bb_anno[:, 3] > 0) + visible = torch.ByteTensor(self.sequence_list[seq_id]['target_visible']) & valid.byte() + return {'bbox': bb_anno, 'valid': valid, 'visible': visible} + + def _get_frame(self, sequence, frame_id): + set_name = 'ILSVRC2015_VID_train_{:04d}'.format(sequence['set_id']) + vid_name = 'ILSVRC2015_train_{:08d}'.format(sequence['vid_id']) + frame_number = frame_id + sequence['start_frame'] + frame_path = os.path.join(self.root, 'Data', 'VID', 'train', set_name, vid_name, + '{:06d}.JPEG'.format(frame_number)) + return self.image_loader(frame_path) + + def get_frames(self, seq_id, frame_ids, anno=None): + sequence = self.sequence_list[seq_id] + + frame_list = [self._get_frame(sequence, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + # Create anno dict + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + # added the class info to the meta info + object_meta = OrderedDict({'object_class': sequence['class_name'], + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta + + def _process_anno(self, root): + # Builds individual tracklets + base_vid_anno_path = os.path.join(root, 'Annotations', 'VID', 'train') + + all_sequences = [] + for set in sorted(os.listdir(base_vid_anno_path)): + set_id = int(set.split('_')[-1]) + for vid in sorted(os.listdir(os.path.join(base_vid_anno_path, set))): + + vid_id = int(vid.split('_')[-1]) + anno_files = sorted(os.listdir(os.path.join(base_vid_anno_path, set, vid))) + + frame1_anno = ET.parse(os.path.join(base_vid_anno_path, set, vid, anno_files[0])) + image_size = [int(frame1_anno.find('size/width').text), int(frame1_anno.find('size/height').text)] + + objects = [ET.ElementTree(file=os.path.join(base_vid_anno_path, set, vid, f)).findall('object') + for f in anno_files] + + tracklets = {} + + # Find all tracklets along with start frame + for f_id, all_targets in enumerate(objects): + for target in all_targets: + tracklet_id = target.find('trackid').text + if tracklet_id not in tracklets: + tracklets[tracklet_id] = f_id + + for tracklet_id, tracklet_start in tracklets.items(): + tracklet_anno = [] + target_visible = [] + class_name_id = None + + for f_id in range(tracklet_start, len(objects)): + found = False + for target in objects[f_id]: + if target.find('trackid').text == tracklet_id: + if not class_name_id: + class_name_id = target.find('name').text + x1 = int(target.find('bndbox/xmin').text) + y1 = int(target.find('bndbox/ymin').text) + x2 = int(target.find('bndbox/xmax').text) + y2 = int(target.find('bndbox/ymax').text) + + tracklet_anno.append([x1, y1, x2 - x1, y2 - y1]) + target_visible.append(target.find('occluded').text == '0') + + found = True + break + if not found: + break + + new_sequence = {'set_id': set_id, 'vid_id': vid_id, 'class_name': class_name_id, + 'start_frame': tracklet_start, 'anno': tracklet_anno, + 'target_visible': target_visible, 'image_size': image_size} + all_sequences.append(new_sequence) + + return all_sequences diff --git a/Stark/lib/train/dataset/imagenetvid_lmdb.py b/Stark/lib/train/dataset/imagenetvid_lmdb.py new file mode 100755 index 0000000..623b1ae --- /dev/null +++ b/Stark/lib/train/dataset/imagenetvid_lmdb.py @@ -0,0 +1,90 @@ +import os +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +import torch +from collections import OrderedDict +from lib.train.admin import env_settings +from lib.utils.lmdb_utils import decode_img, decode_json + + +def get_target_to_image_ratio(seq): + anno = torch.Tensor(seq['anno']) + img_sz = torch.Tensor(seq['image_size']) + return (anno[0, 2:4].prod() / (img_sz.prod())).sqrt() + + +class ImagenetVID_lmdb(BaseVideoDataset): + """ Imagenet VID dataset. + + Publication: + ImageNet Large Scale Visual Recognition Challenge + Olga Russakovsky, Jia Deng, Hao Su, Jonathan Krause, Sanjeev Satheesh, Sean Ma, Zhiheng Huang, Andrej Karpathy, + Aditya Khosla, Michael Bernstein, Alexander C. Berg and Li Fei-Fei + IJCV, 2015 + https://arxiv.org/pdf/1409.0575.pdf + + Download the dataset from http://image-net.org/ + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, min_length=0, max_target_area=1): + """ + args: + root - path to the imagenet vid dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + min_length - Minimum allowed sequence length. + max_target_area - max allowed ratio between target area and image area. Can be used to filter out targets + which cover complete image. + """ + root = env_settings().imagenet_dir if root is None else root + super().__init__("imagenetvid_lmdb", root, image_loader) + + sequence_list_dict = decode_json(root, "cache.json") + self.sequence_list = sequence_list_dict + + # Filter the sequences based on min_length and max_target_area in the first frame + self.sequence_list = [x for x in self.sequence_list if len(x['anno']) >= min_length and + get_target_to_image_ratio(x) < max_target_area] + + def get_name(self): + return 'imagenetvid_lmdb' + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_sequence_info(self, seq_id): + bb_anno = torch.Tensor(self.sequence_list[seq_id]['anno']) + valid = (bb_anno[:, 2] > 0) & (bb_anno[:, 3] > 0) + visible = torch.ByteTensor(self.sequence_list[seq_id]['target_visible']) & valid.byte() + return {'bbox': bb_anno, 'valid': valid, 'visible': visible} + + def _get_frame(self, sequence, frame_id): + set_name = 'ILSVRC2015_VID_train_{:04d}'.format(sequence['set_id']) + vid_name = 'ILSVRC2015_train_{:08d}'.format(sequence['vid_id']) + frame_number = frame_id + sequence['start_frame'] + frame_path = os.path.join('Data', 'VID', 'train', set_name, vid_name, + '{:06d}.JPEG'.format(frame_number)) + return decode_img(self.root, frame_path) + + def get_frames(self, seq_id, frame_ids, anno=None): + sequence = self.sequence_list[seq_id] + + frame_list = [self._get_frame(sequence, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + # Create anno dict + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + # added the class info to the meta info + object_meta = OrderedDict({'object_class': sequence['class_name'], + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta + diff --git a/Stark/lib/train/dataset/lasot.py b/Stark/lib/train/dataset/lasot.py new file mode 100755 index 0000000..103c197 --- /dev/null +++ b/Stark/lib/train/dataset/lasot.py @@ -0,0 +1,168 @@ +import os +import os.path +import torch +import numpy as np +import pandas +import csv +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +from lib.train.admin import env_settings + + +class Lasot(BaseVideoDataset): + """ LaSOT dataset. + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, vid_ids=None, split=None, data_fraction=None): + """ + args: + root - path to the lasot dataset. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + vid_ids - List containing the ids of the videos (1 - 20) used for training. If vid_ids = [1, 3, 5], then the + videos with subscripts -1, -3, and -5 from each class will be used for training. + split - If split='train', the official train split (protocol-II) is used for training. Note: Only one of + vid_ids or split option can be used at a time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().lasot_dir if root is None else root + super().__init__('LaSOT', root, image_loader) + + # Keep a list of all classes + self.class_list = [f for f in os.listdir(self.root)] + self.class_to_id = {cls_name: cls_id for cls_id, cls_name in enumerate(self.class_list)} + + self.sequence_list = self._build_sequence_list(vid_ids, split) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.seq_per_class = self._build_class_list() + + def _build_sequence_list(self, vid_ids=None, split=None): + if split is not None: + if vid_ids is not None: + raise ValueError('Cannot set both split_name and vid_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'lasot_train_split.txt') + else: + raise ValueError('Unknown split name.') + sequence_list = pandas.read_csv(file_path, header=None, squeeze=True).values.tolist() + elif vid_ids is not None: + sequence_list = [c+'-'+str(v) for c in self.class_list for v in vid_ids] + else: + raise ValueError('Set either split_name or vid_ids.') + + return sequence_list + + def _build_class_list(self): + seq_per_class = {} + for seq_id, seq_name in enumerate(self.sequence_list): + class_name = seq_name.split('-')[0] + if class_name in seq_per_class: + seq_per_class[class_name].append(seq_id) + else: + seq_per_class[class_name] = [seq_id] + + return seq_per_class + + def get_name(self): + return 'lasot' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "full_occlusion.txt") + out_of_view_file = os.path.join(seq_path, "out_of_view.txt") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + with open(out_of_view_file, 'r') as f: + out_of_view = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + + target_visible = ~occlusion & ~out_of_view + + return target_visible + + def _get_sequence_path(self, seq_id): + seq_name = self.sequence_list[seq_id] + class_name = seq_name.split('-')[0] + vid_id = seq_name.split('-')[1] + + return os.path.join(self.root, class_name, class_name + '-' + vid_id) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = self._read_target_visible(seq_path) & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, 'img', '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def _get_class(self, seq_path): + raw_class = seq_path.split('/')[-2] + return raw_class + + def get_class_name(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + obj_class = self._get_class(seq_path) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + + obj_class = self._get_class(seq_path) + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/dataset/lasot_lmdb.py b/Stark/lib/train/dataset/lasot_lmdb.py new file mode 100755 index 0000000..51f54ed --- /dev/null +++ b/Stark/lib/train/dataset/lasot_lmdb.py @@ -0,0 +1,165 @@ +import os +import os.path +import torch +import numpy as np +import pandas +import csv +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from lib.train.data import jpeg4py_loader +from lib.train.admin import env_settings +'''2021.1.16 Lasot for loading lmdb dataset''' +from lib.utils.lmdb_utils import * + + +class Lasot_lmdb(BaseVideoDataset): + + def __init__(self, root=None, image_loader=jpeg4py_loader, vid_ids=None, split=None, data_fraction=None): + """ + args: + root - path to the lasot dataset. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + vid_ids - List containing the ids of the videos (1 - 20) used for training. If vid_ids = [1, 3, 5], then the + videos with subscripts -1, -3, and -5 from each class will be used for training. + split - If split='train', the official train split (protocol-II) is used for training. Note: Only one of + vid_ids or split option can be used at a time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().lasot_lmdb_dir if root is None else root + super().__init__('LaSOT_lmdb', root, image_loader) + + self.sequence_list = self._build_sequence_list(vid_ids, split) + class_list = [seq_name.split('-')[0] for seq_name in self.sequence_list] + self.class_list = [] + for ele in class_list: + if ele not in self.class_list: + self.class_list.append(ele) + # Keep a list of all classes + self.class_to_id = {cls_name: cls_id for cls_id, cls_name in enumerate(self.class_list)} + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.seq_per_class = self._build_class_list() + + def _build_sequence_list(self, vid_ids=None, split=None): + if split is not None: + if vid_ids is not None: + raise ValueError('Cannot set both split_name and vid_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'lasot_train_split.txt') + else: + raise ValueError('Unknown split name.') + sequence_list = pandas.read_csv(file_path, header=None, squeeze=True).values.tolist() + elif vid_ids is not None: + sequence_list = [c+'-'+str(v) for c in self.class_list for v in vid_ids] + else: + raise ValueError('Set either split_name or vid_ids.') + + return sequence_list + + def _build_class_list(self): + seq_per_class = {} + for seq_id, seq_name in enumerate(self.sequence_list): + class_name = seq_name.split('-')[0] + if class_name in seq_per_class: + seq_per_class[class_name].append(seq_id) + else: + seq_per_class[class_name] = [seq_id] + + return seq_per_class + + def get_name(self): + return 'lasot_lmdb' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt_str_list = decode_str(self.root, bb_anno_file).split('\n')[:-1] # the last line is empty + gt_list = [list(map(float, line.split(','))) for line in gt_str_list] + gt_arr = np.array(gt_list).astype(np.float32) + return torch.tensor(gt_arr) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "full_occlusion.txt") + out_of_view_file = os.path.join(seq_path, "out_of_view.txt") + + occ_list = list(map(int, decode_str(self.root, occlusion_file).split(','))) + occlusion = torch.ByteTensor(occ_list) + out_view_list = list(map(int, decode_str(self.root, out_of_view_file).split(','))) + out_of_view = torch.ByteTensor(out_view_list) + + target_visible = ~occlusion & ~out_of_view + + return target_visible + + def _get_sequence_path(self, seq_id): + seq_name = self.sequence_list[seq_id] + class_name = seq_name.split('-')[0] + vid_id = seq_name.split('-')[1] + + return os.path.join(class_name, class_name + '-' + vid_id) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = self._read_target_visible(seq_path) & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, 'img', '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return decode_img(self.root, self._get_frame_path(seq_path, frame_id)) + + def _get_class(self, seq_path): + raw_class = seq_path.split('/')[-2] + return raw_class + + def get_class_name(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + obj_class = self._get_class(seq_path) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + + obj_class = self._get_class(seq_path) + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/dataset/tracking_net.py b/Stark/lib/train/dataset/tracking_net.py new file mode 100755 index 0000000..dbf2201 --- /dev/null +++ b/Stark/lib/train/dataset/tracking_net.py @@ -0,0 +1,151 @@ +import torch +import os +import os.path +import numpy as np +import pandas +import random +from collections import OrderedDict + +from lib.train.data import jpeg4py_loader +from .base_video_dataset import BaseVideoDataset +from lib.train.admin import env_settings + + +def list_sequences(root, set_ids): + """ Lists all the videos in the input set_ids. Returns a list of tuples (set_id, video_name) + + args: + root: Root directory to TrackingNet + set_ids: Sets (0-11) which are to be used + + returns: + list - list of tuples (set_id, video_name) containing the set_id and video_name for each sequence + """ + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, "TRAIN_" + str(s), "anno") + + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + sequence_list += sequences_cur_set + + return sequence_list + + +class TrackingNet(BaseVideoDataset): + """ TrackingNet dataset. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, set_ids=None, data_fraction=None): + """ + args: + root - The path to the TrackingNet folder, containing the training sets. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + set_ids (None) - List containing the ids of the TrackingNet sets to be used for training. If None, all the + sets (0 - 11) will be used. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().trackingnet_dir if root is None else root + super().__init__('TrackingNet', root, image_loader) + + if set_ids is None: + set_ids = [i for i in range(12)] + + self.set_ids = set_ids + + # Keep a list of all videos. Sequence list is a list of tuples (set_id, video_name) containing the set_id and + # video_name for each sequence + self.sequence_list = list_sequences(self.root, self.set_ids) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list) * data_fraction)) + + self.seq_to_class_map, self.seq_per_class = self._load_class_info() + + # we do not have the class_lists for the tracking net + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def _load_class_info(self): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + class_map_path = os.path.join(ltr_path, 'data_specs', 'trackingnet_classmap.txt') + + with open(class_map_path, 'r') as f: + seq_to_class_map = {seq_class.split('\t')[0]: seq_class.rstrip().split('\t')[1] for seq_class in f} + + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = seq_to_class_map.get(seq[1], 'Unknown') + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_to_class_map, seq_per_class + + def get_name(self): + return 'trackingnet' + + def has_class_info(self): + return True + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + bb_anno_file = os.path.join(self.root, "TRAIN_" + str(set_id), "anno", vid_name + ".txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, + low_memory=False).values + return torch.tensor(gt) + + def get_sequence_info(self, seq_id): + bbox = self._read_bb_anno(seq_id) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame(self, seq_id, frame_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + frame_path = os.path.join(self.root, "TRAIN_" + str(set_id), "frames", vid_name, str(frame_id) + ".jpg") + return self.image_loader(frame_path) + + def _get_class(self, seq_id): + seq_name = self.sequence_list[seq_id][1] + return self.seq_to_class_map[seq_name] + + def get_class_name(self, seq_id): + obj_class = self._get_class(seq_id) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + frame_list = [self._get_frame(seq_id, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + obj_class = self._get_class(seq_id) + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/dataset/tracking_net_lmdb.py b/Stark/lib/train/dataset/tracking_net_lmdb.py new file mode 100755 index 0000000..4f6b098 --- /dev/null +++ b/Stark/lib/train/dataset/tracking_net_lmdb.py @@ -0,0 +1,147 @@ +import torch +import os +import os.path +import numpy as np +import random +from collections import OrderedDict + +from lib.train.data import jpeg4py_loader +from .base_video_dataset import BaseVideoDataset +from lib.train.admin import env_settings +import json +from lib.utils.lmdb_utils import decode_img, decode_str + + +def list_sequences(root): + """ Lists all the videos in the input set_ids. Returns a list of tuples (set_id, video_name) + + args: + root: Root directory to TrackingNet + + returns: + list - list of tuples (set_id, video_name) containing the set_id and video_name for each sequence + """ + fname = os.path.join(root, "seq_list.json") + with open(fname, "r") as f: + sequence_list = json.loads(f.read()) + return sequence_list + + +class TrackingNet_lmdb(BaseVideoDataset): + """ TrackingNet dataset. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, set_ids=None, data_fraction=None): + """ + args: + root - The path to the TrackingNet folder, containing the training sets. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + set_ids (None) - List containing the ids of the TrackingNet sets to be used for training. If None, all the + sets (0 - 11) will be used. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().trackingnet_lmdb_dir if root is None else root + super().__init__('TrackingNet_lmdb', root, image_loader) + + if set_ids is None: + set_ids = [i for i in range(12)] + + self.set_ids = set_ids + + # Keep a list of all videos. Sequence list is a list of tuples (set_id, video_name) containing the set_id and + # video_name for each sequence + self.sequence_list = list_sequences(self.root) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list) * data_fraction)) + + self.seq_to_class_map, self.seq_per_class = self._load_class_info() + + # we do not have the class_lists for the tracking net + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def _load_class_info(self): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + class_map_path = os.path.join(ltr_path, 'data_specs', 'trackingnet_classmap.txt') + + with open(class_map_path, 'r') as f: + seq_to_class_map = {seq_class.split('\t')[0]: seq_class.rstrip().split('\t')[1] for seq_class in f} + + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = seq_to_class_map.get(seq[1], 'Unknown') + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_to_class_map, seq_per_class + + def get_name(self): + return 'trackingnet_lmdb' + + def has_class_info(self): + return True + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + gt_str_list = decode_str(os.path.join(self.root, "TRAIN_%d_lmdb" % set_id), + os.path.join("anno", vid_name + ".txt")).split('\n')[:-1] + gt_list = [list(map(float, line.split(','))) for line in gt_str_list] + gt_arr = np.array(gt_list).astype(np.float32) + return torch.tensor(gt_arr) + + def get_sequence_info(self, seq_id): + bbox = self._read_bb_anno(seq_id) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame(self, seq_id, frame_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + return decode_img(os.path.join(self.root, "TRAIN_%d_lmdb" % set_id), + os.path.join("frames", vid_name, str(frame_id) + ".jpg")) + + def _get_class(self, seq_id): + seq_name = self.sequence_list[seq_id][1] + return self.seq_to_class_map[seq_name] + + def get_class_name(self, seq_id): + obj_class = self._get_class(seq_id) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + frame_list = [self._get_frame(seq_id, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + obj_class = self._get_class(seq_id) + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/Stark/lib/train/run_training.py b/Stark/lib/train/run_training.py new file mode 100755 index 0000000..f681ce7 --- /dev/null +++ b/Stark/lib/train/run_training.py @@ -0,0 +1,91 @@ +import os +import sys +import argparse +import importlib +import cv2 as cv +import torch.backends.cudnn +import torch.distributed as dist + +import random +import numpy as np +torch.backends.cudnn.benchmark = False + +import _init_paths +import lib.train.admin.settings as ws_settings + + +def init_seeds(seed): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + +def run_training(script_name, config_name, cudnn_benchmark=True, local_rank=-1, save_dir=None, base_seed=None, + use_lmdb=False, script_name_prv=None, config_name_prv=None): + """Run the train script. + args: + script_name: Name of emperiment in the "experiments/" folder. + config_name: Name of the yaml file in the "experiments/". + cudnn_benchmark: Use cudnn benchmark or not (default is True). + """ + if save_dir is None: + print("save_dir dir is not given. Use the default dir instead.") + # This is needed to avoid strange crashes related to opencv + cv.setNumThreads(0) + + torch.backends.cudnn.benchmark = cudnn_benchmark + + print('script_name: {}.py config_name: {}.yaml'.format(script_name, config_name)) + + '''2021.1.5 set seed for different process''' + if base_seed is not None: + if local_rank != -1: + init_seeds(base_seed + local_rank) + else: + init_seeds(base_seed) + + settings = ws_settings.Settings() + settings.script_name = script_name + settings.config_name = config_name + settings.project_path = 'train/{}/{}'.format(script_name, config_name) + if script_name_prv is not None and config_name_prv is not None: + settings.project_path_prv = 'train/{}/{}'.format(script_name_prv, config_name_prv) + settings.local_rank = local_rank + settings.save_dir = os.path.abspath(save_dir) + settings.use_lmdb = use_lmdb + prj_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")) + settings.cfg_file = os.path.join(prj_dir, 'experiments/%s/%s.yaml' % (script_name, config_name)) + + expr_module = importlib.import_module('lib.train.train_script') + expr_func = getattr(expr_module, 'run') + + expr_func(settings) + + +def main(): + parser = argparse.ArgumentParser(description='Run a train scripts in train_settings.') + parser.add_argument('--script', type=str, required=True, help='Name of the train script.') + parser.add_argument('--config', type=str, required=True, help="Name of the config file.") + parser.add_argument('--cudnn_benchmark', type=bool, default=True, help='Set cudnn benchmark on (1) or off (0) (default is on).') + parser.add_argument('--local_rank', default=-1, type=int, help='node rank for distributed training') + parser.add_argument('--save_dir', type=str, help='the directory to save checkpoints and logs') + parser.add_argument('--seed', type=int, default=42, help='seed for random numbers') + parser.add_argument('--use_lmdb', type=int, choices=[0, 1], default=0) # whether datasets are in lmdb format + parser.add_argument('--script_prv', type=str, default=None, help='Name of the train script of previous model.') + parser.add_argument('--config_prv', type=str, default=None, help="Name of the config file of previous model.") + args = parser.parse_args() + if args.local_rank != -1: + dist.init_process_group(backend='nccl') + torch.cuda.set_device(args.local_rank) + else: + torch.cuda.set_device(0) + run_training(args.script, args.config, cudnn_benchmark=args.cudnn_benchmark, + local_rank=args.local_rank, save_dir=args.save_dir, base_seed=args.seed, + use_lmdb=args.use_lmdb, script_name_prv=args.script_prv, config_name_prv=args.config_prv) + + +if __name__ == '__main__': + main() diff --git a/Stark/lib/train/train_script.py b/Stark/lib/train/train_script.py new file mode 100755 index 0000000..8da2b46 --- /dev/null +++ b/Stark/lib/train/train_script.py @@ -0,0 +1,88 @@ +import os +# loss function related +from lib.utils.box_ops import giou_loss +from torch.nn.functional import l1_loss +from torch.nn import BCEWithLogitsLoss +# train pipeline related +from lib.train.trainers import LTRTrainer +# distributed training related +from torch.nn.parallel import DistributedDataParallel as DDP +# some more advanced functions +from .base_functions import * +# network related +from lib.models.stark import build_starks, build_starkst +# forward propagation related +from lib.train.actors import STARKSActor, STARKSTActor +# for import modules +import importlib + + +def run(settings): + settings.description = 'Training script for STARK-S, STARK-ST stage1, and STARK-ST stage2' + + # update the default configs with config file + if not os.path.exists(settings.cfg_file): + raise ValueError("%s doesn't exist." % settings.cfg_file) + config_module = importlib.import_module("lib.config.%s.config" % settings.script_name) + cfg = config_module.cfg + config_module.update_config_from_file(settings.cfg_file) + if settings.local_rank in [-1, 0]: + print("New configuration is shown below.") + for key in cfg.keys(): + print("%s configuration:" % key, cfg[key]) + print('\n') + + # update settings based on cfg + update_settings(settings, cfg) + + # Record the training log + log_dir = os.path.join(settings.save_dir, 'logs') + if settings.local_rank in [-1, 0]: + if not os.path.exists(log_dir): + os.makedirs(log_dir) + settings.log_file = os.path.join(log_dir, "%s-%s.log" % (settings.script_name, settings.config_name)) + + # Build dataloaders + loader_train, loader_val = build_dataloaders(cfg, settings) + + # Create network + if settings.script_name == "stark_s": + net = build_starks(cfg) + elif settings.script_name == "stark_st1" or settings.script_name == "stark_st2": + net = build_starkst(cfg) + else: + raise ValueError("illegal script name") + + # wrap networks to distributed one + net.cuda() + if settings.local_rank != -1: + net = DDP(net, device_ids=[settings.local_rank], find_unused_parameters=True) + settings.device = torch.device("cuda:%d" % settings.local_rank) + else: + settings.device = torch.device("cuda:0") + + # Loss functions and Actors + if settings.script_name == "stark_s" or settings.script_name == "stark_st1": + objective = {'giou': giou_loss, 'l1': l1_loss} + loss_weight = {'giou': cfg.TRAIN.GIOU_WEIGHT, 'l1': cfg.TRAIN.L1_WEIGHT} + actor = STARKSActor(net=net, objective=objective, loss_weight=loss_weight, settings=settings) + elif settings.script_name == "stark_st2": + objective = {'cls': BCEWithLogitsLoss()} + loss_weight = {'cls': 1.0} + actor = STARKSTActor(net=net, objective=objective, loss_weight=loss_weight, settings=settings) + else: + raise ValueError("illegal script name") + + if cfg.TRAIN.DEEP_SUPERVISION: + raise ValueError("Deep supervision is not supported now.") + + # Optimizer, parameters, and learning rates + optimizer, lr_scheduler = get_optimizer_scheduler(net, cfg) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # train process + if settings.script_name == "stark_st2": + trainer.train(cfg.TRAIN.EPOCH, load_latest=True, fail_safe=True, load_previous_ckpt=True) + else: + trainer.train(cfg.TRAIN.EPOCH, load_latest=True, fail_safe=True) diff --git a/Stark/lib/train/trainers/__init__.py b/Stark/lib/train/trainers/__init__.py new file mode 100755 index 0000000..c3fae45 --- /dev/null +++ b/Stark/lib/train/trainers/__init__.py @@ -0,0 +1,2 @@ +from .base_trainer import BaseTrainer +from .ltr_trainer import LTRTrainer diff --git a/Stark/lib/train/trainers/base_trainer.py b/Stark/lib/train/trainers/base_trainer.py new file mode 100755 index 0000000..ba79047 --- /dev/null +++ b/Stark/lib/train/trainers/base_trainer.py @@ -0,0 +1,265 @@ +import os +import glob +import torch +import traceback +from lib.train.admin import multigpu +from torch.utils.data.distributed import DistributedSampler + + +class BaseTrainer: + """Base trainer class. Contains functions for training and saving/loading checkpoints. + Trainer classes should inherit from this one and overload the train_epoch function.""" + + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + self.actor = actor + self.optimizer = optimizer + self.lr_scheduler = lr_scheduler + self.loaders = loaders + + self.update_settings(settings) + + self.epoch = 0 + self.stats = {} + + self.device = getattr(settings, 'device', None) + if self.device is None: + self.device = torch.device("cuda:0" if torch.cuda.is_available() and settings.use_gpu else "cpu") + + self.actor.to(self.device) + self.settings = settings + + def update_settings(self, settings=None): + """Updates the trainer settings. Must be called to update internal settings.""" + if settings is not None: + self.settings = settings + + if self.settings.env.workspace_dir is not None: + self.settings.env.workspace_dir = os.path.expanduser(self.settings.env.workspace_dir) + '''2021.1.4 New function: specify checkpoint dir''' + if self.settings.save_dir is None: + self._checkpoint_dir = os.path.join(self.settings.env.workspace_dir, 'checkpoints') + else: + self._checkpoint_dir = os.path.join(self.settings.save_dir, 'checkpoints') + print("checkpoints will be saved to %s" % self._checkpoint_dir) + + if self.settings.local_rank in [-1, 0]: + if not os.path.exists(self._checkpoint_dir): + print("Training with multiple GPUs. checkpoints directory doesn't exist. " + "Create checkpoints directory") + os.makedirs(self._checkpoint_dir) + else: + self._checkpoint_dir = None + + def train(self, max_epochs, load_latest=False, fail_safe=True, load_previous_ckpt=False): + """Do training for the given number of epochs. + args: + max_epochs - Max number of training epochs, + load_latest - Bool indicating whether to resume from latest epoch. + fail_safe - Bool indicating whether the training to automatically restart in case of any crashes. + """ + + epoch = -1 + num_tries = 1 + for i in range(num_tries): + try: + if load_latest: + self.load_checkpoint() + if load_previous_ckpt: + directory = '{}/{}'.format(self._checkpoint_dir, self.settings.project_path_prv) + self.load_state_dict(directory) + + for epoch in range(self.epoch+1, max_epochs+1): + self.epoch = epoch + + self.train_epoch() + + if self.lr_scheduler is not None: + if self.settings.scheduler_type != 'cosine': + self.lr_scheduler.step() + else: + self.lr_scheduler.step(epoch - 1) + # only save the last 10 checkpoints + save_every_epoch = getattr(self.settings, "save_every_epoch", False) + if epoch > (max_epochs - 10) or save_every_epoch or epoch % 100 == 0: + if self._checkpoint_dir: + if self.settings.local_rank in [-1, 0]: + self.save_checkpoint() + except: + print('Training crashed at epoch {}'.format(epoch)) + if fail_safe: + self.epoch -= 1 + load_latest = True + print('Traceback for the error!') + print(traceback.format_exc()) + print('Restarting training from last epoch ...') + else: + raise + + print('Finished training!') + + def train_epoch(self): + raise NotImplementedError + + def save_checkpoint(self): + """Saves a checkpoint of the network and other variables.""" + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + state = { + 'epoch': self.epoch, + 'actor_type': actor_type, + 'net_type': net_type, + 'net': net.state_dict(), + 'net_info': getattr(net, 'info', None), + 'constructor': getattr(net, 'constructor', None), + 'optimizer': self.optimizer.state_dict(), + 'stats': self.stats, + 'settings': self.settings + } + + directory = '{}/{}'.format(self._checkpoint_dir, self.settings.project_path) + print(directory) + if not os.path.exists(directory): + print("directory doesn't exist. creating...") + os.makedirs(directory) + + # First save as a tmp file + tmp_file_path = '{}/{}_ep{:04d}.tmp'.format(directory, net_type, self.epoch) + torch.save(state, tmp_file_path) + + file_path = '{}/{}_ep{:04d}.pth.tar'.format(directory, net_type, self.epoch) + + # Now rename to actual checkpoint. os.rename seems to be atomic if files are on same filesystem. Not 100% sure + os.rename(tmp_file_path, file_path) + + def load_checkpoint(self, checkpoint = None, fields = None, ignore_fields = None, load_constructor = False): + """Loads a network checkpoint file. + + Can be called in three different ways: + load_checkpoint(): + Loads the latest epoch from the workspace. Use this to continue training. + load_checkpoint(epoch_num): + Loads the network at the given epoch number (int). + load_checkpoint(path_to_checkpoint): + Loads the file from the given absolute path (str). + """ + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + + if checkpoint is None: + # Load most recent checkpoint + checkpoint_list = sorted(glob.glob('{}/{}/{}_ep*.pth.tar'.format(self._checkpoint_dir, + self.settings.project_path, net_type))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + print('No matching checkpoint file found') + return + elif isinstance(checkpoint, int): + # Checkpoint is the epoch number + checkpoint_path = '{}/{}/{}_ep{:04d}.pth.tar'.format(self._checkpoint_dir, self.settings.project_path, + net_type, checkpoint) + elif isinstance(checkpoint, str): + # checkpoint is the path + if os.path.isdir(checkpoint): + checkpoint_list = sorted(glob.glob('{}/*_ep*.pth.tar'.format(checkpoint))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No checkpoint found') + else: + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + checkpoint_dict = torch.load(checkpoint_path) + + assert net_type == checkpoint_dict['net_type'], 'Network is not of correct type.' + + if fields is None: + fields = checkpoint_dict.keys() + if ignore_fields is None: + ignore_fields = ['settings'] + + # Never load the scheduler. It exists in older checkpoints. + ignore_fields.extend(['lr_scheduler', 'constructor', 'net_type', 'actor_type', 'net_info']) + + # Load all fields + for key in fields: + if key in ignore_fields: + continue + if key == 'net': + net.load_state_dict(checkpoint_dict[key]) + elif key == 'optimizer': + self.optimizer.load_state_dict(checkpoint_dict[key]) + else: + setattr(self, key, checkpoint_dict[key]) + + # Set the net info + if load_constructor and 'constructor' in checkpoint_dict and checkpoint_dict['constructor'] is not None: + net.constructor = checkpoint_dict['constructor'] + if 'net_info' in checkpoint_dict and checkpoint_dict['net_info'] is not None: + net.info = checkpoint_dict['net_info'] + + # Update the epoch in lr scheduler + if 'epoch' in fields: + self.lr_scheduler.last_epoch = self.epoch + # 2021.1.10 Update the epoch in data_samplers + for loader in self.loaders: + if isinstance(loader.sampler, DistributedSampler): + loader.sampler.set_epoch(self.epoch) + return True + + def load_state_dict(self, checkpoint=None): + """Loads a network checkpoint file. + + Can be called in three different ways: + load_checkpoint(): + Loads the latest epoch from the workspace. Use this to continue training. + load_checkpoint(epoch_num): + Loads the network at the given epoch number (int). + load_checkpoint(path_to_checkpoint): + Loads the file from the given absolute path (str). + """ + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + net_type = type(net).__name__ + + if isinstance(checkpoint, str): + # checkpoint is the path + if os.path.isdir(checkpoint): + checkpoint_list = sorted(glob.glob('{}/*_ep*.pth.tar'.format(checkpoint))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No checkpoint found') + else: + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + print("Loading pretrained model from ", checkpoint_path) + checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') + + assert net_type == checkpoint_dict['net_type'], 'Network is not of correct type.' + + net.load_state_dict(checkpoint_dict["net"], strict=True) + + return True diff --git a/Stark/lib/train/trainers/ltr_trainer.py b/Stark/lib/train/trainers/ltr_trainer.py new file mode 100755 index 0000000..5b4265b --- /dev/null +++ b/Stark/lib/train/trainers/ltr_trainer.py @@ -0,0 +1,156 @@ +import os +from collections import OrderedDict +from lib.train.trainers import BaseTrainer +from lib.train.admin import AverageMeter, StatValue +from lib.train.admin import TensorboardWriter +import torch +import time +from torch.utils.data.distributed import DistributedSampler + + +class LTRTrainer(BaseTrainer): + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + super().__init__(actor, loaders, optimizer, settings, lr_scheduler) + + self._set_default_settings() + + # Initialize statistics variables + self.stats = OrderedDict({loader.name: None for loader in self.loaders}) + + # Initialize tensorboard + if settings.local_rank in [-1, 0]: + tensorboard_writer_dir = os.path.join(self.settings.env.tensorboard_dir, self.settings.project_path) + if not os.path.exists(tensorboard_writer_dir): + os.makedirs(tensorboard_writer_dir) + self.tensorboard_writer = TensorboardWriter(tensorboard_writer_dir, [l.name for l in loaders]) + + self.move_data_to_gpu = getattr(settings, 'move_data_to_gpu', True) + self.settings = settings + + def _set_default_settings(self): + # Dict of all default values + default = {'print_interval': 10, + 'print_stats': None, + 'description': ''} + + for param, default_value in default.items(): + if getattr(self.settings, param, None) is None: + setattr(self.settings, param, default_value) + + def cycle_dataset(self, loader): + """Do a cycle of training or validation.""" + + self.actor.train(loader.training) + torch.set_grad_enabled(loader.training) + + self._init_timing() + + for i, data in enumerate(loader, 1): + # get inputs + if self.move_data_to_gpu: + data = data.to(self.device) + + data['epoch'] = self.epoch + data['settings'] = self.settings + # forward pass + loss, stats = self.actor(data) + + # backward pass and update weights + if loader.training: + self.optimizer.zero_grad() + loss.backward() + if self.settings.grad_clip_norm > 0: + torch.nn.utils.clip_grad_norm_(self.actor.net.parameters(), self.settings.grad_clip_norm) + self.optimizer.step() + + # update statistics + batch_size = data['template_images'].shape[loader.stack_dim] + self._update_stats(stats, batch_size, loader) + + # print statistics + self._print_stats(i, loader, batch_size) + + def train_epoch(self): + """Do one epoch for each loader.""" + for loader in self.loaders: + if self.epoch % loader.epoch_interval == 0: + # 2021.1.10 Set epoch + if isinstance(loader.sampler, DistributedSampler): + loader.sampler.set_epoch(self.epoch) + self.cycle_dataset(loader) + + self._stats_new_epoch() + if self.settings.local_rank in [-1, 0]: + self._write_tensorboard() + + def _init_timing(self): + self.num_frames = 0 + self.start_time = time.time() + self.prev_time = self.start_time + + def _update_stats(self, new_stats: OrderedDict, batch_size, loader): + # Initialize stats if not initialized yet + if loader.name not in self.stats.keys() or self.stats[loader.name] is None: + self.stats[loader.name] = OrderedDict({name: AverageMeter() for name in new_stats.keys()}) + + for name, val in new_stats.items(): + if name not in self.stats[loader.name].keys(): + self.stats[loader.name][name] = AverageMeter() + self.stats[loader.name][name].update(val, batch_size) + + def _print_stats(self, i, loader, batch_size): + self.num_frames += batch_size + current_time = time.time() + batch_fps = batch_size / (current_time - self.prev_time) + average_fps = self.num_frames / (current_time - self.start_time) + self.prev_time = current_time + if i % self.settings.print_interval == 0 or i == loader.__len__(): + print_str = '[%s: %d, %d / %d] ' % (loader.name, self.epoch, i, loader.__len__()) + print_str += 'FPS: %.1f (%.1f) , ' % (average_fps, batch_fps) + for name, val in self.stats[loader.name].items(): + if (self.settings.print_stats is None or name in self.settings.print_stats): + if hasattr(val, 'avg'): + print_str += '%s: %.5f , ' % (name, val.avg) + # else: + # print_str += '%s: %r , ' % (name, val) + + print(print_str[:-5]) + log_str = print_str[:-5] + '\n' + with open(self.settings.log_file, 'a') as f: + f.write(log_str) + + def _stats_new_epoch(self): + # Record learning rate + for loader in self.loaders: + if loader.training: + try: + lr_list = self.lr_scheduler.get_lr() + except: + lr_list = self.lr_scheduler._get_lr(self.epoch) + for i, lr in enumerate(lr_list): + var_name = 'LearningRate/group{}'.format(i) + if var_name not in self.stats[loader.name].keys(): + self.stats[loader.name][var_name] = StatValue() + self.stats[loader.name][var_name].update(lr) + + for loader_stats in self.stats.values(): + if loader_stats is None: + continue + for stat_value in loader_stats.values(): + if hasattr(stat_value, 'new_epoch'): + stat_value.new_epoch() + + def _write_tensorboard(self): + if self.epoch == 1: + self.tensorboard_writer.write_info(self.settings.script_name, self.settings.description) + + self.tensorboard_writer.write_epoch(self.stats, self.epoch) diff --git a/Stark/lib/utils/__init__.py b/Stark/lib/utils/__init__.py new file mode 100755 index 0000000..b8845fd --- /dev/null +++ b/Stark/lib/utils/__init__.py @@ -0,0 +1 @@ +from .tensor import TensorDict, TensorList diff --git a/Stark/lib/utils/__pycache__/__init__.cpython-37.pyc b/Stark/lib/utils/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..7aafa7a Binary files /dev/null and b/Stark/lib/utils/__pycache__/__init__.cpython-37.pyc differ diff --git a/Stark/lib/utils/__pycache__/box_ops.cpython-37.pyc b/Stark/lib/utils/__pycache__/box_ops.cpython-37.pyc new file mode 100755 index 0000000..ddd638d Binary files /dev/null and b/Stark/lib/utils/__pycache__/box_ops.cpython-37.pyc differ diff --git a/Stark/lib/utils/__pycache__/lmdb_utils.cpython-37.pyc b/Stark/lib/utils/__pycache__/lmdb_utils.cpython-37.pyc new file mode 100755 index 0000000..a5f4669 Binary files /dev/null and b/Stark/lib/utils/__pycache__/lmdb_utils.cpython-37.pyc differ diff --git a/Stark/lib/utils/__pycache__/merge.cpython-37.pyc b/Stark/lib/utils/__pycache__/merge.cpython-37.pyc new file mode 100755 index 0000000..2b06880 Binary files /dev/null and b/Stark/lib/utils/__pycache__/merge.cpython-37.pyc differ diff --git a/Stark/lib/utils/__pycache__/misc.cpython-37.pyc b/Stark/lib/utils/__pycache__/misc.cpython-37.pyc new file mode 100755 index 0000000..747f15c Binary files /dev/null and b/Stark/lib/utils/__pycache__/misc.cpython-37.pyc differ diff --git a/Stark/lib/utils/__pycache__/tensor.cpython-37.pyc b/Stark/lib/utils/__pycache__/tensor.cpython-37.pyc new file mode 100755 index 0000000..52a189e Binary files /dev/null and b/Stark/lib/utils/__pycache__/tensor.cpython-37.pyc differ diff --git a/Stark/lib/utils/box_ops.py b/Stark/lib/utils/box_ops.py new file mode 100755 index 0000000..1bff339 --- /dev/null +++ b/Stark/lib/utils/box_ops.py @@ -0,0 +1,106 @@ +import torch +from torchvision.ops.boxes import box_area +import numpy as np + + +def box_cxcywh_to_xyxy(x): + x_c, y_c, w, h = x.unbind(-1) + b = [(x_c - 0.5 * w), (y_c - 0.5 * h), + (x_c + 0.5 * w), (y_c + 0.5 * h)] + return torch.stack(b, dim=-1) + + +def box_xywh_to_xyxy(x): + x1, y1, w, h = x.unbind(-1) + b = [x1, y1, x1 + w, y1 + h] + return torch.stack(b, dim=-1) + + +def box_xyxy_to_xywh(x): + x1, y1, x2, y2 = x.unbind(-1) + b = [x1, y1, x2 - x1, y2 - y1] + return torch.stack(b, dim=-1) + + +def box_xyxy_to_cxcywh(x): + x0, y0, x1, y1 = x.unbind(-1) + b = [(x0 + x1) / 2, (y0 + y1) / 2, + (x1 - x0), (y1 - y0)] + return torch.stack(b, dim=-1) + + +# modified from torchvision to also return the union +'''Note that this function only supports shape (N,4)''' + + +def box_iou(boxes1, boxes2): + """ + + :param boxes1: (N, 4) (x1,y1,x2,y2) + :param boxes2: (N, 4) (x1,y1,x2,y2) + :return: + """ + area1 = box_area(boxes1) # (N,) + area2 = box_area(boxes2) # (N,) + + lt = torch.max(boxes1[:, :2], boxes2[:, :2]) # (N,2) + rb = torch.min(boxes1[:, 2:], boxes2[:, 2:]) # (N,2) + + wh = (rb - lt).clamp(min=0) # (N,2) + inter = wh[:, 0] * wh[:, 1] # (N,) + + union = area1 + area2 - inter + + iou = inter / union + return iou, union + + +'''Note that this implementation is different from DETR's''' + + +def generalized_box_iou(boxes1, boxes2): + """ + Generalized IoU from https://giou.stanford.edu/ + + The boxes should be in [x0, y0, x1, y1] format + + boxes1: (N, 4) + boxes2: (N, 4) + """ + # degenerate boxes gives inf / nan results + # so do an early check + # try: + assert (boxes1[:, 2:] >= boxes1[:, :2]).all() + assert (boxes2[:, 2:] >= boxes2[:, :2]).all() + iou, union = box_iou(boxes1, boxes2) # (N,) + + lt = torch.min(boxes1[:, :2], boxes2[:, :2]) + rb = torch.max(boxes1[:, 2:], boxes2[:, 2:]) + + wh = (rb - lt).clamp(min=0) # (N,2) + area = wh[:, 0] * wh[:, 1] # (N,) + + return iou - (area - union) / area, iou + + +def giou_loss(boxes1, boxes2): + """ + + :param boxes1: (N, 4) (x1,y1,x2,y2) + :param boxes2: (N, 4) (x1,y1,x2,y2) + :return: + """ + giou, iou = generalized_box_iou(boxes1, boxes2) + return (1 - giou).mean(), iou + + +def clip_box(box: list, H, W, margin=0): + x1, y1, w, h = box + x2, y2 = x1 + w, y1 + h + x1 = min(max(0, x1), W-margin) + x2 = min(max(margin, x2), W) + y1 = min(max(0, y1), H-margin) + y2 = min(max(margin, y2), H) + w = max(margin, x2-x1) + h = max(margin, y2-y1) + return [x1, y1, w, h] diff --git a/Stark/lib/utils/lmdb_utils.py b/Stark/lib/utils/lmdb_utils.py new file mode 100755 index 0000000..4cf1fbe --- /dev/null +++ b/Stark/lib/utils/lmdb_utils.py @@ -0,0 +1,55 @@ +import lmdb +import numpy as np +import cv2 +import json + +LMDB_ENVS = dict() +LMDB_HANDLES = dict() +LMDB_FILELISTS = dict() + + +def get_lmdb_handle(name): + global LMDB_HANDLES, LMDB_FILELISTS + item = LMDB_HANDLES.get(name, None) + if item is None: + env = lmdb.open(name, readonly=True, lock=False, readahead=False, meminit=False) + LMDB_ENVS[name] = env + item = env.begin(write=False) + LMDB_HANDLES[name] = item + + return item + + +def decode_img(lmdb_fname, key_name): + handle = get_lmdb_handle(lmdb_fname) + binfile = handle.get(key_name.encode()) + if binfile is None: + print("Illegal data detected. %s %s" % (lmdb_fname, key_name)) + s = np.frombuffer(binfile, np.uint8) + x = cv2.cvtColor(cv2.imdecode(s, cv2.IMREAD_COLOR), cv2.COLOR_BGR2RGB) + return x + + +def decode_str(lmdb_fname, key_name): + handle = get_lmdb_handle(lmdb_fname) + binfile = handle.get(key_name.encode()) + string = binfile.decode() + return string + + +def decode_json(lmdb_fname, key_name): + return json.loads(decode_str(lmdb_fname, key_name)) + + +if __name__ == "__main__": + lmdb_fname = "/data/sda/v-yanbi/iccv21/LittleBoy_clean/data/got10k_lmdb" + '''Decode image''' + # key_name = "test/GOT-10k_Test_000001/00000001.jpg" + # img = decode_img(lmdb_fname, key_name) + # cv2.imwrite("001.jpg", img) + '''Decode str''' + # key_name = "test/list.txt" + # key_name = "train/GOT-10k_Train_000001/groundtruth.txt" + key_name = "train/GOT-10k_Train_000001/absence.label" + str_ = decode_str(lmdb_fname, key_name) + print(str_) diff --git a/Stark/lib/utils/merge.py b/Stark/lib/utils/merge.py new file mode 100755 index 0000000..1b5c0aa --- /dev/null +++ b/Stark/lib/utils/merge.py @@ -0,0 +1,7 @@ +import torch + + +def merge_template_search(inp_list): + return {"feat": torch.cat([x["feat"] for x in inp_list], dim=0), + "mask": torch.cat([x["mask"] for x in inp_list], dim=1), + "pos": torch.cat([x["pos"] for x in inp_list], dim=0)} diff --git a/Stark/lib/utils/misc.py b/Stark/lib/utils/misc.py new file mode 100755 index 0000000..1ea375e --- /dev/null +++ b/Stark/lib/utils/misc.py @@ -0,0 +1,467 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +Misc functions, including distributed helpers. + +Mostly copy-paste from torchvision references. +""" +import os +import subprocess +import time +from collections import defaultdict, deque +import datetime +import pickle +from typing import Optional, List + +import torch +import torch.distributed as dist +from torch import Tensor + +# needed due to empty tensor bug in pytorch and torchvision 0.5 +import torchvision +if float(torchvision.__version__[:3]) < 0.7: + from torchvision.ops import _new_empty_tensor + from torchvision.ops.misc import _output_size + + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda') + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +def all_gather(data): + """ + Run all_gather on arbitrary picklable data (not necessarily tensors) + Args: + data: any picklable object + Returns: + list[data]: list of data gathered from each rank + """ + world_size = get_world_size() + if world_size == 1: + return [data] + + # serialized to a Tensor + buffer = pickle.dumps(data) + storage = torch.ByteStorage.from_buffer(buffer) + tensor = torch.ByteTensor(storage).to("cuda") + + # obtain Tensor size of each rank + local_size = torch.tensor([tensor.numel()], device="cuda") + size_list = [torch.tensor([0], device="cuda") for _ in range(world_size)] + dist.all_gather(size_list, local_size) + size_list = [int(size.item()) for size in size_list] + max_size = max(size_list) + + # receiving Tensor from all ranks + # we pad the tensor because torch all_gather does not support + # gathering tensors of different shapes + tensor_list = [] + for _ in size_list: + tensor_list.append(torch.empty((max_size,), dtype=torch.uint8, device="cuda")) + if local_size != max_size: + padding = torch.empty(size=(max_size - local_size,), dtype=torch.uint8, device="cuda") + tensor = torch.cat((tensor, padding), dim=0) + dist.all_gather(tensor_list, tensor) + + data_list = [] + for size, tensor in zip(size_list, tensor_list): + buffer = tensor.cpu().numpy().tobytes()[:size] + data_list.append(pickle.loads(buffer)) + + return data_list + + +def reduce_dict(input_dict, average=True): + """ + Args: + input_dict (dict): all the values will be reduced + average (bool): whether to do average or sum + Reduce the values in the dictionary from all processes so that all processes + have the averaged results. Returns a dict with the same fields as + input_dict, after reduction. + """ + world_size = get_world_size() + if world_size < 2: + return input_dict + with torch.no_grad(): + names = [] + values = [] + # sort the keys so that they are consistent across processes + for k in sorted(input_dict.keys()): + names.append(k) + values.append(input_dict[k]) + values = torch.stack(values, dim=0) + dist.all_reduce(values) + if average: + values /= world_size + reduced_dict = {k: v for k, v in zip(names, values)} + return reduced_dict + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self): + for meter in self.meters.values(): + meter.synchronize_between_processes() + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, print_freq, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.4f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + if torch.cuda.is_available(): + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}', + 'max mem: {memory:.0f}' + ]) + else: + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ]) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if i % print_freq == 0 or i == len(iterable) - 1: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.cuda.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=torch.cuda.max_memory_allocated() / MB)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {} ({:.4f} s / it)'.format( + header, total_time_str, total_time / len(iterable))) + + +def get_sha(): + cwd = os.path.dirname(os.path.abspath(__file__)) + + def _run(command): + return subprocess.check_output(command, cwd=cwd).decode('ascii').strip() + sha = 'N/A' + diff = "clean" + branch = 'N/A' + try: + sha = _run(['git', 'rev-parse', 'HEAD']) + subprocess.check_output(['git', 'diff'], cwd=cwd) + diff = _run(['git', 'diff-index', 'HEAD']) + diff = "has uncommited changes" if diff else "clean" + branch = _run(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + except Exception: + pass + message = f"sha: {sha}, status: {diff}, branch: {branch}" + return message + + +def collate_fn(batch): + batch = list(zip(*batch)) + batch[0] = nested_tensor_from_tensor_list(batch[0]) + return tuple(batch) + + +def _max_by_axis(the_list): + # type: (List[List[int]]) -> List[int] + maxes = the_list[0] # get the first one + for sublist in the_list[1:]: # [h,w,3] + for index, item in enumerate(sublist): # index: 0,1,2 + maxes[index] = max(maxes[index], item) # compare current max with the other elements in the whole + return maxes + + +class NestedTensor(object): + def __init__(self, tensors, mask: Optional[Tensor]): + self.tensors = tensors + self.mask = mask + + def to(self, device): + # type: (Device) -> NestedTensor # noqa + cast_tensor = self.tensors.to(device) + mask = self.mask + if mask is not None: + assert mask is not None + cast_mask = mask.to(device) + else: + cast_mask = None + return NestedTensor(cast_tensor, cast_mask) + + def decompose(self): + return self.tensors, self.mask + + def __repr__(self): + return str(self.tensors) + + +def nested_tensor_from_tensor_list(tensor_list: List[Tensor]): + # TODO make this more general + if tensor_list[0].ndim == 3: + if torchvision._is_tracing(): + # nested_tensor_from_tensor_list() does not export well to ONNX + # call _onnx_nested_tensor_from_tensor_list() instead + return _onnx_nested_tensor_from_tensor_list(tensor_list) + + # TODO make it support different-sized images + max_size = _max_by_axis([list(img.shape) for img in tensor_list]) # [[3,h1,w1], [3,h2,w2], [3,h3,w3], ...] + # min_size = tuple(min(s) for s in zip(*[img.shape for img in tensor_list])) + batch_shape = [len(tensor_list)] + max_size # () + b, c, h, w = batch_shape + dtype = tensor_list[0].dtype + device = tensor_list[0].device + tensor = torch.zeros(batch_shape, dtype=dtype, device=device) + mask = torch.ones((b, h, w), dtype=torch.bool, device=device) + for img, pad_img, m in zip(tensor_list, tensor, mask): + pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img) # copy valid regions of the images to the largest padded base. + m[: img.shape[1], :img.shape[2]] = False + else: + raise ValueError('not supported') + return NestedTensor(tensor, mask) + + +# _onnx_nested_tensor_from_tensor_list() is an implementation of +# nested_tensor_from_tensor_list() that is supported by ONNX tracing. +@torch.jit.unused +def _onnx_nested_tensor_from_tensor_list(tensor_list: List[Tensor]) -> NestedTensor: + max_size = [] + for i in range(tensor_list[0].dim()): + max_size_i = torch.max(torch.stack([img.shape[i] for img in tensor_list]).to(torch.float32)).to(torch.int64) + max_size.append(max_size_i) + max_size = tuple(max_size) + + # work around for + # pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img) + # m[: img.shape[1], :img.shape[2]] = False + # which is not yet supported in onnx + padded_imgs = [] + padded_masks = [] + for img in tensor_list: + padding = [(s1 - s2) for s1, s2 in zip(max_size, tuple(img.shape))] + padded_img = torch.nn.functional.pad(img, (0, padding[2], 0, padding[1], 0, padding[0])) + padded_imgs.append(padded_img) + + m = torch.zeros_like(img[0], dtype=torch.int, device=img.device) + padded_mask = torch.nn.functional.pad(m, (0, padding[2], 0, padding[1]), "constant", 1) + padded_masks.append(padded_mask.to(torch.bool)) + + tensor = torch.stack(padded_imgs) + mask = torch.stack(padded_masks) + + return NestedTensor(tensor, mask=mask) + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + if is_main_process(): + torch.save(*args, **kwargs) + + +def init_distributed_mode(args): + if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: + args.rank = int(os.environ["RANK"]) + args.world_size = int(os.environ['WORLD_SIZE']) + args.gpu = int(os.environ['LOCAL_RANK']) + elif 'SLURM_PROCID' in os.environ: + args.rank = int(os.environ['SLURM_PROCID']) + args.gpu = args.rank % torch.cuda.device_count() + else: + print('Not using distributed mode') + args.distributed = False + return + + args.distributed = True + + torch.cuda.set_device(args.gpu) + args.dist_backend = 'nccl' + print('| distributed init (rank {}): {}'.format( + args.rank, args.dist_url), flush=True) + torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + torch.distributed.barrier() + setup_for_distributed(args.rank == 0) + + +@torch.no_grad() +def accuracy(output, target, topk=(1,)): + """Computes the precision@k for the specified values of k""" + if target.numel() == 0: + return [torch.zeros([], device=output.device)] + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +def interpolate(input, size=None, scale_factor=None, mode="nearest", align_corners=None): + # type: (Tensor, Optional[List[int]], Optional[float], str, Optional[bool]) -> Tensor + """ + Equivalent to nn.functional.interpolate, but with support for empty batch sizes. + This will eventually be supported natively by PyTorch, and this + class can go away. + """ + if float(torchvision.__version__[:3]) < 0.7: + if input.numel() > 0: + return torch.nn.functional.interpolate( + input, size, scale_factor, mode, align_corners + ) + + output_shape = _output_size(2, input, size, scale_factor) + output_shape = list(input.shape[:-2]) + list(output_shape) + return _new_empty_tensor(input, output_shape) + else: + return torchvision.ops.misc.interpolate(input, size, scale_factor, mode, align_corners) diff --git a/Stark/lib/utils/tensor.py b/Stark/lib/utils/tensor.py new file mode 100755 index 0000000..c9468c4 --- /dev/null +++ b/Stark/lib/utils/tensor.py @@ -0,0 +1,244 @@ +import functools +import torch +import copy +from collections import OrderedDict + + +class TensorDict(OrderedDict): + """Container mainly used for dicts of torch tensors. Extends OrderedDict with pytorch functionality.""" + + def concat(self, other): + """Concatenates two dicts without copying internal data.""" + return TensorDict(self, **other) + + def copy(self): + return TensorDict(super(TensorDict, self).copy()) + + def __deepcopy__(self, memodict={}): + return TensorDict(copy.deepcopy(list(self), memodict)) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorDict\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorDict({n: getattr(e, name)(*args, **kwargs) if hasattr(e, name) else e for n, e in self.items()}) + return apply_attr + + def attribute(self, attr: str, *args): + return TensorDict({n: getattr(e, attr, *args) for n, e in self.items()}) + + def apply(self, fn, *args, **kwargs): + return TensorDict({n: fn(e, *args, **kwargs) for n, e in self.items()}) + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorDict, list)) + + +class TensorList(list): + """Container mainly used for lists of torch tensors. Extends lists with pytorch functionality.""" + + def __init__(self, list_of_tensors = None): + if list_of_tensors is None: + list_of_tensors = list() + super(TensorList, self).__init__(list_of_tensors) + + def __deepcopy__(self, memodict={}): + return TensorList(copy.deepcopy(list(self), memodict)) + + def __getitem__(self, item): + if isinstance(item, int): + return super(TensorList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return TensorList([super(TensorList, self).__getitem__(i) for i in item]) + else: + return TensorList(super(TensorList, self).__getitem__(item)) + + def __add__(self, other): + if TensorList._iterable(other): + return TensorList([e1 + e2 for e1, e2 in zip(self, other)]) + return TensorList([e + other for e in self]) + + def __radd__(self, other): + if TensorList._iterable(other): + return TensorList([e2 + e1 for e1, e2 in zip(self, other)]) + return TensorList([other + e for e in self]) + + def __iadd__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] += e2 + else: + for i in range(len(self)): + self[i] += other + return self + + def __sub__(self, other): + if TensorList._iterable(other): + return TensorList([e1 - e2 for e1, e2 in zip(self, other)]) + return TensorList([e - other for e in self]) + + def __rsub__(self, other): + if TensorList._iterable(other): + return TensorList([e2 - e1 for e1, e2 in zip(self, other)]) + return TensorList([other - e for e in self]) + + def __isub__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] -= e2 + else: + for i in range(len(self)): + self[i] -= other + return self + + def __mul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 * e2 for e1, e2 in zip(self, other)]) + return TensorList([e * other for e in self]) + + def __rmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 * e1 for e1, e2 in zip(self, other)]) + return TensorList([other * e for e in self]) + + def __imul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] *= e2 + else: + for i in range(len(self)): + self[i] *= other + return self + + def __truediv__(self, other): + if TensorList._iterable(other): + return TensorList([e1 / e2 for e1, e2 in zip(self, other)]) + return TensorList([e / other for e in self]) + + def __rtruediv__(self, other): + if TensorList._iterable(other): + return TensorList([e2 / e1 for e1, e2 in zip(self, other)]) + return TensorList([other / e for e in self]) + + def __itruediv__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] /= e2 + else: + for i in range(len(self)): + self[i] /= other + return self + + def __matmul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 @ e2 for e1, e2 in zip(self, other)]) + return TensorList([e @ other for e in self]) + + def __rmatmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 @ e1 for e1, e2 in zip(self, other)]) + return TensorList([other @ e for e in self]) + + def __imatmul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] @= e2 + else: + for i in range(len(self)): + self[i] @= other + return self + + def __mod__(self, other): + if TensorList._iterable(other): + return TensorList([e1 % e2 for e1, e2 in zip(self, other)]) + return TensorList([e % other for e in self]) + + def __rmod__(self, other): + if TensorList._iterable(other): + return TensorList([e2 % e1 for e1, e2 in zip(self, other)]) + return TensorList([other % e for e in self]) + + def __pos__(self): + return TensorList([+e for e in self]) + + def __neg__(self): + return TensorList([-e for e in self]) + + def __le__(self, other): + if TensorList._iterable(other): + return TensorList([e1 <= e2 for e1, e2 in zip(self, other)]) + return TensorList([e <= other for e in self]) + + def __ge__(self, other): + if TensorList._iterable(other): + return TensorList([e1 >= e2 for e1, e2 in zip(self, other)]) + return TensorList([e >= other for e in self]) + + def concat(self, other): + return TensorList(super(TensorList, self).__add__(other)) + + def copy(self): + return TensorList(super(TensorList, self).copy()) + + def unroll(self): + if not any(isinstance(t, TensorList) for t in self): + return self + + new_list = TensorList() + for t in self: + if isinstance(t, TensorList): + new_list.extend(t.unroll()) + else: + new_list.append(t) + return new_list + + def list(self): + return list(self) + + def attribute(self, attr: str, *args): + return TensorList([getattr(e, attr, *args) for e in self]) + + def apply(self, fn): + return TensorList([fn(e) for e in self]) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorList\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorList([getattr(e, name)(*args, **kwargs) for e in self]) + + return apply_attr + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorList, list)) + + +def tensor_operation(op): + def islist(a): + return isinstance(a, TensorList) + + @functools.wraps(op) + def oplist(*args, **kwargs): + if len(args) == 0: + raise ValueError('Must be at least one argument without keyword (i.e. operand).') + + if len(args) == 1: + if islist(args[0]): + return TensorList([op(a, **kwargs) for a in args[0]]) + else: + # Multiple operands, assume max two + if islist(args[0]) and islist(args[1]): + return TensorList([op(a, b, *args[2:], **kwargs) for a, b in zip(*args[:2])]) + if islist(args[0]): + return TensorList([op(a, *args[1:], **kwargs) for a in args[0]]) + if islist(args[1]): + return TensorList([op(args[0], b, *args[2:], **kwargs) for b in args[1]]) + + # None of the operands are lists + return op(*args, **kwargs) + + return oplist diff --git a/Stark/tracking/Framework.png b/Stark/tracking/Framework.png new file mode 100755 index 0000000..361f0ba Binary files /dev/null and b/Stark/tracking/Framework.png differ diff --git a/Stark/tracking/__pycache__/_init_paths.cpython-37.pyc b/Stark/tracking/__pycache__/_init_paths.cpython-37.pyc new file mode 100755 index 0000000..6ba8d84 Binary files /dev/null and b/Stark/tracking/__pycache__/_init_paths.cpython-37.pyc differ diff --git a/Stark/tracking/_init_paths.py b/Stark/tracking/_init_paths.py new file mode 100755 index 0000000..c48f674 --- /dev/null +++ b/Stark/tracking/_init_paths.py @@ -0,0 +1,17 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os.path as osp +import sys + + +def add_path(path): + if path not in sys.path: + sys.path.insert(0, path) + + +this_dir = osp.dirname(__file__) + +prj_path = osp.join(this_dir, '..') +add_path(prj_path) diff --git a/Stark/tracking/analysis_results.py b/Stark/tracking/analysis_results.py new file mode 100755 index 0000000..828cb0f --- /dev/null +++ b/Stark/tracking/analysis_results.py @@ -0,0 +1,18 @@ +import _init_paths +import matplotlib.pyplot as plt +plt.rcParams['figure.figsize'] = [8, 8] + +from lib.test.analysis.plot_results import plot_results, print_results, print_per_sequence_results +from lib.test.evaluation import get_dataset, trackerlist + +trackers = [] + + +trackers.extend(trackerlist(name='stark_st', parameter_name='baseline_R101', dataset_name='lasot', + run_ids=None, display_name='STARK-ST101')) + +dataset = get_dataset('lasot') +plot_results(trackers, dataset, 'LaSOT', merge_results=True, plot_types=('success', 'norm_prec'), + skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05) +print_results(trackers, dataset, 'LaSOT', merge_results=True, plot_types=('success', 'prec', 'norm_prec')) +# print_per_sequence_results(trackers, dataset, report_name="debug") diff --git a/Stark/tracking/create_default_local_file.py b/Stark/tracking/create_default_local_file.py new file mode 100755 index 0000000..b02ebb7 --- /dev/null +++ b/Stark/tracking/create_default_local_file.py @@ -0,0 +1,23 @@ +import argparse +import os +import _init_paths +from lib.train.admin import create_default_local_file_ITP_train +from lib.test.evaluation import create_default_local_file_ITP_test + + +def parse_args(): + parser = argparse.ArgumentParser(description='Create default local file on ITP or PAI') + parser.add_argument("--workspace_dir", type=str, required=True) # workspace dir + parser.add_argument("--data_dir", type=str, required=True) + parser.add_argument("--save_dir", type=str, required=True) + args = parser.parse_args() + return args + + +if __name__ == "__main__": + args = parse_args() + workspace_dir = os.path.realpath(args.workspace_dir) + data_dir = os.path.realpath(args.data_dir) + save_dir = os.path.realpath(args.save_dir) + create_default_local_file_ITP_train(workspace_dir, data_dir) + create_default_local_file_ITP_test(workspace_dir, data_dir, save_dir) diff --git a/Stark/tracking/profile_model.py b/Stark/tracking/profile_model.py new file mode 100755 index 0000000..6368445 --- /dev/null +++ b/Stark/tracking/profile_model.py @@ -0,0 +1,131 @@ +import argparse +import torch +import _init_paths +from lib.utils.merge import merge_template_search +# from lib.config.stark_s.config import cfg, update_config_from_file +# from lib.models.stark.stark_s import build_starks +from lib.utils.misc import NestedTensor +from thop import profile +from thop.utils import clever_format +import time +import importlib + +def parse_args(): + """ + args for training. + """ + parser = argparse.ArgumentParser(description='Parse args for training') + # for train + parser.add_argument('--script', type=str, default='stark_s', choices=['stark_s', 'stark_st2'], + help='training script name') + parser.add_argument('--config', type=str, default='baseline', help='yaml configure file name') + args = parser.parse_args() + + return args + + +def evaluate(model, search, seq_dict, run_box_head, run_cls_head): + '''Compute FLOPs, Params, and Speed''' + # # backbone + macs1, params1 = profile(model, inputs=(search, None, "backbone", False, False), + custom_ops=None, verbose=False) + macs, params = clever_format([macs1, params1], "%.3f") + print('backbone (search) macs is ', macs) + print('backbone params is ', params) + # transformer and head + macs2, params2 = profile(model, inputs=(None, seq_dict, "transformer", True, True), + custom_ops=None, verbose=False) + macs, params = clever_format([macs2, params2], "%.3f") + print('transformer and head macs is ', macs) + print('transformer and head params is ', params) + # the whole model + macs, params = clever_format([macs1 + macs2, params1 + params2], "%.3f") + print('overall macs is ', macs) + print('overall params is ', params) + + '''Speed Test''' + T_w = 10 + T_t = 100 + print("testing speed ...") + with torch.no_grad(): + # overall + for i in range(T_w): + _ = model(search, None, "backbone", run_box_head, run_cls_head) + _ = model(None, seq_dict, "transformer", run_box_head, run_cls_head) + start = time.time() + for i in range(T_t): + _ = model(search, None, "backbone", run_box_head, run_cls_head) + _ = model(None, seq_dict, "transformer", run_box_head, run_cls_head) + end = time.time() + avg_lat = (end - start) / T_t + print("The average overall latency is %.2f ms" % (avg_lat * 1000)) + # backbone + for i in range(T_w): + _ = model(search, None, "backbone", run_box_head, run_cls_head) + start = time.time() + for i in range(T_t): + _ = model(search, None, "backbone", run_box_head, run_cls_head) + end = time.time() + avg_lat = (end - start) / T_t + print("The average backbone latency is %.2f ms" % (avg_lat * 1000)) + + +def get_data(bs, sz): + img_patch = torch.randn(bs, 3, sz, sz) + att_mask = torch.rand(bs, sz, sz) > 0.5 + return NestedTensor(img_patch, att_mask) + + +if __name__ == "__main__": + device = "cuda:0" + torch.cuda.set_device(device) + # Compute the Flops and Params of our STARK-S model + args = parse_args() + '''update cfg''' + yaml_fname = 'experiments/%s/%s.yaml' % (args.script, args.config) + config_module = importlib.import_module('lib.config.%s.config' % args.script) + cfg = config_module.cfg + config_module.update_config_from_file(yaml_fname) + '''set some values''' + bs = 1 + z_sz = cfg.TEST.TEMPLATE_SIZE + x_sz = cfg.TEST.SEARCH_SIZE + h_dim = cfg.MODEL.HIDDEN_DIM + '''import stark network module''' + model_module = importlib.import_module('lib.models.stark') + if args.script == "stark_s": + model_constructor = model_module.build_starks + model = model_constructor(cfg) + # get the template and search + template = get_data(bs, z_sz) + search = get_data(bs, x_sz) + # transfer to device + model = model.to(device) + template = template.to(device) + search = search.to(device) + # forward template and search + oup_t = model.forward_backbone(template) + oup_s = model.forward_backbone(search) + seq_dict = merge_template_search([oup_t, oup_s]) + # evaluate the model properties + evaluate(model, search, seq_dict, run_box_head=True, run_cls_head=False) + elif args.script == "stark_st2": + model_constructor = model_module.build_starkst + model = model_constructor(cfg) + # get the template and search + template1 = get_data(bs, z_sz) + template2 = get_data(bs, z_sz) + search = get_data(bs, x_sz) + # transfer to device + model = model.to(device) + template1 = template1.to(device) + template2 = template2.to(device) + search = search.to(device) + # forward template and search + oup_t1 = model.forward_backbone(template1) + oup_t2 = model.forward_backbone(template2) + oup_s = model.forward_backbone(search) + seq_dict = merge_template_search([oup_t1, oup_t2, oup_s]) + # evaluate the model properties + evaluate(model, search, seq_dict, run_box_head=True, run_cls_head=True) + diff --git a/Stark/tracking/test.py b/Stark/tracking/test.py new file mode 100755 index 0000000..4787a29 --- /dev/null +++ b/Stark/tracking/test.py @@ -0,0 +1,60 @@ +import os +import sys +import argparse + +prj_path = os.path.join(os.path.dirname(__file__), '..') +if prj_path not in sys.path: + sys.path.append(prj_path) + +from lib.test.evaluation import get_dataset +from lib.test.evaluation.running import run_dataset +from lib.test.evaluation.tracker import Tracker + + +def run_tracker(tracker_name, tracker_param, run_id=None, dataset_name='otb', sequence=None, debug=0, threads=0, + num_gpus=8): + """Run tracker on sequence or dataset. + args: + tracker_name: Name of tracking method. + tracker_param: Name of parameter file. + run_id: The run id. + dataset_name: Name of dataset (otb, nfs, uav, tpl, vot, tn, gott, gotv, lasot). + sequence: Sequence number or name. + debug: Debug level. + threads: Number of threads. + """ + + dataset = get_dataset(dataset_name) + + if sequence is not None: + dataset = [dataset[sequence]] + + trackers = [Tracker(tracker_name, tracker_param, dataset_name, run_id)] + + run_dataset(dataset, trackers, debug, threads, num_gpus=num_gpus) + + +def main(): + parser = argparse.ArgumentParser(description='Run tracker on sequence or dataset.') + parser.add_argument('tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('tracker_param', type=str, help='Name of config file.') + parser.add_argument('--runid', type=int, default=None, help='The run id.') + parser.add_argument('--dataset_name', type=str, default='otb', help='Name of dataset (otb, nfs, uav, tpl, vot, tn, gott, gotv, lasot).') + parser.add_argument('--sequence', type=str, default=None, help='Sequence number or name.') + parser.add_argument('--debug', type=int, default=0, help='Debug level.') + parser.add_argument('--threads', type=int, default=0, help='Number of threads.') + parser.add_argument('--num_gpus', type=int, default=8) + + args = parser.parse_args() + + try: + seq_name = int(args.sequence) + except: + seq_name = args.sequence + + run_tracker(args.tracker_name, args.tracker_param, args.runid, args.dataset_name, seq_name, args.debug, + args.threads, num_gpus=args.num_gpus) + + +if __name__ == '__main__': + main() diff --git a/Stark/tracking/train.py b/Stark/tracking/train.py new file mode 100755 index 0000000..3e9624f --- /dev/null +++ b/Stark/tracking/train.py @@ -0,0 +1,42 @@ +import os +import argparse + + +def parse_args(): + """ + args for training. + """ + parser = argparse.ArgumentParser(description='Parse args for training') + # for train + parser.add_argument('--script', type=str, help='training script name') + parser.add_argument('--config', type=str, default='baseline', help='yaml configure file name') + parser.add_argument('--save_dir', type=str, help='root directory to save checkpoints, logs, and tensorboard') + parser.add_argument('--mode', type=str, choices=["single", "multiple"], default="multiple", + help="train on single gpu or multiple gpus") + parser.add_argument('--nproc_per_node', type=int, help="number of GPUs per node") # specify when mode is multiple + parser.add_argument('--use_lmdb', type=int, choices=[0, 1], default=0) # whether datasets are in lmdb format + parser.add_argument('--script_prv', type=str, help='training script name') + parser.add_argument('--config_prv', type=str, default='baseline', help='yaml configure file name') + + args = parser.parse_args() + + return args + + +def main(): + args = parse_args() + if args.mode == "single": + train_cmd = "python lib/train/run_training.py --script %s --config %s --save_dir %s --use_lmdb %d " \ + "--script_prv %s --config_prv %s" \ + % (args.script, args.config, args.save_dir, args.use_lmdb, args.script_prv, args.config_prv) + elif args.mode == "multiple": + train_cmd = "python -m torch.distributed.launch --nproc_per_node %d lib/train/run_training.py " \ + "--script %s --config %s --save_dir %s --use_lmdb %d --script_prv %s --config_prv %s" \ + % (args.nproc_per_node, args.script, args.config, args.save_dir, args.use_lmdb, args.script_prv, args.config_prv) + else: + raise ValueError("mode should be 'single' or 'multiple'.") + os.system(train_cmd) + + +if __name__ == "__main__": + main() diff --git a/compile_pytracking.py b/compile_pytracking.py new file mode 100755 index 0000000..c2a3db9 --- /dev/null +++ b/compile_pytracking.py @@ -0,0 +1,19 @@ +""" +Written by Matteo Dunnhofer - 2021 + +Initialize CoCoLoT to compile PreciseRoiPooling modules +""" +from PIL import Image +import numpy as np +import vot +import vot_path +import sys +sys.path.append(vot_path.base_path) +from CoCoLoT_Tracker import CoCoLoT_Tracker, p_config + +image = np.array(Image.open(vot_path.base_path + 'CoCoLoT/data/00000001.jpg')) + +tracker = CoCoLoT_Tracker(image, vot.Rectangle(0, 0, 100, 100), p=p_config()) +_ = tracker.tracking(image) + +print('Done!') diff --git a/config.yaml b/config.yaml new file mode 100755 index 0000000..2035b9d --- /dev/null +++ b/config.yaml @@ -0,0 +1,3 @@ +registry: +- ./trackers.ini +stack: vot2022/lt diff --git a/data/00000001.jpg b/data/00000001.jpg new file mode 100755 index 0000000..1a94b24 Binary files /dev/null and b/data/00000001.jpg differ diff --git a/environment.yml b/environment.yml new file mode 100755 index 0000000..07fb384 --- /dev/null +++ b/environment.yml @@ -0,0 +1,127 @@ +name: CoCoLoT +channels: + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - ca-certificates=2021.1.19=h06a4308_1 + - cudatoolkit=10.0.130=0 + - ld_impl_linux-64=2.33.1=h53a641e_7 + - libedit=3.1.20191231=h14c3975_1 + - libffi=3.3=he6710b0_2 + - libgcc-ng=9.1.0=hdf63c60_0 + - libstdcxx-ng=9.1.0=hdf63c60_0 + - ncurses=6.2=he6710b0_1 + - openssl=1.1.1j=h27cfd23_0 + - pip=20.3.1=py37h06a4308_0 + - python=3.7.9=h7579374_0 + - readline=8.0=h7b6447c_0 + - setuptools=51.0.0=py37h06a4308_2 + - sqlite=3.33.0=h62c20be_0 + - tk=8.6.10=hbc83047_0 + - wheel=0.36.1=pyhd3eb1b0_0 + - xz=5.2.5=h7b6447c_0 + - zlib=1.2.11=h7b6447c_3 + - pip: + - absl-py==0.8.1 + - addict==2.2.1 + - albumentations==0.4.5 + - astor==0.8.0 + - attributee==0.1.7 + - attrs==19.3.0 + - bidict==0.21.2 + - cachetools==4.2.2 + - certifi==2019.11.28 + - cffi==1.13.2 + - chardet==3.0.4 + - colorama==0.4.3 + - cycler==0.10.0 + - cython==0.29.14 + - decorator==4.4.2 + - dominate==2.6.0 + - easydict==1.9 + - ffmpeg-python==0.2.0 + - future==0.18.2 + - gast==0.2.2 + - google-auth==1.11.0 + - google-auth-oauthlib==0.4.1 + - google-pasta==0.1.8 + - grpcio==1.28.1 + - h5py==2.10.0 + - idna==2.8 + - imagecorruptions==1.0.0 + - imageio==2.8.0 + - imgaug==0.2.6 + - importlib-metadata==1.6.0 + - intel-openmp==2021.1.1 + - joblib==0.14.1 + - jpeg4py==0.1.4 + - jsonpatch==1.25 + - jsonpointer==2.0 + - jsonschema==3.2.0 + - keras-applications==1.0.8 + - keras-preprocessing==1.1.0 + - kiwisolver==1.1.0 + - llvmlite==0.32.0 + - lmdb==1.1.1 + - markdown==3.1.1 + - matplotlib==3.1.3 + - mkl==2021.1.1 + - mmcv==0.2.14 + - networkx==2.4 + - ninja==1.10.0.post2 + - numba==0.49.0 + - numpy==1.18.1 + - oauthlib==3.1.0 + - olefile==0.46 + - opencv-python==4.2.0.32 + - opt-einsum==3.1.0 + - ordered-set==4.0.1 + - packaging==20.7 + - pandas==1.0.0 + - phx-class-registry==3.0.5 + - pillow==7.0.0 + - protobuf==3.11.2 + - pyasn1==0.4.8 + - pyasn1-modules==0.2.8 + - pycocotools==2.0.2 + - pycparser==2.19 + - pylatex==1.3.1 + - pyparsing==2.4.6 + - pyrsistent==0.16.0 + - python-dateutil==2.8.1 + - pytz==2019.3 + - pywavelets==1.1.1 + - pyyaml==5.3.1 + - pyzmq==18.1.1 + - requests==2.22.0 + - requests-oauthlib==1.3.0 + - rsa==4.0 + - scikit-image==0.16.2 + - scikit-learn==0.22.2.post1 + - scipy==1.2.1 + - shapely==1.7.0 + - six==1.14.0 + - sklearn==0.0 + - tb-nightly==2.2.0a20200205 + - tbb==2021.1.1 + - tensorboard==1.15.0 + - tensorflow-gpu==1.15.0 + - tensorflow-estimator==1.15.1 + - termcolor==1.1.0 + - terminaltables==3.1.0 + - tikzplotlib==0.9.6 + - torch==1.4.0 + - torchfile==0.1.0 + - torchvision==0.5.0 + - tornado==6.0.3 + - tqdm==4.60.0 + - urllib3==1.25.9 + - visdom==0.1.8.9 + - vot-toolkit + - vot-trax + - webencodings==0.5.1 + - websocket-client==0.57.0 + - werkzeug==0.16.1 + - wrapt==1.11.2 + - zipp==3.1.0 +prefix: mlpLT diff --git a/ltr/README.md b/ltr/README.md new file mode 100755 index 0000000..23b5d94 --- /dev/null +++ b/ltr/README.md @@ -0,0 +1,75 @@ +# LTR + +A general PyTorch based framework for learning tracking representations. +## Table of Contents + +* [Quick Start](#quick-start) +* [Overview](#overview) +* [Trackers](#trackers) + * [PrDiMP](#PrDiMP) + * [DiMP](#DiMP) + * [ATOM](#ATOM) +* [Training your own networks](#training-your-own-networks) + +## Quick Start +The installation script will automatically generate a local configuration file "admin/local.py". In case the file was not generated, run ```admin.environment.create_default_local_file()``` to generate it. Next, set the paths to the training workspace, +i.e. the directory where the checkpoints will be saved. Also set the paths to the datasets you want to use. If all the dependencies have been correctly installed, you can train a network using the run_training.py script in the correct conda environment. +```bash +conda activate pytracking +python run_training.py train_module train_name +``` +Here, ```train_module``` is the sub-module inside ```train_settings``` and ```train_name``` is the name of the train setting file to be used. + +For example, you can train using the included default ATOM settings by running: +```bash +python run_training bbreg atom_default +``` + + +## Overview +The framework consists of the following sub-modules. + - [actors](actors): Contains the actor classes for different trainings. The actor class is responsible for passing the input data through the network can calculating losses. + - [admin](admin): Includes functions for loading networks, tensorboard etc. and also contains environment settings. + - [dataset](dataset): Contains integration of a number of training datasets, namely [TrackingNet](https://tracking-net.org/), [GOT-10k](http://got-10k.aitestunion.com/), [LaSOT](https://cis.temple.edu/lasot/), + [ImageNet-VID](http://image-net.org/), [DAVIS](https://davischallenge.org), [YouTube-VOS](https://youtube-vos.org), [MS-COCO](http://cocodataset.org/#home), [SBD](http://home.bharathh.info/pubs/codes/SBD), [LVIS](https://www.lvisdataset.org), [ECSSD](http://www.cse.cuhk.edu.hk/leojia/projects/hsaliency/dataset.html), [MSRA10k](https://mmcheng.net/msra10k), and [HKU-IS](https://sites.google.com/site/ligb86/hkuis). Additionally, it includes modules to generate synthetic videos from image datasets. + - [data_specs](data_specs): Information about train/val splits of different datasets. + - [data](data): Contains functions for processing data, e.g. loading images, data augmentations, sampling frames from videos. + - [external](external): External libraries needed for training. Added as submodules. + - [models](models): Contains different layers and network definitions. + - [trainers](trainers): The main class which runs the training. + - [train_settings](train_settings): Contains settings files, specifying the training of a network. + +## Trackers + The framework currently contains the training code for the following trackers. + +### PrDiMP + The following setting files can be used train the DiMP networks, or to know the exact training details. + - [dimp.prdimp18](train_settings/dimp/prdimp18.py): The default settings used for training the PrDiMP model with ResNet-18 backbone. + - [dimp.prdimp50](train_settings/dimp/prdimp50.py): The default settings used for training the PrDiMP model with ResNet-50 backbone. + - [dimp.super_dimp](train_settings/dimp/super_dimp.py): Combines the bounding-box regressor of PrDiMP with the standard DiMP classifier and better training and inference settings. + +### DiMP + The following setting files can be used train the DiMP networks, or to know the exact training details. + - [dimp.dimp18](train_settings/dimp/dimp18.py): The default settings used for training the DiMP model with ResNet-18 backbone. + - [dimp.dimp50](train_settings/dimp/dimp50.py): The default settings used for training the DiMP model with ResNet-50 backbone. + +### ATOM + The following setting file can be used train the ATOM network, or to know the exact training details. + - [bbreg.atom](train_settings/bbreg/atom_paper.py): The settings used in the paper for training the network in ATOM. + - [bbreg.atom](train_settings/bbreg/atom.py): Newer settings used for training the network in ATOM, also utilizing the GOT10k dataset. + - [bbreg.atom](train_settings/bbreg/atom_prob_ml.py): Settings for ATOM with the probabilistic bounding box regression proposed in [this paper](https://arxiv.org/abs/1909.12297). + - [bbreg.atom](train_settings/bbreg/atom_paper.py): The baseline ATOM* setting evaluated in [this paper](https://arxiv.org/abs/1909.12297). + +## Training your own networks +To train a custom network using the toolkit, the following components need to be specified in the train settings. For reference, see [atom.py](train_settings/bbreg/atom.py). +- Datasets: The datasets to be used for training. A number of standard tracking datasets are already available in ```dataset``` module. +- Processing: This function should perform the necessary post-processing of the data, e.g. cropping of target region, data augmentations etc. +- Sampler: Determines how the frames are sampled from a video sequence to form the batches. +- Network: The network module to be trained. +- Objective: The training objective. +- Actor: The trainer passes the training batch to the actor who is responsible for passing the data through the network correctly, and calculating the training loss. +- Optimizer: Optimizer to be used, e.g. Adam. +- Trainer: The main class which runs the epochs and saves checkpoints. + + + \ No newline at end of file diff --git a/ltr/__init__.py b/ltr/__init__.py new file mode 100755 index 0000000..a7b6f67 --- /dev/null +++ b/ltr/__init__.py @@ -0,0 +1,3 @@ +from .admin.loading import load_network +from .admin.model_constructor import model_constructor +from .admin.multigpu import MultiGPU \ No newline at end of file diff --git a/ltr/__pycache__/__init__.cpython-37.pyc b/ltr/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..36d3015 Binary files /dev/null and b/ltr/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/actors/__init__.py b/ltr/actors/__init__.py new file mode 100755 index 0000000..c269c6e --- /dev/null +++ b/ltr/actors/__init__.py @@ -0,0 +1,3 @@ +from .base_actor import BaseActor +from .bbreg import AtomActor +from .tracking import DiMPActor \ No newline at end of file diff --git a/ltr/actors/base_actor.py b/ltr/actors/base_actor.py new file mode 100755 index 0000000..6424272 --- /dev/null +++ b/ltr/actors/base_actor.py @@ -0,0 +1,44 @@ +from pytracking import TensorDict + + +class BaseActor: + """ Base class for actor. The actor class handles the passing of the data through the network + and calculation the loss""" + def __init__(self, net, objective): + """ + args: + net - The network to train + objective - The loss function + """ + self.net = net + self.objective = objective + + def __call__(self, data: TensorDict): + """ Called in each training iteration. Should pass in input data through the network, calculate the loss, and + return the training stats for the input data + args: + data - A TensorDict containing all the necessary data blocks. + + returns: + loss - loss for the input data + stats - a dict containing detailed losses + """ + raise NotImplementedError + + def to(self, device): + """ Move the network to device + args: + device - device to use. 'cpu' or 'cuda' + """ + self.net.to(device) + + def train(self, mode=True): + """ Set whether the network is in train mode. + args: + mode (True) - Bool specifying whether in training mode. + """ + self.net.train(mode) + + def eval(self): + """ Set network to eval mode""" + self.train(False) \ No newline at end of file diff --git a/ltr/actors/bbreg.py b/ltr/actors/bbreg.py new file mode 100755 index 0000000..f07f49e --- /dev/null +++ b/ltr/actors/bbreg.py @@ -0,0 +1,58 @@ +from . import BaseActor + + +class AtomActor(BaseActor): + """ Actor for training the IoU-Net in ATOM""" + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals' and 'proposal_iou'. + + returns: + loss - the training loss + states - dict containing detailed losses + """ + # Run network to obtain IoU prediction for each proposal in 'test_proposals' + iou_pred = self.net(data['train_images'], data['test_images'], data['train_anno'], data['test_proposals']) + + iou_pred = iou_pred.view(-1, iou_pred.shape[2]) + iou_gt = data['proposal_iou'].view(-1, data['proposal_iou'].shape[2]) + + # Compute loss + loss = self.objective(iou_pred, iou_gt) + + # Return training stats + stats = {'Loss/total': loss.item(), + 'Loss/iou': loss.item()} + + return loss, stats + + +class AtomBBKLActor(BaseActor): + """ Actor for training the IoU-Net in ATOM with BBKL""" + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_density', and 'gt_density'. + + returns: + loss - the training loss + states - dict containing detailed losses + """ + # Run network to obtain IoU prediction for each proposal in 'test_proposals' + bb_scores = self.net(data['train_images'], data['test_images'], data['train_anno'], data['test_proposals']) + + bb_scores = bb_scores.view(-1, bb_scores.shape[2]) + proposal_density = data['proposal_density'].view(-1, data['proposal_density'].shape[2]) + gt_density = data['gt_density'].view(-1, data['gt_density'].shape[2]) + + # Compute loss + loss = self.objective(bb_scores, sample_density=proposal_density, gt_density=gt_density, mc_dim=1) + + # Return training stats + stats = {'Loss/total': loss.item(), + 'Loss/bb_ce': loss.item()} + + return loss, stats diff --git a/ltr/actors/tracking.py b/ltr/actors/tracking.py new file mode 100755 index 0000000..9562477 --- /dev/null +++ b/ltr/actors/tracking.py @@ -0,0 +1,193 @@ +from . import BaseActor +import torch + + +class DiMPActor(BaseActor): + """Actor for training the DiMP network.""" + def __init__(self, net, objective, loss_weight=None): + super().__init__(net, objective) + if loss_weight is None: + loss_weight = {'iou': 1.0, 'test_clf': 1.0} + self.loss_weight = loss_weight + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_iou' and 'test_label'. + + returns: + loss - the training loss + stats - dict containing detailed losses + """ + # Run network + target_scores, iou_pred = self.net(train_imgs=data['train_images'], + test_imgs=data['test_images'], + train_bb=data['train_anno'], + test_proposals=data['test_proposals']) + + # Classification losses for the different optimization iterations + clf_losses_test = [self.objective['test_clf'](s, data['test_label'], data['test_anno']) for s in target_scores] + + # Loss of the final filter + clf_loss_test = clf_losses_test[-1] + loss_target_classifier = self.loss_weight['test_clf'] * clf_loss_test + + # Compute loss for ATOM IoUNet + loss_iou = self.loss_weight['iou'] * self.objective['iou'](iou_pred, data['proposal_iou']) + + # Loss for the initial filter iteration + loss_test_init_clf = 0 + if 'test_init_clf' in self.loss_weight.keys(): + loss_test_init_clf = self.loss_weight['test_init_clf'] * clf_losses_test[0] + + # Loss for the intermediate filter iterations + loss_test_iter_clf = 0 + if 'test_iter_clf' in self.loss_weight.keys(): + test_iter_weights = self.loss_weight['test_iter_clf'] + if isinstance(test_iter_weights, list): + loss_test_iter_clf = sum([a*b for a, b in zip(test_iter_weights, clf_losses_test[1:-1])]) + else: + loss_test_iter_clf = (test_iter_weights / (len(clf_losses_test) - 2)) * sum(clf_losses_test[1:-1]) + + # Total loss + loss = loss_iou + loss_target_classifier + loss_test_init_clf + loss_test_iter_clf + + # Log stats + stats = {'Loss/total': loss.item(), + 'Loss/iou': loss_iou.item(), + 'Loss/target_clf': loss_target_classifier.item()} + if 'test_init_clf' in self.loss_weight.keys(): + stats['Loss/test_init_clf'] = loss_test_init_clf.item() + if 'test_iter_clf' in self.loss_weight.keys(): + stats['Loss/test_iter_clf'] = loss_test_iter_clf.item() + stats['ClfTrain/test_loss'] = clf_loss_test.item() + if len(clf_losses_test) > 0: + stats['ClfTrain/test_init_loss'] = clf_losses_test[0].item() + if len(clf_losses_test) > 2: + stats['ClfTrain/test_iter_loss'] = sum(clf_losses_test[1:-1]).item() / (len(clf_losses_test) - 2) + + return loss, stats + + +class KLDiMPActor(BaseActor): + """Actor for training the DiMP network.""" + def __init__(self, net, objective, loss_weight=None): + super().__init__(net, objective) + if loss_weight is None: + loss_weight = {'bb_ce': 1.0} + self.loss_weight = loss_weight + + def __call__(self, data): + """ + args: + data - The input data, should contain the fields 'train_images', 'test_images', 'train_anno', + 'test_proposals', 'proposal_iou' and 'test_label'. + + returns: + loss - the training loss + stats - dict containing detailed losses + """ + # Run network + target_scores, bb_scores = self.net(train_imgs=data['train_images'], + test_imgs=data['test_images'], + train_bb=data['train_anno'], + test_proposals=data['test_proposals']) + + # Reshape bb reg variables + is_valid = data['test_anno'][:, :, 0] < 99999.0 + bb_scores = bb_scores[is_valid, :] + proposal_density = data['proposal_density'][is_valid, :] + gt_density = data['gt_density'][is_valid, :] + + # Compute loss + bb_ce = self.objective['bb_ce'](bb_scores, sample_density=proposal_density, gt_density=gt_density, mc_dim=1) + loss_bb_ce = self.loss_weight['bb_ce'] * bb_ce + + # If standard DiMP classifier is used + loss_target_classifier = 0 + loss_test_init_clf = 0 + loss_test_iter_clf = 0 + if 'test_clf' in self.loss_weight.keys(): + # Classification losses for the different optimization iterations + clf_losses_test = [self.objective['test_clf'](s, data['test_label'], data['test_anno']) for s in target_scores] + + # Loss of the final filter + clf_loss_test = clf_losses_test[-1] + loss_target_classifier = self.loss_weight['test_clf'] * clf_loss_test + + # Loss for the initial filter iteration + if 'test_init_clf' in self.loss_weight.keys(): + loss_test_init_clf = self.loss_weight['test_init_clf'] * clf_losses_test[0] + + # Loss for the intermediate filter iterations + if 'test_iter_clf' in self.loss_weight.keys(): + test_iter_weights = self.loss_weight['test_iter_clf'] + if isinstance(test_iter_weights, list): + loss_test_iter_clf = sum([a * b for a, b in zip(test_iter_weights, clf_losses_test[1:-1])]) + else: + loss_test_iter_clf = (test_iter_weights / (len(clf_losses_test) - 2)) * sum(clf_losses_test[1:-1]) + + # If PrDiMP classifier is used + loss_clf_ce = 0 + loss_clf_ce_init = 0 + loss_clf_ce_iter = 0 + if 'clf_ce' in self.loss_weight.keys(): + # Classification losses for the different optimization iterations + clf_ce_losses = [self.objective['clf_ce'](s, data['test_label_density'], grid_dim=(-2,-1)) for s in target_scores] + + # Loss of the final filter + clf_ce = clf_ce_losses[-1] + loss_clf_ce = self.loss_weight['clf_ce'] * clf_ce + + # Loss for the initial filter iteration + if 'clf_ce_init' in self.loss_weight.keys(): + loss_clf_ce_init = self.loss_weight['clf_ce_init'] * clf_ce_losses[0] + + # Loss for the intermediate filter iterations + if 'clf_ce_iter' in self.loss_weight.keys() and len(clf_ce_losses) > 2: + test_iter_weights = self.loss_weight['clf_ce_iter'] + if isinstance(test_iter_weights, list): + loss_clf_ce_iter = sum([a * b for a, b in zip(test_iter_weights, clf_ce_losses[1:-1])]) + else: + loss_clf_ce_iter = (test_iter_weights / (len(clf_ce_losses) - 2)) * sum(clf_ce_losses[1:-1]) + + # Total loss + loss = loss_bb_ce + loss_clf_ce + loss_clf_ce_init + loss_clf_ce_iter + \ + loss_target_classifier + loss_test_init_clf + loss_test_iter_clf + + if torch.isinf(loss) or torch.isnan(loss): + raise Exception('ERROR: Loss was nan or inf!!!') + + # Log stats + stats = {'Loss/total': loss.item(), + 'Loss/bb_ce': bb_ce.item(), + 'Loss/loss_bb_ce': loss_bb_ce.item()} + if 'test_clf' in self.loss_weight.keys(): + stats['Loss/target_clf'] = loss_target_classifier.item() + if 'test_init_clf' in self.loss_weight.keys(): + stats['Loss/test_init_clf'] = loss_test_init_clf.item() + if 'test_iter_clf' in self.loss_weight.keys(): + stats['Loss/test_iter_clf'] = loss_test_iter_clf.item() + if 'clf_ce' in self.loss_weight.keys(): + stats['Loss/clf_ce'] = loss_clf_ce.item() + if 'clf_ce_init' in self.loss_weight.keys(): + stats['Loss/clf_ce_init'] = loss_clf_ce_init.item() + if 'clf_ce_iter' in self.loss_weight.keys() and len(clf_ce_losses) > 2: + stats['Loss/clf_ce_iter'] = loss_clf_ce_iter.item() + + if 'test_clf' in self.loss_weight.keys(): + stats['ClfTrain/test_loss'] = clf_loss_test.item() + if len(clf_losses_test) > 0: + stats['ClfTrain/test_init_loss'] = clf_losses_test[0].item() + if len(clf_losses_test) > 2: + stats['ClfTrain/test_iter_loss'] = sum(clf_losses_test[1:-1]).item() / (len(clf_losses_test) - 2) + + if 'clf_ce' in self.loss_weight.keys(): + stats['ClfTrain/clf_ce'] = clf_ce.item() + if len(clf_ce_losses) > 0: + stats['ClfTrain/clf_ce_init'] = clf_ce_losses[0].item() + if len(clf_ce_losses) > 2: + stats['ClfTrain/clf_ce_iter'] = sum(clf_ce_losses[1:-1]).item() / (len(clf_ce_losses) - 2) + + return loss, stats diff --git a/ltr/admin/__init__.py b/ltr/admin/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/admin/__pycache__/__init__.cpython-37.pyc b/ltr/admin/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..cfc6fee Binary files /dev/null and b/ltr/admin/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/environment.cpython-37.pyc b/ltr/admin/__pycache__/environment.cpython-37.pyc new file mode 100755 index 0000000..4927292 Binary files /dev/null and b/ltr/admin/__pycache__/environment.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/loading.cpython-37.pyc b/ltr/admin/__pycache__/loading.cpython-37.pyc new file mode 100755 index 0000000..bdd836d Binary files /dev/null and b/ltr/admin/__pycache__/loading.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/local.cpython-37.pyc b/ltr/admin/__pycache__/local.cpython-37.pyc new file mode 100755 index 0000000..ed9c0ad Binary files /dev/null and b/ltr/admin/__pycache__/local.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/model_constructor.cpython-37.pyc b/ltr/admin/__pycache__/model_constructor.cpython-37.pyc new file mode 100755 index 0000000..085ba5b Binary files /dev/null and b/ltr/admin/__pycache__/model_constructor.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/multigpu.cpython-37.pyc b/ltr/admin/__pycache__/multigpu.cpython-37.pyc new file mode 100755 index 0000000..ba6b401 Binary files /dev/null and b/ltr/admin/__pycache__/multigpu.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/settings.cpython-37.pyc b/ltr/admin/__pycache__/settings.cpython-37.pyc new file mode 100755 index 0000000..a08afdb Binary files /dev/null and b/ltr/admin/__pycache__/settings.cpython-37.pyc differ diff --git a/ltr/admin/__pycache__/stats.cpython-37.pyc b/ltr/admin/__pycache__/stats.cpython-37.pyc new file mode 100755 index 0000000..be38e1a Binary files /dev/null and b/ltr/admin/__pycache__/stats.cpython-37.pyc differ diff --git a/ltr/admin/environment.py b/ltr/admin/environment.py new file mode 100755 index 0000000..3509023 --- /dev/null +++ b/ltr/admin/environment.py @@ -0,0 +1,53 @@ +import importlib +import os +from collections import OrderedDict + + +def create_default_local_file(): + path = os.path.join(os.path.dirname(__file__), 'local.py') + + empty_str = '\'\'' + default_settings = OrderedDict({ + 'workspace_dir': empty_str, + 'tensorboard_dir': 'self.workspace_dir + \'/tensorboard/\'', + 'lasot_dir': empty_str, + 'got10k_dir': empty_str, + 'trackingnet_dir': empty_str, + 'coco_dir': empty_str, + 'lvis_dir': empty_str, + 'sbd_dir': empty_str, + 'imagenet_dir': empty_str, + 'imagenetdet_dir': empty_str, + 'ecssd_dir': empty_str, + 'hkuis_dir': empty_str, + 'msra10k_dir': empty_str, + 'davis_dir': empty_str, + 'youtubevos_dir': empty_str}) + + comment = {'workspace_dir': 'Base directory for saving network checkpoints.', + 'tensorboard_dir': 'Directory for tensorboard files.'} + + with open(path, 'w') as f: + f.write('class EnvironmentSettings:\n') + f.write(' def __init__(self):\n') + + for attr, attr_val in default_settings.items(): + comment_str = None + if attr in comment: + comment_str = comment[attr] + if comment_str is None: + f.write(' self.{} = {}\n'.format(attr, attr_val)) + else: + f.write(' self.{} = {} # {}\n'.format(attr, attr_val, comment_str)) + + +def env_settings(): + env_module_name = 'ltr.admin.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.EnvironmentSettings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. Then try to run again.'.format(env_file)) diff --git a/ltr/admin/loading.py b/ltr/admin/loading.py new file mode 100755 index 0000000..c49d8f7 --- /dev/null +++ b/ltr/admin/loading.py @@ -0,0 +1,151 @@ +import torch +import os +import sys +from pathlib import Path +import importlib +import inspect +import ltr.admin.settings as ws_settings + + +def load_trained_network(workspace_dir, network_path, checkpoint=None): + """OUTDATED. Use load_pretrained instead!""" + checkpoint_dir = os.path.join(workspace_dir, 'checkpoints') + directory = '{}/{}'.format(checkpoint_dir, network_path) + + net, _ = load_network(directory, checkpoint) + return net + + +def load_pretrained(module, name, checkpoint=None, **kwargs): + """Load a network trained using the LTR framework. This is useful when you want to initialize your new network with + a previously trained model. + args: + module - Name of the train script module. I.e. the name of the folder in ltr/train_scripts. + name - The name of the train_script. + checkpoint - You can supply the checkpoint number or the full path to the checkpoint file (see load_network). + **kwargs - These are passed to load_network (see that function). + """ + + settings = ws_settings.Settings() + network_dir = os.path.join(settings.env.workspace_dir, 'checkpoints', 'ltr', module, name) + return load_network(network_dir=network_dir, checkpoint=checkpoint, **kwargs) + + +def load_network(network_dir=None, checkpoint=None, constructor_fun_name=None, constructor_module=None, **kwargs): + """Loads a network checkpoint file. + + Can be called in two different ways: + load_checkpoint(network_dir): + Loads the checkpoint file given by the path. If checkpoint_dir is a directory, + it tries to find the latest checkpoint in that directory. + + load_checkpoint(network_dir, checkpoint=epoch_num): + Loads the network at the given epoch number (int). + + The extra keyword arguments are supplied to the network constructor to replace saved ones. + """ + checkpoint = '/media/TBData2/kristian_projects/conda_env/super_dimp/DiMP_LTMU/pytracking/networks/dimp50.pth' + + if network_dir is not None: + net_path = Path(network_dir) + else: + net_path = None + + if net_path.is_file(): + checkpoint = str(net_path) + + if checkpoint is None: + # Load most recent checkpoint + checkpoint_list = sorted(net_path.glob('*.pth.tar')) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No matching checkpoint file found') + elif isinstance(checkpoint, int): + # Checkpoint is the epoch number + checkpoint_list = sorted(net_path.glob('*_ep{:04d}.pth.tar'.format(checkpoint))) + if not checkpoint_list or len(checkpoint_list) == 0: + raise Exception('No matching checkpoint file found') + if len(checkpoint_list) > 1: + raise Exception('Multiple matching checkpoint files found') + else: + checkpoint_path = checkpoint_list[0] + elif isinstance(checkpoint, str): + # Checkpoint is the path + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + checkpoint_dict = torch_load_legacy(checkpoint_path) + + # Construct network model + if 'constructor' in checkpoint_dict and checkpoint_dict['constructor'] is not None: + net_constr = checkpoint_dict['constructor'] + if constructor_fun_name is not None: + net_constr.fun_name = constructor_fun_name + if constructor_module is not None: + net_constr.fun_module = constructor_module + # Legacy networks before refactoring + if net_constr.fun_module.startswith('dlframework.'): + net_constr.fun_module = net_constr.fun_module[len('dlframework.'):] + net_fun = getattr(importlib.import_module(net_constr.fun_module), net_constr.fun_name) + net_fun_args = list(inspect.signature(net_fun).parameters.keys()) + for arg, val in kwargs.items(): + if arg in net_fun_args: + net_constr.kwds[arg] = val + else: + print('WARNING: Keyword argument "{}" not found when loading network. It was ignored.'.format(arg)) + net = net_constr.get() + else: + raise RuntimeError('No constructor for the given network.') + + net.load_state_dict(checkpoint_dict['net']) + + net.constructor = checkpoint_dict['constructor'] + if 'net_info' in checkpoint_dict and checkpoint_dict['net_info'] is not None: + net.info = checkpoint_dict['net_info'] + + return net, checkpoint_dict + + +def load_weights(net, path, strict=True): + checkpoint_dict = torch.load(path) + weight_dict = checkpoint_dict['net'] + net.load_state_dict(weight_dict, strict=strict) + return net + + +def torch_load_legacy(path): + """Load network with legacy environment.""" + + # Setup legacy env (for older networks) + _setup_legacy_env() + + # Load network + checkpoint_dict = torch.load(path, map_location='cpu') + + # Cleanup legacy + _cleanup_legacy_env() + + return checkpoint_dict + + +def _setup_legacy_env(): + importlib.import_module('ltr') + sys.modules['dlframework'] = sys.modules['ltr'] + sys.modules['dlframework.common'] = sys.modules['ltr'] + importlib.import_module('ltr.admin') + sys.modules['dlframework.common.utils'] = sys.modules['ltr.admin'] + for m in ('model_constructor', 'stats', 'settings', 'local'): + importlib.import_module('ltr.admin.' + m) + sys.modules['dlframework.common.utils.' + m] = sys.modules['ltr.admin.' + m] + + +def _cleanup_legacy_env(): + del_modules = [] + for m in sys.modules.keys(): + if m.startswith('dlframework'): + del_modules.append(m) + for m in del_modules: + del sys.modules[m] diff --git a/ltr/admin/local.py b/ltr/admin/local.py new file mode 100755 index 0000000..d2c4aff --- /dev/null +++ b/ltr/admin/local.py @@ -0,0 +1,17 @@ +class EnvironmentSettings: + def __init__(self): + self.workspace_dir = '' # Base directory for saving network checkpoints. + self.tensorboard_dir = self.workspace_dir + '/tensorboard/' # Directory for tensorboard files. + self.lasot_dir = '' + self.got10k_dir = '' + self.trackingnet_dir = '' + self.coco_dir = '' + self.lvis_dir = '' + self.sbd_dir = '' + self.imagenet_dir = '' + self.imagenetdet_dir = '' + self.ecssd_dir = '' + self.hkuis_dir = '' + self.msra10k_dir = '' + self.davis_dir = '' + self.youtubevos_dir = '' diff --git a/ltr/admin/model_constructor.py b/ltr/admin/model_constructor.py new file mode 100755 index 0000000..0d77a9c --- /dev/null +++ b/ltr/admin/model_constructor.py @@ -0,0 +1,50 @@ +from functools import wraps +import importlib + + +def model_constructor(f): + """ Wraps the function 'f' which returns the network. An extra field 'constructor' is added to the network returned + by 'f'. This field contains an instance of the 'NetConstructor' class, which contains the information needed to + re-construct the network, such as the name of the function 'f', the function arguments etc. Thus, the network can + be easily constructed from a saved checkpoint by calling NetConstructor.get() function. + """ + @wraps(f) + def f_wrapper(*args, **kwds): + net_constr = NetConstructor(f.__name__, f.__module__, args, kwds) + output = f(*args, **kwds) + if isinstance(output, (tuple, list)): + # Assume first argument is the network + output[0].constructor = net_constr + else: + output.constructor = net_constr + return output + return f_wrapper + + +class NetConstructor: + """ Class to construct networks. Takes as input the function name (e.g. atom_resnet18), the name of the module + which contains the network function (e.g. ltr.models.bbreg.atom) and the arguments for the network + function. The class object can then be stored along with the network weights to re-construct the network.""" + def __init__(self, fun_name, fun_module, args, kwds): + """ + args: + fun_name - The function which returns the network + fun_module - the module which contains the network function + args - arguments which are passed to the network function + kwds - arguments which are passed to the network function + """ + self.fun_name = fun_name + self.fun_module = fun_module + self.args = args + self.kwds = kwds + + def get(self, alpha=None): + """ Rebuild the network by calling the network function with the correct arguments. """ + if alpha is not None: + module = 'alpha_refine.ltr.models.AR_seg_mask.AR_seg_mask' + else: + module = self.fun_module + + net_module = importlib.import_module(module) + net_fun = getattr(net_module, self.fun_name) + return net_fun(*self.args, **self.kwds) diff --git a/ltr/admin/multigpu.py b/ltr/admin/multigpu.py new file mode 100755 index 0000000..86a77fb --- /dev/null +++ b/ltr/admin/multigpu.py @@ -0,0 +1,15 @@ +import torch.nn as nn + + +def is_multi_gpu(net): + return isinstance(net, (MultiGPU, nn.DataParallel)) + + +class MultiGPU(nn.DataParallel): + """Wraps a network to allow simple multi-GPU training.""" + def __getattr__(self, item): + try: + return super().__getattr__(item) + except: + pass + return getattr(self.module, item) \ No newline at end of file diff --git a/ltr/admin/settings.py b/ltr/admin/settings.py new file mode 100755 index 0000000..0221e74 --- /dev/null +++ b/ltr/admin/settings.py @@ -0,0 +1,13 @@ +from ltr.admin.environment import env_settings + + +class Settings: + """ Training settings, e.g. the paths to datasets and networks.""" + def __init__(self): + self.set_default() + + def set_default(self): + self.env = env_settings() + self.use_gpu = True + + diff --git a/ltr/admin/stats.py b/ltr/admin/stats.py new file mode 100755 index 0000000..34887fc --- /dev/null +++ b/ltr/admin/stats.py @@ -0,0 +1,71 @@ + + +class StatValue: + def __init__(self): + self.clear() + + def reset(self): + self.val = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val): + self.val = val + self.history.append(self.val) + + +class AverageMeter(object): + """Computes and stores the average and current value""" + def __init__(self): + self.clear() + self.has_new_data = False + + def reset(self): + self.avg = 0 + self.val = 0 + self.sum = 0 + self.count = 0 + + def clear(self): + self.reset() + self.history = [] + + def update(self, val, n=1): + self.val = val + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + def new_epoch(self): + if self.count > 0: + self.history.append(self.avg) + self.reset() + self.has_new_data = True + else: + self.has_new_data = False + + +def topk_accuracy(output, target, topk=(1,)): + """Computes the precision@k for the specified values of k""" + single_input = not isinstance(topk, (tuple, list)) + if single_input: + topk = (topk,) + + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)[0] + res.append(correct_k * 100.0 / batch_size) + + if single_input: + return res[0] + + return res diff --git a/ltr/admin/tensorboard.py b/ltr/admin/tensorboard.py new file mode 100755 index 0000000..94d12ba --- /dev/null +++ b/ltr/admin/tensorboard.py @@ -0,0 +1,28 @@ +import os +from collections import OrderedDict +try: + from torch.utils.tensorboard import SummaryWriter +except: + print('WARNING: You are using tensorboardX instead sis you have a too old pytorch version.') + from tensorboardX import SummaryWriter + + +class TensorboardWriter: + def __init__(self, directory, loader_names): + self.directory = directory + self.writer = OrderedDict({name: SummaryWriter(os.path.join(self.directory, name)) for name in loader_names}) + + def write_info(self, module_name, script_name, description): + tb_info_writer = SummaryWriter(os.path.join(self.directory, 'info')) + tb_info_writer.add_text('Modulet_name', module_name) + tb_info_writer.add_text('Script_name', script_name) + tb_info_writer.add_text('Description', description) + tb_info_writer.close() + + def write_epoch(self, stats: OrderedDict, epoch: int, ind=-1): + for loader_name, loader_stats in stats.items(): + if loader_stats is None: + continue + for var_name, val in loader_stats.items(): + if hasattr(val, 'history') and getattr(val, 'has_new_data', True): + self.writer[loader_name].add_scalar(var_name, val.history[ind], epoch) \ No newline at end of file diff --git a/ltr/data/__init__.py b/ltr/data/__init__.py new file mode 100755 index 0000000..f29ac0f --- /dev/null +++ b/ltr/data/__init__.py @@ -0,0 +1 @@ +from .loader import LTRLoader \ No newline at end of file diff --git a/ltr/data/__pycache__/__init__.cpython-37.pyc b/ltr/data/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..66a6b03 Binary files /dev/null and b/ltr/data/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/data/__pycache__/bounding_box_utils.cpython-37.pyc b/ltr/data/__pycache__/bounding_box_utils.cpython-37.pyc new file mode 100755 index 0000000..8c23d87 Binary files /dev/null and b/ltr/data/__pycache__/bounding_box_utils.cpython-37.pyc differ diff --git a/ltr/data/__pycache__/image_loader.cpython-37.pyc b/ltr/data/__pycache__/image_loader.cpython-37.pyc new file mode 100755 index 0000000..bf2d394 Binary files /dev/null and b/ltr/data/__pycache__/image_loader.cpython-37.pyc differ diff --git a/ltr/data/__pycache__/loader.cpython-37.pyc b/ltr/data/__pycache__/loader.cpython-37.pyc new file mode 100755 index 0000000..d63f11f Binary files /dev/null and b/ltr/data/__pycache__/loader.cpython-37.pyc differ diff --git a/ltr/data/__pycache__/processing_utils_SE.cpython-37.pyc b/ltr/data/__pycache__/processing_utils_SE.cpython-37.pyc new file mode 100755 index 0000000..aca0f6a Binary files /dev/null and b/ltr/data/__pycache__/processing_utils_SE.cpython-37.pyc differ diff --git a/ltr/data/bounding_box_utils.py b/ltr/data/bounding_box_utils.py new file mode 100755 index 0000000..df0c31a --- /dev/null +++ b/ltr/data/bounding_box_utils.py @@ -0,0 +1,94 @@ +import torch + + +def rect_to_rel(bb, sz_norm=None): + """Convert standard rectangular parametrization of the bounding box [x, y, w, h] + to relative parametrization [cx/sw, cy/sh, log(w), log(h)], where [cx, cy] is the center coordinate. + args: + bb - N x 4 tensor of boxes. + sz_norm - [N] x 2 tensor of value of [sw, sh] (optional). sw=w and sh=h if not given. + """ + + c = bb[...,:2] + 0.5 * bb[...,2:] + if sz_norm is None: + c_rel = c / bb[...,2:] + else: + c_rel = c / sz_norm + sz_rel = torch.log(bb[...,2:]) + return torch.cat((c_rel, sz_rel), dim=-1) + + +def rel_to_rect(bb, sz_norm=None): + """Inverts the effect of rect_to_rel. See above.""" + + sz = torch.exp(bb[...,2:]) + if sz_norm is None: + c = bb[...,:2] * sz + else: + c = bb[...,:2] * sz_norm + tl = c - 0.5 * sz + return torch.cat((tl, sz), dim=-1) + + +def masks_to_bboxes(mask, fmt='c'): + + """ Convert a mask tensor to one or more bounding boxes. + Note: This function is a bit new, make sure it does what it says. /Andreas + :param mask: Tensor of masks, shape = (..., H, W) + :param fmt: bbox layout. 'c' => "center + size" or (x_center, y_center, width, height) + 't' => "top left + size" or (x_left, y_top, width, height) + 'v' => "vertices" or (x_left, y_top, x_right, y_bottom) + :return: tensor containing a batch of bounding boxes, shape = (..., 4) + """ + batch_shape = mask.shape[:-2] + mask = mask.reshape((-1, *mask.shape[-2:])) + bboxes = [] + + for m in mask: + mx = m.sum(dim=-2).nonzero() + my = m.sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + bboxes.append(bb) + + bboxes = torch.tensor(bboxes, dtype=torch.float32, device=mask.device) + bboxes = bboxes.reshape(batch_shape + (4,)) + + if fmt == 'v': + return bboxes + + x1 = bboxes[..., :2] + s = bboxes[..., 2:] - x1 + 1 + + if fmt == 'c': + return torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + return torch.cat((x1, s), dim=-1) + + raise ValueError("Undefined bounding box layout '%s'" % fmt) + + +def masks_to_bboxes_multi(mask, ids, fmt='c'): + assert mask.dim() == 2 + bboxes = [] + + for id in ids: + mx = (mask == id).sum(dim=-2).nonzero() + my = (mask == id).float().sum(dim=-1).nonzero() + bb = [mx.min(), my.min(), mx.max(), my.max()] if (len(mx) > 0 and len(my) > 0) else [0, 0, 0, 0] + + bb = torch.tensor(bb, dtype=torch.float32, device=mask.device) + + x1 = bb[:2] + s = bb[2:] - x1 + 1 + + if fmt == 'v': + pass + elif fmt == 'c': + bb = torch.cat((x1 + 0.5 * s, s), dim=-1) + elif fmt == 't': + bb = torch.cat((x1, s), dim=-1) + else: + raise ValueError("Undefined bounding box layout '%s'" % fmt) + bboxes.append(bb) + + return bboxes diff --git a/ltr/data/image_loader.py b/ltr/data/image_loader.py new file mode 100755 index 0000000..636ec0a --- /dev/null +++ b/ltr/data/image_loader.py @@ -0,0 +1,103 @@ +import jpeg4py +import cv2 as cv +from PIL import Image +import numpy as np + +davis_palette = np.repeat(np.expand_dims(np.arange(0,256), 1), 3, 1).astype(np.uint8) +davis_palette[:22, :] = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0], + [0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128], + [64, 0, 0], [191, 0, 0], [64, 128, 0], [191, 128, 0], + [64, 0, 128], [191, 0, 128], [64, 128, 128], [191, 128, 128], + [0, 64, 0], [128, 64, 0], [0, 191, 0], [128, 191, 0], + [0, 64, 128], [128, 64, 128]] + + +def default_image_loader(path): + """The default image loader, reads the image from the given path. It first tries to use the jpeg4py_loader, + but reverts to the opencv_loader if the former is not available.""" + if default_image_loader.use_jpeg4py is None: + # Try using jpeg4py + im = jpeg4py_loader(path) + if im is None: + default_image_loader.use_jpeg4py = False + print('Using opencv_loader instead.') + else: + default_image_loader.use_jpeg4py = True + return im + if default_image_loader.use_jpeg4py: + return jpeg4py_loader(path) + return opencv_loader(path) + +default_image_loader.use_jpeg4py = None + + +def jpeg4py_loader(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_loader(path): + """ Read image using opencv's imread function and returns it in rgb format""" + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def jpeg4py_loader_w_failsafe(path): + """ Image reading using jpeg4py https://github.com/ajkxyz/jpeg4py""" + try: + return jpeg4py.JPEG(path).decode() + except: + try: + im = cv.imread(path, cv.IMREAD_COLOR) + + # convert to rgb and return + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def opencv_seg_loader(path): + """ Read segmentation annotation using opencv's imread function""" + try: + return cv.imread(path) + except Exception as e: + print('ERROR: Could not read image "{}"'.format(path)) + print(e) + return None + + +def imread_indexed(filename): + """ Load indexed image with given filename. Used to read segmentation annotations.""" + + im = Image.open(filename) + + annotation = np.atleast_3d(im)[...,0] + return annotation + + +def imwrite_indexed(filename, array, color_palette=None): + """ Save indexed image as png. Used to save segmentation annotation.""" + + if color_palette is None: + color_palette = davis_palette + + if np.atleast_3d(array).shape[2] != 1: + raise Exception("Saving indexed PNGs requires 2D array.") + + im = Image.fromarray(array) + im.putpalette(color_palette.ravel()) + im.save(filename, format='PNG') \ No newline at end of file diff --git a/ltr/data/loader.py b/ltr/data/loader.py new file mode 100755 index 0000000..bd51bbc --- /dev/null +++ b/ltr/data/loader.py @@ -0,0 +1,190 @@ +import torch +import torch.utils.data.dataloader +import importlib +import collections +from torch._six import string_classes, int_classes +from pytracking import TensorDict, TensorList + + +def _check_use_shared_memory(): + if hasattr(torch.utils.data.dataloader, '_use_shared_memory'): + return getattr(torch.utils.data.dataloader, '_use_shared_memory') + collate_lib = importlib.import_module('torch.utils.data._utils.collate') + if hasattr(collate_lib, '_use_shared_memory'): + return getattr(collate_lib, '_use_shared_memory') + return torch.utils.data.get_worker_info() is not None + + +def ltr_collate(batch): + """Puts each data field into a tensor with outer dimension batch size""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 0, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 0) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +def ltr_collate_stack1(batch): + """Puts each data field into a tensor. The tensors are stacked at dim=1 to form the batch""" + + error_msg = "batch must contain tensors, numbers, dicts or lists; found {}" + elem_type = type(batch[0]) + if isinstance(batch[0], torch.Tensor): + out = None + if _check_use_shared_memory(): + # If we're in a background process, concatenate directly into a + # shared memory tensor to avoid an extra copy + numel = sum([x.numel() for x in batch]) + storage = batch[0].storage()._new_shared(numel) + out = batch[0].new(storage) + return torch.stack(batch, 1, out=out) + # if batch[0].dim() < 4: + # return torch.stack(batch, 0, out=out) + # return torch.cat(batch, 0, out=out) + elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \ + and elem_type.__name__ != 'string_': + elem = batch[0] + if elem_type.__name__ == 'ndarray': + # array of string classes and object + if torch.utils.data.dataloader.re.search('[SaUO]', elem.dtype.str) is not None: + raise TypeError(error_msg.format(elem.dtype)) + + return torch.stack([torch.from_numpy(b) for b in batch], 1) + if elem.shape == (): # scalars + py_type = float if elem.dtype.name.startswith('float') else int + return torch.utils.data.dataloader.numpy_type_map[elem.dtype.name](list(map(py_type, batch))) + elif isinstance(batch[0], int_classes): + return torch.LongTensor(batch) + elif isinstance(batch[0], float): + return torch.DoubleTensor(batch) + elif isinstance(batch[0], string_classes): + return batch + elif isinstance(batch[0], TensorDict): + return TensorDict({key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]}) + elif isinstance(batch[0], collections.Mapping): + return {key: ltr_collate_stack1([d[key] for d in batch]) for key in batch[0]} + elif isinstance(batch[0], TensorList): + transposed = zip(*batch) + return TensorList([ltr_collate_stack1(samples) for samples in transposed]) + elif isinstance(batch[0], collections.Sequence): + transposed = zip(*batch) + return [ltr_collate_stack1(samples) for samples in transposed] + elif batch[0] is None: + return batch + + raise TypeError((error_msg.format(type(batch[0])))) + + +class LTRLoader(torch.utils.data.dataloader.DataLoader): + """ + Data loader. Combines a dataset and a sampler, and provides + single- or multi-process iterators over the dataset. + + Note: The only difference with default pytorch DataLoader is that an additional option stack_dim is available to + select along which dimension the data should be stacked to form a batch. + + Arguments: + dataset (Dataset): dataset from which to load the data. + batch_size (int, optional): how many samples per batch to load + (default: 1). + shuffle (bool, optional): set to ``True`` to have the data reshuffled + at every epoch (default: False). + sampler (Sampler, optional): defines the strategy to draw samples from + the dataset. If specified, ``shuffle`` must be False. + batch_sampler (Sampler, optional): like sampler, but returns a batch of + indices at a time. Mutually exclusive with batch_size, shuffle, + sampler, and drop_last. + num_workers (int, optional): how many subprocesses to use for data + loading. 0 means that the data will be loaded in the main process. + (default: 0) + collate_fn (callable, optional): merges a list of samples to form a mini-batch. + stack_dim (int): Dimension along which to stack to form the batch. (default: 0) + pin_memory (bool, optional): If ``True``, the data loader will copy tensors + into CUDA pinned memory before returning them. + drop_last (bool, optional): set to ``True`` to drop the last incomplete batch, + if the dataset size is not divisible by the batch size. If ``False`` and + the size of dataset is not divisible by the batch size, then the last batch + will be smaller. (default: False) + timeout (numeric, optional): if positive, the timeout value for collecting a batch + from workers. Should always be non-negative. (default: 0) + worker_init_fn (callable, optional): If not None, this will be called on each + worker subprocess with the worker id (an int in ``[0, num_workers - 1]``) as + input, after seeding and before data loading. (default: None) + + .. note:: By default, each worker will have its PyTorch seed set to + ``base_seed + worker_id``, where ``base_seed`` is a long generated + by main process using its RNG. However, seeds for other libraies + may be duplicated upon initializing workers (w.g., NumPy), causing + each worker to return identical random numbers. (See + :ref:`dataloader-workers-random-seed` section in FAQ.) You may + use ``torch.initial_seed()`` to access the PyTorch seed for each + worker in :attr:`worker_init_fn`, and use it to set other seeds + before data loading. + + .. warning:: If ``spawn`` start method is used, :attr:`worker_init_fn` cannot be an + unpicklable object, e.g., a lambda function. + """ + + __initialized = False + + def __init__(self, name, dataset, training=True, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, + num_workers=0, epoch_interval=1, collate_fn=None, stack_dim=0, pin_memory=False, drop_last=False, + timeout=0, worker_init_fn=None): + if collate_fn is None: + if stack_dim == 0: + collate_fn = ltr_collate + elif stack_dim == 1: + collate_fn = ltr_collate_stack1 + else: + raise ValueError('Stack dim no supported. Must be 0 or 1.') + + super(LTRLoader, self).__init__(dataset, batch_size, shuffle, sampler, batch_sampler, + num_workers, collate_fn, pin_memory, drop_last, + timeout, worker_init_fn) + + self.name = name + self.training = training + self.epoch_interval = epoch_interval + self.stack_dim = stack_dim \ No newline at end of file diff --git a/ltr/data/processing.py b/ltr/data/processing.py new file mode 100755 index 0000000..5977039 --- /dev/null +++ b/ltr/data/processing.py @@ -0,0 +1,662 @@ +import torch +import torchvision.transforms as transforms +from pytracking import TensorDict +import ltr.data.processing_utils as prutils + + +def stack_tensors(x): + if isinstance(x, (list, tuple)) and isinstance(x[0], torch.Tensor): + return torch.stack(x) + return x + + +class BaseProcessing: + """ Base class for Processing. Processing class is used to process the data returned by a dataset, before passing it + through the network. For example, it can be used to crop a search region around the object, apply various data + augmentations, etc.""" + def __init__(self, transform=transforms.ToTensor(), train_transform=None, test_transform=None, joint_transform=None): + """ + args: + transform - The set of transformations to be applied on the images. Used only if train_transform or + test_transform is None. + train_transform - The set of transformations to be applied on the train images. If None, the 'transform' + argument is used instead. + test_transform - The set of transformations to be applied on the test images. If None, the 'transform' + argument is used instead. + joint_transform - The set of transformations to be applied 'jointly' on the train and test images. For + example, it can be used to convert both test and train images to grayscale. + """ + self.transform = {'train': transform if train_transform is None else train_transform, + 'test': transform if test_transform is None else test_transform, + 'joint': joint_transform} + + def __call__(self, data: TensorDict): + raise NotImplementedError + + +class ATOMProcessing(BaseProcessing): + """ The processing class used for training ATOM. The images are processed in the following way. + First, the target bounding box is jittered by adding some noise. Next, a square region (called search region ) + centered at the jittered target center, and of area search_area_factor^2 times the area of the jittered box is + cropped from the image. The reason for jittering the target box is to avoid learning the bias that the target is + always at the center of the search region. The search region is then resized to a fixed size given by the + argument output_sz. A set of proposals are then generated for the test images by jittering the ground truth box. + + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generates proposals by adding noise to the input box + args: + box - input box + + returns: + torch.Tensor - Array of shape (num_proposals, 4) containing proposals + torch.Tensor - Array of shape (num_proposals,) containing IoU overlap of each proposal with the input box. The + IoU is mapped to [-1, 1] + """ + # Generate proposals + num_proposals = self.proposal_params['boxes_per_frame'] + proposal_method = self.proposal_params.get('proposal_method', 'default') + + if proposal_method == 'default': + proposals = torch.zeros((num_proposals, 4)) + gt_iou = torch.zeros(num_proposals) + for i in range(num_proposals): + proposals[i, :], gt_iou[i] = prutils.perturb_box(box, min_iou=self.proposal_params['min_iou'], + sigma_factor=self.proposal_params['sigma_factor']) + elif proposal_method == 'gmm': + proposals, _, _ = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + num_samples=num_proposals) + gt_iou = prutils.iou(box.view(1,4), proposals.view(-1,4)) + + # Map to [-1, 1] + gt_iou = gt_iou * 2 - 1 + return proposals, gt_iou + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_iou' + """ + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes, _ = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + frame2_proposals, gt_iou = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = list(frame2_proposals) + data['proposal_iou'] = list(gt_iou) + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + +class KLBBregProcessing(BaseProcessing): + """ Based on ATOMProcessing. It supports training ATOM using the Maximum Likelihood or KL-divergence based learning + introduced in [https://arxiv.org/abs/1909.12297] and in PrDiMP [https://arxiv.org/abs/2003.12565]. + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + gt_sigma=self.proposal_params['gt_sigma'], + num_samples=self.proposal_params[ + 'boxes_per_frame'], + add_mean_box=self.proposal_params.get( + 'add_mean_box', False)) + + return proposals, proposal_density, gt_density + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_density', 'gt_density' + """ + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes, _ = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + +class ATOMwKLProcessing(BaseProcessing): + """Same as ATOMProcessing but using the GMM-based sampling of proposal boxes used in KLBBregProcessing.""" + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, proposal_params, + mode='pair', *args, **kwargs): + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.proposal_params = proposal_params + self.mode = mode + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + self.proposal_params['gt_sigma'], + self.proposal_params['boxes_per_frame']) + + iou = prutils.iou_gen(proposals, box.view(1, 4)) + return proposals, proposal_density, gt_density, iou + + def __call__(self, data: TensorDict): + # Apply joint transforms + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + # Crop image region centered at jittered_anno box + crops, boxes, _ = prutils.jittered_center_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz) + + # Apply transforms + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density, proposal_iou = zip( + *[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + data['proposal_iou'] = proposal_iou + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + return data + + + +class DiMPProcessing(BaseProcessing): + """ The processing class used for training DiMP. The images are processed in the following way. + First, the target bounding box is jittered by adding some noise. Next, a square region (called search region ) + centered at the jittered target center, and of area search_area_factor^2 times the area of the jittered box is + cropped from the image. The reason for jittering the target box is to avoid learning the bias that the target is + always at the center of the search region. The search region is then resized to a fixed size given by the + argument output_sz. A Gaussian label centered at the target is generated for each image. These label functions are + used for computing the loss of the predicted classification model on the test images. A set of proposals are + also generated for the test images by jittering the ground truth box. These proposals are used to train the + bounding box estimating branch. + + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, crop_type='replicate', + max_scale_change=None, mode='pair', proposal_params=None, label_function_params=None, *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + crop_type - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + label_function_params - Arguments for the label generation process. See _generate_label_function for details. + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.crop_type = crop_type + self.mode = mode + self.max_scale_change = max_scale_change + + self.proposal_params = proposal_params + self.label_function_params = label_function_params + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generates proposals by adding noise to the input box + args: + box - input box + + returns: + torch.Tensor - Array of shape (num_proposals, 4) containing proposals + torch.Tensor - Array of shape (num_proposals,) containing IoU overlap of each proposal with the input box. The + IoU is mapped to [-1, 1] + """ + # Generate proposals + num_proposals = self.proposal_params['boxes_per_frame'] + proposal_method = self.proposal_params.get('proposal_method', 'default') + + if proposal_method == 'default': + proposals = torch.zeros((num_proposals, 4)) + gt_iou = torch.zeros(num_proposals) + + for i in range(num_proposals): + proposals[i, :], gt_iou[i] = prutils.perturb_box(box, min_iou=self.proposal_params['min_iou'], + sigma_factor=self.proposal_params['sigma_factor']) + elif proposal_method == 'gmm': + proposals, _, _ = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + num_samples=num_proposals) + gt_iou = prutils.iou(box.view(1, 4), proposals.view(-1, 4)) + else: + raise ValueError('Unknown proposal method.') + + # Map to [-1, 1] + gt_iou = gt_iou * 2 - 1 + return proposals, gt_iou + + def _generate_label_function(self, target_bb): + """ Generates the gaussian label function centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_function_params['sigma_factor'], + self.label_function_params['kernel_sz'], + self.label_function_params['feature_sz'], self.output_sz, + end_pad_if_even=self.label_function_params.get('end_pad_if_even', True)) + + return gauss_label + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_iou', + 'test_label' (optional), 'train_label' (optional), 'test_label_density' (optional), 'train_label_density' (optional) + """ + + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + crops, boxes = prutils.target_image_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz, mode=self.crop_type, + max_scale_change=self.max_scale_change) + + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + if self.proposal_params: + frame2_proposals, gt_iou = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = list(frame2_proposals) + data['proposal_iou'] = list(gt_iou) + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + # Generate label functions + if self.label_function_params is not None: + data['train_label'] = self._generate_label_function(data['train_anno']) + data['test_label'] = self._generate_label_function(data['test_anno']) + + return data + + +class KLDiMPProcessing(BaseProcessing): + """ The processing class used for training PrDiMP that additionally supports the probabilistic classifier and + bounding box regressor. See DiMPProcessing for details. + """ + + def __init__(self, search_area_factor, output_sz, center_jitter_factor, scale_jitter_factor, crop_type='replicate', + max_scale_change=None, mode='pair', proposal_params=None, + label_function_params=None, label_density_params=None, *args, **kwargs): + """ + args: + search_area_factor - The size of the search region relative to the target size. + output_sz - An integer, denoting the size to which the search region is resized. The search region is always + square. + center_jitter_factor - A dict containing the amount of jittering to be applied to the target center before + extracting the search region. See _get_jittered_box for how the jittering is done. + scale_jitter_factor - A dict containing the amount of jittering to be applied to the target size before + extracting the search region. See _get_jittered_box for how the jittering is done. + crop_type - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mode - Either 'pair' or 'sequence'. If mode='sequence', then output has an extra dimension for frames + proposal_params - Arguments for the proposal generation process. See _generate_proposals for details. + label_function_params - Arguments for the label generation process. See _generate_label_function for details. + label_density_params - Arguments for the label density generation process. See _generate_label_function for details. + """ + super().__init__(*args, **kwargs) + self.search_area_factor = search_area_factor + self.output_sz = output_sz + self.center_jitter_factor = center_jitter_factor + self.scale_jitter_factor = scale_jitter_factor + self.crop_type = crop_type + self.mode = mode + self.max_scale_change = max_scale_change + + self.proposal_params = proposal_params + self.label_function_params = label_function_params + self.label_density_params = label_density_params + + def _get_jittered_box(self, box, mode): + """ Jitter the input box + args: + box - input bounding box + mode - string 'train' or 'test' indicating train or test data + + returns: + torch.Tensor - jittered box + """ + + jittered_size = box[2:4] * torch.exp(torch.randn(2) * self.scale_jitter_factor[mode]) + max_offset = (jittered_size.prod().sqrt() * torch.tensor(self.center_jitter_factor[mode]).float()) + jittered_center = box[0:2] + 0.5 * box[2:4] + max_offset * (torch.rand(2) - 0.5) + + return torch.cat((jittered_center - 0.5 * jittered_size, jittered_size), dim=0) + + def _generate_proposals(self, box): + """ Generate proposal sample boxes from a GMM proposal distribution and compute their ground-truth density. + This is used for ML and KL based regression learning of the bounding box regressor. + args: + box - input bounding box + """ + # Generate proposals + proposals, proposal_density, gt_density = prutils.sample_box_gmm(box, self.proposal_params['proposal_sigma'], + gt_sigma=self.proposal_params['gt_sigma'], + num_samples=self.proposal_params['boxes_per_frame'], + add_mean_box=self.proposal_params.get('add_mean_box', False)) + + return proposals, proposal_density, gt_density + + def _generate_label_function(self, target_bb): + """ Generates the gaussian label function centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_function_params['sigma_factor'], + self.label_function_params['kernel_sz'], + self.label_function_params['feature_sz'], self.output_sz, + end_pad_if_even=self.label_function_params.get('end_pad_if_even', True)) + + return gauss_label + + def _generate_label_density(self, target_bb): + """ Generates the gaussian label density centered at target_bb + args: + target_bb - target bounding box (num_images, 4) + + returns: + torch.Tensor - Tensor of shape (num_images, label_sz, label_sz) containing the label for each sample + """ + + feat_sz = self.label_density_params['feature_sz'] * self.label_density_params.get('interp_factor', 1) + gauss_label = prutils.gaussian_label_function(target_bb.view(-1, 4), self.label_density_params['sigma_factor'], + self.label_density_params['kernel_sz'], + feat_sz, self.output_sz, + end_pad_if_even=self.label_density_params.get('end_pad_if_even', True), + density=True, + uni_bias=self.label_density_params.get('uni_weight', 0.0)) + + gauss_label *= (gauss_label > self.label_density_params.get('threshold', 0.0)).float() + + if self.label_density_params.get('normalize', False): + g_sum = gauss_label.sum(dim=(-2,-1)) + valid = g_sum>0.01 + gauss_label[valid, :, :] /= g_sum[valid].view(-1, 1, 1) + gauss_label[~valid, :, :] = 1.0 / (gauss_label.shape[-2] * gauss_label.shape[-1]) + + gauss_label *= 1.0 - self.label_density_params.get('shrink', 0.0) + + return gauss_label + + def __call__(self, data: TensorDict): + """ + args: + data - The input data, should contain the following fields: + 'train_images', test_images', 'train_anno', 'test_anno' + returns: + TensorDict - output data block with following fields: + 'train_images', 'test_images', 'train_anno', 'test_anno', 'test_proposals', 'proposal_density', 'gt_density', + 'test_label' (optional), 'train_label' (optional), 'test_label_density' (optional), 'train_label_density' (optional) + """ + + if self.transform['joint'] is not None: + data['train_images'], data['train_anno'] = self.transform['joint'](image=data['train_images'], bbox=data['train_anno']) + data['test_images'], data['test_anno'] = self.transform['joint'](image=data['test_images'], bbox=data['test_anno'], new_roll=False) + + for s in ['train', 'test']: + assert self.mode == 'sequence' or len(data[s + '_images']) == 1, \ + "In pair mode, num train/test frames must be 1" + + # Add a uniform noise to the center pos + jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']] + + crops, boxes = prutils.target_image_crop(data[s + '_images'], jittered_anno, data[s + '_anno'], + self.search_area_factor, self.output_sz, mode=self.crop_type, + max_scale_change=self.max_scale_change) + + data[s + '_images'], data[s + '_anno'] = self.transform[s](image=crops, bbox=boxes, joint=False) + + # Generate proposals + proposals, proposal_density, gt_density = zip(*[self._generate_proposals(a) for a in data['test_anno']]) + + data['test_proposals'] = proposals + data['proposal_density'] = proposal_density + data['gt_density'] = gt_density + + for s in ['train', 'test']: + is_distractor = data.get('is_distractor_{}_frame'.format(s), None) + if is_distractor is not None: + for is_dist, box in zip(is_distractor, data[s+'_anno']): + if is_dist: + box[0] = 99999999.9 + box[1] = 99999999.9 + + # Prepare output + if self.mode == 'sequence': + data = data.apply(stack_tensors) + else: + data = data.apply(lambda x: x[0] if isinstance(x, list) else x) + + # Generate label functions + if self.label_function_params is not None: + data['train_label'] = self._generate_label_function(data['train_anno']) + data['test_label'] = self._generate_label_function(data['test_anno']) + if self.label_density_params is not None: + data['train_label_density'] = self._generate_label_density(data['train_anno']) + data['test_label_density'] = self._generate_label_density(data['test_anno']) + + return data diff --git a/ltr/data/processing_utils.py b/ltr/data/processing_utils.py new file mode 100755 index 0000000..50765f7 --- /dev/null +++ b/ltr/data/processing_utils.py @@ -0,0 +1,627 @@ +import torch +import math +import cv2 as cv +import random +import torch.nn.functional as F +from .bounding_box_utils import rect_to_rel, rel_to_rect + + +def sample_target(im, target_bb, search_area_factor, output_sz=None, mask=None): + """ Extracts a square crop centered at target_bb box, of area search_area_factor^2 times target_bb area + + args: + im - cv image + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + + returns: + cv image - extracted crop + float - the factor by which the crop has been resized to make the crop size equal output_size + """ + x, y, w, h = target_bb.tolist() + + # Crop image + crop_sz = math.ceil(math.sqrt(w * h) * search_area_factor) + + if crop_sz < 1: + raise Exception('Too small bounding box.') + + x1 = round(x + 0.5 * w - crop_sz * 0.5) + x2 = x1 + crop_sz + + y1 = round(y + 0.5 * h - crop_sz * 0.5) + y2 = y1 + crop_sz + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + if output_sz is not None: + resize_factor = output_sz / crop_sz + im_crop_padded = cv.resize(im_crop_padded, (output_sz, output_sz)) + + if mask is None: + return im_crop_padded, resize_factor + mask_crop_padded = \ + F.interpolate(mask_crop_padded[None, None], (output_sz, output_sz), mode='bilinear', align_corners=False)[0, 0] + return im_crop_padded, resize_factor, mask_crop_padded + + else: + if mask is None: + return im_crop_padded, 1.0 + return im_crop_padded, 1.0, mask_crop_padded + + +def transform_image_to_crop(box_in: torch.Tensor, box_extract: torch.Tensor, resize_factor: float, + crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box_in - the box for which the co-ordinates are to be transformed + box_extract - the box about which the image crop has been extracted. + resize_factor - the ratio between the original image scale and the scale of the image crop + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + box_extract_center = box_extract[0:2] + 0.5 * box_extract[2:4] + + box_in_center = box_in[0:2] + 0.5 * box_in[2:4] + + box_out_center = (crop_sz - 1) / 2 + (box_in_center - box_extract_center) * resize_factor + box_out_wh = box_in[2:4] * resize_factor + + box_out = torch.cat((box_out_center - 0.5 * box_out_wh, box_out_wh)) + return box_out + + +def jittered_center_crop(frames, box_extract, box_gt, search_area_factor, output_sz, masks=None): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. The extracted crops are then resized to output_sz. Further, the co-ordinates of the box + box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if masks is None: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz) + for f, a in zip(frames, box_extract)] + frames_crop, resize_factors = zip(*crops_resize_factors) + masks_crop = None + else: + crops_resize_factors = [sample_target(f, a, search_area_factor, output_sz, m) + for f, a, m in zip(frames, box_extract, masks)] + frames_crop, resize_factors, masks_crop = zip(*crops_resize_factors) + + crop_sz = torch.Tensor([output_sz, output_sz]) + + # find the bb location in the crop + box_crop = [transform_image_to_crop(a_gt, a_ex, rf, crop_sz) + for a_gt, a_ex, rf in zip(box_gt, box_extract, resize_factors)] + + return frames_crop, box_crop, masks_crop + + +def sample_target_adaptive(im, target_bb, search_area_factor, output_sz, mode: str = 'replicate', + max_scale_change=None, mask=None): + """ Extracts a crop centered at target_bb box, of area search_area_factor^2. If the crop area contains regions + outside the image, it is shifted so that the it is inside the image. Further, if the crop area exceeds the image + size, a smaller crop which fits the image is returned instead. + + args: + im - Input numpy image to crop. + target_bb - target box [x, y, w, h] + search_area_factor - Ratio of crop size to target size + output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done. + mode - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + mask - Optional mask to apply the same crop. + + returns: + numpy image - Extracted crop. + torch.Tensor - A bounding box denoting the cropped region in the image. + numpy mask - Cropped mask returned only if mask is not None. + """ + + if max_scale_change is None: + max_scale_change = float('inf') + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + output_sz = torch.Tensor(output_sz) + + im_h = im.shape[0] + im_w = im.shape[1] + + bbx, bby, bbw, bbh = target_bb.tolist() + + # Crop image + crop_sz_x, crop_sz_y = (output_sz * ( + target_bb[2:].prod() / output_sz.prod()).sqrt() * search_area_factor).ceil().long().tolist() + + # Get new sample size if forced inside the image + if mode == 'inside' or mode == 'inside_major': + # Calculate rescaling factor if outside the image + rescale_factor = [crop_sz_x / im_w, crop_sz_y / im_h] + if mode == 'inside': + rescale_factor = max(rescale_factor) + elif mode == 'inside_major': + rescale_factor = min(rescale_factor) + rescale_factor = min(max(1, rescale_factor), max_scale_change) + + crop_sz_x = math.floor(crop_sz_x / rescale_factor) + crop_sz_y = math.floor(crop_sz_y / rescale_factor) + + if crop_sz_x < 1 or crop_sz_y < 1: + raise Exception('Too small bounding box.') + + x1 = round(bbx + 0.5 * bbw - crop_sz_x * 0.5) + x2 = x1 + crop_sz_x + + y1 = round(bby + 0.5 * bbh - crop_sz_y * 0.5) + y2 = y1 + crop_sz_y + + # Move box inside image + shift_x = max(0, -x1) + min(0, im_w - x2) + x1 += shift_x + x2 += shift_x + + shift_y = max(0, -y1) + min(0, im_h - y2) + y1 += shift_y + y2 += shift_y + + out_x = (max(0, -x1) + max(0, x2 - im_w)) // 2 + out_y = (max(0, -y1) + max(0, y2 - im_h)) // 2 + shift_x = (-x1 - out_x) * (out_x > 0) + shift_y = (-y1 - out_y) * (out_y > 0) + + x1 += shift_x + x2 += shift_x + y1 += shift_y + y2 += shift_y + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + # Resize image + im_out = cv.resize(im_crop_padded, tuple(output_sz.long().tolist())) + + if mask is not None: + mask_out = \ + F.interpolate(mask_crop_padded[None, None], tuple(output_sz.flip(0).long().tolist()), mode='nearest')[0, 0] + + crop_box = torch.Tensor([x1, y1, x2 - x1, y2 - y1]) + + if mask is None: + return im_out, crop_box + else: + return im_out, crop_box, mask_out + + +def crop_and_resize(im, box, crop_bb, output_sz, mask=None): + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + + im_h = im.shape[0] + im_w = im.shape[1] + + if crop_bb[2] < 1 or crop_bb[3] < 1: + raise Exception('Too small bounding box.') + + x1 = crop_bb[0] + x2 = crop_bb[0] + crop_bb[2] + + y1 = crop_bb[1] + y2 = crop_bb[1] + crop_bb[3] + + x1_pad = max(0, -x1) + x2_pad = max(x2 - im.shape[1] + 1, 0) + + y1_pad = max(0, -y1) + y2_pad = max(y2 - im.shape[0] + 1, 0) + + # Crop target + im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] + + if mask is not None: + mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad] + + # Pad + im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_REPLICATE) + + if mask is not None: + mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0) + + # Resize image + im_out = cv.resize(im_crop_padded, output_sz) + + if mask is not None: + mask_out = F.interpolate(mask_crop_padded[None, None], (output_sz[1], output_sz[0]), mode='nearest')[0, 0] + + rescale_factor = output_sz[0] / crop_bb[2] + + # Hack + if box is not None: + box_crop = box.clone() + box_crop[0] -= crop_bb[0] + box_crop[1] -= crop_bb[1] + + box_crop *= rescale_factor + else: + box_crop = None + + if mask is None: + return im_out, box_crop + else: + return im_out, box_crop, mask_out + + +def transform_box_to_crop(box: torch.Tensor, crop_box: torch.Tensor, crop_sz: torch.Tensor) -> torch.Tensor: + """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image + args: + box - the box for which the co-ordinates are to be transformed + crop_box - bounding box defining the crop in the original image + crop_sz - size of the cropped image + + returns: + torch.Tensor - transformed co-ordinates of box_in + """ + + box_out = box.clone() + box_out[:2] -= crop_box[:2] + + scale_factor = crop_sz / crop_box[2:] + + box_out[:2] *= scale_factor + box_out[2:] *= scale_factor + return box_out + + +def target_image_crop(frames, box_extract, box_gt, search_area_factor, output_sz, mode: str = 'replicate', + max_scale_change=None, masks=None): + """ For each frame in frames, extracts a square crop centered at box_extract, of area search_area_factor^2 + times box_extract area. If the crop area contains regions outside the image, it is shifted / shrunk so that it + completely fits inside the image. The extracted crops are then resized to output_sz. Further, the co-ordinates of + the box box_gt are transformed to the image crop co-ordinates + + args: + frames - list of frames + box_extract - list of boxes of same length as frames. The crops are extracted using anno_extract + box_gt - list of boxes of same length as frames. The co-ordinates of these boxes are transformed from + image co-ordinates to the crop co-ordinates + search_area_factor - The area of the extracted crop is search_area_factor^2 times box_extract area + output_sz - The size to which the extracted crops are resized + mode - If 'replicate', the boundary pixels are replicated in case the search region crop goes out of image. + If 'inside', the search region crop is shifted/shrunk to fit completely inside the image. + If 'inside_major', the search region crop is shifted/shrunk to fit completely inside one axis of the image. + max_scale_change - Maximum allowed scale change when performing the crop (only applicable for 'inside' and 'inside_major') + masks - Optional masks to apply the same crop. + + returns: + list - list of image crops + list - box_gt location in the crop co-ordinates + """ + + if isinstance(output_sz, (float, int)): + output_sz = (output_sz, output_sz) + + if masks is None: + frame_crops_boxes = [sample_target_adaptive(f, a, search_area_factor, output_sz, mode, max_scale_change) + for f, a in zip(frames, box_extract)] + + frames_crop, crop_boxes = zip(*frame_crops_boxes) + else: + frame_crops_boxes_masks = [ + sample_target_adaptive(f, a, search_area_factor, output_sz, mode, max_scale_change, mask=m) + for f, a, m in zip(frames, box_extract, masks)] + + frames_crop, crop_boxes, masks_crop = zip(*frame_crops_boxes_masks) + + crop_sz = torch.Tensor(output_sz) + + # find the bb location in the crop + box_crop = [transform_box_to_crop(bb_gt, crop_bb, crop_sz) + for bb_gt, crop_bb in zip(box_gt, crop_boxes)] + + if masks is None: + return frames_crop, box_crop + else: + return frames_crop, box_crop, masks_crop + + +def iou(reference, proposals): + """Compute the IoU between a reference box with multiple proposal boxes. + + args: + reference - Tensor of shape (1, 4). + proposals - Tensor of shape (num_proposals, 4) + + returns: + torch.Tensor - Tensor of shape (num_proposals,) containing IoU of reference box with each proposal box. + """ + + # Intersection box + tl = torch.max(reference[:, :2], proposals[:, :2]) + br = torch.min(reference[:, :2] + reference[:, 2:], proposals[:, :2] + proposals[:, 2:]) + sz = (br - tl).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = reference[:, 2:].prod(dim=1) + proposals[:, 2:].prod(dim=1) - intersection + + return intersection / union + + +def rand_uniform(a, b, shape=1): + """ sample numbers uniformly between a and b. + args: + a - lower bound + b - upper bound + shape - shape of the output tensor + + returns: + torch.Tensor - tensor of shape=shape + """ + return (b - a) * torch.rand(shape) + a + + +def perturb_box(box, min_iou=0.5, sigma_factor=0.1): + """ Perturb the input box by adding gaussian noise to the co-ordinates + + args: + box - input box + min_iou - minimum IoU overlap between input box and the perturbed box + sigma_factor - amount of perturbation, relative to the box size. Can be either a single element, or a list of + sigma_factors, in which case one of them will be uniformly sampled. Further, each of the + sigma_factor element can be either a float, or a tensor + of shape (4,) specifying the sigma_factor per co-ordinate + + returns: + torch.Tensor - the perturbed box + """ + + if isinstance(sigma_factor, list): + # If list, sample one sigma_factor as current sigma factor + c_sigma_factor = random.choice(sigma_factor) + else: + c_sigma_factor = sigma_factor + + if not isinstance(c_sigma_factor, torch.Tensor): + c_sigma_factor = c_sigma_factor * torch.ones(4) + + perturb_factor = torch.sqrt(box[2] * box[3]) * c_sigma_factor + + # multiple tries to ensure that the perturbed box has iou > min_iou with the input box + for i_ in range(100): + c_x = box[0] + 0.5 * box[2] + c_y = box[1] + 0.5 * box[3] + c_x_per = random.gauss(c_x, perturb_factor[0]) + c_y_per = random.gauss(c_y, perturb_factor[1]) + + w_per = random.gauss(box[2], perturb_factor[2]) + h_per = random.gauss(box[3], perturb_factor[3]) + + if w_per <= 1: + w_per = box[2] * rand_uniform(0.15, 0.5) + + if h_per <= 1: + h_per = box[3] * rand_uniform(0.15, 0.5) + + box_per = torch.Tensor([c_x_per - 0.5 * w_per, c_y_per - 0.5 * h_per, w_per, h_per]).round() + + if box_per[2] <= 1: + box_per[2] = box[2] * rand_uniform(0.15, 0.5) + + if box_per[3] <= 1: + box_per[3] = box[3] * rand_uniform(0.15, 0.5) + + box_iou = iou(box.view(1, 4), box_per.view(1, 4)) + + # if there is sufficient overlap, return + if box_iou > min_iou: + return box_per, box_iou + + # else reduce the perturb factor + perturb_factor *= 0.9 + + return box_per, box_iou + + +def gauss_1d(sz, sigma, center, end_pad=0, density=False): + k = torch.arange(-(sz - 1) / 2, (sz + 1) / 2 + end_pad).reshape(1, -1) + gauss = torch.exp(-1.0 / (2 * sigma ** 2) * (k - center.reshape(-1, 1)) ** 2) + if density: + gauss /= math.sqrt(2 * math.pi) * sigma + return gauss + + +def gauss_2d(sz, sigma, center, end_pad=(0, 0), density=False): + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + return gauss_1d(sz[0].item(), sigma[0], center[:, 0], end_pad[0], density).reshape(center.shape[0], 1, -1) * \ + gauss_1d(sz[1].item(), sigma[1], center[:, 1], end_pad[1], density).reshape(center.shape[0], -1, 1) + + +def gaussian_label_function(target_bb, sigma_factor, kernel_sz, feat_sz, image_sz, end_pad_if_even=True, density=False, + uni_bias=0): + """Construct Gaussian label function.""" + + if isinstance(kernel_sz, (float, int)): + kernel_sz = (kernel_sz, kernel_sz) + if isinstance(feat_sz, (float, int)): + feat_sz = (feat_sz, feat_sz) + if isinstance(image_sz, (float, int)): + image_sz = (image_sz, image_sz) + + image_sz = torch.Tensor(image_sz) + feat_sz = torch.Tensor(feat_sz) + + target_center = target_bb[:, 0:2] + 0.5 * target_bb[:, 2:4] + target_center_norm = (target_center - image_sz / 2) / image_sz + + center = feat_sz * target_center_norm + 0.5 * \ + torch.Tensor([(kernel_sz[0] + 1) % 2, (kernel_sz[1] + 1) % 2]) + + sigma = sigma_factor * feat_sz.prod().sqrt().item() + + if end_pad_if_even: + end_pad = (int(kernel_sz[0] % 2 == 0), int(kernel_sz[1] % 2 == 0)) + else: + end_pad = (0, 0) + + gauss_label = gauss_2d(feat_sz, sigma, center, end_pad, density=density) + if density: + sz = (feat_sz + torch.Tensor(end_pad)).prod() + label = (1.0 - uni_bias) * gauss_label + uni_bias / sz + else: + label = gauss_label + uni_bias + return label + + +def gauss_density_centered(x, std): + """Evaluate the probability density of a Gaussian centered at zero. + args: + x - Samples. + std - List of standard deviations + """ + return torch.exp(-0.5 * (x / std) ** 2) / (math.sqrt(2 * math.pi) * std) + + +def gmm_density_centered(x, std): + """Evaluate the probability density of a GMM centered at zero. + args: + x - Samples. Assumes dim=-1 is the component dimension and dim=-2 is feature dimension. Rest are sample dimension. + std - Tensor of standard deviations + """ + if x.dim() == std.dim() - 1: + x = x.unsqueeze(-1) + elif not (x.dim() == std.dim() and x.shape[-1] == 1): + raise ValueError('Last dimension must be the gmm stds.') + return gauss_density_centered(x, std).prod(-2).mean(-1) + + +def sample_gmm_centered(std, num_samples=1): + """Sample from a GMM distribution centered at zero: + args: + std - Tensor of standard deviations + num_samples - number of samples + """ + num_components = std.shape[-1] + num_dims = std.numel() // num_components + + std = std.view(1, num_dims, num_components) + + # Sample component ids + k = torch.randint(num_components, (num_samples,), dtype=torch.int64) + std_samp = std[0, :, k].t() + + # Sample + x_centered = std_samp * torch.randn(num_samples, num_dims) + prob_dens = gmm_density_centered(x_centered, std) + + return x_centered, prob_dens + + +def sample_gmm(mean, std, num_samples=1): + """Sample from a GMM distribution: + args: + mean - a single mean vector + std - Tensor of standard deviations + num_samples - number of samples + """ + num_dims = mean.numel() + num_components = std.shape[-1] + + mean = mean.view(1, num_dims) + std = std.view(1, -1, num_components) + + # Sample component ids + k = torch.randint(num_components, (num_samples,), dtype=torch.int64) + std_samp = std[0, :, k].t() + + # Sample + x_centered = std_samp * torch.randn(num_samples, num_dims) + x = x_centered + mean + prob_dens = gmm_density_centered(x_centered, std) + + return x, prob_dens + + +def sample_box_gmm(mean_box, proposal_sigma, gt_sigma=None, num_samples=1, add_mean_box=False): + """Sample boxes from a Gaussian mixture model. + args: + mean_box - Center (or mean) bounding box + proposal_sigma - List of standard deviations for each Gaussian + gt_sigma - Standard deviation of the ground truth distribution + num_samples - Number of sampled boxes + add_mean_box - Also add mean box as first element + + returns: + proposals, proposal density and ground truth density for all samples + """ + center_std = torch.Tensor([s[0] for s in proposal_sigma]) + sz_std = torch.Tensor([s[1] for s in proposal_sigma]) + std = torch.stack([center_std, center_std, sz_std, sz_std]) + + mean_box = mean_box.view(1, 4) + sz_norm = mean_box[:, 2:].clone() + + # Sample boxes + proposals_rel_centered, proposal_density = sample_gmm_centered(std, num_samples) + + # Add mean and map back + mean_box_rel = rect_to_rel(mean_box, sz_norm) + proposals_rel = proposals_rel_centered + mean_box_rel + proposals = rel_to_rect(proposals_rel, sz_norm) + + if gt_sigma is None or gt_sigma[0] == 0 and gt_sigma[1] == 0: + gt_density = torch.zeros_like(proposal_density) + else: + std_gt = torch.Tensor([gt_sigma[0], gt_sigma[0], gt_sigma[1], gt_sigma[1]]).view(1, 4) + gt_density = gauss_density_centered(proposals_rel_centered, std_gt).prod(-1) + + if add_mean_box: + proposals = torch.cat((mean_box, proposals)) + proposal_density = torch.cat((torch.Tensor([-1]), proposal_density)) + gt_density = torch.cat((torch.Tensor([1]), gt_density)) + + return proposals, proposal_density, gt_density \ No newline at end of file diff --git a/ltr/data/sampler.py b/ltr/data/sampler.py new file mode 100755 index 0000000..d041bc4 --- /dev/null +++ b/ltr/data/sampler.py @@ -0,0 +1,189 @@ +import random +import torch.utils.data +from pytracking import TensorDict + + +def no_processing(data): + return data + + +class TrackingSampler(torch.utils.data.Dataset): + """ Class responsible for sampling frames from training sequences to form batches. Each training sample is a + tuple consisting of i) a set of train frames, used to learn the DiMP classification model and obtain the + modulation vector for IoU-Net, and ii) a set of test frames on which target classification loss for the predicted + DiMP model, and the IoU prediction loss for the IoU-Net is calculated. + + The sampling is done in the following ways. First a dataset is selected at random. Next, a sequence is selected + from that dataset. A base frame is then sampled randomly from the sequence. Next, a set of 'train frames' and + 'test frames' are sampled from the sequence from the range [base_frame_id - max_gap, base_frame_id] and + (base_frame_id, base_frame_id + max_gap] respectively. Only the frames in which the target is visible are sampled. + If enough visible frames are not found, the 'max_gap' is increased gradually till enough frames are found. + + The sampled frames are then passed through the input 'processing' function for the necessary processing- + """ + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames, num_train_frames=1, processing=no_processing, frame_sample_mode='causal'): + """ + args: + datasets - List of datasets to be used for training + p_datasets - List containing the probabilities by which each dataset will be sampled + samples_per_epoch - Number of training samples per epoch + max_gap - Maximum gap, in frame numbers, between the train frames and the test frames. + num_test_frames - Number of test frames to sample. + num_train_frames - Number of train frames to sample. + processing - An instance of Processing class which performs the necessary processing of the data. + frame_sample_mode - Either 'causal' or 'interval'. If 'causal', then the test frames are sampled in a causally, + otherwise randomly within the interval. + """ + self.datasets = datasets + + # If p not provided, sample uniformly from all videos + if p_datasets is None: + p_datasets = [len(d) for d in self.datasets] + + # Normalize + p_total = sum(p_datasets) + self.p_datasets = [x / p_total for x in p_datasets] + + self.samples_per_epoch = samples_per_epoch + self.max_gap = max_gap + self.num_test_frames = num_test_frames + self.num_train_frames = num_train_frames + self.processing = processing + self.frame_sample_mode = frame_sample_mode + + def __len__(self): + return self.samples_per_epoch + + def _sample_visible_ids(self, visible, num_ids=1, min_id=None, max_id=None): + """ Samples num_ids frames between min_id and max_id for which target is visible + + args: + visible - 1d Tensor indicating whether target is visible for each frame + num_ids - number of frames to be samples + min_id - Minimum allowed frame number + max_id - Maximum allowed frame number + + returns: + list - List of sampled frame numbers. None if not sufficient visible frames could be found. + """ + if num_ids == 0: + return [] + if min_id is None or min_id < 0: + min_id = 0 + if max_id is None or max_id > len(visible): + max_id = len(visible) + + valid_ids = [i for i in range(min_id, max_id) if visible[i]] + + # No visible ids + if len(valid_ids) == 0: + return None + + return random.choices(valid_ids, k=num_ids) + + def __getitem__(self, index): + """ + args: + index (int): Index (Ignored since we sample randomly) + + returns: + TensorDict - dict containing all the data blocks + """ + + # Select a dataset + dataset = random.choices(self.datasets, self.p_datasets)[0] + is_video_dataset = dataset.is_video_sequence() + + # Sample a sequence with enough visible frames + enough_visible_frames = False + while not enough_visible_frames: + # Sample a sequence + seq_id = random.randint(0, dataset.get_num_sequences() - 1) + + # Sample frames + seq_info_dict = dataset.get_sequence_info(seq_id) + visible = seq_info_dict['visible'] + + enough_visible_frames = visible.type(torch.int64).sum().item() > 2 * ( + self.num_test_frames + self.num_train_frames) and len(visible) >= 20 + + enough_visible_frames = enough_visible_frames or not is_video_dataset + + if is_video_dataset: + train_frame_ids = None + test_frame_ids = None + gap_increase = 0 + + if self.frame_sample_mode == 'interval': + # Sample frame numbers within interval defined by the first frame + while test_frame_ids is None: + base_frame_id = self._sample_visible_ids(visible, num_ids=1) + extra_train_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_train_frames - 1, + min_id=base_frame_id[ + 0] - self.max_gap - gap_increase, + max_id=base_frame_id[ + 0] + self.max_gap + gap_increase) + if extra_train_frame_ids is None: + gap_increase += 5 + continue + train_frame_ids = base_frame_id + extra_train_frame_ids + test_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_test_frames, + min_id=train_frame_ids[0] - self.max_gap - gap_increase, + max_id=train_frame_ids[0] + self.max_gap + gap_increase) + gap_increase += 5 # Increase gap until a frame is found + + elif self.frame_sample_mode == 'causal': + # Sample test and train frames in a causal manner, i.e. test_frame_ids > train_frame_ids + while test_frame_ids is None: + base_frame_id = self._sample_visible_ids(visible, num_ids=1, min_id=self.num_train_frames - 1, + max_id=len(visible) - self.num_test_frames) + prev_frame_ids = self._sample_visible_ids(visible, num_ids=self.num_train_frames - 1, + min_id=base_frame_id[0] - self.max_gap - gap_increase, + max_id=base_frame_id[0]) + if prev_frame_ids is None: + gap_increase += 5 + continue + train_frame_ids = base_frame_id + prev_frame_ids + test_frame_ids = self._sample_visible_ids(visible, min_id=train_frame_ids[0] + 1, + max_id=train_frame_ids[0] + self.max_gap + gap_increase, + num_ids=self.num_test_frames) + # Increase gap until a frame is found + gap_increase += 5 + else: + # In case of image dataset, just repeat the image to generate synthetic video + train_frame_ids = [1] * self.num_train_frames + test_frame_ids = [1] * self.num_test_frames + + train_frames, train_anno, meta_obj_train = dataset.get_frames(seq_id, train_frame_ids, seq_info_dict) + test_frames, test_anno, meta_obj_test = dataset.get_frames(seq_id, test_frame_ids, seq_info_dict) + + data = TensorDict({'train_images': train_frames, + 'train_anno': train_anno['bbox'], + 'test_images': test_frames, + 'test_anno': test_anno['bbox'], + 'dataset': dataset.get_name(), + 'test_class': meta_obj_test.get('object_class_name')}) + + return self.processing(data) + + +class DiMPSampler(TrackingSampler): + """ See TrackingSampler.""" + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames, num_train_frames=1, processing=no_processing, frame_sample_mode='causal'): + super().__init__(datasets=datasets, p_datasets=p_datasets, samples_per_epoch=samples_per_epoch, max_gap=max_gap, + num_test_frames=num_test_frames, num_train_frames=num_train_frames, processing=processing, + frame_sample_mode=frame_sample_mode) + + +class ATOMSampler(TrackingSampler): + """ See TrackingSampler.""" + + def __init__(self, datasets, p_datasets, samples_per_epoch, max_gap, + num_test_frames=1, num_train_frames=1, processing=no_processing, frame_sample_mode='interval'): + super().__init__(datasets=datasets, p_datasets=p_datasets, samples_per_epoch=samples_per_epoch, max_gap=max_gap, + num_test_frames=num_test_frames, num_train_frames=num_train_frames, processing=processing, + frame_sample_mode=frame_sample_mode) \ No newline at end of file diff --git a/ltr/data/transforms.py b/ltr/data/transforms.py new file mode 100755 index 0000000..958c779 --- /dev/null +++ b/ltr/data/transforms.py @@ -0,0 +1,440 @@ +import random +import numpy as np +import math +import cv2 as cv +import torch +import torch.nn.functional as F +import torchvision.transforms.functional as tvisf + + +class Transform: + """A set of transformations, used for e.g. data augmentation. + Args of constructor: + transforms: An arbitrary number of transformations, derived from the TransformBase class. + They are applied in the order they are given. + + The Transform object can jointly transform images, bounding boxes and segmentation masks. + This is done by calling the object with the following key-word arguments (all are optional). + + The following arguments are inputs to be transformed. They are either supplied as a single instance, or a list of instances. + image - Image + coords - 2xN dimensional Tensor of 2D image coordinates [y, x] + bbox - Bounding box on the form [x, y, w, h] + mask - Segmentation mask with discrete classes + + The following parameters can be supplied with calling the transform object: + joint [Bool] - If True then transform all images/coords/bbox/mask in the list jointly using the same transformation. + Otherwise each tuple (images, coords, bbox, mask) will be transformed independently using + different random rolls. Default: True. + new_roll [Bool] - If False, then no new random roll is performed, and the saved result from the previous roll + is used instead. Default: True. + + Check the DiMPProcessing class for examples. + """ + + def __init__(self, *transforms): + if len(transforms) == 1 and isinstance(transforms[0], (list, tuple)): + transforms = transforms[0] + self.transforms = transforms + self._valid_inputs = ['image', 'coords', 'bbox', 'mask'] + self._valid_args = ['joint', 'new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + + def __call__(self, **inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + for v in inputs.keys(): + if v not in self._valid_all: + raise ValueError('Incorrect input \"{}\" to transform. Only supports inputs {} and arguments {}.'.format(v, self._valid_inputs, self._valid_args)) + + joint_mode = inputs.get('joint', True) + new_roll = inputs.get('new_roll', True) + + if not joint_mode: + out = zip(*[self(**inp) for inp in self._split_inputs(inputs)]) + return tuple(list(o) for o in out) + + out = {k: v for k, v in inputs.items() if k in self._valid_inputs} + + for t in self.transforms: + out = t(**out, joint=joint_mode, new_roll=new_roll) + if len(var_names) == 1: + return out[var_names[0]] + # Make sure order is correct + return tuple(out[v] for v in var_names) + + def _split_inputs(self, inputs): + var_names = [k for k in inputs.keys() if k in self._valid_inputs] + split_inputs = [{k: v for k, v in zip(var_names, vals)} for vals in zip(*[inputs[vn] for vn in var_names])] + for arg_name, arg_val in filter(lambda it: it[0]!='joint' and it[0] in self._valid_args, inputs.items()): + if isinstance(arg_val, list): + for inp, av in zip(split_inputs, arg_val): + inp[arg_name] = av + else: + for inp in split_inputs: + inp[arg_name] = arg_val + return split_inputs + + def __repr__(self): + format_string = self.__class__.__name__ + '(' + for t in self.transforms: + format_string += '\n' + format_string += ' {0}'.format(t) + format_string += '\n)' + return format_string + + +class TransformBase: + """Base class for transformation objects. See the Transform class for details.""" + def __init__(self): + self._valid_inputs = ['image', 'coords', 'bbox', 'mask'] + self._valid_args = ['new_roll'] + self._valid_all = self._valid_inputs + self._valid_args + self._rand_params = None + + def __call__(self, **inputs): + # Split input + input_vars = {k: v for k, v in inputs.items() if k in self._valid_inputs} + input_args = {k: v for k, v in inputs.items() if k in self._valid_args} + + # Roll random parameters for the transform + if input_args.get('new_roll', True): + rand_params = self.roll() + if rand_params is None: + rand_params = () + elif not isinstance(rand_params, tuple): + rand_params = (rand_params,) + self._rand_params = rand_params + + outputs = dict() + for var_name, var in input_vars.items(): + if var is not None: + transform_func = getattr(self, 'transform_' + var_name) + if var_name in ['coords', 'bbox']: + params = (self._get_image_size(input_vars),) + self._rand_params + else: + params = self._rand_params + if isinstance(var, (list, tuple)): + outputs[var_name] = [transform_func(x, *params) for x in var] + else: + outputs[var_name] = transform_func(var, *params) + return outputs + + def _get_image_size(self, inputs): + im = None + for var_name in ['image', 'mask']: + if inputs.get(var_name) is not None: + im = inputs[var_name] + break + if im is None: + return None + if isinstance(im, (list, tuple)): + im = im[0] + if isinstance(im, np.ndarray): + return im.shape[:2] + if torch.is_tensor(im): + return (im.shape[-2], im.shape[-1]) + raise Exception('Unknown image type') + + def roll(self): + return None + + def transform_image(self, image, *rand_params): + """Must be deterministic""" + return image + + def transform_coords(self, coords, image_shape, *rand_params): + """Must be deterministic""" + return coords + + def transform_bbox(self, bbox, image_shape, *rand_params): + """Assumes [x, y, w, h]""" + # Check if not overloaded + if self.transform_coords.__code__ == TransformBase.transform_coords.__code__: + return bbox + + coord = bbox.clone().view(-1,2).t().flip(0) + + x1 = coord[1, 0] + x2 = coord[1, 0] + coord[1, 1] + + y1 = coord[0, 0] + y2 = coord[0, 0] + coord[0, 1] + + coord_all = torch.tensor([[y1, y1, y2, y2], [x1, x2, x2, x1]]) + + coord_transf = self.transform_coords(coord_all, image_shape, *rand_params).flip(0) + tl = torch.min(coord_transf, dim=1)[0] + sz = torch.max(coord_transf, dim=1)[0] - tl + bbox_out = torch.cat((tl, sz), dim=-1).reshape(bbox.shape) + return bbox_out + + def transform_mask(self, mask, *rand_params): + """Must be deterministic""" + return mask + + +class ToTensor(TransformBase): + """Convert to a Tensor""" + + def transform_image(self, image): + # handle numpy array + if image.ndim == 2: + image = image[:, :, None] + + image = torch.from_numpy(image.transpose((2, 0, 1))) + # backward compatibility + if isinstance(image, torch.ByteTensor): + return image.float().div(255) + else: + return image + + def transfrom_mask(self, mask): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + + + +class ToTensorAndJitter(TransformBase): + """Convert to a Tensor and jitter brightness""" + def __init__(self, brightness_jitter=0.0, normalize=True): + super().__init__() + self.brightness_jitter = brightness_jitter + self.normalize = normalize + + def roll(self): + return np.random.uniform(max(0, 1 - self.brightness_jitter), 1 + self.brightness_jitter) + + def transform_image(self, image, brightness_factor): + # handle numpy array + image = torch.from_numpy(image.transpose((2, 0, 1))) + + # backward compatibility + if self.normalize: + return image.float().mul(brightness_factor/255.0).clamp(0.0, 1.0) + else: + return image.float().mul(brightness_factor).clamp(0.0, 255.0) + + def transform_mask(self, mask, brightness_factor): + if isinstance(mask, np.ndarray): + return torch.from_numpy(mask) + else: + return mask + + +class Normalize(TransformBase): + """Normalize image""" + def __init__(self, mean, std, inplace=False): + super().__init__() + self.mean = mean + self.std = std + self.inplace = inplace + + def transform_image(self, image): + return tvisf.normalize(image, self.mean, self.std, self.inplace) + + +class ToGrayscale(TransformBase): + """Converts image to grayscale with probability""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + self.color_weights = np.array([0.2989, 0.5870, 0.1140], dtype=np.float32) + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_grayscale): + if do_grayscale: + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) + return np.stack([img_gray, img_gray, img_gray], axis=2) + # return np.repeat(np.sum(img * self.color_weights, axis=2, keepdims=True).astype(np.uint8), 3, axis=2) + return image + + +class ToBGR(TransformBase): + """Converts image to BGR""" + def transform_image(self, image): + if torch.is_tensor(image): + raise NotImplementedError('Implement torch variant.') + img_bgr = cv.cvtColor(image, cv.COLOR_RGB2BGR) + return img_bgr + + +class RandomHorizontalFlip(TransformBase): + """Horizontally flip image randomly with a probability p.""" + def __init__(self, probability = 0.5): + super().__init__() + self.probability = probability + + def roll(self): + return random.random() < self.probability + + def transform_image(self, image, do_flip): + if do_flip: + if torch.is_tensor(image): + return image.flip((2,)) + return np.fliplr(image).copy() + return image + + def transform_coords(self, coords, image_shape, do_flip): + if do_flip: + coords = coords.clone() + coords[1,:] = (image_shape[1] - 1) - coords[1,:] + return coords + + def transform_mask(self, mask, do_flip): + if do_flip: + if torch.is_tensor(mask): + return mask.flip((-1,)) + return np.fliplr(mask).copy() + return mask + + +class Blur(TransformBase): + """ Blur the image by applying a gaussian kernel with given sigma""" + def __init__(self, sigma): + super().__init__() + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def transform_image(self, image): + if torch.is_tensor(image): + sz = image.shape[2:] + im1 = F.conv2d(image.view(-1, 1, sz[0], sz[1]), self.filter[0], padding=(self.filter_size[0], 0)) + return F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(-1,sz[0],sz[1]) + else: + raise NotImplementedError + + +class RandomBlur(TransformBase): + """ Blur the image, with a given probability, by applying a gaussian kernel with given sigma""" + def __init__(self, sigma, probability=0.1): + super().__init__() + self.probability = probability + + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def roll(self): + return random.random() < self.probability + + def transform(self, image, do_blur=None): + if do_blur is None: + do_blur = False + + if do_blur: + if torch.is_tensor(image): + sz = image.shape[1:] + im1 = F.conv2d(image.view(-1, 1, sz[0], sz[1]), self.filter[0], padding=(self.filter_size[0], 0)) + return F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(-1,sz[0],sz[1]) + else: + raise NotImplementedError + else: + return image + + +class RandomAffine(TransformBase): + """Apply random affine transformation.""" + def __init__(self, p_flip=0.0, max_rotation=0.0, max_shear=0.0, max_scale=0.0, max_ar_factor=0.0, + border_mode='constant', pad_amount=0): + super().__init__() + self.p_flip = p_flip + self.max_rotation = max_rotation + self.max_shear = max_shear + self.max_scale = max_scale + self.max_ar_factor = max_ar_factor + + if border_mode == 'constant': + self.border_flag = cv.BORDER_CONSTANT + elif border_mode == 'replicate': + self.border_flag == cv.BORDER_REPLICATE + else: + raise Exception + + self.pad_amount = pad_amount + + def roll(self): + do_flip = random.random() < self.p_flip + theta = random.uniform(-self.max_rotation, self.max_rotation) + + shear_x = random.uniform(-self.max_shear, self.max_shear) + shear_y = random.uniform(-self.max_shear, self.max_shear) + + ar_factor = np.exp(random.uniform(-self.max_ar_factor, self.max_ar_factor)) + scale_factor = np.exp(random.uniform(-self.max_scale, self.max_scale)) + + return do_flip, theta, (shear_x, shear_y), (scale_factor, scale_factor * ar_factor) + + def _construct_t_mat(self, image_shape, do_flip, theta, shear_values, scale_factors): + im_h, im_w = image_shape + t_mat = np.identity(3) + + if do_flip: + if do_flip: + t_mat[0, 0] = -1.0 + t_mat[0, 2] = im_w + + t_rot = cv.getRotationMatrix2D((im_w * 0.5, im_h * 0.5), theta, 1.0) + t_rot = np.concatenate((t_rot, np.array([0.0, 0.0, 1.0]).reshape(1, 3))) + + t_shear = np.array([[1.0, shear_values[0], -shear_values[0] * 0.5 * im_w], + [shear_values[1], 1.0, -shear_values[1] * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_scale = np.array([[scale_factors[0], 0.0, (1.0 - scale_factors[0]) * 0.5 * im_w], + [0.0, scale_factors[1], (1.0 - scale_factors[1]) * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_mat = t_scale @ t_rot @ t_shear @ t_mat + + t_mat[0, 2] += self.pad_amount + t_mat[1, 2] += self.pad_amount + + t_mat = t_mat[:2, :] + + return t_mat + + def transform_image(self, image, do_flip, theta, shear_values, scale_factors): + if torch.is_tensor(image): + raise Exception('Only supported for numpy input') + + t_mat = self._construct_t_mat(image.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (image.shape[1] + 2*self.pad_amount, image.shape[0] + 2*self.pad_amount) + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_LINEAR, + borderMode=self.border_flag) + + return image_t + + def transform_coords(self, coords, image_shape, do_flip, theta, shear_values, scale_factors): + t_mat = self._construct_t_mat(image_shape, do_flip, theta, shear_values, scale_factors) + + t_mat_tensor = torch.from_numpy(t_mat).float() + + coords_xy1 = torch.stack((coords[1, :], coords[0, :], torch.ones_like(coords[1, :]))) + + coords_xy_t = torch.mm(t_mat_tensor, coords_xy1) + + return coords_xy_t[[1, 0], :] + + def transform_mask(self, mask, do_flip, theta, shear_values, scale_factors): + t_mat = self._construct_t_mat(mask.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (mask.shape[1] + 2*self.pad_amount, mask.shape[0] + 2*self.pad_amount) + + mask_t = cv.warpAffine(mask.numpy(), t_mat, output_sz, flags=cv.INTER_NEAREST, + borderMode=self.border_flag) + + return torch.from_numpy(mask_t) diff --git a/ltr/data_specs/got10k_train_split.txt b/ltr/data_specs/got10k_train_split.txt new file mode 100755 index 0000000..7dde8f7 --- /dev/null +++ b/ltr/data_specs/got10k_train_split.txt @@ -0,0 +1,7934 @@ +3784 +8998 +3906 +1631 +8277 +8358 +2338 +7938 +2988 +8302 +2662 +2663 +2825 +7447 +4781 +2218 +6348 +5860 +4517 +2819 +8075 +5391 +116 +3606 +7976 +7941 +1024 +4519 +1970 +557 +8579 +6908 +993 +7204 +1991 +3674 +8781 +6840 +5 +3225 +3763 +8688 +6778 +5777 +4794 +2744 +8126 +3864 +1733 +2923 +6829 +701 +683 +2081 +1831 +2404 +1459 +2741 +5972 +3618 +7462 +2654 +103 +2174 +6224 +2989 +2506 +2766 +5912 +2699 +3295 +3986 +609 +4895 +6673 +801 +1098 +1602 +2490 +3129 +8476 +3186 +7355 +4784 +4270 +1812 +4226 +2267 +8873 +6544 +6112 +2381 +4752 +753 +3776 +6511 +6016 +731 +2559 +7369 +5866 +563 +7731 +1105 +5603 +50 +4238 +2208 +8725 +4994 +4719 +1444 +8807 +7298 +8139 +8760 +8173 +2332 +4131 +5207 +1065 +8562 +3992 +4024 +2188 +9095 +6765 +1707 +6105 +6922 +5362 +1486 +7898 +4135 +6574 +1551 +998 +6565 +8127 +8927 +2544 +4365 +510 +768 +3535 +3875 +6808 +2931 +487 +1088 +4451 +368 +2470 +8111 +3493 +7338 +8281 +6390 +1271 +4373 +3667 +3494 +3757 +2966 +3756 +7840 +6315 +7827 +3300 +6261 +4163 +2217 +6549 +94 +7236 +9136 +1857 +6691 +3470 +6271 +807 +516 +9311 +6098 +3144 +8420 +5425 +5694 +2643 +6696 +6072 +7285 +3781 +903 +8522 +6092 +5979 +2622 +2529 +855 +3420 +3261 +8953 +7866 +2492 +3157 +359 +1520 +2642 +7452 +759 +36 +8931 +1744 +4350 +1089 +9199 +4295 +1889 +1908 +4868 +4498 +1968 +9103 +3273 +8723 +7413 +4114 +5584 +4874 +1427 +5211 +7618 +1542 +1353 +8158 +4168 +3200 +6345 +8560 +5619 +5953 +3158 +8849 +5831 +1411 +7294 +8103 +6539 +7397 +1006 +5450 +3119 +4274 +5352 +4571 +2319 +4217 +4976 +902 +1814 +2651 +3299 +3398 +982 +2428 +5793 +1346 +7057 +3737 +7329 +4449 +2110 +7405 +1773 +958 +3901 +4127 +8234 +2994 +7066 +1289 +2995 +5871 +3556 +9085 +846 +2366 +585 +7032 +5516 +5230 +3481 +2732 +6658 +7423 +1855 +6384 +3554 +5823 +4948 +7058 +4667 +5377 +2503 +7694 +9191 +9144 +655 +3409 +62 +8019 +8970 +5523 +7403 +3379 +2323 +4833 +5750 +3178 +6548 +8891 +7501 +3280 +7404 +343 +2171 +8397 +1367 +8611 +6118 +6603 +3729 +7182 +9048 +7733 +5642 +7141 +3335 +4845 +5449 +3467 +6250 +163 +5168 +2040 +5339 +3609 +8352 +3426 +8567 +769 +187 +6151 +6437 +7028 +8507 +3970 +9146 +2068 +5028 +7492 +1661 +2815 +2469 +2563 +3814 +8430 +4305 +3479 +5678 +9115 +4132 +1211 +5459 +4814 +545 +4556 +238 +4296 +2724 +1260 +2581 +6087 +4632 +4313 +380 +1209 +5447 +3032 +7942 +8943 +806 +2432 +6130 +4314 +2131 +9045 +6531 +5706 +6747 +7724 +2017 +3292 +5469 +2743 +424 +4233 +7643 +8619 +5192 +4516 +9324 +3537 +9152 +8058 +7526 +8711 +1949 +5982 +1732 +6702 +7027 +6388 +7012 +328 +2130 +452 +306 +7669 +3134 +5761 +3703 +44 +4189 +695 +7672 +5224 +9215 +5644 +3143 +3704 +5443 +2348 +7177 +2328 +4725 +354 +1418 +7810 +7746 +9002 +5759 +7226 +4535 +9160 +4385 +5397 +7249 +2936 +3204 +6287 +385 +2371 +2738 +3636 +9033 +2246 +2680 +6940 +4310 +2054 +9250 +9080 +4568 +5586 +4469 +2038 +3410 +7900 +4332 +6108 +678 +3319 +9079 +1054 +4048 +4751 +1320 +6890 +7931 +1398 +4349 +5299 +5025 +7932 +5738 +7787 +4590 +4020 +1274 +2488 +8497 +3372 +8965 +3219 +799 +3664 +6500 +7093 +4362 +6205 +4244 +4652 +1964 +5945 +6434 +2031 +2684 +6632 +4588 +8271 +3232 +5782 +2904 +6789 +5636 +7200 +3632 +5435 +8203 +3480 +4786 +7579 +3351 +1921 +798 +3646 +3094 +4359 +1654 +5975 +376 +5965 +780 +7821 +9224 +6738 +3185 +2133 +6248 +5996 +2834 +531 +5688 +2448 +7925 +7974 +5924 +6401 +5778 +6594 +5442 +8336 +4522 +3770 +6340 +6328 +4946 +4161 +2954 +2588 +8465 +2885 +1606 +5787 +3407 +3121 +7310 +1413 +1932 +4787 +2579 +3325 +508 +5610 +6480 +4290 +479 +3792 +6628 +2545 +6717 +6972 +2665 +6730 +3547 +6845 +5929 +3540 +4356 +8993 +1052 +2235 +8356 +3403 +8818 +8260 +572 +4159 +1180 +5348 +941 +7948 +2676 +3539 +4866 +6422 +8365 +3217 +1310 +2059 +9177 +1419 +2283 +8892 +8162 +1212 +6277 +3725 +7806 +6149 +7874 +718 +6888 +7118 +277 +656 +8763 +8289 +4759 +5854 +8659 +7710 +3145 +5981 +1881 +5799 +6947 +1609 +6396 +2631 +2887 +318 +2550 +6132 +1736 +2907 +7816 +48 +4304 +8133 +6698 +2760 +7779 +7732 +7642 +1154 +7242 +711 +9262 +539 +8033 +7440 +1913 +5480 +5570 +8594 +8772 +4654 +8974 +6128 +6183 +1071 +8449 +2142 +2298 +524 +1695 +820 +4053 +8241 +1856 +8641 +3981 +217 +1063 +9286 +3152 +221 +5461 +1270 +2006 +7164 +1199 +6951 +5604 +5400 +5309 +3498 +6407 +6661 +7097 +8165 +5169 +3852 +7070 +5702 +4344 +6648 +6904 +3272 +7119 +5795 +2365 +2659 +353 +5444 +6968 +2755 +1924 +2098 +2972 +6006 +5865 +8740 +2418 +3401 +7856 +5841 +598 +836 +1147 +931 +8897 +0 +6049 +1837 +865 +1871 +6116 +6831 +5773 +3587 +303 +1883 +2163 +3070 +1308 +7953 +6300 +6909 +853 +7301 +3279 +123 +7186 +3194 +5553 +5133 +1931 +4622 +6075 +4891 +5722 +5693 +8 +2339 +6596 +71 +379 +4506 +4370 +1238 +2707 +3344 +4254 +8767 +1726 +325 +4148 +5438 +5357 +548 +1332 +6824 +2290 +2335 +3146 +2594 +2315 +3389 +3885 +2621 +4116 +5389 +7412 +7222 +4894 +8595 +2000 +4978 +4721 +6444 +3796 +9321 +2236 +6409 +1523 +1468 +9249 +8270 +2341 +2874 +174 +4757 +4502 +4703 +9034 +9108 +5451 +2619 +5022 +9158 +490 +6540 +1466 +2962 +8771 +3036 +2712 +4539 +1581 +5638 +9246 +4308 +4363 +4647 +4470 +1636 +2511 +1311 +6560 +7519 +8027 +9217 +6464 +6364 +3779 +4822 +3563 +3982 +5896 +5510 +6655 +1524 +2846 +3137 +621 +141 +1887 +6567 +8921 +4671 +6052 +8445 +8699 +7349 +3553 +2117 +7651 +5034 +5383 +649 +3818 +9022 +8414 +1012 +8159 +5081 +8571 +4765 +9135 +4361 +4073 +9142 +727 +2835 +8229 +3989 +4490 +4923 +5477 +1638 +3643 +712 +9044 +2230 +499 +7166 +96 +3172 +8431 +8401 +1470 +6356 +8817 +927 +4212 +2152 +1795 +3812 +4949 +1219 +1538 +3029 +6481 +9042 +7775 +7742 +423 +2085 +7715 +4541 +9061 +5916 +3950 +7420 +4878 +7406 +7046 +7808 +4911 +8804 +6927 +8820 +3264 +300 +8670 +2979 +252 +4407 +3383 +4688 +8504 +6723 +26 +3837 +2489 +4137 +8209 +229 +6490 +2364 +9016 +1763 +1728 +338 +8335 +9063 +5280 +2791 +641 +5454 +4581 +5420 +4548 +2840 +8508 +3463 +7231 +7619 +2560 +1755 +6201 +165 +1471 +6279 +5806 +6867 +5890 +2396 +3416 +1981 +6073 +5872 +3045 +4182 +7607 +3318 +4414 +2998 +6553 +7139 +5624 +2123 +3666 +723 +5110 +6932 +8200 +2222 +8399 +1041 +4138 +1594 +3569 +9253 +393 +7940 +8004 +1475 +6759 +5393 +1107 +2597 +878 +9309 +7576 +5250 +1759 +3142 +2015 +571 +3921 +1255 +7080 +893 +2160 +1355 +82 +1562 +9153 +8583 +4085 +4644 +7196 +9165 +3558 +4550 +6374 +7826 +8602 +4146 +9257 +6083 +874 +8383 +3731 +3374 +3653 +8222 +7344 +470 +1813 +4478 +6871 +7245 +6866 +3998 +7433 +276 +1915 +1988 +8168 +2518 +2686 +831 +6143 +5205 +8718 +1703 +7729 +2077 +7983 +8450 +1195 +9232 +507 +7989 +6974 +4054 +5828 +8655 +6679 +5245 +7783 +5886 +9098 +6491 +8782 +3525 +6542 +131 +8110 +9186 +9074 +4933 +9035 +2607 +4 +2057 +6273 +2711 +5829 +3382 +2696 +3043 +2048 +619 +2499 +5295 +1162 +7807 +3694 +2194 +3149 +1940 +7934 +840 +3592 +8237 +4731 +1324 +8486 +8726 +8573 +2928 +9078 +2272 +2564 +1370 +5911 +7434 +8026 +407 +7546 +2004 +5849 +3034 +7887 +3425 +1118 +926 +3430 +1544 +5902 +2282 +1124 +2334 +129 +1372 +4842 +6473 +4382 +1028 +415 +8269 +8073 +6910 +2796 +3038 +5735 +5080 +2852 +6306 +8842 +9188 +3637 +1066 +532 +928 +5485 +2838 +6753 +9008 +7984 +2816 +8819 +7103 +5977 +5044 +2064 +2599 +4973 +382 +3249 +6446 +6638 +852 +1724 +3368 +892 +3250 +8258 +7962 +4300 +1616 +167 +8855 +2090 +4424 +879 +5136 +5350 +2635 +7828 +8506 +63 +3004 +3847 +3676 +1184 +1705 +6745 +1263 +5020 +746 +1888 +7036 +1033 +3914 +5433 +3905 +4641 +8909 +228 +4801 +3766 +8085 +643 +6914 +9280 +3013 +5657 +3696 +1590 +2920 +8282 +2403 +416 +911 +3849 +4215 +1120 +5490 +296 +2306 +3140 +3742 +4819 +6153 +6414 +760 +3000 +7498 +7108 +6429 +3031 +5314 +751 +3357 +5808 +7505 +98 +7652 +4027 +6257 +3943 +1799 +8577 +5577 +4969 +9163 +2025 +6061 +4026 +5732 +588 +7017 +1415 +4961 +4940 +7152 +538 +706 +2802 +8983 +3375 +1246 +6593 +5837 +1789 +7939 +4997 +5939 +2411 +6133 +199 +7593 +1702 +5406 +6082 +2359 +2912 +6109 +100 +8149 +5470 +2807 +3384 +6413 +3362 +5621 +6019 +9241 +9268 +7703 +4111 +7967 +5458 +7181 +5492 +1112 +6729 +4577 +106 +8853 +3774 +979 +7082 +4610 +1853 +9003 +9292 +2867 +6262 +2245 +3460 +1557 +767 +4796 +8147 +2658 +5769 +6985 +7065 +421 +7990 +3289 +1540 +9316 +2251 +6896 +5947 +4965 +2652 +4480 +963 +9047 +7168 +7824 +3976 +6210 +7018 +7179 +5016 +7789 +6102 +6828 +7659 +9109 +9071 +8115 +7628 +7110 +16 +7513 +835 +939 +4078 +2351 +2322 +3881 +4945 +560 +6837 +6094 +6475 +7901 +3 +771 +8029 +3135 +8044 +7127 +3741 +5156 +7030 +4906 +113 +3747 +7042 +5232 +5225 +3002 +4747 +6879 +5379 +4886 +7192 +4184 +1896 +1834 +8689 +3665 +2957 +6913 +8009 +4851 +6420 +7987 +828 +3003 +8884 +8815 +3198 +8008 +194 +6251 +3303 +3934 +395 +1285 +4169 +1648 +1347 +3600 +4631 +509 +211 +6230 +7241 +8250 +2219 +2582 +8353 +7790 +7583 +4462 +3904 +9004 +6942 +1704 +5686 +8051 +2981 +5511 +6182 +7088 +1699 +1222 +3455 +6189 +1528 +5197 +6221 +7893 +3283 +2837 +7773 +8766 +2942 +8021 +614 +4102 +7362 +1786 +400 +133 +556 +3127 +5237 +3727 +1440 +3873 +6322 +8448 +6285 +8696 +8800 +4009 +3386 +454 +4847 +5685 +9093 +246 +1314 +5895 +6863 +4302 +4260 +8405 +8417 +7116 +255 +3223 +4737 +7852 +6337 +814 +710 +1094 +6103 +5809 +5882 +6336 +4974 +1499 +2806 +3744 +2664 +2436 +4482 +8665 +8918 +1076 +8676 +5725 +9248 +4755 +1447 +9328 +5500 +78 +2653 +792 +6854 +6093 +6172 +3378 +4492 +5529 +5476 +3846 +1391 +383 +4289 +3883 +2648 +3265 +2525 +5402 +4599 +6870 +6877 +4413 +2464 +8519 +2521 +1839 +5822 +5664 +7257 +5375 +6852 +6764 +5182 +8914 +3015 +8509 +3080 +4562 +8979 +6215 +6643 +8601 +6096 +4812 +5246 +7862 +527 +7849 +6737 +12 +2468 +7961 +275 +27 +5932 +3840 +7341 +4996 +8564 +2154 +3788 +6138 +7831 +4442 +757 +4464 +1170 +2568 +19 +323 +6584 +7675 +3441 +2067 +9027 +2486 +4379 +4744 +1737 +7563 +301 +3907 +4742 +6857 +1221 +9284 +8458 +8236 +2897 +4004 +1526 +5345 +4423 +6246 +8578 +1057 +3711 +4986 +4785 +3997 +7311 +4788 +107 +8387 +2041 +2608 +8628 +5830 +6031 +783 +6817 +3293 +541 +773 +8473 +2501 +7247 +5667 +804 +483 +1639 +696 +6060 +5429 +5762 +1527 +7342 +1329 +6225 +7895 +381 +8030 +8520 +8362 +4734 +3526 +9273 +2039 +4142 +5084 +875 +6905 +8968 +5275 +3052 +650 +7509 +232 +2595 +3631 +1810 +4355 +8315 +8908 +1777 +4834 +3164 +2336 +1543 +6212 +8346 +3024 +3719 +1242 +6265 +8101 +3133 +6150 +6358 +3316 +4089 +1647 +4629 +7117 +2596 +5366 +1225 +6371 +624 +2209 +1428 +1158 +7648 +466 +8765 +802 +153 +4639 +3657 +6482 +9320 +2693 +6591 +3294 +2617 +5052 +6305 +3227 +8784 +7170 +93 +5868 +6716 +1671 +178 +2703 +954 +3254 +2262 +5046 +5743 +8647 +6393 +7706 +6604 +3728 +6978 +7489 +7474 +8754 +2740 +2233 +6038 +1491 +8814 +2080 +2358 +5944 +5653 +1164 +9259 +4518 +7343 +5748 +3897 +923 +5967 +2677 +3503 +1202 +4966 +1836 +1863 +6634 +1962 +9096 +9064 +977 +4049 +1464 +658 +536 +3402 +8064 +1309 +259 +7999 +8122 +910 +224 +6152 +7142 +6070 +7523 +8411 +2408 +6766 +9214 +9312 +8325 +6192 +626 +6025 +6240 +8708 +4630 +6777 +1075 +8906 +408 +9269 +6236 +9067 +2514 +8568 +2324 +156 +3136 +3530 +7878 +7308 +4335 +2065 +3845 +4453 +3356 +1450 +371 +7219 +5171 +201 +8642 +2099 +477 +1603 +8339 +7430 +3061 +235 +8291 +1133 +8474 +7035 +8653 +989 +4569 +9092 +8347 +3102 +1743 +9086 +5140 +7438 +1530 +4342 +2460 +7646 +5047 +5071 +5430 +6944 +610 +2803 +1448 +4696 +6156 +4386 +4248 +4256 +994 +2112 +805 +8011 +8276 +8999 +4956 +1712 +2795 +7553 +6436 +2158 +9083 +3184 +5784 +4428 +612 +5288 +6222 +1365 +5074 +6848 +575 +5213 +2175 +4240 +351 +2086 +2656 +5150 +9255 +8189 +7735 +1261 +1344 +4097 +8674 +2984 +4235 +5998 +6488 +537 +1267 +7486 +7124 +6245 +7955 +7337 +5436 +1194 +8226 +209 +1710 +7906 +4357 +4139 +5679 +2584 +2854 +1004 +8246 +8586 +5087 +1878 +4926 +6637 +3197 +7757 +8249 +4055 +6502 +1248 +990 +3928 +2770 +2751 +1020 +6426 +4190 +6839 +2671 +884 +3871 +9212 +4179 +3394 +10 +5861 +5316 +6869 +2985 +8905 +8559 +4457 +2480 +2313 +4100 +4395 +6835 +7799 +7890 +2785 +5468 +7302 +5862 +1803 +6376 +3171 +8591 +717 +7053 +1655 +4489 +2522 +2921 +8555 +1984 +895 +8949 +1305 +738 +7606 +112 +3042 +1325 +437 +3167 +3340 +511 +3689 +5813 +8982 +69 +4421 +7150 +550 +8829 +8685 +3147 +8956 +3166 +7023 +8633 +3308 +2014 +3573 +3880 +4045 +2069 +6051 +4950 +702 +6664 +8418 +2454 +6181 +4853 +4166 +7022 +7418 +3605 +9181 +7172 +5031 +4589 +7858 +6586 +6351 +8334 +7504 +634 +3759 +1890 +890 +6959 +5085 +4919 +2161 +1191 +256 +3610 +7079 +3427 +4071 +7323 +2982 +7263 +7444 +4251 +5846 +4864 +3649 +4311 +7461 +8120 +4582 +6373 +2805 +4872 +4869 +5493 +5867 +2670 +7099 +30 +8933 +930 +7919 +501 +7261 +5289 +7449 +7772 +3613 +7848 +3196 +474 +205 +841 +2611 +6185 +3088 +409 +7239 +5938 +7871 +1343 +6705 +1027 +5596 +2199 +9113 +5471 +6134 +838 +2345 +8359 +4061 +1474 +3229 +270 +4245 +1979 +5995 +1517 +8652 +4006 +4880 +6137 +4693 +2528 +6996 +2926 +5798 +2477 +2549 +1128 +3341 +6014 +4479 +2861 +4208 +5175 +5174 +5118 +3736 +5463 +1588 +2327 +8380 +7982 +1514 +1058 +4586 +6608 +7985 +3044 +1822 +3628 +6851 +549 +1811 +2184 +2601 +4608 +8922 +2540 +6659 +3859 +307 +3650 +3767 +8167 +505 +4366 +4824 +5520 +461 +1933 +2401 +8106 +2055 +7844 +8544 +8838 +4797 +7419 +6686 +7670 +6039 +5672 +5141 +6543 +206 +5252 +4718 +888 +1601 +3218 +5114 +713 +4022 +4419 +6708 +397 +425 +6612 +5057 +1729 +6573 +4729 +4080 +1034 +2961 +534 +8194 +5598 +9218 +2424 +329 +4154 +1597 +922 +109 +8823 +3578 +9038 +8437 +3307 +128 +8032 +1412 +7333 +8762 +8851 +8865 +3056 +468 +3808 +3064 +8798 +7052 +7767 +9231 +1086 +2162 +6566 +2109 +3439 +6122 +3642 +7696 +8610 +5279 +1808 +8687 +8377 +817 +8714 +6066 +4008 +3640 +6015 +1021 +7601 +4855 +6017 +87 +7071 +2730 +7268 +3614 +6084 +6117 +6924 +9102 +2829 +375 +8724 +2095 +22 +1541 +2970 +633 +139 +451 +4521 +179 +1396 +3876 +5824 +8020 +426 +4982 +4172 +1157 +190 +4859 +1455 +3110 +3323 +9104 +858 +6719 +6428 +4495 +8551 +2141 +3984 +3066 +67 +4299 +5821 +8444 +6581 +6097 +7090 +7781 +8944 +3085 +8606 +2114 +5355 +8901 +1461 +3301 +422 +7000 +4820 +5790 +1379 +7536 +4199 +8736 +8991 +5241 +1698 +1294 +1753 +196 +2987 +8680 +4658 +4144 +8639 +6441 +8255 +8156 +3677 +6385 +6520 +7700 +3760 +6001 +1144 +5478 +7394 +8057 +5018 +4232 +5235 +6844 +3111 +8802 +867 +949 +7843 +573 +2278 +6801 +7629 +2714 +5105 +6946 +2697 +5315 +1571 +8677 +2537 +4374 +3833 +7820 +3750 +2033 +6526 +3884 +8706 +7195 +417 +3603 +3001 +6284 +5873 +5718 +8576 +8457 +3589 +5839 +459 +3626 +6342 +8729 +6933 +607 +6053 +8228 +3773 +1805 +6365 +5142 +6069 +1389 +9026 +570 +4614 +5712 +5533 +9222 +2821 +1897 +819 +766 +4060 +4902 +5905 +6842 +5446 +1277 +4303 +2836 +934 +1014 +7822 +7494 +3466 +665 +1047 +5881 +3328 +4664 +315 +1315 +1462 +8616 +7725 +2756 +5749 +1730 +8184 +4567 +5065 +7499 +8867 +1304 +3669 +9192 +410 +8177 +6710 +1210 +2329 +8443 +3911 +1899 +7686 +3315 +7190 +6180 +3116 +5341 +4394 +8337 +9182 +6969 +5715 +2172 +1742 +2782 +3715 +9195 +7960 +2517 +4890 +8294 +2337 +8014 +3353 +7475 +2193 +4843 +8831 +4200 +4653 +6196 +6957 +3063 +2996 +8959 +8973 +6529 +3457 +5274 +8002 +6823 +6154 +5561 +1780 +9318 +7657 +1758 +6503 +7678 +3274 +1625 +4327 +3236 +8575 +3155 +4707 +4331 +1494 +8756 +3174 +1074 +8116 +8295 +8311 +3048 +3752 +6050 +6483 +8003 +9175 +4674 +1642 +2556 +6166 +7165 +8441 +5413 +3990 +1640 +1778 +7500 +8304 +1395 +4315 +5949 +3364 +242 +5763 +1036 +249 +2430 +7426 +8131 +411 +6267 +2045 +6606 +899 +8065 +9052 +7507 +5779 +5616 +2107 +5408 +2980 +6310 +5776 +4328 +821 +3251 +2354 +7076 +1700 +5313 +6736 +79 +8212 +3959 +5677 +7545 +160 +6790 +6859 +3659 +6770 +1106 +8846 +956 +7472 +2050 +8099 +4795 +8053 +9293 +7037 +1646 +9307 +1069 +5322 +5332 +2708 +8977 +917 +2419 +184 +2105 +1578 +3923 +5780 +1903 +2512 +429 +5582 +493 +4972 +445 +8286 +555 +320 +8300 +322 +617 +3413 +4459 +525 +5631 +6314 +5157 +5300 +8545 +182 +1031 +4429 +2495 +7586 +1534 +3099 +3916 +3738 +1919 +535 +2119 +1299 +177 +1838 +2159 +4099 +8285 +5172 +8540 +6020 +7683 +3073 +3115 +1673 +3087 +3488 +2416 +1894 +5942 +3597 +5834 +2007 +43 +1779 +4174 +2023 +2546 +2429 +9006 +436 +4214 +4536 +3693 +5426 +6767 +5903 +4368 +2170 +5051 +7490 +7882 +2859 +5035 +7835 +5372 +7122 +925 +3253 +6338 +8393 +4093 +5848 +7588 +2683 +8049 +5403 +5894 +8745 +8550 +2941 +3484 +9029 +4461 +8022 +725 +2355 +1619 +3030 +1975 +5623 +2415 +1957 +6141 +9278 +3226 +3062 +5670 +7326 +8759 +8496 +6619 +8187 +8262 +6199 +951 +7183 +668 +2388 +4698 +5681 +8240 +2851 +871 +4988 +9084 +9089 +3162 +1167 +8244 +5227 +6461 +2831 +776 +5010 +5770 +5282 +3574 +5102 +1278 +2281 +5455 +305 +4628 +4663 +9119 +7487 +8746 +4889 +6569 +1175 +102 +2386 +8940 +2479 +5566 +53 +8833 +1918 +8001 +321 +6786 +6861 +4358 +2771 +7467 +975 +4777 +605 +3543 +2600 +7584 +9299 +4530 +6477 +7364 +7328 +183 +4761 +7543 +304 +1196 +4623 +7839 +2139 +5519 +1953 +533 +5989 +7590 +7428 +6346 +6162 +1091 +1946 +6260 +4405 +5676 +8924 +7171 +8409 +1866 +6379 +3411 +2387 +3051 +7398 +154 +1185 +6442 +6004 +1611 +2165 +9018 +8323 +616 +3995 +8952 +1533 +7853 +4194 +213 +789 +4991 +3675 +7456 +5752 +175 +7556 +4195 +907 +2248 +9057 +8467 +4594 +1017 +7968 +880 +7446 +3304 +1666 +4942 +3867 +4802 +9156 +6357 +4621 +887 +6213 +5261 +1336 +521 +8928 +1818 +7864 +4792 +6742 +157 +1593 +823 +7235 +5303 +5633 +1100 +1692 +8047 +5993 +1460 +6714 +1630 +6440 +6307 +3608 +292 +212 +401 +5974 +7107 +8301 +8342 +2720 +4583 +2757 +7315 +833 +4466 +4236 +1282 +5273 +2149 +287 +8484 +2380 +8119 +7167 +737 +5076 +6598 +3596 +5382 +2650 +8980 +3421 +1356 +1954 +7823 +1172 +2226 +1941 +6136 +7274 +2256 +4928 +324 +1407 +4410 +4579 +1061 +7113 +486 +862 +3435 +6956 +2873 +1465 +6113 +8225 +8512 +6806 +272 +6008 +1241 +88 +5662 +3555 +689 +8733 +2812 +7453 +6282 +420 +2471 +4477 +7495 +1445 +594 +6939 +1564 +8704 +8590 +7992 +7374 +5796 +9298 +4213 +5713 +5864 +326 +5513 +402 +464 +608 +1951 +8640 +8180 +3347 +3459 +4162 +2690 +7478 +5856 +5240 +2389 +3022 +602 +5547 +1798 +1345 +9276 +599 +3673 +3277 +1635 +8625 +1567 +5928 +636 +5671 +2896 +3477 +412 +7575 +4201 +685 +4760 +1229 +4275 +8960 +3123 +4471 +5941 +3355 +3999 +7157 +6354 +7741 +6850 +8783 +1943 +6769 +7330 +8721 +8477 +1381 +848 +778 +6408 +2644 +5817 +1441 +1723 +2144 +2776 +2368 +120 +367 +8839 +8749 +5353 +4158 +3148 +9114 +1233 +9228 +8857 +2895 +1286 +200 +6755 +5125 +5857 +1657 +7658 +5097 +5000 +942 +7020 +586 +784 +7078 +6194 +8658 +8957 +9325 +1851 +8911 +4862 +7004 +1186 +8824 +1651 +2999 +561 +7639 +4316 +5086 +3187 +7912 +2624 +9183 +8487 +5089 +8475 +7554 +4031 +6297 +6059 +5329 +115 +2058 +7650 +7634 +7121 +2485 +7805 +2241 +7713 +4352 +2409 +1026 +2745 +4549 +6474 +5124 +5201 +6556 +6617 +9091 +3945 +8402 +5648 +5257 +2192 +4901 +7750 +6131 +6027 +6352 +4625 +1254 +5498 +3720 +8261 +3939 +5576 +3685 +6713 +8472 +991 +8354 +8068 +5655 +5997 +1029 +7506 +6740 +2575 +2990 +4898 +583 +7402 +3290 +5388 +6715 +8235 +5361 +4970 +1363 +3338 +5731 +9014 +5358 +2216 +2856 +635 +1193 +3705 +6334 +7666 +5270 +1384 +6368 +8604 +3564 +1937 +2481 +1341 +721 +2100 +3958 +6551 +3813 +2592 +7980 +5385 +319 +2357 +8761 +8910 +8693 +1204 +489 +4827 +8024 +7832 +6427 +3895 +89 +9068 +8067 +1708 +1111 +8963 +1902 +9251 +5719 +9143 +5537 +9169 +77 +5365 +1840 +485 +4456 +2841 +1169 +3271 +7144 +6886 +9140 +7173 +6003 +1659 +1807 +8371 +2439 +274 +4660 +3448 +6623 +347 +2103 +3400 +2106 +9073 +8169 +3687 +3305 +4416 +8454 +6635 +332 +2433 +2909 +3839 +4063 +1944 +6509 +1296 +7770 +1880 +6610 +4075 +9331 +4484 +302 +418 +4219 +1333 +2350 +6498 +8424 +4694 +4883 +5269 +6580 +5007 +6722 +1669 +8470 +2571 +513 +3810 +7049 +6332 +7363 +3532 +8456 +2097 +297 +8841 +7180 +714 +1587 +5234 +4268 +2320 +7372 +660 +8503 +1668 +8847 +1101 +7275 +3336 +6460 +722 +7782 +3947 +502 +4258 +2132 +1835 +181 +3841 +427 +3446 +2551 +8324 +6963 +4284 +7297 +7577 +3399 +9148 +8213 +5656 +8440 +851 +657 +2446 +4292 +6992 +976 +1108 +2681 +3237 +8582 +377 +5969 +5287 +9209 +8523 +7178 +7833 +6175 +2126 +3023 +5090 +7491 +6640 +6077 +2221 +2780 +1694 +4094 +144 +6161 +3203 +7123 +749 +3625 +3848 +980 +2270 +7819 +3672 +7689 +7203 +2718 +1714 +2884 +3474 +3802 +3851 +4224 +7237 +5415 +7998 +7207 +4106 +9036 +1046 +8731 +5070 +6818 +4592 +6056 +693 +1328 +3309 +5791 +2629 +2736 +202 +388 +7886 +4417 +8786 +8822 +4035 +7718 +8492 +5505 +1192 +4388 +8941 +5019 +7538 +6732 +7296 +6389 +5923 +1405 +3278 +3917 +1688 +8374 +443 +4037 +9099 +5190 +6402 +4177 +9310 +7747 +4348 +7197 +4844 +4998 +5609 +4345 +29 +3332 +8648 +4107 +346 +2577 +3941 +1215 +3782 +8252 +4706 +2675 +3790 +7459 +6164 +7316 +1149 +6687 +582 +3139 +5040 +7645 +3882 +7322 +4034 +1861 +4701 +8757 +3208 +8801 +6349 +8907 +1823 +4528 +4789 +143 +4746 +9234 +3866 +9245 +1911 +1366 +4393 +2061 +859 +1959 +6967 +3138 +7382 +9031 +6237 +845 +80 +6911 +7163 +5229 +4736 +8738 +33 +8543 +357 +3193 +7262 +4448 +6796 +6793 +3321 +7569 +6411 +7692 +7340 +1417 +5847 +3836 +2678 +1188 +8727 +223 +8615 +7417 +5771 +3170 +8061 +2935 +8263 +8257 +6883 +1276 +1239 +812 +6258 +3922 +7525 +8117 +3039 +603 +8554 +7573 +2787 +3445 +5115 +3478 +962 +3961 +6570 +7722 +216 +2797 +5154 +2530 +4904 +2405 +7542 +4021 +3252 +5370 +9302 +236 +4532 +1361 +3373 +1716 +2183 +1583 +3783 +868 +1687 +8925 +1433 +6198 +8208 +6367 +7603 +882 +3469 +1645 +7654 +1176 +4231 +150 +7997 +5456 +7031 +4375 +8840 +5634 +6945 +705 +3442 +4774 +3822 +7148 +1922 +8459 +6249 +8713 +6197 +8599 +6071 +6756 +1634 +950 +5640 +7749 +5920 +6622 +4783 +7837 +7479 +7229 +3919 +1797 +5272 +8945 +4908 +5439 +6903 +5833 +6930 +8197 +9261 +1711 +5483 +6046 +4285 +8852 +7409 +8971 +8278 +7534 +7792 +2444 +7496 +8063 +1665 +248 +3894 +4585 +1982 +66 +6651 +4850 +1240 +7511 +7524 +9258 +2075 +3979 +4714 +7592 +965 +2919 +8239 +1842 +8013 +4750 +2344 +6155 +3468 +31 +2087 +1599 +1573 +5883 +7613 +195 +3749 +644 +2189 +8779 +8743 +9005 +8081 +1040 +7785 +5820 +8830 +5495 +4867 +2710 +3843 +491 +7153 +6217 +1148 +4741 +1761 +5484 +3423 +5474 +6916 +5876 +7252 +1739 +8930 +6647 +5198 +4903 +8488 +7366 +2774 +2726 +2385 +7625 +3179 +2211 +8845 +6600 +399 +6810 +3447 +6684 +4915 +8368 +1867 +2325 +2101 +1335 +7734 +3722 +7437 +3716 +7025 +4000 +6897 +1408 +7154 +5013 +2204 +9233 +4225 +3817 +1877 +9161 +2197 +6991 +3390 +280 +1892 +1612 +7753 +2801 +7246 +7909 +6229 +9314 +8407 +1436 +3879 +6432 +6849 +5326 +5327 +8535 +7910 +7745 +5545 +7916 +207 +1783 +6158 +8517 +7361 +8070 +6430 +119 +6146 +4183 +1083 +7385 +4497 +9133 +1686 +3765 +5099 +595 +8046 +4418 +4043 +2361 +7915 +9149 +1717 +1141 +6375 +1018 +5602 +1262 +7485 +9178 +6629 +3339 +8934 +4648 +7988 +6252 +3440 +864 +5418 +3874 +7280 +6191 +8388 +4323 +6792 +4324 +2232 +7228 +8684 +7813 +6187 +6678 +3177 +3534 +4953 +4402 +7739 +6319 +2414 +8700 +5946 +8238 +4533 +6917 +4167 +4618 +2115 +2268 +3081 +1247 +4001 +8580 +7636 +3101 +2195 +1559 +3714 +2484 +7188 +6028 +7530 +2828 +1977 +3238 +6496 +2340 +110 +3247 +7532 +7541 +924 +1632 +484 +4487 +4439 +6447 +1319 +4944 +6347 +1791 +2285 +8087 +5452 +91 +1166 +162 +5185 +7933 +4743 +1627 +7259 +8620 +8525 +8207 +5845 +9011 +5525 +4269 +4700 +1824 +8186 +8872 +8299 +3957 +8242 +4558 +6439 +2666 +5943 +6958 +8112 +5121 +8806 +6170 +7688 +3486 +2082 +7436 +2778 +1096 +786 +2206 +5170 +1443 +6030 +3312 +9151 +8485 +6404 +8498 +2883 +8961 +2280 +8341 +9137 +4337 +2809 +2445 +809 +8298 +8643 +8316 +4951 +6853 +1572 +3215 +3938 +2249 +6515 +1337 +8328 +7712 +1429 +4117 +5441 +3230 +4152 +7225 +3513 +6953 +1507 +348 +3639 +5739 +2673 +1550 +6301 +1652 +8453 +204 +6833 +8056 +2200 +5217 +1854 +4711 +7368 +4572 +4032 +7531 +1013 +3634 +2875 +6058 +8307 +7609 +1766 +904 +667 +5410 +6578 +3601 +1664 +3233 +7390 +8178 +4486 +4952 +4427 +4876 +9166 +3107 +2772 +6295 +5001 +5296 +3371 +6518 +6327 +854 +1615 +8288 +1912 +5927 +6202 +5814 +9032 +1059 +3214 +6547 +7038 +5781 +6926 +4390 +6114 +1622 +4318 +5803 +5984 +736 +3561 +6554 +5045 +4277 +7386 +9081 +8462 +2034 +4955 +2701 +932 +1298 +7758 +7176 +9205 +2276 +3077 +3803 +3562 +8054 +7946 +295 +1843 +7728 +1629 +7768 +3663 +6363 +2971 +431 +9285 +2513 +1116 +3656 +4529 +6366 +5758 +6339 +8398 +816 +4153 +648 +2536 +1826 +7870 +8113 +7730 +7101 +6555 +9256 +6774 +1072 +4578 +2598 +3604 +5880 +861 +8273 +3350 +3117 +4685 +9219 +4334 +5165 +2035 +7224 +4066 +4253 +4447 +3815 +5038 +253 +3658 +2252 +330 +3967 +6443 +2143 +7336 +6135 +593 +2734 +8390 +4655 +7800 +1399 +1173 +5618 +2822 +7905 +7503 +4431 +2443 +1568 +3909 +1974 +2496 +4772 +5164 +4105 +2138 +2864 +3799 +3924 +4882 +8245 +1585 +5528 +5692 +5730 +5832 +137 +3175 +2894 +2062 +3899 +2752 +4028 +2113 +5411 +293 +2647 +730 +3758 +1667 +8879 +9303 +6653 +3698 +3968 +3053 +503 +2150 +4645 +2257 +4627 +8303 +7966 +8742 +4692 +5901 +8547 +2277 +5546 +986 +370 +4697 +8712 +4804 +4881 +1182 +6650 +7290 +3487 +2814 +5668 +7567 +5333 +3724 +4164 +3084 +8896 +3888 +6537 +17 +6882 +3531 +704 +1037 +8866 +5263 +6758 +3762 +1393 +3824 +5575 +5112 +214 +1439 +5700 +8932 +1306 +5011 +6928 +5173 +4098 +1132 +7352 +4778 +7723 +1368 +2390 +670 +2685 +5855 +1772 +6380 +3853 +940 +5424 +6091 +1748 +6193 +5297 +6572 +8877 +6874 +430 +5041 +5267 +1145 +7448 +620 +9112 +4294 +1432 +72 +130 +2393 +7920 +4597 +6614 +8889 +3697 +1895 +3462 +2616 +3978 +4791 +7846 +7780 +8372 +428 +6559 +8326 +9211 +2363 +1525 +5980 +7888 +3331 +8118 +7899 +615 +7377 +791 +5930 +6627 +8322 +1138 +770 +8460 +5100 +8274 +8350 +6316 +2893 +7594 +9236 +5082 +8150 +1986 +1909 +8902 +2145 +3617 +3501 +7 +2426 +5056 +8016 +2702 +5360 +8135 +8385 +8378 +8018 +8574 +720 +8893 +3021 +1978 +4782 +1816 +2083 +4051 +1446 +5870 +971 +9097 +8006 +4222 +8287 +686 +1377 +611 +8153 +4920 +4808 +1536 +679 +4096 +3891 +4884 +432 +4615 +8988 +5560 +3451 +5589 +3514 +6169 +1414 +3244 +1490 +7100 +3588 +690 +7317 +4171 +2266 +6800 +108 +2793 +5151 +6977 +2587 +8188 +8752 +6318 +5815 +5116 +263 +3311 +5191 +5689 +289 +3392 +5755 +1022 +5548 +9319 +8937 +6011 +7632 +5328 +4993 +4141 +5407 +1865 +520 +7305 +7208 +526 +3645 +1859 +2520 +3523 +8629 +7304 +8881 +3076 +4005 +8329 +2205 +2214 +6925 +8691 +4136 +8883 +974 +7873 +7952 +3965 +5887 +7964 +7189 +2406 +2783 +8086 +405 +6568 +5147 +2021 +4727 +4826 +7674 +1600 +5078 +2949 +6624 +6541 +8986 +5740 +4679 +8500 +3591 +4434 +398 +983 +7544 +1478 +4570 +6012 +465 +9330 +7206 +808 +8737 +2356 +4959 +8812 +6955 +3599 +2168 +1420 +1721 +1794 +5897 +8422 +2 +4023 +2739 +3619 +8797 +5496 +8951 +8181 +6893 +9254 +1809 +5682 +4309 +6929 +2742 +5988 +3363 +4493 +8434 +4210 +1503 +1876 +5094 +4600 +4936 +4798 +3933 +5216 +646 +7660 +3098 +8773 +4076 +1576 +5335 +3746 +3327 +47 +4602 +8636 +4129 +363 +6417 +7416 +9025 +4377 +4766 +2779 +4151 +9046 +7860 +3154 +3476 +7620 +966 +2052 +8344 +1752 +7199 +4412 +8895 +8882 +2463 +339 +56 +5390 +4821 +7555 +6558 +1905 +5258 +8880 +4205 +3580 +6735 +1023 +4511 +3850 +161 +7395 +2532 +3349 +7055 +7387 +758 +1907 +872 +3006 +659 +815 +1961 +6902 +7668 +4708 +1904 +4433 +5159 +6816 +8664 +6918 +1016 +6513 +7314 +5364 +7480 +9313 +716 +3395 +6843 +2292 +918 +4329 +1035 +6344 +8593 +3404 +5212 +837 +480 +8524 +1342 +3690 +6797 +7414 +288 +8863 +3352 +1628 +24 +135 +3314 +2181 +8650 +5915 +8078 +6812 +1375 +6040 +906 +5635 +7126 +1387 +7458 +6119 +5591 +3795 +1531 +95 +1960 +7522 +3033 +898 +4607 +4921 +3913 +2623 +4430 +6268 +7063 +1326 +9075 +2505 +7400 +1284 +2951 +747 +6466 +1357 +6493 +7320 +5892 +576 +5107 +5559 +97 +2583 +6361 +8843 +3509 +7892 +6086 +1476 +4612 +7427 +4267 +9094 +7050 +6048 +8455 +8382 +2227 +284 +2898 +3221 +2353 +2157 +5990 +5810 +3581 +7279 +6188 +7859 +3549 +5539 +7918 +2022 +9066 +630 +2500 +5111 +6561 +5127 +8095 +5569 +6123 +1338 +8605 +3491 +4187 +8220 +7334 +9213 +3067 +6997 +2853 +4735 +4372 +1489 +5954 +6662 +2207 +973 +3361 +960 +6350 +4170 +7431 +8076 +1129 +750 +7559 +7194 +2261 +2300 +6590 +5893 +6889 +3125 +8788 +334 +7286 +3472 +8164 +7693 +1469 +1181 +669 +7515 +5563 +4773 +3210 +6324 +3113 +9070 +3638 +7551 +2541 +3506 +5138 +4069 +7198 +7560 +3306 +6100 +2932 +4473 +1741 +14 +4672 +7564 +8748 +8874 +3804 +3678 +2240 +2610 +2862 +1358 +5716 +42 +5176 +9326 +8464 +1038 +2993 +3017 +9072 +32 +4809 +4364 +2808 +4125 +448 +152 +7299 +5431 +6178 +793 +3444 +9120 +8410 +4963 +772 +5457 +6954 +3014 +6881 +286 +553 +1948 +6398 +6255 +3057 +8646 +6176 +2700 +7106 +5663 +6683 +1281 +6013 +8799 +7635 +9289 +1885 +442 +2225 +6294 +5054 +2674 +7884 +8730 +8216 +4203 +1488 +7111 +4013 +3623 +7950 +1971 +1966 +3248 +2900 +1553 +472 +3865 +7796 +6937 +4591 +8098 +5208 +294 +5627 +5691 +5687 +7149 +4879 +3624 +7005 +2773 +3112 +9185 +1633 +7830 +5101 +8707 +8469 +4678 +4860 +700 +5527 +9194 +2794 +5068 +2639 +1177 +4282 +6492 +8128 +5859 +5029 +5123 +2877 +522 +5048 +7230 +2104 +6642 +6731 +2717 +5149 +2043 +9059 +5277 +844 +1394 +3262 +5515 +6706 +3651 +9105 +7671 +2880 +3607 +6410 +2508 +8463 +2394 +1916 +1125 +5343 +3322 +5307 +4547 +1589 +8478 +8899 +2955 +8028 +7293 +4619 +4058 +2781 +8715 +1272 +5734 +4474 +4863 +4367 +49 +8844 +5605 +8671 +6743 +4281 +7077 +1874 +2626 +2516 +258 +5249 +6186 +7958 +5432 +3801 +6288 +4732 +9121 +7558 +2527 +4661 +6819 +3835 +7508 +584 +215 +5036 +4261 +8978 +5228 +647 +4657 +2591 +5931 +5088 +9204 +929 +4381 +5421 +2965 +5050 +6495 +5033 +4799 +959 +6115 +3520 +1232 +5811 +317 +8976 +7705 +3842 +2178 +7187 +1373 +7112 +2694 +8627 +8493 +3991 +7441 +6308 +2589 +6462 +3406 +7673 +8660 +2902 +752 +1025 +849 +7682 +6982 +6652 +3612 +298 +5148 +4873 +3414 +1693 +1458 +327 +2016 +5002 +6768 +7016 +5583 +3270 +857 +8232 +7158 +7981 +4676 +4675 +2164 +8360 +6709 +8143 +365 +4062 +4527 +7928 +9009 +6228 +5818 +2533 +9305 +8887 +55 +2507 +8870 +6649 +5158 +76 +5595 +6693 +5306 +8666 +3020 +7527 +3082 +6304 +1591 +6145 +6868 +7205 +9107 +1165 +6773 +172 +1993 +4176 +8400 +4611 +7589 +8702 +5386 +6095 +6335 +1561 +8805 +5963 +7393 +3681 +2037 +4968 +7451 +3360 +7466 +8361 +4455 +4064 +5422 +1689 +3977 +7269 +362 +4178 +4145 +6127 +5162 +2399 +9225 +7068 +1650 +794 +3007 +1348 +7736 +444 +6081 +5298 +2026 +2543 +9087 +3593 +7425 +3730 +8468 +2641 +7529 +1720 +6377 +8732 +5851 +7956 +3150 +3785 +6485 +3611 +2869 +8510 +4775 +4463 +1251 +9124 +6873 +3391 +6505 +4118 +1617 +8837 +7051 +3213 +3668 +5347 +8452 +6289 +5840 +478 +3522 +453 +3376 +6190 +3342 +2237 +2870 +5178 +5567 +5952 +6919 +3005 +134 +3397 +7443 +8539 +6822 +5264 +3288 +5962 +8421 +6744 +8608 +4656 +1802 +2073 +4271 +1043 +2922 +8211 +2196 +5260 +3789 +7211 +7571 +7834 +5680 +2047 +5502 +3369 +3437 +3286 +5517 +3912 +8386 +1442 +6961 +2191 +2417 +9088 +5155 +6813 +4520 +7375 +1224 +811 +1891 +3748 +4123 +2789 +5305 +8419 +7248 +9237 +992 +4038 +4499 +2060 +5538 +850 +2669 +7612 +104 +9290 +2526 +1287 +4160 +4633 +7125 +742 +744 +4534 +2407 +7714 +4555 +8764 +7661 +4722 +7721 +3205 +6657 +1214 +3754 +6080 +4593 +3018 +8792 +2294 +4450 +7701 +9301 +127 +7069 +4513 +6243 +8025 +4010 +8632 +4715 +5284 +4574 +726 +4252 +4561 +7354 +299 +6088 +1090 +5012 +5684 +3489 +5639 +4888 +1584 +1969 +4846 +2915 +6804 +2775 +7306 +6506 +9306 +5231 +7740 +4283 +953 +6725 +458 +8290 +1504 +1539 +8885 +138 +3764 +1256 +257 +335 +1011 +7060 +5986 +9323 +4740 +8994 +4140 +6807 +8254 +3963 +9297 +2102 +2964 +9207 +4910 +8709 +4411 +1672 +457 +5852 +8037 +4932 +3679 +8794 +2362 +8592 +495 +8432 +1608 +2155 +7411 +2881 +9244 +37 +6535 +8219 +4505 +8635 +1928 +8384 +2570 +8996 +7610 +2128 +8728 +6656 +8935 +6681 +2070 +176 +9062 +972 +514 +1796 +4039 +6838 +2462 +230 +569 +5521 +4637 +4939 +4420 +2863 +672 +4995 +3807 +447 +1656 +2005 +5113 +3297 +8858 +2118 +6309 +1926 +481 +1156 +1509 +1228 +1787 +5978 +8678 +3951 +2929 +4980 +5039 +4713 +7002 +151 +5536 +8148 +3823 +4709 +2299 +142 +7067 +2372 +3761 +9 +2265 +5747 +2764 +724 +2913 +3151 +4525 +6370 +4247 +9329 +5494 +3721 +629 +3621 +7371 +59 +1999 +6704 +3734 +2698 +4691 +6938 +9117 +8415 +6353 +6750 +9077 +2679 +7623 +2478 +7321 +6611 +4007 +2076 +5772 +6416 +2264 +8348 +2672 +6546 +754 +6934 +7908 +8546 +4404 +592 +4748 +6625 +2129 +7944 +2377 +6 +8929 +8275 +3515 +4524 +3660 +8710 +419 +6878 +170 +8313 +7460 +8753 +2917 +6891 +6663 +4918 +7129 +396 +7256 +3500 +631 +5585 +8343 +2695 +6168 +6292 +3176 +5092 +5160 +3701 +9021 +7221 +7825 +1216 +1438 +3471 +2318 +8923 +6223 +2182 +7621 +8514 +9010 +8987 +1252 +1972 +1872 +1715 +8205 +6463 +8138 +8989 +5661 +2890 +565 +2427 +8946 +1303 +3718 +6000 +3620 +1560 +5276 +8089 +9260 +1467 +6173 +7641 +7520 +5061 +4677 +5757 +4400 +2620 +2719 +8995 +2079 +6644 +1683 +8141 +7754 +5744 +2952 +7568 +654 +7457 +5368 +3310 +1510 +4440 +1513 +3072 +8034 +1456 +9164 +3163 +3035 +6111 +5042 +7161 +1401 +1084 +8000 +6672 +8531 +5404 +6550 +8379 +9141 +8681 +7752 +6394 +7011 +3739 +8253 +978 +4771 +6024 +4828 +7959 +1649 +1727 +7073 +8349 +6952 +661 +7283 +3159 +2590 +3496 +8741 +3969 +2956 +4565 +920 +1830 +8558 +1930 +6677 +6825 +8256 +7454 +7521 +4710 +1768 +3753 +6459 +5606 +5292 +1397 +240 +2733 +946 +6711 +3242 +2627 +4929 +5006 +3202 +132 +2295 +2746 +1293 +2124 +5405 +4065 +818 +7464 +1820 +4398 +1312 +6994 +6920 +261 +987 +6120 +3109 +331 +2986 +4338 +7774 +5122 +8396 +1364 +8969 +6712 +8161 +7083 +7595 +5940 +1566 +6419 +8634 +4432 +6047 +4749 +6076 +1161 +8217 +674 +8494 +3688 +2447 +4704 +969 +7477 +1160 +3243 +3173 +4979 +9288 +6860 +1662 +6171 +225 +5143 +313 +8327 +3275 +3385 +7626 +3103 +4401 +6794 +5600 +5043 +7664 +933 +6830 +4452 +3980 +1604 +5875 +6633 +4635 +5756 +3329 +1751 +8108 +4817 +1989 +1237 +1893 +2848 +9334 +51 +8875 +4981 +5417 +4134 +877 +6688 +3545 +4943 +5615 +2476 +1684 +3652 +7396 +1769 +1171 +6563 +3415 +3644 +340 +6630 +8284 +3256 +7240 +5371 +3405 +2108 +6360 +1734 +5612 +8638 +2343 +1103 +7803 +6809 +3055 +188 +8031 +3124 +3683 +4537 +988 +2297 +4893 +6499 +3396 +839 +4467 +5195 +4041 +6457 +4441 +6378 +6472 +6195 +4912 +6884 +5922 +7014 +1660 +38 +1595 +6752 +4554 +1292 +2709 +3800 +6057 +1980 +8775 +6587 +6392 +6263 +7214 +5219 +282 +309 +6685 +2253 +6311 +4092 +18 +7570 +5543 +4081 +2515 +6278 +8690 +5294 +6184 +5215 +9130 +6720 +250 +7250 +4983 +639 +3567 +7841 +2636 +4067 +8446 +5703 +8609 +2586 +7695 +1253 +6701 +7930 +6317 +5921 +7719 +8501 +7312 +4110 +6219 +4552 +5059 +4088 +7975 +9132 +6054 +692 +3412 +4079 +6754 +6950 +5281 +3028 +8321 +3877 +7614 +8939 +4188 +2223 +239 +4745 +6875 +7096 +5571 +4403 +2640 +5556 +1845 +6690 +1825 +4157 +314 +4682 +8825 +1003 +6206 +8093 +7215 +6465 +99 +8077 +6631 +4206 +2523 +366 +1208 +6043 +4640 +1457 +5475 +4985 +1351 +3090 +5625 +7307 +8466 +2003 +8854 +218 +1500 +4476 +2293 +1847 +5032 +2147 +866 +3710 +2552 +1749 +6692 +3926 +4112 +6458 +735 +9171 +60 +9304 +6726 +2630 +2882 +1178 +1151 +4922 +4662 +173 +7233 +1776 +6533 +4113 +2423 +2425 +4343 +5800 +970 +6372 +1009 +6607 +3068 +8435 +6423 +3126 +4813 +1709 +1201 +7104 +5620 +3932 +5701 +5724 +3366 +8050 +4984 +5023 +9203 +5079 +627 +290 +779 +5572 +5233 +1392 +4975 +8534 +8210 +2269 +1143 +2475 +2562 +905 +4546 +267 +3536 +8538 +449 +101 +7367 +2722 +4605 +7356 +6781 +8537 +8697 +6820 +8340 +8926 +3821 +2349 +2259 +6545 +8100 +8395 +2258 +2911 +5108 +3946 +1406 +8683 +8296 +5579 +2177 +8264 +1425 +3940 +957 +3647 +515 +5342 +8363 +2449 +3108 +1001 +2937 +3452 +5574 +4319 +9184 +8381 +945 +6876 +600 +5714 +4871 +8532 +1852 +8856 +392 +2018 +8878 +369 +5711 +9230 +5304 +7266 +1681 +7829 +2309 +4683 +8938 +2255 +6159 +3207 +4651 +2029 +4341 +5106 +5794 +9024 +4712 +2434 +7151 +7359 +6431 +1290 +5918 +8705 +3438 +5554 +8876 +7415 +6290 +5373 +3805 +2950 +2331 +6772 +8997 +6576 +2307 +8515 +4033 +3428 +6487 +6595 +45 +5792 +333 +762 +2383 +3388 +666 +2166 +460 +943 +364 +6980 +8223 +8221 +637 +6218 +4108 +5381 +4649 +5096 +1614 +8768 +5095 +3809 +5030 +984 +3538 +5120 +2498 +5222 +5613 +5486 +5119 +241 +5707 +9227 +544 +4109 +7771 +728 +3671 +9327 +1230 +9270 +1070 +8565 +4769 +7056 +5654 +7965 +1793 +5956 +7883 +1362 +5479 +8769 +8821 +8320 +1901 +1994 +2461 +5552 +389 +2839 +6467 +2762 +4763 +3499 +1487 +7599 +4488 +3241 +8272 +1131 +4496 +7006 +7265 +4897 +2747 +6618 +5291 +4563 +5146 +1939 +6369 +8548 +6163 +5526 +4068 +9030 +5349 +8433 +748 +1477 +4265 +9200 +3878 +462 +6846 +9040 +4806 +3519 +6798 +5464 +5179 +546 +6044 +8114 +7216 +6276 +1495 +494 +8146 +5434 +856 +8403 +8071 +3972 +5544 +3337 +6855 +1546 +2824 +1718 +6009 +2042 +251 +9076 +3330 +5004 +192 +4717 +3797 +1146 +394 +7814 +7699 +4659 +4689 +4156 +7903 +9054 +7332 +7811 +1119 +5531 +6782 +5210 +8412 +2633 +7924 +4624 +8314 +5666 +3240 +2310 +4262 +8160 +4553 +8196 +2661 +7213 +7455 +7399 +870 +6126 +1227 +1226 +781 +937 +6343 +2578 +2892 +4124 +2792 +5696 +6865 +6455 +8312 +5193 +6026 +5251 +3787 +4460 +4687 +7923 +1140 +9106 +796 +2482 +9170 +8695 +2749 +6734 +4825 +114 +8319 +827 +4175 +390 +7611 +7484 +1249 +7727 +955 +579 +3629 +8915 +2958 +885 +7227 +1424 +4810 +4604 +1535 +774 +7518 +5428 +1955 +8233 +2645 +2167 +6484 +3855 +1502 +4861 +2333 +2973 +4829 +1906 +3966 +476 +9023 +6960 +3483 +2748 +5891 +8174 +7702 +8948 +5324 +4396 +1605 +2823 +7348 +7347 +5933 +310 +9082 +916 +4255 +203 +4239 +5976 +6200 +6435 +4425 +787 +1121 +6034 +13 +39 +3104 +5961 +5507 +5785 +1463 +7339 +1575 +7801 +5445 +8283 +5951 +6995 +999 +5163 +6023 +3786 +6536 +5850 +3524 +3528 +4508 +6674 +2939 +8227 +4598 +7550 +8495 +8622 +1152 +4538 +4003 +1318 +739 +3296 +8202 +1552 +6204 +5236 +3576 +4699 +9238 +1879 +488 +2274 +433 +5587 +1678 +9282 +7914 +8552 +6445 +7971 +8331 +6880 +7476 +7282 +1570 +7271 +3827 +6489 +8091 +9287 +7351 +1765 +5286 +6921 +542 +1762 +8553 +4987 +894 +3622 +7855 +92 +3131 +4811 +3590 +6517 +4510 +733 +4954 +1360 +5669 +2842 +8107 +5646 +5968 +1618 +1827 +7709 +8521 +5807 +5321 +9239 +5501 +3745 +4437 +1586 +7273 +5265 +6605 +7917 +1607 +6074 +4668 +7061 +1580 +8694 +8461 +4573 +618 +9173 +5243 +435 +8770 +2421 +7450 +3870 +8308 +2605 +2934 +9240 +6887 +4512 +1198 +7585 +7691 +7738 +2843 +8423 +7929 +6971 +7854 +86 +9128 +4298 +622 +790 +9155 +6579 +2203 +7716 +1265 +8645 +3834 +1174 +7380 +623 +8936 +4306 +8082 +4312 +8661 +5753 +7243 +2768 +8155 +85 +4143 +3047 +8479 +7809 +2833 +5555 +7578 +1637 +1936 +8130 +5549 +8062 +7143 +5522 +8966 +5614 +8105 +8719 +7655 +7502 +8268 +5760 +6695 +5565 +7615 +9226 +4870 +4507 +3160 +4835 +1598 +2465 +4422 +5248 +7867 +1078 +5015 +6660 +1676 +5354 +6391 +5351 +7184 +6280 +5936 +6124 +1327 +2906 +269 +8292 +2466 +8809 +5167 +8142 +8204 +2713 +1910 +2930 +2494 +5592 +7384 +7726 +5727 +625 +1735 +5710 +5518 +2491 +1410 +4989 +5183 +8777 +6562 +4947 +3692 +6129 +384 +1097 +2084 +5209 +3723 +7272 +6895 +2459 +543 +8621 +5394 +6211 +2074 +1511 +2524 +7776 +5055 +7191 +6207 +7922 +281 +8436 +2918 +3141 +4800 +6323 +7631 +8903 +2716 +3735 +3012 +5301 +3975 +2800 +7963 +105 +1920 +7391 +4909 +1754 +4816 +5488 +5145 +5098 +5139 +5268 +9317 +8631 +4346 +7318 +136 +3993 +1220 +2151 +308 +7483 +7582 +3071 +1339 +3777 +8191 +5378 +7087 +1056 +7465 +5608 +6564 +512 +2754 +2687 +1596 +5376 +1512 +566 +6382 +7360 +1757 +8035 +2296 +4264 +3551 +1053 +4716 +1537 +8518 +254 +6253 +7132 +8557 +3490 +9267 +5473 +2412 +7539 +7136 +6670 +3974 +891 +1323 +5958 +1217 +2879 +9118 +1259 +2317 +7033 +2467 +6665 +6244 +2180 +2140 +7098 +5126 +6395 +4150 +547 +4120 +4307 +1725 +2737 +8549 +8195 +1245 +6286 +935 +1756 +1701 +1626 +7379 +3492 +3717 +5802 +2817 +1234 +1005 +4101 +21 +2576 +4650 +3381 +1030 +2844 +1641 +936 +2729 +6469 +8913 +8369 +5994 +341 +81 +4083 +1685 +5152 +3380 +8739 +6615 +3829 +164 +7927 +4779 +829 +4216 +8528 +3641 +4606 +2769 +6970 +1545 +8850 +4971 +5489 +2008 +4564 +8682 +7784 +5768 +9252 +901 +438 +3577 +2765 +5904 +664 +3348 +6298 +3602 +2502 +8617 +7684 +4293 +5166 +5805 +4126 +2451 +6906 +7234 +9243 +3778 +2940 +1087 +9053 +5026 +2504 +5283 +2820 +4242 +797 +3925 +1383 +8750 +7861 +1403 +6973 +7617 +968 +3065 +5395 +4347 +8144 +2688 +6527 +8597 +8673 +7327 +6331 +1422 +7115 +244 +7013 +2092 +54 +7970 +5742 +3464 +4823 +8588 +2938 +3060 +6406 +4149 +2375 +6616 +8803 +1555 +4369 +1380 +3011 +6144 +3367 +4990 +7370 +7131 +1995 +2602 +985 +8785 +8480 +9125 +1927 +3269 +3771 +1032 +7378 +6900 +5726 +2731 +2020 +4503 +3313 +6727 +8793 +2304 +523 +6036 +58 +7993 +5512 +5049 +2721 +8482 +673 +7937 +1168 +4472 +8247 +7287 +9017 +6421 +9190 +3584 +1819 +1792 +2810 +6033 +638 +6749 +7677 +981 +7160 +4726 +1886 +7845 +7911 +6975 +568 +7422 +4613 +4501 +2569 +4263 +3206 +4133 +2420 +3706 +8894 +2263 +5774 +4925 +9180 +8888 +2945 +2091 +1873 +6303 +729 +6728 +2156 +3267 +1860 +6597 +1374 +4930 +5253 +938 +580 +5825 +4839 +166 +8198 +6892 +8701 +74 +7094 +7284 +8954 +3156 +6140 +4279 +5594 +2229 +7535 +5466 +8413 +7105 +8192 +2632 +7638 +9308 +8530 +832 +4643 +2201 +3268 +4322 +6510 +2967 +262 +403 +7973 +1258 +8828 +4036 +5838 +9263 +8529 +2788 +4202 +237 +3838 +1291 +2305 +4056 +5628 +7281 +1430 +6476 +7935 +2850 +6041 +2013 +4016 +4576 +5312 +6827 +6321 +8669 +8439 +830 +1942 +1519 +2750 +6106 +6993 +6235 +5899 +7313 +5331 +4371 +7086 +4399 +8600 +2660 +5409 +3465 +5499 +6231 +5745 +1801 +5337 +4468 +1451 +4192 +1275 +8230 +2302 +1114 +4960 +8860 +3900 +6468 +5058 +1505 +8868 +5588 +3858 +1947 +2565 +1472 +8499 +243 +8442 +6583 +7085 +5374 +2250 +4291 +4426 +492 +2311 +8305 +3662 +5338 +8780 +7488 +3890 +5005 +2442 +4680 +7358 +9116 +4397 +5999 +587 +7902 +83 +3566 +2134 +8942 +4767 +6601 +2456 +1745 +5736 +5254 +8017 +4015 +7690 +3798 +8947 +1067 +2116 +7945 +590 +2547 +2535 +64 +2053 +5359 +2493 +6669 +4351 +6412 +7473 +6147 +7175 +6983 +5196 +745 +2657 +3497 +697 +3161 +7528 +2239 +5991 +3201 +7681 +2440 +5189 +2959 +2044 +8917 +2046 +6313 +6333 +5318 +2763 +4301 +2555 +2213 +2933 +4121 +1340 +3903 +4392 +7889 +5323 +1055 +707 +3857 +518 +6078 +5134 +6645 +9138 +1592 +680 +4446 +7943 +3461 +3887 +5601 +2321 +6621 +558 +4914 +913 +5637 +6453 +8511 +4531 +1218 +5508 +2603 +6802 +8426 +8297 +2947 +5971 +6552 +5262 +5935 +782 +7435 +8357 +6139 +1136 +1473 +5008 +3585 +3627 +2914 +5356 +2997 +2347 +881 +5652 +4849 +8808 +8351 +4017 +2010 +6836 +7616 +4391 +3630 +3712 +6099 +2969 +5238 +4333 +2301 +4406 +1236 +1050 +1864 +1104 +8408 +8251 +8795 +5879 +3365 +7481 +8206 +2452 +1767 +8859 +124 +3948 +4444 +8962 +4438 +5003 +1740 +8428 +3105 +5117 +1095 +1480 +8755 +7881 +3097 +4877 +155 +1917 +2455 +6042 +337 +6724 +6045 +8483 +7135 +2242 +4566 +1679 +834 +1746 +795 +3548 +2314 +2036 +4046 +9129 +6979 +7084 +5091 +2413 +8170 +5775 +1817 +529 +7220 +813 +2916 +5130 +8972 +126 +1243 +2370 +4831 +9122 +3010 +5104 +2613 +6761 +7482 +909 +2146 +4595 +5340 +3512 +6283 +2346 +653 +6121 +2615 +7421 +1869 +1002 +8834 +2991 +8992 +632 +1093 +4543 +645 +2352 +4115 +373 +1483 +6966 +8598 +3896 +3434 +5987 +8318 +1815 +1223 +1548 +6885 +5073 +6330 +2573 +1369 +4095 +1431 +2185 +5766 +1301 +7258 +8048 +7598 +2847 +1996 +2378 +8561 +743 +6381 +271 +1956 +7439 +7596 +7134 +6636 +5804 +1858 +6214 +4730 +8536 +1203 +3118 +9202 +1875 +5885 +8975 +168 +5898 +4014 +4186 +3346 +3041 +5558 +9296 +8157 +4339 +3234 +1738 +2604 +6803 +5387 +5590 +125 +2173 +8012 +8005 +4858 +3069 +651 +372 +378 +8366 +6299 +1449 +7793 +8541 +3235 +8043 +3086 +3983 +6949 +4690 +2176 +6494 +7637 +8406 +3856 +7408 +350 +7021 +8224 +7044 +7662 +6697 +7679 +169 +528 +7029 +2790 +7138 +7432 +7602 +8333 +1582 +1378 +519 +482 +9279 +8015 +6592 +4514 +3542 +2612 +628 +5053 +6699 +6227 +2094 +1621 +847 +3598 +2728 +8490 +7276 +6620 +8345 +9216 +4278 +4059 +9058 +5063 +5816 +4173 +8134 +1997 +3182 +3224 +8129 +5109 +4494 +189 +7640 +8243 +180 +2963 +1123 +5593 +3263 +4185 +7140 +8990 +6320 +9275 +4601 +4854 +5907 +1135 +8083 +5964 +7788 +1992 +8069 +9174 +6160 +35 +8572 +2865 +46 +3952 +6418 +2510 +5783 +20 +3816 +2715 +3930 +2548 +5204 +4122 +4103 +708 +7756 +3825 +777 +3550 +8502 +3929 +5440 +6751 +7764 +4070 +7331 +3743 +9131 +9206 +3828 +23 +41 +4197 +234 +5723 +7622 +8832 +4626 +2169 +5599 +2976 +5266 +1967 +1150 +5334 +90 +822 +2538 +3169 +6771 +7442 +498 +4967 +5580 +7581 +7680 +4728 +1115 +4040 +1064 +3106 +6266 +4415 +9294 +5597 +7059 +197 +7218 +6948 +5690 +4234 +1653 +4485 +4019 +3370 +919 +1330 +6085 +2078 +3768 +5427 +4545 +2435 +8862 +3633 +8145 +5221 +1388 +5913 +8140 +7471 +7156 +6989 +1190 +6832 +2830 +4387 +3454 +7469 +2910 +4526 +5187 +2410 +9223 +6247 +6912 +4681 +1300 +7407 +8612 +6523 +3616 +6894 +7253 +4515 +5874 +5448 +7137 +7957 +1130 +3092 +7054 +3516 +5797 +1000 +2727 +4336 +9090 +6403 +7255 +8919 +6522 +6760 +8898 +4803 +1938 +374 +8686 +9150 +3985 +7045 +3475 +6065 +7991 +1409 +7851 +6671 +6090 +5826 +7857 +1155 +8964 +1117 +7072 +6064 +2497 +4899 +2397 +3189 +2369 +15 +5027 +5754 +8950 +5617 +8391 +914 +6264 +279 +6174 +5184 +3733 +7392 +5278 +2924 +567 +7994 +352 +8084 +2148 +2723 +3359 +70 +1870 +7708 +220 +3994 +9013 +3191 +9220 +4155 +5717 +1110 +2198 +9179 +785 +5325 +4770 +4250 +52 +4634 +5072 +9037 +601 +8036 +7996 +2483 +7232 +8675 +8836 +1279 +5346 +7676 +6104 +1515 +4603 +5607 +7894 +5144 +2628 +68 +440 +3586 +3083 +4830 +4378 +7762 +1134 +4542 +7850 +6296 +2866 +4011 +8751 +4776 +7954 +7102 +5697 +2032 +5729 +5017 +6962 +2051 +1092 +764 +9019 +2759 +8581 +1484 +8618 +912 +2382 +4892 +8447 +8176 +5491 +5695 +5504 +1060 +7064 +709 +578 +4320 +2379 +7649 +8416 +1613 +5344 +7512 +7865 +3037 +6689 +6557 +1569 +5955 +3707 +9168 +8566 +1775 +5950 +6943 +7804 +434 +6179 +9300 +1142 +7947 +6456 +6291 +5789 +6538 +9134 +3049 +5075 +5399 +5161 +1623 +948 +6302 +6063 +7516 +117 +506 +3302 +7146 +355 +3854 +1081 +2827 +1496 +2574 +6167 +3183 +4287 +5482 +1722 +7319 +7277 +3860 +3443 +3298 +8364 +3826 +7254 +2360 +5093 +7039 +6325 +4230 +2567 +6241 +4443 +559 +2625 +4228 +8967 +6405 +1674 +3936 +4475 +8556 +8585 +896 +3713 +6259 +4297 +6718 +2392 +2279 +4927 +1283 +2374 +2860 +7665 +663 +596 +6293 +6805 +2811 +7383 +8306 +8330 +3153 +2153 +2618 +2441 +3615 +8092 +552 +5285 +5255 +8124 +9247 +5530 +8175 +6242 +5660 +3433 +1610 +1832 +3892 +3862 +640 +2127 +2474 +4196 +3495 +7217 +5206 +4836 +7759 +4376 +800 +4227 +3699 +9055 +5665 +6826 +7463 +9065 +4720 +5069 +3245 +3453 +3358 +6532 +5970 +7921 +4087 +1547 +3424 +8040 +7995 +6787 +9069 +8716 +2561 +8199 +1479 +2767 +7818 +7145 +604 +7597 +4896 +9281 +4666 +185 +8171 +7978 +3059 +9196 +9221 +2135 +1800 +2974 +1529 +5948 +446 +4436 +8672 +3508 +6208 +5673 +6998 +5203 +278 +7041 +9110 +5853 +8121 +1764 +3046 +2400 +6575 +4738 +2228 +7761 +9322 +7019 +6931 +6383 +6762 +283 +3935 +2534 +7717 +6785 +471 +8214 +231 +4241 +5310 +3844 +5746 +2011 +7209 +336 +6433 +756 +9167 +6741 +3345 +7685 +4018 +6682 +9147 +4790 +5836 +5906 +8747 +676 +3964 +6362 +3510 +7510 +2308 +1806 +5917 +1189 +4012 +3387 +1331 +5319 +5423 +8900 +147 +3780 +1696 +9111 +6783 +6497 +4104 +1898 +3987 +260 +4616 +2121 +9283 +1400 +2437 +4670 +2735 +1163 +2096 +6521 +1423 +4523 +2243 +6667 +6990 +3944 +6915 +6763 +5611 +404 +2691 +1015 +7092 +7562 +8624 +2291 +4193 +5934 +5503 +2326 +4408 +2960 +842 +1963 +3354 +5568 +9050 +3806 +439 +9154 +6055 +6451 +2190 +7633 +688 +4354 +8890 +2813 +2872 +8102 +8317 +6609 +1497 +8389 +6449 +1682 +3594 +5103 +5812 +863 +268 +3054 +8079 +2260 +2027 +3091 +7687 +6703 +3557 +2019 +8427 +2799 +8182 +6641 +3168 +2284 +1934 +4865 +1077 +6507 +1658 +3811 +1774 +7897 +2238 +2943 +191 +3869 +3246 +4057 +3188 +414 +8072 +7838 +1382 +4962 +6010 +5363 +4042 +1983 +4077 +7429 +1833 +3583 +4044 +1109 +1295 +386 +5481 +3927 +311 diff --git a/ltr/data_specs/got10k_val_split.txt b/ltr/data_specs/got10k_val_split.txt new file mode 100755 index 0000000..340e286 --- /dev/null +++ b/ltr/data_specs/got10k_val_split.txt @@ -0,0 +1,1401 @@ +1349 +5651 +5878 +562 +2202 +8904 +765 +1501 +8654 +2975 +2689 +3680 +5180 +1900 +7707 +4723 +8912 +4029 +3579 +869 +2888 +8657 +6599 +741 +4288 +2244 +7357 +5704 +8791 +208 +8587 +7969 +4805 +8526 +4887 +8871 +7468 +3343 +886 +7794 +5764 +2646 +6454 +6101 +7885 +7744 +1297 +4119 +4856 +122 +2286 +2925 +5131 +3570 +5843 +3027 +5320 +5626 +540 +1862 +5401 +7335 +699 +7760 +9198 +3259 +7345 +8698 +1280 +6479 +3100 +3988 +1322 +5737 +1268 +3257 +6791 +3326 +4815 +7644 +1082 +2826 +6821 +8984 +2553 +5290 +5909 +4762 +9242 +8096 +8066 +4325 +6666 +7193 +7114 +8060 +2376 +7872 +6788 +3544 +5460 +3507 +2509 +6626 +3429 +5542 +4220 +2968 +5271 +4249 +3863 +1868 +5581 +2012 +6270 +8038 +4050 +121 +2845 +1565 +1998 +2275 +5524 +6068 +7624 +4913 +9277 +1506 +803 +8848 +5925 +2450 +2072 +8190 +4753 +9162 +1923 +825 +7303 +9028 +2088 +8516 +1556 +5937 +7847 +2367 +7549 +1049 +1521 +4739 +3931 +8958 +4130 +7877 +7876 +897 +5985 +7346 +7537 +111 +3700 +1126 +7896 +1288 +3419 +4673 +1051 +5720 +1068 +3458 +146 +291 +6256 +5514 +2857 +4580 +6239 +6525 +8717 +391 +4841 +6676 +4360 +1453 +4211 +73 +1675 +1987 +4025 +1321 +662 +8265 +6424 +2758 +7765 +7656 +3209 +7497 +7600 +9039 +7697 +5177 +2983 +5622 +9295 +1200 +3284 +964 +2024 +1269 +4551 +8088 +5659 +2212 +5199 +5551 +8607 +5573 +2247 +5200 +6341 +7951 +8429 +7720 +5919 +1273 +3529 +6707 +9176 +7552 +3255 +5649 +6110 +9235 +1137 +9272 +775 +788 +5786 +5186 +6746 +2667 +9145 +7630 +3953 +1828 +8827 +6471 +4702 +7815 +467 +6387 +3195 +6238 +6508 +2373 +5983 +4931 +2948 +921 +2438 +517 +3949 +2137 +3216 +5683 +3695 +1719 +4837 +9159 +6981 +860 +7410 +5497 +1770 +5557 +8810 +5194 +4857 +9100 +6329 +2609 +1925 +3686 +9041 +4924 +349 +9187 +3393 +3661 +7120 +6858 +4587 +3831 +3130 +5396 +5060 +6486 +3937 +8023 +824 +5398 +1354 +8861 +5534 +7292 +4389 +6029 +6226 +3505 +4326 +7445 +581 +6089 +3450 +7324 +6516 +6775 +1207 +4575 +5135 +9265 +3918 +9020 +3473 +3898 +7812 +6571 +6757 +6639 +2557 +1206 +6148 +7325 +8790 +4938 +7026 +4383 +8041 +1250 +7267 +1952 +7561 +8811 +4941 +8373 +4848 +6602 +8355 +8104 +5214 +6654 +4330 +995 +3181 +3422 +456 +1782 +3408 +6530 +719 +7587 +5910 +3058 +740 +2009 +4207 +5336 +2798 +9229 +8668 +2473 +4221 +1493 +3281 +171 +9157 +9139 +7766 +6220 +9127 +3324 +5308 +3708 +2431 +8080 +2093 +2585 +406 +7040 +5064 +5247 +4758 +6512 +2953 +4257 +4935 +2705 +2572 +3436 +8513 +5884 +1385 +4852 +2637 +7091 +2761 +6007 +8332 +6694 +2422 +4917 +2186 +6898 +1390 +6965 +3132 +7698 +475 +2002 +2692 +5024 +7365 +7373 +4091 +1731 +947 +3962 +8692 +1788 +8734 +8656 +6862 +6856 +1950 +1914 +5658 +3635 +1620 +4780 +2580 +1454 +2786 +687 +7238 +3648 +6452 +1197 +3190 +5900 +9043 +4958 +1935 +1821 +1187 +1153 +7737 +7223 +3820 +7169 +7350 +5674 +6254 +3025 +6680 +1690 +2899 +3893 +1577 +5728 +9189 +5077 +34 +3560 +2179 +5462 +1402 +3654 +1376 +7936 +4246 +5506 +1179 +5647 +4686 +8644 +1352 +2855 +6079 +2254 +2668 +2287 +2457 +3418 +7264 +677 +3074 +2655 +1042 +2210 +4504 +7089 +8309 +4209 +4280 +3258 +2977 +84 +4705 +1244 +3511 +6355 +8813 +3228 +9266 +1122 +613 +732 +5202 +8425 +2638 +6470 +2886 +3541 +8132 +2063 +8201 +5129 +2818 +7949 +6936 +8090 +4465 +7295 +5239 +7009 +9271 +8563 +2832 +952 +8136 +6776 +3565 +5188 +7288 +6999 +285 +5487 +7763 +7608 +8584 +2071 +7868 +2804 +3655 +7048 +6847 +3276 +4082 +4272 +3910 +3709 +1574 +4559 +7580 +7081 +5014 +7769 +8183 +6386 +7574 +356 +4937 +2487 +9315 +7572 +3040 +671 +2682 +8626 +3868 +8623 +387 +8679 +4074 +1481 +3527 +3595 +4754 +2453 +1579 +4638 +9123 +1829 +316 +3009 +3691 +763 +4875 +3572 +4642 +3128 +4273 +2777 +6032 +4793 +233 +7147 +996 +3199 +8835 +3517 +7210 +6125 +6037 +3684 +8589 +3915 +3095 +8310 +3180 +7043 +4458 +2889 +57 +4483 +7667 +8375 +1434 +7493 +6986 +4733 +8471 +5827 +2111 +1313 +7986 +3075 +2614 +7547 +4977 +8527 +3212 +7300 +5842 +5244 +3291 +597 +1007 +2030 +227 +3830 +5540 +247 +5643 +9333 +1958 +3096 +1371 +5220 +7926 +2927 +1516 +7130 +193 +1522 +6165 +6923 +3794 +4223 +5535 +2472 +8630 +3971 +9101 +2946 +222 +4609 +7291 +8542 +6501 +7548 +4557 +6274 +1010 +5226 +7309 +1317 +9056 +6275 +1624 +1099 +4191 +4030 +7270 +5392 +2316 +3819 +1670 +8154 +8045 +4807 +8864 +2391 +5908 +8338 +8218 +6400 +9193 +3165 +843 +6613 +6941 +4380 +9332 +5629 +7557 +4321 +3702 +681 +734 +1159 +4665 +5959 +1697 +5509 +8774 +7389 +3832 +3751 +8637 +3079 +1680 +6841 +703 +684 +8293 +3682 +5733 +4818 +3231 +3078 +5562 +9001 +3889 +7024 +2519 +1713 +3287 +219 +6021 +8776 +2289 +7212 +4832 +4684 +4617 +4237 +2649 +8185 +6326 +3568 +551 +1426 +4181 +8869 +312 +2905 +4165 +8248 +2558 +900 +1044 +8613 +7743 +5437 +7604 +3122 +5708 +8649 +2878 +4695 +4491 +1929 +7533 +5223 +7711 +915 +1844 +5751 +3008 +8055 +961 +6142 +4636 +61 +198 +2271 +5698 +4596 +4500 +5709 +5819 +7972 +2992 +1643 +1048 +6281 +8886 +360 +4198 +1841 +6814 +3960 +2606 +7001 +5888 +450 +7133 +7015 +7034 +5153 +8920 +5066 +469 +1302 +8816 +463 +8651 +5869 +8193 +6582 +5578 +1231 +9274 +7260 +7751 +8052 +6799 +2089 +2342 +8451 +3260 +5550 +7795 +2288 +1205 +40 +496 +8367 +7836 +5973 +3908 +5242 +5062 +2706 +997 +6514 +5419 +9201 +1965 +6062 +3050 +5302 +8735 +358 +2398 +7470 +1644 +8179 +7047 +1549 +5414 +2539 +7381 +589 +8166 +8505 +6035 +3956 +4540 +6721 +8074 +1062 +2384 +2531 +7159 +3502 +3902 +4584 +2554 +264 +8720 +2849 +4916 +5218 +7202 +883 +4560 +1677 +4317 +7863 +4509 +6577 +2903 +1452 +1416 +5369 +473 +6233 +6359 +5992 +4934 +8059 +6834 +4907 +3320 +8267 +8280 +2066 +2402 +1485 +3772 +3732 +4764 +9126 +3575 +5564 +4768 +5641 +1884 +2330 +1804 +344 +698 +3089 +1532 +4454 +761 +7289 +8094 +3432 +1747 +6811 +8722 +8826 +4646 +3222 +8614 +2901 +7003 +652 +8663 +4266 +413 +810 +75 +3334 +4905 +6438 +4756 +5137 +6528 +6534 +6988 +6177 +8533 +889 +5384 +7201 +5132 +7802 +6864 +3973 +873 +4840 +1482 +8376 +3769 +5858 +6675 +4286 +2593 +5863 +4353 +7817 +7540 +4999 +4838 +2303 +6002 +7913 +1508 +5317 +7755 +2784 +4964 +3431 +6209 +3755 +6022 +6399 +6232 +3954 +455 +5416 +6448 +1558 +7591 +245 +140 +9210 +6585 +4084 +967 +7798 +6795 +7095 +6733 +3861 +9264 +361 +1045 +755 +8042 +7074 +7778 +6415 +4724 +6450 +2049 +1563 +1307 +3485 +1790 +7869 +3282 +6907 +3920 +2868 +5801 +5632 +1079 +5009 +3955 +7517 +5128 +3417 +3019 +2725 +1784 +2312 +2753 +6976 +342 +8266 +1849 +2273 +5037 +7880 +3793 +7401 +5412 +8279 +1257 +3670 +9049 +3266 +8955 +6519 +8916 +2858 +694 +5650 +1019 +4669 +1785 +3533 +5877 +2704 +8603 +3726 +6668 +497 +1085 +6815 +6157 +6646 +6964 +186 +8097 +5645 +8481 +8215 +3775 +2542 +7514 +5699 +4072 +3518 +5767 +3239 +3740 +1404 +8981 +4086 +6397 +6984 +4204 +6899 +682 +6589 +3317 +2944 +3456 +4340 +7424 +9208 +6504 +4409 +1 +145 +1882 +4620 +2634 +4992 +5453 +4481 +3377 +266 +7875 +530 +1235 +7605 +504 +1771 +8489 +345 +7353 +7797 +7174 +5914 +2871 +5721 +6067 +3582 +7653 +5467 +6234 +691 +8758 +2122 +1213 +2908 +1492 +1437 +2187 +1266 +2395 +7278 +8491 +5256 +1554 +8163 +5966 +7128 +7904 +1691 +6272 +1264 +3996 +1706 +1334 +1316 +6478 +6935 +1518 +6700 +8703 +8744 +8152 +8778 +5367 +4218 +9007 +6312 +606 +7565 +5293 +2891 +675 +2125 +2120 +826 +7008 +5705 +7748 +8010 +1498 +5330 +5472 +2215 +7627 +3016 +6588 +1850 +4128 +8569 +6987 +7566 +148 +8151 +8789 +7907 +8596 +715 +6018 +9060 +3872 +1750 +5889 +4047 +5960 +3120 +3449 +1421 +1102 +3333 +9197 +8796 +8123 +8007 +2028 +8404 +1945 +1985 +8109 +5380 +8438 +3504 +6739 +4180 +5835 +4243 +25 +4002 +1976 +3482 +8392 +158 +5181 +4885 +8985 +11 +6872 +6425 +5926 +7062 +5083 +8394 +4259 +5844 +1990 +3942 +5532 +2220 +28 +5957 +149 +6748 +1663 +3559 +7647 +2566 +1359 +8787 +5259 +7010 +554 +8231 +4229 +6005 +8172 +8125 +1350 +3571 +9051 +1973 +1386 +1781 +5788 +159 +7007 +3220 +1846 +3093 +4445 +2056 +8370 +3211 +1113 +4384 +2231 +273 +4276 +642 +7663 +5311 +265 +226 +9012 +7879 +118 +7109 +7251 +1760 +8667 +2876 +7162 +3552 +6901 +6779 +5021 +6524 +4957 +3114 +4544 +441 +1848 +2136 +2458 +8662 +1127 +5541 +3026 +1080 +6780 +2224 +8259 +1073 +9000 +7244 +7977 +500 +4435 +7376 +7979 +1435 +9291 +7704 +3791 +3521 +210 +7388 +1039 +6269 +4052 +8570 +3285 +564 +8039 +3546 +6203 +1183 +6107 +4147 +6216 +2234 +7185 +3192 +7155 +2001 +7777 +876 +944 +908 +7791 +5465 +6784 +65 +9172 +5675 +7075 +3886 +7891 +2978 +1008 +5630 +591 +5067 +1139 +577 +9015 +574 +8137 +7786 +5765 +4900 +4090 +7842 +5741 diff --git a/ltr/data_specs/got10k_vot_exclude.txt b/ltr/data_specs/got10k_vot_exclude.txt new file mode 100755 index 0000000..7e7291a --- /dev/null +++ b/ltr/data_specs/got10k_vot_exclude.txt @@ -0,0 +1,1000 @@ +GOT-10k_Train_000004 +GOT-10k_Train_000013 +GOT-10k_Train_000015 +GOT-10k_Train_000020 +GOT-10k_Train_000024 +GOT-10k_Train_000034 +GOT-10k_Train_000038 +GOT-10k_Train_000048 +GOT-10k_Train_000051 +GOT-10k_Train_000059 +GOT-10k_Train_000077 +GOT-10k_Train_000081 +GOT-10k_Train_000089 +GOT-10k_Train_000093 +GOT-10k_Train_000094 +GOT-10k_Train_000096 +GOT-10k_Train_000104 +GOT-10k_Train_000107 +GOT-10k_Train_000108 +GOT-10k_Train_000120 +GOT-10k_Train_000132 +GOT-10k_Train_000170 +GOT-10k_Train_000186 +GOT-10k_Train_000212 +GOT-10k_Train_000213 +GOT-10k_Train_000222 +GOT-10k_Train_000223 +GOT-10k_Train_000240 +GOT-10k_Train_000246 +GOT-10k_Train_000249 +GOT-10k_Train_000266 +GOT-10k_Train_000268 +GOT-10k_Train_000287 +GOT-10k_Train_000293 +GOT-10k_Train_000305 +GOT-10k_Train_000316 +GOT-10k_Train_000319 +GOT-10k_Train_000322 +GOT-10k_Train_000331 +GOT-10k_Train_000334 +GOT-10k_Train_000354 +GOT-10k_Train_000361 +GOT-10k_Train_000368 +GOT-10k_Train_000382 +GOT-10k_Train_000401 +GOT-10k_Train_000417 +GOT-10k_Train_000448 +GOT-10k_Train_000454 +GOT-10k_Train_000458 +GOT-10k_Train_000466 +GOT-10k_Train_000475 +GOT-10k_Train_000484 +GOT-10k_Train_000488 +GOT-10k_Train_000501 +GOT-10k_Train_000510 +GOT-10k_Train_000512 +GOT-10k_Train_000519 +GOT-10k_Train_000539 +GOT-10k_Train_000544 +GOT-10k_Train_000555 +GOT-10k_Train_000564 +GOT-10k_Train_000568 +GOT-10k_Train_000583 +GOT-10k_Train_000587 +GOT-10k_Train_000593 +GOT-10k_Train_000621 +GOT-10k_Train_000624 +GOT-10k_Train_000625 +GOT-10k_Train_000638 +GOT-10k_Train_000648 +GOT-10k_Train_000654 +GOT-10k_Train_000669 +GOT-10k_Train_000701 +GOT-10k_Train_000709 +GOT-10k_Train_000712 +GOT-10k_Train_000731 +GOT-10k_Train_000734 +GOT-10k_Train_000737 +GOT-10k_Train_000744 +GOT-10k_Train_000746 +GOT-10k_Train_000748 +GOT-10k_Train_000762 +GOT-10k_Train_000764 +GOT-10k_Train_000765 +GOT-10k_Train_000766 +GOT-10k_Train_000767 +GOT-10k_Train_000775 +GOT-10k_Train_000783 +GOT-10k_Train_000790 +GOT-10k_Train_000829 +GOT-10k_Train_000857 +GOT-10k_Train_000859 +GOT-10k_Train_000867 +GOT-10k_Train_000872 +GOT-10k_Train_000880 +GOT-10k_Train_000884 +GOT-10k_Train_000909 +GOT-10k_Train_000915 +GOT-10k_Train_000922 +GOT-10k_Train_000928 +GOT-10k_Train_000933 +GOT-10k_Train_000941 +GOT-10k_Train_000961 +GOT-10k_Train_000966 +GOT-10k_Train_000968 +GOT-10k_Train_000971 +GOT-10k_Train_000972 +GOT-10k_Train_000995 +GOT-10k_Train_001003 +GOT-10k_Train_001010 +GOT-10k_Train_001011 +GOT-10k_Train_001019 +GOT-10k_Train_001021 +GOT-10k_Train_001035 +GOT-10k_Train_001039 +GOT-10k_Train_001047 +GOT-10k_Train_001057 +GOT-10k_Train_001069 +GOT-10k_Train_001077 +GOT-10k_Train_001079 +GOT-10k_Train_001085 +GOT-10k_Train_001088 +GOT-10k_Train_001091 +GOT-10k_Train_001104 +GOT-10k_Train_001112 +GOT-10k_Train_001113 +GOT-10k_Train_001124 +GOT-10k_Train_001128 +GOT-10k_Train_001143 +GOT-10k_Train_001145 +GOT-10k_Train_001146 +GOT-10k_Train_001148 +GOT-10k_Train_001150 +GOT-10k_Train_001154 +GOT-10k_Train_001156 +GOT-10k_Train_001157 +GOT-10k_Train_001163 +GOT-10k_Train_001181 +GOT-10k_Train_001184 +GOT-10k_Train_001189 +GOT-10k_Train_001200 +GOT-10k_Train_001225 +GOT-10k_Train_001264 +GOT-10k_Train_001288 +GOT-10k_Train_001296 +GOT-10k_Train_001298 +GOT-10k_Train_001299 +GOT-10k_Train_001314 +GOT-10k_Train_001319 +GOT-10k_Train_001329 +GOT-10k_Train_001331 +GOT-10k_Train_001340 +GOT-10k_Train_001374 +GOT-10k_Train_001384 +GOT-10k_Train_001394 +GOT-10k_Train_001407 +GOT-10k_Train_001415 +GOT-10k_Train_001430 +GOT-10k_Train_001433 +GOT-10k_Train_001453 +GOT-10k_Train_001457 +GOT-10k_Train_001471 +GOT-10k_Train_001473 +GOT-10k_Train_001480 +GOT-10k_Train_001484 +GOT-10k_Train_001489 +GOT-10k_Train_001514 +GOT-10k_Train_001537 +GOT-10k_Train_001544 +GOT-10k_Train_001545 +GOT-10k_Train_001551 +GOT-10k_Train_001558 +GOT-10k_Train_001560 +GOT-10k_Train_001562 +GOT-10k_Train_001563 +GOT-10k_Train_001570 +GOT-10k_Train_001576 +GOT-10k_Train_001604 +GOT-10k_Train_001615 +GOT-10k_Train_001617 +GOT-10k_Train_001618 +GOT-10k_Train_001619 +GOT-10k_Train_001624 +GOT-10k_Train_001650 +GOT-10k_Train_001651 +GOT-10k_Train_001663 +GOT-10k_Train_001673 +GOT-10k_Train_001685 +GOT-10k_Train_001692 +GOT-10k_Train_001700 +GOT-10k_Train_001722 +GOT-10k_Train_001731 +GOT-10k_Train_001732 +GOT-10k_Train_001738 +GOT-10k_Train_001740 +GOT-10k_Train_001742 +GOT-10k_Train_001747 +GOT-10k_Train_001759 +GOT-10k_Train_001769 +GOT-10k_Train_001781 +GOT-10k_Train_001791 +GOT-10k_Train_001794 +GOT-10k_Train_001795 +GOT-10k_Train_001818 +GOT-10k_Train_001833 +GOT-10k_Train_001836 +GOT-10k_Train_001841 +GOT-10k_Train_001852 +GOT-10k_Train_001863 +GOT-10k_Train_001865 +GOT-10k_Train_001878 +GOT-10k_Train_001898 +GOT-10k_Train_001919 +GOT-10k_Train_001923 +GOT-10k_Train_001929 +GOT-10k_Train_001935 +GOT-10k_Train_001938 +GOT-10k_Train_001942 +GOT-10k_Train_001955 +GOT-10k_Train_001964 +GOT-10k_Train_001966 +GOT-10k_Train_001982 +GOT-10k_Train_002005 +GOT-10k_Train_002009 +GOT-10k_Train_002035 +GOT-10k_Train_002068 +GOT-10k_Train_002073 +GOT-10k_Train_002076 +GOT-10k_Train_002084 +GOT-10k_Train_002112 +GOT-10k_Train_002115 +GOT-10k_Train_002116 +GOT-10k_Train_002123 +GOT-10k_Train_002125 +GOT-10k_Train_002129 +GOT-10k_Train_002139 +GOT-10k_Train_002146 +GOT-10k_Train_002166 +GOT-10k_Train_002168 +GOT-10k_Train_002176 +GOT-10k_Train_002184 +GOT-10k_Train_002190 +GOT-10k_Train_002192 +GOT-10k_Train_002211 +GOT-10k_Train_002216 +GOT-10k_Train_002233 +GOT-10k_Train_002240 +GOT-10k_Train_002247 +GOT-10k_Train_002250 +GOT-10k_Train_002252 +GOT-10k_Train_002253 +GOT-10k_Train_002261 +GOT-10k_Train_002274 +GOT-10k_Train_002276 +GOT-10k_Train_002292 +GOT-10k_Train_002302 +GOT-10k_Train_002304 +GOT-10k_Train_002305 +GOT-10k_Train_002320 +GOT-10k_Train_002345 +GOT-10k_Train_002355 +GOT-10k_Train_002359 +GOT-10k_Train_002363 +GOT-10k_Train_002374 +GOT-10k_Train_002376 +GOT-10k_Train_002389 +GOT-10k_Train_002393 +GOT-10k_Train_002400 +GOT-10k_Train_002408 +GOT-10k_Train_002418 +GOT-10k_Train_002437 +GOT-10k_Train_002440 +GOT-10k_Train_002442 +GOT-10k_Train_002454 +GOT-10k_Train_002456 +GOT-10k_Train_002465 +GOT-10k_Train_002466 +GOT-10k_Train_002474 +GOT-10k_Train_002479 +GOT-10k_Train_002484 +GOT-10k_Train_002511 +GOT-10k_Train_002514 +GOT-10k_Train_002517 +GOT-10k_Train_002523 +GOT-10k_Train_002527 +GOT-10k_Train_002534 +GOT-10k_Train_002555 +GOT-10k_Train_002587 +GOT-10k_Train_002589 +GOT-10k_Train_002612 +GOT-10k_Train_002627 +GOT-10k_Train_002639 +GOT-10k_Train_002652 +GOT-10k_Train_002693 +GOT-10k_Train_002699 +GOT-10k_Train_002716 +GOT-10k_Train_002725 +GOT-10k_Train_002727 +GOT-10k_Train_002730 +GOT-10k_Train_002755 +GOT-10k_Train_002756 +GOT-10k_Train_002760 +GOT-10k_Train_002763 +GOT-10k_Train_002837 +GOT-10k_Train_002841 +GOT-10k_Train_002856 +GOT-10k_Train_002862 +GOT-10k_Train_002863 +GOT-10k_Train_002866 +GOT-10k_Train_002877 +GOT-10k_Train_002884 +GOT-10k_Train_002886 +GOT-10k_Train_002887 +GOT-10k_Train_002907 +GOT-10k_Train_002908 +GOT-10k_Train_002909 +GOT-10k_Train_002914 +GOT-10k_Train_002920 +GOT-10k_Train_002922 +GOT-10k_Train_002936 +GOT-10k_Train_002940 +GOT-10k_Train_002944 +GOT-10k_Train_002953 +GOT-10k_Train_002961 +GOT-10k_Train_002964 +GOT-10k_Train_002996 +GOT-10k_Train_003003 +GOT-10k_Train_003004 +GOT-10k_Train_003007 +GOT-10k_Train_003012 +GOT-10k_Train_003027 +GOT-10k_Train_003028 +GOT-10k_Train_003033 +GOT-10k_Train_003034 +GOT-10k_Train_003036 +GOT-10k_Train_003044 +GOT-10k_Train_003056 +GOT-10k_Train_003069 +GOT-10k_Train_003078 +GOT-10k_Train_003079 +GOT-10k_Train_003095 +GOT-10k_Train_003096 +GOT-10k_Train_003107 +GOT-10k_Train_003108 +GOT-10k_Train_003127 +GOT-10k_Train_003128 +GOT-10k_Train_003129 +GOT-10k_Train_003132 +GOT-10k_Train_003146 +GOT-10k_Train_003155 +GOT-10k_Train_003173 +GOT-10k_Train_003208 +GOT-10k_Train_003239 +GOT-10k_Train_003245 +GOT-10k_Train_003246 +GOT-10k_Train_003262 +GOT-10k_Train_003275 +GOT-10k_Train_003283 +GOT-10k_Train_003296 +GOT-10k_Train_003308 +GOT-10k_Train_003310 +GOT-10k_Train_003313 +GOT-10k_Train_003317 +GOT-10k_Train_003318 +GOT-10k_Train_003354 +GOT-10k_Train_003379 +GOT-10k_Train_003384 +GOT-10k_Train_003396 +GOT-10k_Train_003401 +GOT-10k_Train_003423 +GOT-10k_Train_003435 +GOT-10k_Train_003438 +GOT-10k_Train_003442 +GOT-10k_Train_003444 +GOT-10k_Train_003455 +GOT-10k_Train_003456 +GOT-10k_Train_003464 +GOT-10k_Train_003466 +GOT-10k_Train_003474 +GOT-10k_Train_003482 +GOT-10k_Train_003488 +GOT-10k_Train_003502 +GOT-10k_Train_003515 +GOT-10k_Train_003520 +GOT-10k_Train_003530 +GOT-10k_Train_003551 +GOT-10k_Train_003570 +GOT-10k_Train_003571 +GOT-10k_Train_003578 +GOT-10k_Train_003583 +GOT-10k_Train_003590 +GOT-10k_Train_003593 +GOT-10k_Train_003618 +GOT-10k_Train_003626 +GOT-10k_Train_003650 +GOT-10k_Train_003652 +GOT-10k_Train_003663 +GOT-10k_Train_003690 +GOT-10k_Train_003704 +GOT-10k_Train_003709 +GOT-10k_Train_003716 +GOT-10k_Train_003721 +GOT-10k_Train_003722 +GOT-10k_Train_003724 +GOT-10k_Train_003729 +GOT-10k_Train_003756 +GOT-10k_Train_003768 +GOT-10k_Train_003782 +GOT-10k_Train_003786 +GOT-10k_Train_003788 +GOT-10k_Train_003791 +GOT-10k_Train_003820 +GOT-10k_Train_003821 +GOT-10k_Train_003827 +GOT-10k_Train_003834 +GOT-10k_Train_003835 +GOT-10k_Train_003839 +GOT-10k_Train_003843 +GOT-10k_Train_003854 +GOT-10k_Train_003856 +GOT-10k_Train_003881 +GOT-10k_Train_003899 +GOT-10k_Train_003904 +GOT-10k_Train_003906 +GOT-10k_Train_003913 +GOT-10k_Train_003937 +GOT-10k_Train_003940 +GOT-10k_Train_003943 +GOT-10k_Train_003950 +GOT-10k_Train_003972 +GOT-10k_Train_003974 +GOT-10k_Train_003978 +GOT-10k_Train_003981 +GOT-10k_Train_003982 +GOT-10k_Train_004003 +GOT-10k_Train_004004 +GOT-10k_Train_004008 +GOT-10k_Train_004012 +GOT-10k_Train_004013 +GOT-10k_Train_004030 +GOT-10k_Train_004036 +GOT-10k_Train_004040 +GOT-10k_Train_004052 +GOT-10k_Train_004054 +GOT-10k_Train_004055 +GOT-10k_Train_004057 +GOT-10k_Train_004063 +GOT-10k_Train_004068 +GOT-10k_Train_004072 +GOT-10k_Train_004075 +GOT-10k_Train_004078 +GOT-10k_Train_004082 +GOT-10k_Train_004102 +GOT-10k_Train_004103 +GOT-10k_Train_004105 +GOT-10k_Train_004111 +GOT-10k_Train_004120 +GOT-10k_Train_004122 +GOT-10k_Train_004124 +GOT-10k_Train_004142 +GOT-10k_Train_004158 +GOT-10k_Train_004170 +GOT-10k_Train_004175 +GOT-10k_Train_004181 +GOT-10k_Train_004190 +GOT-10k_Train_004193 +GOT-10k_Train_004194 +GOT-10k_Train_004199 +GOT-10k_Train_004202 +GOT-10k_Train_004217 +GOT-10k_Train_004225 +GOT-10k_Train_004229 +GOT-10k_Train_004230 +GOT-10k_Train_004234 +GOT-10k_Train_004241 +GOT-10k_Train_004246 +GOT-10k_Train_004249 +GOT-10k_Train_004255 +GOT-10k_Train_004268 +GOT-10k_Train_004276 +GOT-10k_Train_004292 +GOT-10k_Train_004293 +GOT-10k_Train_004295 +GOT-10k_Train_004296 +GOT-10k_Train_004302 +GOT-10k_Train_004324 +GOT-10k_Train_004337 +GOT-10k_Train_004342 +GOT-10k_Train_004351 +GOT-10k_Train_004356 +GOT-10k_Train_004376 +GOT-10k_Train_004380 +GOT-10k_Train_004395 +GOT-10k_Train_004398 +GOT-10k_Train_004399 +GOT-10k_Train_004408 +GOT-10k_Train_004430 +GOT-10k_Train_004439 +GOT-10k_Train_004440 +GOT-10k_Train_004462 +GOT-10k_Train_004473 +GOT-10k_Train_004476 +GOT-10k_Train_004478 +GOT-10k_Train_004481 +GOT-10k_Train_004483 +GOT-10k_Train_004484 +GOT-10k_Train_004503 +GOT-10k_Train_004513 +GOT-10k_Train_004517 +GOT-10k_Train_004533 +GOT-10k_Train_004536 +GOT-10k_Train_004594 +GOT-10k_Train_004595 +GOT-10k_Train_004607 +GOT-10k_Train_004619 +GOT-10k_Train_004626 +GOT-10k_Train_004642 +GOT-10k_Train_004646 +GOT-10k_Train_004652 +GOT-10k_Train_004658 +GOT-10k_Train_004660 +GOT-10k_Train_004661 +GOT-10k_Train_004668 +GOT-10k_Train_004673 +GOT-10k_Train_004679 +GOT-10k_Train_004694 +GOT-10k_Train_004702 +GOT-10k_Train_004709 +GOT-10k_Train_004717 +GOT-10k_Train_004757 +GOT-10k_Train_004768 +GOT-10k_Train_004824 +GOT-10k_Train_004826 +GOT-10k_Train_004833 +GOT-10k_Train_004839 +GOT-10k_Train_004843 +GOT-10k_Train_004852 +GOT-10k_Train_004862 +GOT-10k_Train_004865 +GOT-10k_Train_004878 +GOT-10k_Train_004880 +GOT-10k_Train_004881 +GOT-10k_Train_004902 +GOT-10k_Train_004906 +GOT-10k_Train_004920 +GOT-10k_Train_004950 +GOT-10k_Train_004951 +GOT-10k_Train_004952 +GOT-10k_Train_004973 +GOT-10k_Train_004983 +GOT-10k_Train_004984 +GOT-10k_Train_004990 +GOT-10k_Train_004993 +GOT-10k_Train_004995 +GOT-10k_Train_005004 +GOT-10k_Train_005007 +GOT-10k_Train_005022 +GOT-10k_Train_005024 +GOT-10k_Train_005040 +GOT-10k_Train_005046 +GOT-10k_Train_005047 +GOT-10k_Train_005058 +GOT-10k_Train_005063 +GOT-10k_Train_005072 +GOT-10k_Train_005097 +GOT-10k_Train_005098 +GOT-10k_Train_005099 +GOT-10k_Train_005108 +GOT-10k_Train_005113 +GOT-10k_Train_005119 +GOT-10k_Train_005126 +GOT-10k_Train_005146 +GOT-10k_Train_005166 +GOT-10k_Train_005191 +GOT-10k_Train_005207 +GOT-10k_Train_005255 +GOT-10k_Train_005269 +GOT-10k_Train_005280 +GOT-10k_Train_005310 +GOT-10k_Train_005317 +GOT-10k_Train_005319 +GOT-10k_Train_005334 +GOT-10k_Train_005338 +GOT-10k_Train_005339 +GOT-10k_Train_005354 +GOT-10k_Train_005364 +GOT-10k_Train_005382 +GOT-10k_Train_005385 +GOT-10k_Train_005389 +GOT-10k_Train_005390 +GOT-10k_Train_005396 +GOT-10k_Train_005398 +GOT-10k_Train_005399 +GOT-10k_Train_005401 +GOT-10k_Train_005413 +GOT-10k_Train_005415 +GOT-10k_Train_005420 +GOT-10k_Train_005457 +GOT-10k_Train_005465 +GOT-10k_Train_005488 +GOT-10k_Train_005493 +GOT-10k_Train_005510 +GOT-10k_Train_005523 +GOT-10k_Train_005538 +GOT-10k_Train_005553 +GOT-10k_Train_005556 +GOT-10k_Train_005575 +GOT-10k_Train_005577 +GOT-10k_Train_005582 +GOT-10k_Train_005594 +GOT-10k_Train_005606 +GOT-10k_Train_005611 +GOT-10k_Train_005636 +GOT-10k_Train_005639 +GOT-10k_Train_005642 +GOT-10k_Train_005651 +GOT-10k_Train_005652 +GOT-10k_Train_005653 +GOT-10k_Train_005681 +GOT-10k_Train_005686 +GOT-10k_Train_005689 +GOT-10k_Train_005701 +GOT-10k_Train_005712 +GOT-10k_Train_005716 +GOT-10k_Train_005724 +GOT-10k_Train_005731 +GOT-10k_Train_005732 +GOT-10k_Train_005734 +GOT-10k_Train_005741 +GOT-10k_Train_005764 +GOT-10k_Train_005767 +GOT-10k_Train_005788 +GOT-10k_Train_005791 +GOT-10k_Train_005800 +GOT-10k_Train_005813 +GOT-10k_Train_005816 +GOT-10k_Train_005830 +GOT-10k_Train_005852 +GOT-10k_Train_005876 +GOT-10k_Train_005877 +GOT-10k_Train_005884 +GOT-10k_Train_005910 +GOT-10k_Train_005929 +GOT-10k_Train_005943 +GOT-10k_Train_005958 +GOT-10k_Train_005995 +GOT-10k_Train_006002 +GOT-10k_Train_006010 +GOT-10k_Train_006018 +GOT-10k_Train_006021 +GOT-10k_Train_006022 +GOT-10k_Train_006040 +GOT-10k_Train_006046 +GOT-10k_Train_006057 +GOT-10k_Train_006075 +GOT-10k_Train_006087 +GOT-10k_Train_006099 +GOT-10k_Train_006115 +GOT-10k_Train_006126 +GOT-10k_Train_006129 +GOT-10k_Train_006142 +GOT-10k_Train_006161 +GOT-10k_Train_006163 +GOT-10k_Train_006193 +GOT-10k_Train_006195 +GOT-10k_Train_006204 +GOT-10k_Train_006206 +GOT-10k_Train_006215 +GOT-10k_Train_006216 +GOT-10k_Train_006220 +GOT-10k_Train_006224 +GOT-10k_Train_006232 +GOT-10k_Train_006241 +GOT-10k_Train_006247 +GOT-10k_Train_006287 +GOT-10k_Train_006300 +GOT-10k_Train_006315 +GOT-10k_Train_006318 +GOT-10k_Train_006322 +GOT-10k_Train_006337 +GOT-10k_Train_006341 +GOT-10k_Train_006344 +GOT-10k_Train_006348 +GOT-10k_Train_006349 +GOT-10k_Train_006363 +GOT-10k_Train_006366 +GOT-10k_Train_006376 +GOT-10k_Train_006378 +GOT-10k_Train_006395 +GOT-10k_Train_006402 +GOT-10k_Train_006406 +GOT-10k_Train_006412 +GOT-10k_Train_006413 +GOT-10k_Train_006427 +GOT-10k_Train_006448 +GOT-10k_Train_006459 +GOT-10k_Train_006464 +GOT-10k_Train_006474 +GOT-10k_Train_006477 +GOT-10k_Train_006482 +GOT-10k_Train_006483 +GOT-10k_Train_006496 +GOT-10k_Train_006498 +GOT-10k_Train_006499 +GOT-10k_Train_006505 +GOT-10k_Train_006506 +GOT-10k_Train_006514 +GOT-10k_Train_006533 +GOT-10k_Train_006563 +GOT-10k_Train_006569 +GOT-10k_Train_006573 +GOT-10k_Train_006584 +GOT-10k_Train_006585 +GOT-10k_Train_006587 +GOT-10k_Train_006591 +GOT-10k_Train_006592 +GOT-10k_Train_006598 +GOT-10k_Train_006605 +GOT-10k_Train_006631 +GOT-10k_Train_006633 +GOT-10k_Train_006644 +GOT-10k_Train_006651 +GOT-10k_Train_006654 +GOT-10k_Train_006672 +GOT-10k_Train_006717 +GOT-10k_Train_006728 +GOT-10k_Train_006736 +GOT-10k_Train_006740 +GOT-10k_Train_006746 +GOT-10k_Train_006754 +GOT-10k_Train_006759 +GOT-10k_Train_006766 +GOT-10k_Train_006789 +GOT-10k_Train_006796 +GOT-10k_Train_006797 +GOT-10k_Train_006817 +GOT-10k_Train_006818 +GOT-10k_Train_006849 +GOT-10k_Train_006851 +GOT-10k_Train_006855 +GOT-10k_Train_006872 +GOT-10k_Train_006879 +GOT-10k_Train_006900 +GOT-10k_Train_006912 +GOT-10k_Train_006926 +GOT-10k_Train_006936 +GOT-10k_Train_006955 +GOT-10k_Train_006968 +GOT-10k_Train_006969 +GOT-10k_Train_006979 +GOT-10k_Train_006980 +GOT-10k_Train_006984 +GOT-10k_Train_006986 +GOT-10k_Train_006991 +GOT-10k_Train_007017 +GOT-10k_Train_007032 +GOT-10k_Train_007035 +GOT-10k_Train_007048 +GOT-10k_Train_007064 +GOT-10k_Train_007065 +GOT-10k_Train_007075 +GOT-10k_Train_007077 +GOT-10k_Train_007081 +GOT-10k_Train_007083 +GOT-10k_Train_007089 +GOT-10k_Train_007106 +GOT-10k_Train_007107 +GOT-10k_Train_007131 +GOT-10k_Train_007138 +GOT-10k_Train_007144 +GOT-10k_Train_007150 +GOT-10k_Train_007168 +GOT-10k_Train_007170 +GOT-10k_Train_007177 +GOT-10k_Train_007181 +GOT-10k_Train_007183 +GOT-10k_Train_007190 +GOT-10k_Train_007208 +GOT-10k_Train_007220 +GOT-10k_Train_007223 +GOT-10k_Train_007247 +GOT-10k_Train_007273 +GOT-10k_Train_007284 +GOT-10k_Train_007289 +GOT-10k_Train_007293 +GOT-10k_Train_007294 +GOT-10k_Train_007296 +GOT-10k_Train_007316 +GOT-10k_Train_007322 +GOT-10k_Train_007355 +GOT-10k_Train_007360 +GOT-10k_Train_007362 +GOT-10k_Train_007364 +GOT-10k_Train_007388 +GOT-10k_Train_007392 +GOT-10k_Train_007403 +GOT-10k_Train_007404 +GOT-10k_Train_007426 +GOT-10k_Train_007427 +GOT-10k_Train_007443 +GOT-10k_Train_007446 +GOT-10k_Train_007461 +GOT-10k_Train_007482 +GOT-10k_Train_007489 +GOT-10k_Train_007499 +GOT-10k_Train_007503 +GOT-10k_Train_007507 +GOT-10k_Train_007515 +GOT-10k_Train_007521 +GOT-10k_Train_007523 +GOT-10k_Train_007525 +GOT-10k_Train_007535 +GOT-10k_Train_007559 +GOT-10k_Train_007566 +GOT-10k_Train_007582 +GOT-10k_Train_007586 +GOT-10k_Train_007596 +GOT-10k_Train_007616 +GOT-10k_Train_007623 +GOT-10k_Train_007634 +GOT-10k_Train_007637 +GOT-10k_Train_007643 +GOT-10k_Train_007645 +GOT-10k_Train_007653 +GOT-10k_Train_007660 +GOT-10k_Train_007661 +GOT-10k_Train_007663 +GOT-10k_Train_007672 +GOT-10k_Train_007700 +GOT-10k_Train_007710 +GOT-10k_Train_007714 +GOT-10k_Train_007717 +GOT-10k_Train_007718 +GOT-10k_Train_007737 +GOT-10k_Train_007741 +GOT-10k_Train_007746 +GOT-10k_Train_007763 +GOT-10k_Train_007769 +GOT-10k_Train_007780 +GOT-10k_Train_007803 +GOT-10k_Train_007821 +GOT-10k_Train_007825 +GOT-10k_Train_007839 +GOT-10k_Train_007848 +GOT-10k_Train_007873 +GOT-10k_Train_007877 +GOT-10k_Train_007882 +GOT-10k_Train_007894 +GOT-10k_Train_007905 +GOT-10k_Train_007908 +GOT-10k_Train_007911 +GOT-10k_Train_007914 +GOT-10k_Train_007918 +GOT-10k_Train_007929 +GOT-10k_Train_007936 +GOT-10k_Train_007938 +GOT-10k_Train_007965 +GOT-10k_Train_007969 +GOT-10k_Train_007973 +GOT-10k_Train_007987 +GOT-10k_Train_007999 +GOT-10k_Train_008001 +GOT-10k_Train_008034 +GOT-10k_Train_008050 +GOT-10k_Train_008056 +GOT-10k_Train_008068 +GOT-10k_Train_008073 +GOT-10k_Train_008089 +GOT-10k_Train_008095 +GOT-10k_Train_008101 +GOT-10k_Train_008128 +GOT-10k_Train_008139 +GOT-10k_Train_008147 +GOT-10k_Train_008154 +GOT-10k_Train_008171 +GOT-10k_Train_008180 +GOT-10k_Train_008193 +GOT-10k_Train_008194 +GOT-10k_Train_008201 +GOT-10k_Train_008212 +GOT-10k_Train_008226 +GOT-10k_Train_008230 +GOT-10k_Train_008231 +GOT-10k_Train_008236 +GOT-10k_Train_008239 +GOT-10k_Train_008241 +GOT-10k_Train_008243 +GOT-10k_Train_008249 +GOT-10k_Train_008250 +GOT-10k_Train_008273 +GOT-10k_Train_008278 +GOT-10k_Train_008291 +GOT-10k_Train_008310 +GOT-10k_Train_008311 +GOT-10k_Train_008317 +GOT-10k_Train_008319 +GOT-10k_Train_008331 +GOT-10k_Train_008332 +GOT-10k_Train_008344 +GOT-10k_Train_008369 +GOT-10k_Train_008377 +GOT-10k_Train_008386 +GOT-10k_Train_008392 +GOT-10k_Train_008396 +GOT-10k_Train_008432 +GOT-10k_Train_008438 +GOT-10k_Train_008439 +GOT-10k_Train_008440 +GOT-10k_Train_008442 +GOT-10k_Train_008443 +GOT-10k_Train_008455 +GOT-10k_Train_008471 +GOT-10k_Train_008484 +GOT-10k_Train_008490 +GOT-10k_Train_008492 +GOT-10k_Train_008499 +GOT-10k_Train_008502 +GOT-10k_Train_008507 +GOT-10k_Train_008520 +GOT-10k_Train_008525 +GOT-10k_Train_008568 +GOT-10k_Train_008587 +GOT-10k_Train_008589 +GOT-10k_Train_008591 +GOT-10k_Train_008606 +GOT-10k_Train_008612 +GOT-10k_Train_008623 +GOT-10k_Train_008628 +GOT-10k_Train_008633 +GOT-10k_Train_008634 +GOT-10k_Train_008645 +GOT-10k_Train_008656 +GOT-10k_Train_008668 +GOT-10k_Train_008670 +GOT-10k_Train_008702 +GOT-10k_Train_008714 +GOT-10k_Train_008723 +GOT-10k_Train_008731 +GOT-10k_Train_008732 +GOT-10k_Train_008734 +GOT-10k_Train_008747 +GOT-10k_Train_008787 +GOT-10k_Train_008794 +GOT-10k_Train_008805 +GOT-10k_Train_008829 +GOT-10k_Train_008837 +GOT-10k_Train_008838 +GOT-10k_Train_008853 +GOT-10k_Train_008878 +GOT-10k_Train_008879 +GOT-10k_Train_008880 +GOT-10k_Train_008891 +GOT-10k_Train_008895 +GOT-10k_Train_008907 +GOT-10k_Train_008909 +GOT-10k_Train_008922 +GOT-10k_Train_008935 +GOT-10k_Train_008939 +GOT-10k_Train_008972 +GOT-10k_Train_008975 +GOT-10k_Train_008976 +GOT-10k_Train_009002 +GOT-10k_Train_009031 +GOT-10k_Train_009040 +GOT-10k_Train_009052 +GOT-10k_Train_009056 +GOT-10k_Train_009057 +GOT-10k_Train_009066 +GOT-10k_Train_009076 +GOT-10k_Train_009103 +GOT-10k_Train_009115 +GOT-10k_Train_009117 +GOT-10k_Train_009127 +GOT-10k_Train_009137 +GOT-10k_Train_009145 +GOT-10k_Train_009150 +GOT-10k_Train_009155 +GOT-10k_Train_009156 +GOT-10k_Train_009160 +GOT-10k_Train_009179 +GOT-10k_Train_009181 +GOT-10k_Train_009196 +GOT-10k_Train_009203 +GOT-10k_Train_009216 +GOT-10k_Train_009219 +GOT-10k_Train_009222 +GOT-10k_Train_009224 +GOT-10k_Train_009229 +GOT-10k_Train_009231 +GOT-10k_Train_009235 +GOT-10k_Train_009242 +GOT-10k_Train_009263 +GOT-10k_Train_009265 +GOT-10k_Train_009280 +GOT-10k_Train_009282 +GOT-10k_Train_009300 +GOT-10k_Train_009301 +GOT-10k_Train_009329 +GOT-10k_Train_009332 +GOT-10k_Train_009334 \ No newline at end of file diff --git a/ltr/data_specs/got10k_vot_train_split.txt b/ltr/data_specs/got10k_vot_train_split.txt new file mode 100755 index 0000000..f84e045 --- /dev/null +++ b/ltr/data_specs/got10k_vot_train_split.txt @@ -0,0 +1,7086 @@ +3784 +8998 +1631 +8277 +8358 +2338 +2988 +8302 +2662 +2663 +2825 +7447 +4781 +2218 +5860 +2819 +8075 +5391 +116 +3606 +7976 +7941 +1024 +4519 +1970 +557 +8579 +6908 +993 +7204 +1991 +3674 +8781 +6840 +5 +3225 +3763 +8688 +6778 +5777 +4794 +2744 +8126 +3864 +1733 +2923 +6829 +683 +2081 +1831 +2404 +1459 +2741 +5972 +7462 +2654 +103 +2174 +2989 +2506 +2766 +5912 +3295 +3986 +609 +4895 +6673 +801 +1098 +1602 +2490 +8476 +3186 +4784 +4270 +1812 +4226 +2267 +8873 +6544 +6112 +2381 +4752 +753 +3776 +6511 +6016 +2559 +7369 +5866 +563 +7731 +1105 +5603 +50 +4238 +2208 +8725 +4994 +4719 +1444 +8807 +7298 +8760 +8173 +2332 +4131 +1065 +8562 +3992 +4024 +2188 +9095 +6765 +1707 +6105 +6922 +5362 +1486 +7898 +4135 +6574 +998 +6565 +8127 +8927 +2544 +4365 +768 +3535 +3875 +6808 +2931 +487 +4451 +2470 +8111 +3493 +7338 +8281 +6390 +1271 +4373 +3667 +3494 +3757 +2966 +7840 +7827 +3300 +6261 +4163 +2217 +6549 +7236 +9136 +1857 +6691 +3470 +6271 +807 +516 +9311 +6098 +3144 +8420 +5425 +5694 +2643 +6696 +6072 +7285 +3781 +903 +8522 +6092 +5979 +2622 +2529 +855 +3420 +3261 +8953 +7866 +2492 +3157 +359 +1520 +2642 +7452 +759 +36 +8931 +1744 +4350 +1089 +9199 +1889 +1908 +4868 +4498 +1968 +3273 +7413 +4114 +5584 +4874 +1427 +5211 +7618 +1542 +1353 +8158 +4168 +3200 +6345 +8560 +5619 +5953 +3158 +8849 +5831 +1411 +8103 +6539 +7397 +1006 +5450 +3119 +4274 +5352 +4571 +2319 +4976 +902 +1814 +2651 +3299 +3398 +982 +2428 +5793 +1346 +7057 +3737 +7329 +4449 +2110 +7405 +1773 +958 +3901 +4127 +8234 +2994 +7066 +1289 +2995 +5871 +3556 +9085 +846 +2366 +585 +5516 +5230 +3481 +2732 +6658 +7423 +1855 +6384 +3554 +5823 +4948 +7058 +4667 +5377 +2503 +7694 +9191 +9144 +655 +3409 +62 +8019 +8970 +2323 +5750 +3178 +6548 +7501 +3280 +343 +2171 +8397 +1367 +8611 +6118 +6603 +7182 +9048 +7733 +7141 +3335 +4845 +5449 +3467 +6250 +163 +5168 +2040 +3609 +8352 +3426 +8567 +769 +187 +6151 +6437 +7028 +3970 +9146 +5028 +7492 +1661 +2815 +2469 +2563 +3814 +8430 +4305 +3479 +5678 +4132 +1211 +5459 +4814 +545 +4556 +238 +2724 +1260 +2581 +4632 +4313 +380 +1209 +5447 +3032 +7942 +8943 +806 +2432 +6130 +4314 +2131 +9045 +6531 +5706 +6747 +7724 +2017 +3292 +5469 +2743 +424 +4233 +8619 +5192 +4516 +9324 +3537 +9152 +8058 +7526 +8711 +1949 +5982 +6702 +7027 +6388 +7012 +328 +2130 +452 +306 +7669 +3134 +5761 +3703 +44 +4189 +695 +5224 +9215 +5644 +3143 +5443 +2348 +2328 +4725 +1418 +7810 +5759 +7226 +4535 +4385 +5397 +7249 +3204 +385 +2371 +2738 +3636 +9033 +2246 +2680 +6940 +4310 +2054 +9250 +9080 +4568 +5586 +4469 +2038 +3410 +7900 +4332 +6108 +678 +3319 +9079 +1054 +4048 +4751 +1320 +6890 +7931 +1398 +4349 +5299 +5025 +7932 +5738 +7787 +4590 +4020 +1274 +2488 +8497 +3372 +8965 +3219 +799 +3664 +6500 +7093 +4362 +6205 +4244 +5945 +6434 +2031 +2684 +6632 +4588 +8271 +3232 +5782 +2904 +7200 +3632 +5435 +8203 +3480 +4786 +7579 +3351 +1921 +798 +3646 +3094 +4359 +1654 +5975 +376 +5965 +780 +6738 +3185 +2133 +6248 +5996 +2834 +531 +5688 +2448 +7925 +7974 +5924 +6401 +5778 +6594 +5442 +8336 +4522 +3770 +6340 +6328 +4946 +4161 +2954 +2588 +8465 +2885 +1606 +5787 +3407 +3121 +7310 +1413 +1932 +4787 +2579 +3325 +508 +5610 +6480 +4290 +479 +3792 +6628 +2545 +6972 +2665 +6730 +3547 +6845 +3540 +8993 +1052 +2235 +8356 +3403 +8818 +8260 +572 +4159 +1180 +5348 +7948 +2676 +3539 +4866 +6422 +8365 +3217 +1310 +2059 +9177 +1419 +2283 +8892 +8162 +1212 +6277 +3725 +7806 +6149 +7874 +718 +6888 +7118 +277 +656 +8763 +8289 +4759 +5854 +8659 +3145 +5981 +1881 +5799 +6947 +1609 +6396 +2631 +318 +2550 +6132 +1736 +7816 +4304 +8133 +6698 +7779 +7732 +7642 +7242 +711 +9262 +8033 +7440 +1913 +5480 +5570 +8594 +8772 +4654 +8974 +6128 +6183 +1071 +8449 +2142 +2298 +524 +1695 +820 +4053 +1856 +8641 +217 +1063 +9286 +3152 +221 +5461 +1270 +2006 +7164 +1199 +6951 +5604 +5400 +5309 +3498 +6407 +6661 +7097 +8165 +5169 +3852 +7070 +5702 +4344 +6648 +6904 +3272 +7119 +5795 +2365 +2659 +353 +5444 +1924 +2098 +2972 +6006 +5865 +8740 +7856 +5841 +598 +836 +1147 +931 +8897 +0 +6049 +1837 +865 +1871 +6116 +6831 +5773 +3587 +303 +1883 +2163 +3070 +1308 +7953 +6909 +853 +7301 +3279 +123 +7186 +3194 +5133 +1931 +4622 +4891 +5722 +5693 +8 +2339 +6596 +71 +379 +4506 +4370 +1238 +2707 +3344 +4254 +8767 +1726 +325 +4148 +5438 +5357 +548 +1332 +6824 +2290 +2335 +2594 +2315 +3389 +3885 +2621 +4116 +7412 +7222 +4894 +8595 +2000 +4978 +4721 +6444 +3796 +9321 +2236 +6409 +1523 +1468 +9249 +8270 +2341 +2874 +174 +4502 +4703 +9034 +9108 +5451 +2619 +9158 +490 +6540 +1466 +2962 +8771 +2712 +4539 +1581 +5638 +9246 +4308 +4363 +4647 +4470 +1636 +1311 +6560 +7519 +8027 +9217 +6364 +3779 +4822 +3563 +5896 +6655 +1524 +2846 +3137 +141 +1887 +6567 +8921 +4671 +6052 +8445 +8699 +7349 +3553 +2117 +7651 +5034 +5383 +649 +3818 +9022 +8414 +1012 +8159 +5081 +8571 +4765 +9135 +4361 +4073 +9142 +727 +2835 +8229 +3989 +4490 +4923 +5477 +1638 +3643 +9044 +2230 +499 +7166 +3172 +8431 +8401 +1470 +6356 +8817 +927 +4212 +2152 +3812 +4949 +1219 +1538 +3029 +6481 +9042 +7775 +7742 +423 +2085 +7715 +4541 +9061 +5916 +7420 +7406 +7046 +7808 +4911 +8804 +6927 +8820 +3264 +300 +2979 +252 +4407 +3383 +4688 +8504 +6723 +26 +3837 +2489 +4137 +8209 +229 +6490 +2364 +9016 +1763 +1728 +338 +8335 +9063 +2791 +641 +5454 +4581 +4548 +2840 +8508 +3463 +7231 +7619 +2560 +1755 +6201 +165 +6279 +5806 +6867 +5890 +2396 +3416 +1981 +6073 +5872 +3045 +4182 +7607 +4414 +2998 +6553 +7139 +5624 +3666 +723 +5110 +6932 +8200 +2222 +8399 +1041 +4138 +1594 +3569 +9253 +393 +7940 +8004 +1475 +5393 +1107 +2597 +878 +9309 +7576 +5250 +3142 +2015 +571 +3921 +1255 +7080 +893 +2160 +1355 +82 +9153 +8583 +4085 +4644 +7196 +9165 +3558 +4550 +6374 +7826 +8602 +4146 +9257 +6083 +874 +8383 +3731 +3374 +3653 +8222 +7344 +470 +1813 +6871 +7245 +6866 +3998 +7433 +276 +1915 +1988 +8168 +2518 +2686 +831 +6143 +5205 +8718 +1703 +7729 +2077 +7983 +8450 +1195 +9232 +507 +7989 +6974 +5828 +8655 +6679 +5245 +7783 +5886 +9098 +6491 +8782 +3525 +6542 +131 +8110 +9186 +9074 +4933 +9035 +2607 +2057 +6273 +2711 +5829 +3382 +2696 +3043 +2048 +619 +2499 +5295 +1162 +7807 +3694 +2194 +3149 +1940 +7934 +840 +3592 +8237 +4731 +1324 +8486 +8726 +8573 +2928 +9078 +2272 +2564 +1370 +5911 +7434 +8026 +407 +7546 +2004 +5849 +7887 +3425 +1118 +926 +3430 +5902 +2282 +2334 +129 +1372 +4842 +6473 +4382 +1028 +415 +8269 +6910 +2796 +3038 +5735 +5080 +2852 +6306 +8842 +9188 +3637 +1066 +532 +5485 +2838 +6753 +9008 +7984 +2816 +8819 +7103 +5977 +5044 +2064 +2599 +3249 +6446 +6638 +852 +1724 +3368 +892 +3250 +8258 +7962 +4300 +1616 +167 +8855 +2090 +4424 +879 +5136 +5350 +2635 +7828 +8506 +63 +3847 +3676 +1705 +6745 +1263 +5020 +1888 +7036 +1033 +3914 +5433 +3905 +4641 +228 +4801 +3766 +8085 +643 +6914 +3013 +5657 +3696 +1590 +8282 +2403 +416 +911 +3849 +4215 +1120 +5490 +296 +2306 +3140 +3742 +4819 +6153 +6414 +760 +3000 +7498 +7108 +6429 +3031 +5314 +751 +3357 +5808 +7505 +98 +7652 +4027 +6257 +1799 +8577 +4969 +9163 +2025 +6061 +4026 +588 +4961 +4940 +7152 +538 +706 +2802 +8983 +3375 +1246 +6593 +5837 +1789 +7939 +4997 +5939 +2411 +6133 +199 +7593 +1702 +5406 +6082 +2912 +6109 +100 +8149 +5470 +2807 +3362 +5621 +6019 +9241 +9268 +7703 +7967 +5458 +5492 +6729 +4577 +106 +3774 +979 +7082 +4610 +1853 +9003 +9292 +2867 +6262 +2245 +3460 +1557 +4796 +2658 +5769 +6985 +421 +7990 +3289 +1540 +9316 +2251 +6896 +5947 +4965 +4480 +963 +9047 +7824 +3976 +6210 +7018 +7179 +5016 +7789 +6102 +6828 +7659 +9109 +9071 +8115 +7628 +7110 +16 +7513 +835 +939 +2351 +2322 +4945 +560 +6837 +6094 +6475 +7901 +3 +771 +8029 +3135 +8044 +7127 +3741 +5156 +7030 +113 +3747 +7042 +5232 +5225 +3002 +4747 +5379 +4886 +7192 +4184 +1896 +1834 +8689 +3665 +2957 +6913 +8009 +4851 +6420 +828 +8884 +8815 +3198 +8008 +194 +6251 +3303 +3934 +395 +1285 +4169 +1648 +1347 +3600 +4631 +509 +211 +6230 +7241 +2219 +2582 +8353 +7790 +7583 +9004 +6942 +1704 +8051 +2981 +5511 +6182 +7088 +1699 +1222 +6189 +1528 +5197 +6221 +7893 +7773 +8766 +2942 +8021 +614 +1786 +400 +133 +556 +5237 +3727 +1440 +3873 +8448 +6285 +8696 +8800 +4009 +3386 +4847 +5685 +9093 +5895 +6863 +4260 +8405 +8417 +7116 +255 +3223 +4737 +7852 +814 +710 +1094 +6103 +5809 +5882 +6336 +4974 +1499 +2806 +3744 +2664 +2436 +4482 +8665 +8918 +1076 +8676 +5725 +9248 +4755 +1447 +9328 +5500 +78 +2653 +792 +6854 +6093 +6172 +3378 +4492 +5529 +5476 +3846 +1391 +383 +4289 +3883 +2648 +3265 +2525 +5402 +4599 +6870 +6877 +4413 +2464 +8519 +2521 +1839 +5822 +5664 +7257 +5375 +6852 +6764 +5182 +8914 +3015 +8509 +3080 +4562 +8979 +6643 +8601 +6096 +4812 +5246 +7862 +527 +7849 +6737 +12 +2468 +7961 +275 +27 +5932 +3840 +7341 +4996 +8564 +2154 +6138 +7831 +4442 +757 +4464 +1170 +2568 +19 +323 +7675 +3441 +2067 +9027 +2486 +4379 +4744 +1737 +7563 +301 +3907 +4742 +6857 +1221 +9284 +8458 +2897 +1526 +5345 +4423 +6246 +8578 +3711 +4986 +4785 +3997 +7311 +4788 +8387 +2041 +2608 +6031 +3293 +541 +773 +8473 +2501 +5667 +804 +483 +1639 +696 +6060 +5429 +5762 +1527 +7342 +6225 +7895 +381 +8030 +8362 +4734 +3526 +9273 +2039 +5084 +875 +6905 +8968 +5275 +3052 +650 +7509 +232 +2595 +3631 +1810 +4355 +8315 +8908 +1777 +4834 +3164 +2336 +1543 +6212 +8346 +3024 +3719 +1242 +6265 +3133 +6150 +6358 +3316 +4089 +1647 +4629 +7117 +2596 +5366 +6371 +2209 +1428 +1158 +7648 +8765 +802 +153 +4639 +3657 +9320 +3294 +2617 +5052 +6305 +3227 +8784 +5868 +6716 +1671 +178 +2703 +954 +3254 +2262 +5743 +8647 +6393 +7706 +6604 +3728 +6978 +7474 +8754 +2740 +6038 +1491 +8814 +2080 +2358 +5944 +1164 +9259 +4518 +7343 +5748 +3897 +923 +5967 +2677 +3503 +1202 +4966 +6634 +1962 +9096 +9064 +977 +4049 +1464 +658 +536 +3402 +8064 +1309 +259 +8122 +910 +224 +6152 +7142 +6070 +8411 +9214 +9312 +8325 +6192 +626 +6025 +6240 +8708 +4630 +6777 +1075 +8906 +408 +9269 +6236 +9067 +2324 +156 +3136 +7878 +7308 +4335 +2065 +3845 +4453 +3356 +1450 +371 +7219 +5171 +201 +8642 +2099 +477 +1603 +8339 +7430 +3061 +235 +1133 +8474 +8653 +989 +4569 +9092 +8347 +3102 +1743 +9086 +5140 +7438 +1530 +2460 +7646 +5071 +5430 +6944 +610 +2803 +1448 +4696 +6156 +4386 +4248 +4256 +994 +805 +8011 +8276 +8999 +4956 +1712 +2795 +7553 +6436 +2158 +9083 +3184 +5784 +4428 +612 +5288 +6222 +1365 +5074 +6848 +575 +5213 +2175 +4240 +351 +2086 +2656 +5150 +9255 +8189 +7735 +1261 +1344 +4097 +8674 +2984 +4235 +5998 +6488 +537 +1267 +7486 +7124 +6245 +7955 +7337 +5436 +1194 +209 +1710 +7906 +4357 +4139 +5679 +2584 +2854 +1004 +8246 +8586 +5087 +4926 +6637 +3197 +7757 +6502 +1248 +990 +3928 +2770 +2751 +1020 +6426 +6839 +2671 +3871 +9212 +4179 +3394 +10 +5861 +5316 +6869 +2985 +8905 +8559 +4457 +2480 +2313 +4100 +6835 +7799 +7890 +2785 +5468 +7302 +5862 +1803 +3171 +717 +7053 +1655 +4489 +2522 +2921 +8555 +1984 +895 +8949 +1305 +738 +7606 +112 +3042 +1325 +437 +3167 +3340 +511 +3689 +8982 +69 +4421 +550 +8685 +3147 +8956 +3166 +7023 +2014 +3573 +3880 +4045 +2069 +6051 +702 +6664 +8418 +6181 +4853 +4166 +7022 +7418 +3605 +7172 +5031 +4589 +7858 +6586 +6351 +8334 +7504 +634 +3759 +1890 +890 +6959 +5085 +4919 +2161 +1191 +256 +3610 +7079 +3427 +4071 +7323 +2982 +7263 +7444 +4251 +5846 +4864 +3649 +4311 +8120 +4582 +6373 +2805 +4872 +4869 +5867 +2670 +7099 +30 +8933 +930 +7919 +7261 +5289 +7449 +7772 +3613 +3196 +474 +205 +841 +2611 +6185 +3088 +409 +7239 +5938 +7871 +1343 +6705 +1027 +5596 +2199 +9113 +5471 +6134 +838 +8359 +4061 +1474 +3229 +270 +4245 +1979 +1517 +8652 +4006 +6137 +4693 +2528 +6996 +2926 +5798 +2477 +2549 +3341 +6014 +4479 +2861 +4208 +5175 +5174 +5118 +3736 +5463 +1588 +2327 +8380 +7982 +1058 +4586 +6608 +7985 +1822 +3628 +549 +1811 +2601 +4608 +2540 +6659 +3859 +307 +3767 +8167 +505 +4366 +5520 +461 +1933 +2401 +8106 +2055 +7844 +8544 +4797 +7419 +6686 +7670 +6039 +5672 +5141 +6543 +206 +5252 +4718 +888 +1601 +3218 +5114 +713 +4022 +4419 +6708 +397 +425 +6612 +5057 +1729 +4729 +4080 +1034 +534 +5598 +9218 +2424 +329 +4154 +1597 +109 +8823 +9038 +8437 +3307 +128 +8032 +1412 +7333 +8762 +8851 +8865 +468 +3808 +3064 +8798 +7052 +7767 +1086 +2162 +6566 +2109 +3439 +6122 +3642 +7696 +8610 +5279 +1808 +8687 +817 +6066 +3640 +6015 +7601 +4855 +6017 +87 +7071 +7268 +3614 +6084 +6117 +6924 +9102 +2829 +375 +8724 +2095 +22 +1541 +2970 +633 +139 +451 +4521 +179 +1396 +3876 +5824 +8020 +426 +4982 +4172 +190 +4859 +1455 +3110 +3323 +9104 +858 +6719 +6428 +4495 +8551 +2141 +3984 +3066 +67 +4299 +5821 +8444 +6581 +6097 +7090 +7781 +8944 +3085 +2114 +5355 +8901 +1461 +3301 +422 +7000 +4820 +5790 +1379 +7536 +8736 +8991 +5241 +1698 +1294 +1753 +196 +2987 +8680 +4144 +8639 +6441 +8255 +8156 +3677 +6385 +6520 +3760 +6001 +1144 +5478 +7394 +8057 +5018 +4232 +5235 +6844 +3111 +8802 +949 +7843 +573 +2278 +6801 +7629 +2714 +5105 +6946 +2697 +5315 +1571 +8677 +2537 +4374 +3833 +7820 +3750 +2033 +6526 +3884 +8706 +7195 +3603 +3001 +6284 +5873 +5718 +8576 +8457 +3589 +5839 +459 +6342 +8729 +6933 +607 +6053 +8228 +3773 +1805 +6365 +5142 +6069 +1389 +9026 +570 +4614 +5533 +2821 +1897 +819 +4060 +5905 +6842 +5446 +1277 +4303 +2836 +934 +1014 +7822 +7494 +665 +5881 +3328 +4664 +315 +1315 +1462 +8616 +7725 +5749 +1730 +8184 +4567 +5065 +8867 +1304 +3669 +9192 +410 +8177 +6710 +1210 +2329 +3911 +1899 +7686 +3315 +6180 +3116 +5341 +4394 +8337 +9182 +5715 +2172 +2782 +3715 +9195 +7960 +4890 +8294 +2337 +8014 +3353 +7475 +2193 +8831 +4200 +4653 +6196 +6957 +3063 +8959 +8973 +6529 +3457 +5274 +8002 +6823 +6154 +5561 +1780 +9318 +7657 +1758 +6503 +7678 +3274 +1625 +4327 +3236 +8575 +4707 +4331 +1494 +8756 +3174 +1074 +8116 +8295 +3048 +3752 +6050 +8003 +9175 +4674 +1642 +2556 +6166 +7165 +8441 +3990 +1640 +1778 +7500 +8304 +1395 +4315 +5949 +3364 +242 +5763 +1036 +2430 +8131 +411 +6267 +2045 +6606 +899 +8065 +5779 +5616 +2107 +5408 +2980 +6310 +5776 +4328 +821 +3251 +2354 +7076 +5313 +79 +3959 +5677 +7545 +160 +6790 +6859 +3659 +6770 +1106 +8846 +956 +7472 +2050 +8099 +4795 +8053 +9293 +7037 +1646 +9307 +5322 +5332 +2708 +8977 +917 +2419 +184 +2105 +1578 +3923 +5780 +1903 +2512 +429 +493 +4972 +445 +8286 +320 +8300 +617 +3413 +4459 +525 +5631 +6314 +5157 +5300 +8545 +182 +1031 +4429 +2495 +1534 +3099 +3916 +3738 +535 +2119 +177 +1838 +2159 +4099 +8285 +5172 +8540 +6020 +7683 +3073 +3115 +3087 +2416 +1894 +5942 +3597 +5834 +2007 +43 +1779 +4174 +2023 +2546 +2429 +9006 +436 +4214 +3693 +5426 +6767 +5903 +4368 +2170 +5051 +7490 +2859 +5035 +7835 +5372 +7122 +925 +3253 +6338 +8393 +4093 +5848 +7588 +2683 +8049 +5403 +5894 +8745 +8550 +2941 +3484 +9029 +4461 +8022 +725 +3030 +1975 +5623 +2415 +1957 +6141 +9278 +3226 +3062 +5670 +7326 +8759 +8496 +6619 +8187 +8262 +6199 +951 +668 +2388 +4698 +8240 +2851 +871 +4988 +9084 +9089 +3162 +1167 +8244 +5227 +6461 +2831 +776 +5010 +5770 +5282 +3574 +5102 +1278 +2281 +5455 +4628 +4663 +9119 +7487 +8746 +4889 +1175 +102 +2386 +8940 +5566 +53 +8833 +1918 +321 +6786 +6861 +4358 +2771 +7467 +975 +4777 +605 +3543 +2600 +7584 +9299 +4530 +7328 +183 +4761 +7543 +304 +1196 +4623 +5519 +1953 +533 +5989 +7590 +7428 +6346 +6162 +1946 +6260 +4405 +5676 +8924 +7171 +8409 +1866 +6379 +3411 +2387 +3051 +7398 +154 +1185 +6442 +6004 +1611 +2165 +9018 +8323 +616 +3995 +8952 +1533 +7853 +789 +4991 +3675 +7456 +5752 +175 +7556 +4195 +907 +2248 +8467 +1017 +7968 +3304 +1666 +4942 +3867 +4802 +6357 +4621 +887 +6213 +5261 +1336 +521 +8928 +7864 +4792 +6742 +157 +1593 +823 +7235 +5303 +5633 +1100 +8047 +5993 +1460 +6714 +1630 +6440 +6307 +3608 +292 +5974 +8301 +8342 +2720 +4583 +2757 +7315 +833 +4466 +4236 +1282 +5273 +2149 +2380 +8119 +7167 +5076 +3596 +2650 +8980 +3421 +1356 +1954 +7823 +1172 +2226 +1941 +6136 +7274 +2256 +4928 +324 +4410 +4579 +1061 +7113 +486 +862 +6956 +2873 +1465 +6113 +8225 +8512 +6806 +272 +6008 +1241 +88 +5662 +3555 +689 +8733 +2812 +7453 +6282 +420 +2471 +4477 +7495 +1445 +594 +6939 +1564 +8704 +8590 +7992 +7374 +5796 +9298 +4213 +5713 +5864 +326 +5513 +402 +464 +608 +1951 +8640 +3347 +3459 +4162 +2690 +7478 +5856 +5240 +3022 +602 +5547 +1798 +1345 +9276 +599 +3673 +3277 +1635 +8625 +1567 +5928 +636 +5671 +2896 +3477 +412 +7575 +4201 +685 +4760 +1229 +4275 +8960 +3123 +4471 +5941 +3355 +3999 +7157 +6354 +6850 +8783 +1943 +6769 +7330 +8721 +8477 +1381 +848 +778 +6408 +2644 +5817 +1441 +1723 +2144 +2776 +2368 +367 +8839 +8749 +5353 +3148 +9114 +1233 +9228 +8857 +2895 +1286 +200 +6755 +5125 +5857 +1657 +7658 +5000 +942 +7020 +586 +784 +7078 +6194 +8658 +8957 +9325 +1851 +8911 +7004 +1186 +8824 +2999 +561 +7639 +4316 +5086 +3187 +7912 +2624 +9183 +8487 +5089 +8475 +7554 +4031 +6297 +6059 +5329 +115 +2058 +7650 +7121 +2485 +7805 +2241 +7713 +4352 +2409 +1026 +2745 +4549 +5124 +5201 +6556 +6617 +9091 +3945 +8402 +5648 +5257 +4901 +7750 +6131 +6027 +6352 +4625 +1254 +5498 +3720 +8261 +3939 +5576 +3685 +6713 +8472 +991 +8354 +5655 +5997 +1029 +7506 +2575 +2990 +4898 +7402 +3290 +5388 +6715 +8235 +5361 +4970 +1363 +3338 +9014 +5358 +635 +1193 +3705 +6334 +7666 +5270 +6368 +8604 +3564 +1937 +2481 +1341 +721 +2100 +3958 +6551 +3813 +2592 +7980 +2357 +8761 +8910 +8693 +1204 +489 +4827 +8024 +7832 +3895 +9068 +8067 +1708 +1111 +8963 +1902 +9251 +5719 +9143 +5537 +9169 +5365 +1840 +485 +4456 +1169 +3271 +6886 +9140 +7173 +6003 +1659 +1807 +8371 +2439 +274 +3448 +6623 +347 +2103 +3400 +2106 +9073 +8169 +3687 +3305 +4416 +8454 +6635 +332 +2433 +1944 +6509 +7770 +1880 +6610 +9331 +302 +418 +4219 +1333 +2350 +8424 +4883 +6580 +6722 +1669 +8470 +2571 +513 +3810 +7049 +6332 +7363 +3532 +8456 +2097 +297 +8841 +7180 +714 +1587 +5234 +7372 +660 +8503 +1668 +8847 +1101 +7275 +3336 +6460 +722 +7782 +3947 +502 +4258 +2132 +1835 +181 +3841 +427 +3446 +2551 +8324 +6963 +4284 +7297 +7577 +3399 +9148 +8213 +5656 +851 +657 +2446 +6992 +976 +1108 +2681 +3237 +8582 +377 +5969 +5287 +9209 +8523 +7178 +7833 +6175 +2126 +3023 +5090 +7491 +6640 +6077 +2221 +2780 +1694 +4094 +144 +3203 +7123 +749 +3625 +3848 +980 +2270 +7819 +3672 +7689 +7203 +2718 +1714 +3802 +3851 +4224 +7237 +7998 +7207 +4106 +9036 +1046 +5070 +4592 +6056 +693 +1328 +3309 +2629 +2736 +202 +388 +7886 +4417 +8786 +8822 +4035 +5505 +1192 +4388 +8941 +5019 +7538 +6732 +6389 +5923 +1405 +3278 +3917 +1688 +8374 +443 +4037 +9099 +5190 +4177 +9310 +7747 +4348 +7197 +4844 +4998 +5609 +4345 +29 +3332 +8648 +4107 +346 +2577 +3941 +1215 +8252 +4706 +2675 +3790 +7459 +6164 +1149 +6687 +582 +3139 +3882 +4034 +1861 +4701 +8757 +8801 +1823 +4528 +4789 +143 +4746 +9234 +3866 +9245 +1911 +1366 +4393 +2061 +1959 +6967 +3138 +7382 +6237 +845 +80 +6911 +7163 +5229 +4736 +8738 +33 +8543 +357 +3193 +7262 +4448 +6793 +3321 +7569 +6411 +7692 +7340 +1417 +5847 +3836 +2678 +1188 +8727 +8615 +7417 +5771 +3170 +8061 +2935 +8263 +8257 +6883 +1276 +1239 +812 +6258 +3922 +8117 +3039 +603 +8554 +7573 +2787 +3445 +5115 +3478 +962 +3961 +6570 +7722 +216 +2797 +5154 +2530 +4904 +2405 +7542 +4021 +3252 +5370 +9302 +236 +4532 +1361 +3373 +1716 +2183 +1583 +3783 +868 +1687 +8925 +6198 +8208 +6367 +7603 +882 +3469 +1645 +7654 +1176 +4231 +150 +7997 +5456 +7031 +4375 +8840 +5634 +6945 +705 +4774 +3822 +7148 +1922 +8459 +6249 +8713 +6197 +8599 +6071 +6756 +1634 +950 +5640 +7749 +5920 +6622 +4783 +7837 +7479 +7229 +3919 +1797 +5272 +8945 +4908 +5439 +6903 +5833 +6930 +8197 +9261 +1711 +5483 +4285 +8852 +7409 +8971 +7534 +7792 +2444 +7496 +8063 +1665 +248 +3894 +4585 +66 +4850 +1240 +7511 +7524 +9258 +2075 +3979 +4714 +7592 +965 +2919 +1842 +8013 +4750 +2344 +6155 +3468 +31 +2087 +1599 +1573 +5883 +7613 +195 +3749 +644 +2189 +8779 +8743 +9005 +8081 +1040 +7785 +5820 +8830 +5495 +4867 +2710 +491 +7153 +6217 +4741 +1761 +5484 +5474 +6916 +7252 +1739 +8930 +6647 +5198 +4903 +8488 +7366 +2774 +2726 +2385 +7625 +3179 +8845 +6600 +399 +6810 +3447 +6684 +4915 +8368 +1867 +2325 +2101 +1335 +7734 +7437 +7025 +4000 +6897 +1408 +7154 +5013 +2204 +9233 +3817 +1877 +9161 +2197 +3390 +280 +1892 +1612 +7753 +2801 +7246 +7909 +6229 +9314 +8407 +1436 +3879 +6432 +5326 +5327 +8535 +7910 +7745 +5545 +7916 +207 +1783 +6158 +8517 +7361 +8070 +6430 +119 +6146 +4183 +1083 +7385 +4497 +9133 +1686 +3765 +595 +8046 +4418 +4043 +2361 +7915 +9149 +1717 +1141 +6375 +1018 +5602 +1262 +7485 +9178 +6629 +3339 +8934 +4648 +7988 +6252 +3440 +864 +5418 +3874 +7280 +6191 +8388 +4323 +6792 +2232 +7228 +8684 +7813 +6187 +6678 +3177 +3534 +4953 +4402 +7739 +6319 +2414 +8700 +5946 +8238 +6917 +4167 +4618 +2268 +3081 +1247 +4001 +8580 +7636 +3101 +2195 +1559 +3714 +7188 +6028 +7530 +2828 +1977 +3238 +2340 +110 +3247 +7532 +7541 +924 +1632 +4487 +6447 +4944 +6347 +2285 +8087 +5452 +91 +1166 +162 +5185 +7933 +4743 +1627 +7259 +8620 +8207 +5845 +9011 +5525 +4269 +4700 +1824 +8186 +8872 +8299 +3957 +8242 +4558 +6439 +2666 +6958 +8112 +5121 +8806 +6170 +7688 +3486 +2082 +7436 +2778 +1096 +786 +2206 +5170 +1443 +6030 +3312 +9151 +8485 +6404 +8498 +2883 +8961 +2280 +8341 +2809 +2445 +809 +8298 +8643 +8316 +6853 +1572 +3215 +3938 +2249 +6515 +1337 +8328 +7712 +1429 +4117 +5441 +3230 +4152 +7225 +3513 +6953 +1507 +348 +3639 +5739 +2673 +1550 +6301 +1652 +8453 +204 +6833 +2200 +5217 +1854 +4711 +7368 +4572 +4032 +7531 +1013 +3634 +2875 +6058 +8307 +7609 +1766 +904 +667 +5410 +6578 +3601 +1664 +3233 +7390 +8178 +4486 +4427 +4876 +9166 +2772 +6295 +5001 +5296 +3371 +6518 +6327 +854 +8288 +1912 +5927 +6202 +5814 +9032 +1059 +3214 +6547 +7038 +5781 +4390 +6114 +1622 +4318 +5803 +5984 +736 +3561 +6554 +5045 +4277 +7386 +9081 +8462 +2034 +4955 +2701 +932 +7758 +7176 +9205 +3077 +3803 +3562 +8054 +7946 +295 +1843 +7728 +1629 +7768 +2971 +431 +9285 +2513 +1116 +3656 +4529 +5758 +6339 +8398 +816 +4153 +2536 +1826 +7870 +8113 +7730 +7101 +6555 +9256 +6774 +1072 +4578 +2598 +3604 +5880 +861 +3350 +3117 +4685 +4334 +5165 +7224 +4066 +4253 +4447 +3815 +5038 +253 +3658 +330 +3967 +6443 +2143 +7336 +6135 +2734 +8390 +4655 +7800 +1399 +1173 +5618 +2822 +4431 +2443 +1568 +3909 +1974 +2496 +4772 +5164 +2138 +2864 +3799 +3924 +4882 +8245 +1585 +5528 +5692 +5730 +5832 +137 +3175 +2894 +2062 +2752 +4028 +2113 +5411 +2647 +730 +3758 +1667 +9303 +6653 +3698 +3968 +3053 +503 +2150 +4645 +2257 +4627 +8303 +7966 +8742 +4692 +5901 +8547 +2277 +5546 +986 +370 +4697 +8712 +4804 +1182 +6650 +7290 +3487 +2814 +5668 +7567 +5333 +4164 +3084 +8896 +3888 +6537 +17 +6882 +3531 +704 +1037 +8866 +5263 +6758 +3762 +1393 +3824 +5112 +214 +1439 +5700 +8932 +1306 +5011 +6928 +5173 +4098 +1132 +7352 +4778 +7723 +1368 +2390 +670 +2685 +5855 +1772 +6380 +3853 +940 +5424 +6091 +1748 +5297 +6572 +8877 +6874 +430 +5041 +5267 +7448 +620 +9112 +4294 +1432 +72 +130 +7920 +4597 +6614 +8889 +3697 +1895 +3462 +2616 +4791 +7846 +8372 +428 +6559 +8326 +9211 +1525 +5980 +7888 +3331 +8118 +7899 +615 +7377 +791 +5930 +6627 +8322 +1138 +770 +8460 +5100 +8274 +8350 +6316 +2893 +7594 +9236 +5082 +8150 +1986 +1909 +8902 +2145 +3617 +3501 +7 +2426 +5056 +8016 +2702 +5360 +8135 +8385 +8378 +8018 +8574 +720 +8893 +3021 +1978 +4782 +1816 +2083 +4051 +1446 +5870 +9097 +8006 +4222 +8287 +686 +1377 +611 +8153 +4808 +1536 +679 +4096 +3891 +4884 +432 +4615 +8988 +5560 +3451 +5589 +3514 +6169 +1414 +3244 +1490 +7100 +3588 +690 +7317 +4171 +2266 +6800 +2793 +5151 +6977 +8188 +8752 +5815 +5116 +263 +3311 +289 +3392 +5755 +1022 +5548 +9319 +8937 +6011 +7632 +5328 +4141 +5407 +520 +7305 +526 +3645 +1859 +2520 +3523 +8629 +7304 +8881 +3076 +4005 +8329 +2205 +2214 +6925 +8691 +4136 +8883 +974 +7952 +3965 +5887 +7964 +7189 +2406 +2783 +8086 +405 +6568 +5147 +2021 +4727 +7674 +1600 +5078 +2949 +6624 +6541 +8986 +5740 +8500 +3591 +4434 +398 +983 +7544 +1478 +4570 +6012 +465 +9330 +7206 +808 +8737 +2356 +4959 +8812 +3599 +1420 +1721 +5897 +8422 +2 +4023 +2739 +3619 +8797 +5496 +8951 +8181 +6893 +9254 +1809 +5682 +4309 +6929 +2742 +5988 +3363 +4493 +8434 +4210 +1503 +1876 +5094 +4600 +4936 +4798 +3933 +5216 +646 +3098 +8773 +4076 +5335 +3746 +3327 +47 +4602 +8636 +4129 +363 +6417 +7416 +9025 +4377 +4766 +2779 +4151 +9046 +7860 +3154 +3476 +7620 +2052 +1752 +7199 +4412 +8882 +2463 +339 +56 +4821 +7555 +6558 +1905 +5258 +4205 +3580 +6735 +1023 +4511 +3850 +161 +7395 +2532 +3349 +7055 +7387 +758 +1907 +3006 +659 +815 +1961 +6902 +7668 +4708 +1904 +4433 +5159 +6816 +8664 +6918 +1016 +6513 +7314 +7480 +9313 +716 +3395 +6843 +918 +4329 +8593 +3404 +5212 +837 +480 +8524 +1342 +7414 +288 +8863 +3352 +1628 +135 +3314 +2181 +8650 +5915 +8078 +6812 +1375 +906 +5635 +7126 +1387 +7458 +6119 +5591 +3795 +1531 +95 +1960 +7522 +898 +4921 +2623 +6268 +7063 +1326 +9075 +2505 +7400 +1284 +2951 +747 +6466 +1357 +6493 +7320 +5892 +576 +5107 +5559 +97 +2583 +6361 +8843 +3509 +7892 +6086 +1476 +4612 +4267 +9094 +7050 +6048 +8382 +2227 +284 +2898 +3221 +2353 +2157 +5990 +5810 +3581 +7279 +6188 +7859 +3549 +5539 +2022 +630 +2500 +5111 +6561 +5127 +5569 +6123 +1338 +8605 +3491 +4187 +8220 +7334 +9213 +3067 +6997 +2853 +4735 +4372 +5954 +6662 +2207 +973 +3361 +960 +6350 +7431 +8076 +1129 +750 +7194 +2300 +6590 +5893 +6889 +3125 +8788 +7286 +3472 +8164 +7693 +1469 +5563 +4773 +3210 +6324 +3113 +9070 +3638 +7551 +2541 +3506 +5138 +4069 +7198 +7560 +3306 +6100 +2932 +1741 +14 +4672 +7564 +8748 +8874 +3804 +3678 +2610 +1358 +42 +5176 +9326 +8464 +1038 +2993 +3017 +9072 +32 +4809 +4364 +2808 +4125 +152 +7299 +5431 +6178 +793 +9120 +8410 +4963 +772 +6954 +3014 +6881 +286 +553 +1948 +6398 +6255 +3057 +8646 +6176 +2700 +5663 +6683 +1281 +6013 +8799 +7635 +9289 +1885 +442 +2225 +6294 +5054 +2674 +7884 +8730 +8216 +4203 +1488 +7111 +3623 +7950 +1971 +3248 +2900 +1553 +472 +3865 +7796 +6937 +4591 +8098 +5208 +294 +5627 +5691 +5687 +7149 +4879 +3624 +7005 +2773 +3112 +9185 +1633 +7830 +5101 +8707 +8469 +4678 +4860 +700 +5527 +9194 +2794 +5068 +1177 +4282 +6492 +5859 +5029 +5123 +522 +5048 +7230 +2104 +6642 +6731 +2717 +5149 +2043 +9059 +5277 +844 +5515 +6706 +3651 +9105 +7671 +2880 +3607 +6410 +2508 +8463 +2394 +1916 +1125 +5343 +3322 +5307 +4547 +1589 +8478 +8899 +2955 +8028 +4058 +2781 +8715 +1272 +4474 +4863 +4367 +49 +8844 +5605 +8671 +6743 +4281 +1874 +2626 +2516 +258 +5249 +6186 +7958 +5432 +3801 +6288 +4732 +9121 +7558 +6819 +7508 +584 +215 +5036 +4261 +8978 +5228 +647 +4657 +2591 +5931 +5088 +9204 +929 +4381 +5421 +2965 +5050 +6495 +5033 +4799 +959 +1232 +5811 +317 +7705 +3842 +2178 +7187 +1373 +7112 +2694 +8627 +8493 +3991 +7441 +6308 +6462 +3406 +7673 +8660 +2902 +752 +1025 +849 +7682 +6982 +6652 +3612 +298 +5148 +4873 +3414 +1693 +1458 +327 +2016 +5002 +6768 +7016 +5583 +3270 +8232 +7158 +7981 +4676 +4675 +2164 +8360 +6709 +8143 +365 +4062 +4527 +7928 +9009 +6228 +5818 +2533 +9305 +8887 +55 +2507 +8870 +6649 +5158 +76 +5595 +6693 +5306 +8666 +3020 +7527 +3082 +6304 +1591 +6145 +6868 +7205 +9107 +1165 +6773 +172 +1993 +4176 +8400 +4611 +7589 +5386 +6095 +6335 +1561 +5963 +7393 +3681 +2037 +4968 +7451 +3360 +7466 +8361 +4455 +4064 +5422 +1689 +3977 +7269 +362 +4178 +4145 +6127 +5162 +2399 +9225 +7068 +794 +1348 +7736 +444 +6081 +5298 +2026 +2543 +9087 +7425 +3730 +8468 +2641 +7529 +1720 +6377 +5851 +7956 +3150 +3785 +6485 +3611 +2869 +8510 +4775 +4463 +1251 +9124 +6873 +3391 +4118 +7051 +3213 +3668 +5347 +8452 +6289 +5840 +478 +3522 +453 +3376 +6190 +3342 +2237 +2870 +5178 +5567 +5952 +6919 +3005 +134 +3397 +8539 +6822 +5264 +3288 +5962 +8421 +6744 +8608 +4656 +1802 +4271 +1043 +8211 +2196 +5260 +3789 +7211 +7571 +7834 +5680 +2047 +5502 +3369 +3437 +3286 +5517 +3912 +1442 +6961 +2191 +2417 +9088 +5155 +6813 +4520 +7375 +1224 +811 +1891 +3748 +4123 +2789 +5305 +8419 +7248 +9237 +992 +4038 +4499 +2060 +850 +2669 +7612 +9290 +2526 +1287 +4160 +4633 +7125 +742 +4534 +2407 +4555 +8764 +4722 +7721 +3205 +6657 +1214 +3754 +6080 +4593 +3018 +8792 +2294 +4450 +7701 +127 +7069 +6243 +8025 +4010 +8632 +4715 +5284 +4574 +726 +4252 +4561 +7354 +299 +6088 +1090 +5012 +5684 +3489 +4888 +1584 +1969 +4846 +2915 +6804 +2775 +7306 +9306 +5231 +7740 +4283 +953 +6725 +8290 +1504 +1539 +8885 +138 +3764 +1256 +257 +335 +7060 +5986 +9323 +4740 +8994 +4140 +6807 +8254 +3963 +9297 +2102 +9207 +4910 +8709 +4411 +1672 +457 +8037 +4932 +3679 +2362 +8592 +495 +1608 +2155 +7411 +2881 +9244 +37 +6535 +8219 +4505 +8635 +1928 +8384 +2570 +8996 +7610 +2128 +8728 +6656 +6681 +2070 +176 +9062 +514 +1796 +4039 +6838 +2462 +230 +569 +5521 +4637 +4939 +4420 +672 +3807 +447 +1656 +3297 +8858 +2118 +6309 +1926 +481 +1509 +1228 +1787 +5978 +8678 +3951 +2929 +4980 +5039 +4713 +7002 +151 +5536 +8148 +3823 +2299 +142 +7067 +2372 +3761 +9 +2265 +5747 +2764 +724 +2913 +3151 +4525 +6370 +4247 +5494 +629 +3621 +7371 +1999 +6704 +3734 +2698 +4691 +6938 +8415 +6353 +6750 +9077 +2679 +2478 +7321 +6611 +4007 +5772 +6416 +2264 +8348 +2672 +6546 +754 +6934 +8546 +4404 +592 +4748 +6625 +7944 +2377 +6 +8929 +8275 +4524 +3660 +8710 +419 +6878 +8313 +7460 +8753 +2917 +6891 +6663 +4918 +7129 +396 +7256 +3500 +631 +5585 +8343 +2695 +6168 +6292 +3176 +5092 +5160 +3701 +9021 +7221 +1216 +1438 +3471 +2318 +8923 +6223 +2182 +7621 +8514 +9010 +8987 +1252 +1972 +1872 +1715 +8205 +6463 +8138 +8989 +5661 +2890 +565 +2427 +8946 +1303 +3718 +6000 +3620 +5276 +9260 +1467 +6173 +7641 +7520 +5061 +4677 +5757 +4400 +2620 +2719 +8995 +2079 +1683 +8141 +7754 +5744 +2952 +7568 +7457 +5368 +1510 +1513 +3072 +1456 +9164 +3163 +3035 +6111 +5042 +7161 +1401 +1084 +8000 +8531 +5404 +6550 +8379 +9141 +8681 +7752 +6394 +7011 +3739 +8253 +978 +4771 +6024 +4828 +7959 +1649 +1727 +7073 +8349 +6952 +661 +7283 +3159 +2590 +3496 +8741 +3969 +2956 +4565 +920 +1830 +8558 +1930 +6677 +6825 +8256 +7454 +4710 +1768 +3753 +5292 +1397 +2733 +946 +6711 +3242 +4929 +5006 +3202 +2295 +2746 +1293 +2124 +5405 +4065 +818 +7464 +1820 +1312 +6994 +6920 +261 +987 +6120 +3109 +2986 +4338 +7774 +5122 +1364 +8969 +6712 +8161 +7595 +5940 +1566 +6419 +4432 +6047 +4749 +6076 +1161 +8217 +674 +8494 +3688 +2447 +4704 +969 +7477 +1160 +3243 +4979 +9288 +6860 +1662 +6171 +225 +5143 +313 +8327 +3385 +7626 +3103 +4401 +6794 +5600 +5043 +7664 +6830 +4452 +3980 +5875 +4635 +5756 +3329 +1751 +8108 +4817 +1989 +1237 +1893 +2848 +8875 +4981 +5417 +4134 +877 +6688 +3545 +4943 +5615 +2476 +1684 +7396 +1171 +3415 +3644 +340 +6630 +8284 +3256 +7240 +5371 +3405 +2108 +6360 +1734 +5612 +8638 +2343 +1103 +6809 +3055 +188 +8031 +3124 +3683 +4537 +988 +2297 +4893 +839 +4467 +5195 +4041 +6457 +4441 +6472 +4912 +6884 +5922 +7014 +1660 +1595 +6752 +4554 +1292 +2709 +3800 +1980 +8775 +6392 +6263 +7214 +5219 +282 +309 +6685 +6311 +4092 +18 +7570 +5543 +4081 +2515 +6278 +8690 +5294 +6184 +5215 +9130 +6720 +250 +7250 +639 +3567 +7841 +2636 +4067 +8446 +5703 +8609 +2586 +7695 +1253 +6701 +7930 +6317 +5921 +7719 +8501 +7312 +4110 +6219 +4552 +5059 +4088 +7975 +9132 +6054 +692 +3412 +4079 +6950 +5281 +8321 +3877 +7614 +4188 +2223 +239 +4745 +6875 +7096 +5571 +4403 +2640 +1845 +6690 +1825 +4157 +314 +4682 +8825 +8093 +7215 +6465 +99 +8077 +4206 +366 +1208 +6043 +4640 +5475 +4985 +1351 +3090 +5625 +7307 +8466 +2003 +8854 +218 +1500 +2293 +1847 +5032 +2147 +866 +3710 +2552 +1749 +6692 +3926 +4112 +6458 +735 +9171 +60 +9304 +6726 +2630 +2882 +1178 +1151 +4922 +4662 +173 +7233 +1776 +4113 +2423 +2425 +4343 +970 +6372 +1009 +6607 +3068 +8435 +6423 +3126 +4813 +1709 +1201 +7104 +5620 +3932 +3366 +5023 +5079 +627 +290 +779 +5572 +5233 +1392 +4975 +8534 +8210 +2269 +2475 +2562 +905 +4546 +267 +3536 +8538 +449 +101 +7367 +2722 +4605 +7356 +6781 +8537 +8697 +6820 +8340 +8926 +2349 +2259 +6545 +8100 +8395 +2258 +2911 +3946 +1406 +8683 +8296 +5579 +2177 +8264 +1425 +957 +3647 +515 +5342 +8363 +2449 +1001 +2937 +3452 +5574 +4319 +9184 +8381 +945 +6876 +600 +5714 +4871 +8532 +8856 +392 +2018 +369 +5711 +9230 +5304 +7266 +1681 +7829 +2309 +4683 +8938 +2255 +6159 +3207 +4651 +2029 +4341 +5106 +5794 +9024 +4712 +2434 +7151 +7359 +6431 +1290 +5918 +8705 +5554 +8876 +7415 +6290 +5373 +3805 +2950 +2331 +6772 +8997 +6576 +2307 +8515 +4033 +3428 +6487 +6595 +45 +5792 +333 +2383 +3388 +666 +460 +943 +364 +8223 +8221 +637 +6218 +4108 +5381 +4649 +5096 +1614 +8768 +5095 +3809 +5030 +984 +3538 +5120 +2498 +5222 +5613 +5486 +241 +5707 +9227 +4109 +7771 +728 +3671 +9327 +1230 +9270 +1070 +8565 +4769 +7056 +5654 +1793 +5956 +7883 +1362 +5479 +8769 +8821 +8320 +1901 +1994 +2461 +5552 +389 +2839 +6467 +2762 +4763 +3499 +1487 +7599 +4488 +3241 +8272 +1131 +4496 +7006 +7265 +4897 +2747 +6618 +5291 +4563 +1939 +6369 +8548 +5526 +9030 +5349 +8433 +1477 +4265 +9200 +3878 +462 +6846 +4806 +3519 +6798 +5464 +5179 +546 +6044 +8114 +7216 +6276 +1495 +494 +8146 +5434 +856 +8403 +8071 +5544 +3337 +1546 +2824 +1718 +6009 +2042 +251 +3330 +192 +3797 +394 +7814 +7699 +4659 +4689 +4156 +7903 +9054 +7332 +7811 +1119 +5531 +6782 +5210 +8412 +2633 +7924 +4624 +8314 +5666 +3240 +2310 +4262 +8160 +4553 +8196 +2661 +7213 +7455 +7399 +870 +1227 +1226 +781 +937 +6343 +2578 +2892 +2792 +5696 +6865 +6455 +8312 +5193 +6026 +5251 +3787 +4460 +4687 +7923 +1140 +9106 +796 +2482 +9170 +8695 +2749 +6734 +4825 +114 +827 +390 +7611 +7484 +1249 +7727 +955 +579 +3629 +8915 +2958 +885 +7227 +1424 +4810 +4604 +1535 +774 +7518 +5428 +8233 +2645 +2167 +6484 +3855 +1502 +4861 +2333 +2973 +4829 +1906 +3966 +476 +9023 +6960 +3483 +2748 +5891 +8174 +7702 +8948 +5324 +4396 +1605 +2823 +7348 +7347 +5933 +310 +9082 +916 +203 +4239 +5976 +6200 +6435 +4425 +787 +1121 +6034 +39 +3104 +5961 +5507 +5785 +1463 +7339 +1575 +7801 +5445 +8283 +5951 +6995 +999 +5163 +6023 +6536 +5850 +3524 +3528 +4508 +6674 +2939 +8227 +4598 +7550 +8495 +8622 +1152 +4538 +1318 +739 +8202 +1552 +5236 +3576 +4699 +9238 +1879 +433 +5587 +1678 +8552 +6445 +7971 +6880 +7476 +7282 +7271 +6489 +8091 +9287 +7351 +1765 +5286 +6921 +542 +1762 +8553 +4987 +894 +3622 +7855 +92 +3131 +4811 +6517 +4510 +733 +4954 +1360 +5669 +2842 +8107 +5646 +5968 +1827 +7709 +8521 +5807 +5321 +9239 +5501 +3745 +4437 +1586 +5265 +7917 +1607 +6074 +7061 +1580 +8694 +8461 +4573 +618 +9173 +5243 +435 +8770 +2421 +7450 +3870 +8308 +2605 +2934 +9240 +6887 +4512 +1198 +7585 +7691 +7738 +2843 +8423 +6971 +7854 +86 +9128 +4298 +622 +6579 +2203 +7716 +1265 +1174 +7380 +623 +8936 +4306 +8082 +4312 +8661 +5753 +7243 +2768 +8155 +85 +4143 +3047 +8479 +7809 +2833 +5555 +7578 +1637 +1936 +8130 +5549 +8062 +7143 +5522 +8966 +5614 +8105 +8719 +7655 +7502 +8268 +5760 +6695 +5565 +7615 +9226 +4870 +4507 +3160 +4835 +1598 +4422 +5248 +7867 +1078 +5015 +6660 +1676 +6391 +5351 +7184 +6280 +5936 +6124 +1327 +2906 +269 +8292 +8809 +5167 +8142 +8204 +2713 +1910 +2930 +2494 +5592 +7384 +7726 +5727 +1735 +5710 +5518 +2491 +1410 +4989 +5183 +8777 +6562 +4947 +3692 +384 +1097 +5209 +3723 +7272 +6895 +2459 +543 +8621 +5394 +6211 +2074 +1511 +2524 +7776 +5055 +7191 +6207 +7922 +281 +8436 +2918 +3141 +4800 +6323 +7631 +8903 +3735 +5301 +3975 +2800 +7963 +105 +1920 +7391 +4909 +1754 +4816 +5145 +5139 +5268 +9317 +8631 +4346 +7318 +136 +3993 +1220 +2151 +308 +7483 +3071 +1339 +3777 +8191 +5378 +7087 +1056 +7465 +5608 +6564 +2754 +2687 +1596 +5376 +1512 +566 +6382 +1757 +8035 +2296 +4264 +1053 +4716 +8518 +254 +6253 +7132 +8557 +3490 +9267 +5473 +2412 +7539 +7136 +6670 +891 +1323 +1217 +2879 +9118 +1259 +2317 +7033 +2467 +6665 +6244 +2180 +2140 +7098 +4150 +547 +4307 +1725 +2737 +8549 +8195 +1245 +6286 +935 +1756 +1701 +1626 +7379 +3492 +3717 +5802 +2817 +1234 +1005 +4101 +21 +2576 +4650 +3381 +1030 +2844 +1641 +936 +2729 +6469 +8913 +5994 +341 +4083 +5152 +3380 +8739 +6615 +3829 +164 +7927 +4779 +4216 +8528 +3641 +4606 +2769 +6970 +8850 +4971 +5489 +2008 +4564 +8682 +7784 +5768 +9252 +901 +438 +3577 +2765 +5904 +664 +3348 +6298 +3602 +2502 +8617 +7684 +5805 +4126 +2451 +6906 +7234 +9243 +3778 +1087 +9053 +5026 +2504 +5283 +2820 +4242 +797 +3925 +1383 +8750 +7861 +1403 +6973 +7617 +3065 +5395 +4347 +8144 +2688 +6527 +8597 +8673 +7327 +6331 +1422 +7115 +244 +7013 +2092 +54 +7970 +5742 +4823 +8588 +2938 +3060 +4149 +2375 +6616 +8803 +1555 +4369 +1380 +3011 +6144 +3367 +7370 +1995 +2602 +985 +8785 +8480 +9125 +1927 +3269 +3771 +1032 +7378 +5726 +2731 +2020 +6727 +8793 +523 +6036 +58 +7993 +5512 +5049 +2721 +8482 +673 +7937 +1168 +4472 +8247 +7287 +9017 +6421 +9190 +3584 +1819 +1792 +2810 +6033 +6749 +7677 +981 +7160 +4726 +1886 +7845 +6975 +7422 +4613 +4501 +2569 +4263 +3206 +4133 +2420 +3706 +8894 +2263 +5774 +4925 +9180 +8888 +2945 +2091 +1873 +6303 +729 +2156 +3267 +1860 +6597 +4930 +5253 +938 +580 +5825 +166 +8198 +6892 +8701 +74 +7094 +8954 +3156 +6140 +4279 +2229 +5466 +8413 +7105 +8192 +2632 +7638 +9308 +8530 +832 +4643 +2201 +3268 +4322 +6510 +2967 +262 +403 +1258 +8828 +5838 +8529 +2788 +237 +3838 +1291 +4056 +5628 +7281 +6476 +7935 +2850 +6041 +2013 +4016 +4576 +5312 +6827 +6321 +8669 +830 +1519 +2750 +6106 +6993 +6235 +5899 +7313 +5331 +4371 +7086 +8600 +2660 +5409 +3465 +5499 +6231 +5745 +1801 +5337 +4468 +1451 +4192 +1275 +1114 +4960 +8860 +3900 +6468 +1505 +8868 +5588 +3858 +1947 +2565 +1472 +243 +6583 +7085 +5374 +4291 +4426 +492 +2311 +8305 +3662 +8780 +7488 +3890 +5005 +4680 +7358 +9116 +4397 +5999 +7902 +83 +3566 +2134 +8942 +4767 +6601 +1745 +5736 +5254 +8017 +4015 +7690 +3798 +8947 +1067 +7945 +590 +2547 +2535 +64 +2053 +5359 +2493 +6669 +7473 +6147 +7175 +6983 +5196 +745 +2657 +3497 +697 +3161 +7528 +2239 +5991 +3201 +7681 +5189 +2959 +2044 +8917 +2046 +6313 +6333 +5318 +4301 +2213 +2933 +4121 +3903 +4392 +7889 +5323 +1055 +707 +3857 +518 +6078 +5134 +6645 +9138 +1592 +680 +4446 +7943 +3461 +3887 +5601 +2321 +6621 +558 +4914 +913 +5637 +6453 +8511 +4531 +1218 +5508 +2603 +6802 +8426 +8297 +2947 +5971 +6552 +5262 +5935 +782 +7435 +8357 +6139 +1136 +5008 +3585 +3627 +5356 +2997 +2347 +881 +4849 +8808 +8351 +4017 +2010 +6836 +4391 +3630 +3712 +2969 +5238 +4333 +2301 +4406 +1236 +1050 +1864 +8408 +8251 +8795 +5879 +3365 +7481 +8206 +2452 +1767 +8859 +124 +3948 +4444 +8962 +4438 +5003 +8428 +3105 +5117 +1095 +8755 +7881 +3097 +4877 +155 +1917 +2455 +6042 +337 +6724 +6045 +8483 +7135 +2242 +4566 +1679 +834 +1746 +795 +3548 +2314 +2036 +4046 +9129 +7084 +5091 +2413 +8170 +5775 +1817 +529 +813 +2916 +5130 +126 +1243 +2370 +4831 +9122 +3010 +5104 +2613 +6761 +5340 +3512 +6283 +2346 +653 +6121 +2615 +7421 +1869 +1002 +8834 +2991 +8992 +632 +1093 +4543 +645 +2352 +4115 +373 +1483 +6966 +8598 +3896 +3434 +5987 +8318 +1815 +1223 +1548 +6885 +5073 +6330 +2573 +1369 +4095 +1431 +2185 +5766 +1301 +7258 +8048 +7598 +2847 +1996 +2378 +8561 +743 +6381 +271 +1956 +7439 +7134 +6636 +5804 +1858 +6214 +4730 +8536 +1203 +3118 +9202 +1875 +5885 +168 +5898 +4014 +4186 +3346 +3041 +5558 +9296 +8157 +4339 +3234 +2604 +6803 +5387 +5590 +125 +2173 +8012 +8005 +4858 +651 +372 +378 +8366 +6299 +1449 +7793 +8541 +3235 +8043 +3086 +3983 +6949 +4690 +6494 +8406 +7408 +350 +7021 +8224 +7044 +7662 +6697 +7679 +169 +528 +7029 +2790 +7432 +7602 +8333 +1582 +1378 +482 +9279 +8015 +4514 +3542 +628 +5053 +6699 +6227 +2094 +1621 +847 +3598 +2728 +7276 +6620 +8345 +4278 +4059 +9058 +4173 +8134 +1997 +3182 +3224 +8129 +5109 +4494 +189 +7640 +180 +2963 +1123 +5593 +3263 +4185 +7140 +8990 +6320 +9275 +4601 +4854 +5907 +1135 +8083 +5964 +7788 +1992 +8069 +9174 +6160 +35 +8572 +2865 +46 +3952 +6418 +2510 +5783 +3816 +2715 +3930 +2548 +5204 +708 +7756 +3825 +777 +3550 +3929 +5440 +6751 +7764 +4070 +7331 +3743 +9131 +9206 +3828 +23 +41 +4197 +234 +5723 +7622 +8832 +2169 +5599 +2976 +5266 +1967 +90 +822 +2538 +3169 +6771 +7442 +498 +4967 +5580 +7581 +7680 +4728 +1115 +1064 +3106 +6266 +4415 +9294 +5597 +7059 +197 +7218 +6948 +5690 +1653 +4485 +4019 +3370 +919 +1330 +6085 +2078 +5427 +4545 +2435 +8862 +3633 +8145 +5221 +1388 +5913 +8140 +7471 +7156 +6989 +1190 +6832 +2830 +4387 +3454 +7469 +2910 +4526 +5187 +2410 +9223 +4681 +1300 +7407 +6523 +3616 +6894 +7253 +4515 +5874 +5448 +7137 +7957 +1130 +3092 +7054 +3516 +5797 +1000 +4336 +9090 +6403 +7255 +8919 +6522 +6760 +8898 +4803 +374 +8686 +3985 +7045 +3475 +6065 +7991 +1409 +7851 +6671 +6090 +5826 +7857 +1155 +8964 +1117 +7072 +6064 +2497 +4899 +2397 +3189 +2369 +5027 +5754 +8950 +5617 +8391 +914 +6264 +279 +6174 +5184 +3733 +5278 +2924 +567 +7994 +352 +8084 +2148 +2723 +3359 +70 +1870 +7708 +220 +3994 +9013 +3191 +9220 +4155 +5717 +1110 +2198 +785 +5325 +4770 +4250 +52 +4634 +9037 +601 +8036 +7996 +2483 +7232 +8675 +8836 +1279 +5346 +7676 +6104 +1515 +4603 +5607 +5144 +2628 +68 +440 +3586 +3083 +4830 +4378 +7762 +1134 +4542 +7850 +6296 +4011 +8751 +4776 +7954 +7102 +5697 +2032 +5729 +5017 +6962 +2051 +1092 +9019 +2759 +8581 +8618 +912 +2382 +4892 +8447 +8176 +5491 +5695 +5504 +1060 +578 +4320 +2379 +7649 +8416 +1613 +5344 +7512 +7865 +3037 +6689 +6557 +1569 +5955 +3707 +9168 +8566 +1775 +5950 +6943 +7804 +434 +6179 +1142 +7947 +6456 +6291 +5789 +6538 +9134 +3049 +5075 +5161 +1623 +948 +6302 +6063 +7516 +117 +506 +3302 +7146 +355 +1081 +2827 +1496 +2574 +6167 +3183 +4287 +5482 +7319 +7277 +3860 +3443 +3298 +8364 +3826 +7254 +2360 +5093 +7039 +6325 +2567 +4443 +559 +2625 +4228 +8967 +6405 +1674 +3936 +4475 +8556 +8585 +896 +3713 +6259 +4297 +6718 +2392 +2279 +4927 +1283 +2860 +7665 +663 +596 +6293 +6805 +2811 +7383 +8306 +8330 +3153 +2153 +2618 +2441 +3615 +8092 +552 +5285 +8124 +9247 +5530 +8175 +6242 +5660 +3433 +1610 +1832 +3892 +3862 +640 +2127 +4196 +3495 +7217 +5206 +4836 +7759 +800 +4227 +3699 +9055 +5665 +6826 +7463 +9065 +4720 +5069 +3453 +3358 +6532 +5970 +7921 +4087 +1547 +3424 +8040 +7995 +6787 +9069 +8716 +2561 +8199 +1479 +2767 +7818 +7145 +604 +7597 +4896 +9281 +4666 +185 +7978 +3059 +9221 +2135 +1800 +2974 +1529 +5948 +446 +4436 +8672 +3508 +6208 +5673 +6998 +5203 +278 +7041 +9110 +5853 +8121 +1764 +3046 +6575 +4738 +2228 +7761 +9322 +7019 +6931 +6383 +6762 +283 +3935 +6785 +471 +8214 +231 +3844 +5746 +2011 +7209 +336 +6433 +756 +9167 +6741 +3345 +7685 +4018 +6682 +9147 +4790 +5836 +5906 +676 +3964 +6362 +3510 +7510 +2308 +1806 +5917 +3387 +5423 +8900 +147 +3780 +1696 +9111 +6783 +6497 +4104 +3987 +260 +4616 +2121 +9283 +1400 +4670 +2735 +2096 +6521 +1423 +4523 +2243 +6667 +6990 +3944 +6915 +6763 +404 +2691 +1015 +7092 +7562 +8624 +2291 +5934 +5503 +2326 +2960 +842 +1963 +5568 +9050 +3806 +439 +9154 +6055 +6451 +7633 +688 +4354 +8890 +2813 +2872 +8102 +6609 +1497 +8389 +6449 +1682 +3594 +5103 +5812 +863 +3054 +8079 +2260 +2027 +3091 +7687 +6703 +3557 +2019 +8427 +2799 +8182 +6641 +3168 +2284 +1934 +6507 +1658 +3811 +1774 +7897 +2238 +2943 +191 +3869 +3188 +414 +8072 +7838 +1382 +4962 +5363 +4042 +1983 +4077 +7429 +4044 +1109 +1295 +386 +5481 +3927 +311 diff --git a/ltr/data_specs/got10k_vot_val_split.txt b/ltr/data_specs/got10k_vot_val_split.txt new file mode 100755 index 0000000..734a9da --- /dev/null +++ b/ltr/data_specs/got10k_vot_val_split.txt @@ -0,0 +1,1249 @@ +1349 +5878 +562 +2202 +8904 +1501 +8654 +2975 +2689 +3680 +5180 +1900 +7707 +4723 +8912 +4029 +3579 +869 +2888 +8657 +6599 +741 +4288 +2244 +7357 +5704 +8791 +208 +4805 +8526 +4887 +8871 +7468 +3343 +886 +7794 +2646 +6454 +6101 +7885 +7744 +1297 +4119 +4856 +122 +2286 +2925 +5131 +5843 +5320 +5626 +540 +1862 +7335 +699 +7760 +9198 +3259 +7345 +8698 +1280 +6479 +3100 +3988 +1322 +5737 +1268 +3257 +6791 +3326 +4815 +7644 +1082 +2826 +6821 +8984 +2553 +5290 +5909 +4762 +8096 +8066 +4325 +6666 +7193 +7114 +8060 +7872 +6788 +3544 +5460 +3507 +2509 +6626 +3429 +5542 +4220 +2968 +5271 +3863 +1868 +5581 +2012 +6270 +8038 +4050 +121 +2845 +1565 +1998 +2275 +5524 +6068 +7624 +4913 +9277 +1506 +803 +8848 +5925 +2450 +2072 +8190 +4753 +9162 +825 +7303 +9028 +2088 +8516 +1556 +5937 +7847 +2367 +7549 +1049 +1521 +4739 +3931 +8958 +4130 +7876 +897 +5985 +7346 +7537 +111 +3700 +1126 +7896 +3419 +1051 +5720 +1068 +3458 +146 +291 +6256 +5514 +2857 +4580 +6239 +6525 +8717 +391 +4841 +6676 +4360 +4211 +73 +1675 +1987 +4025 +1321 +662 +8265 +6424 +2758 +7765 +7656 +3209 +7497 +7600 +9039 +7697 +5177 +2983 +5622 +9295 +3284 +964 +2024 +1269 +4551 +8088 +5659 +2212 +5199 +5551 +8607 +5573 +5200 +7951 +8429 +7720 +5919 +1273 +3529 +6707 +9176 +7552 +3255 +5649 +6110 +1137 +9272 +788 +5786 +5186 +2667 +7630 +3953 +1828 +8827 +6471 +7815 +467 +6387 +3195 +6238 +6508 +2373 +5983 +4931 +2948 +921 +2438 +517 +3949 +2137 +3216 +5683 +3695 +1719 +4837 +9159 +6981 +860 +7410 +5497 +1770 +5557 +8810 +5194 +4857 +9100 +6329 +2609 +1925 +3686 +9041 +4924 +349 +9187 +3393 +3661 +7120 +6858 +4587 +3831 +3130 +5060 +6486 +8023 +824 +1354 +8861 +5534 +7292 +4389 +6029 +6226 +3505 +4326 +7445 +581 +6089 +3450 +7324 +6516 +6775 +1207 +4575 +5135 +3918 +9020 +3473 +3898 +7812 +6571 +6757 +6639 +2557 +1206 +6148 +7325 +8790 +4938 +7026 +4383 +8041 +1250 +7267 +1952 +7561 +8811 +4941 +8373 +4848 +6602 +8355 +8104 +5214 +4330 +3181 +3422 +456 +1782 +3408 +6530 +719 +7587 +3058 +740 +4207 +5336 +2798 +2473 +4221 +1493 +3281 +171 +9157 +9139 +7766 +3324 +5308 +3708 +2431 +8080 +2093 +2585 +406 +7040 +5064 +5247 +4758 +6512 +4257 +4935 +2705 +2572 +3436 +8513 +1385 +2637 +7091 +2761 +6007 +6694 +2422 +4917 +2186 +6898 +1390 +6965 +7698 +2002 +2692 +7365 +7373 +4091 +947 +3962 +8692 +1788 +6862 +6856 +1950 +1914 +5658 +3635 +1620 +4780 +2580 +1454 +2786 +687 +7238 +3648 +6452 +1197 +3190 +5900 +9043 +4958 +1821 +1187 +1153 +7169 +7350 +5674 +6254 +3025 +6680 +1690 +2899 +3893 +1577 +5728 +9189 +5077 +3560 +2179 +5462 +1402 +3654 +1376 +5506 +1179 +5647 +4686 +8644 +1352 +2855 +6079 +2254 +2668 +2287 +2457 +3418 +7264 +677 +3074 +2655 +1042 +2210 +4504 +8309 +4209 +4280 +3258 +2977 +84 +4705 +1244 +3511 +6355 +8813 +3228 +9266 +1122 +613 +732 +5202 +8425 +2638 +6470 +3541 +8132 +2063 +5129 +2818 +7949 +8090 +4465 +7295 +5239 +7009 +9271 +8563 +2832 +952 +8136 +6776 +3565 +5188 +7288 +6999 +285 +5487 +7608 +8584 +2071 +7868 +2804 +3655 +6847 +3276 +4272 +3910 +1574 +4559 +7580 +5014 +8183 +6386 +7574 +356 +4937 +2487 +9315 +7572 +3040 +671 +2682 +8626 +3868 +387 +8679 +4074 +1481 +3527 +3595 +4754 +2453 +1579 +4638 +9123 +1829 +3009 +3691 +763 +4875 +3572 +4273 +2777 +6032 +4793 +233 +7147 +996 +3199 +8835 +3517 +7210 +6125 +6037 +3684 +3915 +3180 +7043 +4458 +2889 +57 +7667 +8375 +1434 +7493 +4733 +5827 +2111 +1313 +7986 +3075 +2614 +7547 +4977 +8527 +3212 +7300 +5842 +5244 +3291 +597 +1007 +2030 +227 +3830 +5540 +247 +5643 +9333 +1958 +1371 +5220 +7926 +2927 +1516 +7130 +193 +1522 +6165 +6923 +3794 +4223 +5535 +2472 +8630 +3971 +9101 +2946 +4609 +7291 +8542 +6501 +7548 +4557 +6274 +5226 +7309 +1317 +6275 +1099 +4191 +7270 +5392 +2316 +3819 +1670 +8045 +4807 +8864 +2391 +5908 +8338 +8218 +6400 +9193 +3165 +843 +6613 +6941 +5629 +7557 +4321 +3702 +681 +1159 +4665 +5959 +1697 +5509 +8774 +7389 +3832 +3751 +8637 +1680 +6841 +703 +684 +8293 +3682 +5733 +4818 +3231 +5562 +9001 +3889 +7024 +2519 +1713 +3287 +219 +8776 +2289 +7212 +4832 +4684 +4617 +4237 +2649 +8185 +6326 +3568 +551 +1426 +8869 +312 +2905 +4165 +8248 +2558 +900 +1044 +8613 +7743 +5437 +7604 +3122 +5708 +8649 +2878 +4695 +4491 +7533 +5223 +7711 +1844 +5751 +3008 +8055 +4636 +61 +198 +2271 +5698 +4596 +4500 +5709 +5819 +7972 +2992 +1643 +1048 +6281 +8886 +360 +4198 +6814 +3960 +2606 +7001 +5888 +450 +7133 +7015 +7034 +5153 +8920 +5066 +469 +1302 +8816 +463 +8651 +5869 +6582 +5578 +1231 +9274 +7260 +7751 +8052 +6799 +2089 +2342 +8451 +3260 +5550 +7795 +2288 +1205 +40 +496 +8367 +7836 +5973 +3908 +5242 +5062 +2706 +997 +5419 +9201 +1965 +6062 +3050 +5302 +8735 +358 +2398 +7470 +1644 +8179 +7047 +1549 +5414 +2539 +7381 +589 +8166 +8505 +6035 +3956 +4540 +6721 +8074 +1062 +2384 +2531 +7159 +3902 +4584 +2554 +264 +8720 +2849 +4916 +5218 +7202 +883 +4560 +1677 +4317 +7863 +4509 +6577 +2903 +1452 +1416 +5369 +473 +6233 +6359 +5992 +4934 +8059 +6834 +4907 +3320 +8267 +8280 +2066 +2402 +1485 +3772 +3732 +4764 +9126 +3575 +5564 +5641 +1884 +2330 +1804 +344 +698 +3089 +1532 +4454 +761 +8094 +3432 +6811 +8722 +8826 +3222 +8614 +2901 +7003 +652 +8663 +4266 +413 +810 +75 +3334 +4905 +6438 +4756 +5137 +6528 +6534 +6988 +6177 +8533 +889 +5384 +7201 +5132 +7802 +6864 +3973 +873 +4840 +1482 +8376 +3769 +5858 +6675 +4286 +2593 +5863 +4353 +7817 +7540 +4999 +4838 +2303 +7913 +1508 +7755 +2784 +4964 +3431 +6209 +3755 +6399 +3954 +455 +5416 +7591 +245 +140 +9210 +4084 +967 +7798 +6795 +7095 +6733 +3861 +9264 +1045 +755 +8042 +7074 +7778 +6415 +4724 +6450 +2049 +1307 +3485 +1790 +7869 +3282 +6907 +3920 +2868 +5801 +5632 +5009 +3955 +7517 +5128 +3417 +3019 +1784 +2312 +2753 +6976 +342 +8266 +1849 +2273 +5037 +7880 +3793 +7401 +5412 +8279 +1257 +3670 +9049 +3266 +8955 +6519 +8916 +2858 +694 +5650 +4669 +1785 +3533 +2704 +8603 +3726 +6668 +497 +6815 +6157 +6646 +6964 +8097 +5645 +8481 +8215 +3775 +2542 +7514 +5699 +3518 +3740 +1404 +8981 +4086 +6397 +4204 +6899 +682 +6589 +4340 +7424 +9208 +6504 +4409 +1 +145 +1882 +4620 +2634 +4992 +5453 +3377 +7875 +530 +1235 +7605 +504 +1771 +8489 +345 +7353 +7797 +7174 +5914 +2871 +5721 +6067 +3582 +5467 +6234 +691 +8758 +2122 +1213 +1492 +1437 +2187 +1266 +2395 +7278 +8491 +5256 +1554 +8163 +5966 +7128 +7904 +1691 +6272 +3996 +1706 +1334 +1316 +6478 +6935 +1518 +6700 +8703 +8744 +8152 +8778 +5367 +4218 +9007 +6312 +606 +7565 +5293 +2891 +675 +2120 +826 +7008 +5705 +7748 +8010 +1498 +5330 +5472 +2215 +7627 +3016 +6588 +1850 +4128 +8569 +6987 +148 +8151 +8789 +7907 +8596 +715 +9060 +3872 +1750 +5889 +4047 +5960 +3120 +3449 +1421 +1102 +3333 +9197 +8796 +8123 +8007 +2028 +8404 +1945 +1985 +8109 +5380 +3504 +6739 +4180 +5835 +4243 +25 +4002 +1976 +158 +5181 +4885 +8985 +11 +6425 +5926 +7062 +5083 +8394 +4259 +5844 +1990 +3942 +5532 +2220 +28 +5957 +149 +6748 +3559 +7647 +2566 +1359 +5259 +7010 +554 +6005 +8172 +8125 +1350 +9051 +1973 +1386 +159 +7007 +3220 +1846 +3093 +4445 +2056 +8370 +3211 +4384 +2231 +273 +642 +5311 +265 +226 +9012 +7879 +118 +7109 +7251 +1760 +8667 +2876 +7162 +3552 +6901 +6779 +5021 +6524 +4957 +3114 +4544 +441 +1848 +2136 +2458 +8662 +1127 +5541 +3026 +1080 +6780 +2224 +8259 +1073 +9000 +7244 +7977 +500 +4435 +7376 +7979 +1435 +9291 +7704 +3521 +210 +6269 +8570 +3285 +8039 +3546 +6203 +1183 +6107 +4147 +2234 +7185 +3192 +7155 +2001 +7777 +876 +944 +908 +7791 +6784 +65 +9172 +5675 +3886 +7891 +2978 +1008 +5630 +591 +5067 +1139 +577 +9015 +574 +8137 +7786 +5765 +4900 +4090 +7842 diff --git a/ltr/data_specs/lasot_train_split.txt b/ltr/data_specs/lasot_train_split.txt new file mode 100755 index 0000000..ffa2be4 --- /dev/null +++ b/ltr/data_specs/lasot_train_split.txt @@ -0,0 +1,1120 @@ +airplane-10 +airplane-11 +airplane-12 +airplane-14 +airplane-16 +airplane-17 +airplane-18 +airplane-19 +airplane-2 +airplane-20 +airplane-3 +airplane-4 +airplane-5 +airplane-6 +airplane-7 +airplane-8 +basketball-10 +basketball-12 +basketball-13 +basketball-14 +basketball-15 +basketball-16 +basketball-17 +basketball-18 +basketball-19 +basketball-2 +basketball-20 +basketball-3 +basketball-4 +basketball-5 +basketball-8 +basketball-9 +bear-1 +bear-10 +bear-11 +bear-12 +bear-13 +bear-14 +bear-15 +bear-16 +bear-18 +bear-19 +bear-20 +bear-3 +bear-5 +bear-7 +bear-8 +bear-9 +bicycle-1 +bicycle-10 +bicycle-11 +bicycle-12 +bicycle-13 +bicycle-14 +bicycle-15 +bicycle-16 +bicycle-17 +bicycle-19 +bicycle-20 +bicycle-3 +bicycle-4 +bicycle-5 +bicycle-6 +bicycle-8 +bird-1 +bird-10 +bird-11 +bird-12 +bird-13 +bird-14 +bird-16 +bird-18 +bird-19 +bird-20 +bird-4 +bird-5 +bird-6 +bird-7 +bird-8 +bird-9 +boat-1 +boat-10 +boat-11 +boat-13 +boat-14 +boat-15 +boat-16 +boat-18 +boat-19 +boat-2 +boat-20 +boat-5 +boat-6 +boat-7 +boat-8 +boat-9 +book-1 +book-12 +book-13 +book-14 +book-15 +book-16 +book-17 +book-18 +book-2 +book-20 +book-4 +book-5 +book-6 +book-7 +book-8 +book-9 +bottle-10 +bottle-11 +bottle-13 +bottle-15 +bottle-16 +bottle-17 +bottle-19 +bottle-2 +bottle-20 +bottle-3 +bottle-4 +bottle-5 +bottle-6 +bottle-7 +bottle-8 +bottle-9 +bus-1 +bus-10 +bus-11 +bus-12 +bus-13 +bus-14 +bus-15 +bus-16 +bus-18 +bus-20 +bus-3 +bus-4 +bus-6 +bus-7 +bus-8 +bus-9 +car-1 +car-10 +car-11 +car-12 +car-13 +car-14 +car-15 +car-16 +car-18 +car-19 +car-20 +car-3 +car-4 +car-5 +car-7 +car-8 +cat-10 +cat-11 +cat-12 +cat-13 +cat-14 +cat-15 +cat-16 +cat-17 +cat-19 +cat-2 +cat-4 +cat-5 +cat-6 +cat-7 +cat-8 +cat-9 +cattle-1 +cattle-10 +cattle-11 +cattle-14 +cattle-15 +cattle-16 +cattle-17 +cattle-18 +cattle-19 +cattle-20 +cattle-3 +cattle-4 +cattle-5 +cattle-6 +cattle-8 +cattle-9 +chameleon-1 +chameleon-10 +chameleon-12 +chameleon-13 +chameleon-14 +chameleon-15 +chameleon-16 +chameleon-17 +chameleon-18 +chameleon-19 +chameleon-2 +chameleon-4 +chameleon-5 +chameleon-7 +chameleon-8 +chameleon-9 +coin-1 +coin-10 +coin-11 +coin-12 +coin-13 +coin-14 +coin-15 +coin-16 +coin-17 +coin-19 +coin-2 +coin-20 +coin-4 +coin-5 +coin-8 +coin-9 +crab-1 +crab-10 +crab-11 +crab-13 +crab-14 +crab-15 +crab-16 +crab-17 +crab-19 +crab-2 +crab-20 +crab-4 +crab-5 +crab-7 +crab-8 +crab-9 +crocodile-1 +crocodile-11 +crocodile-12 +crocodile-13 +crocodile-15 +crocodile-16 +crocodile-17 +crocodile-18 +crocodile-19 +crocodile-2 +crocodile-20 +crocodile-5 +crocodile-6 +crocodile-7 +crocodile-8 +crocodile-9 +cup-10 +cup-11 +cup-12 +cup-13 +cup-14 +cup-15 +cup-16 +cup-18 +cup-19 +cup-2 +cup-20 +cup-3 +cup-5 +cup-6 +cup-8 +cup-9 +deer-1 +deer-11 +deer-12 +deer-13 +deer-15 +deer-16 +deer-17 +deer-18 +deer-19 +deer-2 +deer-20 +deer-3 +deer-5 +deer-6 +deer-7 +deer-9 +dog-10 +dog-11 +dog-12 +dog-13 +dog-14 +dog-16 +dog-17 +dog-18 +dog-2 +dog-20 +dog-3 +dog-4 +dog-5 +dog-6 +dog-8 +dog-9 +drone-1 +drone-10 +drone-11 +drone-12 +drone-14 +drone-16 +drone-17 +drone-18 +drone-19 +drone-20 +drone-3 +drone-4 +drone-5 +drone-6 +drone-8 +drone-9 +electricfan-11 +electricfan-12 +electricfan-13 +electricfan-14 +electricfan-15 +electricfan-16 +electricfan-17 +electricfan-19 +electricfan-2 +electricfan-3 +electricfan-4 +electricfan-5 +electricfan-6 +electricfan-7 +electricfan-8 +electricfan-9 +elephant-10 +elephant-11 +elephant-13 +elephant-14 +elephant-15 +elephant-17 +elephant-19 +elephant-2 +elephant-20 +elephant-3 +elephant-4 +elephant-5 +elephant-6 +elephant-7 +elephant-8 +elephant-9 +flag-1 +flag-10 +flag-11 +flag-12 +flag-13 +flag-14 +flag-15 +flag-16 +flag-17 +flag-18 +flag-19 +flag-20 +flag-4 +flag-6 +flag-7 +flag-8 +fox-1 +fox-10 +fox-11 +fox-12 +fox-13 +fox-14 +fox-15 +fox-16 +fox-17 +fox-18 +fox-19 +fox-4 +fox-6 +fox-7 +fox-8 +fox-9 +frog-1 +frog-10 +frog-11 +frog-12 +frog-13 +frog-14 +frog-15 +frog-16 +frog-17 +frog-18 +frog-19 +frog-2 +frog-5 +frog-6 +frog-7 +frog-8 +gametarget-10 +gametarget-11 +gametarget-12 +gametarget-14 +gametarget-15 +gametarget-16 +gametarget-17 +gametarget-18 +gametarget-19 +gametarget-20 +gametarget-3 +gametarget-4 +gametarget-5 +gametarget-6 +gametarget-8 +gametarget-9 +gecko-10 +gecko-11 +gecko-12 +gecko-13 +gecko-14 +gecko-15 +gecko-17 +gecko-18 +gecko-2 +gecko-20 +gecko-3 +gecko-4 +gecko-6 +gecko-7 +gecko-8 +gecko-9 +giraffe-1 +giraffe-11 +giraffe-12 +giraffe-14 +giraffe-16 +giraffe-17 +giraffe-18 +giraffe-19 +giraffe-20 +giraffe-3 +giraffe-4 +giraffe-5 +giraffe-6 +giraffe-7 +giraffe-8 +giraffe-9 +goldfish-1 +goldfish-11 +goldfish-12 +goldfish-13 +goldfish-14 +goldfish-15 +goldfish-16 +goldfish-17 +goldfish-18 +goldfish-19 +goldfish-2 +goldfish-20 +goldfish-4 +goldfish-5 +goldfish-6 +goldfish-9 +gorilla-1 +gorilla-10 +gorilla-11 +gorilla-12 +gorilla-14 +gorilla-15 +gorilla-16 +gorilla-17 +gorilla-18 +gorilla-19 +gorilla-2 +gorilla-20 +gorilla-3 +gorilla-5 +gorilla-7 +gorilla-8 +guitar-1 +guitar-11 +guitar-12 +guitar-13 +guitar-14 +guitar-15 +guitar-17 +guitar-18 +guitar-19 +guitar-2 +guitar-20 +guitar-4 +guitar-5 +guitar-6 +guitar-7 +guitar-9 +hand-1 +hand-10 +hand-11 +hand-12 +hand-13 +hand-14 +hand-15 +hand-17 +hand-18 +hand-19 +hand-20 +hand-4 +hand-5 +hand-6 +hand-7 +hand-8 +hat-10 +hat-11 +hat-12 +hat-13 +hat-14 +hat-15 +hat-16 +hat-17 +hat-19 +hat-20 +hat-3 +hat-4 +hat-6 +hat-7 +hat-8 +hat-9 +helmet-1 +helmet-10 +helmet-12 +helmet-14 +helmet-15 +helmet-16 +helmet-17 +helmet-18 +helmet-2 +helmet-20 +helmet-3 +helmet-4 +helmet-6 +helmet-7 +helmet-8 +helmet-9 +hippo-10 +hippo-11 +hippo-12 +hippo-13 +hippo-14 +hippo-15 +hippo-16 +hippo-17 +hippo-18 +hippo-19 +hippo-2 +hippo-3 +hippo-4 +hippo-5 +hippo-6 +hippo-8 +horse-10 +horse-11 +horse-13 +horse-14 +horse-16 +horse-17 +horse-18 +horse-19 +horse-2 +horse-20 +horse-3 +horse-5 +horse-6 +horse-7 +horse-8 +horse-9 +kangaroo-1 +kangaroo-10 +kangaroo-12 +kangaroo-13 +kangaroo-15 +kangaroo-16 +kangaroo-17 +kangaroo-18 +kangaroo-19 +kangaroo-20 +kangaroo-3 +kangaroo-4 +kangaroo-6 +kangaroo-7 +kangaroo-8 +kangaroo-9 +kite-1 +kite-11 +kite-12 +kite-13 +kite-14 +kite-16 +kite-17 +kite-18 +kite-19 +kite-2 +kite-20 +kite-3 +kite-5 +kite-7 +kite-8 +kite-9 +leopard-10 +leopard-11 +leopard-12 +leopard-13 +leopard-14 +leopard-15 +leopard-17 +leopard-18 +leopard-19 +leopard-2 +leopard-3 +leopard-4 +leopard-5 +leopard-6 +leopard-8 +leopard-9 +licenseplate-1 +licenseplate-10 +licenseplate-11 +licenseplate-14 +licenseplate-16 +licenseplate-17 +licenseplate-18 +licenseplate-19 +licenseplate-2 +licenseplate-20 +licenseplate-3 +licenseplate-4 +licenseplate-5 +licenseplate-7 +licenseplate-8 +licenseplate-9 +lion-10 +lion-11 +lion-13 +lion-14 +lion-15 +lion-16 +lion-17 +lion-18 +lion-19 +lion-2 +lion-3 +lion-4 +lion-6 +lion-7 +lion-8 +lion-9 +lizard-10 +lizard-11 +lizard-12 +lizard-14 +lizard-15 +lizard-16 +lizard-17 +lizard-18 +lizard-19 +lizard-2 +lizard-20 +lizard-4 +lizard-5 +lizard-7 +lizard-8 +lizard-9 +microphone-1 +microphone-10 +microphone-11 +microphone-12 +microphone-13 +microphone-15 +microphone-17 +microphone-18 +microphone-19 +microphone-20 +microphone-3 +microphone-4 +microphone-5 +microphone-7 +microphone-8 +microphone-9 +monkey-1 +monkey-10 +monkey-11 +monkey-12 +monkey-13 +monkey-14 +monkey-15 +monkey-16 +monkey-18 +monkey-19 +monkey-2 +monkey-20 +monkey-5 +monkey-6 +monkey-7 +monkey-8 +motorcycle-10 +motorcycle-11 +motorcycle-12 +motorcycle-13 +motorcycle-14 +motorcycle-15 +motorcycle-16 +motorcycle-17 +motorcycle-19 +motorcycle-2 +motorcycle-20 +motorcycle-4 +motorcycle-5 +motorcycle-6 +motorcycle-7 +motorcycle-8 +mouse-10 +mouse-11 +mouse-12 +mouse-13 +mouse-14 +mouse-15 +mouse-16 +mouse-18 +mouse-19 +mouse-2 +mouse-20 +mouse-3 +mouse-4 +mouse-5 +mouse-6 +mouse-7 +person-11 +person-13 +person-14 +person-15 +person-16 +person-17 +person-18 +person-19 +person-2 +person-20 +person-3 +person-4 +person-6 +person-7 +person-8 +person-9 +pig-1 +pig-11 +pig-12 +pig-14 +pig-15 +pig-16 +pig-17 +pig-19 +pig-20 +pig-3 +pig-4 +pig-5 +pig-6 +pig-7 +pig-8 +pig-9 +pool-1 +pool-10 +pool-11 +pool-13 +pool-14 +pool-16 +pool-17 +pool-18 +pool-19 +pool-2 +pool-20 +pool-4 +pool-5 +pool-6 +pool-8 +pool-9 +rabbit-1 +rabbit-11 +rabbit-12 +rabbit-14 +rabbit-15 +rabbit-16 +rabbit-18 +rabbit-2 +rabbit-20 +rabbit-3 +rabbit-4 +rabbit-5 +rabbit-6 +rabbit-7 +rabbit-8 +rabbit-9 +racing-1 +racing-11 +racing-12 +racing-13 +racing-14 +racing-17 +racing-18 +racing-19 +racing-2 +racing-3 +racing-4 +racing-5 +racing-6 +racing-7 +racing-8 +racing-9 +robot-10 +robot-11 +robot-12 +robot-13 +robot-14 +robot-15 +robot-16 +robot-17 +robot-18 +robot-2 +robot-20 +robot-3 +robot-4 +robot-6 +robot-7 +robot-9 +rubicCube-10 +rubicCube-11 +rubicCube-12 +rubicCube-13 +rubicCube-15 +rubicCube-16 +rubicCube-17 +rubicCube-18 +rubicCube-2 +rubicCube-20 +rubicCube-3 +rubicCube-4 +rubicCube-5 +rubicCube-7 +rubicCube-8 +rubicCube-9 +sepia-1 +sepia-10 +sepia-11 +sepia-12 +sepia-14 +sepia-15 +sepia-17 +sepia-18 +sepia-19 +sepia-2 +sepia-20 +sepia-3 +sepia-4 +sepia-5 +sepia-7 +sepia-9 +shark-1 +shark-10 +shark-11 +shark-12 +shark-13 +shark-14 +shark-15 +shark-16 +shark-17 +shark-18 +shark-19 +shark-20 +shark-4 +shark-7 +shark-8 +shark-9 +sheep-1 +sheep-10 +sheep-11 +sheep-12 +sheep-13 +sheep-14 +sheep-15 +sheep-16 +sheep-17 +sheep-18 +sheep-19 +sheep-2 +sheep-20 +sheep-4 +sheep-6 +sheep-8 +skateboard-1 +skateboard-10 +skateboard-11 +skateboard-12 +skateboard-13 +skateboard-14 +skateboard-15 +skateboard-17 +skateboard-18 +skateboard-2 +skateboard-20 +skateboard-4 +skateboard-5 +skateboard-6 +skateboard-7 +skateboard-9 +spider-1 +spider-10 +spider-11 +spider-12 +spider-13 +spider-15 +spider-17 +spider-19 +spider-2 +spider-3 +spider-4 +spider-5 +spider-6 +spider-7 +spider-8 +spider-9 +squirrel-1 +squirrel-10 +squirrel-12 +squirrel-14 +squirrel-15 +squirrel-16 +squirrel-17 +squirrel-18 +squirrel-2 +squirrel-20 +squirrel-3 +squirrel-4 +squirrel-5 +squirrel-6 +squirrel-7 +squirrel-9 +surfboard-1 +surfboard-10 +surfboard-11 +surfboard-13 +surfboard-14 +surfboard-15 +surfboard-16 +surfboard-17 +surfboard-18 +surfboard-19 +surfboard-2 +surfboard-20 +surfboard-3 +surfboard-6 +surfboard-7 +surfboard-9 +swing-1 +swing-11 +swing-12 +swing-13 +swing-15 +swing-16 +swing-18 +swing-19 +swing-2 +swing-3 +swing-4 +swing-5 +swing-6 +swing-7 +swing-8 +swing-9 +tank-1 +tank-10 +tank-11 +tank-12 +tank-13 +tank-15 +tank-17 +tank-18 +tank-19 +tank-2 +tank-20 +tank-3 +tank-4 +tank-5 +tank-7 +tank-8 +tiger-1 +tiger-10 +tiger-11 +tiger-13 +tiger-14 +tiger-15 +tiger-16 +tiger-17 +tiger-19 +tiger-2 +tiger-20 +tiger-3 +tiger-5 +tiger-7 +tiger-8 +tiger-9 +train-10 +train-12 +train-13 +train-14 +train-15 +train-16 +train-17 +train-18 +train-19 +train-2 +train-3 +train-4 +train-5 +train-6 +train-8 +train-9 +truck-1 +truck-10 +truck-11 +truck-12 +truck-13 +truck-14 +truck-15 +truck-17 +truck-18 +truck-19 +truck-2 +truck-20 +truck-4 +truck-5 +truck-8 +truck-9 +turtle-1 +turtle-10 +turtle-11 +turtle-12 +turtle-13 +turtle-14 +turtle-15 +turtle-17 +turtle-18 +turtle-19 +turtle-2 +turtle-20 +turtle-3 +turtle-4 +turtle-6 +turtle-7 +umbrella-1 +umbrella-10 +umbrella-11 +umbrella-12 +umbrella-13 +umbrella-14 +umbrella-15 +umbrella-16 +umbrella-18 +umbrella-20 +umbrella-3 +umbrella-4 +umbrella-5 +umbrella-6 +umbrella-7 +umbrella-8 +volleyball-10 +volleyball-11 +volleyball-12 +volleyball-14 +volleyball-15 +volleyball-16 +volleyball-17 +volleyball-2 +volleyball-20 +volleyball-3 +volleyball-4 +volleyball-5 +volleyball-6 +volleyball-7 +volleyball-8 +volleyball-9 +yoyo-1 +yoyo-10 +yoyo-11 +yoyo-12 +yoyo-13 +yoyo-14 +yoyo-16 +yoyo-18 +yoyo-2 +yoyo-20 +yoyo-3 +yoyo-4 +yoyo-5 +yoyo-6 +yoyo-8 +yoyo-9 +zebra-1 +zebra-11 +zebra-12 +zebra-13 +zebra-15 +zebra-18 +zebra-19 +zebra-2 +zebra-20 +zebra-3 +zebra-4 +zebra-5 +zebra-6 +zebra-7 +zebra-8 +zebra-9 diff --git a/ltr/data_specs/trackingnet_classmap.txt b/ltr/data_specs/trackingnet_classmap.txt new file mode 100755 index 0000000..fd5dabc --- /dev/null +++ b/ltr/data_specs/trackingnet_classmap.txt @@ -0,0 +1,30133 @@ +AAB6lO-XiKE_0 person +AACM71csS-Q_0 person +AACM71csS-Q_1 person +AARNQeeGCeM_1 person +AARldOxX9Qc_0 bird +AATSbTthMRo_1 person +AAVQ--F7Bk8_7 bird +AAVQ--F7Bk8_2 bird +AAVQ--F7Bk8_8 bird +AAWK6esRYaE_0 person +AAWK6esRYaE_1 person +AAjY2Ci68z8_0 person +AA19zjGEPvg_1 bear +AA28Bcp5cJ4_0 train +ABBGULxaufw_0 person +ABF8Qzi1y6k_1 bear +ABIlEiPfEC4_0 bird +ABJ_agLToOw_0 bird +ABZMoeeFyek_0 bicycle +ABny-jw1_S0_0 elephant +ABrhnT3LRWs_2 cat +ABxlnMGfo5c_0 umbrella +AByCCGnybVU_1 person +AB2MjrpRiEQ_0 horse +AB-q-hxh9XQ_4 bus +AB-q-hxh9XQ_1 bus +AB-q-hxh9XQ_3 bus +ACDuy9fWQCs_1 umbrella +ACFxVnoXE2k_1 horse +ACMvGMt8Neo_0 person +ACM6PJWHfcM_0 person +ACOGOPL4ZH0_1 person +ACOGOPL4ZH0_0 person +ACS5TtaAdG8_0 truck +ACarEC5tuT8_0 truck +ACiNZsAvVTE_0 person +ACkYaVC9f9M_1 umbrella +ACnQKLobnGE_4 airplane +ACnQKLobnGE_5 airplane +AC0Z4yw1hf0_0 person +AC0Z4yw1hf0_1 person +AC-10OYYnLM_1 person +AC-10OYYnLM_0 person +ADHNPU5iB_4_0 cat +ADWpC6kDWFU_0 person +ADiIG2D8pds_2 motorcycle +ADiIG2D8pds_0 motorcycle +ADi674XOuRY_0 dog +ADn8ZdVYOcc_0 train +ADn8ZdVYOcc_2 train +AD1cVG81mpA_0 person +AD4EACfWAIM_0 horse +AD4EACfWAIM_1 horse +AD531xkux4k_0 person +AD7A6_o0Las_0 horse +AEQT6XxEeT0_0 person +AEQT6XxEeT0_1 person +AESfphazWKA_0 person +AESfphazWKA_1 person +AEokTVMPd4A_0 person +AEtwwIR9UkI_0 dog +AE2TrzJHr2s_1 motorcycle +AE3t_VNk3eo_0 person +AE6G6W2CL9M_1 person +AE7tEK8S9pk_0 bird +AE7tEK8S9pk_3 bird +AE-k9jcdaJk_1 giraffe +AFLrK88FzTI_0 motorcycle +AFOjy-9Kf-8_0 person +AFSTw_O6inE_0 person +AFSTw_O6inE_1 person +AFT64SYoPTo_1 person +AFeRUltwvNE_0 knife +AFeRUltwvNE_2 knife +AFf9I30fB6U_0 person +AFkSCsJ_jeg_0 person +AFkSCsJ_jeg_1 person +AFnPp9mvoJs_0 horse +AFpVfranYCA_1 knife +AFrLubifeb4_0 airplane +AFrLubifeb4_2 airplane +AFsmSsZBS6I_1 person +AFsmSsZBS6I_0 person +AF0FDnfdpro_0 train +AF0-2lDeBME_1 bird +AF2bYjH_Q8c_0 person +AF4nO1MeUis_1 train +AGV9gZ6ePKk_0 airplane +AGXVFK896Os_0 cow +AGYehDNUqx0_1 airplane +AGYehDNUqx0_0 airplane +AGdqwMVGRoU_0 horse +AGfcGfMXHPM_3 elephant +AGsg2IV8FME_1 skateboard +ZBPURFcpqDM_0 motorcycle +ZBXAMWkamQk_2 knife +ZBXAMWkamQk_1 knife +ZBcCcSynS3Y_1 car +ZBcTSnaCcqE_1 person +ZBcTSnaCcqE_0 person +ZBcjhADZaUk_0 bear +ZBdz7fg01uE_0 umbrella +ZBp5ICCzoK8_0 person +ZBriZpPQR6Q_0 cat +ZBvEIHeKcKg_2 zebra +ZBvEIHeKcKg_9 zebra +ZBvEIHeKcKg_0 zebra +ZBvEIHeKcKg_1 zebra +ZBvEIHeKcKg_3 zebra +ZBvEIHeKcKg_4 zebra +ZBvEIHeKcKg_5 zebra +ZBvEIHeKcKg_6 zebra +ZBvEIHeKcKg_7 zebra +ZBvEIHeKcKg_8 zebra +ZB0EfmbWfng_0 horse +ZB0kV8Ni0e8_0 person +ZB_pe6v1lVI_0 person +ZB_pe6v1lVI_2 person +ZCAOpABRfTI_10 elephant +ZCAOpABRfTI_0 elephant +ZCAOpABRfTI_3 elephant +ZCAOpABRfTI_4 elephant +ZCAOpABRfTI_6 elephant +ZCAOpABRfTI_7 elephant +ZCAOpABRfTI_8 elephant +ZCFCltdIjeg_1 person +ZCFCltdIjeg_0 person +ZCGB4r_lWmY_0 horse +ZCS_eyAufDo_0 person +ZCTwXcewINc_0 cow +ZCfqT4CDOYA_1 bird +ZCgDbEHLsIg_0 person +ZClABNZVqqw_1 person +ZCmoG6WgVO4_1 person +ZCmoG6WgVO4_0 person +ZCnJ6weWtz8_1 person +ZCnJ6weWtz8_0 person +ZCnJ6weWtz8_2 person +ZCzrSOZhkx8_1 person +ZCzrSOZhkx8_2 person +ZC3Y42jSG_0_0 person +ZC5Jtr93Fc0_0 cat +ZDDtjYsFrzY_0 motorcycle +ZDMLHna_uZU_1 skateboard +ZDMSLfnIpw0_0 person +ZDS-TQTDheA_0 person +ZDWUEeCoa0c_0 person +ZDfRsMjEWrU_0 person +ZDucdx9SldA_0 bicycle +ZDwG7VWIZ2E_0 motorcycle +ZDw-tgE8yQw_0 person +ZEA5lDwY3hY_0 person +ZERPmLuCNr0_1 skateboard +ZEYyXBrvcIU_0 person +ZEbxfeAOLec_1 motorcycle +ZEdGptkowmk_2 cow +ZEdsROg2ZAk_2 horse +ZEgcTqeZxOk_1 person +ZEiW5hvCQyM_0 bird +ZE16Mis16oE_0 bus +ZE3Vro7d4pA_0 cat +ZE415SbIjYI_7 bird +ZE5h8vmL_Vw_0 boat +ZE6oeN8ZzDA_1 person +ZE6oeN8ZzDA_0 person +ZFKQ9r76HHU_1 elephant +ZFKYTz9Jkhw_0 umbrella +ZFSspVdQ_1M_0 person +ZFSspVdQ_1M_1 person +ZFe5vGzmYgY_0 bear +ZFe5vGzmYgY_4 bear +ZFfH8M8dMH8_5 bird +ZFk9b7tQz1g_0 person +ZFn422HSENU_2 airplane +ZFw7fJO3h3U_0 motorcycle +ZF2yE0Tm8D0_0 cow +ZF5yV-qvHfg_0 bicycle +ZF8rySXBivY_0 person +ZF_u1UFqAvg_0 person +ZGHtP6pLosk_0 person +ZGT9Ky1jJ0E_0 horse +ZGWqLNy2PDM_2 bird +ZGeWYNFOH7U_0 person +ZGhdqsb3kNA_0 car +ZGhdqsb3kNA_3 car +ZGhdqsb3kNA_1 car +ZGkmBkelEBU_0 person +ZGpMZT1HUiw_0 horse +ZGsHiz0oPuw_0 bus +ZGvfU-Fgk40_1 person +ZGyWFwMmdbs_0 person +ZG9dVnPGocw_0 person +ZHDkDNgRSz0_0 train +ZHFPykjdFAY_1 person +ZHPeB20mRyI_0 cow +ZHPeB20mRyI_1 cow +ZHX1xXuU_Jw_0 person +ZHlb-NoDPiE_1 elephant +ZHlb-NoDPiE_2 elephant +ZHlb-NoDPiE_4 elephant +ZHl7b8RItn0_0 horse +ZHnW6ge8wBc_0 cat +ZHodaPFcFYU_0 person +ZHovXJVH8xk_0 truck +ZHpZ3CGHl44_0 person +ZHrrW673jzQ_1 person +ZHrrW673jzQ_0 person +ZHrsTuxP7aI_1 horse +ZHu6CNOlw3g_0 cow +ZHu6CNOlw3g_1 cow +ZHxx4jT0QY8_0 person +ZH1tP4KBq4c_0 giraffe +ZH5HXdNA_Vg_0 person +ZH-X6nu5grI_33 horse +ZH-X6nu5grI_2 horse +ZH-X6nu5grI_3 horse +ZH-X6nu5grI_6 horse +ZH-X6nu5grI_7 horse +ZH-X6nu5grI_8 horse +ZH_6GNzE7AE_0 person +ZIAnd6kIMac_0 bird +ZIAnd6kIMac_1 bird +ZICz-o8kLz0_0 skateboard +AGx9YQ6C-6o_7 car +AG1KXUn4YG0_0 person +AG_bCNeWGbQ_0 elephant +AHARpIfT490_0 dog +AHIF--VOeQs_0 person +AHJcPNPqKmI_0 horse +AHKFqtjfRZA_2 bear +AHLL47_EdEA_1 person +AHLL47_EdEA_0 person +AHNC2jifaeA_1 airplane +AHQLEaBATbw_0 person +AHQW1ru8IzY_0 airplane +AHQrFFp5yq4_0 airplane +AHiwgwMi8HU_0 dog +AHjEWaIP4Us_0 cow +AHkvSb7kMDQ_0 person +AHn7KxEbpSw_0 person +AHvhccaU6e0_0 bus +AHx-m9m2WSM_0 person +AIAtwCnT8D0_1 person +AIBVp_3pm4U_1 person +AIBVp_3pm4U_0 person +AIFwUvUUIAU_1 person +AIPKb-NMVjk_0 airplane +AIPKb-NMVjk_3 airplane +AIVpT8BRXaQ_1 horse +AIYDjtWzamM_0 bear +AIYDjtWzamM_1 bear +AIZGolX95Do_0 person +AIbvvs9Mppk_0 person +AIduTWoo-tY_0 skateboard +AIeFzUH7L38_1 train +AIkHZuaZGZc_1 elephant +AIkHZuaZGZc_2 elephant +AIpwAHaTBsI_0 train +AI00Hva5A8g_0 person +AI38cuNcfsE_0 knife +AI73dwp8OlI_1 train +AJAy74dPvNA_0 person +AJCXZxF7mEU_1 skateboard +AJDMiWpRbdY_0 person +AJILdTCo1mA_0 dog +AJKXpUsj3I0_0 bird +AJRdbCnFyVo_0 elephant +AJTfeXepoNQ_0 bus +AJZ65x_ashE_0 airplane +AJaOK6nLWLU_0 person +AJaOK6nLWLU_1 person +AJaOK6nLWLU_2 person +AJh6EhObuEU_0 person +AJiQZJH_ZsU_0 bird +AJiYw7-oCvA_1 knife +AJiYw7-oCvA_2 knife +AJiYw7-oCvA_0 knife +AJkWw2b2Qjg_0 horse +AJor90pfjM8_0 cow +AJtuQLfNvSs_0 cat +AKBoEjrtQwE_1 train +AKDi2KVrR1Q_0 skateboard +AKIcyYzL9C0_0 cat +AKMl62ZFICw_3 bus +AKMl62ZFICw_1 bus +AKN6nvHB7P0_2 airplane +AKN6nvHB7P0_3 airplane +AKPDvaUNx94_1 horse +AKPDvaUNx94_2 horse +AKVUSpeg9Jk_0 knife +AKxpzCrmsi8_0 bus +AK4AJfDZfEo_0 cat +AK64udGI1BA_0 umbrella +AK8imx-InYk_1 horse +AK8imx-InYk_2 horse +AK_J57sNeeo_1 elephant +AK_0-KHw9wc_1 horse +ALCj6V-0pU8_0 person +ALKBlOms7sk_0 truck +ALLYkPepYRc_0 train +ALRR_HHP500_0 person +ALRzJ2FzEoY_0 person +ALYKJChPG6k_0 knife +ALjxXEqJFTg_0 train +ALpnjTPWIN4_0 bird +AL73oE_aovA_2 bicycle +AL73oE_aovA_3 bicycle +AMDjY36EpsU_0 truck +AMEZhZVe7hk_0 person +AMEZhZVe7hk_1 person +AMI4Xu1mmNw_0 elephant +AMZeyszxY78_0 knife +AMn7aithVV8_0 car +AMz8PhUkmpM_0 horse +AMz8PhUkmpM_3 horse +AMz8PhUkmpM_7 horse +AMz8PhUkmpM_2 horse +AMz8PhUkmpM_5 horse +AM5_HQ705r4_1 giraffe +AM6sweCILPU_0 airplane +ANHdxFi36CM_1 bird +ANNbcEcj8Do_0 person +ANQZ1MB6gI4_0 skateboard +ANVkluf6XZA_0 cat +ANWtZTJoYYc_0 dog +ANZDRJnX_Os_0 person +ANlhuKqnObE_1 person +ANlhuKqnObE_0 person +ANmJ_3l01rw_2 horse +ANmJ_3l01rw_3 horse +ANmkxc2V7qQ_0 person +ANufFQ7Fqao_0 car +ANufFQ7Fqao_1 car +ANvWNG7bZj0_0 person +ANwXehjlmOU_0 giraffe +ANwXehjlmOU_2 giraffe +ANwXehjlmOU_6 giraffe +ANwXehjlmOU_7 giraffe +AOFbvqQZz1M_0 person +AOJiO3o1Pgw_0 person +AONi1Rhl0VI_2 person +AONi1Rhl0VI_1 person +AOmvm3OOZZQ_0 person +AOn9I3GEHoU_0 person +AOo1qXfZWsc_0 bus +AOq0zSQhX1E_0 person +AOq0zSQhX1E_1 person +AO9zthhr-og_0 person +AO9zthhr-og_1 person +APAgxsDsZqs_0 person +APCppiM1SL4_0 person +APEd6F66jXU_1 airplane +APHhGoshqFo_0 umbrella +APIrIPchQwg_1 person +APIrIPchQwg_0 person +APJ4_CEV8HQ_0 bus +APLJsXaOe1c_0 person +APQ99QCF6pA_0 person +APRuUBgcBZc_1 person +APYAGnOjUQQ_0 person +APa_Xoa9qgg_1 motorcycle +APcliMIvBe4_2 person +APcliMIvBe4_0 person +APcliMIvBe4_1 person +APp-0CsKxpY_1 person +APp-0CsKxpY_0 person +APqdtMhtWlU_0 motorcycle +APtqUIS_Hyo_0 person +APwqoNNZyaA_0 person +APyVeEcEt1U_0 airplane +APyxRCm1XlY_0 person +AP5QrGcnGoU_0 cow +AP_vNEBzhqM_0 person +AQALHMjkeh0_1 giraffe +AQKHDJ9HKck_0 dog +AQNEkyvgbeA_1 cow +AQRKvHpsUk8_0 person +AQTk87BXkxk_0 person +AQVhyDD8GEk_0 person +AQVthZjIETQ_0 truck +AQcg3TVkW1s_0 person +AQcg3TVkW1s_1 person +AQi0YSJ74cw_0 person +AQj3enGQQeE_0 boat +AQminPRA2W8_0 person +AQtIgG8RHRY_0 person +AQvltP0EarU_0 person +AQy7gL42wfo_0 airplane +AQzJp7Qi_yA_2 elephant +AQzJp7Qi_yA_13 elephant +AQ2bfY90nuU_0 person +AQ7YDkmwB4M_0 dog +ARAX6-JmsNQ_0 zebra +ARAX6-JmsNQ_2 zebra +ARFd2qxDhpQ_0 airplane +ARNkmINZamQ_0 cow +ARNkmINZamQ_1 cow +AROrQJq2sWY_0 person +ARRADkl3-30_0 person +ARW5DipSrBo_0 dog +ARmfFWE2ruc_0 person +ARmsnBnMyPc_0 person +ARnGZQm8zOM_0 truck +ARqQUEVhu24_0 person +ARrbFDLoy0Q_1 person +ARtGNhHj2NU_0 cat +ARyGQdkbuyM_0 person +ARyGQdkbuyM_1 person +ASBgE1svBKQ_0 person +ASD516fNs3g_0 person +ASExrIzixaM_0 truck +ASc0m6oxXVI_0 person +ASc0m6oxXVI_1 person +ASm_mkHCybA_0 cat +AS1xCm7MYs8_0 person +AS1xCm7MYs8_1 person +AS2tsNB9LBI_1 knife +AS5hg_3pOXM_0 person +AS9kBpj7qvE_0 person +ATKytgCulZM_0 umbrella +ATakdxmz3qU_0 car +ATkJNKtd8yo_0 person +ATk9e0fbxBk_0 horse +ATk9e0fbxBk_1 horse +ATk9e0fbxBk_2 horse +AT1zSxV6stw_0 cat +AT5urL0Fr0c_0 bird +AUGQ4XFEkGY_3 knife +AUI-RsDtk4s_0 person +AUMHV6JiwU0_0 bird +AUZevw68t_s_0 bear +AUcOQ1L4Nj0_0 train +AUfaVvy5QxU_0 train +AUguk_8JO_U_0 skateboard +AUgw-t2MrtU_0 person +AUzge-cBHfM_0 bear +AU0RtWdAXcU_0 person +AU114x-Qif4_0 person +AU3mKa0Npq4_0 person +AU8GXMxyP9U_0 person +AVHVVt5Srow_0 bear +ZIGThAlQuUU_1 truck +ZIGkCx4o3G0_0 person +ZIMLdoIIFbg_0 person +ZIWkcVTlaRU_1 person +ZIamYwe-hJ8_0 car +ZIawXDt6JH4_0 cat +ZIlyoSrDQQ8_0 person +ZImLYekhFBQ_3 bus +ZI6J2WSiZy0_0 giraffe +ZI7DX2OSzzQ_0 airplane +ZJCSQFa1W3M_0 person +ZJDAzZZQ38k_1 knife +ZJDAzZZQ38k_0 knife +ZJEQHkA9NLw_1 truck +ZJHeFXEtwNE_0 knife +ZJJoit687Tc_0 person +ZJJpIPciUts_2 skateboard +ZJL9WONxDB8_0 person +ZJMJBrWq8-o_0 person +ZJOVhmSGVMM_0 person +ZJXuyIEaSc4_0 horse +ZJYXcUOxNRc_1 person +ZJdKrkzHR94_0 person +ZJdKrkzHR94_1 motorcycle +ZJe2QoJwNa0_0 horse +ZJimYyH6VUI_0 car +ZJoQRLyRs8o_0 person +ZJpozi2Piqc_0 motorcycle +ZJwWllfPFjo_0 person +ZJyDrvmQwY8_0 elephant +ZJyDrvmQwY8_1 elephant +ZJ5n1Y-yXqM_0 person +ZKF4kfqyu6U_0 person +ZKIuqz6GDSA_0 horse +ZKJuI7-4560_0 cat +ZKKalWR8MBM_0 boat +ZKSF-y6kC1I_0 elephant +ZKSF-y6kC1I_1 elephant +ZKTseP8JqIw_0 person +ZKk703iOFmY_0 horse +ZKrJdHuvvR8_0 person +ZKy67yESvjM_0 person +ZK1zKp1iJY4_5 elephant +ZK1zKp1iJY4_2 elephant +ZK3-Em8w4HE_0 horse +ZK6pkPtSd_4_0 cow +ZK_BL_TGwo0_1 train +ZLFXKnOp0LM_1 knife +ZLH6HbQ5Miw_0 person +ZLSqYLLWQLc_1 cow +ZLSqYLLWQLc_2 cow +ZLcGyr4ZfJU_1 airplane +ZLdb8-YkoiY_0 person +ZLm8Hen6OFM_1 bicycle +ZLm8Hen6OFM_2 bicycle +ZLnf4vSxfgo_1 umbrella +ZLqSGXI7FdM_3 knife +ZLuY9hS-wd4_0 bus +ZLuY9hS-wd4_1 bus +ZLuY9hS-wd4_2 bus +ZLupIiWNPOY_0 person +ZL18xmfIKH4_1 motorcycle +ZL18xmfIKH4_3 motorcycle +ZL18xmfIKH4_2 motorcycle +ZL3DgidLXjw_0 person +ZL5SCZpZWtA_1 horse +ZL-60We4drw_0 dog +ZMDe7QMaLa8_0 person +ZMD2tP69gaU_1 person +ZMKFhrS_QnY_0 cow +ZML6VoRZ_Tk_0 person +ZMMDA6nYXZs_0 bird +ZMPdl-1FCMQ_0 person +ZMZU_V7d3-I_1 umbrella +ZMa0bYeg_NE_0 dog +ZMdAlm9Zx_A_1 car +ZMeQ1Vc3HZk_0 person +ZMuwZKOfK1s_0 motorcycle +ZMvdpTH-1Ug_9 airplane +ZMxu4wRDuqU_1 person +ZMyEEXdgJeA_0 person +ZM1xadWQqKQ_0 bus +ZM2SMTrxUr0_0 train +ZM3QVkm1izg_0 person +ZM5-iyB8rFk_1 dog +ZM_TO-0UDp4_0 person +ZNJ8aytwo1E_0 person +ZNP23sy27W0_0 person +ZNTqZ3wERJE_0 person +ZNUBh1ppeyo_0 skateboard +ZNXCWGzmxK8_0 person +ZNZx7hTxCQE_0 airplane +ZNaTV3nGl6M_0 person +ZNcUW5m7eRw_0 giraffe +ZNg9OZgsMqc_0 bear +ZNoQrAOf3Ns_0 truck +ZNqpyPcacjY_0 motorcycle +ZNv_LrEIljc_0 umbrella +ZNxw9kVCouU_0 bus +ZNzeI_r7GT4_0 truck +ZN2bt7wkvH0_1 bear +ZN5ukEMKLY4_0 cow +ZN_gFe4IzxE_0 truck +ZODUj9lsCzk_0 horse +ZOEa1JGwnwE_0 person +ZOEa1JGwnwE_1 person +ZOGP8-XsFYc_0 person +ZOIuTsiGyRY_0 bird +ZOJSvR5KOsE_0 dog +ZOMPRnYycak_2 cow +ZOMnEZ4dWMk_0 elephant +ZOStUYUIEdA_0 skateboard +ZOTSBcRwdRA_0 person +ZOX1xH7rOus_0 train +ZOthVGHUcjo_3 cow +ZOwhFlp5EiA_0 person +ZOxDsYnvl0M_0 person +ZOymkqw58fw_0 person +ZOzQfVh1LN8_1 motorcycle +ZO_5hZ2ex6Y_0 person +ZPKaBLqoKvQ_0 person +ZPNr3zZg6jk_1 person +ZPNr3zZg6jk_0 person +ZPNr3zZg6jk_2 person +ZPQ0lqiH9uw_0 train +ZPQ0lqiH9uw_1 train +ZPQ3tbJp33I_0 train +ZPVOrRypdRM_0 horse +ZPZjgecd6OQ_1 boat +ZPaWYb_4S8Y_0 person +ZPeRU9CLLew_0 person +ZPgUlFmZyP4_0 person +ZPjN0Rp_1ZA_0 horse +ZPkO4x8HPaI_1 person +ZPqs3xJ8sMY_0 person +ZPqs3xJ8sMY_1 person +ZPq9qgTZ4XI_0 truck +ZPyxQD17Fq4_2 person +ZPyxQD17Fq4_4 person +ZP7SN9kW5kg_0 person +ZP7sET2Y9dU_0 person +ZP8YaHDM_qE_0 horse +ZQCFPzE41bg_0 cow +ZQDoAEWZCQk_0 person +ZQG5CpZ3fLM_0 person +ZQRzkpfy378_0 bus +ZQZRNVrE9hk_0 person +ZQarE1lLDl4_0 person +ZQdhjMVGJrk_0 person +ZQdhjMVGJrk_1 person +ZQmTc5C-h8w_0 person +ZQrMMWQidx0_0 person +ZQuVUoqiT_I_0 giraffe +ZQuVUoqiT_I_1 giraffe +ZQ3LAYCIDf8_3 bear +ZQ8X2cqYANs_0 train +ZQ9G0UkTR1c_1 person +ZQ_vGl5xbKY_0 cat +ZRFMzM7kxuI_3 cow +ZRFMzM7kxuI_0 cow +ZRFMzM7kxuI_1 cow +ZRFMzM7kxuI_2 cow +ZRLkkoSR8o8_0 knife +ZRMOgw0VYRI_0 person +ZRNQrzQlVwA_0 person +ZRNgdckx504_0 person +ZRQug2qT1tc_0 person +ZRSRBBpyBG8_0 person +ZRXjiNMKvis_0 airplane +ZRc8GDK_9hc_1 umbrella +ZRkHgC0EAz8_0 person +ZRmkeBogj-U_0 person +ZRoz_bGkPaE_0 person +ZRuQ3ipcK3o_0 bus +ZRzOWgIAwe8_0 bird +ZRzOWgIAwe8_3 bird +ZR0Qj5P8snw_1 bear +ZR4yO1ASDwo_2 person +ZR_VWPjxLTU_0 dog +ZSDCxbSs-Hs_0 person +ZSFzv92w5z4_0 motorcycle +ZSGJwERlcvM_0 person +ZSXoUfKY7t8_0 person +ZSdzUC2BB8Q_0 train +ZSdzUC2BB8Q_1 train +ZSkkNWgXm6E_0 skateboard +ZSkkNWgXm6E_1 skateboard +ZSn4gRAJToo_0 cat +ZSoJT194AtI_1 skateboard +ZSoJT194AtI_0 skateboard +ZSruK26cGuI_0 dog +ZSs6Knma-Q0_0 cow +ZSs6Knma-Q0_1 cow +ZSu3GocMJzI_0 car +ZS29l3t9vK8_0 person +ZS6NQXztroI_0 person +ZS_wuZnVzbw_0 person +ZTLDJDjvSuQ_0 truck +ZTPTnzEs_Lc_0 person +ZTcRmNM1n8M_0 person +ZTjOZ-dZDEg_1 car +ZTmHHCmX7aw_0 skateboard +ZTnEKCqMNHs_0 person +ZTo33r_63Wg_0 knife +ZTw6Dkp-LPU_7 elephant +ZTw6Dkp-LPU_0 elephant +ZTw6Dkp-LPU_4 elephant +ZTw6Dkp-LPU_5 elephant +ZTw6Dkp-LPU_6 elephant +ZT5iwG3vEhM_0 umbrella +ZUCf2cVBY08_0 person +ZUWSpLaJj4M_0 bird +ZUYtIKrcaKo_0 person +ZUaHjAaQqF0_0 bus +ZUdCQl7WU_U_1 person +ZUdCQl7WU_U_0 person +ZUd0IAbilBA_0 elephant +ZUoFqGf_ijs_0 elephant +ZUoJFmQ6ro4_0 person +ZUwniKcHERQ_0 horse +ZU0WSpOWSak_1 bear +ZU0_sT3EbVY_0 zebra +ZU9LGiLzKJg_0 motorcycle +ZU-ZhVyhBpA_1 bicycle +ZVAHreexSa0_0 person +ZVBjo5HM0Do_0 knife +ZVD-ea5SjMg_0 person +ZVJpmiue5IA_0 truck +ZVKyUsgomW4_0 person +ZVOMkt8TORM_0 train +ZVQo_9tFZGY_0 bus +ZVY_873YYQY_0 skateboard +ZVZJRbJ2h1A_0 cat +ZViLnbCdjZM_1 person +ZVlOetMc3m4_0 person +ZVl8So4V1Ss_0 cat +ZVnaHf8vAhA_0 zebra +ZVtPRAs8Za0_0 person +ZV8NIO3XuLQ_0 person +ZV9eJe2grq4_1 bear +ZWIPlBvd1DI_0 person +ZWIPlBvd1DI_1 person +ZWJv_-wAdws_1 skateboard +ZWKHlq-W7_8_9 train +ZWKHlq-W7_8_14 train +ZWKHlq-W7_8_0 train +ZWKHlq-W7_8_1 train +ZWKHlq-W7_8_4 train +ZWKHlq-W7_8_7 train +ZWKHlq-W7_8_10 train +ZWKHlq-W7_8_11 train +ZWKHlq-W7_8_12 train +ZWKHlq-W7_8_13 train +ZWNe-zcl-IY_0 boat +ZWNjUm5Uzh0_1 bicycle +ZWNjUm5Uzh0_5 bicycle +ZWXE7IAaWrg_0 person +ZWXSnELtawA_1 knife +ZWXSnELtawA_3 knife +ZWX1cGhJG98_0 bicycle +ZWlTD6EbOTo_0 person +ZWqzdCz6UvY_0 bird +ZWr6RECjqV0_1 horse +ZWr6ZU_-ir4_1 person +ZWthtO1iGtQ_0 person +ZWwlzozPAk8_0 person +ZWxn8yT0bXo_0 cow +ZW0HC4IRa64_0 person +ZW3CWoXzrn4_0 bicycle +ZW3CWoXzrn4_1 bicycle +ZW5VkDNSfWA_0 cat +ZXMqiFE6KOE_0 airplane +ZXRcWIcok2I_0 person +ZXgYAh2AWyk_0 horse +ZXp6jOe8DUE_0 person +ZXyJafbGcBM_0 horse +ZXzno8CjUyM_0 elephant +ZYB9yzoJ6jc_0 person +ZYG83auB9Lk_0 train +ZYIgTdUmOWk_0 elephant +ZYKlgXftesk_0 cow +ZYM0_4YzeeQ_0 person +ZYRgw5rNhE4_0 person +ZYS7WVlJbuU_0 person +ZYX53PWsBdk_0 person +ZYY8vkvB1zU_0 person +ZYkIkq9kfLc_0 dog +ZYlANECCXnI_0 person +ZYocOIOyuqs_0 person +ZYsifQxv94s_1 motorcycle +ZYs7rbZt8Zw_0 airplane +ZYs7rbZt8Zw_1 airplane +ZYs7rbZt8Zw_2 airplane +ZYtk2iVNC90_2 airplane +ZYtk2iVNC90_0 airplane +ZYxn9wmzRI4_0 bicycle +ZYxn9wmzRI4_1 bicycle +ZYzeKMdP2SE_0 person +ZYz6B5dwXcE_0 person +ZY_urkqeQLM_0 bicycle +ZZANjG2Z5Jk_0 person +ZZFzCaL48sE_0 cow +ZZNRG-ux4fw_0 person +ZZQDFjbEcHQ_1 bird +ZZQDFjbEcHQ_2 bird +ZZQSDwoLZ00_4 knife +ZZSFKq4WH78_0 cat +ZZVPKuh-2v8_0 person +ZZVx_IT4voA_0 person +ZZlf3LtDpH8_1 bear +ZZpLkBcXUgs_1 person +ZZpLkBcXUgs_2 person +ZZxMtMlV-MM_0 cow +ZZyW-2jZcIo_0 horse +ZZyW-2jZcIo_1 horse +ZZ20JXRExdg_0 person +ZZ8OuI39UTM_1 person +ZZ85EAvnAGU_0 person +ZZ85EAvnAGU_1 person +ZaDVUoq6h5o_1 person +ZaD5V9_Vw2w_0 person +ZaJb3JTan7Q_0 person +ZaLqPrH_aVo_0 train +ZaLqPrH_aVo_1 train +ZaNZV-lM-3o_0 person +ZaNZV-lM-3o_1 person +ZaPC288yVBg_1 bicycle +ZaPC288yVBg_5 bicycle +ZaPC288yVBg_7 bicycle +ZaPltFe0S_o_1 truck +Zabt7ElK3jM_0 person +ZacHdhX9F9M_2 dog +ZadGgAG3PzE_0 person +Zaew_bHz-PQ_11 umbrella +Zaflj5gSZEw_0 person +ZanT0hXyJhk_0 bird +ZavCWamLatc_2 person +ZavCWamLatc_1 person +Za4BYhhaFFQ_1 zebra +Za6oX4aQR34_0 airplane +ZbB-tdDvITQ_0 motorcycle +ZbDu8V7ppZE_0 motorcycle +ZbHt1sn7oTI_0 person +ZbJvtTVTTV8_0 knife +ZbQXzueqj4Y_0 horse +Zbgfg8usx-k_0 person +Zbgfg8usx-k_1 person +Zbm5_qB8fEs_0 person +ZbrJHC_mHlo_1 person +ZbrJHC_mHlo_2 person +ZbrJHC_mHlo_0 person +ZbrqZYGiMvE_1 cow +Zb2Vz655gh4_2 horse +Zb755JeGMpU_2 person +Zb-JKfQ5emU_1 person +Zb-JKfQ5emU_2 person +Zb-JKfQ5emU_0 person +ZcJPap_gVyo_0 person +ZcXA6CyQBi8_0 cat +ZchU4DxP5A8_0 person +Zcw7wSfd2JM_0 person +Zcw7wSfd2JM_1 person +ZdElKzM-US0_0 umbrella +ZdKO1sC4o60_0 person +ZdMbx0IXDzs_0 person +ZdMm6j__cQM_8 bicycle +ZdTZrRX0dv4_0 truck +ZdXrQlOU7iw_1 bicycle +ZdaFXJzLLUs_0 person +ZdaFXJzLLUs_1 person +ZdeTj7nyN-s_0 boat +Zdevf1MbY8U_0 train +Zdevf1MbY8U_1 train +Zdevf1MbY8U_2 train +ZdirtQF_sjE_0 person +ZdlnVpHrDcg_0 giraffe +ZdlnVpHrDcg_2 giraffe +Zdq2csZeJr8_2 person +Zdrk4yHmMXA_0 person +ZdtUPHscS-s_0 person +ZdxD4gqVioQ_0 cat +ZdxHWwaivLc_0 cow +ZdyBZtlMq-M_2 bear +Zd3j0bQV6NI_0 person +ZeHLf0q4Z1Q_0 person +ZeZAZbMg1zY_0 person +ZeaoaXZDhPw_0 person +ZemOY1F1bVo_0 truck +ZemOY1F1bVo_3 truck +ZemOY1F1bVo_1 truck +ZerHfx3SLxU_0 person +ZerYXYTyhoc_0 person +ZetcbIDyydg_1 car +ZetcbIDyydg_0 car +ZeuqVhpsVu0_0 horse +Ze6GIOUVxZU_0 person +Ze8W47hBrrE_2 skateboard +ZfAFALQjUwI_2 person +ZfAFALQjUwI_1 person +ZfAM39o5Cbc_0 bird +ZfDkxwMowSk_4 elephant +ZfF5Z0hrOQw_0 person +ZfHSyDaLaw0_0 airplane +ZfHSyDaLaw0_2 airplane +ZfHSyDaLaw0_1 airplane +ZfJvZeaN7Ro_1 person +ZfTTW39iHJQ_0 person +Zflcz9EKz4g_4 elephant +Zflcz9EKz4g_1 elephant +Zflcz9EKz4g_2 elephant +Zfmwrq2aghI_0 person +Zf86HoPHmBs_1 bird +Zf86HoPHmBs_0 bird +Zf-rSx5ZNB8_0 person +ZgK0Y4PgWSM_0 person +ZgOr7facaIw_0 skateboard +ZgP7q-rIhs0_1 person +ZgTDthFY-aI_0 bird +ZgZ18HIfCGc_1 motorcycle +ZggirLBvHSw_0 dog +ZgjspuwgTAc_0 person +ZgtG8Zy63UQ_0 person +Zg18GZ5OFWw_1 person +Zg2YrzGNuZs_0 person +Zg4f2iY8_zo_1 cat +Zg4f2iY8_zo_0 cat +Zg5MdsCXRWM_1 cow +Zg5MdsCXRWM_0 cow +ZhLB-laOg_g_9 bicycle +ZhLB-laOg_g_3 bicycle +ZhLB-laOg_g_5 bicycle +ZhLB-laOg_g_6 bicycle +ZhLB-laOg_g_10 bicycle +ZhLB-laOg_g_12 bicycle +ZhPafr5WTEs_0 person +ZhtgT8q5Gm4_0 person +Zhtr_XhO6_4_0 train +Zhtr_XhO6_4_1 train +Zh6QWGGQ9dU_0 person +ZiJFOBVGah4_0 horse +ZiPO1UcM3IY_0 dog +ZiP2ydBHuPs_2 person +ZiSl_Dy1ZB4_0 person +Zibk3bXvHCY_0 cat +Zig1VrVbQc0_0 horse +ZimvCFcji0A_0 person +ZisoM7y_CS4_0 person +ZitUYI22J54_1 knife +ZitUYI22J54_0 knife +Zi1etYbSUmQ_1 person +ZjCbmE2jLo4_0 person +ZjFb1VLHvyg_1 horse +ZjPmZ4grIFA_0 person +ZjPmZ4grIFA_1 person +ZjQqfJ1Docg_0 person +ZjQ9lIlCehk_0 skateboard +ZjSloqSrfWU_1 airplane +ZjSloqSrfWU_3 airplane +ZjWBw4tZUO4_0 train +ZjWBw4tZUO4_1 train +ZjWBw4tZUO4_2 train +ZjWBw4tZUO4_3 train +ZjWBw4tZUO4_4 train +ZjWBw4tZUO4_5 train +ZjWBw4tZUO4_6 train +ZjbhM1ZiKW8_0 person +ZjbhM1ZiKW8_2 person +ZjcEfOHRyLQ_0 truck +ZjcevqmMJvY_0 person +ZjgTSjb7Vh4_1 car +ZjnaerD1MHM_0 elephant +Zjn6uD43ewg_4 airplane +Zjn6uD43ewg_5 airplane +Zjn6uD43ewg_1 airplane +Zjn6uD43ewg_2 airplane +ZjpmS5k09Ug_1 person +Zjpzw1n9Lvc_0 skateboard +ZjsEX7nNYdQ_0 person +ZjxiHzcXOAs_0 person +ZjxiHzcXOAs_1 person +Zj2HBun9kBY_0 person +AVW26zY72Ns_0 person +AVXWb0s5LZw_0 person +AVqCe7X9Pp4_0 cow +AVragVmWr8M_0 motorcycle +AVvnZ-Ky-ew_0 person +AV9y4LnUV84_0 dog +AWAQTemnBJc_0 person +AWCUoghX20A_0 cow +AWD_KAfvb0U_0 skateboard +AWOhJ9RZReg_0 person +AWOhJ9RZReg_1 person +AWPNd7zPJzg_0 person +AWPNd7zPJzg_1 person +AWZt9EdU3BU_3 zebra +AWdKXFitdJI_0 boat +AWh2S4rI6kc_0 person +AW1SjuoheU8_0 cat +AW2cvkaExG4_0 cow +AW8munaOGqw_0 person +AW--f4fsLFY_0 train +AXB4hYQKqUw_0 person +AXB4hYQKqUw_2 person +AXQlwoC_K0g_1 truck +AXX66Oq_RkU_0 person +AXhx8hncZvA_0 boat +AXm0KvcIchQ_0 train +AXtXzxTXTqI_0 elephant +AX2rS0bpAmM_0 horse +AX4Hsfdm-Fo_0 elephant +AX8WoOXfJDA_0 person +AX-xVtjP42Q_0 person +AYLoR7L3CMs_3 bird +AYLoR7L3CMs_1 bird +AYUGoWokN_0_0 person +AYYdBxTI_54_1 train +AYakvLR8aVM_0 person +AYe6Wf0URgo_0 truck +AYgbgSVClN4_0 person +AYg1V2ol96s_0 dog +AYj70IRvvwI_2 airplane +AYj70IRvvwI_3 airplane +AYn-qtOy_nc_0 person +AY7foLy1uok_0 elephant +AY7foLy1uok_1 elephant +AY-AbrJPyY0_0 train +AZHYXkv5rMk_0 bird +AZJsII37MPY_0 bird +AZMW1TyN6Z4_0 person +AZQjsUm-CXk_1 person +AZhH2ej_x_g_0 person +AZjZ1ZSyCeE_0 person +AZk4MAu-j90_0 person +AZleWF5zAxc_1 bear +AZl3Emy9K3A_0 horse +AZouBTtQrtM_0 person +AZpAuvQryZo_0 person +AZpAuvQryZo_1 person +AZ9SW8bxD3E_0 bicycle +AaGwVQ6UjOE_0 person +AaRVwgGBmWU_0 person +AaTW4oc5bBU_0 person +AaZsdPwg9qg_3 bus +Aac18k-eLZI_0 person +Aac18k-eLZI_1 person +Aac18k-eLZI_2 person +AakpjcyvFSo_0 person +AalaqaXsEbs_3 umbrella +AalaqaXsEbs_0 umbrella +AalaqaXsEbs_1 umbrella +AalaqaXsEbs_2 umbrella +AaoK6DPQKII_0 bus +AaotWWHg4eU_0 truck +AaotWWHg4eU_1 truck +AaotWWHg4eU_2 truck +AasksRmCk1g_0 person +AatNkWo2ryE_0 person +Aa0FU2EIMZ4_0 bird +Aa-wzDtjCGc_0 person +Aa_biYfYp08_0 person +AbEsU9EX9XQ_0 elephant +AbEsU9EX9XQ_2 elephant +AbO_VrlyQ8I_0 umbrella +AbTxhwSueZw_0 person +Abd7Vn-Nyt8_1 truck +AbeOAFhMXBY_1 bird +AbeOAFhMXBY_2 bird +AblKd4XIjqk_0 person +AbmnNkzkXFg_0 elephant +AbmnNkzkXFg_1 elephant +AbuMVYzS0mw_0 skateboard +AbvoOuTpLtA_0 dog +AbwI4m0H9Hk_2 train +Abx126RTs10_1 elephant +Ab9zgKJnr9Y_1 person +Ab-vGS2mqFQ_0 cow +Ab-vGS2mqFQ_1 cow +AcCU5YAWXlw_0 dog +AcReGpoHOZI_0 person +AcSmnBYhEsg_0 person +AcTgPRNars0_1 truck +AcUEWZRPoGA_0 umbrella +AcZNiBe0Fgo_0 person +AcZukbBG7tI_0 boat +Acc1yTFpH2c_0 dog +AcpBKywfL4o_1 cat +AcpOxyI_YPI_0 person +AcprJcYvkbY_0 person +AdDiiRHwZ2E_0 cat +AdEH-oHs1Qo_3 train +AdEiQT7Nm0o_1 motorcycle +AdE2jnpk6AM_0 boat +AdbsyVjq_Xs_0 cow +AddL-M622TI_0 knife +AdgTVbi_kus_0 person +AdsPsjswSGQ_0 motorcycle +Ad044xbRhE8_0 person +Ad2TSmaLvX8_0 person +AeDfdgrccVw_0 person +AeHbZ3U8S8U_2 train +AeWBkNuJmEA_0 truck +AeWBkNuJmEA_3 truck +AeWBkNuJmEA_4 truck +AeWBkNuJmEA_5 truck +AeakbNNwcW0_0 train +Aec4uweTSes_2 skateboard +AeflYi3Sxss_0 person +AegDGWXkWNw_0 person +AenVUPH1ils_0 bird +AendE1XHSps_0 bicycle +AerUXP3Mmks_0 person +Ae5qWkNt6RU_2 car +Ae7ucKj40mw_0 dog +Ae9Zd3lP7bg_0 person +AfHkdkvxhNs_0 elephant +AfNCSPijpao_0 person +AfNGR5iEpvU_0 cat +AfNtKiB_rD8_1 motorcycle +AfWHElsVCyM_0 cow +AfWfexnwsHg_0 person +AfWfexnwsHg_1 person +AfkKO6j4jWc_0 person +AfmMpft13ZU_0 person +AfnQoNimSjc_0 person +AfynslRqwxI_0 car +Afz2VDV4UHg_1 person +Afz2VDV4UHg_0 person +Af2MGhdZAn8_0 person +Af2VyQEZtfk_0 person +Af6Ve26JUOg_0 person +AgBaUhTbzxA_0 airplane +AgBaUhTbzxA_4 airplane +AgBaUhTbzxA_5 airplane +AgBaUhTbzxA_3 airplane +AgBaZRmz8IY_0 skateboard +AgJCf77qxsY_0 person +AgP2HoU83S4_4 knife +AgYhFemsFag_0 person +AgZ2iflIKWc_1 person +AgaetfTOzc8_0 person +AgdrEW8jmw4_0 truck +AgqmhFD0R94_2 elephant +AgqmhFD0R94_3 elephant +AgqmhFD0R94_1 elephant +AgrKeQXSU2M_0 elephant +AgrKeQXSU2M_1 elephant +AgrKeQXSU2M_2 elephant +AgtCW50wfig_0 person +AgvxdVNj5Oc_0 skateboard +Agw5t7YSQbE_0 skateboard +AhAW4UKPzz0_0 giraffe +AhE2vDF6Gbc_0 horse +AhE2vDF6Gbc_1 horse +AhjsDq9fEzQ_0 person +Ahv2jhPqRPg_0 person +AhwGPZWtf3E_0 person +Ahxq6Rtu3lc_0 person +Ahx3IZujXDw_0 bus +Ah0AGjta1qg_5 bird +Ah04VeRs2hg_0 truck +Ah4x4EfR3BY_0 motorcycle +Ah4x4EfR3BY_1 motorcycle +AiIc8FW3q98_0 car +AiL_iCJ8HZI_1 person +AiNLvzwt3_w_1 bird +AiNLvzwt3_w_2 bird +AiP7EOvTpK4_0 motorcycle +AiP7EOvTpK4_2 motorcycle +AiU_T3DZI2w_1 bus +AiU_T3DZI2w_2 bus +AieRY99VkmE_0 person +AieVzbENJv0_3 bicycle +AiieCerOKpc_0 person +Aik2hirrxEo_3 airplane +Aik2hirrxEo_0 airplane +Aik2hirrxEo_1 airplane +Aim6_lZQi4g_0 person +AiqqXxqnPPM_1 cow +AiqqXxqnPPM_0 cow +AittR1dd2SI_0 train +AittR1dd2SI_1 train +Aiv3XHMuVq8_0 train +Aiyfw0Zh38k_0 person +Ai29fDmklxM_1 person +Ai29fDmklxM_0 person +Ai3S7n1Aofs_0 elephant +Ai-487iZv0E_0 person +AjFhyF1XZw4_0 person +AjJHvamHoMU_0 horse +AjPBAy1xgrY_0 person +AjVe8d0vc1E_0 person +AjamPk2Geuw_1 bus +Ajg7q9zxJUo_0 person +AjroIzI2OW8_1 truck +AjroIzI2OW8_2 truck +Ajsu2bGngDw_1 person +Ajs4qdBK7Jk_0 elephant +ZkD_WAxZB3o_0 cow +ZkHPsjy-YUQ_1 knife +Zkbav-Qoxds_0 horse +Zkbav-Qoxds_2 horse +Zkbav-Qoxds_1 horse +ZkidaaVx2VU_1 bus +ZknqgRL504A_4 bear +ZkqA2kLudwE_4 train +ZkqA2kLudwE_0 train +ZkqA2kLudwE_3 train +Zku9JAotBZ0_0 boat +ZkzM2jvV2AY_0 person +ZlBfF2yK2vg_1 person +ZlBfF2yK2vg_2 person +ZlBfF2yK2vg_0 person +ZlDsSDEHEzY_1 cow +ZlDsSDEHEzY_0 cow +ZlDsSDEHEzY_2 cow +ZlFElBglnHA_0 cat +ZlP8tmFYeyY_5 bird +ZlfyrRfHDoc_0 cow +Zljx0icnRa8_0 person +Zljx0icnRa8_1 person +Zlmsqen0qZo_0 person +Zln667JkWo8_0 person +ZmHKBIsSjQA_0 horse +ZmHKBIsSjQA_1 horse +ZmVLw9-fLDo_0 car +ZmbXlevaX2U_1 boat +ZmgJjFt3JU4_0 skateboard +ZmhKe4_d5Ag_0 person +ZmiCqFxUJSw_1 airplane +ZmkKOYN1dRw_0 person +ZmrCaB8p3IM_0 bear +ZmuzvhzN6EI_0 cow +Zm3AU4TEpEw_0 person +Zm5VvBaQUwU_0 bird +ZnRgQ1VBIGE_1 person +ZnWAM5ju8NM_0 person +Zne4XpVG2YQ_1 person +Zne4XpVG2YQ_0 person +Znr-Uiobo-k_0 person +ZntDSf8cCPI_0 person +ZnvLWU_PCZ0_0 motorcycle +Zn-r14oEJwM_0 airplane +ZoC1knYO0Tg_0 cow +ZoJIup20AGU_0 person +ZoKfc3OL0JY_0 person +ZoK4wKRoZjY_0 person +ZoN4k6UNw6I_1 horse +ZoOvu218D6M_0 person +ZoR1yoQzsbM_0 person +ZouHgocvjDI_0 bird +Zo-8G7N2DXU_0 person +ZpAlbL-YE0E_0 bus +ZpCrRb_a9QI_0 person +ZpCuVDLXQSw_1 horse +ZpCuVDLXQSw_0 horse +ZpSzmFLEm0c_1 car +ZpURI0wRgws_0 person +ZpXJ-0dv6Us_1 cat +ZppFK22HdIk_0 person +ZpqXtZfe-3w_0 cat +Zp1nQXN7dyg_0 horse +Zp2CuvTAZLw_1 person +Zp740cgCPPE_0 person +Zp8GHxi_5l0_0 knife +Zp8GHxi_5l0_1 knife +ZqM9VL5DJ28_1 person +ZqOcOhiAI6k_0 cow +ZqS1PqS3iT0_0 truck +ZqW027iDkCI_0 person +ZqXFvdeNrYI_1 person +Zqa0-AUnl9s_0 person +Zqm8A3wpeJQ_0 person +ZqtVs5joekw_0 cow +Zq018zZzx1c_0 person +Zq1u84GLCHI_0 motorcycle +Zq5nK49UZ_o_2 elephant +Zq5nK49UZ_o_3 elephant +Zq5r3BwLg_c_0 skateboard +Zq-RNCVoZFs_0 person +ZrA0NE09ipc_0 dog +ZrDoGqu-A5A_0 train +ZrI4ruv6B3o_0 bird +ZrKpKmp29_o_1 bird +ZrKpKmp29_o_3 bird +ZrKpKmp29_o_6 bird +ZrK5JKg83qU_0 person +ZrUx83OGIOk_0 person +ZrW7Si0hJKI_0 person +ZrbVa__ne-0_0 person +ZrfPtqkS_MY_0 airplane +ZrfPtqkS_MY_1 airplane +ZrfPtqkS_MY_5 airplane +ZrfPtqkS_MY_6 airplane +ZrfPtqkS_MY_7 airplane +ZrgMnk8f_TA_0 person +ZrgMnk8f_TA_1 person +ZruJ2hhn9z0_1 person +ZrvWeRZ_dyU_1 cow +ZrvWeRZ_dyU_0 cow +ZrwXUWAxjIM_0 giraffe +ZrzdqF_ePkM_0 horse +ZrzdqF_ePkM_2 horse +Zr5eAtkuxQ0_0 bear +Zr_AAxouNfg_0 cow +ZsCaDsfPNec_0 cow +ZsDDOO-bpFA_0 person +ZsDDOO-bpFA_1 person +ZsESx0nIYqI_0 elephant +ZsESx0nIYqI_6 elephant +ZsESx0nIYqI_7 elephant +ZsJCwiPEvkI_0 person +ZsLDBiZ0o14_0 skateboard +ZsPVRik6m_c_1 bear +ZsSkZhL-HOM_2 bicycle +Zsb2ucv_mAg_0 person +Zsdv_3EWODM_0 person +ZsyMk67bjIM_0 dog +Zs0j_1tuTDo_0 person +Zs1ltKMvRec_0 person +Zs1ltKMvRec_1 person +Zs79wUXMpx8_0 bear +ZtA8n6dsH-w_4 car +ZtA8n6dsH-w_1 car +ZtA8n6dsH-w_2 car +ZtA8n6dsH-w_3 car +ZtDUifuLGrM_2 bird +ZtEDTuHcM9U_0 person +ZtM6JRtVtpU_0 motorcycle +ZtToUMIMdYE_0 person +ZtlDJ70ap8Q_1 bear +ZtlJcLPPjsg_0 person +ZtsGzhfZg9g_0 person +ZttTri7sEK4_0 train +Ztyep9o6CLE_4 bus +Ztyep9o6CLE_6 bus +Ztyep9o6CLE_7 bus +Zt9qKAA_xyA_0 person +ZuC0Jr3Y3s8_0 car +ZuGpcHtPLLA_0 person +ZuWlzE4F84c_0 truck +ZuhmoYvtP40_1 person +Zuicm6_fX9I_1 bicycle +Zunjyc7DIP4_2 train +ZuoBIQ-Kq74_0 person +ZuqXxaMAufU_1 person +ZuuL_Yi4FZQ_1 dog +ZuuL_Yi4FZQ_0 dog +Zuy59kV2M-0_1 person +Zu-vh46IwiU_0 cow +Zu_dXJvDHdo_0 person +Zu_f8xuOweg_3 elephant +Zu_f8xuOweg_1 elephant +Zu_f8xuOweg_2 elephant +ZvDo2WbWL4g_1 person +ZvDo2WbWL4g_0 person +ZvJItzBdO04_1 person +ZvJrqHsPVL0_0 bus +ZvSN_Y6vK3c_0 person +ZvV5mqJgbcQ_0 cow +ZvfCrJvE1Tg_0 horse +ZvfIYK-AWCw_0 person +Zvlx8vSlAPs_0 bicycle +ZvtGPgtfhE8_0 person +ZvtuffxB5EY_0 person +ZvyOzgxu-4Y_0 truck +ZvzVi9irgvw_0 bear +Zv6DWiKAux4_1 person +Zv9e9Vm6Vis_0 motorcycle +ZwDqCxCFpF4_0 bicycle +ZwDqCxCFpF4_3 bicycle +ZwH5xnh6Thw_0 person +ZwW6ybIP8ys_0 bus +ZwdSYMz9ioo_0 person +ZwmRodW5wgg_0 horse +ZwrtmR7ewc4_0 person +Zw7a69yU7f0_0 motorcycle +ZxAlVbDwlCc_2 bird +ZxAuwcxhXxc_0 person +ZxE5MjV6i4w_0 skateboard +ZxOVw-Lc-NI_0 person +ZxStkYy-wgo_0 motorcycle +ZxUKijmOWJc_0 person +ZxitXAY6Xsc_1 knife +ZxqbwwO81Xc_0 train +Zxv2BRQIWm0_4 airplane +Zxv2BRQIWm0_5 airplane +Zxv2BRQIWm0_7 airplane +Zxv2BRQIWm0_8 airplane +Aj7HWiU0iQg_0 skateboard +Aj_E-ObfzoE_1 person +AkGYKkcRyPM_0 dog +AkHT5Oo22rQ_0 person +AkMpnm9JrLU_0 person +AkWcVIeIx34_0 boat +AkaR-XgClv0_0 person +AkaR-XgClv0_1 person +AkeAdeJpbpg_0 train +AkeAdeJpbpg_3 train +AkeAdeJpbpg_1 train +Akh0VNTS6G4_0 person +Akh0VNTS6G4_1 person +Akh0VNTS6G4_2 person +Akh0VNTS6G4_3 person +AkkNBGH82Ic_0 horse +AknHhsIpRqc_0 airplane +AkxKeaxEnvQ_0 dog +Ak3XQg9z8XQ_0 person +Ak8ygMb5ykk_0 person +Ak8y7dALcJI_0 person +AlAUJSBL-e4_0 dog +AlNCPdpo1gg_2 bicycle +AlNCPdpo1gg_5 bicycle +AlNCPdpo1gg_6 bicycle +AlNCPdpo1gg_0 bicycle +AlNCPdpo1gg_3 bicycle +AlNCPdpo1gg_4 bicycle +AlPZeADzCKc_0 person +AlPZeADzCKc_1 person +AlXlVnkucyU_3 train +AlXlVnkucyU_1 train +AldX05MqOs0_0 person +AleuxLN7VcU_1 bird +AlfbdsgKBAc_1 person +AlhjN5qz_WI_0 train +AlikgfDMckk_0 person +AlnIWAFamHE_0 bear +AltA5vQ7Icw_0 bus +AlzB8mXDcYc_0 horse +Al2hm71ia6E_0 person +Al9l6-4QDz0_0 horse +Al9wCTPpSWM_0 skateboard +AmPe5gTOCTo_2 person +AmPe5gTOCTo_0 person +AmPe5gTOCTo_1 person +AmQ_UrwLf3g_0 person +AmRyW4hmSjw_0 person +AmcAzvpvDRg_0 bear +AmeaTbvmKvo_0 car +Amt8BGudD0w_0 skateboard +Amt8BGudD0w_2 skateboard +AmuX-Lv7OeM_2 cow +AmwvLxALyCw_0 person +Am2wElVETcw_0 cat +AnD6ijSktyM_0 person +AnEC6v3fXrE_0 cow +AnOwuTW7DKk_0 cow +AnOwuTW7DKk_1 cow +AnQ2ZY1JxAY_2 person +AnWClR8yyu8_0 person +AnZKri0xn-c_1 cow +AnZKri0xn-c_2 cow +Anb2IyxcJbk_0 horse +Anevw4PbqTo_0 person +AnkgvW70F5E_0 person +AnkgvW70F5E_1 person +An342tYqi5g_0 person +AoI1hSI0PSI_2 car +AoKs5jwMuHc_0 person +AoP-So0vjIc_0 cat +AoSwFyY0f_A_0 person +AoXHZgatpco_1 horse +AoXHZgatpco_2 horse +AoXHZgatpco_3 horse +AoXHZgatpco_4 horse +Aof87CGS8NQ_1 skateboard +AoiCmKM8xz0_1 truck +AojgueRMVCY_0 person +AolLjcEFv5o_0 person +AopGnIjKuEk_0 motorcycle +Ao0EDmBMIQk_0 person +Ao0EDmBMIQk_1 person +Ao7Iys-_lZs_0 skateboard +Ao_b43xexzA_0 person +ApJMiJjCxCY_1 car +ApJMiJjCxCY_4 car +ApJMiJjCxCY_5 car +ApP4eoyM72g_1 skateboard +ApWIa9pt-vk_0 person +ApilCZCROGI_0 motorcycle +ApjCOCv29N8_0 person +AppgdYQTII8_0 truck +Ap1gZJZynL4_0 person +Ap-iaHj5SLk_4 elephant +Ap-iaHj5SLk_5 elephant +Ap-3HonA5go_0 person +AqBYSr4wmpQ_0 person +AqKP0V3Xj7E_0 cow +AqOxDunFl08_0 airplane +AqOxDunFl08_1 airplane +AqSP11-eje8_0 boat +AqUxRBRS-n0_0 skateboard +AqZhKjLLG70_2 boat +AqdAnSsQLI8_1 person +AqdAnSsQLI8_0 person +AqlHHwyJypE_0 bird +AqmXAZYmPJc_0 person +AqmXAZYmPJc_1 person +Aqo5yZkzz8I_4 truck +AqpinwPH8gM_1 person +AqpinwPH8gM_0 person +Aqqs8XxA8gM_1 horse +Aqqs8XxA8gM_0 horse +Aqqs8XxA8gM_2 horse +AqqvZzLy3IE_0 motorcycle +AqsuBaW1L0Q_0 person +AqxTv7XRAH0_0 person +Aq_n86sub5o_2 bicycle +Aq_n86sub5o_3 bicycle +ArJNEsuLzDc_0 person +ArJaHKwfOEo_0 person +ArM6GXi6YnI_1 dog +ArbpF1NIm-s_0 car +ArbpF1NIm-s_1 car +ArfeHbvYvKY_0 motorcycle +AriIdq0ZPfE_1 elephant +AroxRXjr3po_3 bear +ArrB-hbOgf8_1 elephant +ArvYqb1hJSk_0 person +AryOE3od43M_0 person +Ar7WaiToztg_0 person +Ar8Wk3m0uZ0_1 person +Ar8Wk3m0uZ0_0 person +Ar-vOeN30bM_0 cat +AsJt3MHLGiM_0 person +AsKUm364aHg_0 person +AsNy8gmdVec_0 person +AsWWfQtZSHA_0 person +AsY1dt4QojM_0 person +AsZa3il8cZQ_0 person +AsfAcK_laZA_2 horse +Asix5lGmXlg_0 airplane +AskNHLhn1t0_0 cow +As_a3CyN-kQ_0 bicycle +As_a3CyN-kQ_2 bicycle +As_a3CyN-kQ_7 bicycle +As_a3CyN-kQ_8 bicycle +As_a3CyN-kQ_10 bicycle +AtFOIFqxLKs_0 person +AtG98YoPQyg_0 bird +AtKUkiMSzfs_2 elephant +AtKieG766oI_0 person +AtawrCflbrM_0 person +AtfXsIpaSgQ_0 person +AtmVV-8Pjsg_0 person +AtmVV-8Pjsg_1 person +At0-VpJyfBY_0 skateboard +At81P33v_z8_0 person +AuA4_FjCMvo_0 person +AuJLIGyAoj4_1 horse +AuJalbdpJP8_0 train +AuLw9iNhPvw_0 bird +AuQYS5w13co_0 bus +AucK5ZDM060_1 airplane +AuchGbKLdmk_0 person +Aucxkj3w3nc_0 person +AugnPC3tdso_0 motorcycle +AunfkfLwN1w_0 bear +AunfkfLwN1w_3 bear +AunfkfLwN1w_2 bear +AutsbWiMLoY_0 person +AuuZLhOpxcI_1 elephant +AuuZLhOpxcI_6 elephant +AvGLANxpJ-Y_1 person +AvJexx39uCE_0 person +AvOpMSLKXTM_1 person +AvOpMSLKXTM_0 person +AvP_DY8SuU4_0 person +AvQgdEmyoFA_0 airplane +AvVBLLWgeWo_0 horse +AvdUsPyX5lE_0 person +AvdgweWTeeg_0 cat +AvgusAC7DUU_0 bird +Avlg_B60Z0E_0 bear +Avlg_B60Z0E_4 bear +Avp80BzoG9Y_1 person +Avp80BzoG9Y_0 person +Avr6FKguO2o_4 skateboard +Avr6FKguO2o_1 skateboard +AvvWfbj5x88_0 person +Av78r-lWmCs_0 horse +Av8Hkyi1fdc_1 knife +Av8k98IyQhs_0 person +AwAX85eLJH4_0 cow +AwDIxdZSWKQ_0 person +AwECiro8_h4_1 elephant +AwEtKHnfKJ8_1 cow +AwEtKHnfKJ8_2 cow +AwFA2LuUWN8_0 person +AwM3QWX5Jsc_0 person +AwOJkAFe8Xs_0 bicycle +AwZ6nHwMMuA_0 dog +AwqZ_9G0pWg_0 person +AwsAA0Xk1J8_0 person +Aw-D6USSthk_0 bear +AxAIZDsViZw_0 person +AxAIZDsViZw_1 person +AxAkf4tRXbI_0 person +AxLiwCy5umU_0 person +AxUFYNgnIq4_0 person +Axg0nab1SDc_0 person +AxvrCidcYqM_1 person +Ax2iIXU4Gyc_0 person +Ax5dd2_2sFA_1 car +Ax5dd2_2sFA_0 car +AyAAL3Rd_Rg_3 bicycle +AyAAL3Rd_Rg_5 bicycle +AyAA5q5B-84_0 person +AyAA5q5B-84_1 person +AyH0zvW0ndQ_1 bird +AyKf0Ufaa_o_0 person +Ayfmwf4oW_k_0 person +AyhXfIgl4Kk_0 knife +Ayo9w6aKSY0_0 person +AyqiYJuONPs_0 airplane +AyqvDNKC1CQ_0 person +Ay2VXLYZW50_1 person +AzFaa7gRy0k_0 person +AzMHek-Oow0_0 cat +AzNf4dneWFU_1 person +AzVMbaXM_QM_1 boat +AzVoOWc-ueY_0 person +AzaUz9OpHMI_0 truck +AzeA4K-S0CI_1 person +Azew3w3WZfI_5 skateboard +Azew3w3WZfI_1 skateboard +Azew3w3WZfI_3 skateboard +Aze0ijK2t2M_0 person +Aze_lfqL6mw_0 cow +AzhTPVtwJVk_0 person +Azh82KkzMVs_0 bird +Azh82KkzMVs_1 bird +Az0Hr5pa_Pw_0 person +Az5vE5ssYxk_0 person +Az5vE5ssYxk_1 person +Az7glF28oOw_0 person +Az_5XR0RSv0_1 person +Az_5XR0RSv0_2 person +A0JB0OdZ2NE_1 knife +A0L6M_8fDyM_0 person +A0Nx4JbdXO0_0 person +A0PQ6Si3nOU_0 airplane +A0XGvY-NO00_5 airplane +A0jhzA4HvrY_0 umbrella +A0n7dLEgCjo_0 cow +A02wb1V5W0A_1 person +A02wb1V5W0A_0 person +A08TTc4NLik_0 person +A1Hvxm2NCpk_1 airplane +A1H8wrYSPlQ_0 bicycle +A1NBheOGWNE_0 bird +A1fdw6WBO_w_0 cat +A1oQZf9EXPg_0 person +A1oQZf9EXPg_1 person +A1oQZf9EXPg_2 person +A1r3FpgoeP0_0 elephant +A1unjHSiYuk_0 skateboard +A1w5Z9ryeJI_0 elephant +A1w5Z9ryeJI_2 elephant +A1w5Z9ryeJI_1 elephant +A11L_7hymDI_0 train +A2ODL8T477o_0 umbrella +A2UiM17u3Ao_0 bear +A2Vhzr_2AAY_0 person +A2WfZtUfAy4_1 person +A2gisYdnTi0_0 bird +A2iD7VC-A9g_1 cow +A2p7Z_Ia9Ak_0 person +A2p7Z_Ia9Ak_1 person +A2rOJWkWoRo_0 person +A23nZy9maYk_1 person +A23nZy9maYk_0 person +A29DgqMHeEQ_0 person +A3EcM1p8r14_0 person +A3FTEFw2Bo0_3 horse +A3JmvJSIxeU_0 person +A3Lmb8E3Ovw_0 person +A3L2pdrSYdE_0 person +A3MpR785VH8_0 person +A3MpR785VH8_1 person +A3UoQh4P1_o_0 person +A3ZIKfh-QPo_0 person +A3b1bCXjWWE_1 knife +A3eocVVFaX8_0 person +A3vXSLx3blY_0 person +A4BVLpu2EQI_1 cow +A4CYcvyDGec_0 person +A4P_7hjid7Q_0 person +A4gw9TbmL54_0 train +A4ijVvmthCQ_0 person +A4oNmb9PiYQ_0 person +A4t4imYj0tA_1 dog +A4u61iOuzr0_0 person +A4u61iOuzr0_1 person +A4u61iOuzr0_2 person +A4wLmZZODQU_1 person +A4zzoIg6-W4_0 skateboard +A42uEePHr8c_0 person +A438LRj4MN0_0 horse +A5Ho_qla_bQ_0 skateboard +A5Kii0lU4h4_0 person +A5ZAKa7xw_I_0 person +A5ciZloGW2o_2 horse +A5nuZ-mKcBE_4 airplane +A5nuZ-mKcBE_7 airplane +A5-RNkQ5yzU_0 person +A5-yfb7-1NM_1 person +A6DfgaqbLDM_0 person +A6GND629_dg_0 person +A6IIHamstQo_0 person +A6KXKalaC7M_0 train +A6KXKalaC7M_1 train +A6LmIR6_mtk_1 truck +A6L7XcS8oF4_0 person +A6MkQdxLBSI_1 bicycle +A6MkQdxLBSI_6 bicycle +A6SipDli3dE_0 person +A6Tx9smTdyo_0 boat +A6Zbpn5hd6Q_0 person +A6jEv9bIawA_1 bus +A6rxrML8vyk_0 horse +A66pUkVBt_M_0 person +A7GxuMCyr50_0 cat +A7KLi_xOQFc_0 person +A7SDQoaalEY_0 person +A7SIvy9srFU_0 person +A7Zz2ESO-PM_2 bear +A7aEqy5QRJ4_0 cat +A7cjjAkLjfQ_1 person +A7cjjAkLjfQ_0 person +A7coVhNQrSs_0 cow +A7c_1Wcr5hM_0 cow +A7ltojA7WTk_0 person +A729VkZvy_s_0 person +A7_WDIFj23s_0 cow +A7_hPlvWyGc_0 cow +A8F5UnJOU5A_0 boat +A8MGPGEOAWk_0 train +A8PGaHrBO-g_0 bus +A8PlfHNTHVQ_0 person +A8RztgyPvCE_1 horse +A8U5HWirVCk_0 person +A8gL-e9dRa8_2 bear +A8oMFSrcteU_0 bicycle +A80V1BVUvf4_0 airplane +A89eQvkZ4go_1 car +A89eQvkZ4go_0 car +A89tFE_-szI_0 person +A9ACfqLHRIM_0 person +A9ACfqLHRIM_1 person +A9LEZHrMOh8_0 person +A9Mw5uHZ7WM_0 dog +A9UlOqoTO3A_0 car +A9WAS-oLC8Q_1 train +A9WAS-oLC8Q_2 train +A9etwHCHkQM_0 person +A9fblLjEn7E_1 person +A9fblLjEn7E_0 person +A9f0bktW-uM_0 train +A9sznaQipiM_1 person +A9sznaQipiM_3 person +A9tOXINxUeA_2 person +A-BcgCHWiLE_1 knife +A-JRl34Jmok_0 elephant +A-JRl34Jmok_1 elephant +A-JRl34Jmok_2 elephant +A-JRl34Jmok_3 elephant +A-MMqq_FLXo_0 person +A-R5A0HMT3w_0 boat +A-SdlQGGdZg_1 person +A-Vo3GQZrd8_0 skateboard +A-gQnulNzVo_0 person +A-gZpG3OWNM_0 person +A-jGPkEGCdo_0 person +A-qT3DcitzM_0 skateboard +A-0o6fFroLk_3 bird +A-1_sR8c39g_0 skateboard +A-1_sR8c39g_3 skateboard +A-37XpNHfQw_0 cow +A_AbA6K8Ouc_0 person +A_AbA6K8Ouc_1 person +A_B83i3dvWQ_0 person +A_CDsn7za4c_1 person +A_CDsn7za4c_0 person +A_DqzmxTyPQ_0 dog +A_Eaoo5O71M_0 skateboard +A_Eaoo5O71M_3 skateboard +A_Nb1jSK7vY_0 person +A_RHSgWC24U_0 elephant +A_R7iK_MLgM_0 elephant +A_Z7Cj10nKA_0 truck +A_aN9LUuMY8_0 person +A_g6G7vBr8I_1 person +A_qnLTG_VBg_0 person +A_uC3UuAVQE_0 cow +A_uxGLJDf9I_0 person +A_xtvYH_7vg_0 person +A__fHCZfwtM_0 person +BACWpC6GdxY_5 airplane +BACWpC6GdxY_3 airplane +BANdhsMHpw0_0 person +BANdhsMHpw0_1 person +BANdhsMHpw0_2 person +BAOR6YBIb8U_1 skateboard +BAO0Uce3vXA_0 cat +BARELTt_9Ko_0 elephant +BAWN6Xpw7sg_0 person +Zx3x1-cBu7I_0 person +Zx3x1-cBu7I_1 person +Zx8LkdyJzG8_0 person +ZyDqefuyQfU_1 cat +ZyDqefuyQfU_2 cat +ZyNwfXl7s2w_0 motorcycle +ZyQL8Ugiq4Y_0 person +ZyQxolWsw2o_0 cat +ZyQ_gFztNXU_0 train +ZyQ_gFztNXU_2 train +ZyqvHk5Ugjk_0 bird +ZyrTKvb3Uq4_0 person +ZyuoNtTPexE_0 person +ZywGdneFaWs_0 dog +Zyw6pIArS1g_0 train +Zy04v73t_oU_0 person +Zy4s6kQgRAs_0 person +Zy7a1FYT_2I_0 person +Zy9BXzUqORk_0 horse +ZzAgbPU4qoA_0 person +ZzBP5IPOX7Q_0 person +ZzBP5IPOX7Q_1 person +ZzFvfG2mfRU_0 cow +ZzIeftZXBMw_0 person +ZzPUlKXnUgE_0 person +ZzRMRSyCzzU_0 person +ZzS_a0D4AhE_1 skateboard +ZzWMnTc1LBY_0 person +Zzdl60FMu48_0 person +ZzeCPtqruzg_0 person +ZzgU7APbNfs_0 person +Zzgoobk2eIA_0 person +Zzgoobk2eIA_1 motorcycle +ZzhCWdZJAQY_0 person +Zzic21J3Ea8_0 person +ZznEoJsdkVI_0 person +ZzpccfyFyL0_0 person +ZzpccfyFyL0_1 person +Zzq_S3HujTo_0 person +ZztD-tmxwyc_0 person +ZzwlUbCfscM_1 dog +ZzxRC2pLBVA_0 person +Zz2oIdSVB6Q_0 person +Zz5GwCMuMj0_0 person +Z0D6uKz7v5Q_0 person +Z0m37r4St5Q_3 truck +Z0pLWU6Wg-o_0 dog +Z0stjlmfTpU_0 cat +Z0xYA5PwrjI_0 person +Z02r-T2hINk_0 elephant +Z04k6LBSuRk_1 person +Z1G9pYdQwCY_0 person +Z1HK6zDIJhg_0 person +Z1MvNM4bmxs_0 person +Z1SML4zVPik_0 person +Z1U7Wnf_WiA_0 cat +Z1XafO8l8gs_0 person +Z1aU1CigISE_0 person +Z1a8Tqg-yjE_0 person +Z1e-5FLWf6I_0 cat +Z1gxFkBk4EY_0 horse +Z1j81keSb9Q_0 motorcycle +Z1j81keSb9Q_1 motorcycle +Z1nr46t7EVk_0 airplane +Z1pv5a0as9c_0 train +Z1rB_fu2lKY_0 dog +Z1x8sEeQIuI_1 motorcycle +Z13O2uGP1nE_0 car +Z14p6heAJRc_2 person +Z14p6heAJRc_0 person +Z14p6heAJRc_1 person +Z15QqHX1Z6M_1 train +Z2HF5_tyxR4_0 bus +Z2K03YbfcGg_0 elephant +Z2QWOKCHkM8_0 cow +Z2QWOKCHkM8_2 cow +Z2QWOKCHkM8_1 cow +Z2SljfwK58g_0 skateboard +Z2SljfwK58g_1 skateboard +Z2VI7eM7BB0_0 bear +Z2acpS-e_cg_0 person +Z2cvYI55Dps_0 skateboard +Z2dab1zmqv8_0 horse +Z2gvlPrX5HA_5 elephant +Z2gvlPrX5HA_6 elephant +Z2kcVxTMZtM_0 person +Z2n2a39MxJQ_7 bicycle +Z2n2a39MxJQ_1 bicycle +Z2n2a39MxJQ_2 bicycle +Z2n2a39MxJQ_3 bicycle +Z2n2a39MxJQ_4 bicycle +Z2n2a39MxJQ_6 bicycle +Z21DONVXY1Q_2 zebra +Z23Gg06mNj8_0 person +Z236ql8Tpvg_0 person +Z23_3K28VSI_1 giraffe +Z3AHrAB9qhw_0 cat +Z3AplkSO6kA_1 car +Z3KMX_N6WSg_0 person +Z3KMX_N6WSg_1 person +Z3KMX_N6WSg_2 person +Z3PzgfwbjLk_0 truck +Z3i5sys0boU_0 person +Z3i5sys0boU_1 person +Z3sRLCOCxMY_0 cat +Z37dIpwPIqI_3 bicycle +Z4DQoYcs5mM_2 person +Z4DQoYcs5mM_0 person +Z4DQoYcs5mM_1 person +Z4XLmQjbg7Y_0 person +Z4XLmQjbg7Y_1 person +Z4ZKg0KbSm4_0 bicycle +Z4ZPyzSGdRU_0 dog +Z4bO8cpjQZI_0 person +Z4bO8cpjQZI_1 person +Z4bW8HHeYP8_0 car +Z4mYWGPFVkw_0 person +Z4n5ieSA6cM_0 cow +Z4tOSluXWnE_1 umbrella +Z4u3PPkCYOs_0 person +Z4u4zasFeAw_1 bird +Z4u4zasFeAw_0 bird +Z4vRtZE1WjQ_0 dog +Z4voZ3h_Dyk_1 person +Z4xVMaYAqJ4_1 bicycle +Z446P08C8vE_0 person +Z5KGx49qaAE_3 bird +Z5KGx49qaAE_5 bird +Z5KGx49qaAE_6 bird +Z5Qo8xdb8os_0 elephant +Z5RKMhlNHEE_0 person +Z5ZBRI0sc4Q_0 bicycle +Z5iJRTvm-Kw_1 person +Z5iV683VDk0_0 person +Z5ls93B1bBk_0 person +Z5mQ_0ttu74_1 elephant +Z5mQ_0ttu74_2 elephant +Z5yNMm-TIjI_0 bus +Z5zGHZ82r9A_0 person +Z53B8-gR640_0 person +Z6BVtmEMfkI_0 person +Z6FikDWrKkA_0 person +Z6MfvYa9hCs_2 car +Z6MfvYa9hCs_3 car +Z6PyYboRq5c_0 dog +Z6Q3LdMwgi4_0 cat +Z6WrlM4ZZKA_0 person +Z6j-7La25S4_0 person +Z6j-7La25S4_1 person +Z6j-7La25S4_2 person +Z6k1unwmsfA_1 person +Z6sd800eFC4_0 person +Z6tGpP8q53A_9 elephant +Z6tGpP8q53A_2 elephant +Z6tGpP8q53A_4 elephant +Z6vCDHs6NrM_0 person +Z6yNyxXPPOw_0 elephant +Z60iXtKpGMQ_0 bus +Z61B0fShfbs_1 cow +Z7AqkWEBwV8_0 person +Z7DGMMQP79U_0 cat +Z7I8r1AqMhU_0 person +Z7JHCdt48hA_0 airplane +Z7KEzuE_7hQ_0 person +Z7LfnFm4OHs_0 person +Z7WaJYiX_1o_0 person +Z7WaJYiX_1o_1 person +Z7bMdjLGiAo_0 person +Z7eGCBjkKrU_0 dog +Z7gxE6ZSQXI_0 airplane +Z7iq45DtCTM_4 horse +Z7iq45DtCTM_5 horse +Z7zeXJ5lJRY_1 person +Z7zeXJ5lJRY_0 person +Z72sIqrQAF4_0 skateboard +Z74EGXvFjFM_0 person +Z76Y_PNOgK4_1 person +Z76Y_PNOgK4_0 person +Z78P87kjtu4_0 person +Z8CXvEObu4c_0 dog +Z8NfZN7WDKw_0 person +Z8Oi5HJEyS4_0 skateboard +Z8k0TTq5BC8_0 horse +Z8s-Kg1PuSg_0 horse +Z86E7eIS9t8_1 airplane +Z89mG68LE2k_0 person +Z8942_IPiTo_0 bicycle +Z8942_IPiTo_2 bicycle +Z9SwanypLJM_0 bear +Z9SwanypLJM_1 bear +Z9XS4cvVVy4_2 person +Z9awHnw5J4o_0 truck +Z9bt3xT5dCc_0 cat +Z9f--QLEQqI_1 motorcycle +Z9jDpr533Cg_0 cat +Z9o5BEm1UeI_0 person +Z9pHCguAO5c_0 person +Z9wO9tftNG0_0 bus +Z9x_cPvKErA_0 person +Z98EscJ1IG8_0 person +Z98GFnZo-LA_0 person +Z-I0S45eRT0_0 person +Z-J0UQfvb5M_0 person +Z-MvTXpMdm4_0 truck +Z-PMnTjqAS8_0 person +Z-QO3lrbh7c_1 skateboard +Z-VVWO3Ovgs_0 person +Z-djkrj-5Cs_0 horse +Z-glDeBd2xA_0 boat +Z-lrIzXr9ck_0 train +Z-mTl_ipVa4_0 umbrella +Z-mXYrvubn8_0 dog +Z-zy-BzjLT0_0 motorcycle +Z-zy-BzjLT0_1 motorcycle +Z-7W_lh96xg_1 airplane +Z_JXyC6v_-s_0 person +Z_KItWz0mTI_0 elephant +Z_PViIzihe8_0 person +Z_QVuM8wEmQ_0 person +Z_QVuM8wEmQ_1 person +Z_kPrUEqYXE_0 bird +Z_p4gYNjwG0_0 person +Z_85vV3FHUg_0 person +Z_85vV3FHUg_1 person +aACqXYewohQ_0 person +aAI7SN5_3CY_4 bus +BAhHrnCKvcM_2 boat +BAhHrnCKvcM_3 boat +BAhHrnCKvcM_5 boat +BAmy5TQke7w_0 person +BAnfbsB8rIY_0 bear +BAnn4L-iNLE_0 person +BAq_fnyQ6z4_0 person +BA4ZGv8flRA_0 person +BBCBbdz3Qvs_0 dog +BBCBbdz3Qvs_1 dog +BBLAyHVLHh8_0 person +BBOd-YBAUgw_0 bicycle +BBPlqTbAphY_1 person +BBQ2xu9OehQ_1 dog +BBS5owVJaTU_1 skateboard +BBS5owVJaTU_0 person +BBVPb5z0x7k_0 cat +BBXs1J4j2mA_0 skateboard +BBdA1qc9H-g_0 skateboard +BBk7ZnOEjMA_0 person +BBopEl_n3Fc_0 person +BBpFu8j2fBc_0 bus +BBpFu8j2fBc_1 bus +BBqTHwpYeEc_0 train +BBrfgTTduuI_0 person +BB9l_znmPls_0 umbrella +BCBCK2k2Bdw_0 person +BCBgjRWuOcA_0 person +BCGB6zaBDpg_1 person +BCGB6zaBDpg_0 person +BCI91i3aEek_0 motorcycle +BCJbf6um28s_1 airplane +BCKVauIBDFM_2 bear +BCin0MjzM8Y_0 cow +BCoTKGNhMVw_0 dog +BCoTKGNhMVw_1 dog +BCo8e6n2dYQ_1 dog +BCqYnyGIols_1 bicycle +BCsmPvRqaNk_0 person +BCuzA73UTl4_0 person +BCwAdqAouFU_0 boat +BCwyoTwckSE_0 truck +BDFBV8JbIF8_0 person +BDFVkc87amI_0 person +BDHUAJn9nnc_0 person +BDHsXkbkS-w_0 skateboard +BDOemJGz04I_1 person +BDcTOMebCHs_0 person +BDcTOMebCHs_2 person +BDcTOMebCHs_1 person +BDdIKtFwnjA_1 train +BDdbk3ZQrP0_0 cat +BDdhenNSY9o_0 person +BDk-BklqSdI_0 person +BDroGke9Ogg_0 horse +BDroGke9Ogg_2 horse +BDtGFVFexaU_0 person +BDzXi4ukhN0_1 person +BDzXi4ukhN0_0 elephant +BD30MTvTuYU_0 person +BD7TQWBytfQ_0 knife +BEArUGKSB-Y_0 train +BEArUGKSB-Y_1 train +BEKMcritl6M_1 person +BEMcwkY2beQ_0 person +BERvmKL4Glc_0 person +BESdHwoIDsA_0 dog +BEUB64a3AIY_0 elephant +BEUB64a3AIY_1 elephant +BEYy-ZRSWSk_0 skateboard +BEa_8wp0528_0 cow +BEqG56tHTEI_2 bus +BEqPniAgjaY_0 cat +BErty5GnulU_0 person +BEuXjB1zLeE_1 car +BExSp8l17GY_0 person +BExlFv0scM0_0 person +BE10HJUHUHw_1 person +BE8KS4PZH54_0 elephant +BE-crlUXSSE_0 dog +BFC3DWxOces_2 airplane +BFC3DWxOces_1 airplane +BFC3DWxOces_3 airplane +BFC3DWxOces_4 airplane +BFC3DWxOces_5 airplane +BFJ4v-XlKAg_0 skateboard +BFPQCoJqTRk_0 person +BFeIwErwdS8_0 person +BFeIwErwdS8_1 person +BFggPKKt6wk_0 person +BFggPKKt6wk_1 person +BFhh8z0Fmk0_0 person +BFponHgVsdA_0 person +BFs239KuGa8_1 person +BFxUyTrqZhU_2 horse +BFxUyTrqZhU_4 horse +BF4YTMGtDs8_1 skateboard +BGAQlsAiJ_0_0 airplane +BGAQlsAiJ_0_1 airplane +BGAQlsAiJ_0_2 airplane +BGAQlsAiJ_0_3 airplane +BGAQlsAiJ_0_4 airplane +BGAQlsAiJ_0_5 airplane +BGAQlsAiJ_0_6 airplane +BGLM4yl_Ka4_2 horse +BGO3DBbNozc_0 skateboard +BGR1gMrCTpA_0 person +BGT-p0CgoFg_1 person +BGW9SDHTWKY_1 person +BGW9SDHTWKY_0 person +BGee3Ar-Fbg_0 airplane +BGpx9Xow9Ew_0 cat +BGqNnzNtWkc_0 person +BGq6TeZHkLU_0 elephant +BGshZfVDb5w_0 person +BG4QyYPKYvg_0 person +BG4QyYPKYvg_1 person +BG_x-4YUtFE_0 dog +BHA5UUg4lCw_2 train +BHH2sTfHwks_0 person +BHH2sTfHwks_1 person +BHPSyq8L5S8_1 person +BHQkdwmXrtI_1 skateboard +BHQkdwmXrtI_2 skateboard +BHYrJ1yaM-w_0 car +BHdbqcxv3Vw_0 truck +BHfXgxJCcrw_0 boat +BH5fxWFpHvE_0 airplane +BH5npOcPlY0_0 car +BH6nqU68dWo_0 person +BH74QV_0vtc_0 bird +BH9Ob6Uiw1w_1 person +BH_SlBCiQ_8_0 person +BIETPRRGGgY_4 elephant +BIETPRRGGgY_5 elephant +BIIU36E15Vo_0 person +BIMggdk7AHQ_0 cat +BIQeL2o_Ogg_0 person +BIUQ935UkDo_0 cow +BIVLmUTNYbk_0 person +BIV-1bNQ7pI_0 skateboard +BIfqcruNiic_0 person +BIkDAHYmcFw_0 person +BIkDAHYmcFw_1 person +BInC--gFqHM_0 person +BIvTK9qvP1w_0 skateboard +BIxCP9ck4-8_0 cat +BI5i3aDb_FQ_1 person +BI-kr0tFSDg_0 person +BJIZYdOZHzg_0 umbrella +BJK_SXpLtnI_0 bird +BJMP05du3Eg_0 person +BJQstPOa8Wk_0 person +BJS2YLbErJg_1 person +BJfRrRcfmF4_0 skateboard +BJf9nFjqLvg_1 bird +BJlcWhfsg_g_0 person +BJriJT6zJl8_1 skateboard +BJwoZcHbBK0_0 umbrella +BJ05o1_UKzw_0 dog +BJ44CIPaDf8_0 person +BKAo6GZ_kNs_0 train +BKTCaKgjiag_2 person +BKUKi0vTt0A_0 person +BKdSO_PNJ4U_1 person +BKdSO_PNJ4U_2 person +BKdSO_PNJ4U_0 person +BKl0wLRzoD8_0 person +BKw9UQxZ3a8_1 horse +BK-rIrwen6U_1 motorcycle +BLB0F-XD8IA_1 person +BLB0F-XD8IA_0 person +BLEdcnrUmEo_0 cat +BLE9cZ8L3a0_1 skateboard +BLFYe-dU9ZU_0 airplane +BLO7KJUu8t4_0 elephant +BLSwwE9mtTQ_1 knife +BLcOGv-0-dc_1 dog +BLfmgLou27o_0 cat +BLvowRU6z7s_0 bird +BLxsg2_sjDM_1 person +BLy6RcifNl0_0 bus +BLy6RcifNl0_1 bus +BLy6RcifNl0_3 bus +BL6tcorHrT4_0 bicycle +BMH2ReDeKuc_0 person +BMUnKa8FUGQ_0 person +BMUnKa8FUGQ_1 person +BMavrQABR1Y_0 person +BMa4xJ1U3Zk_0 person +BMbZc-jxEfo_0 person +BMbZc-jxEfo_1 person +BMfsf9tDz8o_0 cow +BMfsf9tDz8o_1 cow +BMhy1f7EuXM_0 elephant +BMptIGI1Il8_0 car +BMuO2fjJoOw_0 car +BMweJTmvCBg_0 person +BMweJTmvCBg_1 person +BMypDovEOEE_0 person +BMypDovEOEE_1 person +BM0QiiStqd8_1 skateboard +BM6XrBQQ7NE_0 person +BM6609PpfO0_1 person +BM6609PpfO0_0 person +BNGDM8sFM8Y_0 person +BNIVhG5pZh8_1 dog +BNJwAx3eUKc_0 person +BNK68rC7RdI_0 umbrella +BNTS3OPHAP4_0 horse +BNXKRPSr66c_0 person +BNXKRPSr66c_3 person +BNXKRPSr66c_1 person +BNXKRPSr66c_2 person +BNbPQGMLs2w_0 person +BNbPQGMLs2w_1 person +BNbSUPI8feg_0 person +BNcj3161E9o_0 person +BNeWUyqXAC0_1 airplane +BNmMB68b1PA_0 person +BNnVfaIfBx0_0 airplane +BNnVfaIfBx0_1 airplane +BNyK_4tt2fg_0 car +BNybc47kPjg_0 person +BN1HT0FOOhI_0 dog +BN7YfmbYuVs_0 elephant +BOE82LEqzWw_0 cow +BOF3tFvEu0o_0 person +BOHE8JNUcQc_0 boat +BOMeyjZNH5k_0 bicycle +BOQiuL9QlIo_1 person +BOUcPea33eY_2 skateboard +BOfgzvAgVQw_0 bus +aAMhdGuR5DE_0 cat +aARa5-CLhG8_0 person +aAVaqjgY1m8_1 person +aAZ2fVjhcIE_0 person +aAj0EN1Rnc0_0 bird +aAj0EN1Rnc0_1 bird +aAlTiBaLr8M_0 person +aAmVIu8X7p4_1 person +aAma36YlaAo_0 zebra +aAsr-Rf6rEE_0 person +aAsr-Rf6rEE_1 person +aAuz7EfR_fU_0 cow +aAyTLM_PmzA_0 skateboard +aAzpA1iK_bE_0 person +aA0FrWtkjXk_0 person +aA3okCsYx6Y_0 bird +aA5DYzky6o4_0 cow +aA8Tz4nZ99g_0 person +aBBtHXQoEtM_2 person +aBBtHXQoEtM_1 person +aBQm5kN1TfY_0 cat +aBexNnNkORk_0 airplane +aBq4NF1upak_0 person +aBvvXrP1BJs_0 person +aB-tGXFmyFU_0 person +aCQAel27T4o_2 person +aCSzhpU1heQ_0 cow +aCXfvvg8CF8_0 airplane +aCiDDC9KFS8_0 motorcycle +aClye1Ctc9E_3 truck +aCl98J6O9Hk_1 person +aCuXZ3LmfSo_0 person +aDGpg2xtDk8_1 person +aDRE08tF2Wc_1 bus +aDTQRnSeu_E_0 skateboard +aDTTYd0Z5Vk_1 person +aDjhOS5Xa9Q_0 boat +aDmLwCb_o30_0 dog +aDtJSv7XR90_0 car +aDte-e70l7U_0 cow +aDte-e70l7U_2 cow +aDte-e70l7U_3 cow +aDt4Puik-kU_0 horse +aDwTy9yiOms_0 umbrella +aDxRlCI40wo_0 person +aD2q00X0-eg_0 person +aD2q00X0-eg_1 person +aEJy28mvKPk_0 person +aEJy28mvKPk_1 person +aEMPa2NvIl4_0 horse +aERed6pg_h8_0 person +aER-VrHLWwY_0 person +aER-VrHLWwY_1 person +aEZ9vBpXNKU_0 person +aEw_vtKlegE_0 elephant +aExRtJpfZEs_0 knife +aE1veVneq04_0 person +aFC2Zy2-0dY_0 person +aFFKeUdtPcQ_4 knife +aFL2V522q9A_0 person +aFZ03eEOZFE_0 bird +aFbVlCimys8_0 bird +aFdPuo5xB-c_0 person +aFhKp8gVZSE_0 person +aF86vrld8V4_0 person +aF-CmWo8ooM_0 person +aF-CmWo8ooM_1 person +aGAB6WQFklc_0 person +aGE8AphnkNU_0 knife +aGGiVuwB1p8_0 bear +aGY3LCiYRnQ_0 motorcycle +aGgnovv6T3U_0 dog +aGgxdwCpAN0_1 horse +aGhNzJSHCOU_1 knife +aGmxZatPe60_0 person +aGmxZatPe60_1 person +aGuWVv6XS8Q_0 person +aGuWVv6XS8Q_1 person +aGwPRbsru-4_0 cat +aGxOl5SXjtM_0 person +aG1c8x5Dl-w_3 bicycle +aG1c8x5Dl-w_2 bicycle +aG1c8x5Dl-w_4 bicycle +aG20iwkTd_o_0 person +aG6D_te6V3s_0 person +aHEFx7Zz6E4_0 person +aHb4yEpCinw_0 truck +aHiGSUMMfBQ_0 person +aHnMWEvjLzI_0 car +aHrTcxckS-A_0 person +aHrTcxckS-A_1 person +aHsgQAyd8ss_0 person +aH2ZxImdwaU_1 motorcycle +aH2ZxImdwaU_2 motorcycle +aH5Cd20kdJw_0 elephant +aILjXrLJpHw_0 umbrella +aIQf8LQ5QPU_0 person +aISEbZGZH68_1 car +aITryMUZ2b8_0 person +aIUYT8pblHs_0 truck +aIU5E5tHvdc_1 person +aIVWVNBI-n0_0 elephant +aIcFi8LMv0w_0 airplane +aIjLf6T_K3o_1 bear +aIoZO3mu_tQ_0 person +aI311E3BWwI_0 elephant +aI7axTZFW4A_0 truck +aI80ysvYFG4_0 person +aJChqX9Ki8A_6 airplane +aJChqX9Ki8A_1 airplane +aJChqX9Ki8A_2 airplane +aJChqX9Ki8A_5 airplane +aJN9lRsvUv8_0 person +aJQ9scZQmz8_0 person +aJTABCCQtK4_0 horse +aJYmkpuijrk_0 motorcycle +aJYurtxV0Og_0 train +aJYurtxV0Og_1 train +aJcPyWppCcI_0 motorcycle +aJgpAyFnpeI_0 cat +aJ0dUcEIE_U_0 person +aJ1SzcgNcxI_0 cat +aJ8w4L7E368_0 person +aKLf2yC2diM_0 car +aKMqeCkIJSg_0 person +aKOMIxz2RsM_0 person +aKOMIxz2RsM_1 person +aKiwOUy71Lo_1 person +aKiwOUy71Lo_0 person +aKqrwq-Sigg_0 skateboard +aKtBD-3wFMA_2 bear +aKtBD-3wFMA_1 bear +aKu-1-TFl1g_0 knife +aK-rgio7orw_2 bus +aLDq7roX-SU_0 cat +aLFDqtBMblI_0 cat +aLFxGnCM1zs_0 person +aLIa7x90hQc_0 person +aLUSnANtUlE_0 airplane +aLX9cIe12C8_0 skateboard +aLZAMgiWcXk_0 bird +aLZ0lbLzg8Y_0 person +aLZ0wCY2j2s_1 person +aLeeoZ1uVcc_0 boat +aLjomcNk9fc_0 person +aLj4N9Tp6C0_0 skateboard +aLj4N9Tp6C0_1 skateboard +aLo-gekX9j0_0 person +aLo-gekX9j0_1 person +aLuNNRUC09A_1 bus +aLuNNRUC09A_6 bus +aLvCIWJQJbY_0 car +aLvg1CWrY0Q_0 truck +aLxJ8T4CFuM_0 person +aLzL_Gldhzk_1 person +aLzhO0EqNcc_3 horse +aL6H2Jatw0k_0 cat +aL70_drPJtA_0 train +aL8hELYDnTc_0 person +aMAKznXul5M_2 knife +aMAYLrcEnZY_0 bus +aMAeSegIdJg_0 person +aMAeSegIdJg_1 person +aMHtvIvWTBU_0 bear +aMNbQ1Cl5GY_0 motorcycle +aMRtQFBcLNM_0 person +aMX0jhSq6UY_0 person +aMb78Ixlbfw_0 skateboard +aMqHsdXJ7UU_0 person +aMzZxN9uvMc_2 horse +aNB5rIhRL7g_0 airplane +aNEpBEnAUhw_0 motorcycle +aNF18KgxGHA_0 skateboard +aNJuTWrnIfo_0 person +aNJuTWrnIfo_1 person +aNKleFpxS4M_0 person +aNKleFpxS4M_1 person +aNNWNDoOM_4_0 person +aNNWNDoOM_4_1 person +aNOXvvKZ3qU_0 person +aNZMe4tov6w_0 cow +aNdJrRu4imo_0 person +aNjs-khPjiU_0 person +aNj1xwowXYU_0 person +aNqkQnGfWEc_2 skateboard +aNqkQnGfWEc_0 skateboard +aNwIHwPqFPc_0 car +aN4Na3OaY4I_0 bicycle +aN4NmH-GafU_0 person +aN770kOQCD8_0 person +aN82X1hXgEE_0 person +aN82X1hXgEE_1 person +aN9XAd7-rzE_0 person +aN9XAd7-rzE_1 person +aN_3Pwk-7oY_0 person +aOHPVt_93RE_0 bicycle +aON6RKmi-YQ_2 train +aOPbvY62dMQ_0 airplane +aOQ-8RoQYEU_0 person +aOQ-8RoQYEU_1 person +aOQ-8RoQYEU_2 person +aOW81s5KlyA_0 person +aOcGv3kcyhg_0 bear +aOcGv3kcyhg_3 bear +aOjjUIWuG6Q_1 elephant +aOp2NlwNeoY_0 cat +aOz0l6mLHmA_1 dog +BOlBcGufEU8_0 person +BOlBcGufEU8_1 person +BOmgqlRxGlM_1 person +BOmgqlRxGlM_0 person +BOnvGIZd58M_0 person +BOowRuwiNhU_0 person +BOowRuwiNhU_1 person +BOr7CffDWEU_0 person +BOsNz8L3PXI_0 person +BOtfIOm5kag_0 dog +BO1T_-iFGdM_5 bird +BO1T_-iFGdM_2 bird +BO1T_-iFGdM_3 bird +BO3UKxe7nyo_0 person +BO5EdP_PO9M_0 person +BO7sWBaaL7g_0 person +BO7sWBaaL7g_1 person +BO-3uvHhUdI_0 person +BO-3uvHhUdI_1 person +BPBBMIdFoiE_0 person +BPEwUVhfaOk_1 knife +BPVpq7UrI-k_0 person +BPX5EquoyCU_0 motorcycle +BPX5EquoyCU_3 motorcycle +BPX5EquoyCU_1 motorcycle +BPX5EquoyCU_2 motorcycle +BPiWTYUA7eI_0 person +BPjkQ-lEqcw_0 person +BPrrZpiDdo4_0 cow +BPsTDg4C4o0_1 person +BPsTDg4C4o0_0 person +BPxPfFzwlQA_0 truck +BP-GGAbCOhE_1 bus +BQDxNNWRtas_0 car +BQDxNNWRtas_1 car +BQEzj9pP1SU_0 person +BQIO94PF6RE_0 person +BQIO94PF6RE_1 person +BQVcvMWyWpU_1 person +BQZGptzIdjE_0 cow +BQgPk0vRreM_0 bird +BQgPk0vRreM_1 bird +BQgPk0vRreM_3 bird +BQgPk0vRreM_6 bird +BQgPk0vRreM_9 bird +BQh5Ib9nynM_0 truck +BQtDUi4BxRg_0 person +BQwLGv7fgQg_0 person +BQxCcefrjSk_0 cat +BQyowuIZqFQ_0 person +BQzzKQ9ejzw_1 knife +BRCb183ELe0_0 person +BRHPsi_0nTg_0 motorcycle +BRQiSnowTss_0 horse +BRVNuDR5WzI_0 cow +BRcQS0dQqEU_0 car +BRfegSv5VEk_0 person +BRfegSv5VEk_1 person +BRi_AMaK3kc_0 dog +BRjvUtQdukg_0 horse +BRlWBt4WHdU_1 horse +BRnsmPzoEsM_0 skateboard +BRtCCpXG_N8_1 elephant +BRt1o8xqxFs_0 person +BRt5hLASRMU_0 bird +BRxrw0-skYM_0 elephant +BR0SGq2ioqU_2 train +BR0SGq2ioqU_7 train +BR1gOlJPEdk_2 elephant +BR8cOV8KYX4_0 person +BR-XwELzLV0_1 dog +BSDy_dzOSS4_0 cow +BSHg9I0V6Yc_2 bus +BSJgV2iO0jc_0 person +BSOCno_3bfI_0 person +BSSyaPq1EoM_0 train +BSWNCcyXeR4_1 horse +BSWpwtIPQ9U_0 elephant +BSWpwtIPQ9U_1 elephant +BSWpwtIPQ9U_2 elephant +BSWpwtIPQ9U_3 elephant +BSqz3i60KPw_4 bicycle +BSqz3i60KPw_1 bicycle +BSqz3i60KPw_2 bicycle +BSutEBx3H4A_0 truck +BSvCnoryvn4_0 elephant +BSyxB7X9SH0_5 truck +BSyxB7X9SH0_7 truck +BS1lexD0ugY_1 person +BS1lexD0ugY_0 person +BS5mJ0Y7Rys_0 person +BS-S0nYSwkQ_0 person +BS-S0nYSwkQ_1 person +BTBmlFGHK-8_2 person +BTBmlFGHK-8_0 person +BTBmlFGHK-8_1 person +BTKLizyvgcA_0 person +BTR83oP1vpo_0 person +BTlwglCdzOk_0 elephant +BTpBteZfK7Q_0 cat +BTxSuijXVPY_0 person +BTywlpNCABw_0 cow +BTzWqg8vHQI_0 car +BT9sKGDb0Qw_0 train +BT9sKGDb0Qw_1 train +BUF45g7KGB8_0 motorcycle +BUX8raEGFZk_0 dog +BUX8raEGFZk_2 dog +BUX8raEGFZk_3 dog +BUY-_l8_v9s_0 person +BUZ7x7JaQ1k_0 person +BUrMlyUBryI_0 horse +BU4SnrK9UiY_0 horse +BU4SnrK9UiY_2 horse +BU4yiA6qKAQ_0 bicycle +BU5PaU-UTss_0 person +BVAi_zqhIeg_1 person +BVCe2emxuTQ_0 horse +BVFYmsvoNTA_0 cow +BVS5Q8eBmRs_0 person +BVWEvs3lq0Y_0 person +BVWEvs3lq0Y_1 person +BVXMpcHTg80_2 motorcycle +BVm9KRW0iu8_0 motorcycle +BVo3XdFnAJM_0 horse +BVxr6TGFsMQ_1 person +BV5tXmVwddI_1 person +BV-UtDJNS2w_1 motorcycle +BWA5eWlt6Lg_0 car +BWFYpOE-8yo_0 person +BWcaU8lR4rM_0 person +BWdhK5cwgt0_0 bus +BWjRZ-aKRX4_1 person +BWlnPrI8FLk_0 person +BWnFU-Li_8E_0 person +BWn3QGOyZJc_0 elephant +BWn7EPWkJ2I_1 bear +BWp2oVJMG1A_0 person +BWqYVuIKaNA_0 person +BW5r0Kv6h2U_0 boat +BW56O_QhBmc_0 person +BW7uP0jcst8_0 horse +BXA3uMFAA9M_0 cow +BXCd65rDsk4_0 dog +BXCrD4eGGWw_0 person +BXHktSPnW24_0 person +BXTGSkuESqU_0 person +BXUL3aLVZM4_0 person +BXWXLNGacmc_1 motorcycle +BXWXLNGacmc_0 motorcycle +BXdMv9s3Rtw_0 person +BXiQhR0Zj70_0 person +BXrwbMjK_ZU_0 train +BX8AJD8uL3U_2 person +BX-SAZsC6yc_2 knife +BX-SAZsC6yc_4 knife +BYQfvvAP9rY_0 person +BYRNeh3RRZs_0 person +BYS-DmtMpWE_0 cat +BYVhHLCSZ_M_1 dog +BYYakMVK6Ko_0 person +BYi8dYVDYak_0 person +BYkytpBqzHQ_0 airplane +BYq45niURL8_1 truck +BYq45niURL8_0 truck +BYud6fy8t8A_1 knife +BYud6fy8t8A_0 knife +BYud6fy8t8A_2 knife +BYud6fy8t8A_3 knife +BYxg5sQjvQ4_0 person +BYyATiWsxZs_2 car +BYyATiWsxZs_0 car +BYyATiWsxZs_1 car +BYyrXwDFF5U_0 person +BY0XhpATtuI_0 umbrella +BY2Fs4KDDbU_0 motorcycle +BY7KYQ_Qf3Y_0 cow +BY8mmPl_K_A_0 person +BY-5sA1BbFE_0 dog +BY-5sA1BbFE_2 dog +BZDa7e9EFvI_0 knife +BZERyxrpvg4_1 person +BZIzw3XdAgI_1 person +BZI3ovXxotQ_0 knife +BZeIe9Nkb1E_0 cat +BZgZ1H4t3hQ_0 person +BZgxjWSM7Vc_0 bicycle +BZhfYzqKuu8_0 person +BZkYWI_qxz4_1 bird +BZldivEoOo8_0 person +BZli_iMMV8k_0 bear +BZli_iMMV8k_7 bear +BZ94WX4wHn0_0 skateboard +BaDQg_CCQpU_0 person +BaDQg_CCQpU_2 person +BaHS1WcgbbE_0 bird +BaHS1WcgbbE_1 bird +BaJTQLa-vuU_0 person +BaOQYsYuC6A_1 elephant +BaRsW_taGVY_0 cat +BaWQb_lSjYs_0 train +BaYLeM_yk_Q_1 skateboard +BafH7BetIyk_0 person +BakCr5HeDNE_2 boat +BakCr5HeDNE_0 boat +BauKE-faLzM_1 person +BavQVUFfmBU_1 person +BavQVUFfmBU_0 person +BavoG7kb0wo_0 car +Baxc5TW06FU_1 knife +Ba1sC-X1OF8_0 person +Ba1sC-X1OF8_1 person +Ba2T3joy6BQ_0 person +Ba3CWVKFpBE_0 boat +Ba5BO-nvDnE_1 horse +Ba-SiAqH09k_2 truck +BbAdBjyFFEA_0 bird +BbAdBjyFFEA_1 bird +BbAdBjyFFEA_2 bird +BbEfZ9mUKOY_0 cat +BbOabnT5V-E_0 person +BbQyfmZx-2Y_2 bear +BbRarKH6D_Q_0 horse +BbYZ7Ee3Ixs_0 person +BbYqjT1OzLY_0 person +BbYqjT1OzLY_1 person +BbfOXQD21Ac_1 motorcycle +BbnSU5sRdBs_0 person +BbnxzNL5tMk_0 person +Bbq8h83cFE8_0 person +Bbu_YM_GBG4_3 bird +Bbu_YM_GBG4_0 bird +Bbv9Y9Goufk_5 elephant +Bbv9Y9Goufk_0 elephant +Bbv9Y9Goufk_1 elephant +Bbv9Y9Goufk_2 elephant +Bb4uwSjmtKk_2 bird +BcHl4OuJLT4_0 person +BcHl4OuJLT4_1 person +BcSXX5O_YDw_0 bicycle +BcVn38vI_Zk_0 person +BcV5QdDIrMg_0 person +Bcg-TsdpO-Q_0 person +BcjVHV-6WWM_0 person +BcjZaclf1m0_3 bird +aO4uLNN4Gt0_0 bear +aPCEyodWBU4_0 person +aPPUf7JUJRo_0 person +aPf5SoOgmhQ_0 motorcycle +aPheJtUTSps_1 boat +aPm89i_7aKs_0 train +aPm89i_7aKs_1 train +aPswSvCaFDQ_0 elephant +aPvqWgeR03U_0 person +aQAieL0LKIo_0 horse +aQB2gAnqQi0_1 person +aQGQKDLwRqM_0 person +aQVn7fJi_l4_0 cat +aQaKnTZ4hDg_0 person +aQfQqr5W5uI_1 truck +aQfQqr5W5uI_2 truck +aQfQqr5W5uI_4 truck +aQlLjT95Hgs_3 horse +aQub6VGWKzQ_0 car +aQzKS5Sn9u0_0 person +aQ1c75hfANo_0 person +aQ6larydXgI_4 elephant +aQ6larydXgI_0 elephant +aRBWB79BIIg_1 umbrella +aRHGn50eToQ_0 bear +aRQQ75s9Ni4_0 boat +aRRUAfurxVU_0 person +aRcw_PTSf4o_0 person +aRdAN9jVvqQ_1 dog +aRnJ4lIPIL4_0 bus +aRueDRgWEOs_0 truck +aRzwrPXsTRI_0 truck +aR6P3PtMIZc_0 person +aSDuIU0pzYY_0 person +aSH88cb0kww_0 person +aSMzQpOjAc8_0 train +aSUtY_pSN0k_0 bird +aSWGbO-Nfcg_0 train +aSWGbO-Nfcg_1 train +aSb-LY3vBsg_0 giraffe +aSkBoJ55w2Y_0 person +aSqwAZJaQIk_0 bus +aSqwAZJaQIk_2 bus +aSsjyvISV94_0 train +aSw1yhbXHuA_0 elephant +aS2Zw7-j7p4_0 car +aTBr31jkThQ_3 bus +aTOn74Inw24_0 bird +aTR3FylgTkA_1 person +aTR3FylgTkA_2 person +aTS8hur_yyo_0 person +aTcDiEXEhhk_1 horse +aTdIOtWasSE_0 person +aTeFjqoG9fM_0 person +aTeFjqoG9fM_1 person +aTj38bNIsQo_0 cow +aTvgsqSb5aA_0 person +aTvoRXrEvG4_0 bicycle +aTvoRXrEvG4_2 bicycle +aT3idINTybY_0 umbrella +aUFHlj5AVrU_0 person +aUNlQPWMFHo_0 car +aUQh47P34C0_0 person +aUQh47P34C0_1 person +aUX-HZraWQs_3 zebra +aUh41vv5vdE_3 train +aUh41vv5vdE_0 train +aUh41vv5vdE_2 train +aUv4LjbJxLs_0 bus +aU5AZMYHZ2o_0 dog +aU5tePXE5qE_1 elephant +aVFbcdQrobU_0 person +aVGtibXVt40_0 train +aVMpwmT7ojA_0 truck +aVPIHMyNEw8_0 truck +aVZJ8qaxG3s_0 person +aVif6Qc9Prw_0 cow +aVknWcQimJA_0 bus +aVm9jp_ttsk_0 elephant +aVm9jp_ttsk_1 elephant +aVm9jp_ttsk_4 elephant +aVm9jp_ttsk_5 elephant +aVm9jp_ttsk_6 elephant +aVm9jp_ttsk_7 elephant +aVm9jp_ttsk_8 elephant +aVo-jvGoUGs_1 boat +aVo-jvGoUGs_0 boat +aVq4ezzbcTc_0 bird +aVvuGEexwy0_1 person +aVy9mhLlo5U_0 umbrella +aV2_0JBmw8o_1 person +aV7mSkydynI_4 bicycle +aV7mSkydynI_1 bicycle +aV7mSkydynI_2 bicycle +aWCNGGW4Qew_0 person +aWDtrDYqivs_0 person +aWQxqFyyzng_0 cow +aWQxqFyyzng_1 cow +aWWMT0webCY_0 person +aWWtWhgt_V0_0 cow +aWYoUCAev64_2 bicycle +aWYoUCAev64_0 bicycle +aWcaF85RIM8_3 elephant +aWgSKxQO5Ps_0 cat +aWi51gAEIkY_0 person +aWma4eTtHv0_0 person +aWqBSBc-XpU_2 knife +aWt13fGkYuA_0 cow +aW9D5rT3GCo_0 bear +aXFFLOGR_yI_0 person +aXFgCWZLFj8_0 horse +aXFgCWZLFj8_5 horse +aXFgCWZLFj8_1 horse +aXKbkyjRqkU_8 bear +aXKbkyjRqkU_0 bear +aXKbkyjRqkU_7 bear +aXOPdDTpvxc_0 person +aXWkAKNw0Dg_0 bird +aXXfrIsIqi0_0 person +aXhd5BhT4hs_0 cow +aXhd5BhT4hs_1 cow +aXml5kCJyDY_0 skateboard +aXml5kCJyDY_2 skateboard +aXn1cwN8vng_0 airplane +aXn1cwN8vng_1 airplane +aXxKLf5m61g_1 person +aXxKLf5m61g_0 person +aXxPxBeZjQI_0 person +aX0JOJY-BDc_0 person +aX0JOJY-BDc_2 person +aYCA7dz0nbI_0 person +aYJzxhE8-Rs_5 knife +aYPCTMucy6A_0 person +aYgA8AxT0V4_0 giraffe +aY1i2TADX0c_0 person +aY1i2TADX0c_1 person +aY1i2TADX0c_2 person +aY4dOYabpbs_0 cow +aY6lI7qO6kI_0 person +aZF83PK7HKU_0 person +aZF83PK7HKU_1 person +aZGZbrCAFl4_0 person +aZGZbrCAFl4_1 person +aZHznZSD2uE_0 person +aZJ_vArnOC0_0 cow +aZL_n-gon0U_0 boat +aZT_v5WnLio_0 person +aZVtxAF_Imw_0 dog +aZZcXyRJwyI_0 person +aZ4tzgju18s_1 train +aZ-3jypmJiY_0 person +aaAAXDB7ml4_0 elephant +aaAAXDB7ml4_1 elephant +aaA_qcyN3eM_1 cow +aaBf3fxpR7E_1 person +aaQjh2_8aVw_1 motorcycle +aaQjh2_8aVw_0 motorcycle +aaUXN-xWi1c_0 person +aaWV0TEIbhM_0 skateboard +aaWV0TEIbhM_2 skateboard +aacFWGARp08_0 person +aacLCDo8Zus_0 umbrella +aacZc8VUtxg_0 bird +aaoYsiVAFDY_0 airplane +aas39xgvbfg_0 cat +aatdoixvb4w_0 dog +aazC6OJV2GY_0 person +aa0jo00Yxz0_2 boat +aa-J6xg9RH4_0 person +abCu1bwDisA_0 umbrella +abHvXnWduQQ_0 person +abQ7YCx3QQM_0 train +abbympAEM_k_0 cow +ablCJGTLCow_1 elephant +ablCJGTLCow_3 elephant +ablCJGTLCow_4 elephant +ablCJGTLCow_0 elephant +able--ZWvkg_1 person +abnCzyC9R28_0 person +abpyt2p-uMg_1 bird +abrKRGgLV0o_0 dog +abrKRGgLV0o_1 dog +abxcR1X4UIo_1 bird +abxuxX4aHFI_1 horse +abxuxX4aHFI_2 horse +ab1RpuefUA0_3 bicycle +ab2b2WA-fQs_1 person +ab2b2WA-fQs_0 person +ab2b2WA-fQs_2 person +acDY2Ono9WA_0 dog +acL58vxHnnc_0 person +acOdf26jldk_0 person +acYxvpS0b7s_2 airplane +acZFDZif1ww_0 train +aciCzrBQsM0_0 person +acnOEnTXwJY_0 cow +acnOEnTXwJY_1 cow +ac4feYMso4k_0 train +ac6NdTBtc6U_1 person +adAkRe99CDA_0 truck +adE0Nk3CKyI_0 car +adKIteGSOIM_1 skateboard +adY8EtfOO_w_0 train +adcv2A70AoA_0 person +adiBUyRiBfo_1 person +adiBUyRiBfo_0 person +adskAqVAdFQ_1 elephant +ad2C17MGAEo_0 bus +ad94BZD75ck_1 cow +aeAjL4rCjIM_1 truck +aeAjL4rCjIM_0 truck +aeIzIOSHZek_0 person +aeJKW7m42xo_2 airplane +aeJKW7m42xo_0 airplane +aeKckIdL0io_0 bird +aeUVIIEtwdw_1 motorcycle +aeUVIIEtwdw_2 motorcycle +aeUVIIEtwdw_3 motorcycle +aeUVIIEtwdw_4 motorcycle +aeboOU_vdjo_0 person +aeboOU_vdjo_1 person +Bc2pPI9s8bM_2 horse +Bc26F0eEyBg_0 person +Bc5QvTVd-04_0 person +Bc64C5jdZDg_0 person +Bc7NXuSycR4_0 skateboard +Bc-b4WhkWxw_0 person +BdBZuvI8oak_0 truck +BdBZuvI8oak_8 truck +BdBZuvI8oak_1 truck +BdBZuvI8oak_2 truck +BdBZuvI8oak_3 truck +BdBZuvI8oak_4 truck +BdBZuvI8oak_7 truck +BdB6NgtqioE_1 bear +BdCnusBWLuw_0 bicycle +BdC5wdGWMCw_0 person +BdLMnBBX7rc_0 person +BdQ8AC4jpkk_0 person +BdR02myBXHY_0 person +BdTRTQRbNqI_1 skateboard +BdT2u0kYx90_0 bicycle +BdT2u0kYx90_1 bicycle +BdT2u0kYx90_2 bicycle +BdT2u0kYx90_4 bicycle +BdZOawocL-c_0 person +BddRmrmaI6M_0 person +Bd0JDJL6yXk_0 airplane +Bd21KrWCyCg_0 cat +Bd-WW1Hs9kk_1 train +BeAD9m4Yu_U_0 person +BeCQkxXRRww_1 person +BeCQkxXRRww_0 person +BeCmkGB-RCw_0 horse +BeQWoctTF5I_0 bear +BeQWoctTF5I_2 bear +BeQupBkL2y8_0 train +BeTu3Ag6XIw_4 bicycle +BeTu3Ag6XIw_1 bicycle +BeVqWRYzPkY_0 knife +Bebzr4dP1Ug_2 person +Bebzr4dP1Ug_0 person +BedgXkpLAOs_0 person +BefMC4f6Z3s_0 person +BefMC4f6Z3s_1 person +Befq3kL0E7o_0 person +Begwn2Da_j8_0 person +BepRWdKn0QA_0 cat +BetAKo6E3rw_0 person +BezlbA5t77I_1 person +Be4NCK9GwQU_0 person +Be4V9lpSpJw_0 knife +BfIBlw1RkXc_1 truck +BfJUkGEnxvE_0 person +BfOXYUOsSf8_0 airplane +BfSxTA9yZak_0 person +BfT3bVAeXLU_2 boat +BfWpLwfDFbc_0 person +BffFognyZOA_1 skateboard +BffFognyZOA_0 skateboard +BfkXvdTkYF4_0 person +BfkXvdTkYF4_1 person +BfwHmAlZdKA_0 person +Bf1cF3BfY18_0 person +BgBDqhuoTr0_0 dog +BgHvkS4H7w0_0 person +BgamGCKlzTI_0 person +BgbxYgCIde8_0 cow +BggPqcJz12g_1 elephant +BgjdCfaJfsE_0 elephant +BglxBESIjlE_0 person +BgsTkbznAjI_0 person +BgwZN0Ui-Q8_0 person +Bg0_DcQLOys_1 knife +Bg3Zox43xGI_0 skateboard +Bg4NtG5QkwM_0 person +Bg_cKljiGGE_2 person +Bg_cKljiGGE_0 person +BhA7KMeJYAE_0 skateboard +BhL184lkUcw_0 person +BhPyQcTHRmg_0 boat +BhXpOqm8Q5o_0 bird +BhZl6ZTtKDo_0 person +Bha-PhOr-bU_0 bird +BhdcIu_nQYs_0 bus +BhqZrCcQpD4_0 elephant +Bh4QFujTqIo_0 train +Bh5wIL7IE9A_0 person +Bh5wIL7IE9A_1 person +BiGYFhnDhMI_0 airplane +BiQ4cYnaGPo_0 person +BiYzQbOwhWY_1 train +BiYzQbOwhWY_2 train +BipPdxUV2PY_3 boat +BirMOPf7k0I_0 knife +BizSBnzOzy0_0 person +BizSBnzOzy0_1 person +Bi1KsDpJT8w_0 person +Bi1KsDpJT8w_1 person +BjGhd-Eq5ig_1 car +BjGhd-Eq5ig_7 car +BjJSECIrsd0_0 dog +BjLJqIPSyUM_0 bicycle +BjQO2ipch-w_1 dog +BjRyA1cPxA4_0 cow +BjZ9JRI_WkM_0 person +BjbCdEHhCjI_0 person +BjfwCDsBoeg_2 bicycle +BjhITTFavAk_0 person +BjiJ7HAaOj8_0 person +Bjj4KdIbDBY_0 person +Bjk2IA4thIE_0 bear +BjogwheL3BI_0 horse +BjpX2nla914_1 car +BjqdFABBqxA_0 person +BjqdFABBqxA_1 person +BjraW0bXW-0_0 person +Bj8lO8Jag3Y_0 person +Bj9wPwHXNQo_1 horse +Bj9wPwHXNQo_2 horse +Bj9wPwHXNQo_3 horse +Bj_fS2abD9o_1 bird +BkFws1J8IM0_0 bird +BkMb48QM-zQ_0 person +Bkco3wJWvp0_0 person +BkdBnU65i7Y_0 person +BkdWJT3sWro_3 airplane +BkdWJT3sWro_4 airplane +BkfKa-zgphc_1 airplane +BklBU6Epydc_4 horse +BklBU6Epydc_1 horse +BkoQ8_W4drM_0 umbrella +BkteTGu81tQ_0 bus +BkwpJBHM_DM_0 dog +Bk3VbRagAwg_0 dog +BlXhR1rRct8_0 bicycle +BlfVNiQZtko_1 cow +BlfVNiQZtko_0 cow +BlhT8WFfI54_0 person +Blj4FY__L6Y_0 person +BllnWV-BIDo_0 bird +BlqsGIq2hNg_0 person +BlqsGIq2hNg_1 person +BlzUBgB6BEc_0 person +Bl-1081HLyM_0 motorcycle +Bl--N1EQpuA_5 airplane +BmCAiO-WNmE_0 skateboard +BmG7dEBuS6s_0 cow +BmHShiZ1Xus_3 airplane +BmNwfiFBeRo_0 person +BmNzw5vNQNI_0 skateboard +BmRZWeMzQLg_3 bicycle +BmRZWeMzQLg_0 bicycle +BmSBpZrrEt8_0 cat +BmXdIzhVZ0Q_2 bear +BmZN0ljGa84_2 motorcycle +BmfHrAPEMrk_2 person +BmfHrAPEMrk_0 person +BmfHrAPEMrk_1 person +BmjBM58PfZE_0 cow +BmjEEjKDJVI_0 person +BmjLZgp38NI_0 cat +Bm3l_RLjYpo_0 motorcycle +Bm3wZ63Ymvo_2 motorcycle +Bm7e-qOAcKQ_0 person +Bm8qAGd91Gg_0 train +BnADRMlWOsM_0 airplane +BnNJUP6xfG8_0 bear +BniJFr7IJRo_1 person +BniJFr7IJRo_0 person +BniJr-iCh9M_1 truck +BnkIFwVPh8w_0 horse +BnkIFwVPh8w_2 horse +BnkIFwVPh8w_4 horse +BnkU89Dq2IQ_0 person +BoA6CUl4t70_0 cow +BoGAxXRzHWs_0 cow +BoLSvTrm3d8_3 cow +BoNtUpvusGM_3 motorcycle +BoNtUpvusGM_4 motorcycle +BoNtUpvusGM_0 motorcycle +BoNtUpvusGM_1 motorcycle +BoNtUpvusGM_2 motorcycle +BoOANS5_U9I_0 motorcycle +BoPj2W_G2Qg_0 airplane +BoYvNfndu60_0 skateboard +BoZ3ZvdEZ4o_0 car +BoZ3ZvdEZ4o_1 car +BoiPpDeQ2mQ_0 airplane +BomNEWAGolQ_0 person +BomVU8_LL_Y_2 dog +Bowyw_fhWZ8_0 person +Boy5toMvMwo_0 giraffe +Bo2qsQNYATk_3 skateboard +Bo5bT8QP_Og_0 person +BpDLFqS9EAE_0 person +BpVyiSvjk4o_1 dog +BpdZmCkSHco_0 giraffe +BpjdKB7AJ8U_0 skateboard +BpkMUQLoJUM_0 person +BpoWgamMMro_0 cow +Bp1zluIhHzc_0 person +Bp4vXfVIVxA_0 skateboard +BqBkvlijWKg_1 person +BqDnDPIE18k_3 horse +BqPcqKW3uAM_0 dog +BqoRxXUz7q4_2 truck +BqpA7iBOQ_s_0 person +BqqPm3F1F_w_0 person +Bq4id5zA48c_2 bear +Bq_emgXftMI_0 person +BrDdbgxB7qI_1 bird +BrHDj1biLlA_0 airplane +BrHDj1biLlA_1 airplane +BrJiBbRF25U_0 person +BrKgWUQnUWI_0 cow +BrQNhzCKfxs_0 person +aelph1Y8yPk_0 skateboard +ae161Zq0QBg_0 skateboard +afCYMTTgbMw_1 dog +afD_y2ZEHn4_0 skateboard +afLO-CD48TI_0 motorcycle +afLO-CD48TI_1 motorcycle +afWl3lTglsw_0 person +afbS6cTlE5Q_0 person +afu5-raaJEc_1 elephant +af9Z_LR-L7M_0 person +af-MtTvmPic_0 person +agFlIZmS0zU_0 person +agF_eyIgF3g_0 person +agGuxSx4UdI_0 motorcycle +agIme93Q6WA_0 person +agMdtESL5kE_2 cow +agSpfpV4EsQ_0 person +agVHBb-qLAw_1 bus +agWS48KnYWk_0 motorcycle +agXPzkjMl4c_0 bird +agYR35aJ1no_0 person +ag1ohTMq9Iw_0 car +ag5Gy7ZNbfw_2 knife +ag5Gy7ZNbfw_3 knife +ag6NY6nrTvw_0 bear +ahE37MgcoUs_0 person +ahMgOG4Bpcw_0 car +ahQD9PpYoqE_1 train +ahYD0J4XzC0_0 cat +aheVwPx1egw_0 truck +ahiO1CwoaY4_0 person +ahnbyNWfvpM_1 cow +ahsHWgQGPNI_0 person +ahv6_xBxvmg_0 person +ah03BOnPUqs_0 cow +ah-2yN1cKOg_0 bus +aiINQVIMx5o_0 person +aiNcNIUbY3E_1 dog +aiX8ymgR1g0_0 boat +aiX8ymgR1g0_3 boat +aierZPItkn8_0 bicycle +aierZPItkn8_1 bicycle +aiiN3X-f5Ss_0 person +aiklFoEJX1Q_0 person +ainWSZibSIM_1 bicycle +aio5SboRXGU_0 person +aio5SboRXGU_1 person +aizJI68M2SY_2 truck +aizJI68M2SY_1 truck +ai1CTuarr50_0 bus +ai3xYb_xvFA_0 person +ai7WTyMnl1g_2 horse +ai7WTyMnl1g_3 person +ai7WTyMnl1g_0 horse +ai7WTyMnl1g_1 horse +ai9-_EMwk4U_0 skateboard +ai_jmsLJTR0_0 person +ajAuKSOFBKQ_2 bus +ajAuKSOFBKQ_3 bus +ajB-QUVDyXI_0 cat +ajO4xx5beuE_1 bicycle +ajPP5EY_nAo_0 person +ajPP5EY_nAo_1 person +ajPY1htweXM_0 person +ajPY1htweXM_1 person +ajtvjEY9TPA_0 airplane +ajxcj5ovYdw_0 skateboard +aj0Ll84jtZs_0 person +aj0Ll84jtZs_1 person +aj3UwQNtZPo_0 train +aj6sqeG0k54_0 umbrella +akH9ouIrOds_0 skateboard +akIlFKpZAtk_0 person +akOLIpAsxqc_1 person +akQU-s0RCWE_1 bus +akoVZ50spRM_0 person +ak6iAVUNU7c_0 dog +ak6iAVUNU7c_2 dog +ak6iAVUNU7c_1 dog +ak89dpHVmHc_1 person +alAFNWeSJts_0 skateboard +alDkqPNUFLU_0 person +alDkqPNUFLU_1 person +alKgZTVxcV4_0 motorcycle +alX9MOY80Aw_0 person +aluZTs_Ys8I_0 car +alvKKzlOBKM_0 person +alzWhOivD0E_0 person +al2Vh0In4HU_0 bear +al2Vh0In4HU_2 bear +al2Vh0In4HU_3 bear +al8Of2FWy80_0 cat +al8vzWgNDbs_2 bicycle +al8vzWgNDbs_7 bicycle +al8vzWgNDbs_8 bicycle +amIvXQ6aZkE_0 cow +amL9Dar_hp0_0 person +amTcWqrgBBg_3 airplane +amjpcHzuYb4_0 person +ams9MCDF15I_1 person +ams9MCDF15I_0 person +amvLPTONS1U_0 cow +am-3XKJkCqg_0 train +anAXVexurxo_2 dog +anJbsuTwShw_0 person +anLTttUpag0_0 skateboard +anR9cuXRv6Q_0 person +anWxwjzPRBA_0 person +anYy3XNTTGw_0 person +anZ9lxr24eY_0 person +angay7OmUwA_0 truck +aniCxSPm8Uc_0 car +anlydfnmv7g_0 person +annQpJsk6NI_0 bus +anpsTMr_HIo_0 cat +anrBShdHOz4_0 person +anvk-OdKLBE_0 person +anvngue8Qh8_0 cat +anzrRzyYAAc_0 dog +an-QcnhNhL4_0 person +an-mFuTYuCk_0 person +an_FRcZ669c_0 person +aoBqV2Guvso_0 person +aoDJu0KrrQs_0 motorcycle +aoOJR-0sPM0_0 person +aoSWWKtf8mU_0 person +aohLKKJxjIM_0 person +aoizdynEVYU_0 dog +aoqMoScEfqE_1 horse +aotBl0tvpFs_0 train +aotBl0tvpFs_1 train +ao9uUinn2WY_1 truck +apKAwFA4oP0_0 bird +apQKmVEucLQ_0 person +apZAEWvk8XY_0 person +apcgot45Ql0_0 person +apdP6_tCdls_0 person +apfZjUpoTy0_0 skateboard +apfZjUpoTy0_1 skateboard +apprUmnQTcI_2 cow +aqGKBg0azPA_0 cow +aqGp6tCGLOU_0 motorcycle +aqKiwfY3Oqc_6 bus +aqKiwfY3Oqc_5 bus +aqKiwfY3Oqc_7 bus +aqNz8TCica4_0 zebra +aqUHuS5ALXE_0 cow +aqWN-Q0wDHI_0 person +aqWN-Q0wDHI_1 person +aqZfqhHJPLo_0 person +aqdSuLpYlwQ_0 person +aqe_mdIg6k0_0 person +aqmie50AFwE_0 dog +aq2UMxzwliQ_0 person +aq50xKvuSFg_0 skateboard +aq59B_-6ilw_0 person +aq9Sfxn9vMg_5 knife +aq-QzG14KJ4_0 person +arFKRc7lAo0_0 person +arFKRc7lAo0_1 person +arPGoY7uh4E_0 person +arS7aqpkAU0_0 motorcycle +arT4jZLX8pg_1 knife +arW0ZUPkah8_0 person +arZ_mIhaJMo_0 cat +are5LvOB2nQ_1 skateboard +are9NykT9FM_0 truck +arn0j0l_IWI_0 person +artWKQTC7CQ_0 person +artcASpzYrU_0 person +arwZ6ZPJuN4_0 cat +ar7TRjurXMY_0 person +ar-fzXT8Juc_0 truck +asT-GJNeJok_0 person +aseOdDcbIRE_2 person +aseOdDcbIRE_0 person +aseOdDcbIRE_1 person +ashHnkqFz7g_0 bicycle +ashHnkqFz7g_3 bicycle +asl-XTE0jsE_0 person +asrDocOfGQE_0 car +asrDocOfGQE_1 car +asrDocOfGQE_3 car +asrDocOfGQE_4 car +asrDocOfGQE_5 car +asrDocOfGQE_6 car +astLiScyoaQ_0 person +asx2CkH0O6I_0 elephant +as1twjKe3Cw_0 skateboard +as6Y3-EaaCg_0 person +as6Y3-EaaCg_1 person +BrgRnN_LBGk_1 person +BrgRnN_LBGk_0 person +BrhMkJ6n-hQ_1 train +BrnBTne3NBw_0 bear +BrnBTne3NBw_1 bear +BroiAN_qtCI_0 person +BrpRmX410DU_0 person +BrrAlsmwDnk_1 person +BrrAlsmwDnk_0 person +Brrlyds8g1A_0 person +BrwABvccCWs_0 person +BrzEfM8nWCw_0 cow +Br3M-xsvXFQ_0 person +Br9CVteHFEc_0 person +BsCH_ABy0WE_0 person +BsRC5xbG6uY_0 person +BsXphFpnOxE_0 bird +BsXwLsR6dm8_0 person +Bsv8dNYzPkY_0 bear +Bs1rRAtP7bw_1 bear +Bs3BPJZMD9E_0 person +Bs94h8vMmwg_0 person +Bs_9E_Rq524_0 person +Bs_9E_Rq524_1 person +BtFwcgeJjsY_0 person +BtKVAhU1LdI_0 knife +BtKl-iqkgoY_0 cat +BtN0FlaISuY_0 person +Bt19SM8BenY_0 person +Bt41QF0ze6E_1 person +Bt7B7nkGO_4_0 truck +Bt7B7nkGO_4_1 truck +BuFYI1vYj1k_1 person +BuH65mVX5yM_0 person +BuPWtDPEJ-0_0 person +BuXvxclES0s_0 bird +Buco16wWyFA_1 motorcycle +Buco16wWyFA_2 motorcycle +Buco16wWyFA_3 motorcycle +Buco16wWyFA_0 motorcycle +BufY7NdKUlM_2 motorcycle +BufY7NdKUlM_4 motorcycle +BunvBFXoGPg_0 bus +BuqljdjPWWc_0 knife +BuqljdjPWWc_1 knife +Buumm7rgDPY_0 person +Bu0gJwoDkRw_0 cat +Bu5Bgr9asUU_0 person +Bu_HdLSyLSI_0 person +Bu_3ep-qAi0_0 person +BvEAIc3hmkk_0 motorcycle +BvHzGHjR6rk_0 person +BvLCgNWIHfA_0 person +BvLJZAhIR3A_1 truck +BvTLdUcIH5I_1 person +BvTbuvBeunI_0 airplane +BvTjf9mG5MU_0 person +BvZ8DqslB-U_1 airplane +BvZ8DqslB-U_2 airplane +BviGbtAujq0_0 truck +BvrORC4d2yg_0 train +BvrORC4d2yg_1 train +Bv4rjfW9RsM_0 dog +Bv9IXbrDYLk_0 bird +BwDccOS7_vw_0 person +BwIoxW7Ee8M_4 train +BwUYR-ZnpX8_0 horse +BwW4Fs1eTRg_0 airplane +BwW4Fs1eTRg_1 airplane +BwergWBqOOs_2 train +BwgJmjOzlRk_0 person +BwoTsoC3hvQ_3 horse +Bwo1MaJvxRs_0 person +Bwrh4q5KLVg_1 dog +BwsHsSpS0dQ_0 bird +Bw2RhmesY5g_0 person +Bw5iwcbP4eM_0 giraffe +Bw6f2OXYtSo_0 cow +BxHIRvoGZMM_0 person +BxMoEE7XwL8_0 person +BxNE34BGZ-4_0 person +BxQp3-SCUGs_0 person +BxQp3-SCUGs_1 person +BxWs9aINEEI_0 person +BxWs9aINEEI_2 person +BxWs9aINEEI_1 person +BxYdU6vB2YQ_1 motorcycle +BxaEaD7zeX4_0 person +BxhktnvjtLA_0 truck +BxmeqCev3Kw_2 boat +BxmeqCev3Kw_3 boat +Bxm3EvRZAI0_0 skateboard +BxvlWueS9vA_0 motorcycle +BxwmNnxcI7o_1 person +BxzVlf9-SLc_14 bicycle +BxzVlf9-SLc_4 bicycle +BxzVlf9-SLc_6 bicycle +BxzVlf9-SLc_8 bicycle +Bx2YQSFETcw_1 person +Bx4ELKBw9PU_0 cow +Bx4ngxnRjvM_0 motorcycle +Bx-is-dL1ko_0 person +Bx_z_4bt8O4_0 person +Bx_z_4bt8O4_1 skateboard +ByBWtiJJNqk_0 person +ByBWtiJJNqk_1 person +ByFCiUvKd4E_0 cow +ByFCiUvKd4E_1 cow +ByFCiUvKd4E_2 cow +ByJNGLp-Q1Q_0 boat +ByRne1VtDow_1 person +ByfeHjkm0NA_0 bus +ByhpLi9sRUs_4 train +ByhpLi9sRUs_5 train +ByhpLi9sRUs_0 train +Byn2Qo7ghaQ_1 person +ByvWskJDMGg_0 airplane +ByvW2VADH6w_0 motorcycle +By1cSo8DcUw_0 bicycle +By8jq7bVrkw_0 person +BzKADkfj5sM_0 cow +BzNlO4ccRRY_0 person +BzOo01dGJkw_0 person +BzT8xDTB14c_2 truck +BzWiQPw-vQc_0 person +BzX2DmrGvp0_0 train +BzeW7KdQ818_0 skateboard +BzeW7KdQ818_1 skateboard +Bzehenf5vSI_0 airplane +BzgqI8VBlSE_0 person +BzpY-JMNW4c_0 person +BzrM5QG9q2o_0 train +Bzr3gVS8SzI_1 boat +Bz5rpBZ1dzs_0 person +Bz7A9QxD1nY_0 knife +Bz9MqNlU7KM_0 person +B0AazXeFQIU_0 person +B0BXcxFMgrk_0 knife +B0EZ9LIObGc_1 motorcycle +B0FupWyYbG8_1 person +B0NJSrhuWwA_1 person +B0NJSrhuWwA_0 person +B0QFrtXczzE_0 person +B0SYog80Y78_0 person +B0WaLst2GGg_1 person +B0YrdZ7s3UY_1 person +B0YrdZ7s3UY_2 person +B0aFuZP3nYE_0 person +B0aFuZP3nYE_1 person +B01lwUoyl90_0 person +B03gLj0lJrk_0 horse +B0-L6VbxLcU_0 cat +B0-lAJ4tBN4_0 train +B0-lAJ4tBN4_1 train +B1IQyTNE7eg_0 skateboard +B1Ojfucympw_0 person +B1Ojfucympw_1 person +B1YzUGPZQWo_0 train +B1hkAet1OQI_0 person +B1isEeljBFI_0 person +B1pC6hfF_Do_0 person +B1qSE-7JgXE_0 person +B1yiSrv4Ocw_1 horse +B1zPD20nhTg_0 person +B12C84by_eA_0 person +B12C84by_eA_3 elephant +B12C84by_eA_1 person +B12C84by_eA_2 person +B12C84by_eA_4 person +B12C84by_eA_5 person +B12C84by_eA_7 person +B12C84by_eA_10 person +B12C84by_eA_11 person +B2EMVGU5pNA_4 train +B2VryVb5p54_0 horse +B2VryVb5p54_2 cow +B2V7kk7fqSc_0 person +B2X9JzMNZb0_0 person +B2ZpqEJpVX0_0 person +B2fTIk9eCNc_1 elephant +B2gJVve4I58_0 person +B2hKNbDmBtM_0 cat +B2lAxi3jIR0_0 person +B2lAxi3jIR0_1 person +B2lAxi3jIR0_2 person +B2xcdU4Qoz8_0 bicycle +B2xcdU4Qoz8_12 bicycle +B23TpirETNE_0 horse +B26AQtx7Xic_0 person +B3HZSrALQYc_0 skateboard +B3IjPORG3_w_1 bird +B3J2umsYK7E_0 person +B3QykPv8TnI_0 person +B3X5wDENAUw_0 cat +B3kTu0B4OjM_0 person +B32uNSxqzgs_0 cow +B33seWCiea4_1 person +B33seWCiea4_0 person +B4Q6pRC_mZ8_0 bicycle +B4Q6pRC_mZ8_1 bicycle +B4Srj2O1AWQ_0 cow +B4dFepwxEOU_0 person +B4iP6lAoNYo_0 person +B4jbThMFW00_0 person +B4mWkc8-_6A_0 bird +B4oO-miJ6VU_0 umbrella +B4vM2iKb8cs_0 person +B4_mRuPC7o0_0 person +B5BNEoIaQL4_0 person +B5GwJoM3aX8_0 person +B5NgN9mocgI_0 person +B5PHI2HVtuc_0 person +B5fv91yB4Gw_0 bicycle +B5qSvRpXLS8_0 cat +as7rVUFzyzg_0 skateboard +as_Rz9F3slw_0 cat +atA-Cgv2XHY_0 person +atE1O6J4Wls_0 person +atLGWZUbEuM_1 train +atMjLEIbsBI_0 cow +atxnLL4Vjuo_0 person +at2dmAEDdmg_1 person +at4pXKjEDic_0 person +at4pXKjEDic_1 person +at5edW3lMVA_0 person +auA-q9fWwn4_0 elephant +auDJ1xtxFlw_0 person +auDJ1xtxFlw_1 person +auFLAZb-gD8_4 truck +auGyhsy8iLA_0 cow +auNciV4eLVo_0 bus +auOl1mbGUlk_0 bicycle +auOo1Lg_wvU_0 dog +aubLDLbxxsk_0 person +aueT5WO4e_c_0 giraffe +aueT5WO4e_c_1 giraffe +augKp60fa5Q_1 car +auiPa0HNOEQ_0 person +auu_tYb3G1Y_0 person +auzy4oPzM5Q_0 motorcycle +avCqOSeS7WU_0 person +avC67gaD1NM_0 cat +avHbY1Q3vyw_1 elephant +avLxYBedm_c_1 elephant +avT7Q6Wibdg_0 person +avl9d-bL57Q_0 airplane +avl9d-bL57Q_1 airplane +avob12vGzmU_0 horse +avonCFmxPyg_0 person +avonCFmxPyg_1 person +avpWY3czerE_1 car +avpf9VVT6CU_0 motorcycle +avvQ5wNPiew_1 person +av475qBV4QY_0 skateboard +awC9zxAeP54_0 person +awQ1n9aQEco_0 person +awVBieSP5Zw_0 person +awVa7pqR9DU_0 horse +awfg9NsCVQ0_0 person +awjHSQ5uPi4_0 bus +awkpYVN-fJw_1 horse +awmHGFkxxlw_0 person +awwWMuOKe3c_0 person +aw059qHbVm0_0 bus +aw2lOvXUAPg_0 truck +aw5C9nQgLcA_0 person +axB1Gk85UtQ_0 person +axEK7nZ8W3I_0 person +axJZ92uWnkA_0 person +axXs2oUd4ow_0 bear +axcDoOd0G0s_0 truck +axjSgDsN6t8_0 horse +axltu5Qf6ok_0 skateboard +axn6QuPBPqA_0 person +axulii3UXSQ_1 person +axulii3UXSQ_0 person +ax4YUE-PcF8_0 airplane +ax4YUE-PcF8_2 airplane +ayD3RJIjplM_0 dog +ayRmnUb2LAI_0 airplane +ayax5k3PJMs_0 person +aybdlOdul0U_1 person +aybdlOdul0U_0 person +aydxF0r6n9s_0 person +aydxF0r6n9s_1 person +ayg0x1glF2s_2 horse +ayg0x1glF2s_0 horse +ayg0x1glF2s_1 horse +aylBB_8cv60_0 umbrella +aysqPEtZvsg_0 person +ayuF_8chcKM_0 person +aywW_Wvo49w_0 person +ayzzG8M0fzo_1 person +ay1d8NBbrl0_2 bird +ay1d8NBbrl0_3 bird +ay5RnrQple4_0 train +ay5tx1Rovwk_0 cat +ay7LLDO9Ecc_0 dog +azC7-_wC8N8_0 bus +azDn4DU7cGA_0 person +azKKcIb4Ufw_1 boat +azOInI_CMHM_0 bus +azbls7-iaEU_0 person +azbls7-iaEU_1 person +azbls7-iaEU_2 person +azfLb8VvI-4_0 person +azfLb8VvI-4_1 person +azfLb8VvI-4_2 person +azlRI_Jydpw_4 cow +azmZDijLihI_0 person +azmZDijLihI_1 person +a0FDxoXtFyM_1 airplane +a0NOwUio_n8_1 person +a0NOwUio_n8_2 person +a0NdjlW5H_U_0 cow +a0N_vetshbg_0 person +a0N_vetshbg_1 person +a0OjB7xzRx4_0 person +a0RusP9ATfw_0 person +a0dHPtoBS3U_0 person +a0hRgBpppWs_0 person +a0jpiOFS7eM_0 bear +a0oeBV6-20U_0 person +a0uoJdAwobA_0 person +a085oeXd0RE_0 person +a0-Pmmyi8js_1 person +a1ADw1megCI_1 airplane +a1Fzn7iUHO8_1 motorcycle +a1RVXQl4rlY_1 cat +a1RinDI9Hgw_2 knife +a1SaKvoO2Og_0 cow +a1U6U_pntMo_0 person +a1XDxiP1hNA_0 person +a1ctjjNUZ-4_0 dog +a1kLNA-KACs_1 bicycle +a1lQwuhicQI_0 person +a1lQwuhicQI_1 person +a14VlgxHS3M_0 person +a2AT0Xo7uLY_0 person +a2Osa5aleJ0_1 bus +a2Qp2Grx3_8_0 person +a2XMK6mjiZg_0 dog +a2XvXs2guuE_1 person +a2XvXs2guuE_0 person +a2fEq8oS3M8_0 bus +a2gYRtJhP1E_0 horse +a2gYRtJhP1E_1 horse +a2hv4szlq-Q_0 train +a2kH2_9zoWU_0 airplane +a2o_-GSpXXk_0 cat +a2qmS6AhUYk_0 motorcycle +a2vx_F1NOas_0 person +a26mRIQUPoU_0 dog +a26mRIQUPoU_1 dog +a26mRIQUPoU_2 dog +a27UC8vu1hI_1 truck +a29AS00WJrY_0 cow +a3AIwQnG0Ek_0 cow +a3FLLhQu768_0 person +a3THrQYDkqw_1 bird +a3UCtF8nZIY_1 skateboard +a3dbdHben-o_0 elephant +a3dbdHben-o_3 elephant +a3dbdHben-o_9 elephant +a3dbdHben-o_1 elephant +a3dbdHben-o_2 elephant +a3dbdHben-o_4 elephant +a3dbdHben-o_6 elephant +a3rGEI8MdMs_0 cow +a3uvEIsI1no_2 person +a32oJ0GsAYw_0 person +a35UuVw16Ks_0 person +a37D3FoqIJA_1 knife +a3-oi7T-Lw0_1 zebra +a3-tURw95Xo_2 person +a4IU4va7hp0_1 truck +a4LYVAPbEwI_0 motorcycle +a4LaeeZXIc0_2 skateboard +a4Nt5QxFqmY_1 boat +a4PwZfJZVPA_2 bear +a4arqJgXHDA_0 person +a4pR_YBd4yY_1 bicycle +a4uNoGpllg4_3 bear +a4v1ptMpyi0_0 cow +a4v1ptMpyi0_3 cow +a41TZwhyyP0_0 cow +a46BqT5Mo5I_0 cow +a5HZnFcvdyA_1 horse +a5P8pVrcSRk_0 motorcycle +a5brvs-fct0_0 person +a5tSaF5GCKE_1 cat +a5ye5BUJFlY_1 person +a5znd3aNwLk_3 bicycle +a58tMy0mhIk_0 person +a6G_DBEFdFA_0 horse +a6ZXi7Qqls0_0 person +a6fBYYEgBvs_0 dog +a6jDeIJbF7Q_0 person +a6uyjrBkkXs_0 boat +a61piN6ffE4_0 person +a67zz0CSEpk_0 person +a67zz0CSEpk_1 person +a7B81Zeqgfw_2 truck +a7HKuyv2qLQ_0 elephant +a7HKuyv2qLQ_1 elephant +a7Q6eb6feT8_0 person +a7S9rFNKVMI_7 motorcycle +a7Zr0-1LIPc_1 dog +a7hwm4TORvY_0 person +a7pC7IjO2ik_0 truck +a7peWR4xJwQ_1 cow +a7ygZsaDMis_0 person +B5_Hyk-p7kE_0 cat +B6E15pe4UR8_0 horse +B6LGwD1E9SQ_1 person +B6P8B8BO-6U_0 giraffe +B6SaDYczlDQ_1 person +B6U92N9hh6k_2 horse +B6V4xqX67OA_0 truck +B6bDVhRNw00_0 airplane +B6cEdaWTjeU_0 person +B6dBkoOhfBU_0 car +B6lU93wtaDA_1 boat +B6mP9KsnQPc_1 bear +B6mngUQtFJ4_0 cow +B6nlTJYtmws_0 cow +B6pXMjH4geU_3 boat +B6qshzfLYzs_0 person +B6x2dNbgPjM_0 cow +B6y439-imys_0 person +B6z7eCsgfM0_0 bear +B61Wf8NFvcU_0 airplane +B645r0hkdmg_0 person +B645r0hkdmg_1 person +B67FwwZfIEA_0 person +B6_IcyhOHpE_0 person +B7BjhnnQ2K4_0 person +B7GRNv2opSY_0 bird +B7MHQOUO4f8_0 umbrella +B7Z9UV6aQuM_0 bird +B7a8WkaWmH4_0 person +B7a8WkaWmH4_1 person +B7cXCz7jJKQ_0 cow +B7gX18_mDyQ_0 person +B7hmqrwe88o_1 elephant +B7hmqrwe88o_2 elephant +B7iAvi5riV8_0 motorcycle +B7nwfSMbEL8_0 cow +B7pEEUJ-J1g_1 motorcycle +B7rCxgg3F_s_0 train +B8Bp9yKWV9c_0 person +B8D4fPARFvo_0 person +B8HQglK444U_2 airplane +B8HQglK444U_0 airplane +B8HQglK444U_4 airplane +B8LGL1Tt_wg_0 person +B8MxJKDkvkE_0 person +B8eeoykmq1E_1 person +B8eeoykmq1E_2 person +B8f7NnYq5sg_0 person +B8f7NnYq5sg_1 person +B8sWL2syyA8_0 person +B8uIyRkm9YA_0 airplane +B8zGkBkQw4c_0 person +B87W__RIE-E_0 person +B8_Z7m50I_E_0 motorcycle +B9AXF91pIUs_0 airplane +B9Ed_vAN9mc_0 dog +B9Y_LrDVbg4_0 person +B9aqDsvGy5Q_0 person +B9aqDsvGy5Q_1 person +B9j233QxEuQ_0 person +B9oJSA_NJ2s_0 bicycle +B9z17FOPd5A_0 person +B99mIPKaChY_3 cow +B-CR7vl67W8_0 person +B-QiQvJcSVk_0 person +B-T1YNe09SU_4 bear +B-T1YNe09SU_3 bear +B-bDxAN93a4_0 airplane +B-dlnlRKA5s_2 airplane +B-dlnlRKA5s_7 airplane +B-tukWZbXp8_0 person +B-wJpt4zl0c_0 person +B-x2pu-ux3w_0 horse +B-z1uE4iuz4_0 truck +B-0WNs2QYPk_1 elephant +B-48lEXzIS8_0 umbrella +B-7cqxw95Ro_0 person +B_BqrY2eeCY_0 motorcycle +B_Gjc7J18qg_1 person +B_Gjc7J18qg_0 person +B_M6X41emhY_0 person +B_O8idmfoCQ_0 person +B_Tj79jaRXs_1 person +B_Tmq51dx1g_0 person +B_jGC2tlhRo_0 person +B_k6vEEPHK0_0 person +B_lEJv31TlI_1 person +B_lEJv31TlI_2 person +B_nZdcreecE_0 person +B_wWPH9kbxM_0 person +B_ylVg-TN2Q_0 skateboard +B_4Kfa8_9ms_0 person +B_4eJYakoRY_0 motorcycle +CAEqRvJLY-M_1 motorcycle +CAe1SZKZ9T0_1 car +CAq4CxCpeQE_0 cat +CA4UqnJCs58_0 motorcycle +CA9SLI7TOKQ_0 person +CBASqWyp4yk_0 person +CBJQ5dL6Df8_2 horse +CBNqNe7G-QQ_0 person +CBnYDFRfYgo_1 bus +CBqyVKttAwU_0 cow +CBtgGOzZtLQ_0 person +CBz3ZOrTAjI_0 elephant +CBz3ZOrTAjI_2 elephant +CCAsEc2oRAM_0 elephant +CCGg17i4vMU_0 person +CCHay2RSnJI_0 skateboard +CCHay2RSnJI_1 skateboard +CCLRdGNDgdc_0 cat +CCoGim--jEg_0 train +CCp6NLBil8k_0 bicycle +CCwovjgEx1k_0 person +CCwovjgEx1k_1 person +CC0aX78fQFo_0 cat +CC-qoxEyocI_0 person +CDCLLCkr87I_0 cow +CDY4TXCreQ0_0 person +CDbWYF89944_0 person +CDb6uyrYrZA_0 car +CDfjcWI7iBQ_0 boat +CDgBHxiVkFw_0 truck +CDnrG74PXbI_0 person +CDpQZEjohRc_1 cow +CDpQZEjohRc_0 cow +CDrU-q6QdEs_0 person +CD0cWR7d9yI_0 person +CD4SGfIdfSg_3 elephant +CEDTshbJOaI_0 person +CEJoHSbb4gg_0 person +CEJoHSbb4gg_1 person +CEMCCDAYzQs_0 person +CENd4xI4dnY_0 person +CETUG_G0I4k_0 cow +CETUG_G0I4k_1 cow +CETUG_G0I4k_2 cow +CEUjuyvgrB0_0 person +CEUqqi8y4sg_0 cat +CEVHrP5OzJ0_1 knife +CEafe_JTk8g_0 knife +CEqA0cqMfzg_1 cow +CEsjzJHOUBw_0 dog +CEzWiyTQOMA_0 truck +CE1gHqc8aqU_0 person +CE3KdY0X0QE_1 person +CFD0NOl12CA_1 train +CFD6d4OweGQ_3 motorcycle +CFD6d4OweGQ_1 motorcycle +CFD6d4OweGQ_2 motorcycle +CFD-UQW1aQU_1 car +CFD-UQW1aQU_2 car +CFRsGLeMJKc_0 person +CFXkKgig7Io_0 person +CFee6F2rbjc_1 bird +CFxObg2ebKQ_0 airplane +CFxObg2ebKQ_1 airplane +CF0JmXACTww_0 person +CF01UBuV76Q_0 person +CF7DZCaSqIg_0 bird +CF7DZCaSqIg_1 bird +CF7KYbTChlg_0 person +CF71f3YLQ9U_1 person +CF-cX0etaAw_1 cat +CF_NSKkrwjg_0 person +CGCNTZsml7Y_0 cow +CGQoaYTzfaU_0 train +CGQoaYTzfaU_5 train +CGQoaYTzfaU_7 train +CGgxp3ycSWs_0 elephant +CGoqd4n_qJg_0 person +CGsUTzKzV4U_1 train +CGwrXZ2fUqg_0 person +CGy0nn1MCqY_0 person +CGy0nn1MCqY_1 person +CG1sXlDy2Yg_4 horse +CG1sXlDy2Yg_5 horse +CHH1SlvOzfI_0 person +CHIVYSnFst8_1 bear +CHJFpAcH8NM_8 bicycle +CHMzSMq0ui4_0 skateboard +CHZU6sP-loU_0 person +CHZU6sP-loU_1 person +CHbhzxurZNM_1 person +CHbhzxurZNM_0 person +CHnWGkGAnos_0 person +CHo3jSv3HIA_0 train +CHwNoZ55z6c_0 cat +CH6ptLNxppU_0 person +CH8zCsamj44_0 person +CH-_pvq3am4_0 person +CIJ-q_X_y7E_0 person +CIKrCLz06-4_0 cat +CIQLvytEu6E_0 person +CIQz5we_nHI_0 person +CITgpk4GyMA_0 bear +CITgpk4GyMA_9 bear +CIV_VaLTf5c_0 motorcycle +CIc1KbOeijU_0 person +CIgzZOf3uA0_0 person +CIgzZOf3uA0_1 person +CIlb5C929mc_0 knife +CImmRnndBuo_0 person +CItr4F49wO4_0 person +CIxs-77bPrM_1 person +CI2GrLRwQR4_0 person +CI3rFXxUPtI_0 bird +CI6fYr7IJJM_0 person +CI_9TEXzQE8_0 person +CJD7b_dMrVE_0 person +CJG8ou9QuY0_0 person +CJIpdb7wZEc_0 person +CJNAMf-R_J4_0 truck +CJNj2wqp8QU_0 bear +CJOJBhvHmCE_0 person +a79_ETe4ego_0 person +a7_ixAbhsRI_0 elephant +a8MHgXPiRZU_0 person +a8as0DkifS0_0 person +a8eQTqlG-6o_0 person +a8insUA82jQ_1 dog +a8insUA82jQ_2 dog +a8insUA82jQ_3 dog +a8r9Xss8Es0_0 person +a8wT4T21reQ_0 person +a8z4RhTT02c_0 horse +a82uXl_fE7A_2 cow +a82uXl_fE7A_3 cow +a892r_pD5PM_0 person +a9FI5hfZsG0_0 boat +a9GBRb_g82o_1 bicycle +a9GBRb_g82o_2 bicycle +a9YciDJw4wo_0 dog +a9Y2Jm4-FDM_0 person +a9ZvcKL6lEg_0 person +a9fG2p2YO7k_0 bus +a9fG2p2YO7k_2 bus +a9g4dt8Lszw_0 person +a9g4dt8Lszw_1 person +a9riNB4_uhk_0 horse +a90AssqciQk_1 elephant +a90AssqciQk_2 elephant +a-EIC5v0X4o_0 dog +a-EIC5v0X4o_1 dog +a-MNXAJ2mZo_0 person +a-NocjWzZtY_2 person +a-QTXZfMMT4_0 person +a-ZWAMyDG3o_0 person +a-iJ2J3oI-A_0 person +a-lm-MyKchM_0 cow +a-s461-Ddxc_0 skateboard +a-u5tm8bZnc_0 horse +a-yRjCC5TTM_0 horse +a-1bMCU5aj8_0 motorcycle +a-8RK3OMAOo_0 skateboard +a-8RK3OMAOo_1 skateboard +a_KVzTF1RIA_0 person +a_KZ5mevNfs_0 bear +a_OkB8q7LMc_1 person +a_SryCna8Rk_0 person +a_UjbYab9UM_0 train +a_YIQ1VvpcU_0 person +a_YIQ1VvpcU_1 person +a_gLFD5d04A_0 person +a_wdiSqtOK4_0 airplane +a_xkGO87GsU_0 skateboard +a_1zKb6B-bs_0 person +a_6uxh_4kb8_0 person +a_-WUUfn_l4_0 person +a__R_Y49D54_0 person +bALr5X95BQ8_1 person +bAMbXytHB7Y_0 person +bAMbXytHB7Y_1 person +bAdtKFYWQcE_0 person +bAfpD53Vjic_0 horse +bAinSo2I3HI_0 person +bAinSo2I3HI_1 person +bAp653-8UZI_0 person +bAtWugkhW88_0 bus +bAutb-z3rvw_0 cow +bAwVg4MVWds_1 elephant +bAwVg4MVWds_0 elephant +bAwVg4MVWds_5 elephant +bAwVg4MVWds_9 elephant +bAwVg4MVWds_10 elephant +bAwVg4MVWds_11 elephant +bA2bnjEnbus_0 person +bA4v5gLC700_0 person +bA5elX54rTQ_0 cat +bA6JRlAu2yE_0 person +bA8lz4kTY-0_0 bicycle +bA8lz4kTY-0_3 bicycle +bA8lz4kTY-0_5 bicycle +bA8lz4kTY-0_6 bicycle +bA_NwRpP6Tw_0 person +bA_6OElyKFo_0 train +bBPPJNf59kQ_0 umbrella +bBT4o_qtgWU_0 person +bBgRYIPlqAQ_0 person +bBm9VYnMO9g_0 bird +bBt5A6pwnxY_0 person +bB1rIuXXQFA_1 bus +bB4Xm1LS9CI_0 dog +bB6PWM19eMo_0 person +bCB5mMgiGnk_0 person +bCRN4AZbr6o_0 train +bCbqiJ6Ales_0 person +bCuWk5NSB0k_0 person +bCuWk5NSB0k_1 person +bCuuL9wxM7E_0 person +bCuuL9wxM7E_1 person +bCvbst3iM94_0 motorcycle +bCwUgQIL5cE_0 knife +bCx54wbopXs_1 horse +bDBjT69DcT4_0 cow +bDEPo_ZJ8BY_0 truck +bDJyFQqK69A_0 person +bDOeksOYoHc_0 truck +bDOeksOYoHc_1 truck +bDOeksOYoHc_2 truck +bDOeksOYoHc_3 truck +bDO5jSIN9C4_0 person +bDZrANNzYZY_0 skateboard +bDaTeoyWI4g_0 train +bDcapf9qqwU_0 person +bDjiXPhFyUA_0 person +bDu9DwJEoHs_0 cow +bDu9DwJEoHs_1 cow +bDu9DwJEoHs_2 cow +bDxvHkJLr2M_0 bus +bD9LGwYECDw_0 cat +bD-NwifgK0w_1 skateboard +bEDI6tCMZXU_0 person +bEIh6sX-Tl4_0 person +bEKdkY9RBEY_0 person +bEM1_c0lvzs_0 bear +bEOBKFTwR2Q_0 giraffe +bETxZfOvyHY_3 bear +bEUZ0kW5UxE_1 person +bEawSJKPt-Q_0 person +bEhFibV8au4_0 person +bEqXwB3xaWk_0 person +bErIbiSkE10_0 skateboard +bEwALd1GaT4_0 bicycle +bEzk1Y4QUKs_0 bus +bE2p5KejqaA_0 person +bE54N9ho-us_0 elephant +bE9RuKWeuuo_0 person +bE--xARlZGI_1 bird +bFA9McooYzo_0 car +bFCSt5rQdmU_0 person +bFEO4MHzBto_0 person +bFIAwyZ6uuE_2 person +bFIAwyZ6uuE_0 person +bFIAwyZ6uuE_1 person +bFNUtoXNMlQ_0 bus +bFORQXIUbxA_0 person +bFXutLP--Cw_0 cow +bFXutLP--Cw_1 cow +bFXutLP--Cw_2 cow +bFXutLP--Cw_3 cow +bFYfbtcZvsM_1 horse +bFe5fer15nk_1 bus +bFm95kiEE_Q_0 bicycle +bFnZbMhDMQ8_0 person +bFrVmI5XvFw_0 person +bF2D0pMJqLQ_1 knife +bF65L0Tc9w8_0 person +bF8lUYDQNgc_0 person +bGCRyP03o54_1 skateboard +bGFqTDkSuTA_1 bird +bGMKF81Sy6c_0 person +bGcugFPOZ98_0 person +bGeFOznVAdA_0 elephant +bGmggiJ7Hrk_2 boat +bGpuuVQyMOY_0 person +bGsY4wldptk_1 horse +bGsY4wldptk_0 horse +bGyLNR-ZWRY_1 cat +bG7btkvllWc_0 skateboard +bG9Q1zv6YZ4_1 person +bG-X3irBEO0_0 person +bHALJVsPIWo_0 person +bHBuapxTSS0_0 person +bHB5zkcU4DY_0 person +bHO746jxL2Y_0 skateboard +bHP9bh7-qNQ_0 truck +bHWmtSkc1qY_0 person +bHWmtSkc1qY_1 person +bHbgFvCFkb0_0 horse +bHcNLuPTrTk_0 person +bHcbcNIxs_o_0 knife +bHdxB4LnmGY_2 motorcycle +bHdxB4LnmGY_0 motorcycle +bHdypdEXRYY_0 skateboard +bHim6VG9R7E_1 boat +bHoVPJGd7EU_1 truck +bHoVPJGd7EU_2 truck +bHoVPJGd7EU_3 truck +bHvVd9-u80E_0 person +bH5d5crxmiw_0 cat +bIFUXEvQb_4_0 truck +bIFUXEvQb_4_1 truck +bIV7YZEPqTo_0 person +bIiV4e5w280_0 person +bInwFKVbP2c_0 person +bIqcbjzOQ0Y_0 car +bIslKUiw6YQ_4 airplane +bIslKUiw6YQ_0 airplane +bIyfjvesRuY_0 boat +bIzzvd9q2po_0 cow +bI19pnS1D7Q_0 motorcycle +bI8htXUqQkI_0 cat +bJADjJacbIY_1 person +bJAxqtGR-MY_0 person +bJBnGIqBiuw_0 horse +bJDJ5yePi6M_0 person +bJITjrxz5Ns_0 person +bJI1844s-tU_0 horse +bJKrgOW0nMk_0 person +bJMS4sT7XRo_5 horse +bJMS4sT7XRo_6 horse +bJMS4sT7XRo_8 horse +bJMS4sT7XRo_9 horse +bJMS4sT7XRo_0 horse +bJMS4sT7XRo_1 horse +bJWTtXkyZHg_0 person +bJcrA1AOfI4_2 train +bJcrA1AOfI4_3 train +bJfHVvueTbo_0 person +bJh3iPv6jYc_0 cow +bJqhWaDN0hQ_1 dog +bJ0SdP6bjnQ_0 person +bJ24-WqB1xs_0 person +bJ6hIJWstDo_0 truck +bJ6-RBgHmRU_0 person +bJ8k9v22vJA_0 person +bKBLXhOMUi8_0 dog +bKCfbZIUSZI_0 person +bKCjZrT7jIY_0 truck +CJfXDO8EqQ4_0 person +CJfXDO8EqQ4_1 person +CJm40KxFN5E_1 person +CJm40KxFN5E_0 person +CJqFjtBvN9Y_0 skateboard +CJqHpmU9iSk_2 person +CJqHpmU9iSk_0 person +CJrxPkQa2GE_1 train +CJ0sXsga9bM_0 bus +CJ35smVDZW0_0 person +CJ4qgeMiaOQ_0 airplane +CJ6n8mmO1b4_0 cat +CKB_--5AbfU_0 train +CKC6BopJKyk_0 person +CKGpdOkI6P4_0 person +CKNmSha1fz0_0 person +CKQHLTDcKyk_1 bird +CKSN1SlM9ug_0 cat +CKZ1xRX4dh8_4 knife +CKcBs841bV0_0 person +CKhADB_ssaI_0 elephant +CKjQxzl__Fw_0 bicycle +CKkp1wLGtks_0 person +CKmTbQn6J9U_1 person +CKsvfQdlYfo_0 person +CKuBMM3fZ84_0 airplane +CKxmvXSrPIg_0 bicycle +CKzh_WuJFng_0 person +CK29cIxMNP0_0 person +CK39c3vr6gc_0 skateboard +CLAjvvAM-K4_0 person +CLB6UiAOkP0_1 bus +CLMUcOgZdNQ_2 cow +CLQOTITDBeo_0 person +CLXlbsB7sLY_0 person +CLdyznsISW8_2 car +CLosaFzMFeI_1 person +CLzV3TNXkFo_0 person +CL1Bt58elWc_1 person +CL1Bt58elWc_0 person +CL1z2IBwWkA_0 person +CL1z2IBwWkA_1 person +CL4fc23TpVo_0 person +CL5zmQikk-A_0 person +CMBw6j8-QzY_0 person +CMBw6j8-QzY_1 person +CMIMzbsGXk8_0 bus +CMLOYaDEQ9g_0 person +CMMGX4SFyIs_2 person +CMOEwqoxxwo_0 person +CMP-dHylUas_1 person +CMlE5HjD19w_0 truck +CMlNU8W7Lsk_0 cow +CMrJ3Hog9z4_0 elephant +CMrJ3Hog9z4_1 elephant +CMrJ3Hog9z4_2 elephant +CMsMnTwn9o8_1 truck +CMwy_JpVNwc_3 bird +CMwy_JpVNwc_1 bird +CMwy_JpVNwc_2 bird +CNDd5De0h98_0 person +CNEdjudh1lE_0 person +CNID7GMZCtU_1 horse +CNiuz-9TxDo_0 person +CNqKVUmynPk_0 airplane +CNt_itMBqgs_0 person +CNua3gOk0oM_0 bus +CNwRXN4wSAk_0 knife +CN6-VQgDfe4_0 person +CN8AktLgwN8_0 giraffe +CN8AktLgwN8_6 elephant +COAed-b3LTY_0 person +COFcQrVSFcc_0 person +COTylrR16zU_1 boat +COc8fmI9wQ4_0 horse +COh7aoqTWjY_0 elephant +COj_p56dMLI_0 motorcycle +COksm121JZ0_0 train +COxq73j4_rY_0 person +COyU6vUfxXQ_1 person +COyU6vUfxXQ_0 person +CO2cK7r8MNQ_0 person +CO33VpWw45s_0 skateboard +CO_0l5Z12kw_0 cat +CPManZ0i9vw_0 truck +CPN9sc_XrbM_0 elephant +CPOp_zZsQJk_0 cow +CPQXOFjv2LM_0 person +CPXyJXYL8yY_0 motorcycle +CPXyJXYL8yY_4 motorcycle +CPYxpWVVj_M_0 cow +CPZSesZALiI_1 cat +CPuy90LHgrc_0 bus +CP3cZfEx36E_2 bear +CP3u7XjYteQ_1 person +CP3u7XjYteQ_0 person +CQEjDKzTc3Y_2 person +CQE_vEzLzMQ_0 person +CQPAMu_3qwY_0 bear +CQUUCXr0Idg_0 person +CQU9LkJ1PlA_0 person +CQU9LkJ1PlA_1 person +CQbUivUBlJ8_1 bear +CQbUivUBlJ8_3 bear +CQihoSP1KLM_0 person +CQite5jXihw_2 person +CQlL5sCIaM4_2 train +CQlL5sCIaM4_0 train +CQlL5sCIaM4_1 train +CQmCFDEszdc_0 cat +CQyxRGB9-_o_1 elephant +CQzQkumb_iw_0 person +CQ0hdku_Mu0_3 elephant +CQ0hdku_Mu0_4 elephant +CQ0hdku_Mu0_6 elephant +CQ0hdku_Mu0_8 elephant +CQ0hdku_Mu0_11 elephant +CQ2pa82Muc4_0 person +CRGhEOLOPLw_0 bus +CRHfpplogUY_2 car +CRHfpplogUY_1 car +CRPfcUOT10Q_0 train +CRQ8kzUgpGE_0 cat +CRS3P9ePDug_8 train +CRS3P9ePDug_0 train +CRS3P9ePDug_4 train +CRS3P9ePDug_7 train +CRS3P9ePDug_9 train +CRS3P9ePDug_1 train +CRYLa0UnCJY_0 dog +CRZQQc-7Cr4_0 person +CRZQQc-7Cr4_1 person +CRcL9sc8Z_Q_0 person +CRihNgUldQg_0 person +CRpG5Auclh4_0 train +CRscoQhOT24_0 elephant +CRteSMMhdfo_1 person +CR2Qbth78ug_0 person +CR7gNMR7aFk_0 person +CSBnYbN-fwQ_0 person +CSBnYbN-fwQ_1 person +CSCN35ZL4gk_0 person +CSCmLaLpgec_1 train +CSGkGWkJnIo_0 person +CSKOzx-8MRM_0 person +CSKhQtYbLiY_0 person +CSTEfDaVq_w_3 horse +CSgIyZrF2Xw_6 bear +CShE1WLp4V4_0 person +CSlYtyS3ekI_0 cat +CStjlkpuH8I_0 knife +CSwiprmAnWk_0 person +CS4LhFaTdRc_1 person +CS4TVHuh-OI_1 person +CS4TVHuh-OI_0 person +CTBCSXpoCNw_0 knife +CTGjM7vaWkc_0 car +CTNN0vCWthk_0 cow +CTOTTFDvM9g_0 elephant +CTOTTFDvM9g_1 elephant +CTpK5Ywqj4E_0 person +CTtActqncZs_1 person +CTtActqncZs_0 person +CTty0Fesx4k_1 elephant +CTty0Fesx4k_2 elephant +CT6O84zfmoY_0 person +CT8VKdB074U_0 dog +CUB_Y4U0gNU_0 person +CUE1Oj2b7oo_0 person +CUIv9zU0_7M_2 dog +CUQZtS7SlyM_0 truck +CUVQtlpfthI_0 person +CUVqn-7LP_k_0 cat +CUjEVN0BT58_0 person +CUjbAz30mdA_0 person +CUvi-gOiEak_0 airplane +CUvi-gOiEak_1 airplane +CUzrNlKejnA_0 person +CU-5HeXnZag_0 person +CU_cxu2KrzY_1 cow +CU_4MsJSWGw_0 horse +CVCPdF3TevY_0 car +CVJEcVS63rM_0 person +CVJu9kpxa0o_0 skateboard +CVQq3Lnsmb8_0 skateboard +CVRQkAzvHOI_0 cat +CVXbWRarjGI_3 bicycle +CVa-tmxG3G8_0 bus +CVfXcK9LvU4_0 cat +CVnQzQjIfdo_0 person +CVnQzQjIfdo_1 person +CVtUo7t1tg4_0 knife +CVtdQUWrMFo_0 person +CV1gdpxyUvQ_0 umbrella +CV7yBA-RY-s_0 person +CV9Mv-Z5ywo_1 knife +CV9_qaQ3bOc_0 dog +CWNPg3hbbCc_0 person +CWRUw47fnHQ_0 dog +CWcpGIObSb4_0 person +CWcpGIObSb4_1 person +CWhtecFS3Ps_0 person +CWh66yU69HI_1 person +CWq2nbpnjkw_0 person +CWsgkyp-Wv8_1 person +CWsgkyp-Wv8_0 person +CWu6nT2qW2Q_0 person +CWydCxGJyck_0 cat +CW0GVWegie4_0 person +CXEi_k33z08_0 person +CXF-MNV21Uw_1 person +CXF-MNV21Uw_2 person +CXF-MNV21Uw_0 person +bKIEzYSD9LU_0 bird +bKM4LmiXX5k_3 knife +bKM4LmiXX5k_0 knife +bKQQdBiIraA_0 dog +bKT6s25xsS4_0 person +bKh8FyKvOq8_0 umbrella +bKic74m-XKg_0 horse +bKnsY1ytgqc_0 person +bK0HzQHKqhg_0 motorcycle +bK0HzQHKqhg_1 motorcycle +bK0IN2qoSjQ_1 person +bK7Wo0UxDyQ_0 person +bLBmIVS2T-0_0 person +bLLFtAMqoF0_0 person +bLOW53I2oWw_0 knife +bLU0G55kWgs_0 car +bLU0G55kWgs_1 car +bLYGpYiiF7Q_0 person +bLg0SdwRkKc_0 person +bLneVyHWwdk_0 person +bLoyRVgQcTk_0 cat +bLoyRVgQcTk_1 cat +bLoyRVgQcTk_2 cat +bLs4dUFZzcQ_0 person +bLs4dUFZzcQ_1 person +bMEbcFBdRsA_0 airplane +bMM1OZMZ_WY_0 person +bMNzE6F4WK4_0 truck +bMPPnTHvu8c_1 cow +bMQlfzj9vCE_0 person +bMZPcnVc1K0_0 person +bMakr2vwfqQ_0 person +bMdfLBSo6jw_0 bicycle +bMfQw6tBALo_0 cow +bMgWjlwilqA_0 bicycle +bMk8JyTyvUo_0 skateboard +bMojajeogfY_0 person +bMphaUsZuqU_2 elephant +bMrDB2JI0QM_0 elephant +bMuSXdxvaWY_0 bicycle +bMumJTM0f28_0 person +bM3OcevX9F4_0 person +bM6fRimkPZg_0 cow +bM6peJ4lQyU_0 elephant +bNGoGllCEj0_0 car +bNGoGllCEj0_1 car +bNJ5ygVB-GI_0 person +bNPtMp-AuhY_5 train +bNPtMp-AuhY_4 train +bNR89JLsh7Q_0 motorcycle +bNZe9vwuE8E_0 car +bNcTCIgwqNY_0 boat +bNinDD5s0LQ_0 person +bNo2RseLYYs_0 person +bNqXgNLQX3s_0 person +bNtivYIWtQE_0 person +bNtivYIWtQE_1 person +bNtivYIWtQE_2 person +bNyyHqBZnmQ_0 airplane +bN4vggzwxWI_0 person +bN-epcJfRJ8_0 person +bOPvxhSlnZI_0 truck +bORQv_d22gA_0 bear +bOTYFfq_264_0 person +bOXM6ibmbG0_0 truck +bOarvmUMdLs_0 person +bOarvmUMdLs_1 person +bOb4k6pTF-k_0 motorcycle +bOeUzXPOIWw_0 motorcycle +bOfrPHjROWI_0 dog +bOm9Qgnl2KI_1 umbrella +bOor15z5M5Y_1 truck +bOuuxRt7ugE_0 bear +bOwOVcqeajs_1 boat +bPAO0nyCO8Y_2 cow +bPLKx5uJaZY_0 bear +bPTTPAsH7v8_0 airplane +bPZdC3oRr1c_0 dog +bPanGwtU82U_0 airplane +bPavgNJxZnI_0 horse +bPavgNJxZnI_4 horse +bPcXQrlHs60_0 zebra +bPddyJH2fm4_0 cow +bPeFwxV66_s_1 cow +bPfaS8RIHVw_1 train +bPjZsDes9ck_0 bird +bPvvA8Wm5Ts_0 person +bPw91vtx0rY_0 dog +bP17881jyH4_0 elephant +bP17881jyH4_2 elephant +bP17881jyH4_1 elephant +bP6QvQUfZSI_0 person +bP7ZU4wl_xs_1 person +bP7lN2WyBTg_2 bird +bP7lN2WyBTg_0 bird +bP7pux4nQa4_0 person +bQJQKEfdctc_1 person +bQKuVB3YmRI_1 knife +bQNLK-43XKM_0 person +bQNXrSVq4r4_0 person +bQQS-amRhxU_0 person +bQQr8FzMTHE_0 person +bQR6KxB4qjg_1 train +bQWO4r5DLWY_7 bicycle +bQWO4r5DLWY_8 bicycle +bQZ8WQ2mS9o_0 horse +bQd1k1RNZZA_0 person +bQwDt3XOok0_1 skateboard +bQy9W_tIPJg_0 cat +bQ7FEMZ309U_0 bicycle +bRElYolSzbI_2 horse +bRKfUmz_7hE_0 bicycle +bRKfUmz_7hE_5 bicycle +bRP4TElBetA_0 skateboard +bRUtCCY00Yw_0 person +bRd_NGjRFpU_0 cow +bRgNc063rsk_0 person +bRgNc063rsk_1 person +bRiVaIWzo4k_0 person +bRiVaIWzo4k_1 person +bRpbblTb1VU_1 person +bRq06zdCv4k_0 dog +bRsjD1GTjeE_0 truck +bRuSrTOibGY_0 skateboard +bRw2PFlL8l8_0 cat +bRxyuZTXkWo_0 person +bR61bP65wdI_0 person +bR_EeaX8Kns_0 cat +bSC7MwTZ0Og_0 person +bSJbBDA3-rI_0 person +bSJbBDA3-rI_1 person +bSSSYoS7HhY_2 person +bSSX8qJnGak_0 person +bSVCTx_L7lU_0 person +bSbZuDkimC8_1 cow +bScFgdC-DH8_0 motorcycle +bSkEsUu7aBI_0 cat +bSqX5D_GrEc_0 person +bS4mTtP-Ud4_0 person +bS4mTtP-Ud4_1 person +bTAxiISsPNE_0 cow +bTHRXr-yw54_0 person +bTOZp15gd24_0 airplane +bTOZp15gd24_1 airplane +bTOZp15gd24_2 airplane +bTO9Pid9808_1 cow +bThFysASYJg_0 person +bThX-5t7OWM_3 bus +bTl-dt761p8_2 bird +bTp1hk4dhPE_0 person +bTuho6CpJpg_0 horse +bT7mzx9P1Yo_6 bird +bT7mzx9P1Yo_8 bird +bUDYPhSFyyw_0 airplane +bUFCsL247kY_1 person +bUFCsL247kY_0 person +bUIov_O62GU_0 train +bUVi7VVygmM_0 person +bUa61WY6E38_1 person +bUu6iW_nRvM_0 person +bU8cBepgoMY_4 elephant +bU8cBepgoMY_1 elephant +bU8cBepgoMY_3 elephant +bU8r7rNDaHQ_0 motorcycle +bU8r7rNDaHQ_1 motorcycle +bVCLNxl4PQY_0 person +bVPgCZmg1CY_0 person +bVTzUiTPtww_0 person +bVZixqlT1AI_0 person +bVbT4F3I0s4_0 person +bVbdO8rj6TQ_0 person +bVbdO8rj6TQ_1 person +bVdjQbIzOGc_0 horse +bVgKe0-_228_0 bear +bVkYqw1YJ6c_0 person +bVnmeQsd3xk_1 car +bVph6GZ3jLE_0 skateboard +bVrck_XYsR8_0 bicycle +bVtMukuPx9A_0 motorcycle +bVtWuhD1L1s_0 car +bVvVMOxHOT4_0 cat +bVwWkzYdrvk_0 person +bVw9txmBeX0_0 person +bVz-pHuWNfc_0 person +bV3UXbGCshc_3 elephant +bV3UXbGCshc_4 elephant +bV3UXbGCshc_0 elephant +bV3UXbGCshc_2 elephant +bV8k_w0cphI_0 person +bV9tUYWi-9o_0 truck +bV9tUYWi-9o_1 truck +bWCW4QZTIXE_0 person +bWCxObc3uVo_0 person +bWEnwFThRlA_0 person +bWEtMBeQQCA_0 bus +bWEw8rNQ-kI_0 person +bWJg9jatoBY_0 person +bWLcKJauKIs_0 person +bWO4NBx37Vk_4 airplane +bWdWgIB371Y_0 person +bWdWgIB371Y_1 person +bWkKy-_YzW8_0 umbrella +bWotjBNgmiA_1 motorcycle +bWotjBNgmiA_2 motorcycle +bWo4CzHWaZ8_0 dog +bWqayCqhqVQ_0 person +bWtXkAzA6zE_0 person +bWtXkAzA6zE_1 person +bW1JoZnZpXs_0 bicycle +bW1JoZnZpXs_2 bicycle +bW2I1hUiWgg_1 bear +bW2I1hUiWgg_3 bear +bW2I1hUiWgg_2 bear +bW6PJACBEFo_0 boat +bW6PJACBEFo_1 boat +bW7x14tLsxU_0 cow +bW7x14tLsxU_1 cow +bXGa-FIGViQ_0 truck +CXOKkaurfXo_0 person +CXVmfrDfalE_0 person +CXVyHpmc_fU_1 cat +CXXWvUVLBBE_1 train +CXXWvUVLBBE_3 train +CXaF0E3wEzI_4 boat +CXaF0E3wEzI_1 boat +CXaF0E3wEzI_2 boat +CXdGDPRtlo4_1 cat +CXdjIo4q-w4_0 dog +CXoeLQPShqU_3 horse +CXoeLQPShqU_0 horse +CXrwHki5ShI_0 person +CXw5HMRQwEk_7 bear +CXxPPuZcT2k_0 knife +CXyujV2S5aE_0 person +CX1US3Y-2jI_0 person +CX5Y01eJ_g0_0 knife +CX838M4iPkw_1 bear +CX_YxpWurRk_0 person +CYEtgx1uVTM_0 train +CYEtgx1uVTM_1 train +CYFtiy8FtgM_0 person +CYGBUw8HZ8Q_0 person +CYKbj5BgaiI_0 person +CYPFpTJXCp8_1 person +CYXd3muNlJ8_0 person +CYcxxdqG02k_0 person +CYcxxdqG02k_1 person +CYghFhQySik_1 person +CYghFhQySik_2 person +CYghFhQySik_0 person +CYg8fy66poA_0 train +CYjEASXRoys_0 person +CYkow-sm2pA_0 person +CYmpj4UFFtA_0 cow +CYsgb4GhJ_0_1 cat +CYtehjvIIIE_0 cat +CYw9ONxIi0M_4 bear +CY3-VTI7lQU_1 cow +CY48729zIgM_0 bus +CZAt34OJpoI_0 elephant +CZGoAqWEDQM_1 horse +CZJz6zZt3cE_0 person +CZXHqexGqfI_0 cow +CZduQndn_Eg_0 train +CZfMxEFk9hc_0 motorcycle +CZfe1GuZxPI_1 person +CZws8sfLA8M_0 person +CZ8bjG4wdZU_0 person +CZ9MT7tZZ2E_0 knife +CZ-Kodbg_2A_0 bus +CaA-PFuqaXw_0 truck +CaFlo5YQHXw_0 train +Cag3vCKRh6c_0 bicycle +CajF9IxbOvI_0 person +CajF9IxbOvI_1 person +Cam_wHie6XQ_1 person +Ca4_dI-Ii8o_0 person +Ca5GzZ-rifE_2 horse +Ca5GzZ-rifE_0 horse +Ca5GzZ-rifE_3 horse +Ca5mOzqFz70_2 bear +Ca6g367yxss_3 dog +Ca9JsTGifmQ_1 knife +Ca-l5zpgIL0_0 horse +Ca-wDaXxSn8_0 train +Ca_LwXljv5I_2 dog +CbBrv9GkBDM_0 person +CbKVR2EGoWU_0 cat +CbO4r5w5NEM_0 cat +CbTbpHHYfGo_1 cow +CbYQk8GFQwY_0 person +CbYXzAv9G40_0 person +CbZA75LYWsk_0 boat +CbZA75LYWsk_4 boat +CbZA75LYWsk_7 boat +CbZA75LYWsk_8 boat +CbZA75LYWsk_6 boat +CbbsxxHKQBs_1 bicycle +CbbsxxHKQBs_3 bicycle +CbfML92fBFc_0 person +CbrOGI6D5oo_0 dog +Cbz0hgvZtyM_0 person +Cb0EbSTABAw_0 person +Cb31aGVbcGE_0 person +CcJ-51mUw00_0 person +CcNfpk8tVxA_2 person +CcNfpk8tVxA_0 person +CcNfpk8tVxA_1 person +CcadL-XHA8w_0 person +CccC-FK79hM_0 skateboard +CceETksmvEc_0 bus +CcfAKl1kCRM_0 person +Ccl3EZzzNhc_2 bird +Ccl3EZzzNhc_3 bird +CcmiWGPbuT4_0 car +CcyRYeSG3sQ_0 truck +Ccyqd4ZzDtQ_0 person +Cc5DUip1-eE_0 person +Cc9-Kd--ejs_0 car +CdA-Gg7O6d4_0 person +CdD0W0pS7gk_0 skateboard +CdG8sd9UZFM_1 elephant +CdG8sd9UZFM_3 elephant +CdOwMZqCiMs_0 bird +CdRgo9V_e_U_0 person +CdTDo40rdz4_3 umbrella +CdVnK1TcGcQ_0 knife +CdW2qTShGbY_2 person +CdW2qTShGbY_1 person +CdYkEASWMqQ_0 person +CddXUsFqg4Q_10 bicycle +CddXUsFqg4Q_12 bicycle +CdeUORbvfgs_0 person +CdkbBdQwTX0_0 person +CdmrCOVxj8c_0 person +CdosWRXaOgY_0 person +CdtY-oTmACc_0 elephant +Cd3qxnZC6s4_0 airplane +Cd8dfcT-D9U_0 horse +Cd8zY0wsrLc_0 umbrella +Cd_ZgXZ7qKw_0 person +Cd_ZgXZ7qKw_1 person +CeCnRUGvs9Q_1 horse +CeEMUoHNeVA_0 person +CeICmGeQXOk_0 motorcycle +CeICmGeQXOk_1 motorcycle +CeVjsWpfoCY_0 person +CekBpSMLr08_0 horse +CetmVa_LV2A_0 bird +Cetw-N1I1bA_0 dog +Cew6y9K7ynI_0 cat +CezGmkW4sRY_0 person +Ce1tW6uV_lw_0 person +Ce1tW6uV_lw_1 person +Ce_dgPawIkU_0 person +CfC--i0DQ-o_0 car +CfThv8Vk-oM_0 umbrella +CfbzDUZ6PyQ_0 truck +CfqtCB_f_Z8_3 skateboard +Cfwk3niR9Uc_0 motorcycle +CfyvbbrxquI_0 cat +Cf_GVLLQaTA_0 person +CgB0fwUOZd4_2 bus +CgDcN1Lk7ag_0 car +CgDcN1Lk7ag_1 car +CgDcN1Lk7ag_2 car +CgDyrbc-LLo_0 person +CgHCCqADKys_0 person +CgQl21vwrqk_0 person +CgQv6o97KqY_0 person +CglmlO92nKA_0 person +CglmlO92nKA_1 person +Cgod2p17L48_0 person +CgwHXWDGAak_1 person +Cgzt1Kv6Sqg_0 cow +Cg9H20lr5Uk_0 person +Cg9H20lr5Uk_1 person +Cg9H20lr5Uk_2 person +ChBKKPEO8N0_0 person +ChOKPIVr5XE_2 bicycle +ChPBGkSbJ0g_0 elephant +ChRNCk9Bq-k_0 cat +ChZB3vAX8sk_0 person +Chc7poZ9r-k_3 skateboard +ChmcE3Lz1Vc_0 person +Ch2_CQg4r1o_0 person +Ch-PosNzqZ8_4 elephant +Ch-PosNzqZ8_0 elephant +CiCqdFq_a7U_1 person +CiCqdFq_a7U_0 person +CiLbnwjSJ9w_0 person +CiQOmR8VCzs_0 person +CiQOmR8VCzs_1 person +CiQS0RMaLZQ_0 truck +CiT09gfBJPA_1 person +CiVwjoLvdAs_1 horse +CiWhBWV1zGM_0 cow +CiWhBWV1zGM_1 cow +CiYOn9VW1eY_0 horse +CihCAad2Duo_0 person +CilRWTfS8e4_0 person +CiwaaMNfvCo_0 airplane +Ci0S27Qp1w4_0 cat +Ci2vW1OGHe0_0 cat +Ci6mTJ6BqYI_0 person +CjJ3l2smqAc_0 person +CjMaorKuwf0_1 horse +CjRX9J2BM4Y_0 skateboard +CjUf3D9IsCQ_0 person +Cje7Ip85T1I_0 person +Cjm9Wky44TM_0 elephant +Cjm9Wky44TM_1 elephant +Cjn-mt97y-w_0 person +Cjq3dda3PlA_1 person +Cjq3dda3PlA_0 person +Cjw2f0M_eB8_0 bird +Cj1CpXDG_Qw_0 person +Cj3PTZcRbd4_0 person +Cj3ZEx4SDe4_0 cow +Cj-a9t9yiiA_0 person +Cj-a9t9yiiA_1 person +CkBGaJnF9vo_0 person +CkC43WVctnk_0 cat +CkKQhDP2FGY_1 person +CkKQhDP2FGY_0 person +CkKQhDP2FGY_2 person +CkLE-s6CsgY_0 cow +CkLwgOIBF_I_0 person +CkLwgOIBF_I_1 person +CkP_70u-2zU_1 boat +CkX8laawskQ_2 horse +CkZeki9RVDI_0 person +CkZhHtevDk8_0 person +CknHFY05prw_0 person +CkoK8C4Rzj0_0 person +CkvEr5T38Wc_0 person +CkvEr5T38Wc_1 person +CkvEr5T38Wc_2 person +CkyU5jU74Js_1 dog +CkyU5jU74Js_0 dog +Ck8GRgUrpoE_0 person +ClBCXl7l2pw_0 skateboard +ClH2-R5LeVo_0 cat +ClLZcmIHrTw_0 person +ClM3Ftm0S7o_0 cow +ClRLFlpMUhU_1 horse +ClSzHW4AuJ0_0 person +ClV1oHNuF9o_0 person +ClV6A8WNCvw_0 cow +bXcKQNGRBvw_3 airplane +bXcKQNGRBvw_0 airplane +bXcKQNGRBvw_1 airplane +bXcKQNGRBvw_2 airplane +bXjVvJ8eOJc_0 skateboard +bXkjwotai0Y_0 bicycle +bXnvGCFA9Dg_0 person +bX9TcejzzTM_0 person +bYCvd_BTMsk_0 dog +bYE-vUOh10s_0 boat +bYN8lkupLt4_0 bird +bYQiCAwebzs_1 bicycle +bYSbuWYiixQ_0 person +bYVgzwF1hNw_0 bicycle +bYWGnwi8nDQ_0 motorcycle +bYm9aUK2zzk_0 person +bYpG750b7pE_0 motorcycle +bYvzSXZ0w_I_1 person +bYwwOO6vMAw_0 person +bYwwOO6vMAw_1 person +bYyFEbIGMfo_1 dog +bY3sDu5BZDI_0 elephant +bY3sDu5BZDI_1 elephant +bY3sDu5BZDI_2 elephant +bY6vPIaJDGA_0 person +bY8BdyCsCAw_0 person +bZL41d9eFyc_0 cow +bZRpdnJtcT4_0 train +bZRpdnJtcT4_2 train +bZVMygQQgNg_0 person +bZVZbn0oTjo_1 giraffe +bZdq8Rk75M8_0 knife +bZgZihlL0IU_0 person +bZsoMlw4CnI_2 bus +bZuOWV67gnY_0 cat +bZwJl6ye9Cc_0 motorcycle +bZwJl6ye9Cc_1 motorcycle +bZzzlD0C8Jg_0 train +bZ2u1x38Qbg_1 airplane +bZ6gk6FLGss_0 person +baDesUZ9Pyc_0 bear +baRyXrRn_ls_1 motorcycle +baWLnj87FOc_0 cat +babQ3FBdeqQ_0 cow +bagbzsb-tg4_0 person +ba1hwKdPRx8_0 cow +ba3cGHmc_OA_0 person +ba5407XQYAQ_0 cow +bbHdRyrdpDA_0 boat +bbH4CQx07Go_2 knife +bbLW6902ITg_0 person +bbLW6902ITg_1 person +bbLW6902ITg_3 person +bbLW6902ITg_4 person +bbM0SbH_pgk_2 bear +bbZAdo3awRs_0 car +bbZeVbzmLVw_0 elephant +bbaUzB0Na2o_0 person +bbfDHSIT9ys_0 person +bbhyEgEjfvQ_0 cow +bbjuucY5QQc_0 person +bbkjnF0iGrs_0 horse +bbkjnF0iGrs_2 horse +bbkjnF0iGrs_3 horse +bbkjnF0iGrs_6 horse +bbnb-beW0p0_0 horse +bb0DRm0ueKk_0 horse +bb4sgALviyc_0 bear +bb5OO1wMKr8_0 person +bcJ1MAj_A_w_1 person +bcLW7YqnUGs_0 skateboard +bcdQmV1-Z5k_0 motorcycle +bcgTPCycRIw_0 skateboard +bcksTLjC1fs_0 motorcycle +bcrQdxrU_vI_0 person +bc1C8HrNVqE_0 horse +bc28CjoKODI_0 person +bc28CjoKODI_1 person +bc3rySF6iao_0 person +bc6jeLN-DUo_0 train +bdU9JALjnmw_0 person +bdYKw4SpkQQ_0 zebra +bdZpXHSW4Ps_0 cat +bdbVAdua3uI_0 airplane +bdbVAdua3uI_1 airplane +bdcoNmelRw4_1 dog +bdcoNmelRw4_2 dog +bdcwT2ufUBg_0 bird +bddes6RyfCI_0 skateboard +bddes6RyfCI_1 skateboard +bdeoe5gmCd4_0 elephant +bdeoe5gmCd4_2 elephant +bdgSMIY2A8Q_0 horse +bdoNsiMM1RY_0 bird +bdwlZMpXPJo_8 bird +bdwlZMpXPJo_7 bird +bd--DVCeT-s_0 cow +beE5VOzxibM_0 giraffe +beLTv9YiY78_0 dog +beLTv9YiY78_1 dog +beLTv9YiY78_2 dog +beQOHdCA8KM_16 elephant +beQOHdCA8KM_3 elephant +beQOHdCA8KM_6 elephant +beQOHdCA8KM_7 elephant +beQOHdCA8KM_10 elephant +beQOHdCA8KM_12 elephant +beSTl1azmTY_1 skateboard +beVVM2pBQdA_0 cow +beVVM2pBQdA_1 cow +becTICXjrg4_0 person +beliMXc3JE8_0 train +besXR1P9Oew_0 car +beu-edT1daM_0 person +be9BCy6kHvY_2 person +be9CXLatX9I_0 horse +be-ggiVD4V0_0 knife +be-5ARU_aHA_0 person +be_IhYef3hE_0 person +bfBZLLwpNWA_0 giraffe +bfJaD1qZ2gE_0 bus +bfJaD1qZ2gE_3 bus +bfJtapJ86Gw_0 person +bfRgL9oanEc_1 person +bfRgL9oanEc_0 person +bfS8FB_HOlY_0 person +bfZfMA1mLrQ_0 dog +bfZfMA1mLrQ_1 dog +bfaMdaYiK90_0 cat +bffC89pE6fo_0 person +bffC89pE6fo_1 person +bfkNVFr6Cwg_0 cow +bfkNVFr6Cwg_1 cow +bflVgDgAHSo_0 umbrella +bfrY2wEePwY_0 person +bfrY2wEePwY_2 person +bfwWF0XO7bE_0 boat +bf9YySHJcdQ_0 person +bgAOYaooc18_0 person +bgAo5vgwe2M_0 zebra +bgBK4sMnLig_0 cow +bgBK4sMnLig_1 cow +bgC-r6p-XHU_2 elephant +bgE_uy3Ml6g_1 umbrella +bgHMLwWY4Qo_0 person +bgV-FqQ8Tv8_0 umbrella +bgXZ3BpIOh8_0 train +bgaD7K2iEPI_0 person +bgbS11O9lSw_0 bus +bgelX1blhpQ_0 truck +bglPgA_0LAk_0 motorcycle +bgpB-A04RLI_0 person +bgyEHsMav4U_0 person +bhBMa8wQ5KA_0 bird +bhGJ9gZmP90_0 person +bhGJ9gZmP90_1 person +bhH_pqCQ3Co_0 cow +bhJGFbgXlts_1 person +bhNfsUPLKDg_1 train +bhWmpmnXSlc_0 person +bhZZubkX8_o_1 bird +bhdtzsUvieg_1 person +bhqr680CLr0_0 person +bhrOzwB-7qA_0 person +bhsCCw1J_JU_0 person +bhuOX61sk8M_0 person +bhz6HG2KpnI_0 skateboard +bh0ZZ4Z76cc_0 person +bh3QacG9JYk_0 airplane +bh3QacG9JYk_1 airplane +bh3QacG9JYk_2 airplane +bh8aMNVny8s_1 truck +biAdsjypETI_0 knife +biFm-y7gSrc_0 horse +biGJ8vHOsZM_0 umbrella +biLY6NMsqJU_0 cat +biUFB3c0Ucc_0 bus +biZU5SOHQvc_0 umbrella +bibJ3Bv5YmQ_0 motorcycle +bik9GuCughc_1 bird +biuEbYnn68k_0 bus +biwbqbVsZeE_1 elephant +biyu3sxIOYc_0 person +bi1kYvu5Irg_0 train +bi1kYvu5Irg_1 train +bi3GSUnfzd8_0 person +bi5Bkz2MVP4_0 bird +bi5Bkz2MVP4_3 bird +bi6BNwvsR_0_0 person +bi-GKlUZMR8_0 motorcycle +bjBwCQ5z4IQ_0 cat +bjH2OQR68Vc_0 person +bjRQ69TaeKs_2 person +bjgooTfy3JM_0 train +bjgooTfy3JM_1 train +bjgooTfy3JM_2 train +bjhEqucWULo_0 cow +bjq8de0pw5M_0 person +bjq8de0pw5M_1 person +bjrq_Kj-wSU_0 airplane +bjrq_Kj-wSU_1 airplane +bjrq_Kj-wSU_2 airplane +bjrq_Kj-wSU_3 airplane +bjwdTl5zyaI_0 skateboard +bjx96uw-Q24_0 person +bj-Grf4s790_0 elephant +bkElaSUqJjM_0 train +bkIBcqXKARI_0 person +bkMU7xViDvA_0 person +bkXBjOrn2yI_0 person +bkggwniG4vc_0 person +bkiQTbQF_TA_0 elephant +bkigtjV1zA0_1 motorcycle +bklheVvsfac_0 truck +bkoOiNz6Zmo_0 person +bkok3wr4188_0 person +bk2l-O9wSEc_0 person +bk8UlOzFy7U_1 person +blAiGXbJxmI_0 train +blIpNvBakFI_0 person +blW8z3TPVvo_0 motorcycle +blhCjXE5cRo_0 person +bli5Z83QY_U_0 person +blnFzQdaVRc_0 person +bluU1CAbJfo_0 person +blubKbt8mLE_0 car +bluqyqDv2eE_0 car +blv0QslQ524_5 bus +blv0QslQ524_6 bus +blzDAgvxJMw_0 person +bl1XJCtyP2E_0 truck +bl2xZSpcZqs_0 cat +bl6wIjxfuJo_1 bicycle +bl6wIjxfuJo_2 bicycle +CloG2hcM5nU_9 bicycle +CloLHr7NJqg_0 person +CloOQkTkYfY_0 bus +ClpDLu1qCx4_2 person +ClpDLu1qCx4_3 person +ClpDLu1qCx4_1 person +ClvAi34e1zM_1 elephant +Cl1mEpQ3wy4_0 boat +Cl1mEpQ3wy4_1 boat +CmEoz728tlo_2 bear +CmGSMnkcvrg_1 train +CmIXZuJDwt0_0 person +CmNv_yKt5oM_0 person +CmOIqZyQpPI_3 bird +CmOIqZyQpPI_1 bird +CmVoggJ6fxY_1 horse +CmYL2EyELbA_0 elephant +CmezWT8A2i8_0 bus +CmjUCOwcOT8_4 bicycle +CmjUCOwcOT8_11 bicycle +CmjjEuS9_Ww_0 bicycle +Cmjw8kbfDCw_1 knife +CmoknpL1cMA_0 person +CmqXoT7CXJs_0 dog +Cmq1qVX-Ugo_1 cat +CmsqpFOcosw_0 person +CmtmoydPH08_0 cow +CmxhIEztsyg_1 skateboard +Cm1y7USHcrg_0 person +Cm3tYZlSc0o_0 skateboard +CnBJ9TMTRAA_0 person +CnBJ9TMTRAA_1 person +CnCTVtsK5Kw_2 bear +CnEXHgq3AE4_2 elephant +CnGp9Wq2rTs_0 bear +CniS9Q6Y200_0 person +Cn0UKsWocEI_0 elephant +Cn0UKsWocEI_1 elephant +Cn1dXZ_p3dw_1 person +Cn9Bj5B29UI_0 motorcycle +CoBuNWx_OwM_0 person +CoDB7ZeilsQ_0 person +CoKMowfrd5Q_2 truck +CoKMowfrd5Q_3 truck +CoKVaYX3c1k_0 person +CoKVaYX3c1k_1 person +CoKVaYX3c1k_2 person +CoOwm7ccDrs_0 truck +CoSIyrW5lvA_1 skateboard +CoSSvI2-U_w_1 bicycle +CoZY8o0c-h8_0 elephant +CoZY8o0c-h8_1 elephant +CocSNWws-Qo_0 person +CodelARKQ10_0 skateboard +CosYvoW04Uk_0 person +Cot7Xj8C308_0 boat +Coz9g_0N91c_0 person +Co_XBpd6lxE_0 person +CpDHwc5JmK8_3 elephant +CpFiT_6KvM4_0 person +CpF-80dM2aY_0 person +CpF-80dM2aY_1 person +CpxxxHYsJy8_0 person +Cp0lT2opaL0_1 person +CqANE5ByBvY_0 person +CqDjHjvw8T0_0 elephant +CqDjHjvw8T0_1 elephant +CqVeLNnA0vk_0 horse +CqZz9FnLLjk_0 knife +Cqkhrld_7LU_0 person +CqzahbOVzO4_0 person +Cq02-pFNn6w_0 motorcycle +Cq02-pFNn6w_1 motorcycle +Cq4KAVAWq7g_0 person +CrAxPJajbcs_0 airplane +CrCNqDd18fw_0 umbrella +CrUmEDCjFtU_0 person +CrUmEDCjFtU_1 person +CraDHWuN4Q0_0 person +CrgMhrCYmOo_2 motorcycle +CriTKYemGmo_0 person +CrmzwYKpLAY_0 umbrella +Crn24ZKAP1k_0 person +CrsjxpJoY5Q_0 person +Cru8KBJqhng_0 person +Crz3l2CEDzA_0 person +Cr0SWcS1qX0_0 cow +Cr_B3I0QPEQ_6 airplane +CsM_GTD0TZE_0 person +CsPLGd2dgl0_1 airplane +CsTntmE8EWs_0 person +Csa542XNEXo_0 person +CsfkuwD6-nA_0 person +Csh_4yR8bFk_1 truck +Csh_4yR8bFk_2 truck +Csii4vkefsM_0 boat +Csii4vkefsM_2 boat +Csw3kLrhjoM_0 person +Cs38JY7Gqjo_3 skateboard +Cs-Vx_ym23o_1 bicycle +CtC2yC9NGTk_0 bird +CtD4wnIU0Pw_0 bicycle +CtF9IxfLhaQ_1 person +CtF9IxfLhaQ_2 person +CtF9IxfLhaQ_0 person +CtHIoS1lGKA_0 person +CtLVK2j48gA_0 person +CtO5dmTdzYQ_0 person +CtPEAoFPnE4_0 person +CtQPPKpIEIc_0 person +CtTcyoZvRvU_2 skateboard +CtUPPSKU8cE_0 bus +CtVUqIFqqr8_2 bus +CtYDJRkhtpg_1 umbrella +CtYDJRkhtpg_5 umbrella +CtfPPnpBKHs_2 bird +CtipU0GHAEo_1 elephant +CtjTAe-FFe4_3 elephant +Ctkjh9fntpQ_0 bird +Ctkjh9fntpQ_4 bird +Ctkjh9fntpQ_5 bird +Ctkjh9fntpQ_2 bird +Ctkjh9fntpQ_3 bird +Ctnjw80kgcw_0 person +CtxK3wGlqx0_2 motorcycle +Ct1QrXUgBGg_0 person +Ct1QrXUgBGg_1 person +Ct8S9nC7sfk_1 person +Ct870xrnBGU_0 person +CuDfCpgoIjg_6 boat +CuGfRQMwYd8_0 cat +CuHF9Hd0uwI_0 person +CuIkNejeZrY_0 cat +CuUJUrjEcc4_0 person +CuWdZPYMLww_0 person +CvDW2A8hD78_0 person +CvRJwKt7FfY_1 skateboard +CvVVS4SUiuw_1 train +CvZaA28QUK4_1 knife +CvajmAL3sjQ_0 person +Cvda-hutmbg_0 dog +Cvqylkq9fwI_0 truck +CvxsoaCV1_8_0 person +CvzsX_s6tek_0 person +Cv2T8U0uQcQ_2 person +CwAdBrBzIcA_0 truck +CwBiMh4zHWQ_0 person +CwFcmrnz1yw_0 elephant +CwFcmrnz1yw_1 elephant +CwFcmrnz1yw_2 elephant +CwR2tJptu0Y_2 motorcycle +CwVLRawns04_0 person +CwVTSONqnVw_6 knife +CwnHi50fuuQ_0 person +CwnHi50fuuQ_1 person +Cw22-zpE1UY_0 person +Cw3iLs4yV4g_0 person +CxFRYsUCyWc_0 cat +CxH8vGqLVM0_0 bicycle +CxH8vGqLVM0_1 bicycle +CxH8vGqLVM0_3 bicycle +CxH8vGqLVM0_6 bicycle +CxJ7Uww1mSk_0 elephant +CxN5CG94Q5Q_1 airplane +CxN-YEErXFg_0 train +CxPyIeBtRec_2 truck +CxWaiU0rF9g_1 cow +CxWaiU0rF9g_0 cow +CxXdw0Cqr4Y_2 airplane +Cxa8q3QXoRs_0 person +CxgqklOxSfo_0 airplane +CxgqklOxSfo_2 airplane +CxnCTBBNWCY_0 person +CxnCTBBNWCY_1 person +CxoZT0--IBo_0 person +CxooWldim98_0 person +Cxs-xZDDZWw_0 person +Cxug83tjWyc_0 horse +CxzJV_HYpAc_0 airplane +CxzJV_HYpAc_1 airplane +Cx0XeFKQ06o_1 train +Cx7ZY8oqOmE_10 bicycle +Cx7ZY8oqOmE_6 bicycle +Cx7ZY8oqOmE_8 bicycle +Cx9efnltcUY_0 person +CyE1kuECzfg_0 person +CyH0woBc0zU_0 boat +CyI7nyp65bI_0 person +CyI7nyp65bI_1 person +CyLLTzV_lAg_0 cat +CyOXSqLm7ao_1 person +Cyb4-vF1WMM_0 airplane +Cyedl__okwE_0 person +Cyedl__okwE_1 person +CynfaDsQ1AI_0 zebra +CysFfEkdDT4_0 bear +CytiPd_Wbkg_0 airplane +CytiPd_Wbkg_1 airplane +CyvInNqvQyE_0 truck +Cy002CigJRQ_0 person +Cy_hvqOd0RY_0 knife +CzFRG22Jmvs_0 cow +CzHeIzQZUEg_0 person +CzNFSb4N6p8_0 person +CzQ03Z7Dv5U_2 skateboard +CzQ03Z7Dv5U_3 skateboard +CzQ03Z7Dv5U_6 skateboard +Cza2-_wwpd4_0 person +Cza2-_wwpd4_1 person +CzcwXF0Z1TQ_0 cow +Czt8McI8UTE_0 person +Czze2Jy6Ook_0 cat +C0Tk6QryTA0_0 bus +C0Tk6QryTA0_1 bus +C0a9pkujXQg_1 person +C0lvs-UEqKs_0 person +C0pOQ36uosU_0 person +C0pOQ36uosU_1 person +C0qbh7OJTHI_2 skateboard +C0tGKqnFyZA_0 person +C0xTDmlUYSA_0 person +C0xZYHsXNws_0 person +C0xZYHsXNws_1 person +C0xjvq51pVA_0 horse +C0xl46ieUxg_0 skateboard +C0zUOQoeQrA_0 person +C0zrmcMf8D4_0 bird +C05P4mCw-xA_0 bear +C1DCcNlUQDk_0 boat +C1DX9TjKTrE_0 bus +C1MfcNYih9c_1 person +C1RCXQFjvvc_1 person +C1RCXQFjvvc_0 person +C1bdSMUVy2Q_1 truck +C1bdSMUVy2Q_0 truck +C16ZlJRDfUc_0 bird +C16_rFYBwUA_0 person +C17jwrOnSCI_0 horse +C19rR4b8CSQ_0 dog +C1_gk-bIL6Y_0 airplane +C1_tauCAYjs_0 person +C2GvHXU8mIc_0 person +C2HZBTrCAf8_0 horse +C2Hcs2itPTc_1 elephant +C2H_P7MX3zw_0 bus +C2H_P7MX3zw_1 bus +C2IJYHPWHJM_1 cow +C2K7zu49SKw_0 person +C2K7zu49SKw_1 person +C2LdkQMjxJk_0 cow +C2ROFMcXam4_0 cat +C2S4CV9mnC0_0 truck +C2VjZHe3ID8_0 person +C2r9VGslxTE_0 person +C2v7hcs3Ax0_0 zebra +C2zRn25TBOo_1 airplane +C2zRn25TBOo_2 airplane +C2zRn25TBOo_4 airplane +C2zRn25TBOo_6 airplane +C23ZGYnWhgo_0 person +C26HiGgIjYg_0 person +C2-glFtt9Vw_0 umbrella +C3LbuiUjzvo_0 cat +C3LbuiUjzvo_1 cat +C3LbuiUjzvo_2 cat +C3Qu-KUydyg_1 cow +C3UX9hrlLeE_0 person +C3YcvZKgCgY_0 person +C3terpXzPm4_0 person +C3z1zbkmwdU_0 bird +C30B6KXg9vs_0 person +C3399zrSQ6A_0 horse +C34_EkCWJaU_0 motorcycle +C4HzsadhLW0_0 boat +C4QHknuNLYI_0 person +C4RAj-omUMo_0 person +C4W_g9eheB8_0 skateboard +C4XGGPoj4q8_0 person +C4dV8SPq6Mk_0 person +C4e-5QS1FmU_0 umbrella +C4e-5QS1FmU_1 umbrella +C4irKghQYTE_0 horse +C4jghf6KKYI_0 skateboard +C4vFHmzTY-s_0 cat +C4xJ3_Wrrn4_0 train +C4yVuAqcr0U_0 train +C409K0fAxiM_0 person +C42397qio9c_1 skateboard +C4317zxtzKA_0 person +C4-k1XW5O3U_0 dog +C5DAyL_gEQU_0 cow +C5GJx1VFRm8_2 cow +C5HT9La1jDY_0 person +C5JobuZa590_0 skateboard +C5MJ8fSfmLw_2 bear +C5dPwnswp8Q_0 cat +C5jo-fCBqmA_0 person +C5jo-fCBqmA_1 person +C5jo-fCBqmA_2 person +C5pop0SvnOM_0 person +C5r41vkLsKE_0 person +C5sXGZRLfmU_4 truck +C5sXGZRLfmU_6 truck +C5umaWklWFQ_0 boat +C5ybfGh51LM_0 cat +C55z9Fe6H7A_0 dog +C56Bp4toMG8_0 person +C6NYuB7zIzs_0 person +C6NYuB7zIzs_1 person +C6XCgppHkHA_0 bus +C6Yy8uEd0bQ_0 person +C6aB6M0DHrU_0 person +C6cOmWIisxU_0 person +C6eN6sMtuXY_1 boat +C6gNbZUU7xg_0 person +C6ia-W4TV1U_0 horse +C6nHtSy67OY_0 cow +C6n6ECY5h84_0 cow +C6qWzx58kxo_0 elephant +C6qWzx58kxo_2 elephant +C6rqmPvlIlI_0 person +C6upTeuDG4E_1 skateboard +C6xv6Wmy97M_0 horse +C62nD-_VXpM_0 horse +C62nD-_VXpM_1 horse +C66OM90TFXI_0 train +C66OM90TFXI_1 train +C66z-I_UHqQ_0 airplane +C6_p7BXwCTA_0 elephant +C7CB2A_bxa0_0 person +C7COsB9pcOQ_0 person +C7CXGBdoJWo_0 cat +C7KZnM_0j8s_0 person +C7QYoT22ZYo_0 train +C7W0oxkg-nU_0 bicycle +C7kKR6pqYzw_0 horse +C7to6tRsC9U_0 person +C72k6hv1NPM_1 cow +C72k6hv1NPM_0 cow +C7-sqpILAXM_0 person +C7-sqpILAXM_1 person +C7_HhvBNDSw_0 person +C8ETc2K6ef0_0 train +C8G_kcqjspU_0 knife +C8IE7aLZvIA_0 person +C8IUB4Opf44_0 person +C8IUB4Opf44_1 person +C8PqOHn0izQ_6 bird +C8Zex-ptYyk_0 person +C8daRmtyPo0_0 person +C8fcFW4HKGs_0 airplane +C8mEWe-TWYs_0 knife +C8n1dTEDWvk_0 skateboard +C8ukXeoRjbI_0 cow +C9Zq_rDHwgg_1 cow +C9dD6oS_Zs0_0 person +C9je005HOlA_0 bus +C9jqFBMRyPs_1 person +C9vG5qPPhzE_1 train +C9wgqGACPso_2 elephant +C95TX0IOPa8_0 skateboard +C97oHqKqdBk_0 person +C97t3TGT2oc_0 person +C-AoVBwcBUw_0 person +C-FX5hgFDd0_2 person +C-Q9RDsPyOw_0 person +C-Q9RDsPyOw_1 person +C-S34-Drg7M_0 cow +C-TWHpbtVNY_1 person +C-WsGZQoLx0_0 boat +C-cL2hzThKI_3 airplane +C-cL2hzThKI_6 airplane +C-omy9mzD7E_0 person +C-q9nO8X1rs_0 person +C-seg-BCK0U_0 bird +C-v3Ttrvuo8_0 airplane +C-38hraIyOs_0 person +C-47EdafspI_1 airplane +C-54wttM4AA_0 person +C-9LBJqCMm0_0 train +C-_ebeJtjyE_0 person +C_BX3dg-lc4_0 person +C_DOGAVETwk_1 bird +C_EMJm-Z2I8_1 bird +C_EMJm-Z2I8_2 bird +C_EwPB6zgIA_0 person +C_EwPB6zgIA_1 person +C_GnC_IEwJM_0 person +C_GnC_IEwJM_1 person +C_HBU7EUsoE_1 person +C_HBU7EUsoE_0 person +C_IjqR1NOxw_0 person +C_POS7ndKw0_0 truck +C_PXq5TsPRQ_1 train +C_TfufSsuEU_1 person +C_VePcGhr10_0 knife +C_aP0fKyudQ_0 horse +C_aYcFttRC8_1 person +C_aYcFttRC8_0 person +C_cUky_0p2Q_0 cow +C_uGdKk79X0_1 person +C_ykabkQ2U0_2 person +C_2EFIuyDSA_0 person +C_2p_N8Kvpk_0 person +DAJkfl5W8Vc_0 horse +DANymtBuoIs_0 dog +DAOBGjTf7xI_0 person +DAQ9-YTrpp0_0 cat +DAU6UNdxbRI_0 person +DAn4fH-1Ucs_0 person +DApkEgrJX0Q_0 person +DAqHnZA6tBQ_0 truck +DAtSTeTmg8I_1 horse +DAwdyKiZyzM_0 person +DA1bsx2RsGA_0 person +DA1bsx2RsGA_1 person +DA4LF3u2VTI_0 car +DA5X-ADHM1w_0 person +DBFMXaS9LRg_1 umbrella +DBLaZSSthxo_0 person +DBR0l2rW6Ew_0 horse +DBVbRonJkb8_0 person +DBaAVcI4Ftw_0 person +DBaAVcI4Ftw_1 person +DBmVOTuCJ8Q_0 person +DBvOm1qnWrA_0 cow +DBySPDEqsO8_0 person +DB1Cvyyike0_0 airplane +DB3lsf7fD84_0 dog +DB6TJh9r1Dw_0 person +DCE8Dg_ycjo_0 truck +DCHv6sxfCAs_0 person +DCPk1uyVNlU_0 person +bmHyfvCZWsg_0 elephant +bmHyfvCZWsg_2 elephant +bmHyfvCZWsg_3 elephant +bmLLdC88ohM_0 train +bmMB6Mr1uKI_1 person +bmPhh5NpV7U_0 person +bmQbHpw-4fY_1 bird +bmUFMo3pjyo_1 airplane +bmhSkbKIg0U_0 cow +bmhSkbKIg0U_2 cow +bmhSkbKIg0U_1 cow +bmhfPSKCY8I_1 dog +bmqPIwMWGj4_0 person +bmuIwo4T6rk_0 cow +bmvh7yxyWcY_1 horse +bm2eU4uLgQE_0 skateboard +bm8MRDfmerA_2 person +bm8MRDfmerA_0 person +bnOUoCjxIvA_0 bird +bnWQnn3a2xE_0 cat +bnZwZd6xdHY_0 person +bnc1LyPUCLg_0 train +bnfN43NoRbA_0 person +bnqbJR2oSPk_1 person +bnqbJR2oSPk_0 person +bnsuTEBQy44_0 person +bnw6G0Prvc0_0 bus +bnyALwWqo4Y_3 cow +bn8epY7auRE_1 person +bn8epY7auRE_0 person +bn9y-iIDoUU_0 person +bn9y-iIDoUU_1 person +boHeJDDjRf4_1 person +boIKCyPzxr8_0 bicycle +boNYwNYmh1E_0 cat +boVVWwoXNDw_0 truck +boZ6xZrNpzc_0 person +boadjC5Lci8_0 person +bocql7vYA4o_0 bus +boja3N4XQVo_0 person +borBr_AiOmM_0 person +bornws-twE0_4 airplane +bosTHwpZ8Ao_1 dog +bo7P3hYkeog_0 person +bo9sUjViaHQ_0 person +bo-qyHCKssw_0 bird +bo-qyHCKssw_4 bird +bpI4nUgSqbE_2 person +bpI4nUgSqbE_0 person +bpI4nUgSqbE_1 person +bpJNbivFLKE_0 skateboard +bpdgYRz5hPs_0 person +bpiM4FHf540_0 person +bpjVhXyB4M0_0 airplane +bpjVhXyB4M0_2 airplane +bpsMni7yj3M_0 truck +bps3HXPsekI_0 bear +bpu9NYWxcEE_0 skateboard +bpyH8PRkBQM_0 person +bp1zW8j_ajo_3 bus +bp26IdTs4XE_0 person +bp3rDJju8n4_0 person +bp3xwI_FfOI_0 elephant +bp6K7EUtORo_0 cow +bqBtysMz94c_0 person +bqEmBkEnR1c_0 person +bqGkchWbZYE_0 car +bqJcZwUB1Go_0 person +bqPKigpT9AY_0 person +bqQk37pcpVA_0 person +bqaeUBH6J3Y_0 person +bqhQG8t_2XA_0 person +bqjcNzWyaC4_1 airplane +bqoG__OO_5g_0 person +bquLxAXnaww_0 truck +bqwFWjwCZas_0 truck +bq6n9q-Qpv8_0 person +bq6870eY1a8_7 bicycle +brDq8RFzVTo_1 truck +brIIDuCmk-E_0 person +brLbzZeRz1o_0 person +brLeJHMfMXQ_0 horse +brNR68fKeMk_0 bus +brWg7FAeBEA_0 person +brZj8bv9oxY_1 person +brhA4NqjrgQ_0 horse +brh4hrmrs0Y_1 skateboard +brpbaoTNe4s_4 bicycle +brpbaoTNe4s_0 bicycle +br3e--6oH8Y_0 airplane +bsGmFJGua4w_0 elephant +bsR9KXIHlCM_0 umbrella +bsVBX8u9pW8_0 bus +bsXpGvnXpmk_0 cow +bsa-G_HEllM_0 person +bsbzpk_ejJk_0 person +bsbzpk_ejJk_1 person +bsgdfqE8ySk_0 person +bspbqjb3wAg_0 person +bsv_swJ9_KY_0 knife +bs2FVeXKiYQ_0 person +bs3u00S0eu0_0 person +btI7FYFXsfI_0 person +btL1Ptjq7pM_0 motorcycle +btMmnZdL_uQ_0 person +btO34shZMZo_0 horse +btSyjckocDA_0 person +btVQJbFp8Dw_0 cow +btdt4lysW6U_0 dog +btihrVidTTg_0 cat +btk27mnJY_A_1 person +btrdQ6N7QJc_0 truck +btrdQ6N7QJc_1 truck +btsT4XRF0nI_2 cat +btul_U3BMKI_0 bus +btvg47tz3Ps_1 person +btvg47tz3Ps_0 person +btz7EwI5rYY_0 person +bt75khQG0w8_1 bird +buFiFNHj41w_0 person +buOqwfPnqkI_0 cow +buRfiT3Mq6Q_0 bear +buSgd-PrRmA_0 elephant +buSgd-PrRmA_2 elephant +buSgd-PrRmA_6 elephant +buSgd-PrRmA_8 elephant +buWf8ffXWTs_0 person +bue8SUcqigE_0 cat +bugTv6zkE0Q_0 person +buh8d20UxNw_1 airplane +bulc7gZ_YQY_0 boat +buqR3s7EZeQ_0 person +buq0_IIvQqc_0 person +busJdrzEeJU_0 truck +buyJwHRaSYc_0 person +buyJwHRaSYc_1 person +buzd3FYmwQQ_0 bus +bu6QE_qf8fw_0 skateboard +bvLQLfRAI9s_0 person +bvW_ZJYSOLg_0 person +bva98_iD8pI_0 person +bvc6dUfKFpM_0 skateboard +bvg-QHsENSc_0 umbrella +bvnuyMz5Pk4_1 person +bvnuyMz5Pk4_0 person +bvqPJIDHXHI_0 person +bvqPJIDHXHI_1 person +bvwJ75OkrTk_0 person +bvwJ75OkrTk_1 person +bvwwPOK7lN8_0 skateboard +bvw4raRDAys_0 person +bvxAWBUG1zk_0 dog +bv6ASjMljew_2 person +bv6ASjMljew_0 person +bv6ASjMljew_1 person +bv7NOTxSDhg_0 person +bv7lroHoMyE_0 person +bv8CHN4kwyM_0 person +bv9J7oplKjY_1 bird +bv-ps8hofSY_0 person +bv_rrakMnsY_0 elephant +bwB-cfh8UFY_0 cat +bwIBXBulTRg_0 person +bwM3RKdZAd0_1 airplane +bwM3RKdZAd0_2 airplane +bwSSE1XeKkg_0 person +bwSSE1XeKkg_1 person +bwTJKRhesM4_0 person +bwZEDD10b44_0 person +bwd7bbxG4Kw_1 person +bwjUOg-CI1E_0 horse +bwotbTZHoPA_0 horse +bwotbTZHoPA_1 horse +bwv4Q2VqV5A_0 bus +bwv4Q2VqV5A_3 bus +bwwud6bxEeY_3 elephant +bw1HepCVmL8_0 person +bw3c96BQrRU_0 car +bw3c96BQrRU_1 car +bw96DHOgI1I_0 airplane +bw_opOTzI6k_0 dog +bxRX_05rH9Y_0 bus +bxXWi1nvXjI_1 bird +bxYeOYlqDPc_0 cow +bxaC_opt7IU_0 truck +bxjIDI2ZkO4_0 cat +bxnu-AITJt4_0 person +bxoclb4AFb8_0 person +bxsI00qOi6c_0 person +bx0h8tvY6kw_0 person +bx6BVBAcBtM_0 person +bx6BVBAcBtM_1 person +bx7PtvZe6O8_1 airplane +bx7-RzWnIe4_1 truck +byDPGQJdn1s_0 person +byQIRt1JF9I_2 dog +byQIRt1JF9I_0 dog +byQIRt1JF9I_1 dog +bycJD4U6rIs_0 bird +byehVoG0_eg_0 person +bye0FepI8wg_0 bird +byi-4Qx3vx4_0 person +bykN9ap_QTw_0 bird +byvddKaL_kw_0 person +DCRIRGz2xhc_0 person +DCRIRGz2xhc_1 person +DCUcxHDfYiE_1 cow +DCUvhnZnRGQ_0 horse +DCXrBMEdS4E_1 person +DCrv8CyK9zM_0 bus +DCx698xXxjs_0 person +DC0PPRyXlD4_0 person +DC4ZTdVoj2o_0 boat +DC5fRZmUZV8_1 airplane +DC8lKdla6rE_0 person +DC8lKdla6rE_1 person +DC_Kd2iaw9U_0 person +DDZILIDFFXc_0 elephant +DDd8CfnxkYM_0 person +DDgtm9B7Yj0_0 train +DDhlugZ-vro_0 person +DDhlugZ-vro_1 person +DDjUzAM4mLE_0 bus +DDjUzAM4mLE_1 bus +DDjUzAM4mLE_2 bus +DDjUzAM4mLE_4 bus +DDoBBLQQ1Mg_0 train +DDtWIKexWpM_0 skateboard +DDw2iF2W4HI_0 bird +DD4YGjlBsHc_0 boat +DD844YVVMXE_6 bicycle +DD844YVVMXE_0 bicycle +DD844YVVMXE_1 bicycle +DD844YVVMXE_3 bicycle +DD844YVVMXE_4 bicycle +DD844YVVMXE_5 bicycle +DEHHjz2xiz4_0 person +DEI-qJD08Pc_0 person +DELUfY3m37k_0 person +DEVUyfQt_G0_0 cow +DEVUyfQt_G0_3 cow +DEVUyfQt_G0_1 cow +DEXhh5rt_24_0 motorcycle +DEXhh5rt_24_1 motorcycle +DEZHoMWiFBQ_1 person +DEau5L3A9S0_0 person +DEjPKQLASJg_0 umbrella +DEtj0Fb-Jbo_0 skateboard +DEuYWYNXbw4_0 truck +DE3kl7rbakE_0 skateboard +DE6z5oB-0vo_0 elephant +DFBlkKPYtl0_1 cow +DFBlkKPYtl0_0 cow +DFI7_dtUb0U_1 giraffe +DFI7_dtUb0U_3 giraffe +DFRmdyjR_Dc_0 giraffe +DFb4KWUX31Y_0 person +DFpZ6f1iWT4_0 person +DFwPVEPK4-Y_0 cat +DFzgqOHlnAk_0 person +DGC_pivLAEE_0 person +DGMfSMlhL4w_4 elephant +DGMfSMlhL4w_6 elephant +DGMfSMlhL4w_13 elephant +DGMfSMlhL4w_17 elephant +DGM9CDF3ks8_2 motorcycle +DGM9CDF3ks8_0 motorcycle +DGM9CDF3ks8_1 motorcycle +DGbZYKPp7XI_0 person +DGc9VSWQUyQ_2 person +DGc9VSWQUyQ_1 person +DGp5vBVf28g_0 person +DGsQAjKXPBw_0 cat +DGs0ZHnAtkg_1 person +DGs0ZHnAtkg_0 person +DGvsndSWlBw_0 elephant +DGx5aC4h8wg_0 horse +DGygUuHcJhs_0 person +DGygUuHcJhs_1 person +DG8TJBoerZ0_1 person +DG8TJBoerZ0_0 person +DG93jIsco3E_0 person +DG93jIsco3E_1 person +DHB_RgHOHdo_0 umbrella +DHB_RgHOHdo_1 umbrella +DHLK8xDGwL0_2 knife +DHLg5KzzoOM_2 cow +DHLg5KzzoOM_0 cow +DHPWnuYI2qA_0 person +DHSGQLguGZ4_0 truck +DHdFVfp7SvM_1 horse +DHl_QoiyZ2I_1 person +DHl_QoiyZ2I_2 person +DHl_QoiyZ2I_0 person +DHqrGwHgnAA_0 person +DHr77uGYi-g_0 dog +DHsorh6ngMI_0 umbrella +DHs1KtWx2n4_0 person +DH0OVsYB2vs_0 person +DH5nSZZ6uJE_0 umbrella +DH_wEdP1Glk_2 train +DIFEQ3rorSw_0 person +DILtO1oyoCY_0 person +DIOuJC_mv_k_0 person +DIO8l6DAJX0_0 person +DIO8l6DAJX0_1 person +DIP8d1YC6vM_0 person +DISU2i6bJqs_0 cow +DIaTXSXAfJM_1 person +DIaTXSXAfJM_0 person +DIpJyhb8gzw_3 motorcycle +DI7rj5AAYEE_0 elephant +DI801ysby74_0 knife +DJD4Xlf0eNg_0 person +DJKFzJe6KAk_1 skateboard +DJKokwprK90_2 skateboard +DJLSHLPE0po_0 person +DJQ8goQ4xyo_0 person +DJV-ft_10HY_1 person +DJjjrdYts2s_0 elephant +DJ4oQ03HqyE_0 bicycle +DKBIz_MLIpw_2 knife +DKC58UBq-0w_1 airplane +DKEmSml-t4c_1 person +DKEmSml-t4c_0 person +DKHCjzNZE3U_0 elephant +DKHCjzNZE3U_4 elephant +DKICHseWnGQ_0 person +DKJ3As_9Mlw_0 person +DKKsGGUWero_0 person +DKLxBVm3HHk_0 airplane +DKMUARFnh2Q_0 person +DKShwn6Xk8w_0 cat +DKZ21QA0lBM_1 person +DKcpPg_tEUU_0 skateboard +DKj3fFeAaL8_0 person +DKq7d2C6gOI_0 motorcycle +DKxIadOj4D0_0 horse +DKyckH3XY8Y_0 bicycle +DKydJWySeUw_0 car +DLKE31mt2Qc_0 bird +DLLrkv1aF-k_0 train +DLMDzB4XBPg_0 person +DLPmEX5pwY0_0 cow +DLT57E3vm98_2 truck +DLct7_2tyWI_0 person +DLd6kxxgSUM_0 person +DLkx4w5oteM_0 person +DLmCj6q5vD0_0 person +DL3V2mhMX7M_0 skateboard +DL3eQSTbZ9Y_0 skateboard +DMB6Mr7lTSI_0 person +DMEXGsc-PaU_0 person +DMFEU87_IrU_2 boat +DMR4kX1M_zk_2 elephant +DMR4kX1M_zk_1 elephant +DMTP7OyjdJ4_4 bus +DMT_n1VJG80_2 bird +DMbwyGKLF4c_0 person +DMb-AjUXKe8_0 giraffe +DMiFC67o2P0_1 horse +DMiFC67o2P0_2 horse +DMiFC67o2P0_3 horse +DMn1JpU6MBE_0 person +DMn-kaSNd5Q_0 person +DMuLn7wJTcc_0 person +DM7c57qvjgs_0 person +DNAMMWkSfLY_11 umbrella +DNAjFU24eK8_0 boat +DNB4bgEP-8Y_0 person +DNGlLqzJF6Q_0 person +DNGlLqzJF6Q_1 person +DNOZeC0gZzs_0 truck +DNXuVh_X_qY_1 person +DNXuVh_X_qY_0 person +DNhOrRaOe2M_0 person +DNul7ILzxkQ_0 person +DNul7ILzxkQ_1 person +DN0xWDfCAM0_0 motorcycle +DN1ujoUaAKU_0 person +DN1ujoUaAKU_1 person +DN4TuB3csDg_0 person +DN4e8ljPm1g_0 bicycle +DN5mGCGzOOY_0 person +DN7FitWe9k8_0 person +DN8yb60bxNc_0 person +DOAU-JodN0U_1 airplane +DOAmtFxCuKA_1 person +DODU9JghuAA_0 cow +DORauVZJhAU_1 person +DORauVZJhAU_0 person +DOhLqHOLbQY_0 person +DOiUy3AGiKw_0 person +DOiUy3AGiKw_2 person +DOoTpSSHVho_0 truck +DOoTpSSHVho_1 truck +DOsVwDV787M_0 bus +DOuULWa1RKM_0 person +DOvC_-Yrn5k_0 cat +DPAEt1AqwbQ_1 car +DPCyQOQdLHE_0 cat +DPFO_O_f3hc_0 cow +DPIm8x0i2yo_0 motorcycle +DPJ7ZSWY2Qs_0 skateboard +DPXJpAVtRfM_0 train +DPXJpAVtRfM_1 train +DPZi4DZaTmk_0 person +DPZi4DZaTmk_1 person +DPelBJ73uaU_0 bicycle +DPo9M61p8gI_0 umbrella +DPvxwOvedrQ_1 knife +DPz3CG4lD2Q_5 truck +DPz3CG4lD2Q_6 truck +DP2q1TrqjAE_0 person +DP2q1TrqjAE_1 person +DP6ZB5PxNfc_0 person +DP-JZPR9HFc_2 elephant +DQDV1Wr7qo8_0 bear +DQOglBZHFCs_0 bear +DQZiSQmMBnc_0 bird +DQcCfbTKP1s_1 person +DQcCfbTKP1s_2 person +DQcCfbTKP1s_0 person +bywgcqNg6RU_2 car +by7PLb7MqM0_0 motorcycle +by_OJvQqlKE_0 person +bzKVRbSQpZE_0 knife +bzLdvZQAWgA_0 person +bzO5MBTTrdQ_0 person +bzRELZo9WMU_2 dog +bzRELZo9WMU_0 dog +bzZgsynjAGk_0 cow +bzfE3U02_44_1 person +bzfE3U02_44_0 person +bzimWzymgu0_0 person +bzquVP0NUms_2 truck +bz5Ht4jyT0k_0 bus +bz66OedbeoI_0 person +b0C_2T7-IfU_0 cat +b0GlXXGkfRQ_0 person +b0GlXXGkfRQ_1 person +b0HXAfyZ7Sk_1 person +b0Q3EfK70fg_2 airplane +b0Q3EfK70fg_4 airplane +b0Q3EfK70fg_5 airplane +b0Q3EfK70fg_6 airplane +b0a7ewqE8S4_0 dog +b0nOQfZSaUo_0 person +b0nt17hBmDw_0 boat +b0qXUUs3-WE_1 person +b0t8uuynzIM_0 train +b0xQRq8njAI_0 cat +b0z1nalEX08_0 truck +b0-UOt-DT1A_0 person +b1ETK4nP9ag_0 dog +b1EnXvOZQbQ_0 truck +b1Gd5IWJBRI_0 person +b1R3uk0VLc4_0 person +b1SyeZsSk80_5 elephant +b1SyeZsSk80_3 elephant +b1UAPTD4s74_0 person +b1UpjRRBrTw_0 cat +b1cpAYk99_U_0 person +b1cpAYk99_U_2 person +b1cpAYk99_U_3 person +b17OiOMReIs_0 person +b1-WFxZ7Lcs_0 truck +b2DqNP9s4t0_0 person +b2Tm_7DUimQ_0 person +b2Y6KLIX5vE_1 motorcycle +b2Y6KLIX5vE_0 motorcycle +b2azzMxEH84_0 motorcycle +b2fq5Ba1L8M_0 person +b2fsE3wZfWM_1 person +b2m2gaVpjNE_0 person +b2qNS9qjYbE_1 person +b2tlrwd_LIg_0 person +b28pEbOSeUs_0 dog +b2_dSc2NxNI_0 person +b3KP0d-WX38_0 bicycle +b3KP0d-WX38_1 bicycle +b3KP0d-WX38_2 bicycle +b3R6fHlRZu4_1 bicycle +b3R6fHlRZu4_3 bicycle +b3R6fHlRZu4_4 bicycle +b3SsKosfjOA_0 train +b3SsKosfjOA_1 train +b3SsKosfjOA_2 train +b3UOZHA5jRI_0 cat +b3Z1Ay2o1zQ_0 knife +b3bkNCYQbwc_0 cow +b3p-fFVYM4E_2 train +b3p-fFVYM4E_4 train +b3p-fFVYM4E_6 train +b3tgGsan2vc_0 truck +b3x6f5xFPTQ_0 horse +b3x6f5xFPTQ_1 horse +b3x8Gwk4V8o_1 person +b3x8Gwk4V8o_0 person +b323CLKf_vM_0 person +b34Cdm6l5_k_1 airplane +b34JUq19S0E_2 motorcycle +b34JUq19S0E_0 motorcycle +b34JUq19S0E_1 motorcycle +b344je6lVYA_0 airplane +b35ihWGyz_4_0 cat +b37tPdAEkEw_0 person +b39uBVwcm48_0 motorcycle +b4E8uT19QkY_0 bus +b4E8uT19QkY_1 bus +b4FBbr4Pud8_0 person +b4GXrkSKAdA_0 cat +b4HAPQ_xX5E_0 person +b4HAPQ_xX5E_1 person +b4KwBIif5OY_0 cow +b4KwBIif5OY_2 cow +b4KwBIif5OY_3 cow +b4KwBIif5OY_4 cow +b4UXSjdnqZ0_0 person +b4Xn8--nfvI_0 person +b4aEJNvYqtU_0 bear +b4j8lkkY_lE_0 zebra +b4tTUDVt6Gk_0 person +b42WUwHAKPs_0 boat +b455pPKgTj4_0 person +b5D9lQq3uf8_0 bear +b5IshxZjL7o_0 motorcycle +b5NxbNaAo_8_0 person +b5R1HVvc040_1 train +b5S8Db1Gu7I_1 bicycle +b5S8Db1Gu7I_3 bicycle +b5T_VSM7nbg_0 motorcycle +b5nwFyniymA_0 dog +b5ud9dsnS1c_1 person +b5ud9dsnS1c_0 person +b51dSWD8MF4_0 elephant +b59pPUKW_78_0 car +b5-eXPHW4Mg_0 person +b6AoStVIzkw_2 person +b6IE2imnfp4_0 person +b6MtzhRufn4_2 skateboard +b6MtzhRufn4_0 skateboard +b6RIavVJ660_1 person +b6dVZMAHwro_1 airplane +b6gsIu7Pxbc_0 dog +b6ndIInoIzU_0 boat +b6xUAyNCbdY_0 person +b61MghNCCTI_0 person +b61MghNCCTI_1 person +b65S2P2Pfms_0 person +b66BE9WdQP0_2 bicycle +b7HqfhRNtAQ_0 cow +b7H_n_w2eFQ_0 person +b7Igw_OO-P4_0 person +b7LHlx86tk0_0 train +b7RYkf4oXv0_0 skateboard +b7WQe48-0NI_1 giraffe +b7WQe48-0NI_0 elephant +b7WiE1a8IAM_0 person +b7go-l8jA5s_1 boat +b7hJ62ORLHc_0 person +b7iLQoOKVrM_1 horse +b7ivqvv6s6A_0 motorcycle +b7mawJlPASQ_0 person +b7u0NZEc8OI_1 person +b7ycKg8GLHA_0 person +b71SThzfrDg_0 bird +b78PYqyYWZA_0 person +b8LqaxvNRHw_0 person +b8LqaxvNRHw_1 person +b8VoRclgULc_0 cat +b8aWJIa4RFI_0 giraffe +b8es8BWiC5c_1 person +b8g4M9Yov8M_11 bear +b8g4M9Yov8M_3 bear +b8xtOCMwjJM_1 bird +b8x1qHT8nvE_2 boat +b8yA8bHlrtQ_0 bus +b8yqEFXS8Ck_0 horse +b82N91HYnUo_0 knife +b9O_mJTNj2A_0 train +b9SLHObDJzQ_0 horse +b9Y5tpPv-LQ_0 car +b9iCmG9fIHc_1 motorcycle +b9melHkIeV4_0 bird +b9oiO21MJh0_0 horse +b9oiO21MJh0_1 horse +b9u4WV9ft4s_0 motorcycle +b9wwfAu5DCs_0 skateboard +b96WdT0DXKk_2 bicycle +b96WdT0DXKk_0 bicycle +b96WdT0DXKk_1 bicycle +b98Gs0d8AKo_0 motorcycle +b9-xiVm1Xck_0 skateboard +b9-2bW13faI_0 person +b-Cp0i6fBOU_0 person +b-Cp0i6fBOU_1 person +b-S7G5A0MNI_0 person +b-T0AS7CuxI_1 knife +b-VYy9eEU6w_0 person +b-W1PY33nQg_0 person +b-hT8zKObfM_0 person +b-hqwYjKCH8_0 truck +b-i49sLOjBo_0 person +b-i49sLOjBo_1 person +b-mQajOHUAA_0 person +b-mQajOHUAA_1 person +b-mQajOHUAA_2 person +b-ncxt38EFw_0 person +b-wiIOBccF0_1 person +b-x--HjbnpM_0 knife +b-5K7RwiHdw_3 boat +b-8ARNgk-Tw_0 person +b-_FeNpM_wI_0 person +b_B3oYiBWi4_1 skateboard +b_KBD-NL4Vo_0 train +b_ZVDwMrcEU_0 airplane +b_exMPY7gnM_0 person +b_fR7aS10Z0_0 bear +b_h4xugql44_0 umbrella +b_kksCK6cbw_0 cat +b_n776bwyJo_0 boat +b_n776bwyJo_1 boat +b_vDLf3193s_0 bus +b_1TwBIgwKE_0 car +b_7EvlxDWFc_0 truck +cAARR6q3Qq8_1 skateboard +cAARR6q3Qq8_0 skateboard +cAFqK_6ltXw_0 cat +cAJsxlkMG_s_0 dog +cAJsxlkMG_s_2 dog +cAJsxlkMG_s_1 dog +cAKfCLDFg34_1 person +cASL6wZ33vA_0 boat +cAYIECe6Bvs_0 truck +cAnDryag2FA_0 truck +cAqs3d9KNzk_0 person +cArYvJEUdOg_0 horse +cA0HCmGOK84_8 horse +cBAG9pjaV70_0 cow +cBBDfwkH23A_5 horse +cBBDfwkH23A_2 horse +DQk3Xvbv57I_0 cat +DQqBXfTgqTE_0 train +DQ04rtHIqHQ_0 elephant +DQ7GZOJxra8_0 person +DQ-vQygnOx0_0 train +DQ-vQygnOx0_1 train +DQ-vQygnOx0_2 train +DQ-vQygnOx0_5 train +DQ-vQygnOx0_7 train +DQ_yyvagS0g_0 truck +DRMoOpmUgn8_0 person +DRO4MalcQFk_0 person +DRSSiSNzV7Y_0 person +DRXxJArWrQA_0 person +DRaIGIiQXd0_1 train +DRaX3P2ysBk_0 person +DRhRKwI26n8_0 bear +DRhRKwI26n8_1 bear +DRseWxukwaI_0 person +DRsoi5DxAJk_0 car +DRuDqkZ0zfE_0 person +DRuDqkZ0zfE_2 person +DRuDqkZ0zfE_1 person +DRxLQ6we5YU_0 horse +DRybt0Cgr_U_1 bird +DR0QGL0n_wM_0 person +DR4mzyMklY8_0 skateboard +DR82KhNzs1w_0 person +DR-AMnnLCCQ_0 cat +DR_jo4aSqn0_0 person +DR_jo4aSqn0_1 person +DSAbzYpUW5w_0 cow +DSB9X3bgG2A_0 person +DSCt67aveiw_0 truck +DSCt67aveiw_2 truck +DSEt02E1kJE_0 person +DSM_BlK-ggg_1 person +DSM_BlK-ggg_2 person +DSRGbK9rPbo_0 train +DSWlLGL3xj8_0 horse +DSZkEwhJEI4_0 skateboard +DSaSooZZeAg_2 bus +DSn5-dKW_P0_0 person +DSoRmFNRxiE_0 person +DSoRmFNRxiE_1 person +DSqy2MlVOxE_0 person +DSq0q8dCuCw_0 truck +DS5z-K8Cpzs_0 person +DS-V_NKOawo_0 knife +DTBhYAFcQ94_0 skateboard +DTFg8SeWhbE_3 skateboard +DTYiSIRTXW8_0 knife +DTZkCYvGZ9E_0 person +DTm5L6IAHC4_0 person +DTnIC_Q8YoY_1 boat +DTs2uXh47Xw_0 person +DTtejx1VYBs_0 person +DTvjWj60ixI_0 person +DTvzQwX0KRQ_1 horse +DT4KxrhD89E_0 person +DT7TSCbFXek_0 person +DUAhVOWkluQ_0 person +DUAhVOWkluQ_1 person +DUBzIIKht_w_0 person +DUBzIIKht_w_1 person +DUB3OOi7dQc_0 person +DUHEv94Tyno_0 person +DUHEv94Tyno_1 person +DUHEv94Tyno_2 person +DUPQ3fPhomY_0 person +DUQa7q5NTQI_1 horse +DUZhPq4FiJM_1 person +DUb6-VQcokc_0 cat +DUlYPwiuBrw_0 truck +DUlYPwiuBrw_1 truck +DUmKu-rc7jI_0 person +DUwVOy7IYvA_0 person +DUxGnuYB_GI_0 cow +DU1ww3ryP7s_0 person +DU4acd1_vuI_0 person +DU8jvzO9tEA_0 zebra +DVFfZw4HW3E_0 train +DVFfZw4HW3E_1 train +DVK9BrG_Y_8_0 person +DVOFKTeh9BY_0 person +DVgCgSDZVw0_0 person +DVjOMylPUfU_0 person +DVlEnd5Ra2Y_0 person +DVm_-u6oWwA_0 car +DVqsCPYrMrg_0 person +DVqsCPYrMrg_1 person +DV4GPAloBks_1 person +DV4GPAloBks_0 person +DV79-MpnE1Y_0 person +DWQ0kmCIT0E_0 person +DWZNfCg0W8o_0 person +DWjj9U_lr30_0 person +DWoRZEAFpUI_0 person +DWqyeu4eovM_0 horse +DWuaB5j6-CQ_0 person +DWwGWBcxL0k_0 person +DW1iqzQEWkE_0 person +DW4OTTF7Jc4_0 person +DW8G3A0trOk_9 bear +DXEqDJWN72E_0 person +DXEqDJWN72E_1 person +DXI2AmrILgw_1 cat +DXa15hEKLAc_0 truck +DXgs-pfW-0M_0 train +DXpyVrXMs1w_0 person +DX5AP4s6u0k_0 bird +DX867I2CNRk_0 airplane +DX-PbjeeB6o_1 giraffe +DYJJBRoUlnU_0 knife +DYUiMLisOzs_0 person +DYbb8_mMeLs_0 horse +DYhTdNMuv5g_0 knife +DYkV2TPfOBk_0 truck +DYlrCUMDv_g_0 cat +DYpBOmbclGY_0 person +DYqIQv97tuE_0 person +DYvHdc4rnxk_2 person +DYvHdc4rnxk_1 person +DY0ggbU0cIk_0 person +DY3h0Y3ijmo_0 elephant +DY3h0Y3ijmo_2 elephant +DY6eQdk8jaE_0 person +DZESlirYB3I_1 train +DZGEjl9U78c_0 person +DZIFKtO6y2Q_0 person +DZIFKtO6y2Q_1 person +DZMd9NPNnLE_0 person +DZRZg1gGn1g_0 bus +DZWsGelqCPg_0 person +DZXldsAgY7o_4 skateboard +DZYjfZMMVAE_1 person +DZgbeXD-bZg_0 bear +DZqs7ie6HPU_0 person +DZ3JlgmRHQ8_0 person +DZ4G9EBImOM_1 person +DaMdWu7CyRE_0 person +DaRYBq6zsmY_2 elephant +DagKzwyphZY_0 person +DapmUIRDw3o_0 airplane +DaqVTidNtg0_1 person +DatNYbTqxlw_0 person +Daz5kZBXn5c_1 elephant +Da10JheIcaw_0 person +Da25bjhf1WQ_0 person +DbAZPBnTh3U_1 person +DbGX12xMbWM_0 person +DbNOHXsDP5I_1 boat +DbSGsjNmQ8A_0 cat +DbXz_8anwSM_0 person +DbZGV4ixs2E_0 bird +DbdZugU9GWk_0 bus +DbeCxvMCD-Q_0 person +DbfJ2s7qQJ8_0 truck +DbivV-It_rM_0 person +Dbmwr1_ObHM_0 person +DbnhReILFSs_0 person +DboUAm-F7Rg_0 person +Dbpte835xwc_0 person +Dbqj1XCvcGw_1 cow +DbrGY3BalZ0_0 skateboard +DbrGY3BalZ0_3 skateboard +DbrGY3BalZ0_2 skateboard +DbvkTKJjRj8_0 person +DbwEevYFGrg_0 person +DbzakdG34mg_0 car +DbzakdG34mg_1 car +Db3OG025sz0_0 person +Db74WjMmf-0_0 bear +Db74WjMmf-0_1 bear +DcAxPsNVe28_0 train +DcFWetycnqY_0 person +DcKjrocJ8iM_0 person +DcKjrocJ8iM_1 person +DcOl0Ec1kuI_0 person +Dca5CTtFQZ8_0 motorcycle +DcexSE28IOA_2 person +DcexSE28IOA_0 person +DcexSE28IOA_1 person +Dcfs-bFQcxk_0 person +Dcj-1vKe6iI_0 elephant +DckRd1CpSm0_0 skateboard +DckTHE_Pn5Q_0 person +DcknQtmjIDA_0 elephant +Dclr-tDJMO8_0 person +DcpuJSx5z78_0 person +DcpuJSx5z78_1 person +Dc3yhv5mfN8_0 person +Dc4EXPP0fqU_0 cat +Dc9dWfPxIEM_0 bicycle +DdGvFcujfxo_0 person +DdHWfz7kw4I_0 person +DdJuIi7LexI_0 bus +DdKvI-6rMII_1 person +DdNpi-Pmvgc_0 person +DdNpi-Pmvgc_1 person +DdNpi-Pmvgc_2 person +DdOk9lG9b1k_0 knife +DdUa-CozM14_0 person +DdUa-CozM14_1 person +DdYyeGgXLKw_0 person +DddB5joJQC4_0 airplane +DddRHyvYqFI_0 person +DddRHyvYqFI_1 person +Ddf4T9I0sdI_0 person +Ddz7VVJXgHs_0 person +Dd2qrXASEzk_1 person +Dd2qrXASEzk_0 person +DeCtt_QZqjk_0 person +DeCtt_QZqjk_2 person +DeFuoRV0yCw_0 person +DeFuoRV0yCw_1 person +DeHiMvczAD4_0 person +DeIpwOsUzjw_0 person +DeVZ83g93sE_1 bird +DeViLrLvD1Y_0 horse +DefHSc2VTOo_0 person +DfGzSVv2ELQ_4 horse +DfGzSVv2ELQ_1 horse +DfGzSVv2ELQ_3 horse +DfS7lvAcDQc_0 umbrella +DfS7lvAcDQc_12 umbrella +DfT_7BUGNQA_0 person +cBI2gZhpA-8_0 person +cBMnKBVcoOE_0 person +cBMnKBVcoOE_1 person +cBQJU95uwwM_0 person +cBQJU95uwwM_1 person +cBSbDKv-Z_o_0 car +cBb6VPKgF1M_0 knife +cBeH0xcCCWE_1 person +cBhDn0TkAdc_0 elephant +cBhDn0TkAdc_2 elephant +cBhDn0TkAdc_3 elephant +cBhDn0TkAdc_1 elephant +cBlqBEElvDI_0 person +cBpFzTn_uOo_0 person +cBvZAwlCN4M_1 horse +cBvZAwlCN4M_2 horse +cB1RhnpteUg_3 airplane +cB9XRu3bb_0_0 person +cB_RQN9IXg8_2 skateboard +cCA7llOU4HQ_0 person +cCEUd1IZ6OQ_0 person +cCEUd1IZ6OQ_2 person +cCMe4KdqzeI_0 person +cCaz75u-bCM_0 motorcycle +cCfInBOvqkk_0 person +cCfVriTflG8_0 person +cCnjh5F8dvM_2 boat +cCvpQCZ33xQ_0 train +cCwB7O-yg4Q_1 airplane +cCxZRIxh_yk_0 cow +cC2UgNbG7Rs_0 cat +cC3-bziiNKk_0 cow +cC3-bziiNKk_4 cow +cC4nZNGoC-g_1 horse +cC4nZNGoC-g_2 horse +cDGz5cnIzK0_0 train +cDIc8cs3igI_1 person +cDL0YZ_vXOk_1 person +cDaR5WdXvIo_0 dog +cDfSk2g6wRM_0 dog +cDg-vYWO3AI_0 umbrella +cDvCYN97QYU_0 dog +cDvWWER9oeI_0 person +cD_EAISZcwM_0 person +cD_zwwrcvkI_1 person +cEAwCEnfITY_2 horse +cEFLP7rdZSU_0 person +cEIAg54WPCs_0 skateboard +cEOHFcu3Uic_0 person +cEOqnkbgfMQ_0 person +cEXYVwmcpSg_0 person +cEdeOfPvcQ0_0 person +cEomNeUqQUI_0 umbrella +cErRs5qv8mc_0 elephant +cEyCX-t8Jlo_0 bird +cEyCX-t8Jlo_1 bird +cEzC3hwdO_o_0 person +cE7AS1hrlYA_1 person +cE7AS1hrlYA_0 person +cFBoLads7vA_0 person +cFHTt7uFxH4_4 umbrella +cFOk-AMS2Aw_0 motorcycle +cFOk-AMS2Aw_1 motorcycle +cFkmNa2nYEk_0 person +cFoUf9UmoZ0_0 person +cFq4fzO00qE_0 cat +cFtfKwaxphA_0 person +cFuoJPf6prU_0 skateboard +cFzjl_SiNhg_2 dog +cFzjl_SiNhg_0 dog +cF0SM2Lf82s_0 person +cF7uQwB8sEg_0 person +cF9YklqKEp0_0 cow +cGBOBTCgzP8_3 horse +cGBOBTCgzP8_4 horse +cGCbcyeQqG8_0 person +cGCbcyeQqG8_1 person +cGC4pGWPOUk_0 person +cGC732t-itM_0 person +cGEvxRn1UtQ_0 person +cGNmKg25XMs_0 boat +cGUXUioIa4o_0 person +cGVaIIV18ug_0 person +cGcyxMp1ZQc_0 person +cGcyxMp1ZQc_1 person +cGdeftwBWL4_0 person +cGiVzhQI2a0_0 person +cGpNQ9Vk-5E_0 person +cGtaJVgvTJg_0 person +cG1_sZqy7lU_0 person +cG2fL1nRZmE_0 person +cG5TxH-1Sf4_0 person +cG65cBtyj20_0 cow +cG7BBtumZnQ_0 dog +cHCYX0EqsfE_0 person +cHQLun1YTiM_1 person +cHQLun1YTiM_0 person +cHSjCxvPumA_0 motorcycle +cHWE72lnzZo_0 person +cHYcXW7HAkA_0 person +cHaBQgTFdr4_2 knife +cHjKy80ojXM_2 bear +cHkm25QAG8A_0 truck +cHnV0yZTha4_0 car +cHpaD5PtHnM_0 cow +cHv3ulnF1fo_0 person +cHyjhzLIeO0_0 person +cH2A35uULdc_0 person +cH2g9vV4SyM_0 bird +cH27awicc50_0 person +cH8zYhvzdb8_0 person +cICrfFzHoZs_0 person +cIFXOWG5Dd0_1 person +cIF9coXttVs_0 person +cIIlWssV9Sk_0 person +cIJSKwcTQ10_2 bicycle +cIJSKwcTQ10_3 bicycle +cIPlCULXXHQ_3 elephant +cIPlCULXXHQ_2 elephant +cISwax-t_78_0 person +cIVGJQrNkT8_0 person +cIV9T5ZQmdI_0 person +cIh9baL5Hzw_1 person +cIjMwiaApEc_0 person +cIvqOdvwX6w_0 person +cIwDGqmKrfY_0 person +cJH4RK9aVR0_0 elephant +cJJDfdbopiQ_0 person +cJSjHpF7ILg_0 airplane +cJUj9q6wgis_0 person +cJfW0Gfkzrg_0 knife +cJjaVdNaUko_0 bus +cJnihDxg0wg_1 dog +cJtGcHMJlMA_0 person +cJ0hAba-pck_2 giraffe +cJ0_u3Ta6kU_2 skateboard +cJ0_u3Ta6kU_0 skateboard +cJ2f7qDBm7M_0 horse +cJ41GQMsJIA_0 dog +cJ6BfbrgwDM_0 person +cJ7Akre7-Sc_1 cow +cJ7ZHI-8gU0_0 person +cKO8G1ZXQgo_0 person +cKdank8BDik_0 person +cKgqIdOoBmE_0 person +cK4yj3jgWek_0 person +cK5MabT7iIA_2 train +cK5MabT7iIA_0 train +cK5MabT7iIA_1 train +cK9R8KdVuIE_0 person +cLKgng5yuC4_0 person +cLKgng5yuC4_2 person +cLKgng5yuC4_1 person +cLPSEK3_jEE_2 horse +cLPSEK3_jEE_3 horse +cLPSTXefj2Y_0 person +cLY_N1jEC8E_0 person +cLg1pn5Oh1k_0 person +cLlL2uHDyBw_0 bird +cLnQAhX42Eo_1 horse +cLnQAhX42Eo_0 horse +cLn0Kz_p2U0_0 train +cLrXQvFZ-y0_0 knife +cLvgs19Vm18_1 person +cL2jFa-Zd_M_0 person +cL4k6bdNmbs_0 boat +cL6G_y5LoDo_0 motorcycle +cMGnmOyYWcM_1 person +cMIyGPpW9Xw_0 person +cMJhk7y1Nng_2 bird +cMJhk7y1Nng_0 bird +cMJhk7y1Nng_1 bird +cMOULCqujvs_0 cat +cMRhR707ZfA_11 bear +cMRhR707ZfA_13 bear +cMeXNjQUwe0_0 horse +cMg1O__kPFA_0 horse +cMwsAfZMG1c_0 person +cMwt7xBZ9i4_1 person +cM6-id-uhMg_0 person +cM6-id-uhMg_1 person +cNLuZxPpWho_9 elephant +cNLuZxPpWho_14 elephant +cNLuZxPpWho_1 elephant +cNLuZxPpWho_4 elephant +cNLuZxPpWho_8 elephant +cNLuZxPpWho_11 elephant +cNLuZxPpWho_13 elephant +cNalYSGXOkM_0 person +cNnMvF7oiUo_0 horse +cNr9rjOJ0ps_0 person +cNxEreBWMRc_0 person +cNxEreBWMRc_1 person +cOD8xhwGfME_0 person +cOD8xhwGfME_1 person +cOYK17trE9k_0 person +cOYK17trE9k_1 person +cOZOzY6XDLU_0 person +cOalncX8fwg_0 airplane +cOalncX8fwg_1 airplane +cOalncX8fwg_2 airplane +cOalncX8fwg_3 airplane +cOalncX8fwg_4 airplane +cOkVxYbnFRs_0 person +cOkiG4LRtQU_1 truck +cOp33oi4C8E_0 skateboard +cOzNmIBhiMY_0 person +cO1F_0l1vSU_0 person +cO1MbnbgUbU_0 dog +cO3WA2g_UeM_4 bear +cO3WA2g_UeM_2 bear +cO5xsG3ud_0_0 train +cO7nCAZ-uLk_0 person +cPBvSHKPNvk_0 person +cPdRddyxsVA_0 cow +cPdjr1zTQQ4_0 person +cPeGSXSLepg_0 person +cPkbg5bdpcE_1 person +cPkbg5bdpcE_0 person +cPn5c5t2g6w_3 skateboard +cPqAK1E1Ajo_1 dog +cPqAK1E1Ajo_0 dog +cPsXS3_4zOk_0 bus +cPu-riLrt1c_0 person +cPu-riLrt1c_1 person +cP-gl2IN_AI_1 person +cP-gl2IN_AI_0 person +cP_nenKIU4g_2 bear +Df70QgKA_Hc_0 person +Df70QgKA_Hc_1 person +DgSwJVCLkYM_0 person +DgcSsQKaX7Q_0 person +DgoFmJFWpUw_0 bear +DgtiaphLkMc_0 person +DguiMPx8nn0_2 person +DgvI1azs_0E_0 airplane +DgwM5b-eKvc_0 person +Dg2sU0bmBho_0 person +Dg8r8QlJw80_0 person +DhAkswxLuAs_0 person +DhJZwbql4dc_1 person +DhLD44-KIUU_0 person +DhYbvvwSsEA_1 person +DhYbvvwSsEA_0 person +Dhd-0-xOF6I_0 cow +Dhl-jIQaam0_3 person +Dhl-jIQaam0_0 person +Dhl-jIQaam0_1 person +Dh6APdqkNZ0_0 person +Dh_6tF8ndZs_0 person +DiAj24Xsadk_0 person +DiDELcBJWh4_0 person +DiPjO5frbNc_0 person +DiQ-VgXIDMo_0 person +DiVX_-kQv0k_0 person +DiVX_-kQv0k_1 person +DiWi-oWT9EI_0 boat +DiXsD6VHEr4_0 person +DiZ4OCT30AM_0 person +Dia6QIxORbM_4 airplane +DihnxPkojnQ_0 giraffe +DihnxPkojnQ_1 giraffe +Di41WoS7T1M_1 bear +DjAQs68BiwA_1 giraffe +DjB4dpC4TVs_0 horse +DjD15NlLBYI_1 truck +DjD15NlLBYI_0 truck +DjK1R_LBqgM_0 person +DjMnoAbMiIU_0 person +DjMnoAbMiIU_1 person +DjQF34GUthk_0 person +DjS-0VOep0Y_2 person +DjXtIIwfITI_0 person +Djb2blFeoNM_0 person +DjdAxUWgSdk_0 knife +Dju4Bl2fx88_0 bicycle +DjyldIzPJbA_0 horse +Djy5UE0Ofa8_0 person +Djy5UE0Ofa8_1 person +Dj7DVsCVqqY_0 cow +Dj9npayKJqk_0 elephant +DkAG7dFDk94_0 person +DkC_iJTIrYc_1 person +DkC_iJTIrYc_0 person +DkF-LqA7wSk_0 bus +DkNY4yun6ek_0 boat +DkPYbKRQBE4_1 motorcycle +DkTfU9q9U_I_0 cat +DkTqTY04y30_0 person +DkTqTY04y30_1 person +DkbRBY4ZlFY_0 bicycle +DkbRBY4ZlFY_5 bicycle +DkbRBY4ZlFY_6 bicycle +DkbikYoLycQ_0 bus +Dkmab-wxSy4_0 person +Dkmab-wxSy4_1 person +DknRMqifZFE_0 skateboard +DkpZP7RtrJM_1 bus +Dkqy-okNDVM_0 person +DkrkY6blx3U_1 person +DkrkY6blx3U_0 person +Dk0wXCp-USs_0 boat +Dk1QPiNji5I_0 skateboard +Dk4V0c6Yzbs_1 boat +Dk47lOWl3NM_2 cat +DlCMYyDhSVY_1 person +DlCMYyDhSVY_0 person +DlDFQ88ui2A_0 person +DlDJpNWKuPM_0 knife +DlFJTfO-mc0_0 cat +DlG-VsdsPCk_0 motorcycle +DlTE01-45gQ_0 airplane +DlX2Yvp20gY_0 person +DldXGda7zfE_0 person +DldXGda7zfE_1 person +Dlg5BFm20wI_0 person +Dlg5BFm20wI_1 person +Dl3fDWG23zU_0 person +DmG9v9xVPbg_0 person +DmIeMGzqZEc_0 cow +DmJ9x-DFdqA_0 person +DmJ9x-DFdqA_1 person +DmLGGv6YNEo_1 bus +DmL_6_a_54g_0 bird +DmNmgatXwU8_1 knife +DmSRZp63qTo_1 truck +Dme3Rfsqbz8_0 person +DmiucPhqXMg_1 bus +DmiucPhqXMg_4 bus +DmlMgF-BuRo_0 person +Dmt8pgQG3M4_1 skateboard +DnLVGRyXAR4_0 person +DnN9tjwPn-0_0 person +DnR4VFNo44s_1 airplane +DndaJVRuOoo_0 person +Dniy3zze90s_0 person +Dniy3zze90s_1 person +Dnj_fhGXHC8_1 bird +DnkUzsPqjE8_1 person +DnkUzsPqjE8_2 person +DntJ297deXI_1 person +DntJ297deXI_2 person +DntJ297deXI_0 person +Dnx6TlTvRfI_0 person +Dn80jV69sbs_0 person +DoEWhY2BkZo_0 person +DoOq_FhWze0_0 person +DoPKGr2HJwM_3 bird +DoRoLk97UqY_0 truck +DobAdZVysXc_0 cow +DohloSZ6YdA_0 person +Domgj6ptFOs_0 bus +DpH2eSmcTk4_0 bus +DpJA_qYLobk_11 bicycle +DpJA_qYLobk_0 bicycle +DpJA_qYLobk_2 bicycle +DpJA_qYLobk_5 bicycle +DpJA_qYLobk_6 bicycle +DpJWhFnF2Fo_0 dog +DpR63uhHTjo_1 horse +DpWw1SaCdTQ_0 person +DpbGsvglx7Q_0 elephant +DpbGsvglx7Q_1 elephant +DpimIW1T2Sw_0 person +Dpp32dLn0hQ_0 person +DpvuhymOiUM_0 person +DpwjQ_KcYAc_0 person +DpxoJ_GWJA4_0 giraffe +DpxoJ_GWJA4_3 giraffe +DpxoJ_GWJA4_4 giraffe +DpxoJ_GWJA4_1 giraffe +Dpz-s6E9VWg_0 person +Dp2pGcutqDQ_0 person +Dp2pGcutqDQ_1 person +Dp4XaG6247k_0 person +Dp5KRKUJBGE_0 cow +Dp6qJvgV4fQ_0 person +Dp71z8eyq7o_0 bus +DqBNoutsr4M_0 person +DqBNoutsr4M_1 person +DqDElT9H4Tg_0 boat +DqESUtRuhPw_0 dog +DqVUeH6XI2Q_0 person +DqegnRXQd5Q_0 airplane +Dqi5KTmt04s_0 bus +Dqy6NbRkVPE_2 skateboard +DrAnw0S9Pmc_0 person +DrCKp4YB7rI_0 person +DrE7aW7O0eQ_0 person +DrFxlXYC6-o_0 person +DrGCtlmxxVc_0 person +DrPpkd-UxFY_0 cat +Drc0Grdb_LU_0 cat +DrgjySu3e-c_0 motorcycle +Dr9XXUA4UKc_0 person +Dr9XXUA4UKc_1 person +Dr--We7lD3I_0 person +DsA5QOOIZJw_0 person +DsP87b0IuoU_0 person +DsZ6Cf42EdQ_0 person +DsiAcCUi8iE_2 bear +Dsm48Msjw6k_0 bird +DsxyH6AKBd0_0 truck +Ds0GIUe1AFo_2 person +Ds0GIUe1AFo_0 person +Ds0GIUe1AFo_1 person +Ds3E7n1kRQk_0 train +Ds44yYfSEr8_0 bird +Ds8xwquSVkw_0 skateboard +DtKSEQhjq2I_1 cat +DtQGDwZ1PIU_0 truck +DtQGDwZ1PIU_2 truck +DtSpyLMbD9o_1 motorcycle +DtU93_s53sI_0 train +Dtc3hZBmn9Q_0 person +DteEg93cINc_0 person +Dtf2WRyd4OA_0 airplane +DtgUpKmdw_g_0 person +DtuRiD_E6HU_0 person +DtyatJX8J1A_0 bicycle +Dt1MDqN3TCs_1 elephant +Dt1PLFoRvoM_7 airplane +Dt1PLFoRvoM_0 airplane +cQAr7IVeBrU_0 person +cQC7jBc1pC0_0 person +cQIviFGN-_M_0 train +cQOFvBNN9to_0 airplane +cQOFvBNN9to_1 airplane +cQPP6SqX-uk_0 truck +cQbqByuUnW8_1 car +cQgUGmyvkJ8_0 train +cQttS-GIM5c_0 person +cQttS-GIM5c_1 person +cQw1wXvFnLM_0 person +cQ29m5z8Cnk_1 cow +cQ4aR8OLr74_0 motorcycle +cRGrqg7y9tE_0 boat +cRVqyVvxjHI_0 train +cRczdkzrJ-w_0 cat +cRnDFinbH-s_0 bird +cRrjU515FKg_0 person +cRvAv1Nn-WQ_0 cat +cR6qM7wjtDw_0 knife +cSDafQMsYwc_0 cat +cSJ2ISog6Pw_0 bird +cSJ2ISog6Pw_1 bird +cSLerMX3IBg_0 person +cSNwXF8OcR8_0 cow +cSO-70KCypM_0 skateboard +cSVIvCYuDtU_0 cow +cSdBaGsGWKk_4 bird +cSdBaGsGWKk_9 bird +cSdBaGsGWKk_1 bird +cSdBaGsGWKk_3 bird +cSdBaGsGWKk_6 bird +cSdBaGsGWKk_7 bird +cSdUwiTGXPc_2 motorcycle +cSor-u6VHHw_1 dog +cSqMDH0-sDs_2 person +cS398dAyQ9k_0 cow +cS-QgqiUgLQ_0 person +cS-QgqiUgLQ_1 person +cTGOQnmi7bo_0 person +cTLa1dxk76g_0 person +cTUTNgp9rZ4_0 person +cTUTNgp9rZ4_1 person +cTayBCWq6xo_0 person +cTiETDBrGv4_0 skateboard +cTiETDBrGv4_1 skateboard +cTk8pacLUcc_0 bus +cTmv-vp89sY_0 elephant +cTmv-vp89sY_1 elephant +cTsipIh7xF8_0 cow +cTvxGA-EvvY_1 person +cTzz_ZCUpxc_0 person +cT4Y0HSeBgg_0 elephant +cT5UlPnc5MQ_0 person +cT5UlPnc5MQ_1 person +cT7LjXG7ByI_0 airplane +cT7LjXG7ByI_1 airplane +cT7LjXG7ByI_2 airplane +cT7kZP5B_2s_0 bus +cT_US5II64I_0 person +cUEWtKzcAsM_2 airplane +cUEWtKzcAsM_1 airplane +cUM5ajI3KJg_3 horse +cUNExkBml18_0 person +cUSRVmcbXxI_0 person +cUS9QgCXcPo_0 person +cUWmN_HuZiA_0 person +cUYlfMGqB_8_0 dog +cU7JEUo5qdM_1 person +cU7sT9UHs7s_0 person +cVCqOzgt2vI_2 train +cVCqOzgt2vI_0 train +cVM2h5qbyUw_0 elephant +cVXIaONp5o8_2 person +cVYqiMXSh9g_1 person +cVbcrOx7768_0 person +cVfH0tFh5Kc_0 person +cVfWBtl-qK4_0 truck +cVq5VnfZtNw_0 person +cVr16pInr5k_0 person +cVsZMfMaxSM_0 person +cVtyGQKWFcI_0 motorcycle +cV0a2ScBxpE_0 person +cV0a2ScBxpE_1 person +cV1mBGRlLe8_0 bird +cV1szYodba0_0 motorcycle +cV8BGLBROa8_0 person +cWBCCAo3pUM_0 bird +cWBTkrImlLQ_0 train +cWBTkrImlLQ_1 train +cWGCbw5I6cI_0 skateboard +cWIDcoPB3Rg_0 person +cWKf_KANUSM_0 person +cWRO27zzxF4_0 person +cWaVXNQ5cvg_0 person +cWb-i8hj8uc_0 person +cWcJrAQuNA4_0 bird +cWtIT6V98zc_1 person +cWxELKsh43s_0 person +cW2hQE3lS9k_1 person +cW4fmuV2JuU_0 skateboard +cW7OrsSn-m8_0 person +cXP1Lit5Pmk_0 person +cXS9VytLIjM_0 cat +cXT5_AFSI8Q_0 person +cXUdqfIp-Hs_1 person +cXUdqfIp-Hs_2 person +cXWgDE6boPQ_0 person +cXZt2UZe6QQ_0 motorcycle +cXaAcHkHUzU_0 person +cXsRP67GHA0_0 person +cXsRP67GHA0_1 person +cX0yQ5KIAKw_0 person +cX3mnglolLE_2 elephant +cX3mnglolLE_3 elephant +cX6lyv1DI80_1 airplane +cX-s4BNxb0c_0 person +cYHq8xoYMO4_1 bus +cYVLbgGxJMM_1 person +cYnyDXx580I_0 person +cYpas0B5zEo_0 cow +cYvyTVEqiEU_0 giraffe +cYwkpA75A8Y_0 person +cY1cmlwRnaE_2 bicycle +cY1cmlwRnaE_1 bicycle +cY6HDOEiINs_0 skateboard +cY_INarfLQ4_0 person +cZA_Yoq3vy8_0 person +cZB5MQY5kVA_0 skateboard +cZDoXwn5lv8_1 person +cZPvtKaqRxc_0 person +cZU2LAWtwUM_0 knife +cZZT6OJ6xGk_0 horse +cZZT6OJ6xGk_1 horse +cZe888DWA8M_0 person +cZgt8s4mARc_1 person +cZugy4cYVng_0 cat +cZz6eOuSV9Y_0 person +cZ155yARalk_0 person +cZ155yARalk_1 person +cZ7siEIFHlI_0 cow +caAnHYU-Gwk_0 horse +caGQ2b4L930_0 person +caGzwv3HLKU_0 skateboard +caLKu0yKW0Y_0 dog +cacCjMLNpIg_2 bird +carYHHE3y3A_3 knife +cavT34ZvciI_0 elephant +ca4_gKs6MN0_0 bear +ca8aNafTzeY_0 person +ca_weHSJH80_1 train +cbRztq6KZn0_0 horse +cbVll1hxlDA_1 person +cbVll1hxlDA_0 person +cbvbRxOMJ-A_0 truck +cb6YFX4CVqc_2 airplane +ccIWh5JBil8_2 bear +ccIWh5JBil8_0 bear +ccQ7JnYrTL8_0 bird +ccQ7JnYrTL8_1 bird +ccRdzj5Zi-U_0 person +ccR-h9z3bRI_1 knife +ccR-h9z3bRI_2 knife +ccVJXErLdOo_0 dog +ccWTUq_mvsU_0 elephant +ccWTUq_mvsU_1 elephant +ccaCWXJ0jKY_0 person +ccaYdn2p4Uk_6 knife +ccaYdn2p4Uk_10 knife +ccfTQmE0zsA_0 person +ccfTQmE0zsA_1 person +ccwFXG9D98w_0 person +cc0S9924O-s_0 skateboard +cc76qcSHNMM_1 dog +cc76qcSHNMM_0 dog +cdBO6xYUmzE_0 person +cdBO6xYUmzE_1 person +cdKEh34fsYk_0 person +cdNWg2zU6bY_0 person +cdOQ7lTQJBw_1 cow +cdOQ7lTQJBw_2 cow +cdSG1fcxNAA_0 person +cdS-7_Egk88_0 person +cdW8PgwFm6o_0 motorcycle +cdZqtqh5PwE_1 person +cdZqtqh5PwE_0 person +cdZ1ODMJYKM_0 bird +cdbmvoa89QU_3 train +cdbmvoa89QU_4 train +cdbmvoa89QU_5 train +cdf-C-P2bW0_0 elephant +cdkSgKIMQEM_0 truck +cdkSgKIMQEM_1 truck +cdoGDD6m8Og_3 person +cdpYTik8eL4_0 person +cdruQqCvfrI_0 truck +cdxkCeoDX6Y_1 person +cd80Ii4FB1Q_0 bird +ceH46gqMWak_0 person +ceIoRNo5FBk_0 person +ceIoRNo5FBk_1 person +ceLI06w8-Yo_0 person +ceVkcz1wysc_2 dog +Dt5UnNOUlZA_0 motorcycle +DuMGrFowOWE_0 airplane +DuUmKpZym5U_4 boat +DuV6ahfZ_yw_5 knife +DupWsV-iiys_0 knife +Dur1W4FemFs_0 person +Du7sKt25RiA_1 knife +Du8hVxuK10c_1 airplane +Du8hVxuK10c_2 airplane +Du8hVxuK10c_3 airplane +Du8hVxuK10c_4 airplane +Du9r_1zpPkA_0 person +DvEWbWxGJvQ_0 bus +DvEykMsNibg_2 bicycle +DvIS9FV5pag_0 person +DvIS9FV5pag_1 person +DvKLYYQzmas_0 person +DvNTMqUwwWo_0 person +DvR9Ctfk8lg_0 person +DvWCGbG9LT4_0 car +DvWDBQ9eMNQ_0 elephant +DvWDBQ9eMNQ_2 elephant +DvuQOS7UVI0_2 elephant +Dv1e0Y8A8yg_0 cow +Dv4azGPr4YI_0 truck +Dv7eGdF004Y_1 person +Dv7eGdF004Y_0 person +DwJntGNV4Gw_0 person +DwWzbtiIs7k_0 skateboard +DwhCZK1eUPw_0 person +Dwi-kq9Gcsw_0 zebra +Dwi-kq9Gcsw_1 zebra +DwlOBOv0IC8_1 bicycle +DwlOBOv0IC8_0 bicycle +DwvclcpHQNY_0 horse +DwzuhLu_Jew_0 bicycle +Dw2QHLXWmos_0 truck +Dw7BXQFtH60_0 person +Dw8lXatl4wE_2 person +Dw8lXatl4wE_0 person +Dw8lXatl4wE_1 person +DxAMNpw-4qg_0 person +DxB962sZJ_c_0 airplane +DxB962sZJ_c_1 airplane +DxB962sZJ_c_2 airplane +DxFjGsjegtk_0 person +DxHhkA1fVdA_0 person +DxPOOsSCJpc_0 cat +DxU9ZTI7KzY_0 bird +DxXEapsjhOg_0 cow +DxYW3ZMCXUw_0 person +DxegJbsalCo_0 person +DxegJbsalCo_1 person +Dxl8-fknJjM_0 bird +Dxl8-fknJjM_1 bird +DxmdjAoDhkE_4 knife +DxpMePWSgjs_0 person +DxsdKCCUvCY_0 person +Dxw3Y-UB0jk_0 airplane +Dx0fgXYBRV0_0 knife +Dx4a9ZiekrQ_0 elephant +Dx4a9ZiekrQ_1 elephant +Dx5VMmCltKo_0 person +Dx8eIjF--eo_0 person +Dx8eIjF--eo_2 person +Dx8eIjF--eo_1 person +DyFNZgEaw24_1 bird +DyZHVNsbZeE_0 person +DyceiTbkpMw_0 bicycle +Dyd1Aj3RO3I_0 cat +DyfyfDI4jqk_0 person +DytAOZD9DLU_1 person +Dy1-ch56AMc_0 boat +Dy5kD11Wnbk_0 person +Dy5kD11Wnbk_1 person +DzAi_cumPY4_0 person +DzCPCgkI8XA_0 motorcycle +DzCPCgkI8XA_1 motorcycle +DzFhvnd07Ck_0 train +DzKdERTAA8U_0 cat +DzMXxF7XRaI_0 person +DzW2oC31Gcs_1 person +DzXDPH8p-6Y_0 motorcycle +DziXgWdCrvY_3 horse +DzkCtRPiI-Q_0 cat +DzlPtZXxtpU_6 elephant +DzlPtZXxtpU_4 elephant +DzlfBATujA8_1 horse +Dzp0BrJSMBU_0 person +Dz0d79BMerc_0 motorcycle +Dz34hVhjpzA_0 person +Dz7kWPDxgbg_1 bicycle +Dz73CrM7pH8_0 person +Dz8_y0iOjLM_0 skateboard +D0DtV2eD7cs_0 knife +D0HGjOZ5XWU_1 elephant +D0O-T4E2DVo_0 cat +D0R59ANL6o4_0 person +D0TQLmGtPm4_0 airplane +D0TTR7qCVXQ_0 person +D0WAC7ByU0M_0 person +D0Yx5cLcrqk_0 skateboard +D0mf15dFGhk_0 person +D0pcdPd6hwY_0 dog +D0qo2f2Cshk_0 person +D0xc1K3BQnQ_1 bicycle +D0zhUpZhZi4_1 airplane +D04tMZ7n3YM_0 skateboard +D09x5ezi5hU_0 elephant +D0-sW80X3kI_1 elephant +D1Ct81qiyT4_0 truck +D1Ct81qiyT4_1 truck +D1DYQay-d_E_0 cat +D1IQfkEa2-8_0 truck +D1KUzeiWmUE_1 cow +D1XPuPzMvv4_1 bus +D1cTj9Fy4yE_0 dog +D1dWoFMnKhc_0 person +D1f92BE9HmI_0 person +D1ktXwG0_jM_0 person +D1plKiNFzvI_0 cat +D1tZzoBOWfA_0 person +D1yVIEgFGrY_1 airplane +D10WSuM8eqU_0 person +D19A7AUqZJ0_0 person +D2CXHzxp1TU_0 cow +D2Iqqb3RP6c_0 person +D2Iqqb3RP6c_4 person +D2Iqqb3RP6c_2 person +D2Iqqb3RP6c_3 person +D2KcVzav3YU_2 airplane +D2KoBI6R7W8_0 train +D2Qw63hsi1E_3 bear +D2RT-qUSw_U_0 dog +D2RZP8Y6VT8_0 dog +D2Ri5Wy9XPQ_0 person +D2RkdlTKlsE_0 person +D2VABHjSM6E_0 bus +D2VABHjSM6E_2 bus +D2co1ZGkwCs_0 skateboard +D2rbERtPxNM_0 person +D2t36StaDcc_0 elephant +D2t36StaDcc_1 elephant +D2wSgbAelUc_0 cat +D2yQaYJDNvs_2 bicycle +D2yQaYJDNvs_0 bicycle +D24GJS9nKC0_0 person +D3EIh6pBTdQ_0 train +D3F3xWCoWD8_0 person +D3IDGSQSrFY_3 giraffe +D3IDGSQSrFY_4 elephant +D3IDGSQSrFY_5 elephant +D3IDGSQSrFY_7 elephant +D3IDGSQSrFY_8 elephant +D3OvvA5jYlM_2 bird +D3OxudXglSM_1 cow +D3XqhAXefSA_0 person +D3Zg90Ib5GI_0 cat +D3b-w5J-wR0_0 person +D3tuGaFbdbE_0 person +D36Pwfuad5E_0 horse +D4CWBceBJEk_0 person +D4OMvYw25w0_0 bus +D4aL-0UevEY_0 person +D4do8kCWydY_0 person +D4do8kCWydY_1 person +D4goZXgzVC8_0 person +D4oLradsvXE_0 person +D4qq5Olmh24_0 person +D410FuTGoPI_0 bicycle +D4_2g_M4CXM_1 person +D5GNIcodIw0_0 bird +D5KLVLNs7-0_0 train +D5KWKhPhqWE_0 dog +D5OtHFsiXiI_0 person +D5UGpkiG-CQ_0 person +D5hYrAC2iIg_0 person +D5jUPc4nQO0_0 person +D5kSwHOWPBU_1 bird +D5kSwHOWPBU_0 bird +D5n4B-O8y8g_0 person +D5tLtHWe0Jk_0 person +D5uTmoMYXDE_0 cow +D5x402SaAk8_0 truck +D537kaRoYEk_0 person +D552mK5tfLU_0 dog +D59Eb3u0iPs_2 person +D59Eb3u0iPs_0 person +D6EDJA1bO3s_0 zebra +D6G1X8WFAA8_0 person +D6LDq6Q1Aic_0 person +D6NzaXWZGEA_1 person +D6UsriFwkjQ_0 person +D6XIhwBoaik_0 person +D6XUUDKA1CA_0 person +D6d20KAVyzk_0 person +D6f2wdAt_Ug_0 person +D6kIRV5rEPk_0 person +D6qXaD6WnVQ_0 bicycle +D6zUwxeZ1zU_0 person +D7c2tRlXz5k_0 skateboard +D7dAkMkQf4I_5 elephant +D7kHPyS4Gw0_0 person +D7r_HLTwhWY_0 person +D71B5jrYOig_2 elephant +D77yNiFrtmw_0 person +D78FDAi2log_0 skateboard +D7_S2hp6aKI_1 airplane +D7_S2hp6aKI_0 airplane +D7_tUVFGy2o_0 person +D7_zjfakeYM_0 dog +D7_zjfakeYM_3 dog +D7_zjfakeYM_4 dog +D8GQWYiVK1U_0 dog +ceczRgI6HDM_0 boat +cev1umQFsVA_2 person +cev1umQFsVA_1 person +ce8j1r_CDH8_0 dog +cfD9yGF5XmY_0 car +cfFAjaziwn4_0 person +cfWqngaDvvg_0 person +cfWqngaDvvg_1 person +cfex3QJFkTY_0 dog +cfex3QJFkTY_1 dog +cfpiw6KGB70_0 dog +cfyY4mfwN7A_0 airplane +cf0a6xp7r9s_0 bus +cf3VOLwZdKY_0 dog +cf6daxmvx6M_1 person +cf6kCO9JdOM_1 person +cf6kCO9JdOM_0 person +cgAiH_9c5DU_1 bird +cgD7Gr2Y-c8_0 person +cgQ_34JYUkU_0 car +cgT26vQK-4A_0 person +cgZo7nUeCNE_0 bus +cgjjdvXBsFI_0 person +cgj_bzL4vsQ_0 skateboard +cgmkRlhxVQ8_0 person +cgmkRlhxVQ8_2 person +cgmkRlhxVQ8_1 person +cgxIrs3ySiA_0 skateboard +cgyRQ1a79c0_0 train +cgyRQ1a79c0_1 train +cgzHPxfb-R4_2 person +cg4GIYiUNiI_0 person +cg9Y2DTUiDQ_0 cow +chc30sNO6KA_0 person +chl-Wa4_hic_0 person +chrXgx4NWck_0 person +chrXgx4NWck_1 person +chwYzLEqKp4_0 person +chyVy1kdL5M_0 person +ch_yUR9RHIM_0 dog +ciEhviIYSFY_0 bicycle +ciFKNPdVskg_0 airplane +ciUZ2LoiaCs_0 person +ciZNBF9RdaA_1 knife +ciZNBF9RdaA_0 knife +ciZNBF9RdaA_2 knife +ciZNBF9RdaA_4 knife +cifpYBLq6dM_0 person +cit4hdvCIp0_0 motorcycle +ci83tdO3GuM_0 horse +cjAhjjWOj24_1 cat +cjL-hMHdmN8_0 person +cjdImYwFXEI_0 person +cjlPNeNKoSo_0 car +cjmps6UKu_Y_0 person +cjtjQu1YoTc_0 person +cjuRQJf1_qs_0 horse +cjvMLM_Uzbw_0 person +cjye6t7P2XY_0 person +ckIaNsLDst8_0 person +ckJHbJCefVc_0 bear +ckY7Izfnggc_0 person +ckfgZsmJEbs_1 elephant +ckyL1lkCzU8_0 person +ckzaUAcrtY4_0 person +ck6hJJVJfvQ_1 person +ck6hJJVJfvQ_2 person +ck6hJJVJfvQ_0 person +clCQhmV8nf8_0 person +clL4lyl6J7I_0 person +clO2SRgOzAk_0 person +clQ98CON1pE_0 person +clUGOwaYaPg_0 cat +claqhrkmhPg_0 person +clmsmTFOSLo_1 dog +cl410aCQA8k_0 train +cl6C5KiOEHQ_0 train +cmAN1SqRkDM_0 person +cmGz-63gi5Q_0 train +cmHjbUBM4q8_0 elephant +cmKnHqPGlTw_0 person +cmV1BLuEvpU_0 cow +cmeGuaSUg34_1 car +cmqxX05lPiI_0 person +cmtruoCpSec_0 person +cmwRk4-z_BQ_0 person +cmwzhxa6Kd8_0 boat +cm7Xd_WXZAs_0 person +cnAC9g_fYUY_0 train +cnAC9g_fYUY_6 train +cnAC9g_fYUY_1 train +cnAC9g_fYUY_3 train +cnAC9g_fYUY_7 train +cnAC9g_fYUY_8 train +cnAC9g_fYUY_9 train +cnJKH5dTKyI_0 skateboard +cne8MAKWcjo_2 person +cne8MAKWcjo_1 person +cnoIwn3cQ7Q_0 bird +cnplEeb8Iuk_0 motorcycle +cnp30cLXzq8_0 skateboard +cnrSdMSCW6w_0 truck +cnrSdMSCW6w_1 truck +cnrSdMSCW6w_3 truck +cnryAbqs0sM_0 horse +cnryAbqs0sM_2 horse +cnt7MyeNlHA_0 person +cnvzLGyGalU_0 cow +coBLne1vSV0_0 person +coDrWV3qbQE_1 car +coIhjdND3yY_0 person +coVT-MPjIsc_1 cat +cobC6BjJahk_0 person +codE_-LtIRY_0 boat +cofwfK4F5ac_0 person +cohdkT2S_oA_0 skateboard +coh6clK_Q6A_0 person +comEv_WJ4Uc_0 person +cousEghehEo_1 person +cousEghehEo_0 person +co17Vvf3bag_0 knife +co17rRdOvwc_1 motorcycle +co5rBTsE2i0_0 knife +co7SR4bgOM4_0 knife +co9DJtEU4eg_0 person +cpEYJnyJ9XM_0 train +cpLmgivniko_3 knife +cpLmgivniko_2 knife +cpO5pHTOelo_0 cow +cpQ9HawKR-Q_0 airplane +cpQ9HawKR-Q_1 airplane +cpUTjBksgdA_0 person +cpmMEngbDHE_3 person +cpmMEngbDHE_0 person +cpmMEngbDHE_1 person +cpnZFfnjGYs_0 car +cpre_wIt0hs_0 train +cpre_wIt0hs_1 train +cptcOzotQ0E_0 person +cpuYK9y7zu8_1 boat +cpxkLEREnwo_0 cow +cp4ttild7EA_0 train +cqEdqz5F7tg_0 cat +cqOLpxxqIBw_1 person +cqOLpxxqIBw_2 person +cqOclzkqkVg_0 person +cqO2VRSBGGg_0 bus +cqRNPM3jgNs_0 cow +cqS_ZvZF4Kk_0 person +cqS_ZvZF4Kk_1 person +cqez5FuSf44_0 person +cqf4Vh7Vy9M_0 person +cqkZZqtr3z8_0 person +cqkZZqtr3z8_1 person +cq3TwUTSBFA_0 horse +cq84vJoKj0A_0 person +crXlnYSuCuw_0 person +crgSyPjbLBw_0 person +crh-ncEjMd8_0 umbrella +criMO4N0K5E_0 person +crmw_2KCRlY_1 horse +crmw_2KCRlY_0 horse +cruWABLWvD0_0 person +crzo7x07GTs_1 elephant +cr02TlSWnkI_6 elephant +cr5ddm3njdQ_1 bird +csGJS_sNJx4_0 person +csKSGFZyk04_0 horse +csTChnltOdg_0 cow +csiWQna-zcg_0 skateboard +csl1NFlhS0I_0 person +cswk8vZ6th8_0 person +cs16RhEpmu4_1 person +cs16RhEpmu4_2 person +cs3PfcpDro8_0 cow +cs_yLDexfXk_0 person +ctAtCH6V1Dw_1 person +ctAtCH6V1Dw_0 person +ctCQsTBheHg_1 person +ctJATSvGLTo_0 elephant +ctJATSvGLTo_4 elephant +ctJATSvGLTo_1 elephant +ctJATSvGLTo_2 elephant +ctK8CQu6Nvg_2 boat +ctLUri8cnqU_0 bear +ctNE8tj4Z18_0 truck +ctOTsI_RZps_1 person +ctOTsI_RZps_0 person +ctPfu5shFA0_0 person +ctPfu5shFA0_1 person +ctRpeLVhC50_0 bicycle +ctWUEkluOFo_0 truck +ctWrHmTAoxw_4 dog +ct24BXc-tWg_0 person +ct8_KhvMuHo_0 motorcycle +ct_TbfWVBQc_0 person +ct_TbfWVBQc_1 person +ct_TbfWVBQc_2 person +ct_TbfWVBQc_3 person +ct_vznHYblc_0 airplane +cuHFcWEuUNo_0 skateboard +cuQ5swAtzfk_0 person +cuRuiFR7bNY_0 person +cuU3htRHPgM_0 person +cuWjLEIrs8k_5 bus +D8btdwmdRNU_0 knife +D8sBFUu104g_1 knife +D8urBZQXl6o_0 person +D8wVRKGVcLw_0 dog +D804JptI7_4_0 motorcycle +D8-J5NgmOQg_0 person +D9J-SuKzTU4_0 bicycle +D9RlyV_QhoQ_0 bear +D9WsxKDzM80_1 horse +D9WsxKDzM80_3 horse +D9WsxKDzM80_5 horse +D9XDsr6tkug_0 dog +D9XDsr6tkug_1 dog +D9XwHuLUv_E_0 car +D9ixoNe1mQ8_0 person +D94_XdBnfjQ_0 horse +D97nupvam-4_0 person +D97wkVsbfJk_0 person +D97wkVsbfJk_1 person +D98TSSeEEXc_0 person +D9-PVz9eRtA_0 person +D9-PVz9eRtA_1 person +D-DNyYPMTvE_0 car +D-EA0oKq0qI_0 cat +D-UToJ9lT9w_0 person +D-YgpB48Efg_0 person +D-YtknfK7cQ_0 person +D-a0sdpLGlI_0 umbrella +D-gTVzHdFAE_0 bus +D-gxEOUdm98_0 person +D-jl7sUktcE_1 person +D-pfJT6Nyfo_0 person +D-pfJT6Nyfo_1 person +D-u2wEUntuI_0 person +D--GMbo7meg_0 person +D_FozyNGP_g_0 person +D_OvU_wvmsg_0 skateboard +D_QDxlwnenM_0 bird +D_TbGwH_U4I_0 person +D_XHitiDPXI_0 person +D_XwOiOHuZU_1 person +D_XwOiOHuZU_0 person +D_g7kf5F2CE_0 motorcycle +D_kMPno6xDw_1 person +D_r43ev6HHs_0 airplane +D_uO4kxnCwM_0 train +D_vXQa4wYoY_0 person +D_vxl0ffX4U_6 bicycle +D__WGD95lSY_0 cat +EABbbYMrVPo_0 person +EABxiYRLhro_1 knife +EANBKNPscIU_1 dog +EANBKNPscIU_0 dog +EATgn3uQFCc_0 truck +EAecqVilQ60_0 airplane +EAh-eJriiEM_0 cat +EAlTNLBenas_0 elephant +EAmeB0UClfE_0 person +EAoS9E3JQM0_0 knife +EApLpwcDY04_0 cow +EApLpwcDY04_1 cow +EAvGskBbSsI_0 person +EAvUn45orps_0 person +EAvhz7EUrHs_1 person +EAvhz7EUrHs_0 person +EA2Zq7j78Zw_2 horse +EA33eNV3TsM_0 bus +EA4Pppxm9q8_2 airplane +EA9IwJGPZFo_0 person +EBBWzGDSfhQ_0 train +EBCEcy1RAZU_0 bear +EBDSyGzaeVM_0 person +EBDSyGzaeVM_1 person +EBGwUwk8_KI_0 motorcycle +EBL5WSEhHwQ_0 cow +EBTH0ShVz5s_1 horse +EBYJEkaJizQ_0 truck +EBmABlnU3Ns_0 person +EBpvJEz7GAs_0 cow +EBqxBh52uek_1 person +EBrNePUYA80_0 cat +EB0XdJ6nl5Q_1 bear +EB5sThk9G-k_0 person +EB7yZ9myXmo_2 horse +EB7yZ9myXmo_1 horse +EB-GUW188Kc_0 person +ECDxDS-R1ZU_0 train +ECEv0inW5Cs_1 dog +ECKwTK9kBHk_0 cat +ECLYb63wsdY_0 person +ECT7_2qKJJw_0 person +ECUpMJzxafs_0 person +ECXdLGCGSRU_1 person +ECdvMn526ho_0 skateboard +EChWuqD2kxc_0 person +ECofUr-jIIU_0 person +ECpmJNOAfZU_0 person +ECuo32_WqfU_0 person +EC0Q7uMrJh0_0 cow +EC1pupdSC2Y_0 person +EC-RADUn0SA_0 skateboard +EC-RADUn0SA_1 skateboard +EDBYWaa97hs_0 person +EDUY2xl1Jkw_0 cat +EDYGYkJTUAw_0 person +EDZ9Cu6WUAU_1 horse +EDcpyGbwAVs_1 train +EDcpyGbwAVs_2 train +EDqFOrLwfpE_0 elephant +EDqFOrLwfpE_1 elephant +EDrX2_SzLF8_0 elephant +EDtN3eOjUXg_1 motorcycle +EDvdnYUw9b0_0 person +EDxj4RwQr7k_0 truck +EDxj4RwQr7k_1 truck +EDxj4RwQr7k_2 truck +EDxj4RwQr7k_3 truck +EDxj4RwQr7k_5 truck +ED-QWlNA_QI_1 person +ED-QWlNA_QI_0 person +EEFgTj2V6IY_0 person +EEMkBuPFopc_0 person +EENkey7gvFA_0 cat +EENyo-VOtiA_0 person +EEQVWkmTS6A_0 person +EEQVWkmTS6A_1 person +EEfWTq58rX0_0 motorcycle +EEfWTq58rX0_1 motorcycle +EEiUwF9ID5k_1 elephant +EEiUwF9ID5k_0 elephant +EEiUwF9ID5k_2 elephant +EEiUwF9ID5k_5 elephant +EEnpnVNwpgk_0 person +EEnpnVNwpgk_1 person +EEn1JwzcH7Y_0 person +EEtv5FqPqG0_0 motorcycle +EEx5nPfhJdI_0 bear +EE5owiH92Io_0 bird +EFHnwo5U2Bc_0 bird +EFHnwo5U2Bc_1 bird +EFTcDwwNw_M_0 person +EFd6XVMNdEk_0 umbrella +EFpWVH06Tf4_3 motorcycle +EFpWVH06Tf4_1 motorcycle +EFpWVH06Tf4_2 motorcycle +EFryCLs5aWc_0 person +EFwar_GkK6Q_0 cow +EF0hPkNXnoA_0 skateboard +EF1htFUPo80_1 bus +EF23dhLqzKk_1 person +EF23dhLqzKk_0 person +EF4KGrH7s08_1 train +EF4KGrH7s08_2 train +EF4KGrH7s08_0 train +EF8PHVKHaq8_0 person +EF9VafNyS20_0 person +EGCQIKdLkIU_1 train +EGHYSrxI1Ek_1 person +EGIhtnFv2f4_0 person +EGI5Yk7IU8s_0 boat +EGOtOZyUpk4_0 train +EGOtOZyUpk4_1 train +EGOtOZyUpk4_2 train +EGZ7-ChFJQI_2 knife +EGd19Lwe3vM_0 person +EGgvoXoby8c_0 person +EGgvoXoby8c_1 person +EGiEfcahLzY_0 person +EGsRldGZ4Bc_4 truck +EGsRldGZ4Bc_5 truck +EGsRldGZ4Bc_0 truck +EGsRldGZ4Bc_1 truck +EGsRldGZ4Bc_2 truck +EGvzZJ10zwQ_0 train +EG7cF7KMqs8_0 motorcycle +EG-A5-_1i-o_0 car +EHD613XdEQc_0 person +EHMEQV26qfk_0 boat +EHUgk_5vbps_0 horse +EHafuO8IcpI_3 bird +EHcP0uDfEyE_0 umbrella +EHft6kH6siE_0 person +EHft6kH6siE_1 skateboard +EHtU4jYmFWw_0 elephant +EHvP9Bwmq7M_2 person +EHvP9Bwmq7M_0 person +EHvP9Bwmq7M_1 person +EHv9RwkIPXM_0 skateboard +EIIC6lIbxO4_0 cat +EIRbrmP8N9U_1 elephant +EISmAs76j_g_0 train +EIUHtk1IdtA_0 cow +EIcGpS1nsXk_6 elephant +EIcGpS1nsXk_4 elephant +EIdaSifBFgk_0 person +EIdaSifBFgk_1 person +EIe7fhZxKpQ_0 person +EIe7fhZxKpQ_1 person +EInkqD_T5Os_0 train +EIwa8hvMQ9g_2 bicycle +EIwa8hvMQ9g_0 bicycle +EI8OMIBxEOo_0 person +EI-G2_K6zus_0 person +EJE1AAlhjcQ_0 person +EJE2EqHSaLA_0 airplane +EJJefx2O7lo_0 person +EJJ0aK1Mefo_1 bird +EJMke8tdD9c_0 person +EJMp6Gszq8M_0 person +EJM15lQ1nds_0 bus +EJM15lQ1nds_1 bus +EJNv-W_Wh3s_0 airplane +EJNv-W_Wh3s_1 airplane +EJOO-gnqZOQ_0 person +EJQZBc87T7Q_0 person +EJTbpxYS19w_0 person +EJdJUArfCgA_0 person +EJdJUArfCgA_1 bicycle +EJ2XL046J4A_0 person +EJ3IJ7_jx0s_0 knife +EJ3IJ7_jx0s_1 knife +EKDm7Y7dQ-g_1 bird +EKETFVqhfZI_0 person +EKOgJfGpWw8_0 horse +EKPKBwGLkg0_0 person +EKR2BQWkMTI_1 person +EKf-TzUsoG8_0 person +EKsbh9eVG0w_1 airplane +EKv1nvgLQLc_0 motorcycle +EK2VY_FFN04_0 person +EK56Obpu5ME_0 elephant +EK56Obpu5ME_4 elephant +EK5-ZuOavbM_0 train +EK5-ZuOavbM_1 train +EK5-ZuOavbM_2 train +EK7wRGel2vk_0 person +cuXky9bc80o_1 elephant +cuXky9bc80o_3 elephant +cuXky9bc80o_0 elephant +cuYker921kg_0 person +cuZPt_f2GfE_0 person +cusvncJOcwQ_0 horse +cu0Z8d-ioZA_0 airplane +cu_YsyYcbL0_0 cat +cvBKWYZidIs_0 person +cvFAAQuXQR8_0 person +cvJuXsDfcUY_0 train +cvUktXqTBBA_0 car +cvUktXqTBBA_1 car +cveuhB6Z_D8_1 bicycle +cveuhB6Z_D8_6 bicycle +cvfI6ccn-J4_0 person +cvgZ-1Uaigk_0 person +cviAzkIEA00_0 skateboard +cvlOlYpovm8_0 person +cvyLalOdUEY_0 person +cvyTQ9oFD8s_0 elephant +cv9PMwKXLoA_0 person +cwBgT8f3504_0 person +cwB99KCLazI_3 person +cwEuIwecOZA_0 car +cwHQZi15U3s_1 bear +cwHQZi15U3s_2 bear +cwKndGwjXho_0 person +cwKndGwjXho_1 person +cwPtR7LsWag_1 person +cwPtR7LsWag_0 person +cwTq-wB6R3U_0 skateboard +cwe2t4eoAs0_0 person +cwf1OksNfQ0_1 horse +cwjK5oxoq5Y_1 person +cwjK5oxoq5Y_2 person +cwmY9UYaukc_0 person +cwnltT3Eelo_2 bicycle +cwp0G17bk0I_0 truck +cwp8Oe0F6y0_0 truck +cwsLz_ppMx8_0 truck +cwsx0Rs732s_0 person +cwyDOlWxH00_0 bus +cwzHLMKmpWM_0 horse +cw054hU6MdM_0 person +cw4vlk-0siU_1 boat +cw45Y0beNG4_0 bus +cw55i8mKHnE_0 person +cw55i8mKHnE_2 person +cw57dOs_v5A_0 bear +cxAcLoLkk2g_0 person +cxJp5-r_mjQ_0 person +cxLrrWl89wo_0 person +cxMcoeT1INo_0 person +cxQENdEkIVQ_0 skateboard +cxSj2n8O4Vk_0 person +cxUXpTWO4iY_0 train +cxbTIQtmtLs_0 person +cxiI7jApblc_0 boat +cxkH0GxPEqU_0 motorcycle +cxm8wGi_pl4_0 person +cxsitsK8l9w_0 horse +cxsitsK8l9w_1 horse +cx0cCIp1KeU_0 person +cx0cCIp1KeU_1 person +cx0tj_0g0-k_0 person +cx2bUajKTrw_0 person +cx4EC6uXkkY_3 boat +cyBgPXda4lw_0 person +cydwQgvjXlk_1 person +cyd0m3k4Iv8_0 cat +cynwjNSXfDs_0 elephant +cyz45rMhH9E_0 person +cy4xwLUwDN4_0 person +cy4xwLUwDN4_1 horse +cy4xwLUwDN4_3 horse +cy5IjIQ0UNQ_0 motorcycle +cy58Sr7mA_Q_0 knife +cy6woAEQ0aU_0 knife +cy8BRHRLKa4_0 train +cy9CeQwHsws_0 bird +cy9kq-lD2Q8_0 skateboard +czD_BiifXv4_0 knife +czLen_XZrRo_0 horse +czUjYoRVVYw_1 horse +czec9DaQ1sQ_0 person +cze3sm-N48s_0 person +czjU6Q4s1jc_1 person +cznO_APZ6xQ_0 bear +czpxbOFiY_Q_1 person +czpxbOFiY_Q_0 person +cztHS4laeBQ_1 bicycle +czto2OaEIww_0 person +cz0dXFpjC6o_6 bear +cz0dXFpjC6o_4 bear +cz0dXFpjC6o_5 bear +cz5kAZB6n0k_3 bear +cz6eGvs1xNE_1 motorcycle +cz8sE1Vn4Gw_0 person +cz83QPHVLnk_0 umbrella +c0GrJULqad0_0 person +c0GstZDjoNM_0 person +c0IYOMYovRo_1 person +c0J3zJ8n3SI_0 horse +c0LibLcues0_0 bear +c0MEfCeuV5U_0 bird +c0MdSWVdmqY_0 bus +c0PyfX2HFqE_0 person +c0TJZWOz78g_1 dog +c0XKBQNwSlg_0 truck +c0aHKGTYgeo_0 person +c0bZsiE4obs_0 horse +c0jq_aReY5M_0 motorcycle +c0kH2qIyG7E_6 horse +c0kH2qIyG7E_4 horse +c0lBfqi79wQ_0 cow +c0lDR6ABjTE_2 person +c0nRMc9KiiQ_0 dog +c0nXpd7yJsk_0 person +c0o_nv0BL6Y_1 bear +c0pzN4lVApI_1 person +c0qkbu5wLF8_0 elephant +c0qkbu5wLF8_2 elephant +c0wve_629pA_0 person +c0yrclVs1YA_0 cat +c02KdAN0Hwg_0 bird +c04Vd9VQao8_0 person +c04ixznYflE_1 giraffe +c07Yqknz4KI_0 train +c07k0EtqcVs_1 car +c08cFHAOc7I_0 train +c0_M6VhGXOo_0 person +c0_M6VhGXOo_1 person +c1JGF-ltiJ8_1 bicycle +c1JGF-ltiJ8_2 bicycle +c1PUETYl8Lk_0 airplane +c1QAgByBiYE_0 person +c1WZ6dEz6kw_0 airplane +c1XMeGkSwJQ_0 person +c1XfiRiOTb0_0 horse +c1a_E7CZsVk_0 person +c1djg96PnM0_1 person +c1djg96PnM0_0 person +c1hBqL_LWE0_3 bird +c1j8TlZsEmQ_0 boat +c1laLoj4fM8_0 person +c10eOkpL080_0 person +c10eOkpL080_1 person +c2B7cQwr4Pk_0 person +c2EIdJJnku0_0 motorcycle +c2E5_n_bZKc_0 train +c2Kh-3yj9Ak_0 person +c2MTwEvPGGk_0 person +c2MUYY-qPhA_1 bus +c2MqPrUNXQ4_0 train +c2UDI136z20_0 elephant +c2UDI136z20_4 elephant +c2UDI136z20_5 elephant +c2UDI136z20_7 elephant +c2YlmT-aFE4_0 cat +c2a9uwUCFK8_0 cow +c2dk3AjUcYs_0 person +c2gJYqYcsZg_0 person +c2luSxdPZ6A_0 person +c2m_PmRSEmw_0 elephant +c2qJhOvlIUU_0 airplane +c2xTBZttrzA_0 person +c22HGSTHjBA_2 knife +c22HGSTHjBA_1 knife +c22yvcXZcM0_0 bird +c2_qHguvZbI_2 bear +c2_qHguvZbI_0 bear +c3E9z6F-Txk_0 train +c3J2U0kR6Hg_0 person +c3TisGCbmoU_1 person +c3Ur6j05SgQ_1 bicycle +c3YFgnDBuXw_0 person +c3bCGnwqGxc_0 car +c3eo0_ftrn4_0 cow +c3pP__Uybq8_0 person +c3wt1MUbgD4_0 person +c3wt1MUbgD4_1 person +c37EOoRHd7E_2 truck +c4A01X82TfI_0 train +c4FmSUmvYbo_0 person +c4FmSUmvYbo_1 person +c4Hh2XdTBGY_0 cow +c4ICOFVvcTs_0 person +c4e-qA4esVY_1 person +c4iCXPdqm6c_0 elephant +c4jbOCZyGsQ_0 person +c4k8Yk1x3H8_1 person +c4k8Yk1x3H8_0 person +c4xRJS9_5Fk_0 train +c4xRJS9_5Fk_1 train +c40Mwg88VJI_0 person +c43ihGsR1eA_1 person +c5AKIs1XUhc_1 bicycle +c5AKIs1XUhc_2 bicycle +c5AKIs1XUhc_3 bicycle +c5BYdZTaBgc_0 person +c5CmxgLHcxA_0 bus +c5Fw-Fi4daE_0 cow +c5GANV8PlSM_0 person +c5GIQcIJ9Tc_0 truck +c5GOwfkZXFk_0 person +c5GOwfkZXFk_1 person +c5Q2ZeMDx3o_0 train +c5TlkWtFymE_3 dog +c5WT0W8SfGg_0 cow +c5WT0W8SfGg_5 cow +c5WT0W8SfGg_1 cow +c5WT0W8SfGg_2 cow +c5WT0W8SfGg_3 cow +c5WT0W8SfGg_4 cow +c5cooFy7-SM_1 elephant +c5hEygqOXOU_0 person +c5oiA5xy15M_0 person +c56nid2YSes_6 bird +c56nid2YSes_0 bird +c56nid2YSes_1 bird +c56nid2YSes_2 bird +c56nid2YSes_5 bird +c56nid2YSes_8 bird +c56nid2YSes_9 bird +c5_dNG2vWXg_0 car +c6EIognIYWs_0 bird +c6ZQRNXfcZA_1 person +c6a4xySAJ0o_0 truck +c6niMRNXDeo_0 person +c6qKbpvd-iw_0 person +c6rbqnU4LXs_2 motorcycle +c6rbqnU4LXs_0 motorcycle +c6s839WnVhE_0 truck +c6yBOD3Wo5A_0 person +c7B-3x-3V34_0 person +c7ILC5wYs8A_0 person +c7KoGv5Ha7k_0 person +c7PMPnuPjp8_0 person +c7RFexe2Ba4_1 bicycle +c7RFexe2Ba4_3 bicycle +c7RFexe2Ba4_0 bicycle +c7RFexe2Ba4_2 bicycle +c7SMRurbkY4_0 bus +c7bKlPVR5pI_0 boat +c7hVbIhp0Wc_0 person +c7jWXqWoMz0_4 bicycle +c7s8weR8lEY_0 person +c7v4ZFCK-A4_0 person +c70kaPblMLU_0 cow +c74hYNtpwdA_0 dog +c75cllxWxZE_0 person +c7_op6G05l0_0 airplane +c8B4ZVLv364_0 person +c8Cl-5olqWk_0 motorcycle +c8Gaja-xUeQ_1 person +c8I3JAxoLTs_0 bicycle +c8I3JAxoLTs_1 bicycle +c8I3JAxoLTs_3 bicycle +c8LHqWmKrJU_1 airplane +c8LHqWmKrJU_2 airplane +c8Mo16hH7qs_0 person +c8UrmdREAO8_0 person +c8Y7MJRWFqE_0 cat +c8Y8y9BsPHw_0 cow +c8b9qqF9Xvw_0 person +c8b9qqF9Xvw_1 person +c8ezNTNUXqc_0 cat +c8wbvQnndJc_1 bicycle +c8wdGQw1jB4_1 bus +c8wdGQw1jB4_2 bus +c8y3bmW0X9s_1 cow +c8zphqgYcJM_0 person +c80SYyKXCCw_0 person +c8_fHVnrzZ8_2 elephant +c9EDbgCRGP0_0 person +c9GKsfyRkmE_0 person +c9IdrMV-Y_Y_0 person +c9Q9LPaqyug_0 umbrella +c9SbfXgAoO8_1 airplane +c9Somjq2gLs_0 umbrella +c9WDXLFtYLU_0 bus +c9XaEHVxu4M_0 person +c9Y9a6KVWRE_0 bird +c9Y9a6KVWRE_1 bird +c9ZWCwVv6Q0_0 person +c9dPiEkCwR4_0 motorcycle +c9gCDztKasg_0 elephant +c9pYz2lTh3I_1 person +c90ldeMSfL0_0 cat +c94gzpjmj24_0 person +c9_87BKOW1I_0 cow +c-CCw_cyicE_0 cow +c-G0LV4kyY0_0 car +c-T9ITcEW9c_0 person +c-T9ITcEW9c_1 person +c-ZnwBvVFGE_0 person +c-gH6T1q-sk_0 person +c-pKAy_3arM_0 person +c-uOjPSq-10_0 cow +c-vwn6zqogs_0 person +c-vwn6zqogs_1 person +c-4uPwFKBdY_0 person +c-_iMD-ihnE_0 motorcycle +c-_94CuEo_M_1 person +c_SQI7NirwY_0 person +c_THUYYi_-k_0 airplane +c_YojhaB5pI_0 motorcycle +c_jNM33kJuA_0 person +c_rUQgBtHY4_0 person +c_rUQgBtHY4_2 person +c_rUQgBtHY4_1 person +c_wkIYzEEDk_0 dog +c_6OcDyZ93k_0 bus +c_9GO2BbPz4_0 horse +dAQu2GQSyrY_0 cat +dAS6SqC7TCw_1 elephant +dAVIZQJ5Af4_0 person +dAqurx13i7I_0 knife +dAynVVxxb_o_0 person +dA7mx3mrJeA_0 train +dA_ZtitJeMA_0 person +dBDSqZ8rirA_0 person +dBGKqrEvsIE_0 boat +dBGKqrEvsIE_4 boat +dBKexOUQSQA_0 cow +dBKexOUQSQA_1 cow +dBKexOUQSQA_2 cow +dBKexOUQSQA_4 cow +dBKexOUQSQA_5 cow +dBKexOUQSQA_6 cow +dBOrrvJDv54_1 skateboard +dBPu5iVlw1Y_2 horse +dBSryinfjiI_0 person +dBS9maEElcw_0 person +dBUpfcdFDUQ_0 bicycle +dBWeUQd06l4_0 person +dBWeUQd06l4_1 person +dBiGneGqmh0_0 cow +dBk2FwZgrtk_0 cow +dBq77lvujCk_0 bird +dBuvGegR_vA_0 person +dByVvpTlwL4_1 knife +dB29dsCcN9s_0 train +dB43vSgLY2M_0 person +dCG24UL_NeM_0 person +dCSF80Y6lso_0 person +dCSF80Y6lso_1 person +dCZ9suBocXk_0 person +dCgz-7OgwMQ_1 person +dCl8hSleXYQ_0 cow +dCoi3rXWgbM_0 person +dCqdvmS1jts_0 person +dCqdvmS1jts_1 person +dC9rTC3kzsI_0 cow +dDADJZV4i74_0 horse +dDA5p5TJ03g_0 person +dDB84W_zVOI_0 skateboard +dDB84W_zVOI_1 skateboard +dDE3p8Gs878_0 elephant +dDGiQLFJtPs_0 bicycle +dDIbBZtEJ2w_0 knife +dDLgQQ2XRc8_5 horse +dDLgQQ2XRc8_3 horse +dDLgQQ2XRc8_6 horse +dDO-RlSt3Gw_0 person +dDQ58wciink_0 cow +dDZYTPEd9KE_1 airplane +dDacKPH4sOw_0 car +dDacKPH4sOw_1 car +dDcBtNpmCeU_0 person +dDgcHWpKMeo_0 person +dDkaPLEvAwM_0 horse +dDkaPLEvAwM_1 horse +dDkaPLEvAwM_2 horse +dDqe9sBGR24_0 bird +dDx0MqaKT2w_0 person +dDx0MqaKT2w_2 motorcycle +dD-AlVwxf-g_1 cow +dD_Ew85jXzk_1 train +dD_PbxvCBcA_1 person +dECTTSpEUKg_0 person +dEW9ZwvMsDE_0 cat +dEc5fHlEXCo_0 truck +dEuzpQL0tNo_7 elephant +dEuzpQL0tNo_1 elephant +dEuzpQL0tNo_2 elephant +dE7OwbOHsu8_0 person +dE7WsfeVkI8_0 person +dE7X93gdVPQ_0 cat +dFCUyBTrvNM_0 horse +dFCu7E6aYM4_0 person +dFCu7E6aYM4_1 person +dFEo5YKHAcA_2 skateboard +dFEo5YKHAcA_0 skateboard +dFMPz16FOzE_0 motorcycle +dFZSSPvMBqE_0 zebra +dFZSSPvMBqE_1 zebra +dFa7TcQRCUU_1 bird +dFbZxetmjCQ_0 skateboard +dFkNDweVNFU_0 cat +dFpJq9s5fec_1 bicycle +dFpJq9s5fec_2 bicycle +dFsDjjWW00Q_0 knife +dFth5-8MEhM_0 person +dF7OkxFt3I8_0 person +dF_aGgW1jcM_0 person +dGE7t6KgXHc_0 person +dGFrWX61Zk0_0 person +dGS01inQU1U_2 person +dGS01inQU1U_0 person +dGS01inQU1U_1 person +dGZBUkIXMpo_0 person +dGZ_pzDrl70_0 person +dGdh_BHleU4_0 boat +dGh51ZQ9QAg_0 bird +dGk8D_De-2E_0 person +dGk8D_De-2E_1 person +dGpbPaorWys_1 bear +dGq1bpRxbiA_0 person +dGyR5TWO-p4_1 person +dG0CtnphYzg_0 person +dG5mjfvTY7c_0 boat +dG7DSOtetMY_0 knife +dG9J5UpxeyY_0 person +dG9J5UpxeyY_1 person +dHCgtjlT_Lg_4 horse +dHCpH8dTwfw_0 horse +dHF9NIqrx6Q_0 car +dHGIXivupi4_0 person +dHGIXivupi4_1 person +dHGIXivupi4_2 person +dHJkOetpjQw_0 bus +dHO6vTrB66w_0 person +dHO6vTrB66w_1 person +dHVDjpivOKw_1 person +dHVDjpivOKw_0 person +dHVgQCO07SU_1 person +dHVgQCO07SU_2 person +dHfs5GT-YpY_0 cow +dHg1Xorklm0_0 person +dHimuOjriUc_0 cow +dHnk6ulSNSo_0 person +dHnsZs2Riqk_0 person +dHnsZs2Riqk_1 person +dHsD3F8dTpc_0 bird +dHvlIrb2Q-k_0 person +dHwR5d4xGEk_0 knife +dHwR5d4xGEk_1 knife +dHwR5d4xGEk_2 knife +dHwR5d4xGEk_3 knife +dHwR5d4xGEk_4 knife +dHxmY1bGbNc_4 bird +dH89qyunr6s_0 person +dH94i4xFlZU_1 elephant +dH94i4xFlZU_6 elephant +dH94i4xFlZU_0 elephant +dH94i4xFlZU_5 elephant +dH94i4xFlZU_7 elephant +dICl73jYZ3M_0 person +dICrafh45_I_3 airplane +dIDxqrhmBE4_0 truck +dIDxqrhmBE4_2 truck +dIEZ2kfTzzY_0 boat +dIJk0w4SnH8_0 bird +dIVtaleUNWI_0 person +dIVtaleUNWI_1 person +dIX81Ov0fUY_0 person +dIZM-9d8bSQ_0 person +dIZM-9d8bSQ_1 person +dIm0Sv_iE2E_0 motorcycle +dIqYGVVgYsU_0 person +dIzMmAGaF6U_1 skateboard +dI93uXfSaRM_0 bird +dJB-DXpgq2U_1 bird +dJKAhixNM9Y_1 truck +dJYNs94fv_0_0 person +dJgqX3uy6z4_0 person +dJg4R9cpbjI_0 person +dJisrPH71tE_0 person +dJi_dOrUZnw_0 person +dJjrFTy9H3c_0 person +dJkzzYh6BkY_1 cat +dJnRg-1zO1g_3 knife +dJqGj0FeC9I_0 cat +dJvoaqZjIDw_0 person +dJ2B9A0mYl0_1 dog +dJ2kWscI-tc_1 dog +dJ4PR9zme-s_0 person +dJ6S9bSEYDc_0 cow +dJ8J7WOLZtk_0 skateboard +ELDxjZXMtCg_0 person +ELLTxQ47f90_1 person +ELLTxQ47f90_0 person +ELNgTt9Jswc_0 train +ELOZutiZKMM_0 person +ELOZutiZKMM_1 person +ELPpy9ABb3s_1 elephant +ELTeW4X2mGY_1 cow +ELbg8i93W8I_0 person +ELbjX2Ya0_o_0 dog +ELmktutrkDk_0 person +ELqA6fb0un8_0 person +EL8H94Lycf8_0 person +EMAVfcO6JFE_0 person +EMKcTJp7ehY_0 person +EMOpCv3vVfE_1 skateboard +EMP7p3FNxZU_0 person +EMU8vGL7ZFQ_0 person +EMb28oLn66k_0 airplane +EMgh3pwtnXg_0 person +EMiRla730lM_1 person +EMiRla730lM_0 person +EMmg9OKgyBE_1 boat +EMmmZ6ADzfI_0 skateboard +EMngQ4YMTv0_0 motorcycle +EMorunu9Ik8_0 truck +EMqd3lVNUxg_7 bus +EMuGAIADn3s_0 person +EMwcDTRPPMw_0 airplane +EMyQWQ_Yobc_0 dog +EM0yGxKJWqY_0 elephant +EM1R3HXt7DY_0 person +EM1z9o601v4_0 knife +EM3tBaIyR0o_0 motorcycle +EM5e1snhsCs_0 person +EM-k8ZAva6k_0 person +EM-zjCQyGAc_0 dog +ENAr6j6fcWU_0 bird +ENCHiWUV4dk_0 person +ENI-JuSPNQA_0 motorcycle +ENSEWig-4ZM_0 knife +ENXXFcrrxGM_0 car +ENc0uxXKsaI_0 person +ENkqstdLKl4_0 person +ENk4JRIbEaE_1 person +ENnPjtPjU6c_0 person +ENtoAci6OwQ_0 cow +ENvdCzm4whM_0 truck +ENvdCzm4whM_1 truck +ENvdCzm4whM_2 truck +EN0Klsi-AKY_0 bicycle +EN4IIJjhBeI_0 zebra +EN-QCSvtEd0_3 elephant +EN-4SsZnn-k_0 person +EOEXVXG1TDk_0 person +EOVNlasJhIo_1 person +EOdHjLYopi0_1 bird +EOedzXaVI4U_2 bird +EOe3CfOT53g_0 person +EOmVKXeoKBc_1 airplane +EOq-3ZRn0SQ_0 skateboard +EOt6j5ecODw_0 train +EO7NccQDQyM_0 cat +EO8Dpvy4oXs_0 zebra +EO8mQrkIZuY_0 person +EO_DwtyWh0s_3 person +EO_DwtyWh0s_0 person +EO_DwtyWh0s_1 person +EO_DwtyWh0s_2 person +EPOXqdKNjKg_2 giraffe +EPU630RSI5c_2 person +EPU630RSI5c_0 person +EPWmdYKJaXk_0 bird +EPycDWf2vY4_0 skateboard +EP_ezteElzk_0 person +EQBFPIdI8gY_0 person +EQC8eEghvs8_0 person +EQNSjjkyRBg_0 person +EQNSjjkyRBg_1 person +EQTee9qqTZs_0 person +EQVCizuJQFY_0 umbrella +EQdEm5HuPG4_5 train +EQx1XHc0mRM_1 motorcycle +EQzXCoQRbas_1 train +EQ5rBLoiT78_0 bus +EQ9-lbsee1s_0 person +ERCvzMzkDhg_0 skateboard +ERGwo6vIXdQ_0 person +ERJR-zQYyH4_0 person +ERR-qjVJ3lY_0 person +ERVp_cX1juc_0 person +ERev6rrd5XA_3 motorcycle +ERyyYMb2fFk_0 cow +ERzh41uuxUE_3 bicycle +ER0IdSeymeI_0 person +ER0IdSeymeI_1 person +ER03PLUBt4c_0 train +ER03PLUBt4c_1 train +ER03PLUBt4c_2 train +ER03PLUBt4c_3 train +ER53sUYwz1I_0 zebra +ER6vMbAyQ6E_1 skateboard +ER6vMbAyQ6E_0 skateboard +ESDQMC_70Pk_0 bear +ESInVf3ioiA_1 dog +ESMdbpGXk4I_0 person +EST4CUX19Eg_0 person +ESokfN84OYk_0 elephant +ESokfN84OYk_3 elephant +ESokfN84OYk_4 elephant +ESpwZsbwQGA_1 elephant +ESpylyha7g0_0 horse +ESt5TEXuGIM_0 person +ESt5TEXuGIM_1 person +ESwsyjITYGM_0 skateboard +ETBia7K3ZHw_0 motorcycle +ETBia7K3ZHw_2 motorcycle +ETQTZgnfRK4_1 person +ETQi93bP3YQ_8 elephant +ETQi93bP3YQ_2 elephant +ETTgj1pxvME_2 person +ETWI4nXFANg_0 person +ETcmjY7Jigo_1 motorcycle +ETgN7EcVVQI_1 person +ETmYIq5CF2k_0 motorcycle +ET4xC8Wl_CA_0 person +ET4yAsJTvlk_0 cow +EUH3oSBX950_0 person +EUH3oSBX950_1 person +EULIYiiV-O0_0 person +EULIYiiV-O0_1 person +EULchAlLDfM_0 train +EURUU5P5flo_0 person +EUcHraiUCjA_0 bicycle +EUcWvzarnb0_0 umbrella +EUdNEi4myuA_0 person +EUtfoblvHn0_0 person +EUuCDfb8lf4_2 person +EUuCDfb8lf4_1 person +EU93Mw9WGkc_0 skateboard +EVBHY1qGVos_0 person +EVBHY1qGVos_3 horse +EVElggpPSCM_0 elephant +EVE2SBJ-2S8_0 person +EVH8Ql7_pYE_0 person +EVTW6Ka7-NU_0 person +EViJ_JQcv5c_0 train +EVmGPGaP6bY_0 person +EVnnSfmb4go_0 giraffe +EVn52FBjG9E_0 person +EVn52FBjG9E_1 person +EVxEEc26TWg_1 giraffe +EWLiwu56oQc_1 person +EWNd02yWiYw_0 person +EWP0Hhxsf58_0 person +EWQo_1YXfYM_1 person +EWQo_1YXfYM_0 person +EWTvjjpAUm0_0 airplane +EWXyQ1tS3jI_0 elephant +EWdNgXvr54s_0 dog +EWfPRTjQO9k_0 dog +EWgsivaLhl0_6 elephant +EWgsivaLhl0_1 elephant +EWgsivaLhl0_2 elephant +EWi25l2D0cw_0 cat +EWkndzLXvLc_0 bicycle +EWuOSRFWTzg_1 elephant +EW0Mgele6Gc_0 person +EW0Mgele6Gc_1 person +EW6FHYagN0Y_0 person +EW98OEvTxM8_0 person +EW-Zuo7ArI4_0 dog +EXDDO7gLoL4_1 person +EXDDO7gLoL4_2 person +EXDDO7gLoL4_3 person +EXDDO7gLoL4_4 person +EXGwKMtyR1M_0 person +EXHZgqkcXG8_1 cow +EXJITC62tU4_0 umbrella +EXSMz4HnWfg_0 dog +EXaiYiUQrMI_1 dog +EXfiGeKWKTk_7 airplane +EXfiGeKWKTk_1 airplane +EXiGyq1TD80_0 person +EXiGyq1TD80_1 person +EXkbZbo1n5U_2 elephant +EXkbZbo1n5U_0 elephant +EX817S50E5U_0 person +EX-dqihLUwY_0 motorcycle +EX-dqihLUwY_2 motorcycle +EYCaJR9md8k_0 airplane +EYEWPdaJuL0_4 bird +EYEWPdaJuL0_5 bird +EYEwLM8YTwc_0 person +EYFMOBeF9UE_0 knife +EYHtNGztiRQ_1 car +EYKrEDelAdU_1 bear +EYM1oXAmBq0_1 bus +EYRf00qGMVU_0 train +EYV6D6G6t2c_1 person +EYZsYCSedGw_0 person +EYd9lSK7Bbk_0 person +EYhtY59whvs_0 person +EYmWVBDEutA_0 horse +EYnEMtlMaPY_0 person +EYoj8D64YLA_0 skateboard +EYuLodJTgYs_0 train +EY2pZ9A48ng_0 truck +EY2pZ9A48ng_1 truck +EY2pZ9A48ng_3 truck +EY25PJWD2j4_0 person +EY36YeIgOYI_0 person +EY36YeIgOYI_1 person +EZWcsRlXIA8_0 person +EZbOH9yEe-A_0 dog +EZh1lf4yfCg_0 person +EZ5Wa2duCoM_0 person +EZ5Wa2duCoM_1 person +EZ7d9ab31ys_0 giraffe +EZ9-_7o9Vds_0 bird +EZ9-_7o9Vds_1 bird +EZ_xC5EBwvk_0 bus +EaBdeSUjDYs_0 dog +EaFSd7_S8kc_0 horse +EaQ1P4QyRsY_0 person +dKEVBoMMD2w_0 boat +dKJz_EakSc4_0 person +dKMb2S2SSfI_0 skateboard +dKTgMjbnNPQ_0 skateboard +dKiwficH2d4_0 person +dKi4xI4vB-k_0 umbrella +dKlCFQxk5Dc_3 person +dKlCFQxk5Dc_5 person +dKlCFQxk5Dc_0 person +dKlCFQxk5Dc_1 person +dKlCFQxk5Dc_2 person +dKq4S1IVjlA_0 person +dLFWcgSewxs_0 truck +dLH8fBNk89Y_0 cat +dLIld9ux7p4_0 airplane +dLT61O_htwI_0 cat +dLUCKkji5wo_0 person +dLUCKkji5wo_1 person +dLV2VJkpyMI_0 airplane +dLbhzrFtNC0_0 person +dLhVV7DMXkw_0 person +dLoxdmLuphk_0 dog +dLq5OW1xY54_0 elephant +dLq5OW1xY54_3 elephant +dLq5OW1xY54_2 elephant +dLtQB9P_7BU_2 bear +dLty27VgJcc_0 train +dLvr7BjgsHg_0 person +dLwXzYr8beg_0 car +dL3dSZMnBko_0 person +dL3vGWsRVCg_0 knife +dMDGwTdSHIo_0 motorcycle +dMJQi7oYiqQ_1 person +dMS5hB4uWdk_0 bird +dMWgiVqknaE_2 person +dMWgiVqknaE_0 person +dMZONdbNFbk_4 bicycle +dMZONdbNFbk_2 bicycle +dMdUZi9lxrU_0 cat +dMiwR-DS6UE_0 car +dMsIDwHkWNE_0 person +dMulBz-N8oA_0 horse +dM7lOj89YZE_0 person +dM7-xh2kSmc_0 person +dM7-xh2kSmc_1 person +dM9u0c0qSV0_0 cow +dNCm5MtFcp0_0 person +dNEAY77it7o_0 person +dNShS9OdIoA_1 person +dNShS9OdIoA_0 person +dNSlL572gMU_0 truck +dNSlL572gMU_1 truck +dNVvIPWEH1Q_0 person +dNVvIPWEH1Q_1 person +dNdTs9Qa1A0_0 truck +dNeF_3qppZQ_0 skateboard +dNj_77jiPcs_1 cow +dNknNwahiv4_0 giraffe +dNoz32bgN0U_0 car +dNpQfDg_dIg_0 person +dNqdMh44imM_0 train +dNs2JO9SgGo_1 airplane +dNs2JO9SgGo_2 airplane +dNyMDstraS0_0 person +dN1cn1CPEa8_0 person +dODPVlzMR1A_0 person +dOHuuTREVQk_0 person +dOHuuTREVQk_1 person +dOHuuTREVQk_2 person +dOHuuTREVQk_3 person +dOMW6BLHI2s_0 elephant +dOMW6BLHI2s_1 elephant +dOOQ32tmk14_0 elephant +dORLSKDLr1w_0 cat +dOUVBpTWHzc_0 person +dOVzO5pkY2o_0 horse +dOWhuaTBmr8_0 truck +dOdX5nkOBoQ_1 person +dOdYYCqd6i0_0 person +dOdYYCqd6i0_1 person +dOd-8kfbjz4_0 train +dOd-8kfbjz4_1 train +dOfNevz8wlc_0 bus +dO2CbXVpSl0_0 elephant +dPA7g60qlnk_1 boat +dPJk57_DSuI_0 truck +dPJ7_mdmjJo_4 truck +dPJ7_mdmjJo_1 truck +dPTnDrK0jl0_0 knife +dPZPjPwJCnA_0 person +dPiOaLH0K4Y_0 bear +dPiOaLH0K4Y_2 bear +dPma_hb-MR8_0 skateboard +dPnxUa8yPbw_0 train +dPpwBkl-F9k_3 bicycle +dPpwBkl-F9k_0 bicycle +dPp0no_eYOQ_0 dog +dPqheqisvs8_0 person +dPvgWsIPDr0_0 horse +dP0jXsi0KUw_0 skateboard +dP_-3SJLP1Y_0 person +dQB4GI0Bgus_0 truck +dQCFCRTz2rc_1 giraffe +dQCFCRTz2rc_4 giraffe +dQCFCRTz2rc_5 giraffe +dQCFCRTz2rc_0 giraffe +dQIQv4YkBaM_0 truck +dQI-ReUS1hk_0 person +dQM_-V4jSpM_0 cat +dQNG1syFdKQ_0 person +dQPdAoRj8vw_0 dog +dQWw3losmfA_1 bicycle +dQY2wbSJyOQ_0 person +dQh9dmaqW3s_0 person +dQh9dmaqW3s_1 person +dQlybGW3tbw_1 cat +dQnNTlCD_AQ_0 elephant +dQnNTlCD_AQ_1 elephant +dQoX3OkaI4M_0 person +dQzWZhDVLYk_1 person +dQ4hJadqL_w_0 person +dQ62PlC9Frc_0 zebra +dRBb5v_Fv3g_0 elephant +dRDdBvl4olg_0 person +dRHTO6H764g_0 person +dRHYGXImEBk_2 person +dRHYGXImEBk_0 person +dRInM_HaQZs_0 bus +dRVEs1099F8_0 horse +dRcLZtR6KFs_0 person +dRcrvTR9xIY_0 person +dRiBVua-2Ck_0 person +dRjzvcGshbA_1 person +dRjzvcGshbA_0 person +dRs8FcKuu6w_0 boat +dRt8H1uQ5Og_0 umbrella +dRt8H1uQ5Og_1 umbrella +dR7jBT3cxr8_0 person +dR8kCc9XNJs_0 boat +dR-8FlykNZ0_0 person +dSAODa472ys_0 bird +dSAYK4yUlDs_4 person +dSAYK4yUlDs_0 person +dSAYK4yUlDs_1 person +dSAYK4yUlDs_2 person +dSAYK4yUlDs_3 person +dSEv_R8nQik_0 zebra +dSFMrnh2szI_0 cat +dSLakvIEH9o_0 bear +dSLmBYdUku8_0 person +dSQTVC-RyAU_0 person +dSWhe4RgQ_w_0 cat +dSZBg-Vcr7E_0 motorcycle +dSojBtCOkqQ_0 person +dSx4IloBWZs_0 person +dSzAX5l_fs0_0 person +dSzAX5l_fs0_1 person +dS0mBDDgP_A_0 person +dS0mBDDgP_A_1 person +dS8x0l5I7f0_0 boat +dTDxzi0o_Qg_1 airplane +dTMe2Vse97w_0 cat +dTVBSXs5Me8_0 person +dTVKs9m3eZU_0 cat +dTm_DRCtjCo_0 elephant +dTm_DRCtjCo_1 elephant +dTrt1C_90H0_0 knife +dTurjz-gJek_0 person +dT6A3DwqZb0_0 boat +dT8wudfW9gg_1 horse +dT-INB6puFM_0 skateboard +dT-INB6puFM_1 skateboard +dUAtLBDfmBo_0 airplane +dUAtLBDfmBo_2 airplane +dUC_SF_mN_E_3 horse +dUC_SF_mN_E_1 horse +dUInMUIPtTs_0 person +dUJH8d3CMU8_0 bear +dUMLWt99A7o_0 person +dUP4OTLrOA0_0 person +dUW_G_--wI8_0 train +dUXFUWivXPA_0 horse +dUXFUWivXPA_1 horse +dUbP54CBYd0_0 airplane +dUm9A-1AoMU_0 person +dUqrowFcbD0_0 person +dUx_UfS9cQI_1 dog +dUx_UfS9cQI_0 dog +dU-bQRDInro_2 bird +dU-bQRDInro_4 bird +dVAMoKYgrwE_0 person +dVKQhCF8o8w_0 person +dVTHVxh6Tro_1 knife +dVWAD4gOu-8_1 person +dVd7OzbhOq0_0 person +dViVbA7N_AE_0 airplane +dVqPo7-p71Y_0 person +dVtqTTZTFDQ_0 person +dWCqnck4Um0_0 person +dWFVX1psRZI_0 bird +dWGkW13rQBY_3 horse +dWGkW13rQBY_5 horse +dWGkW13rQBY_8 horse +dWVJFIzIKEc_2 bicycle +dWVJFIzIKEc_0 bicycle +dWVJFIzIKEc_1 bicycle +dWXSWEaCId8_1 person +dWdOl13DwwY_0 airplane +dWdl9RdXrHo_0 person +dWdl9RdXrHo_2 person +dWd0sszZOXc_0 person +dWesodD0ff4_0 airplane +dWgfwKBrSiE_0 person +dWgpYitSv0c_0 person +dWkrnxWB1CU_0 person +dWlDN9Hozgg_0 dog +dWtqRwEurDU_0 person +dW1oE_LHALo_0 elephant +dW4DX7lQoGg_0 elephant +dW5aU0U7K28_0 person +dW53l1sR_zM_0 person +dXEH9QiCyHk_0 train +dXEH9QiCyHk_1 train +dXKi3ZHjgWM_1 umbrella +dXLyWGJxHnI_0 person +dXOsaszlVY0_0 horse +dXSuppGXFeI_0 elephant +dXSuppGXFeI_1 elephant +dXdFEix8vu4_0 train +dXjUZeuzgaw_0 train +dXkmG8AR82Q_2 airplane +dXkmG8AR82Q_5 airplane +dX6W4-sxsX0_0 cat +dX9J6yDM5Q8_0 person +dX-4XwYWv48_0 person +dYGOSaGjHQU_0 person +dYQMrQe1pSk_0 person +dYRIEDyD9Qs_0 airplane +dYRKwU2TJYI_0 elephant +dYVcalOS1SE_0 dog +EacR2o35-kc_0 bicycle +EaeD7utPpTQ_0 person +EakGzU5UgWI_0 person +EakGzU5UgWI_1 person +EakGzU5UgWI_3 person +EamZ8De_WFE_6 elephant +EamZ8De_WFE_0 elephant +EamZ8De_WFE_2 elephant +EamZ8De_WFE_3 elephant +EamZ8De_WFE_4 elephant +EavqjWy5gag_0 person +Eaxszmfn7WA_1 person +Eaxszmfn7WA_0 person +Eay0MFBCdqY_1 horse +EazzsVK1-pM_2 umbrella +EbJV0e75xtk_1 person +EbJV0e75xtk_0 person +EbWt1hAb3LQ_0 person +EbXzlcsBsfA_0 person +EbYJAv5c_G8_0 person +EblX3oKGsBA_0 skateboard +Eb1n2o0YpOM_0 cow +Eb3sGSIWtCw_0 person +Eb7juFDG3Dw_0 car +EcMh5TIKmzY_0 person +EcNpsheyrIU_0 person +EcNpsheyrIU_1 person +EcWrNFz5J-o_1 dog +EcpsBV2FEBE_3 horse +EcsiLHpIvL4_0 person +Ecu8VEIC2y8_2 elephant +Ecu8VEIC2y8_1 elephant +EcvYBldDm_U_0 person +EdE8zCwJ56g_0 person +EdE8zCwJ56g_1 person +EdIfx7lQxEw_1 dog +EdIfx7lQxEw_0 dog +EdOvSD40Tb0_0 cow +EdTkeITBkvY_0 person +EdTkeITBkvY_1 person +EdaY0DFamDc_1 skateboard +EdfKMOIOHtI_0 person +Eds-fi9s-O4_0 person +Ed486SKW0kM_0 train +Ed-ENhlS7Dg_1 boat +EeCjxMzh5_A_0 person +EeDhzR9I-Tc_0 motorcycle +EeLllq2Zim4_0 dog +EeMUemitsFU_0 person +EeRqVkQ1Z7Q_0 car +EeRqVkQ1Z7Q_1 car +EeTRT4j5GcQ_0 person +EeYRHJuK3wo_0 boat +EeYqy9QZZTU_0 airplane +Eeb2vPJsaN0_0 person +Eee6rmiMYKY_1 car +Eesk8VSxpIU_0 cat +EetKMgVh0Pk_0 person +EexaBL5jDL4_0 knife +EexaBL5jDL4_3 knife +Eeyjjk9-BvY_0 horse +Ee7CW7lZfXA_1 person +Ee7CW7lZfXA_0 person +EfE6r-Iq5CM_0 person +EfG_eBrAjdI_0 motorcycle +EfHCZUHt0d8_0 person +EfMCesQKyoE_3 airplane +EfNSTkpl6dQ_0 person +EfSMsLkasg8_1 person +EfjC0VVD2Do_0 person +EfvRGCuPoF4_0 person +Ef1Tm3dKzbY_0 motorcycle +Ef2GKdopP_A_0 person +Ef7-yzJqZto_0 person +Ef9YiYODEbg_0 cat +Ef9q8mAPYZA_0 person +Ef_N7JmICUU_10 bicycle +Ef_5u21WLbs_0 cat +EgDOCraAd64_2 train +EgHVReOnDpM_0 person +EgPKMlxhH0A_0 person +EgPxUnCFS10_3 knife +EgYCBIlDm98_0 horse +Egf4iNTfanU_0 airplane +Egf4iNTfanU_2 airplane +EghxGvj6pTs_0 person +Egl_1FgGUyE_2 bird +EgpSSMkQOEE_0 bicycle +EgxlP5S15uQ_1 motorcycle +Eg6YUwqAQqM_0 person +Eg7bJ46L4Cg_0 airplane +Eg7bJ46L4Cg_1 airplane +Eg7bJ46L4Cg_2 airplane +Eg82FN1vC3A_0 knife +Eg9-5uBMrpc_0 cat +Eg-cp7jgFA0_0 person +EhF73HJvEWo_1 train +EhKAs4Z1JE0_0 person +EhSaOGOPUns_0 skateboard +EhbaW6F3U6I_1 person +EhbuzBK5bes_3 giraffe +EhbuzBK5bes_2 giraffe +EhcmJOG2Jws_0 person +EhfmC9Wa8xs_0 person +Eho09eptX7c_0 person +EhpwK0_8UJA_0 boat +Ehpz_gcdCcY_0 knife +Ehpz_gcdCcY_1 knife +Ehpz_gcdCcY_2 knife +Eh6FARrS1VY_0 skateboard +Eh7f9wgtUns_0 bus +Eh88_JdkWWs_0 person +Eh-x-OzZxGo_0 person +EiE9eIJ-Rv4_0 car +EiLWN5T6wko_1 person +EiNTdTOmvDU_0 person +EiUbGE2f6fU_0 train +EiUbGE2f6fU_1 train +EiZG3M9_EMc_0 bird +EiaYgqLcbqM_2 elephant +EibdBvTND-I_0 person +EibdBvTND-I_1 person +Eine_0RExlI_0 person +Ei1XBJFaUeI_0 person +Ei1XBJFaUeI_1 person +Ei6ZitRjwdA_0 person +Ei7n3944Ovs_0 umbrella +Ei9d8OX0ui0_1 airplane +Ei9d8OX0ui0_0 airplane +Ei9724H_wUs_1 person +Ei9724H_wUs_0 person +EjcMZ8Y0Oeg_0 boat +EjgxtJaNIH8_0 skateboard +Ej2wn6JRBzA_0 skateboard +Ej7xV32Trwc_0 person +Ej8UwQiT5jk_1 knife +Ej8UwQiT5jk_3 knife +Ej_zFc5qxRw_0 cat +EkMGStKSilE_0 person +EkMdmPclE3k_1 dog +EkTrskvsL5c_1 horse +EkWd3wPBEyg_0 airplane +EkawSvsvh3g_0 person +EkdP_pWa9s0_1 airplane +Eke0rATHhX4_0 person +Ekh_cm7q1y8_0 cow +EklOuZWH-8Q_0 motorcycle +EkyydrsMSkY_0 person +Ek1DlGGsUdY_0 umbrella +Ek4323MkRYo_0 bicycle +ElJtz3uv-AQ_0 person +ElLiin7Cda4_1 person +ElLiin7Cda4_0 person +ElNzy4USrLA_0 truck +ElR4MuOUYKM_0 bird +ElgmQr70py4_5 train +Elrxptn-Zqo_0 person +EluRnlB_s6c_0 train +EluRnlB_s6c_3 train +ElwZ1M6McHo_0 skateboard +El2nzuCxrGk_1 horse +El5fRl-4vko_0 knife +El9Efl32L8w_0 person +EmDjVcaznIA_0 zebra +EmDjVcaznIA_1 zebra +EmDjVcaznIA_2 zebra +EmJeLKaG_hE_2 bird +EmJk7hDSzaM_0 person +EmJk7hDSzaM_1 person +EmJk7hDSzaM_3 cow +EmWzmxDjjOs_0 person +EmkwHglcEKA_1 motorcycle +EmlvoH2AxWs_0 person +EmqEntvqLw0_0 airplane +EmsMjm0VXJc_0 skateboard +Em44RLa7Qp4_0 person +Em_UT-f7q0E_1 train +EnJkvPAMuaM_0 train +EnJkvPAMuaM_3 train +EnJkvPAMuaM_1 train +EnL2FiVIuJg_0 elephant +EnL2FiVIuJg_1 elephant +EnS1Yte0Xzw_5 knife +EnS1Yte0Xzw_2 knife +EnUW7YSmli0_0 horse +EnVtYzkXwjM_0 person +EnbXP2xywwk_0 person +EnmwKpZJTQc_0 person +EnoNrjMNAC0_0 person +EnrcDrbyUxY_0 person +EnrcDrbyUxY_1 person +EoaeqRc88HU_0 person +EoallCLchmo_0 cow +EodtHMtH9zw_0 person +EojPQY8nQ2Y_0 train +EouV6Ut4NP8_1 person +EouV6Ut4NP8_0 person +EouZIHzCFq8_0 airplane +dYVtJPfJmf4_0 person +dYgPc190feM_0 person +dYgxCdKNrIo_1 airplane +dYjCbeBAgYs_0 person +dYmREF5dDkw_0 dog +dYosdOz5mZo_0 person +dYr1OKT1lCA_0 person +dYyHudM-fQc_0 person +dYyHudM-fQc_1 person +dYzh49Wr9bQ_0 airplane +dY9dlzr4w0Y_0 person +dZFiRqMkFPc_0 person +dZHJc_1os9Q_1 person +dZHJc_1os9Q_0 person +dZHJc_1os9Q_2 person +dZMQgxFHQPA_0 train +dZQ2o-4a5tU_0 person +dZSQXDQcafc_0 knife +dZUOCWwr2xs_0 knife +dZaFo3C_1ts_0 person +dZdvK41DxLI_3 car +dZio0uN6DHY_0 horse +dZio0uN6DHY_1 horse +dZjnkqYO2lE_0 truck +dZmG64W2CtM_2 umbrella +dZmG64W2CtM_0 umbrella +dZsXB4o-wdE_0 airplane +dZzfVDrmMj0_0 bird +dZzfVDrmMj0_1 bird +dZ1vVETiQAQ_0 person +dZ6ub2CEvbg_1 bicycle +dZ6ub2CEvbg_2 bicycle +dZ6ub2CEvbg_3 bicycle +daBl0Q92zLE_4 bear +daBl0Q92zLE_0 bear +daIJjuHo2EQ_0 cow +daMcE2oorrE_1 person +daWo89I2Tuo_0 skateboard +daWo89I2Tuo_1 skateboard +daWywQD6R4g_8 elephant +daWywQD6R4g_0 elephant +daWywQD6R4g_2 elephant +daWywQD6R4g_4 elephant +daWywQD6R4g_5 elephant +daWywQD6R4g_6 elephant +daXEykL8UQ0_0 horse +daZHZXfmY7k_0 cat +daaHTdFcx5o_0 boat +daaX2TXbYmo_2 airplane +dadAGYt0vS0_1 horse +dalHUNR5yAA_1 person +dan-4YoB-Vw_0 person +daoysu5sfUQ_0 person +dapxBMe8Wz8_1 person +daqWFFdK8Ck_0 person +dawGJDtHlcs_0 person +da4jNzO5wL0_0 person +da61HPBGEwo_0 bicycle +dbU6Fn_5bHI_0 bus +dbXr-9m66-U_0 person +dbdhdeVMuL0_0 bird +dbhGB6XW3fM_0 horse +dbxb42TzQ_g_0 skateboard +dbysY1V2TwI_0 person +dby-fBGIPRU_1 boat +dby-fBGIPRU_4 boat +db9i2fI8dv4_0 horse +dcADt99ndxg_0 person +dcADt99ndxg_1 person +dcBMrHLTvPo_0 person +dcEW4y5AI1E_1 elephant +dcHcm85hd5s_2 bear +dcH304rxwLY_0 person +dcJN3WJZLOE_0 train +dcLR55c41rg_1 horse +dcLoVk60Gkg_0 cow +dcLoVk60Gkg_1 cow +dcLp5mtSkPA_0 cow +dcO5id4LTVE_0 person +dcO5id4LTVE_1 person +dcO5id4LTVE_2 person +dcO5id4LTVE_3 person +dcO5id4LTVE_4 person +dcUA_Wf8vrc_2 skateboard +dcXdmOY1YCw_0 car +dcXdmOY1YCw_1 car +dcblbU5lyQU_0 person +dcdXiEQkghM_0 person +dcdXiEQkghM_1 person +dcf4zn9wOjM_1 person +dcj9u89LAu8_0 umbrella +dcoFS0-09xc_0 person +dcoFS0-09xc_1 person +dcwbXzJsVDw_1 car +dcxhSnf9sg0_1 horse +dc1_WHDpL3w_0 person +dc-BpV5fuQM_2 cow +ddK4WXTyoWw_0 cow +ddPN4QZuLBE_0 train +ddPxOsA2Cro_0 person +ddPxOsA2Cro_1 person +ddW0MYEUWlc_0 person +ddaqR7COVYo_0 person +dddKAnk7-hQ_0 umbrella +ddlPux88liU_0 person +ddruq0KhCxM_1 skateboard +ddsTE3NwHyM_0 person +ddtNIDCxqCk_0 person +ddw0wDJgJwM_0 person +ddxQR-NB6E4_0 person +ddzrzJEogWQ_4 motorcycle +ddzrzJEogWQ_6 motorcycle +ddzrzJEogWQ_0 motorcycle +ddzrzJEogWQ_1 motorcycle +ddzrzJEogWQ_2 motorcycle +ddzrzJEogWQ_3 motorcycle +ddzrzJEogWQ_5 motorcycle +dd0CsqY6Fbo_0 airplane +dd8a6btF_B4_0 person +deDEnw72hQk_0 person +deNoMwyFOO4_0 person +ded6WOfO9O8_1 person +deep6EOo6ds_0 person +deihMrgBXEc_0 person +delKGPVRJsY_0 person +demxgFkqGxA_0 bus +deqo50gGTBo_1 airplane +dew_lb_L9hE_0 person +dezAUC4KbJI_0 person +de1f8qTDYUI_0 person +de2HZ6DBOuM_0 person +de4mcJTPj48_0 person +de4mcJTPj48_1 person +de7-gbLffxs_0 cow +de8KeV2waGY_1 person +de8V1ovs5eM_0 person +de_fGa7Zxus_0 person +dfAvID4lRsE_0 person +dfAvID4lRsE_1 person +dfDTR9mCUZI_2 dog +dfEF6SMFbGM_0 skateboard +dfKBB3-VicU_0 bus +dfK1HsVc2B0_0 person +dfh2lETTLZI_0 skateboard +dfp4iVaXCpg_0 skateboard +dfqLJxxdinA_0 train +dfsTKKT5-UU_0 person +dfseA2X5Cow_0 person +df_PzyC0gTw_0 cat +df_SYY4pb3I_2 cow +dgGYa05XpYo_0 skateboard +dgIsZXSKACE_0 person +dgOQKwvhLpE_1 dog +dgTYRveHMjM_0 cat +dgYN1OH5oc0_0 zebra +dgl2b2bRpq0_0 person +dgtaJOOOtKg_0 person +dgweyIjmmDY_0 cat +dgyGZqXgvag_0 person +dg6u7R87Gh4_0 person +dhFII58PWhI_0 person +dhIL9wRZMm0_1 horse +dhIt9lg6Sbw_1 boat +dhUG1gnTlso_0 dog +dhZ-JmFNyak_0 person +dhcVp1GmJyI_0 elephant +dhcVp1GmJyI_1 elephant +dhgs2glg_N8_1 person +dhgs2glg_N8_0 person +dhiYTV7DJLY_0 cow +dhjeKi58cuU_0 cow +dhkFVTvJ6ZU_0 cat +dhy85XNJT3c_0 horse +dh03d5vq1B0_2 dog +dh1XFXciUf4_3 bus +dh1XFXciUf4_2 bus +dh6zZFXD0_c_0 elephant +diDDNe-MVfs_1 elephant +diMmgSNBO8k_2 person +diRn1fE6zMg_0 person +diSTaGHORrc_0 person +diSZzd4jM0E_0 person +diUCxWmV084_0 person +diZ-mRLPpqI_0 person +didB6Es7Des_0 person +didTjworKXg_2 umbrella +dif0t09rdZg_1 cow +dioELry6bbk_0 airplane +dix7GRytfcw_0 person +dix7GRytfcw_1 person +di1KJ0Mb5M8_0 dog +di2TPYyIeWc_0 dog +djIw9AQoU3o_2 person +djLPrNtPSY8_0 person +djLUJy1sWMg_0 cat +djNzrBpqnnY_0 car +djSxYfG99k8_0 car +djaGBINLXTQ_0 elephant +djh9QeYLg7M_0 airplane +djiTvgkjTW4_0 train +djiTvgkjTW4_3 train +djiTvgkjTW4_4 train +djiTvgkjTW4_5 train +djiTvgkjTW4_7 train +djlet5--ZW0_0 person +djlet5--ZW0_1 person +djpCG2oprrA_1 person +djvQyzGNp7o_0 person +dj2Qk--KIkk_0 person +dj6yGGCBFWc_0 person +dj8d91U-F_0_0 person +dkQWD9hv4fo_1 train +dkQbDCav3eM_1 person +dkSetHNXnNY_0 cow +dkb-6x7zo5E_0 person +dkdCTCL5imo_2 truck +dkdCTCL5imo_3 truck +dkdCTCL5imo_4 truck +dkiOcFZwrA0_0 bear +dknj-Sv4HUs_1 person +dkpsViIYlsI_0 cow +dkw4aWG9l6E_0 bear +dkw4aWG9l6E_4 bear +dkw4aWG9l6E_5 bear +dkxLcr2kvIM_1 horse +dk3Nf8K3RzI_0 boat +dk4gT0vHgeU_0 person +dk6h_GL9OZo_0 person +dk7QISqnWZc_0 bird +dk7juEuA2is_0 bear +dk7juEuA2is_2 bear +dlAMvsjssrY_0 person +dlDsSVM3JJ8_0 person +dlG7MtSpAK4_0 person +dlIG99k9Hoo_0 elephant +dlIkYaty1Uw_0 car +dlNMnGKJJjU_0 cow +dlQ1Gr54T74_11 bicycle +dlQ1Gr54T74_14 bicycle +dlQ1Gr54T74_5 bicycle +dlVOuZK_1bY_1 person +dlVTSnDsl38_1 knife +dlW_HPbVriI_1 truck +dlW_HPbVriI_3 truck +dlW_HPbVriI_0 truck +dlW_HPbVriI_2 truck +EpH59JsxI3w_0 car +EpIb8r7uBqM_0 person +EpJ_M6rB_PA_1 bird +EpOaQjhIh_M_0 airplane +EpP_TLXxb7Y_0 cow +EpSURaF1BfY_0 truck +EpT8zxDFPf8_0 cow +EpVdzlk5GYU_0 truck +Epd3r6iiqVk_0 bicycle +EpeIZCFbjw0_0 skateboard +EpnttpyYTAo_0 person +Epoqtu0Pqe4_0 cow +Ep8bd1STWKw_0 motorcycle +Ep81Lk66O50_0 person +Ep84L7WDoyE_0 person +EqBJeYu5f_E_0 elephant +EqBJeYu5f_E_3 elephant +EqHBjvHkvf0_0 person +EqJR5UZAlSg_1 car +EqLYPeo9ZC0_0 person +EqMqvcHp8Ko_0 car +EqMqvcHp8Ko_1 car +EqSYKCxmeDA_0 dog +EqSYKCxmeDA_1 dog +Eqh7XqsYl5M_2 person +EqmnFPweBmk_1 boat +EquATbp9uL0_0 person +EquATbp9uL0_1 person +EqvMMBAZP2o_0 person +ErUllSQJNgI_4 elephant +ErUllSQJNgI_5 elephant +ErWUOje4g8Q_0 motorcycle +ErX04vJ-JcU_0 cat +Erf0FkqYsTE_0 person +Ero36xFQKS4_0 truck +Ero36xFQKS4_1 truck +Er4yJXTWNNo_3 bicycle +Er4yJXTWNNo_4 bicycle +Er4yJXTWNNo_5 bicycle +Er5D0fXZsjk_0 person +Er9tboOA5k8_0 person +EsEreMKZP7Q_1 person +EsQ05q5ZZVM_3 skateboard +EsQ05q5ZZVM_5 skateboard +EsQ05q5ZZVM_2 skateboard +EsYZbF7hCTE_0 person +EsZV26-jxX8_0 motorcycle +EsbWwOYbT8Q_0 train +EskqA8x8mX4_2 airplane +EsrUSkNrqWs_1 person +Es0O5wtTZ2Q_0 person +Es9GOUryI0U_0 person +Es9Yq8uZ4fA_0 person +Es-W0AxQ5Us_1 cow +EtebDuK3fUY_0 person +EtlKR9-Q2dk_0 person +Etx8YkcrSF8_0 person +Et0RRuaW-Rg_1 dog +Et1PKq61KAk_0 person +EuETmswYRrs_0 cow +EuHJB5UXmZg_0 umbrella +EuHvelij5ao_0 cat +EuIGG3PoslE_0 person +EuInxfWuqqA_0 person +EuZnOeXR020_0 person +Eua2VIbXEMs_0 boat +EufXUqphYVw_0 person +EumfsHXsVGk_0 person +Eunz2V1RXXo_0 train +EurWaA7qCDw_0 bear +EuwjSGtSYlY_0 person +EuwjSGtSYlY_1 person +EuzDIk8ag30_0 person +EuzVaAXsy4o_0 motorcycle +Eu0nzh2HQNk_0 person +EvDZK2cFYVE_0 motorcycle +EvGoGf-YCA8_0 bicycle +EvKPt0vynKY_0 truck +EvN8x67_EQ0_0 person +EvZF9DagIoQ_4 horse +EvZF9DagIoQ_0 horse +EvZF9DagIoQ_1 horse +EvmcyDEPnoA_1 skateboard +EvvbUe6FBSM_0 bird +Evvij-hmE4A_0 person +EwBKceBTBbo_0 dog +EwBwIUrHR3o_0 person +EwBwIUrHR3o_1 person +EwDyryqt94g_4 airplane +EwDyryqt94g_5 airplane +EwKIz0qAvKQ_0 person +EwSJeylFWsY_0 person +EwUGFtWeyMA_0 person +EwUeAvO5mrE_0 cow +EwU8puKxN8Y_0 person +EwU8puKxN8Y_1 person +EwWCc9whfDI_0 cow +EwYNowdS57c_0 person +Ewet2EA1xX8_1 elephant +Ewet2EA1xX8_2 elephant +Ewet2EA1xX8_0 elephant +EwozH_35SDg_0 person +Ewq-V9jATzg_0 person +Ew8lEc8Ufi8_1 bus +ExCPGilpuMM_0 person +ExCPGilpuMM_1 person +ExCjkt_zXuw_0 person +ExCjkt_zXuw_1 person +ExJjWM_rAnI_3 airplane +ExJjWM_rAnI_1 airplane +ExPBVcERfwY_1 person +ExPBVcERfwY_3 person +ExPBVcERfwY_4 person +ExT3xg9phtQ_0 person +ExVHmko3jfY_0 horse +ExW1ju88BW8_0 cat +Exb1TjMi76I_0 boat +Exc3W9o5-04_1 horse +Exe2EizU9VQ_0 cow +Exe2EizU9VQ_1 cow +ExfZl3DY8JM_0 person +ExfZl3DY8JM_1 person +Exl9alp64lE_1 person +ExqpcHBGBlw_1 person +ExvcP05yrS0_0 person +ExvcP05yrS0_1 person +ExxZODpPkQQ_1 train +Exz2WL2-kR0_0 giraffe +Ex4__JMKkqI_0 person +EyMzZV5iTEA_0 horse +EyP_0uEuXVs_1 bear +EybT7tq6XGk_0 person +EymmgPoUyuM_0 person +EymmgPoUyuM_1 person +EymmgPoUyuM_2 person +Eyn7IfnWm4o_0 airplane +Eyn7IfnWm4o_3 airplane +Eyn7IfnWm4o_1 airplane +Eyn7IfnWm4o_2 airplane +Eyp8nornJW0_0 bear +Eyp8nornJW0_1 bear +Eyrfi9lGdoo_1 airplane +EyuKu6qMB6g_0 person +EywYZ3Gjwuc_0 person +EywnxH68jDU_0 cow +Eyzwbz1ZxmU_0 cat +Ey2TgrQ30Z0_1 bicycle +Ey2TgrQ30Z0_2 bicycle +Ey36TlCS4rQ_0 person +Ey4BLGQL2Bg_0 bear +Ey7eosaz0zU_0 person +Ey7us0SSVAs_0 airplane +Ey7us0SSVAs_2 airplane +Ey7wIzCkFU4_0 person +Ey7wIzCkFU4_1 person +EzC0tuKaVGA_0 person +EzEX4OUEHHQ_1 skateboard +EzGa4SSPsbI_0 bicycle +EzYjRjhff20_0 person +EzZEWp1cluc_0 person +EzeDITt3y5I_0 person +EzeDITt3y5I_1 person +Ezlyx_EudUQ_0 person +Ezlyx_EudUQ_1 person +EzuizVcVbSA_0 person +Ez6I4TpzC5I_0 person +E0K5Ll7wHUw_0 bird +E0YZDyUoHTM_0 knife +E00cOMpNw3o_0 motorcycle +E01EgIBFxRk_0 person +E038teDC3EM_0 person +E0-Z0KM1UB4_1 person +E1AwHXQ00ns_0 person +E1MTmF3FAN0_0 bicycle +E1NfSTmGCRE_0 knife +E1ZhuBRYvKY_0 cow +E1bNSKg9iv8_0 horse +E1oEO09-bAw_0 dog +E1pmsS_ufrs_0 person +E1xPwEvYymk_1 person +E1xPwEvYymk_2 person +E1xPwEvYymk_0 person +E1zxNG3Fglo_0 bird +E17S76lXHfI_0 person +E1_ETAQHwcM_0 person +E2O5Y6VAhIc_0 person +E2O5Y6VAhIc_1 person +E2Pobz5qoAE_0 person +E2Pobz5qoAE_1 person +E2Vqlq1BQYs_0 airplane +E2WWQOKGeb4_0 skateboard +E2aiCls-clY_0 person +E2lj1iRVceA_0 skateboard +E22IW-PgLfU_0 person +E28Cad7vBrw_0 person +E28Cad7vBrw_1 person +E29-bZY3lEo_0 airplane +E3NmlH6taDs_0 truck +E3SKOBDl6u0_0 person +E3enDSeq6P0_0 person +E3tmvYSpQSQ_0 person +E35M5UWMXeE_0 horse +E35M5UWMXeE_2 horse +E4Bl9c7JbYs_0 person +E4DFW1SxJfY_0 dog +E4DFW1SxJfY_2 dog +E4TfSUdVt8U_1 truck +E4pulnGY9X8_1 person +E43SZ65LnfY_0 cow +E45LqepDuqg_1 person +E5BtXla2lCQ_0 bicycle +E5CQkNJct6Q_0 motorcycle +E5HB-EDNtE8_0 person +dlZZzrMO6yY_0 person +dlbAWAuByWk_0 person +dlcovhFKigE_0 person +dlh5RGS5Bzw_0 bird +dlkVXsIhcZg_1 person +dlo83yH621I_1 cow +dl2g71ftw9A_3 train +dl2g71ftw9A_4 train +dl2g71ftw9A_5 train +dl6ogvuxF78_0 person +dl_fuQYhAP8_0 person +dmDdRd6wULk_2 dog +dmJ1DuWiAdM_0 person +dmMz5FhGOCc_1 person +dmVAi4WMi3M_0 person +dmVAi4WMi3M_1 motorcycle +dmVAi4WMi3M_3 motorcycle +dmW77KHtuCQ_0 horse +dmYSNG-7VCg_0 elephant +dmfX7DsSS1k_0 bicycle +dmuWxnAfMn4_0 elephant +dm4rFNN7FZQ_0 truck +dm-lOmiP2d8_0 cow +dnAQ7q60f_g_0 elephant +dnB0we4_DrY_0 cow +dnB6auv8PBk_0 person +dnFZkG7_E1w_0 person +dnNh07bnI_s_0 cat +dnUXo5nstys_0 person +dnVV1s-LcAY_0 person +dnY-4hOzYts_1 person +dncQtuB_6qA_0 motorcycle +dncxd1B2sLk_0 giraffe +dnwqVE3lPyY_1 train +dnwqVE3lPyY_2 train +dn_r7u_5apk_0 skateboard +doHOuG6wqXY_0 motorcycle +doSDuIGLFXY_0 cat +doTj5H8Uf1I_0 cow +doUwj_z1x5o_0 elephant +doX3oiADm_s_1 person +domu9ia2Vo8_0 person +dorx67yK7WU_0 bird +dovn1QHCR7o_0 person +dowbL0CZ5do_0 bicycle +do1QIWrYeW8_0 person +do5o5Dw0vPc_1 elephant +do5o5Dw0vPc_4 elephant +do7abiC5aZk_1 car +do82ENX9cOc_0 person +do-LmSJTPj4_0 skateboard +dpDG64ULlUg_0 boat +dpGCSoTITrw_2 elephant +dpJWbIaQYoI_0 person +dpJWbIaQYoI_1 person +dpQP5r61_GQ_0 person +dpUorqkSYZE_0 dog +dpYYMgh5TS0_0 truck +dpcwUs5srlc_0 horse +dpi0u6pfCTM_0 person +dpjLyHb9AyI_0 person +dpkF3SwOunc_0 dog +dpn6vUVXBuM_2 umbrella +dptZbHZQYPM_1 dog +dptZbHZQYPM_2 dog +dpxGzRQqAaU_0 motorcycle +dpxGzRQqAaU_1 motorcycle +dpxGzRQqAaU_2 motorcycle +dpxVPiv62SY_0 person +dp2cUWhnP0A_0 knife +dp3Q_aTYeJ4_0 person +dp_JQh45a50_0 person +dp_1VrEUWbU_0 person +dqCFYWRf9g8_1 elephant +dqDLl7BlAAA_0 skateboard +dqFRS9o1CSU_1 person +dqOoL5LiXc8_0 boat +dqQPbKE4UhQ_0 person +dqTlCZzLk6A_1 cow +dqWEwvhVNiI_0 person +dqavRiIA-38_0 truck +dqj-msAUvnc_0 cat +dqzc4W6f-x4_1 person +drAhAL_F38Y_0 person +drAh2lmjDs4_0 skateboard +drJGoPHMunk_0 person +dreDU-1isrI_0 person +dre_PgfS8yw_0 elephant +drf5ijiEkUo_0 person +drm2oJ3X1HM_0 person +drqFwF60pgE_0 airplane +drqFwF60pgE_1 airplane +drqFwF60pgE_2 airplane +drqe2hP0PKI_0 person +dr3TumG_tlI_1 cow +dr4dU5UDF-Q_0 person +dr8s5VC9Fxg_1 person +dsLbM2wZHrc_0 dog +dsPwJ3J1ZKA_0 person +dsTR1vv9XLE_0 person +dsTR1vv9XLE_1 person +dsUuAVsJSi4_1 motorcycle +dstcI7MYsZ0_0 person +dsyBSejpe-k_0 person +ds1BJMsasQI_0 person +ds6FmQYwgYw_0 skateboard +dtDGbuCwBuY_0 bicycle +dtHgnX0NtxE_0 person +dtMbzXL9wO4_2 bear +dtOFqz41TJ0_0 bird +dtR2UeJbIvg_0 person +dtWfbusf4Es_0 horse +dtYdUj-d8fA_0 train +dtZrB9iDzgQ_0 horse +dtlUL4D7_NM_0 bird +dtvZaXxNgKQ_0 person +dtwUG12h74g_0 person +dt8Tngmse50_0 bicycle +duOX3z4IJSY_0 person +duTvmDpj0sI_3 boat +duTvmDpj0sI_2 boat +duV82Wn9rXk_0 car +duZYUVeDXEM_0 cat +duaO7S-EH1A_1 person +ducdg4KXQsg_0 person +duoFWPZbeNc_0 person +dupnmzaPsWA_6 elephant +dutp3txJPTY_0 person +duvuNqufLjs_0 cow +du5hbB5w3UU_0 horse +du96VR7vtOk_0 bird +dvKKmu56UkE_0 person +dvS2DSYGOGg_0 person +dvbVbBosw38_1 person +dvgf3R9k0uY_0 bird +dvur4MZD_yc_0 person +dvur4MZD_yc_1 person +dv0ptUC-DIE_0 person +dv6ymk8duso_0 bird +dv_KURooPDU_0 person +dwbRsYPV7Ag_0 person +dwpopXTeeGc_0 person +dwrYJ92znpw_0 cat +dwy7k_gtEco_1 boat +dw8kejnR7L4_0 person +dw-2_KqGeYY_1 bird +dxFrLHoW9jI_0 motorcycle +dxGlDl4IukI_0 horse +dxGlDl4IukI_1 horse +dxViI6VXh6Y_0 dog +dxn8VDPNvJM_0 person +dxq9r-qrJ2A_0 person +dxsQn1MuZRA_0 bus +dx0z7DYxGSw_0 person +dx4rtOOz7tA_1 umbrella +dx6ucdpKZP0_0 person +dx8nEHWD1xc_0 person +dyAC2ey1DQU_4 bird +dyJ83t1zgkU_0 skateboard +dyPMbIsTtFs_0 person +dyPt3VKGZPo_1 person +dyR4vnjF5do_0 truck +dyZixtbxEE4_1 person +dym-lDsiSTM_0 boat +dyt8LtUqIMU_0 boat +dyy3oxsiErU_19 truck +dyy3oxsiErU_14 truck +dy2J0aeX5eQ_0 truck +dy3nkqKOjbk_0 person +dy6zETD5NFo_0 cow +dzEKq7fsVnQ_0 train +dzNRDfnNbeE_1 person +dzS2ClyakEg_0 truck +dzXv_YFLPqg_0 person +dzahMuEcbCM_0 cow +dzeNnQOePGs_0 person +dzhSVb26d7Q_0 umbrella +dzoQb8C3vxE_0 person +dzsHYOJpBbY_0 bear +dzv-u3s_YtI_0 person +dzyVndvBofo_1 horse +dz3SP1rd9zE_0 car +dz_ATSJBx6k_0 airplane +dz_ATSJBx6k_1 airplane +d0J7uodSxF8_2 motorcycle +d0NY8eqs19s_0 motorcycle +d0NtMMBjQp0_1 truck +d0NtMMBjQp0_2 truck +d0NtMMBjQp0_0 truck +d0RIwZfoGNg_0 person +d0ZEYzyD9Vg_0 person +d0b8-K_6D68_0 umbrella +d0hJditcWj4_0 person +d0hQQC2i1Y0_0 person +d0hQQC2i1Y0_1 person +d0hdtlKidzs_0 person +d0h9QWelhII_0 boat +d0lVKBOzOQ0_0 skateboard +d0qGN1A7XJA_0 person +d0vHpkvShqg_0 giraffe +d0vUARlHvjc_1 cow +d0v47QFRyvg_0 person +d0v47QFRyvg_1 person +d00UKAQHK2A_0 person +d02xOzIVP-s_0 person +d04Dr38addQ_0 airplane +d09H7U6x-Fc_0 cat +E5OHeMbBp9s_1 giraffe +E5RbbN1bPN8_0 person +E5YibOn90Co_0 skateboard +E5b9Yug5vbk_0 bicycle +E5b9Yug5vbk_4 bicycle +E5b9Yug5vbk_1 bicycle +E5b9Yug5vbk_2 bicycle +E5b9Yug5vbk_3 bicycle +E5dBaFyBYX0_0 airplane +E5me_giHEOE_1 person +E5trQkGM3Wk_0 cat +E5wZ4pk5X0I_1 train +E59OnpOGBLU_0 skateboard +E6Am4hIuXvk_0 person +E6Avey2AVRM_1 person +E6A8vfHTdOQ_0 person +E6EtoMfo384_0 train +E6EtoMfo384_1 train +E6GvpwdOQrw_2 train +E6GvpwdOQrw_3 train +E6GvpwdOQrw_8 train +E6JLxU918TE_0 bicycle +E6XGO0hx4N8_0 person +E6Y2QsetU0M_1 person +E6s0XT5G7Eo_0 bird +E6s0XT5G7Eo_1 bird +E6uGh-cPDjI_0 bicycle +E62w4NFSm5E_1 dog +E64d0EH39M4_0 train +E67ceZopcqQ_0 person +E67ceZopcqQ_1 person +E68IhhK04s0_1 giraffe +E68IhhK04s0_2 giraffe +E7BIM8cnCrc_2 train +E7BIM8cnCrc_0 train +E7F0Gt3Rea4_1 person +E7F0Gt3Rea4_0 person +E7LY2yKO0Jg_0 knife +E7MvCesCxNk_0 knife +E7dG4qPI_QY_1 knife +E7eYGQjaVYs_0 bird +E7hXPqOOiqo_1 boat +E7hXPqOOiqo_0 boat +E7qoCZ2e-vQ_0 dog +E7rhwzBxMqY_0 person +E7zwjNToyao_0 person +E70FO7I2AQ0_1 person +E70FO7I2AQ0_0 person +E76moy2SQhA_0 person +E8JYTxKfqmQ_0 boat +E8OzYJ2gVAs_1 bicycle +E8OzYJ2gVAs_2 bicycle +E8OzYJ2gVAs_3 bicycle +E8RSSepY8tk_0 person +E8R5lzlo5qw_0 motorcycle +E8Xxr8SUaEY_0 horse +E8h4YnZbJg4_1 person +E8n_eTUwyhc_0 person +E8pbsHhMGOw_0 person +E842T5CgJfk_0 person +E854nPMWssI_0 horse +E8-Z9saoTjk_0 person +E8_NjWtQtgI_1 car +E9J2Brm4LSg_0 truck +E9J2Brm4LSg_1 truck +E9N59GTZ8uE_0 person +E9R_qLxcZdY_0 bird +E9S5Tk5r2wU_0 person +E9ZjM9SY__o_1 person +E9ZjM9SY__o_0 person +E9sCn_XaSHw_1 bicycle +E9sHGoiMmXc_0 person +E9zmtafFrCo_0 dog +E9-1FSPKZ7k_0 person +E-DE7HZ04WY_1 person +E-OdBMMpwlo_0 umbrella +E-VRMpgKXIE_0 elephant +E-VRMpgKXIE_7 elephant +E-VRMpgKXIE_1 elephant +E-VRMpgKXIE_2 elephant +E-VRMpgKXIE_4 elephant +E-YDPyDXtR8_0 cow +E-h1XNBlqsE_0 person +E-pnZZeRFyQ_0 person +E-q9j7xipsA_0 cat +E-seUZ3B-Ts_0 motorcycle +E-zFmY_9LWk_0 horse +E-0FMMDuLw8_0 person +E-3jsRP7KHc_0 elephant +E_En6n1IyBw_0 elephant +E_GC0IeKtu4_0 person +E_K6zdkr0mo_1 person +E_Xi5uEIiec_2 bicycle +E_e6E8T7on0_0 dog +E_02tA9RLyw_0 umbrella +E_7qbAkVDYE_0 elephant +FAKE4Rfwdik_0 person +FATjlgllzBU_0 person +FATjlgllzBU_1 person +FAdlwBJZk78_0 elephant +FAeK9y98GL8_0 zebra +FAiIhoJh5uQ_0 cat +FAm6HgSzPTA_0 cow +FAn11rZ-gsU_0 person +FAqiar6B2U8_2 bird +FAu0yvyjW-Q_4 boat +FAu0yvyjW-Q_9 boat +FAu0yvyjW-Q_1 boat +FAu0yvyjW-Q_5 boat +FAx0CsAigS4_0 motorcycle +FA_K15dKk6k_0 bear +FBAcUphtxR4_0 person +FBIVWWIbq-8_1 cow +FBIawPqElJ8_0 bus +FBKIUCHqUQk_0 skateboard +FBKIUCHqUQk_1 skateboard +FBNFSYoMCNM_0 bird +FBOWbksU5pI_0 person +FBOWbksU5pI_1 person +FBjp-C_Sbug_2 bicycle +FBjp-C_Sbug_11 bicycle +FBnFn5mY2R0_0 person +FBwWw9c4KdY_0 person +FBz0aAYDBFI_1 person +FB8F1ku1XkU_0 person +FCBsCwjCPWU_0 person +FCQB6p_GcDY_0 person +FCRAvY0glAI_0 airplane +FCd1d_7Hfpg_0 umbrella +FCkT11nk468_0 airplane +FClLRpdDi9A_0 person +FCnE02wQQk4_0 bird +FCp7AKKYViY_0 person +FC-ONjCL7tM_0 person +FC_gwQU4yrs_0 horse +FDJyHtHix-0_0 train +FDYS2AyPJhc_0 person +FDZBIlbFrk0_0 person +FDej1TTCjP0_0 umbrella +FDfaLuM3y5A_0 person +FDkiv1x0OGQ_0 car +FDq3yKNo4Qs_1 person +FDvTPzckQKc_0 motorcycle +FD3pT-lj2tc_0 cat +FEM7OGFO_BI_0 elephant +FEN0F0V1nhg_0 dog +FEOAvRWKb-k_0 airplane +FEU4yHFzkZs_1 person +FEU4yHFzkZs_0 person +FEWZolQuMv0_1 person +FEfYdrS3kFc_0 bird +FEjcdYO4xPo_0 person +FEoFDmI0pxI_0 airplane +FEzBza78J4w_0 person +FEzBza78J4w_1 person +FE0DpZ9GXoM_2 person +FE0DpZ9GXoM_0 person +FE0DpZ9GXoM_1 person +FE0Q5phKq3c_0 person +FE0Q5phKq3c_1 person +FE4gj8EYF9k_0 person +FE51Dml-nZY_0 person +FE7iv_llNT4_2 bicycle +FE-JTPLk3fI_0 truck +FFCtm1GZH_s_1 bird +FFHJUeZ_KKE_1 truck +FFHJUeZ_KKE_2 truck +FFLxkwDj1b0_2 bus +FFME8B_6LNA_1 motorcycle +FFQl2DLyjdk_0 cat +FFQl2DLyjdk_1 cat +FFantnd2gLY_0 person +FFantnd2gLY_1 person +FFd_4DPNyRI_0 car +FFijp_s0YwA_0 dog +FFi3nSvA0WY_0 person +FFjqbw4R9l0_0 cow +FFm26XU-R7c_2 person +FFm26XU-R7c_0 person +FFm26XU-R7c_1 person +FFndlV1rKas_0 airplane +FFpyQ_5PU7M_0 bus +FF9eHa3K8fM_1 bird +FGO6y3WssIg_0 person +FGQCxd5EAx0_2 airplane +FGQCxd5EAx0_3 airplane +FGQCxd5EAx0_1 airplane +FGcS28ri5uY_0 person +FGdEufjjhtg_0 person +FGicL13npRI_0 person +FGkNC4hzcfM_0 person +FGkx6qk4oDk_0 person +FGmjmDC1RoU_1 skateboard +FGmjmDC1RoU_0 skateboard +FGoutavzP5Y_0 person +FGqrkJ3h0DA_0 skateboard +FG0PrdHReB0_2 person +FG5l2wX8ccA_0 horse +FHAj71IwE7E_0 skateboard +FHA6nVCnv28_0 person +FHB5eraeYEw_1 knife +FHJupOaUmtQ_1 train +FHOLOunv9Ec_0 horse +FHTc_V_05W0_1 bird +FHT1DAZpJVY_0 cow +FHZ-3pbJQrY_0 bird +FHgO4zu5RGA_0 person +FHu50D73Fzo_0 person +FIA67WzAuNs_0 bear +FIA67WzAuNs_1 bear +FIB12MYkANg_1 bear +FIDI0sZMPVU_0 person +FIGhnuJWX5M_0 person +FIGhnuJWX5M_2 person +FIHYnB8Jrh4_0 person +FIMbYQASgkk_0 horse +FIQ1iL3jVkM_0 giraffe +FIV4OFmfS_s_0 person +FIV4OFmfS_s_1 person +FInOWVIV_go_0 motorcycle +d1N4NJqa_8E_0 person +d1PqtOyYTY0_0 train +d1PqtOyYTY0_1 train +d1PqtOyYTY0_2 train +d1Quy8k5O88_0 cow +d1UWs3bPTsc_0 person +d1UWs3bPTsc_1 person +d1YYgiXq3tw_0 person +d1YYgiXq3tw_1 person +d1bzn92PO0c_0 person +d1eo2OWc45Q_0 cow +d1tf08A41eo_0 person +d1ukwE8h4f8_0 horse +d1wbMXvcgNc_0 person +d1wlubAM1-k_0 person +d10K79pdybE_3 train +d14rOFFvTg4_0 person +d14rOFFvTg4_2 person +d14rOFFvTg4_1 person +d165nDy63o8_0 bicycle +d165nDy63o8_1 bicycle +d17kaiZ5Ztc_0 person +d2DRRd9l3TI_0 person +d2RD5tyZt6c_0 person +d2TxcbWHoBM_0 cat +d2WfBDEMf40_0 truck +d2ZGi2fOtPY_0 person +d2cDVorBK8s_0 airplane +d2cDVorBK8s_1 airplane +d2e49A9MnF4_0 person +d2lSueNvuG4_0 horse +d2ns5iCGj78_0 elephant +d2sn_b1z1Vw_0 person +d2wHwCwQymw_0 person +d2zgNRFDpSw_1 bird +d203fSHLzv8_0 train +d21TfucuHss_0 umbrella +d217pENbZVs_0 person +d28DHw2okF8_0 person +d3F_Gm514J0_2 elephant +d3G8COtsJco_0 person +d3MN8Sm5tiY_0 person +d3MVAijPTjY_0 motorcycle +d3P2bH2t8IQ_0 person +d3Wdg9MPgLA_1 skateboard +d3Wdg9MPgLA_0 skateboard +d3duKA35FEI_0 person +d3jP_YP-6EQ_0 person +d3ro5gubiaQ_0 person +d3ro5gubiaQ_1 person +d3rzFaWiWwA_5 truck +d3sHFgbvhIU_0 car +d33yoN6QyYg_0 bus +d36tDEgs-IA_0 person +d4A2uUrnVWI_0 person +d4Cumy6qZPY_0 truck +d4DbIWORtjY_0 person +d4DbIWORtjY_1 person +d4GvMFc_Vqg_0 knife +d4Le0GuzhaY_0 skateboard +d4QkJdQwkCo_0 motorcycle +d4VJot5IZek_0 person +d4VJot5IZek_1 person +d4WRTfC57h0_0 horse +d4b9-LX5V1s_1 cow +d4hB6abJCs8_0 person +d4mhHPSo7C8_0 skateboard +d4q-0AcOs78_0 person +d4vhL4dar5s_0 giraffe +d4vhL4dar5s_1 giraffe +d45YTUkd_9M_0 person +d47DPSbvftI_0 person +d484zxSSkJM_1 person +d4_lDGwny4k_0 skateboard +d5Ao3JBz7WM_0 person +d5B0EMjLeZE_0 person +d5PBtpn_6JQ_0 person +d5gDBPwofbs_0 person +d5gDqlNLGmw_0 person +d5hj8eaC5fQ_0 person +d5jIlHa1Y6o_0 cow +d5m8giMORSk_0 person +d53_McJDtt4_0 person +d55FAEl6kfM_0 cat +d55rz05ynyg_0 airplane +d6AkvjKCaE0_0 person +d6AkvjKCaE0_1 person +d6TWHVESLa8_6 cow +d6TWHVESLa8_5 cow +d6VCXnnHXGQ_0 person +d6VCXnnHXGQ_1 person +d6YTAD3T2i8_0 person +d6a2EN1cB-4_0 person +d6cgbxc35Ms_0 person +d6mM21E4x-4_0 umbrella +d6m3DUG5E7Y_0 person +d6uLbEhrIvw_0 airplane +d65wDJoMyA8_0 person +d67YXl13SSo_0 person +d6-bn34gHFc_0 person +d7H5qLPNFz0_1 elephant +d7cwZ3G7xSU_0 bird +d7kWNGqyvRk_0 person +d7mQdSSoZ2E_0 person +d7m0BF65qro_1 person +d7m0BF65qro_2 person +d7n5m9UuhP4_0 person +d7n5m9UuhP4_1 person +d7yxmt8AvOM_0 person +d7yxmt8AvOM_1 person +d71rdGKeKkE_0 person +d74EhPMCxb0_0 person +d7-3m4Nz8fk_0 horse +d8CJ5urtRlk_0 train +d8HIJN0pULI_0 person +d8XcNMVXCD8_0 bicycle +d8b-SN3JEvk_0 person +d8dPRbquLuM_1 person +d8dPRbquLuM_0 person +d8t8y3kLzgc_0 person +d84iekZaJHc_4 knife +d9JyT5Kko5c_0 person +d9LvxSh5P-Q_0 person +d9OaiymMq0w_0 person +d9PCSJzZTy8_0 person +d9Pj3WrvXXc_1 person +d9S0dKjWhNU_0 person +d9S0dKjWhNU_1 person +d9S0dKjWhNU_2 person +d9YlucRFs0U_0 person +d9cSZXEb_5E_1 person +d9dysX9rdmA_0 skateboard +d9hh6urZ5FU_0 train +d9kzobAaimY_0 motorcycle +d9lIw5maa3M_0 person +d9qijNyVVmU_0 person +d95k-74VSVE_0 cow +d-JD-mAXyIA_0 dog +d-Mnc38YAmw_8 truck +d-OQw6tKhuM_0 knife +d-S3AmiMI1s_0 car +d-e8mKtYWjk_0 person +d-e8mKtYWjk_2 person +d-e8mKtYWjk_1 person +d-fv8fmGSlY_0 person +d-hMPjLP2WE_0 bicycle +d-hMPjLP2WE_1 bicycle +d-hgDDQ3kwg_0 person +d-h6ncywZ58_1 person +d-h6ncywZ58_0 person +d-oFe9Z0Obs_0 dog +d-oFe9Z0Obs_1 dog +d-rpsQgR8sw_0 person +d-22m5Sq5OU_0 elephant +d-5xdAZSjX8_2 skateboard +d--9RMf5LCA_1 boat +d_AudyfCYzg_0 car +d_EP2nM4YMw_0 bus +d_ElAbuvxGQ_0 dog +d_ElAbuvxGQ_8 dog +d_SB-LVXyi0_1 horse +d_SmnRMWLD8_0 dog +d_S0JCKcFCg_0 cow +d_hsQ2L-klo_0 person +d_nTA-SKHNM_2 knife +d_nTA-SKHNM_6 knife +d_ocJQiPpn0_1 skateboard +d_vnePeLmwI_0 person +d_2HhXHP8fg_1 cow +d__UUbvo2t4_0 person +eADPEBi8wWs_0 car +eADPEBi8wWs_1 car +eADqJI9JKq8_0 person +eAFdLVF01GU_0 bicycle +eANH6WnEpPs_1 person +eAPcJi7CaBw_2 horse +eAPcJi7CaBw_1 horse +eARl2H_FaEU_0 cat +eAXN0KAt66I_0 person +eAXN0KAt66I_1 person +eAYoRncVO74_1 person +eAZbke5Perk_0 car +eAfmOFI5jUM_0 horse +eAsHKktPNSo_1 horse +eAvDt4p-AvA_1 knife +eA3lmhfjTuM_0 cow +eA5hiUXY2_Q_4 airplane +eA5hiUXY2_Q_6 airplane +eA7FV9uQbYw_0 bus +eA8fIAfGi5k_0 person +eBB5vRA9JPE_0 knife +eBHEKUkaBcI_0 bird +eBLisw9b8i8_0 cow +eBLisw9b8i8_1 cow +eBLisw9b8i8_2 cow +eBMqhmQr7vI_0 bicycle +eBRcZ5KDeEA_0 knife +eBgLKDW3lH4_0 person +eBmdALv9WEE_0 person +eBwWJ_geg4Q_0 knife +eBy554vRg9M_0 person +eB83_xIotrw_0 bicycle +eB83_xIotrw_3 bicycle +eB_ZHbAvx-c_1 person +eCInOWr32gc_0 dog +eCNG8qj36vs_0 cow +eCSzfVb87kI_0 person +eCUuH2vPeDI_0 person +eCWhtTVetLA_0 umbrella +eCeVtq40bcM_4 bus +eCf8h359-j0_0 bus +eClBvJnyYa4_0 truck +eCmgHa6ThE4_1 person +eC3Fwv7Uows_0 person +eC-5SEhAGvo_0 cow +eC_fRVwxsiI_0 person +eDJamx945Ao_0 elephant +eDJamx945Ao_1 elephant +eDSAGlcfwKA_0 person +eDSmePW-Vrg_0 person +eDXqzj7vKFI_0 motorcycle +eDX2HUt9ttU_0 person +eDX2HUt9ttU_1 person +eDuzDDESzU0_0 person +eDwjZL3IGqM_0 person +FIrviDrZriY_0 bus +FI2T176uKi4_0 person +FI4oF175yHo_0 cow +FJCE3uzu0i4_0 dog +FJL5lb3wBKI_0 airplane +FJPRJ0A8BII_0 boat +FJVcRzA_pdI_0 airplane +FJdcStnbgU0_0 person +FJl_FwYbg8s_1 knife +FJmyu27Omwk_0 person +FJsMdQrRgFs_0 train +FJvHbRGgbXM_0 giraffe +FJvSXVq8PPk_0 bicycle +FJxbfz8q8Qw_0 person +FJzU4eC5GiI_0 person +FJ5jeLsVXys_0 elephant +FJ5jeLsVXys_1 elephant +FJ7oeGn4dBM_0 cat +FKGFVLnchKE_0 skateboard +FKGFVLnchKE_2 skateboard +FKGFVLnchKE_4 skateboard +FKGFVLnchKE_5 skateboard +FKKoXDLhFjo_0 person +FKMCYA2_RMs_0 horse +FKMCYA2_RMs_2 horse +FKMsbMSiqrQ_0 person +FKTETXdoJjk_0 person +FKVxjU1kTMM_0 person +FKWzB37H8-E_0 cow +FKdcZ0D4-K8_4 horse +FKdcZ0D4-K8_1 horse +FKhBf2FcrKE_1 person +FKhBf2FcrKE_0 person +FKnj73Wv84c_0 umbrella +FKsZiccYt_g_0 person +FKwKsWjLhiI_0 person +FKzvgRVfOjM_1 horse +FKzvgRVfOjM_5 horse +FK0ezSvbg7o_0 dog +FK37T3KvNUU_0 cow +FK8OxK802HI_0 person +FLF92L3WRrs_0 person +FLF92L3WRrs_1 person +FLQzeGFBo2I_1 bird +FLQzeGFBo2I_2 bird +FLTewjXG6Wc_1 person +FLTewjXG6Wc_2 person +FLTewjXG6Wc_0 person +FLWAw0tGOo8_2 bicycle +FLWAw0tGOo8_3 bicycle +FLZeutEdtzU_1 horse +FLqZVv798FE_1 person +FLqZVv798FE_0 person +FLq3zU7UtgQ_0 skateboard +FLr23Hv4LfE_0 train +FLr23Hv4LfE_2 train +FLskMa3WD7M_0 person +FLyV4pkEHUg_0 person +FL1q74zVLvo_1 truck +FL8ulwhcOho_1 car +FL-QttmKDc0_0 airplane +FL-73OGqifE_0 cat +FL_DeYOGkaU_2 horse +FL_DeYOGkaU_0 horse +FMHc-oH_rOE_0 person +FMTZga_deFY_0 dog +FMig7WOUQyU_1 bear +FMig7WOUQyU_2 bear +FMv3NfETfq4_0 bicycle +FMv3NfETfq4_1 bicycle +FNCMx4Aum_M_1 motorcycle +FNJmejn3KNQ_0 truck +FNJmejn3KNQ_3 truck +FNJmejn3KNQ_5 truck +FNKJAi0Xbz0_0 person +FNNdAL0qtWM_0 horse +FNSpSfZSQfE_0 person +FNbjJJgHt6c_1 person +FNgfcu9JUHA_0 cow +FNjDy-du_gs_0 truck +FNv5k4sCs5k_0 person +FNxfPhr1AZk_0 person +FN1B1veyxCQ_0 cow +FOAmP97Gboo_0 elephant +FOAmP97Gboo_2 elephant +FOL80Pq_HSs_0 cat +FOXwGm4ddCk_1 person +FOacAsl9vUM_1 bird +FOnRpTgHAdI_0 person +FOyA2uyFS0s_0 car +FO-yhRhInHQ_0 motorcycle +FO_sYJabdgQ_1 bird +FPBkLbjkE0I_1 person +FPC9a1ebnRk_0 person +FPFEZjz68RM_0 person +FPHxPqZ9of4_0 elephant +FPIVRAQI9Ao_1 airplane +FPS-rWu8sfw_0 truck +FPdj2aDA2Is_0 person +FPd8NgysFbw_0 person +FPhiHYzZrc8_2 bird +FPmbKUp9Apc_0 person +FPoBK2S6-kE_0 elephant +FPpdaMeuTPM_0 person +FP-joReSPjM_1 train +FP-joReSPjM_4 train +FQBe4ewvq3k_0 bus +FQDYCsUTzLU_0 person +FQIKRtrwRJU_0 person +FQKMItJWON8_4 bicycle +FQNa7v1nuHs_0 bird +FQNa7v1nuHs_1 dog +FQPeEa0PIhY_0 person +FQQ5mFLQS_8_0 airplane +FQTA_Rs2r4k_0 airplane +FQa2-poPUOQ_0 person +FQiI3CA-HsU_2 person +FQiI3CA-HsU_0 person +FQiI3CA-HsU_1 person +FQnnRHyzLcE_0 boat +FQyvUPmvsSo_0 bus +FQ0G5VjpRO8_0 cat +FQ09pTeRKXM_0 person +FQ8nNpJodyM_0 person +FQ_PnAPHimg_0 train +FQ_YvOmwGng_1 skateboard +FQ_YvOmwGng_2 skateboard +FQ_YvOmwGng_0 skateboard +FRBmAObAjLg_0 umbrella +FRCsksZQW0g_0 motorcycle +FRFZtNbUMfU_0 person +FRFZtNbUMfU_1 person +FRKbwt_HIJY_0 cat +FRUF5D_Bg4I_0 boat +FRZeTLb7R70_0 person +FRcpw1KTh4w_0 skateboard +FRh68K9peM8_0 knife +FRs6gVga80M_2 airplane +FR0IeE_jWVE_1 person +FSCpm1kxTIE_0 umbrella +FSJSVNwlHck_0 person +FSSrkLtKRBk_0 person +FSchPfgxMmk_0 person +FSmTDuGYKRo_0 person +FSrvVBrHdIY_0 person +FSrvVBrHdIY_1 person +FSs-_cK-4DE_1 bird +FS8ZnDA42Xg_0 zebra +FTHxfldxSrg_0 person +FTlLAXuBE2M_1 person +FTlLAXuBE2M_2 person +FTlLAXuBE2M_0 person +FTr8b641J_g_2 zebra +FTr_sg-tAYA_0 person +FTr_sg-tAYA_1 person +FT7LfULOrmU_0 person +FUNI1-oxWb0_0 person +FUPer2xPyRM_0 person +FUQokq7Dm_0_0 bird +FUWPXNKt90g_0 skateboard +FUcLObUwigo_1 person +FUcQGevNVQs_0 person +FUp8cy7p6kc_0 person +FUt-f-8QJmk_0 boat +FUzb9oSwhq4_2 horse +FU63gEB5T14_0 person +FU63gEB5T14_1 person +FU-Gyo-nX8w_0 person +FU-Gyo-nX8w_1 person +FVGYeJ_eKRY_0 person +FVGYeJ_eKRY_1 person +FVSihamjW0c_0 person +FVcaEg-4Saw_0 airplane +FVm133076uE_0 person +FVxqyMXxbTg_0 person +FVxqyMXxbTg_1 person +FVyZRq7FJUM_2 person +FVyZRq7FJUM_0 person +FVyZRq7FJUM_1 person +FWAdovzWBpk_0 person +FWCxpF5CAAo_0 person +FWH6qzGM4Ko_0 cat +FWTx-_C46YA_0 dog +FWVW97tTSiI_2 skateboard +FWZANVS2JwI_0 bird +FWbVfjbC570_0 train +FWd_KJNB1hY_0 person +FWeJwZsAuq4_3 knife +FWiwkCVxsvU_0 airplane +FWpcgznz11Q_0 knife +FWqFrwl7d-g_0 airplane +FWqFrwl7d-g_2 airplane +FWuSKVVP9Gw_0 airplane +FXPnVqm98h8_2 car +FXbqlcQOm4U_1 car +FXcjcGBH8uA_0 airplane +FXdP8V2Fyag_0 bus +FXdevKY06to_0 bus +FXjUPTGnrIk_1 person +FXjUPTGnrIk_0 person +FXrzFKXFtUE_0 skateboard +FXvqDQa0_pw_0 bus +FXz3PiouB_s_0 truck +FX7DATABx3o_0 person +FYPRZ3A5Wug_1 horse +FYQxEw6enVw_0 knife +FYR_8E37mhY_1 boat +FZJlwJ_5CIY_0 person +FZJ0L36775Q_0 bear +FZOwW_igs2Q_0 person +FZUo3m0w40U_1 boat +FZXz9ivLbZE_1 person +FZfD0ASOr-0_0 person +eD5a0lOEA4c_0 person +eD5_C8Rnll0_1 cow +eD9mxZpbjpo_3 knife +eEBoNITml_U_2 airplane +eEBoNITml_U_5 airplane +eEKY2ZIJ7cw_0 person +eEKY2ZIJ7cw_1 person +eEUzIzmFpmg_0 dog +eEZirBqUuUc_0 cow +eErb9l8tm9Q_1 person +eEwALO20qQs_0 motorcycle +eEzaprIjPOA_1 horse +eE7zgmIkklg_0 person +eE_bJ6JguBg_0 person +eE_bJ6JguBg_1 person +eFDTDuBtPdg_1 elephant +eFIUN94eOFY_0 skateboard +eFKWB3vWXzM_0 person +eFNnJotKCuE_0 dog +eFQAqsrxJIk_1 cow +eFQAqsrxJIk_0 cow +eFYXRQfFBFk_0 person +eFYi8GYHOwc_0 bus +eFYi8GYHOwc_2 bus +eFYi8GYHOwc_1 bus +eFbHzEjDjsQ_0 person +eFbHzEjDjsQ_1 person +eFbOmylKLps_0 bicycle +eFbOmylKLps_1 bicycle +eFbOmylKLps_2 bicycle +eFbOmylKLps_3 bicycle +eFbOmylKLps_5 bicycle +eFbmkhM4yvA_1 skateboard +eFeLxXgEWb4_9 airplane +eFeLxXgEWb4_10 airplane +eFeLxXgEWb4_19 airplane +eFkMiDqxNNg_0 person +eFn7qz_Ik-g_1 bicycle +eFsEtWFKOCE_0 person +eFsEtWFKOCE_1 person +eFsJVO58dOk_0 motorcycle +eFsJVO58dOk_1 person +eFtXO4KQyP0_0 person +eF6vo2K3X7Y_1 horse +eGANqnJQvcA_0 person +eGEeIkSKn9I_0 person +eGFxLRdHt9o_0 person +eGIMcDTDuZI_2 giraffe +eGKe_SHbpew_0 dog +eGLaqISw-ZU_0 cow +eGXX9n0KkAw_0 train +eGavpqx_a-Y_1 person +eGeSgNqD64Q_0 cat +eGp90l6AeQM_3 horse +eGp90l6AeQM_4 horse +eGp90l6AeQM_6 horse +eGp90l6AeQM_7 horse +eGp90l6AeQM_1 horse +eGp90l6AeQM_2 horse +eGsO1ybeNmw_0 person +eGulNc3Hz6E_1 person +eGw-BT7HLw0_0 person +eGx11vRzfMI_0 person +eG420j0UncU_0 cat +eG9ay7ouawQ_0 boat +eG_gCk-NdFc_0 bicycle +eHFxA8eOkKo_1 dog +eHJOSAF8Ksc_0 boat +eHMokGJS_8k_0 bird +eHPZiFRZgH8_0 person +eHS3e7Drwlw_0 horse +eHYl5vL9urI_0 person +eHYl5vL9urI_1 person +eHZGFVBiNbM_0 person +eHhu8cP6sYY_1 truck +eHlKAc_jO3w_0 horse +eHlKAc_jO3w_1 horse +eHmn6jMH470_0 bicycle +eHo7GgOz-4M_0 bicycle +eHo7GgOz-4M_1 bicycle +eHpMDoo4x9o_0 person +eHpMDoo4x9o_1 person +eHrYu8_xQuI_3 airplane +eHuFhF5mn60_2 dog +eHuHorwvDFE_0 person +eH-lfDuzZRU_0 person +eIbRJYX77lM_1 person +eIceWO1K4hg_1 knife +eIlLo4L0TBY_0 person +eIm2mZqCQIU_0 person +eItSvz_9tc8_1 horse +eI5A6Q8wsk8_0 person +eJGswWs5a_U_0 person +eJJBtIMsces_0 cat +eJNeGPvJZBs_0 person +eJN7jtqxGc0_1 person +eJO3ahTuQlg_2 knife +eJTzEdYt2KA_0 person +eJTzEdYt2KA_1 motorcycle +eJZyuG0FB0M_1 person +eJg7Dq1HzW8_1 person +eJi66YisQnM_0 cat +eJnTGfqwSKw_0 person +eJntPRQdD6A_0 cow +eJntPRQdD6A_3 cow +eJxFV3LV_-o_1 elephant +eJzkkZWgmiM_0 person +eJ2omVOUJv4_0 person +eJ4AprAxRh4_0 airplane +eJ4AprAxRh4_7 airplane +eJ4AprAxRh4_5 airplane +eJ9q5sR4oiE_1 train +eJ9q5sR4oiE_3 train +eKBgCy3izjg_0 person +eKCONra70xU_1 person +eKGFKx5vbJw_1 bird +eKGFKx5vbJw_2 bird +eKJMggclbAI_0 truck +eKYCRb3cMSc_0 cat +eKcN648xBxg_0 cow +eKdNbqJsxIY_1 car +eKirxEVv1N4_1 giraffe +eKpHpiZZSOY_0 motorcycle +eKsu0SXh0Cg_0 giraffe +eK5wkhSqhQg_0 person +eLAIclbgwtw_1 motorcycle +eLAIclbgwtw_2 motorcycle +eLCZ9U490do_0 person +eLK_O-E6TXY_0 cow +eLLFV2_GBOs_1 cow +eLLFV2_GBOs_4 cow +eLLFV2_GBOs_5 cow +eLLFV2_GBOs_0 cow +eLLFV2_GBOs_3 cow +eLRLhwJpaKE_0 person +eLXWvZhL6g4_0 cat +eLfUxNIWQn8_0 cat +eLsJ-MoKt-c_0 motorcycle +eLzEA8IlB5E_0 cat +eL2OKu4DhkM_1 bear +eL-v_R-bG30_0 skateboard +eMJ8eEFu7lo_1 car +eMJ8eEFu7lo_3 car +eMN980Fn4Kc_1 horse +eMQEyMimXFU_0 cat +eMWM---NOF0_0 person +eMcgmNHMY_g_0 person +eMdVb5oIUWc_0 person +eMgUOtsKC0w_0 train +eMsSwXfIf7o_0 person +eMv2h_s0LpQ_1 skateboard +eMwSfQmonxM_0 bird +eM5e2PBO5hY_0 giraffe +eM-1RwyzQpI_1 truck +eM-1RwyzQpI_4 truck +eM-1RwyzQpI_5 truck +eNDHGq_Vm3A_0 person +eNEaC09BQF8_0 person +eNG3je3HCHI_0 person +eNG3je3HCHI_1 person +eNIXfUjWW10_0 bus +eNSkFxbG_L0_0 skateboard +eNTeTVBDq8U_0 person +eNVGmOIKNII_0 skateboard +eNVGmOIKNII_2 skateboard +eNYeXwUr7rY_0 skateboard +eNbwp7DEy6A_0 dog +eNbwp7DEy6A_1 dog +eNlXrdcWYPA_0 person +eNllsU_utBs_0 giraffe +eN0ufEmLTDM_0 person +eN3a3uFzNxw_0 person +eOJorgJNcl4_1 car +eOMSAOLQMc0_0 person +eOMro57lp5o_0 bicycle +eON5oS1ddkA_2 knife +eOXMKiuur7c_0 person +eOZ2mMo0l60_0 person +eOe9DskHw1g_4 airplane +eOe9DskHw1g_3 airplane +eOhLZkf2gyQ_0 person +eOj2KctQDKQ_1 bear +eO0M1RCeWaA_0 dog +eO9s3APOXdI_0 bear +ePDBmIR0Mnk_1 bear +ePEoVXrSERQ_0 person +ePPnXOa8FII_0 motorcycle +ePWPPUSuctk_0 horse +ePWPPUSuctk_2 horse +ePWPPUSuctk_3 horse +ePaqZZz_gtY_1 horse +ePgL4a_1DcI_0 person +ePgqzaxKKo8_0 person +ePhchRaBs-k_1 airplane +ePhchRaBs-k_2 airplane +ePjAF53eBSA_0 person +ePkzyffCJhs_0 person +ePli_zXbgF4_5 bear +ePli_zXbgF4_1 bear +ePli_zXbgF4_2 bear +ePli_zXbgF4_3 bear +ePli_zXbgF4_4 bear +ePoC0Pj8xLA_2 person +ePo6J3guHBw_0 person +eQA0KwcbJlQ_0 person +eQI72zFfl34_0 cow +eQI72zFfl34_2 cow +eQMmOyBJUaA_0 person +eQOqA8LeUOU_1 truck +eQOqA8LeUOU_2 truck +eQOqA8LeUOU_8 truck +eQS3V0HV61g_0 person +eQTlUSSbOyY_0 person +eQWRQaVSPT8_0 skateboard +eQXSsw2MJGk_0 horse +eQZEFoxVGuY_2 person +eQZOAGlSYBc_0 person +eQcocP3auyk_0 car +eQfbBM_c96I_0 knife +eQfbBM_c96I_1 knife +eQi8AZ4DQO4_0 airplane +eQjFi5iBL-c_0 skateboard +eQl0Q82jNOY_0 cat +eQmSzg2ZEpw_0 person +eQmSzg2ZEpw_1 person +eQoRdZR8_q8_0 person +eQpbjnMSNLE_1 bus +eQ1R5EruVgo_0 bird +eQ1R5EruVgo_1 bird +eQ2eWzgVggo_0 person +eRAZ8LnDRN4_0 person +eRBc8OmROx4_0 cat +eRCMzS-dM8o_0 person +eREzhoz4UA8_0 bicycle +FZieBxFsZO4_4 bird +FZieBxFsZO4_7 bird +FZieBxFsZO4_8 bird +FZieBxFsZO4_11 bird +FZsDQUdCBiE_0 person +FaINra3PYko_0 bus +FaINra3PYko_2 bus +FaINra3PYko_1 bus +FanmFyCIvSc_1 skateboard +Faxr0F1n4lk_0 person +Fa8JS9CCs60_0 person +FbC6M7cRN1k_0 person +FbLE0CqDZ_I_0 person +FbN-_RdBAoA_0 person +FbRfH2tJCZg_0 train +FbUasHXeVXg_1 person +FbVrmfwHLD8_1 car +Fba1mHso_c8_0 person +Fbcl3O89qPI_0 person +Fbryy4ItyRo_0 motorcycle +FbsxP5HIH-w_0 person +FbtbQbo3w6A_0 person +FbtbQbo3w6A_1 person +FbtbQbo3w6A_2 person +FbzdX2M1spw_0 person +Fb9GVgZUQkk_1 bird +Fb-bT-5HFvo_1 person +Fb-bT-5HFvo_0 person +FcAKq2q6WuI_0 person +FcGoc7P1MnA_0 airplane +FcHZFDzsW6U_0 person +FcI2xE1s0tE_0 person +FcJofbjqKR0_0 person +FcNTnULQ914_0 train +FcPxUMks1f8_0 airplane +FcQ9ypCnsnM_3 elephant +FcdE5l-9Cl4_0 person +Fcfkxe_EegE_3 skateboard +FckxSGw75TA_8 elephant +FckxSGw75TA_1 elephant +FckxSGw75TA_3 elephant +FckxSGw75TA_4 elephant +FckxSGw75TA_6 elephant +Fcmq6FVlPrs_2 horse +FcyT7NFOtOU_1 truck +FczLlZB8PPQ_0 horse +FdBcdDQa2Yc_0 person +FdG3QrZtdYo_0 person +FdM1BVOZnpc_0 person +FdM1BVOZnpc_1 person +FdYZH48B1gQ_0 giraffe +FdYpikKc6Rk_0 person +FdcxQx4sFow_0 person +FdgWx-kasEQ_0 car +Fdgw87Au0kg_0 person +Fdp1t1Kk42s_0 person +FdvgBe0Ix0A_0 person +FdvgBe0Ix0A_1 person +FdviMb1gxkI_0 elephant +FdyA9CQ40Xo_0 cat +Fd1Rn6HvibQ_0 bus +Fd1ZmuLPSNA_2 truck +Fd1ZmuLPSNA_0 truck +Fd1ZmuLPSNA_1 truck +Fd1ySlMqOEk_0 horse +Fd6kpMD00LI_0 person +FeAmji-BcLE_0 skateboard +FeHGwC6UYlQ_1 person +FeHGwC6UYlQ_0 person +FefqZU-M3NQ_0 dog +FeioRbELmKY_0 cat +Fel-MqoIa98_0 person +FenJI9gPekk_0 person +FevOpclGxX8_0 person +Fe0XVxKTD10_0 person +Fe1ne3adKqs_0 person +Fe1o0fdRyjk_0 person +Fe1o0fdRyjk_1 person +Fe1o0fdRyjk_2 person +Fe_r1BcuOm8_0 airplane +FfCfKve9svg_0 elephant +FfGzM6IRg6I_0 person +FfTyXxo_JLY_0 horse +FfWtRI5MlvQ_1 person +FfWtRI5MlvQ_0 person +FfddIx2fdDE_0 person +FfkcxMLN90Q_1 person +FfkcxMLN90Q_0 person +FfpScNxcfaE_0 person +FfpuED53W2w_0 person +Ff3kCsp4dss_0 horse +Ff37VadXulw_0 person +Ff37VadXulw_1 person +Ff-s3k4nzl0_0 cow +FgAW1wm55t4_0 umbrella +FgBAfHhZDtY_0 cow +FgCkJ9L956k_2 horse +FgHkoen3Fbs_0 person +FgHkoen3Fbs_1 person +FgHkoen3Fbs_2 person +FgK205YdiNI_0 zebra +FgaH6B8Im-s_1 person +Fgh-oweWR10_1 truck +Fgh-oweWR10_2 truck +Fgh-oweWR10_5 truck +FgkgjnYWuvc_0 motorcycle +FglWoBFeCGs_0 boat +Fgqe5FVDM7w_1 bus +Fgqe5FVDM7w_3 bus +FgtxhgrL-1s_0 bicycle +FhAkQ-D6j7M_1 person +FhNe0p3NvAk_0 person +FhS2OrbfOqA_0 horse +FhTIUIB4MQk_0 person +Fhdb7UXlKgw_0 person +FhhQQi3XBRs_0 person +Fhim9zq_3dc_0 dog +Fhtl-JSkWvY_1 skateboard +Fh1QSbERb_I_0 person +Fh1jlYGKYy8_0 cow +Fh2wm1SuBlM_0 person +Fh5hapK4iY0_0 horse +Fh-e1BaovqE_0 person +FiAj5FRP_QI_0 bear +FiAj5FRP_QI_1 bear +FiAj5FRP_QI_2 bear +FiGZEZ8BFeg_0 person +FiLeL7fMtKI_0 person +FiMl9o33Uaw_0 person +FiQbZpev_LA_0 person +Fim4ZNdANXI_0 horse +FipIgAA0lFk_0 bicycle +FirrKl6H41c_0 person +FirrKl6H41c_1 person +FivrGIBKDvo_1 elephant +Fiz1rnLi2OM_0 person +Fi4kJfnwDFc_1 bicycle +Fi4kJfnwDFc_0 bicycle +Fi7LPQxqu14_0 person +Fi9uLLmtWaQ_0 person +Fi_IAiAUqaU_1 horse +Fi_IAiAUqaU_0 horse +FjBRf4S85bg_0 elephant +FjBRf4S85bg_1 elephant +FjCz86a5wp4_0 person +FjF5nRRKjKc_0 person +FjMslXNPmHo_0 airplane +FjRDB5KtmZk_0 cow +FjUvDc65QJo_0 person +FjZltjNG2NU_0 skateboard +FjfP5wdsmM0_0 cat +Fjo3Q6r1Unc_0 cow +FjsVcnD_MIg_0 motorcycle +FjvoIjZBqfU_1 person +FjvoIjZBqfU_0 person +Fj98ZrblH1g_0 umbrella +FkAQLLdAAbk_0 elephant +FkAQLLdAAbk_1 elephant +FkFAVoUYxPc_1 skateboard +FkOkAlvY34U_0 cow +FkSrQgrkwxM_0 person +FkSrQgrkwxM_1 person +FkZy3LGoN9I_0 dog +FkkUslZGIbg_0 bear +FkvcJknwKuY_0 person +FkzewHxki8o_0 skateboard +Fk4XzK5XI6A_0 bus +Fk4XzK5XI6A_1 bus +FlD1RAiVpek_0 person +FlD1RAiVpek_2 person +FlD1RAiVpek_1 person +FlEhS-F3ygQ_0 umbrella +FlGO6UYJUzE_0 horse +FlNEteNmUhc_0 person +FlR1fAhH2Xo_0 dog +FlYY0RaMPNY_0 person +FlgN1oA45yM_0 bear +Fl2yqFTps4E_0 person +Fl6OhW0-1w0_0 person +Fl9EhNo7Keg_0 person +FmDFcSMFeno_0 person +FmDFcSMFeno_1 person +FmDOHRJspxI_0 person +FmMYoani5Vg_0 person +FmOLwdbHDxQ_0 person +FmOfXWRFoXQ_2 bird +FmUhkvEy_7s_0 person +FmUhkvEy_7s_1 person +FmVDxGIS5zk_5 train +FmVDxGIS5zk_7 train +FmVDxGIS5zk_8 train +FmVDxGIS5zk_9 train +FmVDxGIS5zk_10 train +FmVDxGIS5zk_1 train +FmVDxGIS5zk_2 train +Fmc6udEpldU_0 cat +Fme4Abd5nUA_2 bird +Fme4Abd5nUA_1 bird +FmoAxj0I_HE_0 person +FmqOvCWa7zg_0 person +FmrozJZpKR8_0 train +FmsAY671mqQ_7 knife +FmuPNtoqS2E_0 elephant +Fm1Depfmi_k_1 person +Fm5EMiek6AE_0 person +Fm6Hq8f2Qxk_1 airplane +Fm6Hq8f2Qxk_2 airplane +FnEnQ8PP_eE_0 skateboard +FnEnQ8PP_eE_1 skateboard +FnGScEGhwDA_0 person +FnKvuj-emb4_0 person +FnKvuj-emb4_1 person +FnMl1BAE_jc_0 bear +FnMl1BAE_jc_4 bear +FnNceIdqZ3w_0 person +FnNceIdqZ3w_1 person +FnTofG0IZf0_0 person +Fnb6xihA7ck_0 person +FncXKaqIxJo_0 person +FncXKaqIxJo_3 person +FniMTwzxRZQ_0 person +Fnv6GlZeZ98_2 airplane +FnwZm6-uVkU_0 person +Fn6j8CspFw4_5 horse +Fn6j8CspFw4_2 horse +Fn6j8CspFw4_3 horse +Fn6j8CspFw4_4 horse +Fn7CPx1Df1I_0 dog +eRGlFEYZ74g_0 person +eRQQ8fY6DVA_0 person +eRToPN2xDdI_1 horse +eRToPN2xDdI_2 horse +eRVbBhT_bcs_0 person +eRXcoQINrwY_0 cow +eRa3aIGemkw_0 person +eRiOVczmKs0_0 person +eRk0k7ru0C0_0 person +eRlVo64o3EE_0 horse +eRn_VZZAhDc_0 bird +eRpQzm5PYXw_0 person +eRvRu0q-GoE_0 dog +eR2L8Yeikhc_0 person +eR2s4XgNo7o_2 dog +eR6IwGLaa1M_0 bicycle +eR7y-Ei3DLg_0 person +eSGBtfzFobI_0 train +eSId-3VXvKk_3 dog +eSIwAUMyFgU_0 person +eSKH9cYOKk8_0 horse +eSPrJOSU8AM_0 train +eSa1vsOaz1c_0 knife +eSiLV8rS59E_0 person +eSiLV8rS59E_1 person +eSljhVPS-Ik_2 person +eSljhVPS-Ik_0 person +eSpAsKZSmiA_0 airplane +eTDKrXMMrQ0_0 cow +eTKPoRwNChU_0 person +eTKPoRwNChU_1 person +eTKSWSWvAyw_1 person +eTNf-Cqbbro_1 person +eTQF3UDg8qc_0 truck +eTTKvmF97nI_0 elephant +eTUWLCcJU2k_2 bus +eTU8LeMW9qA_0 person +eTc1z6mbb50_0 truck +eTdIp3O6Gdc_0 bear +eTkYJ5e2d6g_0 person +eTkbZ2QtHvw_0 train +eTkbZ2QtHvw_1 train +eTpyN9lx8_4_0 horse +eTsE0jLxU3w_0 truck +eTsE0jLxU3w_2 truck +eT3B8Dicg34_1 person +eT5K9fPU-0g_0 person +eUGoobFpS4s_0 person +eUKe6XaWIfA_0 motorcycle +eUQjLdCSTbY_0 person +eUQ4P2JG1yg_0 bus +eURPg0TbtFI_0 person +eUU0KJ-w2bc_0 person +eUVgOxQT_-8_0 cow +eUbEHnOzRA8_0 person +eUbEHnOzRA8_1 person +eUbEHnOzRA8_2 person +eUe_Rayk8X8_0 person +eUyzGl0--ms_1 person +eU6G8jITD_Y_0 airplane +eVJOOrHqc34_1 skateboard +eVL1UQ_nteE_0 car +eVNGBAn5Oxc_0 cat +eVPABDrI9js_0 bird +eVYydWvg5Go_1 person +eVcLRosJZew_0 person +eVhB8QJJogM_1 knife +eVn8akHyS64_0 airplane +eVn8akHyS64_2 airplane +eVn8akHyS64_3 airplane +eVn8akHyS64_6 airplane +eVuy4uctm28_0 person +eVu1gME4-Qs_0 elephant +eVu1gME4-Qs_1 elephant +eVywFyCLwko_0 person +eVzfhyg8qFU_0 person +eV2KIbTSnH4_1 train +eV4pA62ABv8_1 train +eV6nRsgY8PQ_0 person +eV64Qw4Zebk_0 person +eV-VIypuuNY_1 bird +eWHnCpVoKhw_0 truck +eWbvhqFVvXk_0 boat +eWlQOgHQT7g_0 airplane +eWpIepmfRus_0 person +eWpIepmfRus_1 person +eWsle8FxRvY_0 person +eWyDiulNMGo_0 motorcycle +eW6l7xJBq-Q_1 boat +eW6o2X8qAtQ_0 car +eXDegroOl34_0 person +eXECAC_iXPc_0 person +eXLLe0Z-fJk_0 person +eXUIt5B2NQc_0 person +eXYniqUW4z8_0 bicycle +eXYniqUW4z8_2 bicycle +eXaCA1qL7uY_0 person +eXeifN6Jv8c_0 elephant +eXeifN6Jv8c_1 elephant +eXeifN6Jv8c_3 elephant +eXeifN6Jv8c_4 elephant +eXeifN6Jv8c_7 elephant +eXfkthdw2L4_0 person +eXixQXmPyYw_0 elephant +eXoF6xS_5u4_3 knife +eXuelMqu_1M_0 knife +eXveKyc2TQg_0 horse +eXxAlPRFiqs_0 person +eXxAlPRFiqs_1 person +eXxAlPRFiqs_2 person +eX3bd4kHxuc_9 airplane +eYDpQFJpz7k_0 person +eYJe2k1E0XQ_0 bus +eYY-Mz3L_Ac_1 elephant +eYeHu-IftM0_0 person +eYnlQEvgHVc_0 cat +eYqlHj6MSc0_7 bicycle +eYyGqoW9Q3c_0 bus +eYyri5GAJDE_0 person +eZEN_5rnTLM_0 person +eZL3Ew4O7YI_0 person +eZXS_3nTpdo_1 motorcycle +eZXS_3nTpdo_2 motorcycle +eZZb5rnc1iA_0 bus +eZf-Rsr1aNs_1 train +eZgo_XfmmO0_0 person +eZgo_XfmmO0_1 person +eZl_FRsZx3o_0 person +eZym_LkJnpY_1 knife +eZ2Y_Qtg0VU_0 horse +eZ2Y_Qtg0VU_1 horse +eZ4N2Y737ss_0 person +eZ_peGgPSDE_0 person +eaHXGY8ImzY_0 person +eaOqHSeEVG0_0 elephant +eaR-dFaZRGc_2 giraffe +eaTX3J2X23g_1 person +eaTX3J2X23g_0 person +eaalMrdHsQ0_0 horse +earUgdES0lk_0 person +eaxPmkwGK5U_0 bird +ea1EeKBBjxk_0 umbrella +ea1YcZPjbxU_2 truck +ea4saeRZ0_M_0 person +ea8mbQn2kv0_2 dog +ea8mbQn2kv0_1 dog +ebFgEyNciRc_0 cow +ebMZJ-lUhbw_2 bicycle +ebMZJ-lUhbw_3 bicycle +ebMZJ-lUhbw_1 bicycle +ebOubiwIUC0_0 person +ebV9mcxICDs_0 dog +ebY5nNOPdN0_0 person +ebY52fJyTPs_1 person +ebY52fJyTPs_0 person +ebagV2pOV20_0 boat +ebhnTUXh7Pc_0 cat +ebh7xOXlO7Y_1 person +eboXP28MlOE_0 airplane +ebt0_AWnuyM_3 bear +ebyMEAOqPhQ_0 skateboard +ebz4umtEYag_1 motorcycle +eb0UO8Y5r5A_0 car +eb1-qD5D7Us_0 person +eb5d4XIDSqs_0 car +ecDEmZdWz8Q_0 person +ecGOS5ZO0Tw_0 skateboard +ecGOS5ZO0Tw_1 skateboard +ecJIf9dcDHk_0 person +ecKMZLATsNg_0 person +ecKst7suEZo_1 motorcycle +ecPynengjhg_0 person +ecUmR_974l4_0 bear +eccbjuLjCr0_0 bicycle +ecex13DrS00_1 bus +ecgqb4spDo0_0 cow +eclnV3fwFVg_0 car +ecndV9N-b9M_0 boat +ecrgwn6gB7c_2 person +ecrgwn6gB7c_0 person +ecrgwn6gB7c_1 person +ec0L5W9HzYQ_0 person +ec0zPF4t8jM_0 person +ec10-YUa1PE_0 person +ec4Mjwm2hyQ_0 person +ec4ya7ogbFU_0 person +ec59VG2krTI_0 knife +ec7hzm4ZgOM_0 bus +ec8daVdUMW8_0 elephant +edErePLiFl4_0 truck +edFb7FxjVPc_1 person +edOvHaEGfM0_0 train +edO7Q7znUJA_0 cat +edPmPMqUt4c_1 person +edPmPMqUt4c_2 person +edS79MnRXwE_1 person +edYcGdD4UGI_0 person +edd8R4oDMdg_0 person +edlAlkitTfg_0 bird +edlAlkitTfg_1 bird +edq1Zw1FWGY_0 person +edrtSs6UdCI_0 boat +edtqJ_N0258_0 person +ed0O35MjM6Q_0 cow +ed5jfyH6JyI_0 person +eeEjRmROBZs_0 train +eeEjRmROBZs_1 train +eeJDVUC0bio_0 bird +eeV0a3p0uz8_1 dog +eeYr-ujfh4Y_1 person +eeYtwUSuQzY_1 airplane +eeYtwUSuQzY_2 airplane +eeYtwUSuQzY_0 airplane +eeZyIsjtgj0_0 train +eeahFaPbx5M_0 skateboard +eea6uRdJLL4_1 bird +eee-1I8uLeU_0 cow +eefTfPIGkq4_1 person +eef-qkyU0jY_0 boat +eepn_UxMI5o_0 skateboard +FoFA-VOPhV8_0 zebra +FoIc9MjzbBk_0 person +FoSynLz7aJ8_0 horse +FoSynLz7aJ8_1 horse +FoUqmWxXlNU_0 person +FoUqmWxXlNU_1 person +FobAHnW_q6s_0 person +Fog-McdMlO0_0 person +FomH9b8uRKs_2 knife +Fot4m5WU4Aw_1 person +Fot4m5WU4Aw_0 person +FouVJvkYyPs_0 person +FpCdNHknwMQ_3 car +FpCdNHknwMQ_5 car +FpEzn8x46OE_0 bird +FpGO4RTCIuk_6 bicycle +FpGO4RTCIuk_0 bicycle +FpGO4RTCIuk_2 bicycle +FpGyjKY-NIk_0 motorcycle +FpGzMvzCvKo_0 person +FpI0Do5LaU8_0 person +FpTdRnuOS8M_0 person +FpTdRnuOS8M_1 person +Fpaob2f1sqE_1 person +Fpaob2f1sqE_0 person +Fpev0w7vGO4_0 person +FprxIVYXUL4_0 horse +FpzpuYeDf6M_0 bus +Fp1vbL5guA0_0 person +Fp2HgWZlr2k_0 person +Fp7RJqXwz6c_0 person +Fp-TG2XDrC4_4 car +Fp-TG2XDrC4_0 car +Fp-TG2XDrC4_1 car +Fp-TG2XDrC4_2 car +Fp-TG2XDrC4_3 car +Fp_5yBxyvR4_0 umbrella +FqFhpogmR2s_0 cat +FqHStgmNnKA_0 bicycle +FqHStgmNnKA_1 bicycle +FqTHQ5KBbaY_0 elephant +FqjhuAhttZw_2 train +FqjhuAhttZw_1 train +FquAMi_ikSA_0 truck +FqxWiT-6dLM_0 person +FqxZmvVkHIA_0 giraffe +FqxZmvVkHIA_2 giraffe +Fqx-wOpqzZo_0 airplane +FqzYUW3X9pc_0 person +FqzYUW3X9pc_1 person +Fq_esHSu_sk_0 person +FrC2HuRBsYA_0 person +FrC-Gp1GmVw_0 cow +FrC-Gp1GmVw_1 cow +FrIO6gNGeao_0 person +FrUCytgm6sM_2 horse +FrViqM6fVR0_0 dog +FrVxG6x7tj0_0 knife +FrVxG6x7tj0_2 knife +FrgvokGeeds_0 person +Frk0tcM1o_w_0 person +Frm5N8YRz_E_0 person +FrpsbU7nO00_0 person +FrxIGKawDiA_0 person +FrzgyfVukw4_0 person +Frz8huGrR4M_2 motorcycle +Fr0K__Q_Kv4_1 bird +Fr2qdnHURF4_0 boat +FsHjWJUILr4_0 person +FsScYp1HNk0_0 person +FsXYM3nf7O4_0 horse +FsZyoaRLGfw_1 person +FskWl7cTGUU_4 motorcycle +FslFjbzL4rY_0 train +FsuA_2-7e1w_0 elephant +FsuA_2-7e1w_1 elephant +FsvwyL1hLDU_0 bus +FswGt3qhUXE_1 horse +Fs6Lk0xDsWk_0 dog +Fs6Vua80iU4_1 bus +Fs-DmOC6Ksw_0 person +FtAgz58w2vs_0 person +FtC0Y3Dca60_0 dog +FtD8uBgTi3E_0 cat +FtJ8y0gIpKg_0 dog +FtJ8y0gIpKg_3 dog +FtJ8y0gIpKg_5 dog +FtJ8y0gIpKg_1 dog +FtJ8y0gIpKg_4 dog +FtMshKheG8Q_0 elephant +Ftet3EW_gR0_0 skateboard +Ftet3EW_gR0_1 skateboard +Ftj_1qTEwE8_0 cow +FtqLCjhRQgQ_1 person +FtqLCjhRQgQ_0 person +FtwMaVMlLbM_0 person +FtwZasadNWo_1 person +FtwZasadNWo_0 person +Ft3Xr78g1jg_0 dog +Ft4RUB75d64_0 horse +Ft5ZV3L5LV4_0 person +Ft8VPp_VNJs_0 knife +FuCuNV5vL-8_0 person +FuIIvsD7qyY_1 person +FuMf00RPDmg_0 bear +FuNvDTe7cAM_0 bird +FuR3p7f2R30_0 person +FuTf8iiIHWI_0 motorcycle +FuVQuZfX71w_1 elephant +Fuc49AUfyaA_1 train +FufG8eRehvk_0 person +FuoKMOMcl0I_0 bus +Fu3A7S4V26Q_0 person +Fu4p4U9AqY4_0 train +Fu5TDXXdHyc_3 train +Fu5TDXXdHyc_0 train +Fu5TDXXdHyc_1 train +Fu5TDXXdHyc_2 train +FvB0FA24g0c_0 motorcycle +FvD-5pXN6B4_0 person +FvF8CGSAVBw_0 horse +FvIqBpjD4A4_0 person +FvKJQTsxS6o_0 bus +FvNiWF5wWJA_0 truck +FvN6HD0c3I8_1 bicycle +FvQ8wYSFAhA_0 bird +FvZ_lMA5MYE_0 person +FvZ_lMA5MYE_2 person +FvZ_lMA5MYE_1 person +FvcxD9PJ1-g_0 bear +FvcxD9PJ1-g_1 bear +FviKCn2JGbY_0 person +FvksDxENves_0 bird +FvksDxENves_1 bird +FvmW4A9wN1c_0 person +FvslrkU6Ii8_1 skateboard +FvslrkU6Ii8_5 skateboard +FvslrkU6Ii8_4 skateboard +FvuJoToFsZ0_0 skateboard +Fv2LjW2C5SU_0 knife +Fv2LjW2C5SU_2 knife +Fv2SAN8CNlg_0 horse +Fv6OQz_y5V0_0 person +Fv80QjBLyXw_3 train +Fv80QjBLyXw_4 train +FwBCZ90I_aw_0 cat +FwIN5LlmnSA_0 person +FwMy9UR3xJA_0 person +FwMy9UR3xJA_1 person +FwNHDlUxkVE_0 person +FwSQA6A_bWE_0 person +FwZzzptQg0s_0 person +FwZzzptQg0s_1 person +Fwf5SGfOguQ_0 bird +Fwf_1L-RQB4_0 cow +FwhmGtqpt5s_1 skateboard +FwrkNuHACuE_0 person +Fwtyj6Ut62E_2 dog +Fw8NHywJSJw_7 airplane +Fw8NHywJSJw_8 airplane +FxHZCFGlLk8_0 truck +FxI0-u_zPQQ_1 skateboard +FxI0-u_zPQQ_0 skateboard +FxJg66y6Vj4_0 person +FxJ0douRc4s_0 person +FxMnA-aNvVI_0 knife +FxXVgnAjOCs_0 person +FxXVgnAjOCs_1 person +FxitbyLzBbw_0 person +FxmfshFrhyg_0 person +FxmfshFrhyg_1 person +Fxp_EDLEylo_1 bear +FxxuVRsJiCQ_7 bird +FxxuVRsJiCQ_9 bird +FxxuVRsJiCQ_11 bird +Fx74SXbZiUI_0 boat +Fx-8EgSEaDg_0 person +FyFea2NifCo_0 elephant +FyKB3iEKNlg_0 person +FyO1UliwWNQ_0 skateboard +FyQulDaVp8I_0 person +FyTFrxalrzY_2 bicycle +Fyb5_PxuzrI_1 airplane +FyjgIZnRT0A_0 person +FylDI9Ssx18_0 dog +FyqooE73pSs_0 train +FyuLo6pvAxk_0 person +FyuLo6pvAxk_1 person +Fy6UODQTxBw_0 dog +Fy8cULzM424_0 person +FzJOOqEWb48_0 person +FzP8vDH_ynM_0 bicycle +FzV_56qru4c_1 person +FzV_56qru4c_0 person +FzaaAJ_dGjI_1 dog +Fzc4L1eWvQ0_0 knife +FzeiG746wec_0 person +FzoJlCfL5bc_0 person +FzpV3zrU7w0_0 cat +FzufL9SIDZ4_2 person +FzvLoCiUbCU_0 person +Fz4RMW4ONrQ_0 skateboard +F0Ekv-HAlnk_0 airplane +F0G64yaBMBM_0 person +F0G64yaBMBM_1 person +F0I59IAm-vo_0 person +F0Qk5fG3X-M_0 person +F0Q9zBIa4vg_0 knife +F0Q9zBIa4vg_1 knife +F0Q_-7qxWws_3 elephant +F0UBtRxGNhA_5 bird +F0XjqeFLlgU_1 bird +F0ZAshDVPxg_0 person +F0c4qnJQtDU_0 bear +F0gFV3Zl1ew_0 train +F0gFV3Zl1ew_2 train +F0hx5kgZ3go_0 elephant +F0mBUyvb90Y_0 person +F0qXU9y4p-Q_0 person +F0z1cmfnPsQ_1 bicycle +F1B_Y1twDK0_0 cow +F1CZ2DPXJ9M_4 bicycle +F1CZ2DPXJ9M_1 bicycle +F1KHVI6XeVo_0 person +F1eNAhwM5Pc_0 horse +F1jGg9828BI_0 person +F1j27LEBSpI_1 car +F1qXLHQywDc_1 elephant +F1sQlUVWZLM_0 person +F15XLgp6ED4_0 skateboard +F2Bb2pFQRyU_1 person +F2EV6W4vdT8_0 bus +F2GhztG-3ZM_0 cat +F2HupbPd4Rc_0 person +F2JDbaIJXuM_0 person +F2JeBrL43Kg_0 person +F2JnnpLll3c_1 horse +F2Kd_wTgfHc_0 bird +F2N-fmDDyCs_0 train +F2an_w-D4WM_0 dog +F2bbT3y10lk_0 person +F2dx02YK1MY_0 cat +F2kBHcrY7Ck_0 person +F2nvlBMOvGc_0 boat +F2nvlBMOvGc_2 boat +F2nvlBMOvGc_3 boat +F2nvlBMOvGc_4 boat +F2yvXHbr1Us_6 bird +F2yvXHbr1Us_7 bird +F20W1m4x2Ys_0 person +F20_Ihwr_1Y_0 elephant +F21R2kQ-je4_0 person +F2244CO9Fuo_0 airplane +F250PqK5Gb4_1 airplane +F3AMItpIJlI_0 dog +F3AMItpIJlI_4 dog +F3FUBdTgY7c_0 car +F3FUBdTgY7c_1 car +F3Lz3rnQ-7A_0 person +F3Lz3rnQ-7A_1 person +F3NneLgyZiU_0 person +F3RkQzIQjeU_2 bicycle +F3XFJeSjPDU_0 bird +F3XFJeSjPDU_3 bird +F3gY7oCc-j8_0 cat +F3j318NP2P0_0 person +F3j318NP2P0_1 person +F3oP1Se_HdQ_0 motorcycle +F35JtGCIiCo_0 dog +F377W3trtdg_2 dog +F4DJmxH-fuw_0 skateboard +F4FXVb3DdJE_0 person +F4FXVb3DdJE_1 person +F4HgVMHEiVQ_1 bird +F4Ja9TDp5eg_0 person +F4R1rt0I4Ik_1 person +F4R1rt0I4Ik_0 person +F4WWEXEO6Cw_0 airplane +F4hUo05eI2s_0 person +F4hVb1AsJ9M_0 umbrella +F4hVb1AsJ9M_1 umbrella +F4hp-2UBFcI_0 person +F4l8U4NGPMU_1 elephant +F4rQJlBkGa8_0 person +F4tzOjT91r0_2 elephant +F41NWCYabpM_0 person +F44j0JHVdfU_2 bicycle +F44z7XXoIZk_0 cow +F4-R6x6hSno_0 airplane +F4-R6x6hSno_3 airplane +F5IEcbmSBiU_0 person +F5UiBt9FiQ4_1 truck +F5brWxznDYA_0 bicycle +F5drV0qDFvU_0 person +F5pSgana5Ds_0 person +F5pwABHMaZM_1 skateboard +F5y_lQCCiYk_0 person +F51aHL_AuQ8_2 person +F51aHL_AuQ8_0 person +F51aHL_AuQ8_1 person +F54NzXjey4Q_1 person +F6AkwJu9acQ_0 person +F6BUhbvKAY0_3 bear +F6I3hGIdHBM_0 airplane +F6L1DckOdFs_0 person +F6L1DckOdFs_1 person +F6L1DckOdFs_2 person +F6UTU1zVfY0_0 person +F6X-PDReV8U_0 skateboard +F6uVxnnSkQg_0 cat +F63FWqs6n6A_1 person +F63OB46zw20_0 person +F66U-dCKTVs_5 elephant +F67kQb83GEo_0 person +F7Aw74QT7I8_0 motorcycle +F7D1ccHfWQM_0 train +F7GYFMuRxr8_0 person +F7MruF3gqRk_0 person +F7MruF3gqRk_1 person +F7M2n9Irv10_0 person +F7adrDrejOI_0 bicycle +F7adrDrejOI_3 bicycle +F7adrDrejOI_7 bicycle +F7iFGXShjIg_1 knife +F7lmwAhsTVE_1 cat +F7lmwAhsTVE_0 cat +F7wyUoc1ELM_1 person +F7wyUoc1ELM_0 person +F72e40LPG8g_2 airplane +F72e40LPG8g_3 airplane +F72yH9hRoS0_0 person +F77I6mkMOmM_0 person +F77I6mkMOmM_1 person +F77WzfDD-Ac_0 person +F77WzfDD-Ac_1 person +F8VZcw3-DMg_0 person +F8XbiaxQYFA_0 car +F8kTGPYH29o_0 airplane +F8sVrU5FfZw_0 person +F8vyo42LQM0_0 airplane +F9KIXBo3lNI_0 bird +F9KIXBo3lNI_1 bird +F9WnfUhb8A4_0 boat +F9hhOJk3fdY_0 person +F9jiY40SX4g_0 person +F9kDOaogdPA_0 train +F9kDOaogdPA_1 train +F9nirQJj4wc_0 motorcycle +F9qYvrO4nMM_1 person +F9qYvrO4nMM_0 person +F942FTRne2Q_0 person +F95fIsG0A7U_0 horse +F98XVAomn1s_0 person +F-AROt5V1zQ_0 airplane +F-L2byRMMEI_0 truck +F-QpXlvCAdw_0 giraffe +F-RVugkjZ1k_0 person +F-RVugkjZ1k_1 person +F-dxzMmjOT0_0 person +F-dxzMmjOT0_3 person +F-dxzMmjOT0_1 person +F-poowwxrxU_0 person +F-3G1FhnsdY_2 cow +F-3G1FhnsdY_3 cow +F-7EAK7rTI8_0 bird +F_AoZsBu8j8_0 person +F_AoZsBu8j8_1 person +F_BBB0J-9tQ_0 motorcycle +F_CsG_jIxC8_1 truck +F_I4rwh1mtE_0 person +F_JJmqKJBnY_0 person +F_Kw8qyfgjU_0 person +F_WtOi2ZeSE_0 umbrella +F_oxJfyCUrw_0 person +F_wVAS7hR9E_0 cat +F_5NdFCcCrQ_0 airplane +F_59LD9YnAU_2 person +F_8qVC7MHM0_0 person +GABXImD8qwM_3 dog +GADBGhd7Hbc_0 horse +GAF3BbJqKos_0 person +GAF3BbJqKos_1 person +GAGFuwQyn2A_1 person +GAVdXzEftIU_1 person +GAaPJd_iVeU_0 train +GAb6ZqG64o4_0 person +GAb9NG_JnoU_0 cow +GAe7SnwoPQQ_1 airplane +GAg-aVsz7AI_1 person +GAinaDnPPO0_0 elephant +GAnYrNhN90c_1 person +GAoDRtFNSeQ_0 bird +GAoaBt8kfHQ_0 train +GApyoyRTlPk_0 person +GArUrBTpgzk_4 airplane +GArUrBTpgzk_1 airplane +GArUrBTpgzk_3 airplane +GAzsUwyCRAI_0 cow +GBF7wVda328_0 dog +GBLwQswYGpQ_0 dog +GBUiAfFHr8o_0 person +GBYAc4swbr8_0 person +GBYFzcFWKtI_0 skateboard +GBYeOSgHxaw_1 person +GBhV-vm_cDs_0 motorcycle +GBhV-vm_cDs_1 motorcycle +GBhV-vm_cDs_2 motorcycle +GBhV-vm_cDs_3 motorcycle +GBjWoHEvi24_0 truck +GBnf-AAsQts_0 person +GBvWcmiB_zQ_0 person +GBv60Rpf6hA_0 person +GBwqR6gIUJk_0 person +GBwqR6gIUJk_1 person +GB0RUQ72TDU_1 motorcycle +GB0RUQ72TDU_2 motorcycle +GB0RUQ72TDU_4 motorcycle +GB1A1gXLxF8_1 umbrella +GB1A1gXLxF8_0 umbrella +GB2Z9Zd9kCM_0 cow +GB3M7jlJvZo_0 umbrella +GB3dD_Sz5yA_0 cow +GCECUCM275I_0 truck +GCECUCM275I_3 truck +GCECUCM275I_4 truck +GCECUCM275I_1 truck +GCECUCM275I_2 truck +GCHyhn505e4_0 person +GCL5aSCyDAQ_1 horse +GCR8piyI8to_0 person +GCdYlCKelqg_2 bird +GCf79ImcoV4_0 truck +GCiR2DBKEUo_3 umbrella +GCiR2DBKEUo_0 umbrella +GCyZCLCX4jI_1 bus +GC5X3-Zi5fo_0 bear +GC_4PRhWwy0_1 person +GDBvvswiioY_0 horse +GDErDO6sQxg_0 person +GDHukw9i8AE_0 bear +GDPBufHJ6pE_0 person +GDVxjq335kg_0 person +GDVxjq335kg_1 person +GDW_ebhUmXg_0 person +GDeoeNk-jj8_1 train +GDgRHR5rt5g_0 dog +GDhVskUd-i0_0 truck +GDkTfXax1EI_1 person +GDr1CfMsWCo_0 knife +GDyR3j6e9uU_0 bear +GD0qZhFYMtE_1 bear +GD5H2vUIQUM_0 bird +GD7nVz18opA_0 cow +GEC16HE9LPs_0 skateboard +GEK0W7Soe5I_0 person +GEOILdSs_m4_0 person +GEXtPkuLXV4_0 person +GElPgxFGsYM_0 person +GEmM96O2bm0_0 person +GEoAqEILC5I_0 bicycle +ee4MHg5K9xo_0 person +ee4MHg5K9xo_1 person +efANTTg0s7E_0 person +efD7irKhsjg_1 zebra +efFDVTrJnI0_0 person +efQ-zUFNN-U_2 airplane +efQ-zUFNN-U_3 airplane +efQ-zUFNN-U_0 airplane +efQ-zUFNN-U_1 airplane +efUVmXxR3pI_0 person +efXikRhGmrs_0 person +efdHHLZ3g1Q_0 motorcycle +effHbT0DhsY_1 horse +effHbT0DhsY_2 horse +effHbT0DhsY_3 horse +efj0ZypW97U_0 person +efl9qpSfN9o_0 skateboard +efo_cgnnucQ_4 knife +efqCl5PWA5Y_2 bear +ef6fQWU1KdY_0 person +ef9zPCUJ5uQ_0 boat +egByT16s_54_0 person +egByT16s_54_1 person +egHnmalt3d8_0 horse +egQiifLgKHE_0 person +egVsaW3pIR8_0 bus +egotrU2sxIs_1 cow +egotrU2sxIs_0 cow +egymuz3YUjw_0 person +eg0xHA2KO2M_0 car +eg0xHA2KO2M_1 car +ehAg6V-5Puk_0 airplane +ehB-VoBE8As_0 person +ehFoBFIrRho_0 person +ehFvz7g6tcc_1 person +ehFvz7g6tcc_0 person +ehF--LpGjPU_0 person +ehI3hX4P2gg_0 bus +ehSU0TuduDM_9 boat +ehSU0TuduDM_0 boat +ehSU0TuduDM_3 boat +ehSU0TuduDM_7 boat +ehSU0TuduDM_8 boat +ehTOHuz8De4_0 horse +ehhoOXi21uc_0 person +ehhzn87_kyY_0 knife +ehpsJCYWhMo_0 dog +eh0-hoyeQv4_0 person +eh383O3j2o8_0 train +eh8ClQx55Pk_0 elephant +eh8ClQx55Pk_3 elephant +eh8ClQx55Pk_1 elephant +eh-Hpgj7SPM_0 bird +eiIxHOvvvog_0 person +eiKfZPTeN-M_0 person +eiMVAVfFk50_1 giraffe +eiNlPbSqaQM_2 bear +eiOC7H2_I7E_0 motorcycle +eiYV7UFe9_4_0 person +eiZm5CglnLc_0 person +eiirsESzuHs_0 bicycle +eim8NPBqZXg_1 person +eis2vlxPtf4_1 person +eivFKGFBySc_0 person +eivMnaQyUKU_0 person +ei0PFx0qNIQ_1 person +ei0PFx0qNIQ_0 person +ei4Yn0KXnAM_0 person +ejDpzIUHAMk_0 person +ejD4KjqrkFo_0 cat +ejIMw0_a1Zo_0 person +ejIMw0_a1Zo_1 person +ejVKT8cDDTY_2 motorcycle +ejoDQZqi4DU_0 person +ejsflVtvinE_0 dog +ejzqfqBU2XY_2 horse +ejzqfqBU2XY_0 horse +ejzqfqBU2XY_1 horse +ej5D22-gpzY_0 person +ekBhYo1n09M_0 person +ekGn7Al_5S0_0 person +ekOQkNLi9gA_0 person +ekPQmhXqsJs_0 cow +ekQPPxQDQrA_0 bird +ekYErFjRBcY_0 person +ekaQzIhIz6U_0 person +ekhId7QWajE_0 person +ekw22HGT0TY_0 person +ek6F1Yy6r4g_1 person +ek6F1Yy6r4g_0 person +ek9m3wFRD78_0 motorcycle +elAJmgZ3uV8_1 person +elIopJ6sLS8_0 motorcycle +elS7CV83kDQ_0 cat +elbH9USSXbU_1 person +ele_x5If5RM_0 cat +elfDIDNaxO8_0 bicycle +elfDIDNaxO8_1 bicycle +elk9Eg_zAzA_0 horse +elwOqTHVPb4_0 car +el_1tnvsCAY_0 elephant +emAlGe0D2Ro_0 car +emBk5WfF9MA_0 person +emFvwwYH0Dk_0 person +emLp02HobE4_0 person +emO2DsNKmTw_0 train +emVjapACNME_0 person +emWHcaPL5H0_0 person +emXkTzHEyT4_0 boat +emhCPyXIbNk_0 person +emqrQO4JZsU_1 skateboard +emxIavKneZw_0 person +emzfRpng4hM_0 bicycle +em3XyVBpKCc_0 train +enA3HVeW4MM_1 person +enCpXewY40c_0 truck +enCpXewY40c_1 truck +enR0OQhVBwE_0 person +enWAeU6n9LQ_0 person +enXS9AGUoow_0 motorcycle +enY96p1ZALE_0 knife +enfPrTim6AU_0 cow +engcDIwacLg_1 person +engcDIwacLg_0 person +en06DIx0cz0_1 person +en06DIx0cz0_0 person +en6AOaqCY1s_0 truck +en9gUgAJoek_0 person +eoFFf1yMhOg_0 person +eoauVNDdle8_0 person +eodvToXk2OQ_1 cow +eodvToXk2OQ_0 cow +eohpHQHPoXo_0 dog +eovUEztTVZ4_0 person +eoyj6UfwM1c_0 airplane +epIcFi7yUZg_3 cow +epK_YUgNzQI_0 cat +epUTWEmTW1o_0 bus +epXYWAgJeJM_0 person +epZSAxAzWRs_0 person +epeLK68bI3k_0 person +epeLK68bI3k_1 person +eph8ACa_bv4_0 person +eph8ACa_bv4_2 person +epis0oQPudE_1 person +epu8oDLyhBw_0 cow +epxbwMupoU0_0 truck +epxxfkiUpVQ_0 person +ep15pnX1AxU_0 truck +ep4od2aZYv8_0 dog +eqAMk_GzwUg_0 truck +eqMRouLMQI0_0 person +eqPXFnE2SxE_0 person +eqTdm4-YomY_0 train +eqWb0eTMl98_0 cow +eqiPG6XAei8_1 person +eqiVR6aa8XA_0 person +eqnF1_Lwa94_0 motorcycle +eqswu7XtVeE_0 boat +eqswu7XtVeE_1 boat +eqvu61eQ-D0_0 person +eqwZeHPEjT0_0 bus +eq2VUeTEEGM_0 elephant +eq2VUeTEEGM_1 elephant +eq2-yJIiWyA_0 skateboard +eq7fzAhOZEo_0 person +eq8-99wqpC4_0 motorcycle +eq-XVpUOFlQ_0 cow +erDb15O0GYM_0 person +erIMuEor6gc_0 person +erJzcEpQ-sA_0 person +erKEWcCPgjU_0 person +erKRZXMcCzQ_0 bus +erLW6pBgIrE_0 person +erLW6pBgIrE_1 person +erWerfoGejo_1 dog +erZ0-WmkPj8_0 person +erfJrdfPp8M_0 truck +eri-jOmjJ5U_0 person +erprzr0GCa0_0 person +errX-c_luf8_0 horse +erwHbfRwbDc_0 train +eryYeuoNAdw_0 person +esEKixC0bi0_0 motorcycle +esFUx8MS7FU_0 person +esFUx8MS7FU_1 person +esHEHZv3XAw_0 person +esdMTvdz7G8_0 person +esd9prHEDmY_0 cat +esnr6cTpfQI_0 skateboard +esnr6cTpfQI_1 skateboard +esrkVh27SSg_0 giraffe +esr3dKZtZ9I_1 person +estRADheTso_0 person +esxEV1BYf8g_0 dog +es0lurDiGrM_0 truck +etCrz_vcvJI_0 zebra +etFtHhL2hac_6 bicycle +etHjccaFHjw_0 person +etZXvy6wqZM_0 cat +etZjkcz1NXE_1 person +etfOefeQ0NA_2 knife +etgjVXNON5k_0 person +ethiyhktDW0_0 train +etrQY3yeg8M_1 person +etrQY3yeg8M_0 person +etu6chaT_o0_0 motorcycle +etu6chaT_o0_1 motorcycle +etu6chaT_o0_2 motorcycle +euNO4mGjpL4_0 person +euS2rEsG-jA_0 person +euaiFpmh6SU_1 person +GEuy-JvOFBM_0 horse +GEwLV10zHSM_0 person +GEwYE_QVNHE_0 boat +GE061if8j60_0 horse +GE8D0jEjasg_1 bird +GFCN_4akSi4_0 person +GFMwf7Ly_Sc_2 person +GFMwf7Ly_Sc_0 person +GFN08ryY-U0_2 knife +GFTwQgse_Lk_4 knife +GFXh14V5BN0_0 cow +GFkCQFowcfs_0 person +GFkCQFowcfs_1 person +GFlTNatYs1E_2 horse +GFlTNatYs1E_0 horse +GFmBVLxS0W4_0 person +GFsVA4Rxqv0_0 cow +GFtZEmPze30_0 person +GFytNaOS7eE_0 boat +GF28RuK9Mio_0 person +GF28RuK9Mio_1 person +GF29WU5hVFU_1 umbrella +GF29WU5hVFU_2 umbrella +GF4b86WLzWE_0 person +GF-zdmzb4zY_0 bus +GGBhXIkXN-U_0 dog +GGCSOyr8iNg_0 cat +GGNkUcwxgU0_1 airplane +GGX2r0RT9h4_0 bird +GGY5BDDn5LE_0 person +GGtf7t-SVb0_0 person +GGytoCC23B4_0 dog +GG2kiaUm9pg_0 person +GG_CxOFs69U_0 bicycle +GHAR-041e4w_0 person +GHF_00q4fw0_0 person +GHN9eBe1Bp8_0 knife +GHWPuquucrM_0 cow +GHZjWHKMwyw_1 truck +GHqedSEAQ9k_1 person +GHqmzbJnjVg_0 person +GHu-Q-Jbh6E_0 umbrella +GH_-l0dCs1A_0 truck +GINmKyxk55E_0 person +GIOByl4-GaE_0 person +GIQcZHeI0rA_1 knife +GIRWosek2kk_0 person +GIesL1NmKrU_0 airplane +GIiKoRSDN-Q_0 skateboard +GIiKoRSDN-Q_1 skateboard +GItE5rGj_-g_0 person +GI0iwCtSgJY_0 person +GI7YeWGyVRM_0 horse +GJAe8ctAWb0_0 person +GJHbNDEY178_1 person +GJHbNDEY178_0 person +GJIPOsnsWAg_0 person +GJIPOsnsWAg_1 person +GJL8p4_PeKo_0 person +GJMk0Meedm0_0 person +GJbtzWK_dYk_0 person +GJpkQJ1A6Gw_1 cow +GJy5Zhvk6lE_0 person +GJ1O_aGTN94_0 motorcycle +GJ4kWS7SklQ_0 person +GJ7mp6eUiPg_0 car +GJ9641JuJGs_1 person +GJ9641JuJGs_0 person +GKCr5DPt-O4_0 car +GKC9zObtOMM_0 person +GKEhy910De4_0 train +GKWJ0lgaDCg_0 umbrella +GKWJ0lgaDCg_2 umbrella +GKewJtAM0mQ_1 person +GKewJtAM0mQ_0 person +GKhEkZ-cdNQ_0 train +GKlP0uncbyg_0 person +GKlP0uncbyg_1 person +GKlP0uncbyg_2 person +GKlP0uncbyg_4 person +GKmEvD6kEV0_0 bicycle +GKn-IcumftE_0 person +GKpcLh6EzTI_0 truck +GKs6SswOMow_0 skateboard +GKyR_cV3NzE_0 bird +GK1HKUicpqc_0 person +GK7khWET2AA_0 person +GLBHzmRhRXw_0 person +GLCLinUtVWM_0 person +GLJJdMPYSaY_0 person +GLLgtpj5VIc_2 elephant +GLLkz3ew2Cw_0 person +GLN48vyNNE8_0 person +GLOfyCC7cpg_1 person +GLOfyCC7cpg_0 person +GLTbuhg3c9c_0 cow +GLTcmtEP3PQ_6 person +GLTcmtEP3PQ_0 person +GLTcmtEP3PQ_1 person +GLTcmtEP3PQ_2 person +GLTcmtEP3PQ_4 person +GLT0qdbJFmE_0 person +GLYc7lsUKvQ_0 cow +GLemLQ7Taz4_0 dog +GLiiNf5XBGw_1 person +GLnBX7vZMds_0 car +GLncyVpSovs_0 person +GLonpYW6Yi8_0 person +GLsxpYW-07A_0 person +GLy3RuBdLZ4_0 giraffe +GL2K160VZnM_0 airplane +GL5i6mrfwJQ_0 person +GL6eTReYh8E_0 giraffe +GL7g579uon4_0 bus +GL_EwiiBm1A_1 person +GL_EwiiBm1A_0 person +GMCQFxoF1UE_0 bear +GMJi6djWGYg_0 elephant +GMLP7F_Da2w_0 person +GMVqWicQ2d4_0 motorcycle +GMeN9Z1A9X4_0 car +GMj9b1A2R98_0 bus +GM3BiiUS2Xw_0 cat +GM31sVP8NMA_0 elephant +GNJ088XwXpI_2 skateboard +GNLzZ4OPnHc_0 boat +GNLzZ4OPnHc_1 boat +GNN-BevC79g_0 knife +GNRZ4AjoiSE_0 airplane +GNawMpiTEFs_0 person +GNnrNuC9zGU_2 person +GNnrNuC9zGU_1 person +GNqCvE7d9mE_0 person +GNr1nF-F-40_2 boat +GNvEs3KBgRw_0 person +GN97F0ERx8k_1 person +GN97F0ERx8k_0 person +GOE3QOj97xk_0 person +GOLZ7CWDXjk_1 person +GON778LYTqk_0 person +GOQICMUoGL8_2 person +GOWRiwkZo2U_0 person +GOW84-_w-LQ_0 bicycle +GOZwEuPDmzc_0 person +GOb0e4ojb3c_0 airplane +GOkeNGfFi8Q_0 person +GOkeNGfFi8Q_1 person +GOpAs6aca30_1 person +GOpAs6aca30_2 person +GOrO-A4yd5c_0 person +GO0RyAWdVQA_0 person +GO1tmJmOjZU_0 cow +GO9YRVC_2SA_3 elephant +GO9YRVC_2SA_4 elephant +GO98cqZbP2o_0 car +GO98cqZbP2o_1 car +GPABD8HFpQU_0 skateboard +GPCArlk4udc_0 bird +GPHwY1J1u04_1 cat +GPLKI0foxxc_0 person +GPUUqd1IyNA_0 dog +GPUdCDtaGOQ_2 boat +GPViSMkz1ds_1 horse +GPViSMkz1ds_0 horse +GPZznxc87vA_0 cow +GPlHiCxNeIU_0 person +GPnO7jt_-JI_0 person +GPn2JSguaBI_4 umbrella +GPn2JSguaBI_0 umbrella +GPn2JSguaBI_1 umbrella +GPtN0Kb9qZs_0 train +GPzwYc908OM_0 bicycle +GP2YaQXsf0s_0 umbrella +GQJu2FlmC0A_0 knife +GQRDl6gw-n8_2 bear +GQRDl6gw-n8_3 bear +GQV1QfplpXU_0 person +GQ6mrqpELDs_0 person +GQ99sfZjwTo_0 person +GRMv9irLuQw_0 motorcycle +GRQUwn0jA8Q_0 person +GRRXv9O7hNk_0 motorcycle +GRRullNXQUY_3 skateboard +GRTcBPmHWPU_0 motorcycle +GRjf8G-WDvc_0 person +GRk94EZiwO8_0 skateboard +GRo9Bmi4ghA_0 cat +GRwCcOF0NyI_0 train +GRwCcOF0NyI_3 train +GRwCcOF0NyI_1 train +GRwCcOF0NyI_2 train +GRwvd8Xl-l0_0 bird +GR5qTAjCnB4_0 cow +GSD3hdUWKNg_0 person +GSD_Asi3tsA_0 elephant +GSD_Asi3tsA_6 elephant +GSIFRlloCGA_0 cow +GSMYNBUuI74_1 motorcycle +GSb8ilGRCd8_0 umbrella +GSkpDZZFQd4_0 boat +GSmR-G7zCN0_0 airplane +GSqatXKKzUU_1 boat +GS1El_XLryU_3 bird +GTaW87cQCZk_0 bird +GTegSO4BiDY_0 person +GTgztSxvdzw_0 horse +GTg35QGB0bQ_1 person +GTg35QGB0bQ_0 person +GTjqtTiUFFA_0 person +GTkZ7eZIV5I_0 skateboard +GTpF9CW8Kyo_2 cow +GTpF9CW8Kyo_3 cow +GTpF9CW8Kyo_0 cow +GTpF9CW8Kyo_1 cow +GTt9sqczKqg_0 person +GTuP3gwjf70_0 person +GT4askC-EmE_0 skateboard +GT4askC-EmE_2 skateboard +GT6Ta63CfGc_0 bus +GT7pB1SoSWQ_0 horse +GUA64cJx_1s_0 person +GUG7toTLyt4_0 bear +GURTVjQ25hM_0 airplane +eufhHTT-6cc_0 person +eujtr13Kbtg_0 cow +eutsycO_2Zw_0 umbrella +eu0WWqOzPNI_1 boat +eu07YiPAVxk_0 truck +eu6zY6HpY1M_0 person +evA7SzcjAkU_2 knife +evA7SzcjAkU_3 knife +evA7SzcjAkU_0 knife +evDr0RJRRV8_0 horse +evMMyqn2S94_0 person +evRaMSC7xlI_0 train +evVOgDU7DsE_6 truck +evcE8ru07G8_0 umbrella +evcWn6cN50A_0 umbrella +evhP2M5P0rM_1 person +evksM4sehcQ_0 cat +evtk4IiqjkM_1 person +evw-tqTTtQ8_0 horse +ev1ATOeJPxY_0 person +ev1ATOeJPxY_1 person +ev53NALjp3I_0 person +ev7a6Z-ZOv4_0 person +ev-fVsUuvfA_0 person +ewB46nb-ZFI_0 bird +ewFZmQCCZm0_0 truck +ewFZmQCCZm0_2 truck +ewOgoCimrdA_0 elephant +ewUWpmdjLHA_0 bicycle +ewUWpmdjLHA_2 bicycle +ewgdEY7GtsQ_1 airplane +ewkBRzmoZzo_1 train +ewkBRzmoZzo_2 train +ewkeB8zzSVE_2 dog +ewkeB8zzSVE_3 dog +ewkeB8zzSVE_1 dog +ewoUjWEEJS4_0 dog +ew9rbdv73TA_0 umbrella +exR3lT_G3Yk_0 knife +exZF88kJoP8_0 person +exjWaQ0ssbM_3 airplane +exjWaQ0ssbM_0 airplane +exjWaQ0ssbM_1 airplane +exn-_MfEP6Q_0 person +exoNfV0vU_Q_1 person +exoNfV0vU_Q_0 person +exw_qJh1qp8_0 cat +ex6Il_1Ielw_0 motorcycle +ex7mPB9cYwc_0 person +ex7mPB9cYwc_1 person +ex-yo1W_s34_0 skateboard +eyAxkbxVdHA_0 person +eyAxkbxVdHA_1 person +eyNJXyldIhM_0 person +eySeJsY8tZU_0 horse +eyZeTi4-udw_0 boat +eycvZhhuzOI_0 person +eyd3cO1cRyw_0 person +eyg_dFAAJ_c_0 umbrella +eyi_kSPelbM_0 person +eyo2iTfyALs_0 cat +ey49lNbkqdQ_0 person +ey7evH7qmFA_1 person +ey9CIllx21w_2 truck +ey9CIllx21w_5 truck +ey9CIllx21w_8 truck +ezOxb6H18Dk_0 person +ezX_8NsARn4_1 person +ezYCeDV1Aew_0 bicycle +ezam_iANUkY_0 motorcycle +ezdehi1wmW4_0 cow +ezktd-PtOQo_2 horse +ezktd-PtOQo_3 horse +ezrNhnjWp-s_0 person +ezrNhnjWp-s_1 person +ezu6OcJjjLk_1 person +ezvAmpvi364_1 person +ezyLlrEVZRU_1 train +ez4u6-2yh8U_1 person +ez7mJtg4aoU_0 cow +e0Al-yQwL8w_1 bear +e0C174hEUpI_0 person +e0HCj6FnKMo_0 person +e0HrgDMAL5c_0 boat +e0K-Wc2SGSk_0 person +e0V--elE2Dc_3 boat +e0V--elE2Dc_0 boat +e0XejLvBbTw_0 motorcycle +e0dXS2okSxo_0 train +e0jUh6hQykw_0 person +e0jUh6hQykw_2 person +e0kJTvItoXc_1 person +e0kJTvItoXc_0 person +e0qJxStHuGA_1 skateboard +e0rXPv5Q8ac_0 person +e1KQ3rXcBVg_0 airplane +e1KQ3rXcBVg_2 airplane +e1KQ3rXcBVg_1 airplane +e1S7tY6zlBs_0 bus +e1ZNGYPt280_0 cow +e1a0tLtZdm8_0 person +e1dAdTW0-s8_0 person +e1guDr5Lq88_0 person +e1iYijyYnIc_0 person +e1iYijyYnIc_1 person +e1v5-Vy3ikU_0 motorcycle +e11u2SRsMQk_0 umbrella +e110Ssoc3rc_0 horse +e2Biqc_Y8fI_0 boat +e2Biqc_Y8fI_1 boat +e2C6vpxx1BQ_1 person +e2C6vpxx1BQ_0 person +e2DeceLJ4QU_1 elephant +e2DeceLJ4QU_0 elephant +e2DmJ2nN-bM_0 person +e2DmJ2nN-bM_1 person +e2IXk3LUK0k_1 truck +e2Jc499uBac_0 bus +e2MbvKCUxBQ_0 skateboard +e2oWEimFUeM_0 boat +e2oWEimFUeM_6 boat +e26M0NUTUcs_0 person +e29Si0sk8Vs_0 person +e3Ep8F-TVbQ_1 bicycle +e3Ep8F-TVbQ_0 bicycle +e3MrKt1yh3E_0 airplane +e3ezeG4Gm80_1 knife +e3fz03vzrmQ_0 person +e3pGW6uqeQA_0 cat +e3tP581aZ0Q_0 person +e34jQApS9Bw_0 person +e3_zIH1Jrf0_0 person +e4R8Aj-X5iA_1 horse +e4ZrrwoRRXc_0 bear +e4c8OdRhAyA_0 knife +e4c8OdRhAyA_3 knife +e4iZ27N3agg_0 person +e4rO9AJXQzY_1 person +e4yT58KhTcs_1 airplane +e4yT58KhTcs_2 airplane +e4zdJYlc4z8_0 person +e47QRGUx_Hs_0 truck +e47QRGUx_Hs_1 truck +e48A0CBQct8_0 person +e5CFfGS4B1s_0 person +e5DZWu7GqG4_3 bicycle +e5MbNYLt7wU_0 person +e5MbNYLt7wU_1 person +e5RlRpaBXnE_0 dog +e5UjJAZHaBc_0 person +e5VUEXqXFTM_0 umbrella +e5kfPy-MIGw_0 elephant +e5lFDgi4EIs_0 cow +e5-Pz_Q8VUA_0 person +e6F88LQJoLc_0 person +e6G0gHixPGE_0 boat +e6IQ-jfygns_0 person +e6IQ-jfygns_1 person +e6T5hbKQwAs_0 person +e6aWxOF189s_0 person +e6hz-jEGxsg_0 person +e6muu75RFmg_0 bus +e6s13mZyuYY_0 skateboard +e6s13mZyuYY_2 skateboard +e6s13mZyuYY_3 skateboard +e6xT3S6wuwE_0 person +e64lVlYKNYs_0 horse +e7IeNjbA7ms_0 motorcycle +e7JZ2C-e9_w_1 skateboard +e7Q3z9gbUw8_0 skateboard +e7TKWwysO8Q_0 elephant +e7W79Xp4qxI_0 person +e7aF0fG2O2U_0 bear +e7aF0fG2O2U_1 bear +e7eZQb8WjmQ_0 person +e7xAzZCvd_Y_0 truck +e70XtlB-Au8_0 truck +e70XtlB-Au8_1 truck +e70XtlB-Au8_2 truck +e70XtlB-Au8_3 truck +e70XtlB-Au8_7 truck +e70jqVThihE_3 knife +e70jqVThihE_1 knife +e72VJJ7jkoI_2 airplane +e76gr0pJMLg_0 boat +e8BQbcBgcjc_0 person +e8VeeESy9Xc_0 horse +e8XzpXJnucs_0 motorcycle +e8XzpXJnucs_1 motorcycle +e8XzpXJnucs_2 motorcycle +e8Y4hXyFPDY_0 person +e8ZFu6n4mg8_0 person +e8b7eo56B5Y_1 person +e8b7eo56B5Y_0 person +e8mSJe1G9U4_0 horse +e8mSJe1G9U4_1 horse +e8mSJe1G9U4_3 horse +e8mSJe1G9U4_4 horse +e804z6ehgWE_0 train +e836XbTclWA_0 person +e86xkdgTdTA_0 person +e873uWjeaPU_0 person +e88X3OKvqTI_0 cow +e9Ceg407V2o_1 bird +e9GSzFiQj8I_0 person +e9GoxfmycMQ_0 person +e9MugXot7JI_0 elephant +e9MugXot7JI_2 elephant +e9MugXot7JI_1 elephant +e9Y8BHEdYpg_1 person +e9Y8BHEdYpg_0 person +e9Z237Wup_E_0 boat +e9aADbJBMmQ_1 boat +GUY72Rg_9g4_3 airplane +GUY72Rg_9g4_0 airplane +GUY72Rg_9g4_1 airplane +GUY72Rg_9g4_2 airplane +GUcZWh6tol4_0 cow +GUq5xrqphew_0 cow +GVCJZzVnGUQ_2 person +GVCJZzVnGUQ_0 person +GVCJZzVnGUQ_1 person +GVG_dHMt7eA_0 truck +GVRLfBtpGgA_0 person +GVeNt6hXwK4_0 person +GWCwYIRE8YU_0 person +GWIAU4GsgZM_0 person +GWQD6FxWwpk_0 boat +GWckuI3sTHA_0 bear +GWmOpSmpGmg_0 car +GWmOpSmpGmg_1 car +GWmOpSmpGmg_2 car +GWsXKIAM9yY_1 cat +GWsXKIAM9yY_0 cat +GWygvbszdUs_1 train +GXS6axKBr7A_0 person +GXX1pJeR1HE_0 elephant +GXX1pJeR1HE_1 elephant +GXZ3IXi7YXk_0 person +GXcbgDsx_Zc_0 person +GXfsYdVEMeA_10 elephant +GXfsYdVEMeA_0 elephant +GXfsYdVEMeA_5 elephant +GXfsYdVEMeA_6 elephant +GXfsYdVEMeA_8 elephant +GXgoAnrkdVg_0 person +GXiDQ52vcoY_0 person +GXoA1zfvnOA_0 car +GXrzW-OHh_Q_0 cow +GXtA9dxzvII_0 person +GXyeuhOYX2k_0 truck +GXyeuhOYX2k_1 truck +GX1v3ymtHtc_0 person +GX-3aTTy4lM_0 person +GX-3aTTy4lM_1 person +GX-3aTTy4lM_2 person +GYA-3PblNaU_0 person +GYHWtVM2x6c_0 person +GYTD79P3b8w_1 person +GYT5Cq1tl2Q_0 cat +GYWNYnWPaeE_0 person +GYY-ElZl7ZM_0 dog +GYldHkVSD_A_3 airplane +GYmeM7epDjY_0 person +GYmeM7epDjY_1 person +GYoXwAkvJns_0 person +GYsx_49_O1U_0 truck +GYuIsHEGV6o_0 person +GYuMuXQgLPI_0 person +GY0HVEiAPvo_0 person +GY3D9bb9kLY_0 airplane +GY65ShkktrM_1 person +GY9iCFFBA20_0 person +GY-carc6vxw_2 horse +GY-carc6vxw_3 horse +GY-carc6vxw_4 horse +GY-dmOLQNH4_0 truck +GZIpKCyb0bU_0 airplane +GZLsv-Y_aRw_0 person +GZM5nvvMeNo_1 airplane +GZOUGcF_xaM_2 train +GZThnpa-8Ak_0 train +GZUk3BlrK7k_0 person +GZWH1bUqm9U_0 person +GZYSkuRZwGE_2 skateboard +GZb9G8sVRz4_0 person +GZb9G8sVRz4_1 person +GZgL3ZQI9nM_0 cow +GZhuCclpFuk_0 elephant +GZq8tIKR9b4_5 bus +GZsP_n7aFMo_0 person +GZxvpxqvHFs_1 airplane +GZ0bYvVD_us_1 bird +GZ1aL_iE5a8_1 person +GZ6PRvVVeZk_0 person +GaAL3IYDUgM_0 skateboard +GaD4QsNCcik_0 person +GaF_t9Af1hg_3 umbrella +GaJvFxg_lFY_0 person +GaJ7Bu5UrgQ_1 bus +GaJ7Bu5UrgQ_2 bus +GaVmURUD-i8_0 person +GaYAyNs2FDI_1 person +Gad1St-JBls_0 dog +GaeWhfSP3EA_2 knife +GagCDetg0dg_0 bicycle +Gai7qgVSFc8_1 cat +GangZBQawtQ_0 person +Gax9nZtMs7M_0 person +Gayl2EVJTkw_0 dog +Ga3YHyqOqYY_1 person +Ga3YHyqOqYY_0 person +Ga_Oju23T9s_0 person +GbBl5CcJgeE_14 elephant +GbBl5CcJgeE_6 elephant +GbBl5CcJgeE_8 elephant +GbBl5CcJgeE_9 elephant +GbBl5CcJgeE_10 elephant +GbC0DAAn-XU_3 bear +GbC0DAAn-XU_12 bear +GbC0DAAn-XU_14 bear +GbE-oXaNVBA_0 elephant +GbE-oXaNVBA_3 elephant +GbE-oXaNVBA_5 elephant +GbE-oXaNVBA_6 elephant +GbE-oXaNVBA_7 elephant +GbE-oXaNVBA_8 elephant +GbE-oXaNVBA_9 elephant +GbE-oXaNVBA_12 elephant +GbGEC5pQ9f8_1 cow +GbHLET097K8_0 boat +GbN_zMz1D6o_0 person +GbOK07Tq7mA_0 boat +GbVDftpuPMo_1 person +GbW-55xLUnQ_0 airplane +GbY3uHcC3ys_0 truck +Gbbhlv2Obsc_0 person +Gbbhlv2Obsc_1 person +Gbd1-rm9Oyw_0 truck +GbmEMxbMtCI_0 bicycle +Gbs4s3pX3H0_5 knife +Gbs4s3pX3H0_0 knife +Gbs4s3pX3H0_1 knife +Gbs4s3pX3H0_2 knife +Gbs4s3pX3H0_3 knife +GbulfCx1hwo_0 person +Gb_YkJHLgns_0 train +Gb_YkJHLgns_1 train +GcCQF52Ok14_5 person +GcCQF52Ok14_1 person +GcCQF52Ok14_3 person +GcCQF52Ok14_4 person +GcEgsdqMiBg_1 person +GcEsDxUkr00_5 elephant +GcEsDxUkr00_1 elephant +GcRRhnk4ynk_0 person +GcnVDv6bIAk_0 person +GctFFbsebBs_0 person +GcwS7IyeG5Y_0 motorcycle +Gc0lgXRlxGE_1 person +Gc0lgXRlxGE_0 person +Gc3iNFz3s-o_0 cow +Gc5OyOM0VxI_1 person +Gc5OyOM0VxI_0 person +GdI2CnryrFQ_2 car +GdNJ-VDNc3k_1 person +GdQuxx_RXvs_2 bear +GdbphRsxpKU_5 horse +GdbphRsxpKU_3 horse +GdfyxcmHHOQ_0 person +GdiGBeJ9m_k_0 person +GdiGBeJ9m_k_1 person +GdsJ0QHb83w_1 person +GdsJ0QHb83w_2 person +GduwjeptozQ_0 person +Gd5qUjEeqZ4_0 motorcycle +GeHV-tf-ZGA_0 bus +GeUECF6hDkg_0 airplane +Geb74PkjTYY_1 person +GehgPYVYwDs_0 person +Gek3IJfBaU0_0 train +GeuYAXldbbg_4 airplane +GeuYAXldbbg_1 airplane +GeuYAXldbbg_2 airplane +GeuYAXldbbg_3 airplane +GewTJtB97l8_2 knife +Ge2suMLyOTY_0 cow +Ge4SjOnEYWs_1 person +Ge4SjOnEYWs_0 person +Ge8RWLzmrE0_0 person +Ge8RWLzmrE0_2 horse +Ge9uJatNWuw_0 person +Ge9uJatNWuw_1 person +Ge-VfDpriPY_1 person +Ge-VfDpriPY_0 person +GfCjURNr9T4_0 person +GfLxzlZxHic_0 person +GfbcHsH3DKI_0 person +GfeXUZVyvL4_0 person +GfefENTSQOI_0 person +GfkX7I9bclY_0 cow +GfqA0SZPeXU_2 horse +GfqA0SZPeXU_3 horse +GfxwasnA0Ao_0 bird +GfxwasnA0Ao_3 bird +GfyBiJNU7bY_0 car +Gf50aWojLhk_1 airplane +GgV4eSmNyaA_1 elephant +GgV4eSmNyaA_0 elephant +GgcoCmlTlbc_0 person +GgfESlKFIkU_0 dog +GgkncqtrgPI_0 person +GgsFohIKlpw_0 dog +GgyOGY2q9xE_0 skateboard +Gg9uDi7KjJ0_0 person +GhBPvHC15BE_0 person +GhHPtGuUtRY_0 person +GhI4uqxOQpc_0 horse +GhLdswZDYMs_0 bicycle +GhLdswZDYMs_1 bicycle +GhMC34aeHnU_2 person +GhMC34aeHnU_0 person +GhMC34aeHnU_1 person +GhQRZOseJfY_0 truck +GhbtO__NASs_0 person +GhbtO__NASs_1 person +Ghbt5lVT3dk_0 truck +GhiVm-6oFyg_0 train +GhwtPgHjLvg_0 dog +GhxWr3HvvXA_1 person +GiRzA3Fe1-s_0 person +Gijruln92tk_0 truck +Gik59IGJFLo_0 bird +GioAI9XlGGg_0 bird +GioEMsI07Jw_0 person +e9ihaIQuVMU_0 knife +e9ihaIQuVMU_2 knife +e9iolRKSwBw_0 person +e9mOqKDBOVg_0 person +e9nH--aGWDM_0 person +e90GV6rl3NE_0 person +e9-w67QSEBs_0 person +e9-w67QSEBs_1 person +e9_LqDqVkGs_0 person +e9_LqDqVkGs_1 person +e9_LqDqVkGs_2 person +e-PcZyfAPZ4_0 person +e-R-FxrDQao_0 person +e-dVHSE1qXI_0 person +e-gU8I2kZyY_1 bicycle +e-n0pRU6uSk_0 bus +e-n0pRU6uSk_1 bus +e-qbVMLqnEw_0 person +e-siUblegSA_0 dog +e-siUblegSA_1 dog +e-v2yWUGKiU_1 boat +e-zbkYroVUk_0 person +e-43rdp3psc_0 person +e--Qr92yhBo_2 horse +e--vN-5QX-E_0 person +e-_nLPye6sc_0 person +e_APlM8VSiw_1 person +e_APlM8VSiw_0 person +e_FyX6iUBZk_1 person +e_GD2rN9Jcg_0 person +e_SYVD0TY14_0 airplane +e_UwPkRMD74_0 person +e_aHtRh2PpI_0 cat +e_b_4zlKmdo_0 giraffe +e_qdDAeerKQ_1 bird +e_-SOM0hufo_0 truck +fAHFZWyNZQ4_0 bird +fAHFZWyNZQ4_2 bird +fAJAQb5tzFA_0 dog +fAJ939SI_YI_0 person +fAKXvHREf8E_0 bird +fAMkbedQ0GI_1 person +fAQoNDLgds4_0 bear +fAUG8-TdflE_0 person +fAjj5137yKM_0 bicycle +fAm_6grpTOI_0 person +fAyBUKM7898_0 person +fAz2ecihxEU_0 person +fA5ArJS7ScI_0 car +fA6XfSl7pqY_0 person +fA_OWAI_8kc_0 person +fBH6rLEukMU_0 person +fBIh-CAYfy0_0 person +fBLrr2zYnRw_1 person +fBLvIU3Q7Rw_0 horse +fBPjBSdwz1o_0 elephant +fBPjBSdwz1o_1 elephant +fBP3dZYp3sM_0 person +fBT1cNog4Lw_0 person +fBkDTXhVYCs_0 giraffe +fBmp8URVoB4_0 car +fBsQegHOF8Y_0 person +fBtfkn4uDKE_0 cow +fBvAf66603Q_0 person +fBwrgO05rqo_0 truck +fByljFegqK4_0 person +fCADagfWgSU_1 elephant +fCK_OirKTO4_0 person +fCMJnkyFS5c_0 person +fCMJnkyFS5c_1 person +fCPVsi1S2jM_0 cat +fCTNp-hiUkQ_0 person +fCTNp-hiUkQ_1 person +fCT0UeuTcQk_0 person +fCUZclkgF-c_3 car +fCUZclkgF-c_4 car +fCUZclkgF-c_5 car +fCVoLETgca4_0 bicycle +fCW56GByDs0_1 person +fCW56GByDs0_0 person +fCX_8Q_OAos_1 dog +fCZXrHFimHM_0 person +fCbvdNQUcRE_0 cat +fCdlrWXZ7kY_0 person +fCiWi1Dk-yE_1 person +fCkgtao7rJk_0 motorcycle +fCmwPCLYVXE_0 skateboard +fCmwPCLYVXE_1 skateboard +fCm-8YmQfoY_1 giraffe +fCoXLMBzqTc_0 cat +fCohGx6PWyM_0 person +fCr-fmsVVWE_0 person +fCsSoErwvfw_2 skateboard +fCsSoErwvfw_0 skateboard +fCsSoErwvfw_1 skateboard +fCtyUxRaSdQ_0 skateboard +fCwicNYDKmo_0 person +fCzWVcZvGuk_1 motorcycle +fC6O_2ljm_c_1 person +fC6O_2ljm_c_2 person +fC6O_2ljm_c_0 person +fC8FUnipL3M_0 bird +fDBgRd9yK8Q_5 airplane +fDBgRd9yK8Q_1 airplane +fDBgRd9yK8Q_4 airplane +fDCK-s1gX18_0 skateboard +fDCadv28EEo_1 person +fDCadv28EEo_0 person +fDFpsal4hHo_0 person +fDIVkvMCQ9I_1 cow +fDJjIhw4XBI_2 person +fDJjIhw4XBI_1 person +fDLBxom0wgI_1 cat +fDVesIz_ON0_1 person +fDe30IPiQ0Y_1 horse +fDuiW9_sHcQ_1 person +fDyXAhF761Q_0 person +fD89z8ycv7U_0 person +fD89z8ycv7U_1 person +fD89z8ycv7U_2 person +fEDj20Gce80_0 boat +fEK6hdzjG5E_0 cow +fESV3o1vc1A_1 bird +fES_1kR2d8o_0 person +fEVLKYBuE7k_0 truck +fEXq69B6L0s_0 giraffe +fEZ5cqJWg0A_0 bicycle +fEdlpwoza6o_0 person +fEdlpwoza6o_1 person +fEdlpwoza6o_2 person +fEgqRE0XOMM_0 person +fEh5hyz4LCU_0 skateboard +fEiWI60P4XI_0 bicycle +fElOryAiN0s_0 person +fEmh4mfGsCA_0 person +fEupHSTMXLk_0 knife +fE0raHY_nY8_0 cat +fE_sSvVFvZU_0 dog +fFBkKrJlobs_0 cow +fFEDu-fiUUM_0 person +fFGmvl4E9QI_0 bird +fFImZECw1c0_0 skateboard +fFImZECw1c0_1 skateboard +fFOTZMvg0n0_0 horse +fFRp0dBucFA_0 bus +fFTJuANVr2I_0 person +fFWU4PNTKDo_0 person +fFWU4PNTKDo_1 person +fFaJ5epORzQ_0 person +fFd91uPKDVA_0 person +fFksYDaR-NI_1 elephant +fFmCHQgzMRc_1 person +fFmCHQgzMRc_2 person +fFmhW2ygNKw_0 person +fFncU3kR5qw_0 car +fFogpyIr-Ic_0 person +fFq0hnzgGSw_2 bicycle +fF0RlMrKBFo_0 bicycle +fF1S-952IOU_0 horse +fF3WOuwnvrA_3 elephant +fF3WOuwnvrA_5 elephant +fF3pBoS7xFg_1 person +fF3pBoS7xFg_0 person +fF34g3sNiHo_0 person +fF7snD5S5Q4_0 car +fF_BanWRtKo_1 skateboard +fF_BanWRtKo_0 skateboard +fGGJnSDPzUI_0 person +fGI6_U9U_zc_1 person +fGPsR0YiVaE_0 train +fGgJ0VACAo4_0 umbrella +fGlnCmVPzIs_0 person +fGrC6VCXVL4_0 person +fG1NOqIRoLA_0 person +fG6uSVeocMo_0 person +fG-4n3Gy1fk_0 person +fHO3g6Q_bNE_0 person +fHUjlWalvJQ_0 person +fHVJzD_AvV8_0 person +fHepRAiQQ04_0 cow +fHlfVMMfXNg_0 person +fHm5WgSYk2Y_0 bus +fHoBjwC8H50_0 dog +fHoBjwC8H50_3 dog +fHsaxiTw0dI_0 motorcycle +fHzSK8AEv5U_0 person +fHzzixV1xyg_1 cow +fH5U2jXbkEg_1 knife +fH8PS8Fjvbg_1 cow +fH8PS8Fjvbg_2 cow +fIABVBcluZ0_0 skateboard +fIABVBcluZ0_1 skateboard +fIFMCt78hmI_0 truck +fILyoB3Pgrg_1 dog +fIM7jmsq_FE_0 person +fIN8z4lkdyA_0 car +fIN8z4lkdyA_2 car +fIN8z4lkdyA_3 car +fIPXE6MOZp0_0 airplane +fIT1bTlW3UQ_0 person +fIVT3rTMptI_1 truck +fIXFrPFEL0w_0 giraffe +fIlXSJxnKD8_0 person +fInEVgREyyY_0 dog +fInYB8sD7tM_0 person +fIrb5Y93wjw_0 train +fIvUwaa2ziY_0 person +fIyrHecb8SQ_0 elephant +fI0VoDDN2lE_2 person +fI0VoDDN2lE_0 person +fI0VoDDN2lE_1 person +fI5fnVs_kWg_0 motorcycle +fI8DySScPWU_0 skateboard +fJGPTgv8EUs_0 person +fJJBGybbnH4_1 knife +fJJX9D4siG4_0 cat +fJTeqi3aqRc_0 car +fJYGkMT9c6U_0 truck +fJY5zGaYs8s_0 person +fJdWgbIMXZ0_5 train +fJdWgbIMXZ0_0 train +fJdWgbIMXZ0_2 train +fJpRqXhL3wE_0 skateboard +fJp4DAu46Yg_1 person +fJxbRDMY46o_0 person +fJyBgU7rZvE_0 person +fJ71o3Q-oVE_1 cat +fKDRpRcSnrw_0 cat +fKHs2FNZk6M_0 person +fKLJqhEdsTY_0 cow +fKLJqhEdsTY_1 cow +fKLS0DAexvw_1 boat +fKLS0DAexvw_2 boat +fKLS0DAexvw_3 boat +fKRZ4PPWgg8_1 person +fKcOtlmf6r0_3 boat +fKcOtlmf6r0_2 boat +fKgpRiyDlvc_0 person +fKhENDvpnmA_0 boat +fKhe37bCgeA_1 horse +fKp-Lvw2bUM_2 elephant +fKp-Lvw2bUM_3 elephant +fKp-Lvw2bUM_4 elephant +fKrxRvMxZqM_0 person +fKxBpYS29uM_0 dog +fKyPRwF5y6s_0 person +fKzFEc6hR-c_2 person +fK89Z2AwlCg_3 bus +GiuUBGsdiqI_0 person +GizeLrnWRmk_1 person +GizeLrnWRmk_0 person +Gi--TM8Xz3I_0 person +GjCs_s2EnpE_0 person +GjFr4qO_LX4_0 dog +GjJFQButa0w_0 bear +GjJk6U2crcw_0 skateboard +GjJp-yqt7xk_0 airplane +GjZDPTKpIdE_0 person +GjZP-buSAG8_0 person +Gjdyi0kf79Y_0 truck +GjfhgZMeHAA_0 person +Gjgu3OFbWKI_0 bear +GjkrI0adkJk_0 person +GjmNPrYyCwg_0 person +Gj87GZKvhdo_0 horse +GkCXvg93pAA_0 cow +GkGG1F5by14_0 person +GkddmkbGSAc_0 cat +Gkfp-yV9e94_0 person +GklwzbjOzYQ_0 person +GkmRFBuktnQ_0 person +Gkxkfi_wHeA_1 motorcycle +Gkxkfi_wHeA_0 motorcycle +Gk6IzYQADXg_1 skateboard +Gk6IzYQADXg_0 skateboard +Gk9v8ABOPNw_1 elephant +GlLzIn-6ouU_1 bicycle +GlLzIn-6ouU_2 bicycle +GlPdixjfu44_0 cat +GletqIQ8irw_0 motorcycle +GlsMcq1cM2c_1 bird +GlxEVs7z_7Y_0 person +Gl7S2JNezLg_0 boat +Gl7S2JNezLg_3 boat +Gl9cy66E4FQ_2 knife +Gl_UMssuTWU_0 person +GmI47tbiNQ0_0 person +GmKT2rhDILU_1 knife +GmQX3sIhhqo_0 cow +GmS0yrU3Hcw_0 person +GmUFocQWPTo_1 boat +Gmdxq1glmKY_1 dog +GmeGRg8XZ5M_0 person +GmvKmbIHKHM_1 person +GmvKmbIHKHM_0 person +Gmww9V50JtU_0 dog +Gm9BnQSZlxk_1 person +Gm9kb3zHsLA_0 cat +GnFoElm_rrw_0 dog +GnGd8Q_cSHU_0 person +GnGd8Q_cSHU_1 person +GnO2sxJNWjk_0 elephant +GnRp7QHoAr4_0 train +GnkSrEpnmRo_1 person +GnmgLr5p-r8_0 bus +Gno0JyFsjGk_5 knife +Gn0av9LV5FU_0 elephant +Gn3AqY6vUyU_0 elephant +Gn7B_MiLuhA_0 skateboard +GoEBr-GbeCk_0 elephant +GoEcYxqxcZ8_1 bus +GoEy1J3s8Xs_0 cow +GoRGaOgttBU_0 horse +GoUjZ5wJ2do_0 car +GoWyqQorqOY_0 cat +GoXlqK766lk_0 person +GolDzhH16vg_0 train +GorfZ7y-Jw8_0 skateboard +GosFitiV7as_0 person +GotzQ9ecvkM_0 person +GoubTEJzKUI_0 person +Go16BKYvDSs_0 horse +Go5M-oyC28A_0 elephant +Go8BM-B0ML4_0 skateboard +GpCjTjkSw3k_0 train +GpCjTjkSw3k_5 train +GpCjTjkSw3k_3 train +GpCjTjkSw3k_4 train +GpCjTjkSw3k_2 train +GpDilZGSveI_0 person +GpJmJforKzo_0 person +GpPbMduP_3Y_0 cow +GpProJiVxa4_0 bear +GpTPDl3MzZw_0 cat +GpVy_gD1slw_0 dog +GpY4Nw8LLy4_0 bird +GpkftB3rq5g_0 dog +Gpn_kF1lXuc_0 bicycle +Gpn_kF1lXuc_8 bicycle +Gpn_kF1lXuc_13 bicycle +Gpn_kF1lXuc_14 bicycle +GpzE4RQTM1Y_0 airplane +Gp3g6UYBBzw_0 person +Gp3g6UYBBzw_1 person +Gp70TnjZRfU_1 train +Gp70TnjZRfU_2 train +Gp70TnjZRfU_0 train +GqZeX-EEEL8_0 person +Gqc_LkQvKak_2 horse +GqjVd_dRiB8_0 person +GqjVd_dRiB8_1 person +GqjoBpwsgUc_0 person +GqjoBpwsgUc_1 person +Gqntj1GoicU_0 bus +GqzN0dyl5p4_4 truck +Gq-mMFeLCyo_0 person +GrG-ipHg_4w_0 person +GrK4qEJjeKE_0 airplane +GrNDwiO4kdI_0 airplane +GrQ0zJbkeXE_0 person +GrXOOtPiIGw_0 zebra +GrYsw9-Skqg_0 person +GrZvWtxffXE_0 person +GrpvM1_CRqI_0 train +GruxXrzWzjk_0 airplane +GruxXrzWzjk_2 airplane +GruxXrzWzjk_3 airplane +GruxXrzWzjk_5 airplane +GrzyUDtV-Ug_0 person +Gr6be_D6d9Q_2 skateboard +GsFDHyoPppk_0 person +GsGHB19iuE4_0 person +GsKJMkVSeV4_2 airplane +GsL7VYYWhu0_0 person +GsOgw9XtlWc_0 airplane +GsOgw9XtlWc_1 airplane +GsTlT_7Zb1Y_0 train +GsVvc55IHn0_0 skateboard +GshXL9V-lrM_1 person +Gsj4aXqBPHM_0 truck +Gsn06D15nmk_0 motorcycle +GsrSyK5ymQo_0 boat +GsrenPacLW0_1 person +Gs67R7prarI_1 motorcycle +Gs7J9Yo-uF0_0 cow +Gs7J9Yo-uF0_1 cow +Gs79ZsyWm74_0 person +GtAKWYvc9kY_0 elephant +GtCbEqqQgqY_0 person +GtCbEqqQgqY_1 person +GtD2m1EXxjc_1 bicycle +GtKaIcQJZcc_1 person +GtLYNeredOY_0 boat +GtVrmoeEcMM_0 knife +GtZPw5ftw88_0 person +GtZSRodviU8_0 person +Gta1hcIAAE0_0 elephant +GtiiYqVQ2Kw_0 person +Gtmp8y8APfQ_1 skateboard +Gtnqm4SnEXo_0 horse +Gtnqm4SnEXo_1 horse +Gtnqm4SnEXo_2 horse +Gtnqm4SnEXo_3 horse +Gtnqm4SnEXo_4 horse +Gtqcx01NTTw_0 knife +Gtsvc9lA7hs_0 airplane +Gt33VfmFDWw_0 person +Gt6q9b3QUvE_0 bicycle +Gt6q9b3QUvE_2 bicycle +Gt7thmVY6aQ_0 person +GuQvGMFuhu4_1 car +GuQvGMFuhu4_3 car +GuXelRN3wMo_4 bear +GuaD24NfCe0_0 person +GuawwNMbfBI_0 person +Gue43DvNTGc_1 train +Guf15LHosg8_0 person +GugU0nZdPJU_0 bus +GuhfGduN9v0_0 person +GulmsZq-VsU_6 boat +GulmsZq-VsU_0 boat +GulmsZq-VsU_3 boat +GulmsZq-VsU_4 boat +GulmsZq-VsU_5 boat +GusEs8RA4_o_0 motorcycle +GuwTG6RtcFI_0 person +Gu4MWCc2Wws_0 bicycle +Gu-vFv_w9Vo_0 person +GvFmkdxnKyI_0 horse +GvIj2sMkJwM_0 person +GvNhgCGtUOQ_0 truck +GvQvyfTNykM_0 truck +GvRM_UnjJoE_2 horse +GvdMRPX4KR4_0 train +GvdMRPX4KR4_1 train +GvdMRPX4KR4_5 train +GvoIcT-hFek_0 person +Gv9mTaerVLc_0 person +GwFrSa-YwfI_0 bear +GwFrSa-YwfI_1 bear +GwIn1NaaEwE_0 bus +GwbpMG2B14Y_0 truck +GwgaNLd1f7s_0 truck +GwlNXPuUvXM_0 person +GwnBP9a07RE_0 person +GwnBP9a07RE_3 person +GwnBP9a07RE_4 person +GwnBP9a07RE_1 person +GwnBP9a07RE_2 person +Gwx1ad4lW1Q_2 person +Gwyl7djxZkg_0 cow +Gwy4ODXAAU8_0 person +Gw5YyHT1Nt8_0 person +Gw9Vi_Io9DM_0 person +Gw_Tiv72jms_1 horse +GxANCkxq7Ng_0 motorcycle +fLCd0DDhfBk_0 person +fLEUT0rTkv0_0 bird +fLJniCJFPTg_3 elephant +fLPHwVvk6K4_0 person +fLPHwVvk6K4_1 person +fLWW1YWO26Y_0 bird +fLdMmSIfseM_2 person +fLdMmSIfseM_0 person +fLe279fKywo_0 dog +fLsDTJxlsW8_0 person +fLwrxElzLZs_0 person +fLyNbq9v6kg_0 person +fL1w15qwbqE_0 person +fMOnb4P7tww_1 person +fMOnb4P7tww_0 person +fMO1J7ojQqk_0 dog +fMTosfHKy2I_0 dog +fMi6lVyCOHw_0 boat +fMwCpOTv9RY_0 bus +fM-puV4uyzs_0 person +fNAZ9IDLZy0_0 person +fND_OguW0MM_1 elephant +fNIdPhAsjiM_0 cat +fNJSPU5r3sc_0 person +fNO_o1D0kvY_0 person +fNdRm3HWQmo_1 motorcycle +fNgr2EBEDCQ_0 car +fNgr2EBEDCQ_1 car +fNg3y0FHjgg_0 person +fNhDT1fwzKM_0 person +fNhDT1fwzKM_1 person +fNh54BNEJBQ_0 cat +fNw9dDcM4ms_0 bear +fN-FYknWOSk_1 person +fN-FYknWOSk_2 person +fN-43XPvLwg_0 motorcycle +fOLR2dvBtqo_0 cow +fOO1pHvrPWQ_0 person +fOatLQK_AyQ_3 bicycle +fOcPVX4sAxg_0 horse +fOjKgQf86dk_0 horse +fOkrLuGKDvk_0 person +fOkrLuGKDvk_1 person +fOkrLuGKDvk_2 person +fOsd2aWzfBo_0 cow +fOtnatCU7_Q_0 person +fOuV2101nEo_0 bear +fOv8ocd2xhA_2 knife +fO30fgQYdT4_0 bus +fO8Do_0RQXU_0 person +fO9GgD7GqE0_2 bus +fPBIIZV6fuU_0 person +fPMNtuJztSA_0 person +fPVn9Wxf_HQ_0 person +fPVn9Wxf_HQ_1 person +fPrhiYslRjA_0 person +fPzDDdztZNk_0 horse +fPzQyo7caqU_0 person +fPzqpL90owQ_6 bear +fP5AyxuGIS8_0 person +fP8x_x2_k5g_0 person +fP-DMm3u5n4_0 cat +fQEGEb4W3IE_0 person +fQNyLEXwnn0_0 person +fQOjoYB5hPQ_0 person +fQOjoYB5hPQ_1 person +fQOymYsdTtU_0 person +fQdA_-549Dk_0 dog +fQh5RtZzYzo_0 bicycle +fQlChBB42M0_0 person +fQoJWcmQmsU_1 person +fQo0G2i1QjY_0 person +fQt3g_9u1RQ_0 airplane +fQyE_yIAu_0_1 skateboard +fQ26oO2Y5NM_0 bicycle +fQ4H6UmTepU_5 giraffe +fREDiuJlBf8_0 person +fREDiuJlBf8_1 person +fRFF0xtrWhI_0 elephant +fROdeQpu88o_1 knife +fRS5rhYP7LM_0 person +fRXDSh8gr0c_1 person +fRZ7Wze7ATs_3 knife +fRcegyxH0Is_0 car +fRhNtVu6anA_0 dog +fRjCbO3MyU8_0 person +fRmnBvuwZlU_0 dog +fRmnBvuwZlU_1 dog +fRrLguORoeU_1 umbrella +fRrLguORoeU_2 umbrella +fRrd-Z2R-Gs_0 person +fRtzYh_gGgI_1 cow +fRwzMPH6Kvw_0 person +fR1zDIeBHFg_0 person +fR6FrFNXUxY_0 person +fR-JNy5hccc_0 umbrella +fSA7T5svJ-o_0 bus +fSBe_a8ZkZU_0 cat +fSey4VJgLM0_0 person +fSfKYTVt7V8_2 bird +fSfX4Z6SR2U_0 horse +fSj-h8lAhWw_0 cat +fSoqM6oq2AA_0 train +fSoqM6oq2AA_2 train +fS0098HnnhM_0 person +fS3KL3nj7FY_0 person +fS73PiHaNi8_0 person +fS8_byjM-1M_3 zebra +fS8_byjM-1M_0 zebra +fS_6fgFOiPU_3 train +fTFLfGUcgMs_0 elephant +fTFLfGUcgMs_3 elephant +fTFVwPKxUHE_2 elephant +fTP9YgSJZg8_2 knife +fTVb5uxWnsI_0 person +fTVb5uxWnsI_1 person +fTgirzB_QLU_0 person +fThV1JtaTJg_0 person +fTkIm1nb6qg_1 bird +fTkIm1nb6qg_2 bird +fTnnG_WcLYY_3 knife +fTnnG_WcLYY_4 knife +fTwiavhNzxs_0 person +fUB-cH8rjW4_1 person +fUB-cH8rjW4_0 person +fUF__EdDFVs_0 skateboard +fUISEtXSRYM_0 person +fUU4R6RP4ek_0 motorcycle +fUXpqgf4jUA_0 bus +fUd8LjmonBM_0 person +fUetaCH3tZk_0 person +fUg6JULdTnU_0 person +fUonzpmV18o_3 bird +fUqVKgWVVNY_1 person +fUqVKgWVVNY_2 person +fUwzXH9i0yQ_0 person +fUx60fl9UkU_0 person +fUzsVWD48bA_0 person +fU3o6Frqdww_0 truck +fU4DzirdCVE_1 airplane +fVAmI93Yb6E_0 cat +fVAsOuag4vY_1 giraffe +fVHZEHosow0_2 person +fVH3n0aghP4_1 person +fVH3n0aghP4_0 person +fVH7PpDqlPE_0 boat +fVIVas1R1tk_0 cow +fVOy449KQlY_0 person +fVX7qR-o-9I_0 cat +fVZfWzDBb-c_0 person +fVZ_9hWIGpA_2 truck +fVdrMKHN9WY_1 cow +fVq7Of0Tr-s_0 person +fVr3XVUzJaA_0 train +fVv5EqFYsAY_0 person +fV80H_L3AN8_1 motorcycle +fWLqbV7Z7Go_1 person +fWLqbV7Z7Go_0 person +fWb_-8hhubg_0 person +fWmJ9tUUCwg_0 person +fWpdcmgr5r4_0 horse +fWxgjNDC4OQ_0 car +fWxgjNDC4OQ_1 car +fWxsOgW3P6U_0 person +fW1Z_Mx1RaA_0 person +fW4fh_WBiMY_0 train +fW7yPljMFRc_0 person +fW7yPljMFRc_1 person +fW_HPaNBsDE_0 cat +fXCFktk2xdc_0 person +fXLB02IH0G4_0 person +fXLB02IH0G4_1 person +fXOdZ0uKuBc_1 dog +fXWqvRfBWto_0 person +fXX7K6CQfBw_0 airplane +fXYn01Cgmqs_0 dog +fXY7h0cc6tw_0 cow +fXbnEKMaIoM_1 boat +fXbnEKMaIoM_0 boat +fXka5y708fI_1 person +fXowuJDXhhU_0 person +fXyBm7_EDVc_0 skateboard +fXzIQASqygY_0 bird +fX-kSrf_K8w_0 horse +fYDgPdRtmjU_0 train +fYLtnvuW_VI_0 motorcycle +fYMA0fLN8sI_0 horse +fYN5ZIicl_k_0 car +fYmfHE2mONE_1 person +fYnsIFGQfT8_0 person +fYql4FiApLQ_0 horse +fYtm_pGBWkU_0 person +fYu5ChRgapY_0 motorcycle +fYw5KVCsg_4_0 person +fYyI8x0tNAA_1 bear +fY4-6vsjmD8_0 person +fY82KLfOpbk_0 person +fY82KLfOpbk_1 person +fZCdkf9VQzU_2 cow +fZEFEAYBlGE_0 cat +fZFYdgZbSBg_0 person +fZFYdgZbSBg_1 person +fZJOS8BlA-w_0 person +fZOtury_J_w_0 person +fZTIKbSjOhk_0 airplane +fZTJH_9Pqvg_0 person +fZTJH_9Pqvg_1 person +fZWP75nltcM_0 bird +fZXzEYFmZ_8_0 person +fZXzEYFmZ_8_1 person +fZiiYH3WfD8_0 skateboard +fZnbOFaSEQc_0 person +fZnbOFaSEQc_1 person +fZp_UgW_xZU_1 motorcycle +fZp_UgW_xZU_0 person +fZu7wEVEuX8_0 person +GxHmm60dKvc_0 skateboard +GxLI4BFLrps_0 person +GxPYf4SAQvE_0 person +GxPYf4SAQvE_1 person +GxWuAfBV300_0 person +Gxg0Pt_9bIE_0 person +GxwwTXW-DdQ_2 train +Gx1zPI3b2oc_0 person +Gx3xtKPwlz0_1 horse +Gx4ryd6AGl4_1 train +Gx4ryd6AGl4_2 train +Gx4ryd6AGl4_3 train +Gx4ryd6AGl4_0 train +GyGdlCtDdJc_0 person +GyIKdb5KDHk_1 train +GyPRnKI78iA_0 person +GyU8x9urAxE_0 motorcycle +GyVDsnuS5jU_0 person +GyXlgRxQ1jo_0 train +GyXlgRxQ1jo_1 train +GyZHiIEOBos_0 cat +Gya_TrOGXpo_0 person +GyhjyC5aJ8U_0 bus +Gyjb_P1W7TA_2 bus +Gyn_wSuRB3w_1 truck +Gyzaf_gaIYY_0 motorcycle +Gy9JueTT4XU_0 person +Gy_XuBCvbUc_1 dog +Gy_XuBCvbUc_2 dog +GzB9OTV44PA_0 person +GzHy2xjKB_8_0 person +GzLmftr6tl8_0 person +GzRkvFxVlx0_0 person +GzTDLPCsgSM_0 person +GzVj8bI0bSk_0 skateboard +GzVj8bI0bSk_1 skateboard +GzcgYGEqOlY_1 horse +GzesZ0laH2w_0 motorcycle +GzizYdL25ZY_0 person +GzjkTrnmEnU_0 airplane +GzjkTrnmEnU_1 airplane +GznFDBDT2c0_0 truck +GznFDBDT2c0_2 truck +Gzrgq_nWH_Q_0 horse +GzujCDTak_4_0 horse +GzujCDTak_4_2 horse +Gzy_PnFtEpM_0 person +Gz3Np50b9q4_0 truck +G0DQ6VdMp-U_7 car +G0DQ6VdMp-U_0 car +G0DQ6VdMp-U_1 car +G0DQ6VdMp-U_2 car +G0DQ6VdMp-U_4 car +G0DQ6VdMp-U_5 car +G0DQ6VdMp-U_6 car +G0FSe53KN-w_0 person +G0WsFATo9RQ_0 person +G0dXxEbeJnM_1 person +G0d44YoKXX4_0 person +G0kDhLojiI4_0 giraffe +G0leBoTgEx4_0 person +G0rwWyFSsYE_0 train +G0r2tR6EcF8_1 person +G0urH-9ytbc_0 horse +G01Xi8VMxgQ_0 person +G03JTuHY_RM_0 knife +G1AIHF-KITc_0 person +G1AtN7CvCXw_0 person +G1EnmuHlxig_0 person +G1P_XnEL4dc_1 person +G1P_XnEL4dc_0 person +G1TS-PvdREA_0 person +G1TS-PvdREA_1 person +G1ThERK4a8E_4 airplane +G1ThERK4a8E_0 airplane +G1UoN56m5DM_0 person +G1YNrrT9-z8_0 bird +G1YNrrT9-z8_1 bird +G1cY71JK5_E_0 motorcycle +G1c0-CTyZ3I_0 person +G1dKhZZARDk_0 airplane +G1z6RMtKkbM_0 bird +G1z6RMtKkbM_1 bird +G11cHAnx17E_0 horse +G13ARgckI9w_0 person +G17Kpx1bgXM_0 horse +G1_R_EJpLZU_0 cow +G2FXcVDezv4_0 truck +G2HOmWxj5gg_0 person +G2LNQIwbLHE_0 person +G2S4rwP6qJY_0 bicycle +G2V6wliL2AA_0 knife +G2g4Z-Syzi8_1 dog +G2lFYYEolz4_0 train +G2lFYYEolz4_2 train +G2x5gACWSwA_0 cow +G2z7yjdCUuI_0 airplane +G23Q_C35Uqs_0 bear +G24yJOgl9t0_1 person +G25iisvOYhA_0 cat +G2-v9IBlnTs_0 person +G3AuCS7s68w_0 bird +G3IID08lWos_0 person +G3P-Vvra2GU_0 horse +G3SowFCFa0g_0 person +G3VeVH6pbdE_1 person +G3a0EYtnqHA_0 person +G3cazaory7w_0 person +G3f8bIoGGZ0_0 dog +G3kNB0zhHQc_0 person +G3pT4MJrpDI_5 umbrella +G3pT4MJrpDI_6 umbrella +G3pT4MJrpDI_4 umbrella +G3vP7_U6yXU_1 cow +G37Dm4oy794_0 bicycle +G38EbyEOITE_0 horse +G38SrxcVYWs_1 person +G39ryVtNnhQ_3 elephant +G39ryVtNnhQ_8 elephant +G39ryVtNnhQ_9 elephant +G39ryVtNnhQ_11 elephant +G4PD_RAK48Y_0 person +G4VPBDOgq54_1 skateboard +G4VpcUuXgRs_0 person +G4VpcUuXgRs_1 person +G4ckSGXUGts_0 person +G4fbkcKiZVg_0 person +G4nRZ4PHvC4_0 dog +G4rJejZ9FIM_0 car +G4r0UJvtDXs_0 cow +G4xFWKKoN0M_0 motorcycle +G47wnMA6RVE_0 bus +G4_xR7lZIPo_3 bear +G5D1cAo2D6s_1 person +G5JwolS0D1M_5 elephant +G5QgL60_yfc_0 knife +G5SlrQeATlc_0 bus +G5SlrQeATlc_2 bus +G5hG8j0KxBI_0 person +G5ixkqq66VA_0 person +G5rBbx_kODY_0 person +G5ztukDN_Qg_0 zebra +G51fdi_hG_0_0 train +G52uuPWcC3M_0 umbrella +G553b8ZAd3Q_0 person +G58FuwBYL-0_0 skateboard +G5_UJ1wEKh4_0 person +G6OttGznP9E_0 person +G6OttGznP9E_1 person +G6QMME1QbK8_2 car +G6Qmm4T-cd0_0 bus +G6WiR4W4WWk_0 person +G6b9lySVCCY_0 person +G6eAvUHoDkc_0 person +G6fvYSH13nI_2 train +G6iVTjyPM04_1 horse +G6sFOs8MgGU_0 bird +G6sFOs8MgGU_3 bird +G6sFOs8MgGU_6 bird +G66e5ltBFoI_0 person +G7DhRPK7pwc_1 bicycle +G7F-ufxEXPY_0 knife +G7H7fQ_Q1Ec_0 person +G7H7fQ_Q1Ec_1 person +G7ID9RdMSkE_0 person +G7MvPG8Qv84_0 giraffe +G7TezoE9Cmo_0 person +G7WblvVQPF0_0 person +G7Z01jmMzlI_0 bird +G7krBQa_KLc_0 person +G7p90FBQk_0_0 truck +G7slUshqPvY_0 elephant +G74HXSqYO-A_0 motorcycle +G75uQAEuUkE_0 person +G766vinfuBw_5 bicycle +G766vinfuBw_9 bicycle +G77KKnCpwWY_3 skateboard +G8EC6svgwKU_0 person +G8NIqmq7YdE_2 bear +G8V2UsTc1Ik_0 cat +G8V33bTVNII_14 bicycle +G8V33bTVNII_1 bicycle +G8V33bTVNII_2 bicycle +G8V33bTVNII_6 bicycle +G8V33bTVNII_9 bicycle +G8XX8bkx6Ek_0 person +G8hStuDYwH0_2 airplane +G8kDZAPbUe8_0 person +G8kDZAPbUe8_1 person +G8k84FwnW2k_0 motorcycle +G8lDrK3u3r0_2 elephant +G8lfwRN3Iew_12 boat +G8lfwRN3Iew_0 boat +G8lfwRN3Iew_8 boat +G8lfwRN3Iew_9 boat +G8lfwRN3Iew_11 boat +G8sDCWad2Bg_0 cat +G8s2n3jAKW8_0 cow +G8tbj2R0iso_0 person +G80DOuBBH_Y_3 airplane +G8--2JpJa6g_0 person +G9DdsOO1mZo_0 horse +G9FQJdIxjsk_0 bird +G9YPEOrV5UU_0 person +G9YPEOrV5UU_1 person +G9YPEOrV5UU_2 person +G9ZKH_DS9DU_0 person +G9gsnqhd_Sw_0 cat +G9hPaEx7Ci0_1 knife +G9i66tUOspc_0 dog +G9juxPad3zY_0 person +G9nlPUwJQB0_0 person +G9nvXjuig6s_0 person +G9qCl1NZelo_0 cow +G9rxIfeUWVo_0 airplane +G9vDsElCKAY_0 dog +G9zd0G8dIt0_0 person +G93PAKTtVpM_0 horse +G97UC0qtVDw_0 person +G97YtHMd2hw_0 person +G99rEXOdlC8_0 horse +G9_TgGWQQi8_0 person +G-Sr-qmWZNo_0 cow +G-YYtvCU7qY_0 dog +G-d6o3nTBFA_0 zebra +G-nFiFb0Xos_1 knife +G-nbiqZuFdc_2 horse +G-qCe2DK3Tk_0 motorcycle +G-u_ThqhoJE_0 train +G-yCRlVSs6w_0 person +G-3kOsn1fPY_1 person +G_ADLUKVq8Y_0 boat +G_LtPKO6be4_0 horse +fZ1GVGZmTRA_0 person +faJuqm4umTQ_0 person +faSv8ijeKeE_0 person +faVBgge6xkE_0 person +faW2tWwuCMg_1 person +faW2tWwuCMg_0 person +fahs60oGhLU_0 train +fatTPMeG5Pc_1 bear +fa-rHhFEloA_1 truck +fa--elcQpd4_0 elephant +fbDYKST2P-I_0 motorcycle +fbFVM0UM5V0_0 person +fbM5MhIve5s_0 dog +fbM5MhIve5s_1 dog +fbiXTCkCkqY_0 skateboard +fbmZZXaRkak_5 horse +fbmZZXaRkak_6 horse +fbmnWcE_64U_0 skateboard +fbsyvHQPZZk_1 dog +fb3Iq9yQ1VY_0 person +fb3WxEfe8l8_0 motorcycle +fcCb2W4HMLk_0 person +fcD6n99azfw_0 person +fcGNPf6n7Ws_0 bear +fcWegrm8wCE_0 person +fcbcnvGoWLs_0 car +fchtQi7-OD4_0 horse +fclxNO1L-rY_0 cow +fcpGNeDgpDI_0 person +fc1qNL5u2wg_0 person +fdCTLMd6wEY_0 cat +fdQaoSZKA_s_0 person +fdRULl8YSnU_0 cow +fdYvCuft5zQ_4 elephant +fdYvCuft5zQ_5 elephant +fdYvCuft5zQ_1 elephant +fdYvCuft5zQ_2 elephant +fdZBeWyKON0_0 person +fdbvWvUoFW8_1 bird +fdbvWvUoFW8_2 bird +fdbvWvUoFW8_3 bird +fdkrZ9uL854_0 person +fdlDkbbDniw_1 elephant +fdmV18YEDKM_0 cat +fdnBDcIwPBA_0 person +fd3ea86gmJI_0 motorcycle +fd3ea86gmJI_1 motorcycle +fd8Ba2cZgxI_2 bear +feAexE1IYq8_0 person +fePU3BlF4Zc_0 person +fePU3BlF4Zc_1 person +feQX_1dqh9g_9 bicycle +feQX_1dqh9g_1 bicycle +feQX_1dqh9g_3 bicycle +feZfxIunWHo_0 person +feZoXB7I6wE_0 person +fedmeW-WImw_0 train +fegJtwcNo5c_0 bicycle +feh4XVzjQdI_0 cat +felt48AIbIs_1 person +fenYF-k-y4c_0 skateboard +feqLG8n4nDE_1 person +fe05wKXl2cI_0 person +fe05wKXl2cI_1 skateboard +fe5_49oxMwc_0 person +ffIQZZ_P3ck_0 cat +ffOeGlw8_C8_1 cow +ffZoY75S_-k_1 bird +ffZoY75S_-k_0 bird +ffbSaNikNF4_1 elephant +ffeYBfcgF3s_0 person +fftSD6UfvEA_1 person +ffttXyArNGc_1 knife +ffvXiSjPp6c_0 horse +ffwk_8ycQiA_0 person +ff1PHzfARZk_0 person +ff5MH6QQuJk_6 knife +ff5MH6QQuJk_2 knife +ff5SaJnQg5M_0 person +fgEpQHGYIjc_0 person +fgFy8l-b1iI_0 motorcycle +fgJJxPEHVZQ_0 person +fgPShysxuQM_0 cat +fgQE-9shdmQ_0 elephant +fgUjCKe_e_Y_0 person +fgWtwTKCtMQ_0 person +fgfizI4AnVs_0 person +fggT4HM2Uy4_0 person +fgsaC375d38_1 bird +fgvUj1mCqio_0 train +fg1ISXcyb10_1 dog +fg5mCaScLE4_10 umbrella +fg5mCaScLE4_0 umbrella +fg5mCaScLE4_3 umbrella +fg5mCaScLE4_4 umbrella +fg5mCaScLE4_6 umbrella +fg5mCaScLE4_7 umbrella +fhHLCLuQAdE_0 bird +fhHLCLuQAdE_3 bird +fhHLCLuQAdE_4 bird +fhHLCLuQAdE_1 bird +fhHLCLuQAdE_2 bird +fhQN_vhNmgo_0 cow +fhan95LbdqQ_1 knife +fhmsHcZfBC4_0 person +fhutr5rLQN0_0 person +fh5lB6U-7Wk_0 person +fiGa0nIEYbw_0 person +fiKecNhAgFU_0 motorcycle +fiS0pY80kkU_0 dog +fiWtkuDUFvM_0 elephant +fiZAhg2twZs_0 person +figjWJDEn1c_0 person +fijO0rB1rfY_0 airplane +finRU64JVRU_1 bus +fi2s2k_aamk_0 person +fi46OpYa89I_3 bicycle +fi46OpYa89I_10 bicycle +fi46OpYa89I_2 bicycle +fi6gdEVUAUc_0 cat +fi8YGUm_6x0_0 person +fi9GleMDHIc_0 person +fjF31Mh-tNQ_0 person +fjKXALm76kI_0 bus +fjXufPzimEQ_0 person +fjZ4J-BZX2U_0 person +fjaHYcaE7-w_0 person +fjaHYcaE7-w_1 person +fjnR81fSTeI_0 umbrella +fjnxqBnMZzs_0 person +fjtn0lRVX_4_0 truck +fjwgdNBSCFc_0 person +fjwgdNBSCFc_1 person +fj29rB34ea8_0 person +fkERi_ma2UE_0 person +fkERi_ma2UE_1 person +fkHiDyuUaWA_0 person +fkIfLHGu_CQ_0 person +fkQEEtG6Tbg_0 person +fkSf5a3q6oY_0 boat +fkSf5a3q6oY_3 boat +fkUDB0V3UXc_0 horse +fkUDB0V3UXc_1 horse +fkVSILZPyXg_0 bear +fkaKyYrWPpQ_0 person +fkfnbZ2MSXk_4 bicycle +fkfnbZ2MSXk_0 bicycle +fkfnbZ2MSXk_6 bicycle +fkx0e2gvPYA_0 truck +fkyM4LNUCck_0 person +fk0v7vZDpgU_0 person +fk10mtIF_Hs_0 horse +fk8yMMO1gRA_0 person +fk8yMMO1gRA_1 person +flADy--Uwx8_0 truck +flERyzHjhzQ_0 skateboard +flMijcdhRAU_0 person +flgTyT4DB7E_0 bear +flgaLcoSjb4_0 bear +fluEronPyZk_0 cow +fl6-NRwVy10_0 person +fl7Q9yxFoOs_2 person +fl95IAyDN-s_0 skateboard +fmERtylbqN4_0 person +fmGJj0qYc6g_1 person +fmGJj0qYc6g_2 person +fmLKgz4DQhQ_0 airplane +fmL66yeOiI8_0 person +fmRfUvIIvT8_0 person +fmYELQL9Cs0_0 bus +fmbEAdugI3Q_0 person +fmbb6SQ6qiI_0 person +fmbb6SQ6qiI_1 person +fmbu89zGN4Y_0 person +fmdem4Z9BHI_0 bird +fmfg5yyhjkA_1 person +fmiq_EhaURY_1 person +fmiq_EhaURY_0 person +fmtIa6nxUd4_0 train +fmuzrZHZYis_0 skateboard +fmwC1khd3BU_2 person +fm3zFVlJw4k_1 person +fm-ScTLdSL8_1 bus +fm_bcsJYhu4_0 dog +fnAGderLxPg_0 elephant +fnAGderLxPg_3 elephant +fnDP4B5jpSY_0 person +fnFMQ2VFlEc_0 person +fnOL3ZL61u0_0 person +fnOkwsmzdaI_0 horse +fnRq5X91IV0_0 person +fnZR6FD_eZ8_0 boat +fnZR6FD_eZ8_1 boat +fnbSgwO8v0c_1 boat +fnbsAmTQJOs_0 bicycle +fnbsAmTQJOs_1 bicycle +fniJ36z0_Pc_0 cow +fnj1YtAaztU_0 person +fnkHdQf9H3w_0 knife +fnmuFbydHek_0 person +fnpjkwiPkSY_0 skateboard +fntRlkYDiD0_1 person +fntZVzkwhz4_1 person +fnvst-Sk4MU_0 umbrella +fnvst-Sk4MU_1 umbrella +fnz6gTPuInQ_0 dog +fnz6gTPuInQ_1 dog +foAoOCF4rE4_0 car +foI1jEbg9uA_0 train +foJs0wXX1O8_0 truck +foaFgrzsPOY_0 person +fobJTCY7ifQ_0 bus +fodsoLtLzqI_1 cat +fojRgMUsu3c_0 person +G_RgJ0t0Cbo_0 person +G_aU-_2ZiSw_0 dog +G_lOQAV6xWs_0 cat +G_poofS7HD0_1 person +G_poofS7HD0_0 person +G__VTazZtp0_0 elephant +HARRnedV05U_0 car +HAVUursfTOI_1 zebra +HAtu6frOH1k_0 person +HA1TDbNot8E_0 person +HA-iE7bcfT0_0 car +HA-iE7bcfT0_1 car +HBI13CpuAmI_0 knife +HBLJbCs1mSg_0 truck +HBMah_r3E1g_0 person +HBOqQBe7rhE_0 person +HBO6G57uhXA_0 person +HBY4_6b_sRY_0 cat +HBiSuZWtb4E_0 boat +HBmaJJ0nTAo_0 person +HBwjWdXrpPA_0 dog +HBzYVphfmRQ_0 person +HCA4jkg9HTY_1 person +HCA4jkg9HTY_0 person +HCEjNJewxbw_0 person +HCJ1EYfF8qg_0 elephant +HCKZ7kihdaM_2 airplane +HCMBgpQ2z18_0 cow +HCSbzHGXxmA_0 cat +HCczjWUmlW0_1 truck +HCczjWUmlW0_0 truck +HCg0k7LnfkY_1 cow +HCg0k7LnfkY_0 cow +HCiRQdh20qg_0 dog +HCm-B3JjzhY_0 cow +HCpxRBja8lE_0 person +HCp6gYC9NFE_0 cow +HC72_Yrigik_0 person +HDN4DqO_KLg_0 dog +HDQEWwETuU4_0 person +HDRKiYaoEnA_0 person +HDSw0KM8cSs_0 person +HDkI156rPRA_0 person +HDmK6y86kYM_0 person +HDmK6y86kYM_1 person +HDnYEdh7xG8_0 person +HDqUvaFm_R0_0 skateboard +HDr5if6Mb_4_0 person +HDziFGwpXmg_1 car +HDziFGwpXmg_2 car +HDziFGwpXmg_3 car +HDziFGwpXmg_7 car +HD1tKnKT1Dc_0 motorcycle +HD7QKzuFNas_1 person +HD7QKzuFNas_0 person +HD_alEnCVhM_0 truck +HD_alEnCVhM_1 truck +HD_wYO2_O8k_0 person +HD_4ZJr68p8_1 horse +HEIjtOJze90_0 person +HEfIJ3wMKRI_1 person +HEmv-biWoEA_0 airplane +HErkHysJd-M_0 person +HEr_leMW1zE_0 bear +HEr_leMW1zE_3 bear +HEr_leMW1zE_1 bear +HEyY4zEX-no_0 person +HE-4YEdBwuw_0 dog +HE-4YEdBwuw_1 dog +HFDK_y7kibQ_0 knife +HFE9ujNILoA_0 cat +HFQFlm1jWiE_0 person +HFQFlm1jWiE_1 person +HFRCZSouOn4_0 bird +HFWQl2JJfic_2 person +HFa18pRSsXU_0 train +HFlanXHBGHg_0 person +HFuw8C2bQ6g_0 person +HF07qDRPgrw_0 horse +HF1xhyTtWLk_0 motorcycle +HF3Nn3KqXOk_0 person +HF3Nn3KqXOk_1 person +HF4PefI86r0_0 person +HGFcsJmjWHs_0 elephant +HGFcsJmjWHs_9 elephant +HGFcsJmjWHs_4 elephant +HGFcsJmjWHs_5 elephant +HGFcsJmjWHs_7 elephant +HGLC_YFRxPY_0 skateboard +HGLLnmQiCU0_0 person +HGLLnmQiCU0_2 person +HGLLnmQiCU0_1 person +HGLdrgf2e2c_0 person +HGVNoha70iA_0 truck +HGZDROOjAY4_1 person +HGZDROOjAY4_0 person +HGeCBN48g9o_0 person +HGm4OftDlT8_2 horse +HGnIxotAPOU_0 person +HGnegc2CRTM_0 person +HGvXva6SUvE_0 person +HGw4URr4QUs_0 person +HG1zQzSX2rU_0 person +HG8oY2Ac4-M_0 person +HG_JAnXBzJQ_0 skateboard +HHGq5gd6w1g_0 skateboard +HHPW65GVeoA_0 person +HHRUnCEVnAo_0 cat +HHc5mD1TxGQ_1 knife +HHe9m9BOi3A_0 person +HHgC0pkNiIA_0 person +HHgC0pkNiIA_1 person +HHi26rWtC38_0 person +HHx5E8VfnkY_0 person +HH0OILx6PKY_0 person +HH1JApHMx2I_0 dog +HH148v63a5o_0 person +HH9wMNMJ2sE_0 elephant +HIBd79qG-XQ_0 person +HICJGOFvwoc_2 bird +HIHX1rpDx_I_0 cat +HIIQ917jPqg_0 train +HIJGcmgyEcg_0 knife +HIJGcmgyEcg_1 knife +HIKyhRtWQ4c_2 horse +HIK-Z8wXFug_0 person +HISWMgqg80E_0 skateboard +HITf8extnnk_0 person +HIXuU8Z0N9o_1 motorcycle +HIgiF2bkOys_0 person +HIgiF2bkOys_1 person +HIiu2EVu5H8_0 person +HIqhXDkhHsc_0 person +HIqr0-BB8Xo_1 knife +HIrcAjP1fDs_2 bird +HIz27dqnl20_0 bus +HI3L38NCy0A_1 boat +HI3L38NCy0A_0 boat +HI_h7HfFDVw_0 boat +HJGPBeom3y4_1 umbrella +HJSiTzkFpHk_0 person +HJVpMFJT2LU_0 person +HJVpMFJT2LU_1 person +HJg7wtoy2vk_0 person +HJhZhn0zf1s_0 person +HJi1L5HxuLo_0 skateboard +HJi1L5HxuLo_1 skateboard +HJi1L5HxuLo_2 skateboard +HJq4kVvdeRg_1 skateboard +HJrd3kpvjh0_0 person +HJr5BOgO9XY_0 person +HJ6BZjeSHTY_0 boat +HKFJzdCsRfA_0 person +HKGK0FLN9vA_2 zebra +HKGK0FLN9vA_3 zebra +HKIwynmyQp4_0 person +HKWELXwIVvI_0 person +HKqHmDjxF6Y_1 person +HKsVn1IWaas_0 person +HK28Vb__IfY_0 person +HLAEqFEcR90_4 horse +HLAEqFEcR90_0 horse +HLAEqFEcR90_2 horse +HLAEqFEcR90_3 horse +HLBgSJD-3lg_0 bicycle +HLL_j-CQKqQ_0 umbrella +HLaiRkL4gFA_0 motorcycle +HLhbGKVR4mE_3 dog +HLy3UUDhaJY_4 giraffe +HL06bx_HNg0_0 cat +HL6dNcrAEoM_0 person +HL8fh6O6iUA_1 train +HL9F68y-0kY_0 horse +HL9F68y-0kY_1 person +HL9o2Vs9d8s_1 person +HMF0KrAf0iI_0 person +HMIGIwIcNq8_0 person +HMJerOjZn4I_0 person +HMQQrRvzwiM_0 boat +HMUBbUP6Ko8_2 boat +HMV7H81wz84_0 train +HMb-pPTMZ5I_0 umbrella +HMxMledcSVE_0 person +HMyUpcpZGdM_1 bird +HM4hJE0Db2Q_0 person +HM4zY3uzwOQ_0 person +HM7sD8YClkI_0 person +HM_3ck6yooo_0 person +HNGh3Rvn6Sw_2 knife +HNGh3Rvn6Sw_3 knife +HNRwM8zXMTM_0 person +HNXQ_dkhX-Y_0 truck +HNdRITK9TGE_0 person +HNeVOXPyunw_2 person +fo9SmkQa35Y_0 motorcycle +fo9SmkQa35Y_1 motorcycle +fpM1eiK3iok_0 truck +fpNLFTgOciY_1 umbrella +fpRq9BsaPzs_1 horse +fpRq9BsaPzs_2 horse +fpVZYKlsFsU_0 boat +fpdUwZ8Gnd8_1 cow +fpeYfCUzvDY_0 cat +fpkxYBJDTtI_0 person +fpkxYBJDTtI_1 person +fpmtNez1u0o_0 bus +fpnTZF4bvk8_0 person +fpomSxrdTyE_0 person +fpo2kf1idyo_0 person +fpp_41AxRNI_5 giraffe +fpp_41AxRNI_1 giraffe +fpp_41AxRNI_4 giraffe +fqQL3QPq-lo_0 train +fqXvzEGxSak_0 bus +fqcie5yyOxA_0 cat +fqfHWT5hjkY_0 cat +fqkVB4qZbgw_0 person +fqlWb2OJg3Y_0 bus +fqnioIm10xY_1 train +fqpMhE5qOKk_1 person +fqxGN6r9oIY_0 zebra +fq5Zh2Lo9GQ_0 elephant +fq959dAMasM_0 truck +frFSlwby-0k_0 train +frFrggXiJZY_1 person +frItg4I9oEQ_0 person +frItg4I9oEQ_1 person +frJtciauQQw_0 person +frRHj0FPzVQ_1 person +frW5BpQ3-Fw_0 person +frXxZevI11c_0 person +frXxZevI11c_1 person +frY6tIPR-Co_0 bicycle +freW9Vk3GhU_1 person +frfLZ70XIXI_1 dog +frgCmAtYao4_1 boat +frh4LMyWaQw_0 person +frn-rfqmGVs_0 person +frx5Uv7-1zw_0 person +fr3S3gEtDS0_1 person +fr616yExbeg_0 knife +fsD7pYdfrpg_0 person +fsE0DlVODpY_1 person +fsFtKjirvM4_1 person +fsFtKjirvM4_0 person +fsOoFz6I_js_1 person +fsOoFz6I_js_0 person +fsVlTdh13Lk_0 person +fsXVGaRpUNg_0 person +fsd-DhcH5gE_0 person +fsd-DhcH5gE_1 person +fsh-wcyuPM0_0 person +fs3oXXx75XA_0 person +fs6L5bmf4pQ_1 person +fs6Rgfl4CtI_0 boat +fs6p-qaLswQ_0 cow +fs7RdtNY3Ck_0 elephant +fs9uDpde9ig_1 elephant +ftG2YflDq_E_0 knife +ftH3_awR5ZA_0 person +ftIp5PyaGNc_1 knife +ftNSK_rSs98_1 airplane +ftSUBEOhdck_0 cat +ftX9ErOmiAE_0 car +ftX9ErOmiAE_1 car +ftcnCvd4yeU_0 person +ftlmGO0CnHk_0 truck +fuHAM8D3ros_3 bicycle +fuO2QMXiDMU_0 motorcycle +fuPtCtdvowQ_0 person +fuSxdcdxe70_1 person +fuSxdcdxe70_0 person +fuh4-mC5fvg_0 car +fuklviv_MRE_0 truck +funKReksXEQ_4 horse +fur41mRCURs_0 cow +futBuKCP9zw_0 umbrella +fu5d7x7pORY_0 horse +fu_f4n_bYPU_0 person +fvAislzoQVU_0 person +fvDUF-aukF4_0 person +fvH1bolPY2U_0 person +fvKg6ReEigA_14 bicycle +fvKg6ReEigA_2 bicycle +fvKg6ReEigA_3 bicycle +fvKg6ReEigA_4 bicycle +fvKg6ReEigA_5 bicycle +fvKg6ReEigA_8 bicycle +fvKg6ReEigA_11 bicycle +fvKg6ReEigA_15 bicycle +fvKg6ReEigA_16 bicycle +fvKg6ReEigA_17 bicycle +fvKg6ReEigA_19 bicycle +fvLauezWx5g_1 skateboard +fvLkNgA4N0k_1 person +fvZYmQ6SJrQ_0 person +fvcIpyJFuQA_0 person +fvdoipKMj4g_0 person +fvfb_kQCs-I_0 horse +fvhVuqonUHg_0 person +fvhVuqonUHg_1 person +fvlGWjjirUQ_0 person +fvqWMyJJqog_0 person +fvqWMyJJqog_1 person +fvtTggVCkFk_0 person +fvzbC9c98ik_0 dog +fv42-nzlEsY_0 train +fv8F7gjL7Js_0 airplane +fwCUjUa0cHQ_0 person +fwG8C9CEISw_0 person +fwLL8mlHf0I_0 bicycle +fwL9zu2j3rk_0 person +fwQMFtFdERs_0 horse +fwQMFtFdERs_1 horse +fwTB5tDP4cU_0 person +fwT-VIjQCa8_0 person +fwop4msktdA_0 cow +fwv2gGVEi6g_0 person +fwwOICMutXc_0 dog +fxFzCD192K4_1 bird +fxHZn2FXRGk_0 horse +fxHZn2FXRGk_1 horse +fxQYhMoNR9I_0 person +fxQY5tnybxQ_0 skateboard +fxWwYiT8yXk_0 person +fxWyDyUmxuY_0 horse +fxbNI1vTtq0_0 train +fxbjh88g3Vw_0 person +fxcDLsblNhs_1 bird +fxdVSYuYJOE_0 person +fxhuSOpUuGs_0 person +fxr4HpTRNS0_0 dog +fxxjK3mjCF0_1 person +fxyg5GQk8H8_0 airplane +fxyg5GQk8H8_2 airplane +fxyg5GQk8H8_3 airplane +fxyg5GQk8H8_4 airplane +fx07mGL1WQY_1 train +fx2_nahpAfE_0 person +fx4HT1nuEg4_1 person +fx4HT1nuEg4_0 person +fx9TwmuIYCY_0 skateboard +fx9fckiExps_0 person +fx_zN3FWeJ0_1 bus +fx_zN3FWeJ0_3 bus +fx_zN3FWeJ0_0 bus +fyE4_usnxHc_0 person +fyE4_usnxHc_2 person +fyOZZ_u9Jm0_0 person +fyOxr6iISdI_0 elephant +fyRO8_b4wJU_0 person +fyTzI2wuC0M_0 person +fybHaZZmAzE_1 train +fydZoAN9JpI_0 person +fydZoAN9JpI_1 person +fydZoAN9JpI_3 person +fyhSoeveW3I_0 train +fyyLjISjzvM_0 person +fyztN8okJkU_0 person +fyztN8okJkU_1 person +fy5GdRFHsLs_0 cat +fzFR54WdDEU_0 person +fzV_Z79golE_1 truck +fzaNjkWQtW0_1 skateboard +fze3woUbt0w_0 dog +fzh-lO5lQhQ_1 bird +fzoZsW3AMTU_0 bird +fzp3cT3c5Wg_0 person +fzp3cT3c5Wg_1 person +fzp3cT3c5Wg_2 person +fzqX7N7ICQw_1 person +fzqX7N7ICQw_0 person +fzrGdIi_J9k_0 person +fzr9mWLJM6E_1 person +fzr9mWLJM6E_0 person +fzvrWQX908c_0 person +fz1PTzziIcg_0 person +fz1kPSLo_p8_1 train +fz8emqnbleQ_1 boat +f0BJ56Dn3D0_0 cat +f0E5mPnVSSU_1 person +f0JOvKbLwTQ_0 person +f0LbneUbWUk_0 cow +f0TYLMAZLpA_0 person +f0XZTHcpmZY_4 elephant +f0XZTHcpmZY_2 elephant +f0XpDJO5Tw0_0 person +f0XpDJO5Tw0_1 person +f0Z8cmobjWs_0 truck +f0Z8cmobjWs_4 truck +f0Z8cmobjWs_7 truck +f0Z8cmobjWs_8 truck +f0mYYISWwxo_1 person +f0mYYISWwxo_0 person +f0o0SmB2JAE_1 cow +f0o0SmB2JAE_0 cow +f03_N__tWuI_2 elephant +f1ASjw4-yL8_0 person +f1Da4qa1SIw_1 person +f1EKnOQEf5g_0 boat +f1GkfW2mOlE_0 person +f1G2DlbJqyI_0 person +f1HKyLr8nL0_0 person +f1JCS5F-LuU_0 person +f1KEvGLqqwI_1 umbrella +f1O6FYMq5zk_0 person +f1XB0uA4Dvo_0 bus +f1Z1HedJzos_0 skateboard +f1fEuZwBkDQ_0 person +f1nxCdtYwdQ_0 horse +f1sTzp9ahWM_1 person +f1sTzp9ahWM_0 person +f1uaPSveXCI_0 person +f2ADBeQ0Vys_0 person +f2ADBeQ0Vys_1 person +f2EbBSZ8osI_0 zebra +f2EbBSZ8osI_1 zebra +f2HKs4L6fwE_0 person +f2HKs4L6fwE_2 person +f2HKs4L6fwE_1 person +f2MDAAk-Euo_1 person +f2ULSb7lIAo_0 cow +f2ULSb7lIAo_1 cow +f2ULSb7lIAo_3 cow +f2hfKAL0ZoA_0 umbrella +f2hfKAL0ZoA_4 umbrella +f2hhMTSObNY_0 skateboard +f2p2YcmHn8c_1 bicycle +f2s4nNZ_qew_0 boat +f2ypHkP1WUg_0 person +f3EOdxK13SU_0 giraffe +f3HU85Jx7m0_0 cow +f3JkzQkcdVM_0 horse +f3Kxw7yBcW0_2 person +f3Kxw7yBcW0_1 person +f3Np8rGlxOE_1 person +f3VJKfFdBW0_1 truck +f3aufQBTMME_0 boat +f3bk60UZpqE_0 truck +f3bk60UZpqE_5 truck +f3bk60UZpqE_9 truck +f3kQ_6EG8cM_0 person +f3spBT1AGyw_0 person +f31ePv3WlNc_0 person +f33OpHIFMWA_1 elephant +f33OpHIFMWA_3 elephant +f33OpHIFMWA_0 elephant +f33OpHIFMWA_2 elephant +f35syqOsqSo_0 boat +f38P7AlhP5g_0 person +f39rc-7_QQc_0 person +HNr7Ed0_pQY_1 bus +HNtUUtLCSDY_0 giraffe +HNtojLNWnKQ_0 person +HN6XGq0aRx4_0 person +HN84N_vu_hw_1 person +HOAbQ4r1tzM_1 knife +HOA47mRJ9B8_0 person +HOOwNsMTi9g_0 person +HOSMm-4fUVM_0 dog +HOZcbA0OPF0_0 person +HOkS1ljUX4s_0 bear +HOmzECHFah4_0 dog +HOxzSXuj0O0_0 elephant +HOxzSXuj0O0_3 elephant +HO6yeFgs7Hs_1 bicycle +HO7Uf5Enr1U_1 person +HPAa3KI1Z30_1 dog +HPDws9wJu40_0 train +HPIdRNu7STU_0 dog +HPIxVE3OLG4_0 person +HPPTr0Mpe0A_0 bicycle +HPRp9F-4ts4_0 dog +HPSJZXcOiEc_0 person +HPjcp8hS6vs_0 person +HPjcp8hS6vs_1 person +HP0RUfuvfx4_0 person +HP4O8FbEpEg_0 bus +HP6ROW7ahtU_0 person +HP6YRIGqiI4_0 horse +HP62suxiDNw_0 bicycle +HP62suxiDNw_2 bicycle +HP62suxiDNw_3 bicycle +HP62suxiDNw_1 bicycle +HP9u4FmRvbw_1 bear +HQBhagraDwo_0 cat +HQIxUlu7xSY_0 person +HQKVBNWD_ls_0 person +HQM9aDN7Tf0_0 person +HQZVUknJ0lw_1 person +HQZVUknJ0lw_0 person +HQePQ1mfzKw_0 person +HQePQ1mfzKw_1 person +HQhnj0h9OyA_0 person +HQhnj0h9OyA_1 person +HQjXFK_0sFo_0 person +HQxihmm6sSs_0 person +HQz_At1F0Yk_2 bicycle +HQ4ZWia0f1E_2 cow +HQ9gmrJ6Bm4_3 airplane +HQ9gmrJ6Bm4_4 airplane +HQ9gmrJ6Bm4_5 airplane +HQ9gmrJ6Bm4_1 airplane +HRCOvhALHv0_0 train +HRUX75Ve2aQ_0 person +HRVMd5SmF8Y_0 umbrella +HRl1VhUfhok_0 person +HR1wffFOaEw_0 elephant +HR4ExP8Ompc_0 horse +HSKpu2UmvBo_0 person +HSKpu2UmvBo_1 person +HSN6tO3rh-c_0 person +HSVWpwFagLg_1 person +HSdyrMzM64w_0 cow +HS3WVWEFHm8_1 person +HS3WVWEFHm8_0 person +HTAnAeW5Bhs_0 bird +HTS20hgMcFQ_0 bicycle +HTTz78R4i0c_0 person +HTehrgCQAPo_0 person +HTgldgqci04_0 person +HUFGafskCjw_0 person +HULASsoz03U_0 person +HULASsoz03U_1 person +HUPxNiCgjn0_0 knife +HUfwe7j7IBE_0 person +HUgX2V1AkVw_0 person +HUiMyxUEC_A_0 person +HUv2tT_n5Bo_0 person +HUy4cHFX-04_0 person +HUz7znJTRNg_1 umbrella +HU_HuNQ4TDw_0 cow +HU_HuNQ4TDw_1 cow +HU_HuNQ4TDw_2 cow +HVEmUm86PBo_0 motorcycle +HVI1w93kCfo_0 person +HVOWKezX_bo_0 horse +HVOWKezX_bo_2 horse +HVYf36PFglw_0 dog +HVY9hWgMujc_1 truck +HVeqzrLyVtk_0 person +HVkFV2q27S0_1 person +HVkQkPaQbrw_0 person +HWAW-J3ZpIs_0 cow +HWA45moBwMo_0 horse +HWEI24n2tHY_0 person +HWItJuo6DSM_0 bus +HWXgDvYdlHE_1 person +HWZSmtWVH54_0 person +HWZenKFJqkY_0 person +HWZenKFJqkY_1 person +HWZenKFJqkY_2 person +HWfpkRSnZp8_0 train +HWfpkRSnZp8_2 train +HWjaeLf99dU_0 bear +HWr9Kqi0B2A_0 person +HWsTMfZok5E_0 person +HWtKIjJacjk_0 person +HWtyII4CMWg_0 car +HWtyII4CMWg_3 car +HW7FTNqTKhs_0 train +HW7yQK_j65g_0 horse +HXARJhNURSs_0 person +HXH_F5SX6FU_0 truck +HXH_F5SX6FU_3 truck +HXH_F5SX6FU_1 truck +HXKnqbEGfVw_0 bird +HXKnqbEGfVw_6 bird +HXKnqbEGfVw_1 bird +HXKnqbEGfVw_2 bird +HXKnqbEGfVw_3 bird +HXLA3nbxgh4_0 person +HXWoqdza4oA_0 dog +HXaAJtjX1mE_0 bicycle +HXaAJtjX1mE_2 bicycle +HXaAJtjX1mE_1 bicycle +HXa-0NlFTP4_0 person +HXcSrTLsF9c_0 train +HXhYYfE4uN8_0 person +HXvgiezvrYI_0 truck +HXx4tRTfGRM_1 dog +HX0kjr3XYHI_1 bear +HX7P1ipPByA_0 dog +HX-gTvdUaOE_2 motorcycle +HYLAdzbqvC0_0 person +HYWEWmMMrsU_0 cat +HYW3dAv02gE_0 cow +HYW6VucwAEg_0 person +HYXFGMzivds_10 truck +HYbuNzqXmyY_0 person +HYiN6skKjfY_0 knife +HYoonHvZXCc_0 motorcycle +HY1aAYxxlQo_0 person +HZC5bba_V4Y_0 knife +HZJ-JQkt590_1 bicycle +HZKExvpKLQ8_1 person +HZLdGfto2mI_0 car +HZSPPN3TMx8_0 bird +HZZadt4SIl0_0 dog +HZceU_BV2GM_0 person +HZceU_BV2GM_1 person +HZceU_BV2GM_2 person +HZd4rCCsNMs_0 skateboard +HZd4rCCsNMs_1 skateboard +HZd4rCCsNMs_2 skateboard +HZkmrVeoUV4_0 person +HZscUISrdww_0 person +HZ-tGW__JOI_0 cat +HaE1N8Q1b7s_1 train +HaMpIMApSi8_0 person +HaO3z-4gcBs_2 train +HaRliuOtm7s_1 person +HaiLotzzEXk_1 elephant +HaiLotzzEXk_2 elephant +HaiLotzzEXk_0 elephant +HarW34izH-M_1 person +HauA239AM7I_0 dog +HavxbX8tng0_0 person +HayoEz1x5Ks_0 person +HayoEz1x5Ks_1 person +Hay4Nx9S5-k_4 bicycle +Hay4Nx9S5-k_1 bicycle +Ha8XGRvxQxs_0 person +Ha_OuYxLXIs_0 person +Ha_w-xJsHAY_0 zebra +HbBCtCXKIEE_0 person +HbH7DpR0WUw_0 person +HbJufGCjdSE_1 person +HbKh31cncOI_0 bird +HbLoxqqdYsQ_0 cow +HbQu1mfGg4c_2 elephant +HbQu1mfGg4c_3 elephant +HbQu1mfGg4c_0 elephant +HbQu1mfGg4c_1 elephant +HbcyjRGbMBY_0 dog +HbcyjRGbMBY_1 dog +HbhmBauZqxE_0 horse +Hbq35QImz2w_0 person +Hbq35QImz2w_1 person +HbuCy2fsJk8_2 knife +HbyKQdGpxhA_0 boat +Hb3INTcuOVk_0 person +Hb5zCzD4J_E_1 train +Hb5zCzD4J_E_2 train +Hb5zCzD4J_E_3 train +Hb5zCzD4J_E_6 train +Hb5zCzD4J_E_7 train +Hb5zCzD4J_E_8 train +Hb5zCzD4J_E_11 train +HcBQXS22BDs_0 person +HcJTaK6Q9P8_0 person +HcXN4Pwnaeg_0 horse +Hcfxwdbwk8c_0 person +Hchet3FQwII_0 person +HcxL3_INS_0_0 person +Hc5ZM6UWTbY_0 person +f4OI46BYh08_0 skateboard +f4Oj9uMeFdI_0 elephant +f4PgAt4YpfE_0 cat +f4P-R7h_gTU_0 person +f4QyVWC6yrw_0 person +f4XkIcezAd8_0 person +f4XkIcezAd8_1 person +f4Y2tjwOV2k_0 cow +f4Y2tjwOV2k_1 cow +f4bys9o_Z2M_2 bird +f4s0cImpNBM_1 cow +f4xLPprxm30_4 knife +f49BXPlU-iI_0 knife +f4_Mfc9Ccg8_0 truck +f5BIXG_nLok_0 bus +f5HsrI3Codk_0 bird +f5J7yrE24eY_0 person +f5LuupUslCU_0 person +f5Q2iD7VUx8_0 skateboard +f5W37dv91tU_0 person +f5apNjAecEc_0 person +f5bVoAXze0Q_0 motorcycle +f5d1IXK1Tz0_0 bird +f5rzpIRd4wA_0 train +f5wHsLucnf8_0 person +f5zEWaDr1jg_0 cat +f50eMXA_-bM_1 person +f50eMXA_-bM_0 person +f53Jmsa7Jkc_0 person +f6AcbdJ77A4_1 train +f6E2ODGGF28_1 person +f6Px5vjTeRI_1 elephant +f6Px5vjTeRI_0 elephant +f6Px5vjTeRI_3 elephant +f6Px5vjTeRI_5 elephant +f6UBVcEIt3I_1 person +f6cXiuO-MvQ_1 truck +f6dVANLzPTY_0 person +f6dVANLzPTY_1 person +f6o6ukW_Qog_2 bear +f65c6sEDtkE_0 person +f7A6AOC8fOg_0 person +f7A6AOC8fOg_1 person +f7ExsvPto-E_1 motorcycle +f7Fs7-jGglk_1 bear +f7GJgMh9xt4_0 person +f7WvltLziTI_0 boat +f7cI-B4pJso_0 cow +f7kLnCuNTQo_0 cow +f7lmZQGcfBA_3 elephant +f7lmZQGcfBA_4 elephant +f7lmZQGcfBA_0 elephant +f7lmZQGcfBA_1 elephant +f7oBEoL94vw_0 person +f7pnt1rB9kI_0 person +f7x074oihas_0 person +f73BEqi2_DM_0 person +f7-S_iQAyKU_0 car +f7-htlH5qd4_0 bird +f7-htlH5qd4_2 bird +f8A1o9Nbs64_0 skateboard +f8BXIJnggCI_1 boat +f8BXIJnggCI_3 boat +f8BXIJnggCI_4 boat +f8Dp8Yvyr_0_0 person +f8PVrlhAIV4_0 person +f8T4DHNu6MY_1 truck +f8ZxXHSqC_8_0 boat +f8cW6kw6240_0 person +f8mzzGhPBaw_1 car +f8q3fKwf5PY_0 knife +f8yFyIwDCQ4_4 giraffe +f8zLCa1oGOE_0 horse +f8z83D9vGPo_2 knife +f80hjE6vabs_0 person +f80hjE6vabs_1 person +f84ypk41ULc_0 elephant +f9H0LrBLc9Y_0 person +f9H0LrBLc9Y_1 person +f9H0LrBLc9Y_3 person +f9H1bUagACA_0 horse +f9H6UaPUITk_0 cat +f9LOlCLfsJs_0 person +f9N4Jxt-kUs_1 knife +f9N4Jxt-kUs_2 knife +f9TCFTluRIc_1 bus +f9e12AC1jXM_0 bear +f9oWC3kSP1M_0 motorcycle +f9ovukmKaq4_1 person +f9sPt8HIN0w_1 skateboard +f9sj-0ZFV6E_0 person +f9sj-0ZFV6E_1 person +f9v2ONFCiwQ_0 person +f91XzUXz11U_0 person +f96d9EwxAB4_0 person +f9-IyW9tVLY_0 person +f-FxqFk0TdM_0 person +f-JXaNm7TBw_0 person +f-J7SQBHRN4_0 truck +f-Yei4idfG8_0 airplane +f-dhfS-geuI_1 elephant +f-dhfS-geuI_2 elephant +f-h9L-PN1ZM_1 bird +f-iLJUDdrD8_0 person +f-niuVrgiIc_1 person +f-rp_CghH-E_0 skateboard +f-s-4lM4qPA_0 truck +f-w51BH60RQ_0 person +f-1WVe76te0_0 cow +f-4EyKUawVo_0 bear +f-7ZEGsCz9U_0 person +f_GKi-DGmzM_0 person +f_Gf2hpt7y4_0 giraffe +f_GudF8uST0_0 person +f_NsA6enCZE_0 person +f_OOyDOAAOU_7 elephant +f_QhMhkyUSY_3 truck +f_QhMhkyUSY_1 truck +f_QhMhkyUSY_4 truck +f_Us8TvJMUQ_0 person +f_VwDCt9HTc_0 dog +f_WQIaZ5PjY_0 boat +f_bXOtZjzfo_0 person +f_b0IaRqtbs_0 person +f_jLGz53IpQ_0 person +f_jLGz53IpQ_1 person +f_mo54sXCc8_1 person +f_mo54sXCc8_0 person +f_rC1JIAMBU_0 person +f_wk-NOqceY_0 horse +f_yMF9tkk70_1 car +f_yvJuTzFHc_0 motorcycle +f_yvJuTzFHc_2 motorcycle +f_2I0S-EYu8_0 dog +f_3x9qJXCjA_0 person +f_49EFLQ02I_0 person +f_8S2hHC2rc_0 bicycle +f__fXHkVh5E_1 cow +gAKFUl9e_kg_0 person +gAQ92hISW6g_0 person +gARNWQDyaYM_0 boat +gAYbqApcfGs_0 person +gAdIZN7_0SM_1 airplane +gAeHmfC6t5s_0 cat +gAetQXcftXM_2 dog +gAnOylz1kDY_0 person +gAnmF0EFcB4_2 elephant +gAorjWC_59o_0 cat +gAo9Rsd6xwg_0 cow +gA2FDYNulg8_1 person +gA22uEcTAuY_1 dog +gA84cp5Keqk_0 horse +gA_a2Ajm7B8_1 horse +gBFsvbfVaLg_0 person +gBJgWZcXu9o_0 person +gBK7NwUcSoY_1 person +gBOpan7nm6M_0 horse +gBOpan7nm6M_1 horse +gBPipHCII3M_0 bus +gBRc8zqsL78_0 dog +gBUOzZPs_o4_2 person +gBUOzZPs_o4_0 person +gBYqrtFnN_Y_0 person +gBYqrtFnN_Y_2 person +gBeaBC0u9cQ_0 person +gBhKhiEJUCM_0 horse +gBiq_BH15FM_0 dog +gBoebgAjbVw_0 person +gBoebgAjbVw_1 person +gBs3hPLJTGs_1 horse +gBwCej92lKg_1 person +gB0wConR2VI_1 skateboard +gB2QHXkiiHs_2 elephant +gCDBnQV_G3c_0 cat +gCDBnQV_G3c_1 cat +gCGtBmntCiI_1 motorcycle +gCHegjuq0os_0 person +gCHegjuq0os_1 person +gCI1E3Hezdo_2 cow +gCI1E3Hezdo_1 cow +gCTp3CdMHCo_0 person +gCT0VAdPm98_0 cat +gCuOoA6aZ5U_0 cat +gC7K3OeQFHo_3 bird +gC7XtkA9y_Y_0 dog +gC-xUbdM-tU_0 person +gC-xUbdM-tU_1 person +gDAPPFBC9Gw_0 train +gDEpD9ek-O8_0 skateboard +gDGLrPPl_PU_0 cat +gDMsKJ61KPo_1 skateboard +gDOGAHsBM_o_0 person +gDTs0BOj8Fw_0 cat +gDU0hHsqtbU_3 knife +gDU0hHsqtbU_5 knife +gDU0hHsqtbU_0 knife +gDVGs8wTXCQ_0 cat +gDkDXOm8z5Q_1 cow +gDkDXOm8z5Q_0 cow +gDk-zDBsv7g_0 dog +gDnSIxaiPzk_0 person +gDn3-DCSgNg_0 train +gDsBFuJE6D8_2 dog +gDvOoWXI3yg_0 person +gD2GATPADlA_0 person +gD5_x_Bz1z4_0 person +gD5_x_Bz1z4_1 person +gED4_ImWufA_0 truck +gEE_GCrAqF0_0 person +gEJi9Jawk2A_0 person +gEOxDCDD97k_1 horse +gESEn7ZZELM_0 person +gESEn7ZZELM_1 person +gEai3uMvvFg_0 airplane +gEai3uMvvFg_3 airplane +gEai3uMvvFg_4 airplane +gEhLmQnM720_0 car +gEu4mV0DWRQ_0 person +gE0ZQD1rCy8_0 person +gE0mBxOEwRI_1 skateboard +gE0mBxOEwRI_3 skateboard +gE8ErAnVuzY_0 bird +gE8ErAnVuzY_2 bird +gE-GVN9ErhI_0 person +gFEnoylVci0_0 person +gFac0jUOjCE_0 horse +gFcIMdm4qtI_0 train +gFdHQTLSmnc_0 airplane +gFfVZSPVYmY_0 person +gFiSl9m-w0k_0 person +HdBc9ySq76E_1 bird +HdCyMGZFJhM_0 person +HdFYXjdN5_8_0 person +HdO2lmXvENQ_0 horse +HdR6VoZEwAU_0 cat +HdSXU0fhHbM_0 person +HdT_9pXdxuc_1 person +HdbZzqJGLo8_1 cow +HdcXcqUlgI4_0 skateboard +HdhKF0UWx4g_0 person +Hdh3nOzwVW8_0 person +HdjbDB8UvCY_0 person +Hdo3_NQiVKw_0 knife +Hd85XlwoOMc_0 person +Hd-wT5OTZDE_0 person +Hd-wT5OTZDE_1 person +HeIrGQnIMOE_0 dog +HeLNz5XJe08_0 person +HeTGT7JfvB0_0 person +HeUD1Hrzswg_0 bird +HeYNsU-PKJs_0 cow +HeYNsU-PKJs_1 cow +HedUVNznPK0_0 car +HedUVNznPK0_1 car +HeoyKd78htI_0 person +HeoyKd78htI_1 person +HewdFRJAXH4_0 person +He08dewEgbY_3 motorcycle +He08dewEgbY_0 motorcycle +He1OQxCPk_w_0 person +He5cucK-e48_0 person +He6bAMDkCss_0 elephant +HfDHvE46LYU_1 bird +HfDzCPRQ2nw_1 elephant +HfEXlJ0dOhU_0 person +HfEZYvYqq_Y_0 cow +HfHNi93ZHoo_3 cow +HfHNi93ZHoo_1 cow +HfOcLeLWchM_0 person +HfZ871F0xSo_0 cat +Hfnnbr4CeTg_3 bus +HfqI5BIpp0s_0 person +Hfq3_YJ7BpY_0 motorcycle +Hfq9JFmquE4_0 person +HfvJc2dxUR4_0 boat +Hf1Iyyz2DMY_0 person +Hf1Iyyz2DMY_1 person +Hf8JWsbSYYk_0 person +Hf8-8h45g-g_1 elephant +Hf8-8h45g-g_0 elephant +Hf8-8h45g-g_2 elephant +HgDimNCaxF0_1 bear +HgFCKM4ndEc_0 car +HgMYuCtsOwc_0 person +HgMYuCtsOwc_1 person +HgO57Npp9Yg_0 train +HgexaoNeZJk_0 person +HgiYmNrxUzg_1 person +HgkeptGXNt4_0 motorcycle +HglF9x-ORXU_0 person +Hgr5__oevds_0 person +Hg2vqnLAc8I_0 dog +Hg4DJ-x85Dw_1 elephant +Hg-R_RMIEN8_0 airplane +HhASNiFpJlw_0 truck +HhF6cAtp7Xs_0 knife +HhGGJNmwWHk_0 person +HhVSLU0A-wk_0 car +HhcMy4KZ9mY_0 skateboard +HhfSUB2LOTU_0 person +HhiUVwHWmwM_1 person +HhiUVwHWmwM_2 person +HhiUVwHWmwM_0 person +HhjGAeK-XWg_0 person +HhoRf1Ovlf8_0 person +Hhvq-cwBJgo_0 person +Hhwzl9x_m34_3 cow +HhxV27YhiqI_0 skateboard +Hh1xD0M0N8Q_0 person +Hh6x850teNQ_5 airplane +Hh6x850teNQ_7 airplane +Hh6x850teNQ_8 airplane +Hh6x850teNQ_9 airplane +Hh6x850teNQ_10 airplane +HiBUWbOyqcQ_0 person +HiGZ2EdJh2o_0 person +HiMItbtVHcY_0 cat +HiMItbtVHcY_1 cat +HiNt0G1AIO4_0 motorcycle +HiTE5nqzjBw_0 zebra +HiUz61ffgHA_0 person +HiZDjdREbmc_0 umbrella +Him7gJ7sArU_0 person +Him7gJ7sArU_1 person +HinGUsliCKc_0 truck +HirBTVnhNls_0 cow +Hi4ITByGP0Q_0 person +Hi4mzrYdRBQ_0 horse +Hi4mzrYdRBQ_2 horse +Hi4mzrYdRBQ_3 horse +Hi8Ey0o5mCQ_1 person +Hi-7ZtG_JWI_1 person +Hi_YHp3Jz48_0 cow +HjAtN_MbguE_0 person +HjLLTWwaCB8_0 horse +HjNfykX021M_0 person +HjNfykX021M_1 person +HjgdNiVfO9M_0 skateboard +HjlX9nu9Vf4_0 person +Hjo13y8dFy4_0 motorcycle +Hjt_y0CW-dY_0 person +Hjt_y0CW-dY_1 person +Hjxd2cno65M_0 skateboard +Hj0J8FVxBjg_2 person +Hj0J8FVxBjg_0 person +Hj0J8FVxBjg_1 person +HkApyQz8MTY_1 horse +HkQ4tzUFCUU_0 truck +HkW_wLkAKpg_0 person +Hke6h3Sv5bA_1 bicycle +HkzYNIDq0q4_0 train +Hk45sdCRh9g_1 bear +HlEkgK08UfY_1 person +HlTQbPXnzu8_0 dog +HlWsih27OmA_0 bird +HlaPVZM-53c_0 person +HlfpirtC6oQ_0 person +HlmuHGoCGAI_0 cow +HltyUzvtugM_1 bicycle +HlurUBv4bh0_1 giraffe +HlurUBv4bh0_3 giraffe +HlurUBv4bh0_4 giraffe +HlwSaYwFLRE_0 horse +Hl3qik9GRX4_0 person +Hl5MXwWiXWM_0 person +HmDDLtJcD5g_0 person +HmORePbYJkk_0 skateboard +HmPvsdwo_fY_0 dog +HmRm2phIiGo_1 bird +HmY8zwmIiac_0 cow +HmaGylwEFxw_0 person +HmbTCfB3Vkg_0 person +Hmk4dZnPtRY_0 bus +Hmn3xf-zqWI_0 person +HmqV_7hAxdw_0 person +Hmr0jbygomI_0 giraffe +HmwxDK0zo6U_0 person +Hmyj1zKgToA_0 person +Hm0kxS31F_U_0 person +Hm0kxS31F_U_1 person +HnNJeASG0-M_3 person +HnNJeASG0-M_4 person +HnNJeASG0-M_2 person +HnNzkYDhWks_1 person +HnNzkYDhWks_2 person +HnNzkYDhWks_0 person +HnP7iXcgg8g_0 truck +HnSHJ_iCdi4_3 truck +HnSHJ_iCdi4_1 truck +HnUrGKpAsOk_0 cat +HnbNOJpzYPE_0 person +HnjhdtM8qSI_0 skateboard +HnptRKjBUF0_2 boat +HnwYRWj3fk4_2 knife +HnxaJbaAiUI_0 person +HoH5exlgIxk_1 skateboard +HoLifxKZUpI_0 person +HoLifxKZUpI_2 person +HoLifxKZUpI_1 person +HoNs_4V1pNs_1 bear +HoNs_4V1pNs_4 bear +HoP_nMgAxAk_0 boat +HoeeRkyNozc_0 cow +Hon64st5_6g_0 train +Ho2ixBE8dzE_0 giraffe +Ho5TcUOlb3Q_0 motorcycle +Ho5o7aBqNAc_0 person +Ho6N0OgD-1M_0 person +HpBBda_pbf8_0 motorcycle +HpGr16tW9dk_1 person +HpQ90KkREGo_0 person +HpUPD5_WMYI_0 train +HpZ3IzUfsGg_3 bus +HpbQsLdUHN4_0 boat +HpjyvLHus3Y_1 skateboard +HpkTeQdQ03Q_0 skateboard +Hprw9lNWGGs_0 person +HptcjVcfzgY_0 cow +Hpwk73qvroU_1 elephant +HpzTTAS6Qt8_0 person +Hp0SQy5w9Q4_0 person +Hp-eaTbVfLY_1 bear +Hp-2Gb7Fwns_0 cow +HqxhhM71S2g_0 horse +Hq1KLztJBrE_0 person +Hq6tGHLzg4Q_0 person +Hq814Tfrblw_1 airplane +HrHPBJOnFgg_1 train +HrHPBJOnFgg_0 train +HrHPBJOnFgg_4 train +HrHPBJOnFgg_6 train +HrdVu5J3rZQ_0 person +Hr-keYNRBhA_0 train +HsLZwGFHYUg_1 horse +HsNcZZ6iwHQ_0 person +HsOiHc1moVk_0 person +HsOkCwZLv_w_0 bus +HsOkCwZLv_w_3 bus +HsOkCwZLv_w_1 bus +HsOkCwZLv_w_2 bus +HsR2xk4I1as_0 person +HsVKw_8AQtM_0 person +HsZgeesgCZQ_0 person +HsjVUPs3XB4_0 boat +HslbDMoiABY_0 car +Hslld67XdsY_0 person +HswufOfUGyk_0 truck +HsyscFWIPZs_0 bus +Hs0HRqYcYqA_0 car +Hs6bVSOu98U_0 dog +Hs_vQr20HdQ_0 skateboard +Hs_vQr20HdQ_3 skateboard +HtErHV_tZqs_0 elephant +HtIbfC8DDos_0 truck +HtNaGNO6nnc_0 person +HtRiNzzfakk_0 person +HtUPhgHKN9c_1 boat +Hth8t7jhKPs_4 horse +Hth8t7jhKPs_7 horse +Hth-I5KYVsI_0 cat +Ht054jKgWfE_0 person +Ht9C8ABsxrg_0 person +Ht_bczKGV-0_0 person +HuNIgJEUelo_0 person +HuNIgJEUelo_1 person +HuOzcY9ybpo_2 dog +HuVl7peYYF8_0 person +HuVoecmBgpM_2 bird +HuVoecmBgpM_1 bird +HuZPTuSe7Zw_0 person +Hue6Q5JKEKw_0 cow +Hun4T6fv3cs_0 person +HuqC6CX9uRA_1 person +Huyd-7WlWWU_0 person +Hu3xpcZqwRg_0 person +Hu9DGxLcg2c_0 person +Hu-VYy60p64_0 person +HvHJi-EkL8c_0 skateboard +HvIubGltpPY_0 dog +HvLq5xDKM6E_2 bicycle +HvP4rcOll6k_0 person +HvQGnFuiwtg_0 cat +HvTvaPx2hXw_1 train +HvhkLhJ4YFQ_0 person +HvuLPfhVT3s_0 person +HvyIg5RMLbU_1 person +HvyIg5RMLbU_0 person +HvyzpBvy40o_0 person +Hv5sH0eTE_M_0 dog +HwSP55CmiCk_0 person +HwS3weg4aQc_0 dog +HwS3weg4aQc_2 dog +HwY6kiQlICc_0 person +HwdEYJ2bZkg_0 airplane +HwdyzravQpY_0 cat +HwfLycybCD0_0 motorcycle +HwgmR0Qlm_I_0 person +HwipRH29Hr0_0 bus +Hwnqezsko-Q_0 person +Hwnqezsko-Q_1 person +HwxnH--ot8o_0 car +Hw0JhQaRYcA_0 cow +Hw2Bhz2SkUI_0 person +Hw2Bhz2SkUI_1 person +HxMniz8r1x4_0 person +HxP056QWsGY_0 person +HxP056QWsGY_1 person +HxaFZyog34E_0 person +HxaFZyog34E_1 person +HxgU1Dh8wMs_1 person +HxiBpvG82Ys_0 motorcycle +Hxq1wNRv5Yg_0 person +Hxv6y6I4mvE_0 horse +Hx19D3w4xGI_0 giraffe +Hx_Z9TOIV8U_0 motorcycle +HyJgfYNotwk_0 truck +HyUY7bqdm9Q_7 dog +HyUY7bqdm9Q_0 dog +HyVLne6RE-A_0 person +HyXjUWAQ970_0 skateboard +Hygs9OBUgg4_1 person +HyuQCu-z558_0 motorcycle +HywSTw3dtgs_0 person +HywSTw3dtgs_1 person +Hy4E2NZEc34_1 train +HzAOQnmw_bo_1 elephant +HzAOQnmw_bo_2 elephant +HzCClfShiwM_0 person +HzCClfShiwM_1 person +HzDzb9xxc6o_0 person +HzESeh3ZV4g_0 person +HzHWWeZEU6E_1 skateboard +HzJgpBBIk1o_0 cat +HzLm3QfIx9w_0 person +HzLm3QfIx9w_1 person +HzXBY-SJECY_0 horse +HzYY4-iAvrk_0 cow +HzdSxrJ2oBw_0 skateboard +HzkmlCJwvqo_0 horse +Hzlcc_lAGVo_2 skateboard +HzqIVSJNXAU_1 person +HztbwJhPXyk_0 person +Hz6I6jLi4NA_0 dog +Hz8qayZDGpU_0 person +H0Adt_c6kJo_2 elephant +H0EEB1bPOjE_0 person +H0VjOJvg49Q_0 bicycle +H0Ym6NE2ny8_0 cat +H0gWl9KRbHo_0 person +H0k2WZec6aA_1 train +H0k2WZec6aA_3 train +H0k2WZec6aA_4 train +H0k2WZec6aA_0 train +H0u061QsnHw_0 cat +H0yhw97jkkY_0 person +H0z8VqDW-vg_1 airplane +H01F2fhFpr0_0 elephant +H097WsXpask_0 person +H097WsXpask_1 person +H1C2ZZeeVs0_0 cow +H1Hd5Japfbc_3 train +H1Hd5Japfbc_0 train +H1Hd5Japfbc_1 train +H1Hd5Japfbc_2 train +H1JIvu1dbbk_0 person +H1JIvu1dbbk_1 person +H1MTfTrQrE0_1 person +H1d68B_jDjI_0 person +H1hg-0_AS9A_0 cow +H1xBJoYM7rE_4 truck +H1xBJoYM7rE_5 truck +H117IshzypA_0 knife +H144B0rpQh0_0 person +H144B0rpQh0_1 person +H1-_3CvKDzc_0 bird +H2Q-46IlKEc_5 truck +H2Q-46IlKEc_6 truck +H2RoEMwxEAk_1 person +H2TqEPsubdM_0 bear +H2iTxNLOK1Q_2 motorcycle +H2iTxNLOK1Q_0 motorcycle +H2iTxNLOK1Q_3 motorcycle +H2vkpfO2yqU_0 person +H22P5Z4GfkE_0 person +H29Xe5gG_-s_0 person +H3A2DSw_xNU_1 elephant +H3GcVWKTVd4_2 truck +H3NrFrjQlfc_0 person +H3exbzmmPQY_0 person +H3jC0oToDjU_2 person +H3jC0oToDjU_3 person +H3jC0oToDjU_0 person +H3o1VsopVFM_1 bicycle +H3o1VsopVFM_2 bicycle +H3pifBCagTI_0 person +H30IPtBzf_s_5 skateboard +H30ifg3HO_I_3 dog +H33IRr1Z3-w_1 train +H36UOsilz4M_0 person +H4Hp-UJYZ_g_0 bicycle +H4JiUp8EH3s_0 zebra +H4VZD26aqe8_0 skateboard +H4VZD26aqe8_1 skateboard +H4bN1hcXw9Q_1 person +H4dTHFeYa30_0 motorcycle +H4eE_LAeWXQ_0 person +H4eE_LAeWXQ_1 person +H4gxLA7vTo4_0 person +H4lBmXOi3Uc_0 dog +H40G2dsVha4_1 train +H41XJMKpfFM_0 bus +H42hQSjU97o_0 knife +H5NqMNaMEiM_0 bird +H5YO56LD_dY_0 elephant +H5YO56LD_dY_1 elephant +H5iHzuWmtDw_1 dog +H5sijKl_Xi4_0 cow +H50EXfjT2O0_2 airplane +H50EXfjT2O0_0 airplane +H50EXfjT2O0_1 airplane +H50-_mqAU14_1 cow +H55Ru4hgats_2 elephant +H55Ru4hgats_3 elephant +H6OhYxXS1So_0 cat +H6UwkC3sYic_0 cat +H6ZHYEOcjCI_0 bicycle +H6ZHYEOcjCI_1 bicycle +H6Z8sZ34ZGw_0 motorcycle +H6dXJIZnH-k_2 train +H63oHdGMBAs_0 bird +gFunUi36tVM_0 horse +gFunUi36tVM_1 horse +gFvhLM1k-IY_2 truck +gFwCuQBtZiU_1 umbrella +gF7IM-CiOdU_7 bicycle +gF7IM-CiOdU_0 bicycle +gGBEKYXUhbE_0 truck +gGMxVO2zmP4_9 bird +gGMxVO2zmP4_1 bird +gGMxVO2zmP4_2 bird +gGMxVO2zmP4_5 bird +gGMxVO2zmP4_8 bird +gGSCGkm00jM_1 bicycle +gGYN2hnw1SQ_1 elephant +gGdKtY4p1E0_0 airplane +gGt9CVOzJOI_3 knife +gGzaN_8PxZw_0 skateboard +gG8tfb-eSuo_0 train +gHC3HqRbW6g_0 elephant +gHF9PM2MVuw_1 train +gHvzU7dfBU8_0 giraffe +gHyK46CyQtA_0 cow +gH0LLPcn-H8_0 elephant +gIBZr7Mh05k_0 bird +gIMq_fnjtSM_0 cat +gISy0wedyW4_0 boat +gInHAdlbB60_1 skateboard +gIsXFCo7Nt4_1 dog +gIxuS1GwPPo_0 train +gJV63DGM7Ew_1 car +gJa0yNDBFio_3 person +gJa0yNDBFio_0 person +gJa0yNDBFio_2 cow +gJfD9eHnos4_1 elephant +gJn5fXk7dCs_0 airplane +gJuZGVWuQQ8_2 bicycle +gJ-k_oHkqYc_0 cat +gKHR68FmKE8_3 airplane +gKHR68FmKE8_0 airplane +gKHR68FmKE8_4 airplane +gKmF78OWCUc_0 motorcycle +gKqUwiPYSh8_0 motorcycle +gK7dud30V7k_0 giraffe +gK_K33gm3SA_1 motorcycle +gLQWgnWqQ1Y_0 bicycle +gLRU7lXCgNw_1 dog +gLRexWYaW_Q_0 skateboard +gLbADp0AlZU_0 bird +gLtnBhTBpkA_1 boat +gL3uBv5NWJU_1 bus +gL7JySv9H4I_0 bicycle +gMAW4Am5_pc_0 cow +gMBTewi9VZg_0 cow +gMCCgBzug_U_0 knife +gMFgEtqbTXs_0 boat +gMJuszEOURk_0 cat +gMMJH4UYboM_3 bus +gMXt8X-xC_g_0 dog +gMlNev_l4Yg_0 bus +gMlhd1gczF4_0 airplane +gMsGe7w79Hg_1 car +gM9tFNvc1xw_0 cow +gNDSQ2l9FYg_1 elephant +gNMkDmfkZ1E_0 motorcycle +gNcGXjn7g9o_0 skateboard +gNwKVPIi010_1 skateboard +gN2aKPpTpzQ_1 dog +gN7-cLfUlt8_4 giraffe +gN7-cLfUlt8_6 giraffe +gOOB0RZmnUA_0 cow +gORdlzUa3nQ_1 bird +gO48FZrUm88_0 skateboard +gO-8RNI2Puc_1 dog +gPhcXlQLLRU_0 horse +gPrWvEE7yjw_0 cat +gPteWZyyJeo_0 cow +gP3SQErTTOg_1 motorcycle +gQBW4py4GhY_0 skateboard +gQEGmIhhEQ4_0 train +gQEGmIhhEQ4_1 train +gQEGmIhhEQ4_2 train +gQFqppfDRRk_0 umbrella +gQLZ5H-n0Uk_4 knife +gQVlREJXkik_0 knife +gQWTTEHj5Hs_0 cat +gQeqE3dgZoM_3 airplane +gQe5gykuyi4_1 train +gQpWY94Fx5E_0 motorcycle +gQpuEhphXHk_0 car +gQpxfwrF7Sc_0 bus +gQ6AUvEXuaQ_0 bicycle +gQ9HhxeKI4A_0 motorcycle +gQ_SF2MtsUc_0 elephant +gRFcteFGpLM_0 skateboard +gRJGd_HzC-8_0 knife +gRJpf6JwJeU_1 giraffe +gRNKgw2D_mE_0 knife +gRVrvJioWZ8_1 train +gRoGrhv1ebI_0 elephant +gRsOR1tKh8U_0 truck +gR3ihf3rch0_0 car +gSXDTJjj1jk_0 train +gSi2fNTUsy8_0 horse +gSlT3ALqvTM_0 skateboard +gS0DTbVQ2x8_1 knife +gS25yLrNO98_0 bear +gS2-SAccVh0_0 skateboard +gS7U-6Z8M2g_1 knife +gS_9D3OWXAk_0 airplane +gTqgARR0BBQ_1 boat +gT27MQBhatA_0 skateboard +gUDoTzwZlso_0 dog +gUL0-NbHvuA_0 motorcycle +gUMLascwbtU_0 train +gUNCDmbzxq8_0 train +gUbc_OUTnOs_0 airplane +H7ONEeAkBFo_3 motorcycle +H7ONEeAkBFo_2 motorcycle +H7YUH_GBWdQ_0 train +H8B-3STVp6E_0 cat +H8LitQV6pNM_0 cat +H8SccYIiPs8_0 zebra +H8coORJpR80_1 skateboard +H8k1E1i7AvQ_0 knife +H9AQUC0N1zI_0 horse +H9JfwPhdCjg_0 boat +H9KjlXZYxJU_0 train +H9KjlXZYxJU_8 train +H9TUml4LflE_0 cow +H9UTvMwaoRg_0 cow +H9bbSssKl2o_14 umbrella +H9eutGBn3zw_0 motorcycle +H-C6EBylvh4_1 cat +H-IoiGsEU5Y_0 train +H-QKbNwtoH8_1 car +H-gh485Om10_0 bus +H-gh485Om10_1 bus +H-kkRVEs3Bg_0 motorcycle +H-uiufHSb3s_0 knife +H-uvqjsUCLc_0 dog +H-uvqjsUCLc_1 dog +H-5Ynjv0dQI_1 train +H-62b99sK_s_0 train +H-62b99sK_s_1 train +H_Ei1gRODpw_0 dog +H_KMZLSAxMw_0 train +H_iI201Iqws_1 truck +H_iYHl4pFuQ_0 horse +H_mRfG30Gzo_0 skateboard +H_1O-OBZ3BA_0 horse +H_6vxd3ckIY_0 cat +IADSsAb2KSo_1 umbrella +IADSsAb2KSo_2 umbrella +IAFApeJ5FvM_1 motorcycle +IAOiNYVeqzE_0 bird +IAaINtcnO7A_0 bicycle +IAcbsZcN_pM_1 motorcycle +IAkSntQ2Aso_0 horse +IAlz_evs7fU_3 car +IApV0rfD9oQ_0 dog +IAsXYmK1baI_0 motorcycle +IAwKojHnvtU_0 train +IBD9tJNb9_o_0 train +IBFp5y96q78_0 motorcycle +IBFp5y96q78_2 motorcycle +IBKLgBXZFzw_0 motorcycle +IBYJQU6-nGg_2 cow +IBYg-hMbb04_0 knife +IBm1C4qJtTg_5 umbrella +IBm1C4qJtTg_8 umbrella +ICQbVnaJL_0_0 bus +ICZ4tinBQZg_1 knife +ICZ4tinBQZg_2 knife +ICZ4tinBQZg_3 knife +ICg3W1-Prhk_0 elephant +ICnAWjPDzRw_0 cow +ICtLhp-qveM_0 boat +IDCBO7W7xpo_0 cow +IDNvFEra8mc_5 horse +IDNvFEra8mc_1 horse +IDNvFEra8mc_2 horse +IDNvFEra8mc_3 horse +IDNvFEra8mc_4 horse +IDO6jw3u3_w_1 airplane +IDcxChwEqDs_2 horse +IDeGA2EV3WY_0 airplane +IDeimFOIbVc_0 train +IDmwsXLZKUs_0 cow +ID1faW2L3rM_0 cat +IEOg-ZulFR0_1 bird +IEPYJyHfP2E_1 elephant +IEYC-aYAQ40_0 boat +IE5qZDd7tWw_0 elephant +IFGohfPURX4_0 person +IFfS7hatV0s_0 truck +IFkUMGE7bbc_1 elephant +IFkUMGE7bbc_0 elephant +IFrHlldbUdQ_0 cow +IFvO1O-6vqk_0 truck +IHQvg9gYLjw_0 dog +IHSCfRs-J38_2 skateboard +IHY0eeHfBcY_4 truck +IHjI35oW0T4_0 car +IHxX0fKU9iM_1 skateboard +IH3E7RS6Hn8_0 cat +IH9BmEg26Cw_0 person +IIBN7FGNNEs_1 train +IIBN7FGNNEs_2 train +IIBN7FGNNEs_3 train +IIBN7FGNNEs_4 train +IINTapIzzes_2 skateboard +IIw0KKAeBeQ_0 skateboard +II0JbbQq-Sg_1 bird +II61z65eDCY_2 cow +II61z65eDCY_0 cow +II94vSsb4Uc_0 car +II_okDlDaO0_0 cat +gUt0vA8_1Ow_0 airplane +gUvZ3RC9tEU_0 knife +gU3SNUS1_ng_0 bicycle +gU4mBoB-b7k_1 train +gVAp7rt84ic_2 bicycle +gVCrRXledlU_1 boat +gVCrRXledlU_0 boat +gVV-5JdLuXk_3 car +gVXzT_h1SFI_3 horse +gVXzT_h1SFI_4 horse +gVXzT_h1SFI_2 horse +gVaB7hwBhTA_0 cat +gVjL5txcFMI_0 knife +gVrTFXdPWJ8_0 elephant +gVxqk8tLXL8_0 truck +gV27xS9pqNQ_0 train +gV3Xmwy3RKo_6 train +gV3Xmwy3RKo_13 train +gV9A5NfFexQ_0 car +gWcacGgcxYU_4 bear +gWlmYVY4kW4_1 bicycle +gWnhQi-zfEE_0 skateboard +gWpNWuo7vio_2 elephant +gWpNWuo7vio_3 elephant +gWsOR7UiwDs_0 airplane +gWz5ZMzC58s_0 car +gXBIzdmmHbA_1 bird +gXEHUZgPCGg_4 bear +gXFmghAzaVg_1 motorcycle +gXGvO4k4xQY_0 truck +gXHsyuynhso_2 knife +gXW33K91X7c_0 bicycle +gXn0Y5X5MJE_1 zebra +gXn0Y5X5MJE_0 zebra +gXt0u16Y6ZY_0 boat +gY_Ey8Ps_ZE_0 cow +gZhsGXSn5bU_0 motorcycle +gZqGyIMgMbs_0 bicycle +gZxcxQBlx0s_0 cat +gZzmloffFW4_0 bus +gZ8kZt451Ww_3 horse +gZ92ZDty9wI_0 skateboard +gaCEAVQd1-M_1 bird +gaS7x3F3gpk_0 bicycle +gaS7x3F3gpk_1 bicycle +gaS7x3F3gpk_2 bicycle +gaS7x3F3gpk_3 bicycle +galykATgRC0_0 cow +gaqS-4IaQ5c_2 bus +gbA3ItatxL8_0 skateboard +gbE0vzWpHj0_1 knife +gbE0vzWpHj0_4 knife +gbGl_-TnPjk_0 bird +gbI95ZXEUz0_0 knife +gbTTJah5oMw_0 elephant +gbTTJah5oMw_2 elephant +gbgbqiiEKVs_0 giraffe +gcBaPcA_1_0_0 train +gcExbr9FO94_0 giraffe +gcJ7XqXHPwM_0 elephant +gcT_dy3neEk_8 bicycle +gcXhYL06Acs_5 bicycle +gcYBNx0fUg8_0 truck +gchz9HDvVDk_0 train +gc80cGOHyKM_0 knife +gdCpPYwBVlY_0 knife +gdEBkAYaDPw_1 elephant +gdELg0NrkdA_0 dog +gdvUXfsBMIk_0 train +gdzzJI7xjBg_0 train +gdzzJI7xjBg_1 train +gd2O-Z5dOIk_0 airplane +gd4r5aA8jeg_0 bird +gd4r5aA8jeg_1 bird +geBwGOC-lX4_0 train +geBwGOC-lX4_1 train +geBwGOC-lX4_2 train +geBwGOC-lX4_3 train +geQCe6Cq5MU_1 elephant +geQCe6Cq5MU_2 elephant +geWChvEotKU_0 train +gefGPLN-abw_0 person +gfGsOzQ7gto_0 bear +gfS7FJH6Vkk_0 bear +gfUC20NWtjU_0 motorcycle +gfVlQhN0BBU_0 bicycle +gfuVNdXffSs_0 airplane +gf1mvdt9kbI_0 horse +ggIyqAThI1g_0 bird +ggPHtWoCcKs_3 umbrella +ggTFLaNIJck_0 train +ggVLptkmsys_0 truck +ggpz03j1REI_0 bus +gg3sG7O2P-g_0 bus +ghEfyxUaVGs_1 cat +ghIGC_DOfuk_0 horse +ghqqgJWnVEU_0 knife +ghyp-SKVuC8_0 motorcycle +giVGzMF1Yo4_0 skateboard +giVGzMF1Yo4_1 skateboard +gipHWMPB-W4_3 bear +gipHWMPB-W4_1 bear +gitOEvGnoYk_0 airplane +gi9bnW7uLkE_0 cat +gjGlUXCT9A4_1 knife +gjK5A6cIEnw_0 dog +gjRhqzTAkWw_0 cow +IJFaomtLVDE_0 cat +IJNUwvacbKY_0 cow +IJVUMGoBSQs_4 cow +IJXVtb2GeJ4_0 train +IJdYiBYP31A_0 motorcycle +IJlBmhH72m4_1 cow +IJ6g4ZRBksE_0 cat +IKLj0LJIMKs_4 airplane +IKLj0LJIMKs_5 airplane +IKLj0LJIMKs_2 airplane +IKftyV_zwkE_0 skateboard +IKqmWAu3GF0_0 dog +IK7Mnvty4VY_0 person +IK8IJWsxg3M_5 airplane +IK8IJWsxg3M_6 airplane +ILAGhYr9yts_1 motorcycle +ILLYlwlFTzA_0 elephant +ILmTjHZqkCo_1 truck +ILqxie6aqXg_0 bicycle +ILqxie6aqXg_1 bicycle +ILqxie6aqXg_2 bicycle +IL1HokSKOyY_0 cat +IL9r35lU8So_0 skateboard +IMD3U_DzO3E_0 motorcycle +IMD3U_DzO3E_1 motorcycle +IMde-053G78_0 horse +IMulJdQXZvM_0 train +IM7vwh5qua4_0 cow +IM8dlwNTjXU_0 cow +IM8v82x7ovA_2 train +IM8v82x7ovA_1 train +INFs2lfikXE_1 knife +INULdzdrdys_0 horse +INXkuJ9WvIU_0 train +INZhGblywrk_0 bus +INkhg9y4asY_0 bear +INtj4nfjRA0_1 bear +IN2TGHJrQEg_2 skateboard +IN2TGHJrQEg_0 skateboard +IN2TGHJrQEg_1 skateboard +IOPYEZzmeqg_0 car +IOPYEZzmeqg_1 car +IOQuWawPM3k_0 bird +IOfUvlEkN7g_0 bus +IOiqrNof90k_1 knife +IO3Z-ebx_f8_5 bus +IPI2_GXx1tI_0 bird +IPWixEFBDOY_0 horse +IPfYf-nFKic_0 airplane +IPfYf-nFKic_1 airplane +IP1CH8MMir0_0 knife +IQOfCy4FW8w_0 skateboard +IQXAYnslAnc_0 car +IQoVuUTZILY_0 airplane +IQsV_hTCyMA_1 bicycle +IQwk7Ge6Apk_0 truck +IRK6-ixyaVI_0 elephant +IRSbjN-mnJI_0 skateboard +IRZBnQJoKiU_0 skateboard +IRztQZ4bigY_0 car +IR9A3u83crI_4 elephant +IR-PGdIPgcE_0 skateboard +ISAnMprDgCk_0 skateboard +ISJW4GuahWg_2 dog +ISSTEs8xDWk_0 umbrella +ISYwpUKxHJU_1 elephant +ISYwpUKxHJU_2 elephant +ISYwpUKxHJU_0 elephant +ISud5E9hZxU_0 train +ISud5E9hZxU_1 train +IS9s3kJzTcA_0 airplane +ITCcMWC_RW8_0 umbrella +ITbwhPVxFv0_0 umbrella +ITrisbHlaJw_1 truck +ITzBy7T7_fI_1 umbrella +IT6TArZww6A_0 cat +IT8VqGbdH_A_0 horse +IT_zQ44PPOo_0 dog +IUH4PYmObvU_0 dog +IUO1sDZgGHs_0 bird +IUdyfRMOyX8_0 elephant +IUdyfRMOyX8_8 elephant +IUdyfRMOyX8_1 elephant +IUdyfRMOyX8_2 elephant +IUdyfRMOyX8_3 elephant +IUdyfRMOyX8_4 elephant +IUdyfRMOyX8_5 elephant +IUdyfRMOyX8_6 elephant +IUdyfRMOyX8_7 elephant +IUf7a2WuoBw_0 train +IUgkMOA3siY_1 bus +IUlDlS2KD-k_0 bicycle +IUlDlS2KD-k_1 bicycle +IUzpvnXep7M_0 bear +IU7x7I53cng_0 elephant +IVFq204Rr9c_0 airplane +IVHx3I13xdQ_0 boat +IVSJSu0PlsI_0 train +IVVFeaTw6IE_0 bicycle +IVjCZS2Fo7k_0 bird +IVpmCnL5cE8_1 giraffe +IVrBPzhFMi8_1 motorcycle +IVrBPzhFMi8_2 motorcycle +IVzxeeJEtiY_1 bear +IV6EMw4XYco_0 skateboard +IV6EMw4XYco_1 skateboard +IWCZ1PDW99k_0 motorcycle +IWVIIKxipc8_0 motorcycle +IWVIIKxipc8_1 motorcycle +IWn16DCfLbc_1 knife +IWumeAEXWVo_1 boat +IWu47p4l06Y_5 umbrella +IWu47p4l06Y_6 umbrella +IWu47p4l06Y_3 umbrella +IWu47p4l06Y_4 umbrella +IW1cFMDjPUk_0 bear +IW2mFJ8iw6Y_0 bird +IW4ZnmQeNtA_1 elephant +IW4g0kfA3GE_0 truck +IW5Vgh3SE-I_4 elephant +IW7TwQ-hY7I_0 motorcycle +IW7TwQ-hY7I_1 motorcycle +IXTgztKfRQU_0 skateboard +IXVCCLG3_cw_0 bird +IXyV2vpIEA8_0 dog +IXyV2vpIEA8_2 dog +gja4H3sGrqQ_0 car +gjdlZhmnGbk_0 airplane +gjfdI7hO92E_0 bird +gjquLAxFRWw_2 umbrella +gjx4xu1TyWU_1 cow +gj7W2zjQApw_3 knife +gkEoTLpAw7g_0 airplane +gkLRnt1OCH4_7 horse +gkRqNmGQbPI_0 skateboard +gkXKCuc0Moc_0 skateboard +gkXKCuc0Moc_1 skateboard +gkb4Ya5QW9M_0 bird +gkb4Ya5QW9M_1 bird +gkf0Bcsuhlc_1 car +gkf0Bcsuhlc_3 car +gkf0Bcsuhlc_4 car +gkiUpdrObXo_1 elephant +gkz49y5qcvc_0 horse +gkz-LCZcGtc_5 bird +gk1x_qYyDl4_0 cat +glNWqIolkq8_0 skateboard +glOskJOtnTU_0 knife +glOskJOtnTU_2 knife +glSdaND81E8_0 person +gltHxIp_ma8_0 bird +gmCT9tUPTB4_1 giraffe +gmdxOMQMgnw_0 airplane +gmnvPoB2cNY_0 motorcycle +gm53_sbr85Q_1 bird +gm53_sbr85Q_2 bird +gm9M-m4mCZ4_0 car +gm9M-m4mCZ4_2 car +gnA9QVNkmTU_1 knife +gnD6mU9A2oo_0 elephant +gnEttGTQqQ4_1 train +gnEttGTQqQ4_0 train +gnF9YJM1jaE_1 cow +gnGvXHS4UDs_0 airplane +gnM9SRiFh7M_0 truck +gnM9SRiFh7M_1 truck +gnPrHGB85WY_0 bus +gnTj3krZROI_4 boat +gnVo44q-XDI_0 knife +gnb1N_MLdcY_2 elephant +gnwCzU63_YY_0 person +gn2XuCFK-hE_0 truck +gn2bME2rmGw_0 truck +goIfg0C9kmM_0 dog +goOIZE0j6DM_0 bicycle +goSyNORcJ00_0 airplane +gok9kHQ77dY_0 skateboard +gollBTymf8I_1 bus +gomnpeJd5zw_0 boat +gonzAOezSOQ_1 train +gonzAOezSOQ_2 train +gosq350N9dI_2 skateboard +goyIWrU1Lbo_0 cat +gpBoXY6MM5E_0 dog +gpEiPRMcPwo_4 bear +gpY-o8xPA3w_0 bicycle +gpa4WfWCLa0_1 elephant +gpa4WfWCLa0_0 elephant +gpa9p4XNeKc_3 bear +gpbdiDEPd-s_0 skateboard +gpjqG97-SyQ_0 horse +gpmdLMUX53k_0 bear +gp2SDJHMADo_3 horse +gp2SDJHMADo_0 horse +gp2SDJHMADo_2 horse +gp9q0jvTKo0_0 bird +gqNgT7LxZSQ_1 bus +gqOfm9XTr6M_3 airplane +gqOfm9XTr6M_0 airplane +gqOfm9XTr6M_1 airplane +gqOfm9XTr6M_2 airplane +gqbDkeOx0mA_0 motorcycle +gqgQpw4DWZA_0 giraffe +gqhweewmNn8_0 skateboard +gqkLzCkKKtE_0 skateboard +gqucExXpPys_0 car +gqxvRzuWcrI_0 bird +grBVFo1wSjs_1 bird +grFPTYaKb7Q_0 bus +grI0uf6IwBw_0 bear +grNkPqf-ySE_0 dog +grWw42izM6M_1 train +grWw42izM6M_2 train +grWw42izM6M_0 train +grbP7mKMX_A_5 airplane +grbP7mKMX_A_1 airplane +grbP7mKMX_A_4 airplane +grdEE264TwM_0 motorcycle +grdIYaNewv0_0 motorcycle +grhIgcHgpOw_0 bus +gsCvhqZCWX0_0 dog +gsUrGSN-k00_0 horse +gsbJ13WiSvE_1 horse +gsfIYIQ1siA_0 skateboard +gsvn88OsH_8_3 knife +gsv7RJk7dtY_0 dog +gs_C12A8Wq4_1 bicycle +gtFIMtVrAGk_0 bicycle +gtNJSexRjxE_0 car +gtNdVTTd0tg_0 bicycle +gtNdVTTd0tg_2 bicycle +gtOa6rSatLA_0 cow +gtQ_uFTKEck_1 horse +gtii5vwjSTY_1 dog +gtuj1cOmYSs_1 train +gtuj1cOmYSs_3 train +gtz5ClHTSVo_0 cat +gtz5ClHTSVo_1 cat +gt_WHCkauOA_1 knife +guVl_gp0sJE_0 bus +gugP5f2JRJ0_1 bear +gugP5f2JRJ0_0 bear +guh1OUkdIGE_0 horse +guktzkv1els_0 boat +guv5reh2NH4_0 boat +guxRXiegac0_4 bird +gvNxDnFriAI_0 skateboard +gvcioONBIcE_0 train +gviQTbs7dIk_1 bird +gvjcggbLXRo_0 elephant +gvjcggbLXRo_1 elephant +gvjcggbLXRo_2 elephant +gvk0hzlYu9E_0 umbrella +gvraCN0RYko_0 dog +gvtY3fwbgdc_0 cow +gvuBfR3HXac_0 elephant +gv4sQFTuJ-k_0 elephant +gv7qY66lOhs_0 giraffe +gv8pF9t1zYM_0 elephant +gwKq56_M6Kc_0 horse +gwN_p_IRuoo_0 horse +gwP-6gOPn2c_0 motorcycle +gwTc-69C_P4_0 knife +gwTyjJwBgRk_0 horse +gwy7eePYryM_1 boat +gw9MjutMhLs_1 airplane +gw9MjutMhLs_3 airplane +gw9MjutMhLs_0 airplane +gw9MjutMhLs_2 airplane +gxKnyBP8_cs_0 elephant +gxejG9D0guY_1 person +gxgZg6BU3ds_0 dog +gxgZg6BU3ds_1 dog +IX4HjI_9vLY_2 dog +IX4IwgbTdCk_0 dog +IYBF45M9nTc_0 skateboard +IYBzvotFEYo_0 motorcycle +IYZZ-K_Ygpo_0 bicycle +IYdXz1cOCWc_0 giraffe +IYukRQKxhFI_0 person +IYukRQKxhFI_1 motorcycle +IZESZPVT0zk_3 bear +IZGady38Nh8_0 bird +IZIPpBl_h0Q_5 truck +IZIPpBl_h0Q_0 truck +IZIPpBl_h0Q_6 truck +IZJ1PO3Fkuw_0 umbrella +IZLMXYU4A-0_0 airplane +IZLMXYU4A-0_2 airplane +IZTfd31H0AI_0 bicycle +IZUO1x0QT1I_1 elephant +IZ2nFUgP-Pw_1 elephant +IZ2nFUgP-Pw_5 elephant +IZ2nFUgP-Pw_6 elephant +IZ2nFUgP-Pw_3 elephant +IZ2nFUgP-Pw_4 elephant +IaAPZOFgclo_1 elephant +IaG7siKVlak_0 giraffe +IaxZJVx5ptw_0 truck +IaxZJVx5ptw_1 truck +IaxZJVx5ptw_2 truck +IaxZJVx5ptw_3 truck +Ia0DjYXcBWc_8 elephant +Ia0DjYXcBWc_4 elephant +Ia0DjYXcBWc_5 elephant +Ia0DjYXcBWc_6 elephant +Ia0DjYXcBWc_9 elephant +Ia0DjYXcBWc_10 elephant +Ia0DjYXcBWc_11 elephant +Ia0DjYXcBWc_12 elephant +Ia0DjYXcBWc_13 elephant +Ia0DjYXcBWc_14 elephant +Ia0DjYXcBWc_16 elephant +Ia0DjYXcBWc_18 elephant +Ia0DjYXcBWc_19 elephant +IbEpwiOUFEI_0 dog +Ib15GlTvqTQ_2 skateboard +Ib2u6u-j2vk_0 skateboard +IcEs4vbIcDM_0 umbrella +IcSumCpVOy0_0 skateboard +IcZ2D-MawSg_0 truck +IciJuq7ZY6o_0 elephant +IckUkdfRndY_1 knife +Ic1cufihs-0_0 elephant +Ic1cufihs-0_1 elephant +IdSlvHXTrmE_1 skateboard +IdXPNOQD97w_0 motorcycle +IdabN3kTjSk_0 skateboard +IdrTVVio1U4_0 dog +IdvQme2elLk_1 truck +IdvQme2elLk_2 truck +IdvQme2elLk_3 truck +Id6HsaEvZ0k_0 person +IeB4Nf3h7T4_0 bus +IeENvG3Qtk0_5 elephant +IeFUkGY1b4Y_4 elephant +IeXb8CHr4ms_0 train +IefPtlA5ebA_0 motorcycle +IehTemq8EYc_27 bicycle +IehTemq8EYc_28 bicycle +IehTemq8EYc_0 bicycle +IehTemq8EYc_6 bicycle +IehTemq8EYc_11 bicycle +IehTemq8EYc_15 bicycle +IehTemq8EYc_17 bicycle +IehTemq8EYc_19 bicycle +Iejh8w6egIA_0 umbrella +Iek9nAfsymA_0 bus +IewJcdqOzCY_0 train +IewJcdqOzCY_1 train +Ie4Ct_HRDNw_1 dog +Ie5lfGQndBs_0 airplane +Ie8dc7EO7VI_0 bicycle +Ie8dc7EO7VI_1 bicycle +Ie8dc7EO7VI_2 bicycle +IfBft2ltqqE_0 skateboard +IfBft2ltqqE_1 skateboard +IfFnkz6EUno_1 horse +IfGZXa16ZnQ_0 knife +IfTrYE-Ox50_0 cat +IfZDLHBP_qk_0 bus +Ifpbe7xlKp4_0 truck +If4WPZY4LIY_0 elephant +If8EotoXQVQ_1 truck +IgO9_kN8D5I_0 cat +IgRs6nmhv2w_0 cat +Ige9Idj8fDw_3 cow +Ige9Idj8fDw_2 cow +Ig0Luv6UlkE_1 bicycle +Ig1JdzucmLI_0 boat +Ig9jZPM0n2A_0 car +IhR6ePM1wRw_0 bird +IhXAXy3VAqA_0 cat +IhdGvFfk3Ks_0 bird +IhlRPxknT9E_1 motorcycle +Ihp3YZGcRjM_0 horse +Ihp3YZGcRjM_1 horse +Ihsr3gT-u00_0 cow +IiBzrow5m9w_0 cat +IiH0f7VOXTY_4 airplane +IiH0f7VOXTY_2 airplane +IiH0f7VOXTY_3 airplane +Iie6uM_sdLE_2 truck +Iie6uM_sdLE_5 truck +IiscR53FEz0_1 airplane +Iiy_W2tIOWI_0 boat +Ii9URMIXJjc_0 dog +IjHqTBt-tzY_0 horse +IjMLYR0bH6g_0 cow +Ijf2ZMTxDUs_0 cow +Ij57BoIbMws_0 train +IkOG3ZnCvY4_0 cow +IkVifrtYlcI_0 skateboard +Iklc7ijgOtA_0 horse +Ikl-nlqwUJA_2 train +IkqFTjEXf4g_0 motorcycle +IkrKcORoFLI_0 cat +Ik4UxtlIrw0_5 airplane +Ik4UxtlIrw0_13 airplane +IlJT6oek8KQ_0 dog +IlNV-gFlp3Q_0 umbrella +IlshSY2CGU0_0 cow +Il1TKTSRPO4_0 train +Il7GtfxmBlQ_0 skateboard +ImCV4d0kYxY_0 skateboard +ImEKl15Aipo_2 bear +ImOLHl6gwLE_0 giraffe +ImO7oG_YuSU_0 train +gyBWGyhFuWg_0 elephant +gyBWGyhFuWg_1 elephant +gyBWGyhFuWg_2 elephant +gyBWGyhFuWg_4 elephant +gyBWGyhFuWg_7 elephant +gybSfaDRdVA_2 airplane +gy3zF39Y7B8_0 airplane +gzQrsNwx8MQ_1 truck +gzTHA0tMocM_0 bird +gzUj7KfvRPY_0 train +gzVdw-5l3sY_5 bear +gzWwT4ufwFY_0 bicycle +gzwzd6nOPoI_3 bear +gz13nfjIblU_0 skateboard +g0Jq0uIY3i0_2 knife +g0LufqNJtss_1 elephant +g0LufqNJtss_2 elephant +g0SdZmm5Mm0_0 horse +g0W6U-p-T2c_0 horse +g0om0nrfC4w_5 airplane +g0om0nrfC4w_1 airplane +g0tXovGqqSE_0 cow +g0zcJWO1MbU_1 airplane +g02OQmAgfo4_0 train +g02OQmAgfo4_1 train +g04xUjb4z0w_0 bicycle +g05TJKB5TL0_0 elephant +g05TJKB5TL0_1 elephant +g05TJKB5TL0_2 elephant +g1HtoWJ3NjA_0 airplane +g1UUBEfyzJ4_0 horse +g1UUBEfyzJ4_1 horse +g1ZtaoEqtjI_0 bus +g1j_9A4-PL4_0 cow +g1n74kWqKFM_0 truck +g1vq3JO3eH0_0 skateboard +g12DCVqfKjM_0 airplane +g13JzTyNCPY_0 truck +g17hrSF1YN8_1 bear +g2Hh_97o7jY_0 person +g2KeNy_WECo_0 bus +g2MUK80Ht8k_0 horse +g2MUK80Ht8k_1 horse +g2MUK80Ht8k_2 horse +g2MUK80Ht8k_3 horse +g2MUK80Ht8k_4 horse +g2cCr0rRIeo_0 motorcycle +g2vRpfpQuNE_1 motorcycle +g2-SNBvYdNc_3 car +g2-SNBvYdNc_2 car +g3DAFznLlXw_0 elephant +g3e6vDSvpN4_0 skateboard +g3g7M2Xv3JY_0 zebra +g3ytRwjgoMI_2 horse +g3ytRwjgoMI_3 horse +g30xOR9j3_A_0 skateboard +g30xOR9j3_A_1 skateboard +g38MDXW9ndc_0 elephant +g4BX8_C-NeQ_1 dog +g4KzjuhixSo_0 motorcycle +g4KzjuhixSo_1 motorcycle +g4R5jZXlnl4_0 truck +g5OKbEXlegI_0 cow +g5SIvfoi7tE_2 bird +g5S-76eh6vs_0 car +g5ztjA03q5k_0 horse +g55_MKVNAE8_0 motorcycle +g57hZ17etp8_0 skateboard +g5-55T7AzUE_1 skateboard +g7Qk-cV3IFs_1 car +g7YvJasRFj0_0 skateboard +g7fZhFRdYJs_3 zebra +g7oMLF6ZfT8_0 horse +g7oMLF6ZfT8_1 horse +g8aScpqmhVU_0 umbrella +g8iDSRkz_go_1 boat +g80ZYUNhRME_1 dog +g9Am-b3OqbI_0 truck +g9RM9VSJPIY_0 knife +g9WrMIn5AkI_0 skateboard +g9sD-4RBa3Y_0 motorcycle +g9uOEJm7wdw_0 elephant +g9yESRreg5k_0 boat +g9zLmd4IZ78_0 bus +g91mK1sMiSI_1 elephant +g9-6tclIBcc_0 motorcycle +g-Dfzs3HQ8w_0 boat +g-EVS_QxLxA_0 horse +g-F4Eig_Rxc_0 motorcycle +g-F4Eig_Rxc_2 motorcycle +g-F4Eig_Rxc_1 motorcycle +g-JTM0dCFFA_0 cow +g-SJXmYYHqI_0 truck +g-SlOveVnAs_0 cow +g-Z7CA3qr1A_0 skateboard +g_B2r70EsjY_2 horse +g_XW0YLzND0_0 motorcycle +g_XW0YLzND0_1 motorcycle +g_XW0YLzND0_2 motorcycle +g_dN59QhubM_0 person +g_jq8Uy4P2s_0 truck +hAHsYyTOJoI_0 cow +hAIBcR5MAVE_0 boat +hAUD4Cy2GiM_0 cow +hAUD4Cy2GiM_6 cow +hAUD4Cy2GiM_1 cow +hAUD4Cy2GiM_3 cow +hAUD4Cy2GiM_4 cow +hAUD4Cy2GiM_5 cow +hAVbFSsRfOY_0 airplane +hAcx9u12Rd0_1 cat +ImZcOQCdJng_0 skateboard +ImiKNikVSsM_0 horse +ImqKWexMOEA_0 bird +Imuhe4E1pxo_0 car +Imy4SpqoC4k_0 cat +Im3ooIguQHk_4 train +Im3ooIguQHk_5 train +Im3ooIguQHk_6 train +Im3ooIguQHk_0 train +InEZSi4Zz08_4 train +InEZSi4Zz08_1 train +InEZSi4Zz08_2 train +InTq6s23Ygc_0 cat +Inn1lo0hbX0_0 train +Invv-JPzV-0_0 elephant +In_dBFPRoso_1 airplane +IobdPoAtEB0_0 bear +IoqRCAQzibw_1 skateboard +IoqRrAswOwY_5 bear +IoqRrAswOwY_4 bear +Io5wOOkpkdE_0 skateboard +IpOFHasyloc_0 cat +IpQQ9QabgiU_0 bear +IpVCKTRou10_1 truck +IpVCKTRou10_3 truck +IpVCKTRou10_4 truck +IpYZmcVrqdQ_0 cow +IpnTUQCHioc_0 giraffe +Ip0c_3xCHRA_2 horse +Ip-N_PYIqhA_0 motorcycle +Iqv9963BN8w_0 cat +IrAxUS0aBTQ_0 bird +IrDY9nE1V2I_1 motorcycle +Ir4CkmTmSXQ_0 cow +IsSCjgdAQiE_0 dog +IslqPZDUBHI_0 motorcycle +IssSzh7Z-vo_0 umbrella +IsxRqs7KcbQ_0 cat +Is2E8gFNBWo_4 bear +Is2E8gFNBWo_1 bear +ItL-C-szpU8_0 truck +ItiAXqRQm3A_1 knife +ItkxwET4PNc_0 dog +ItzhXkBVmEY_0 car +ItzlBA8cl3c_2 airplane +It_dJluX63g_0 cat +IuN_risviek_0 giraffe +IuZ6JD-k2nM_0 dog +Iuk4W5KJbQ8_0 bus +IuwJz5d-8J4_0 umbrella +Iuw0f-Y8t6I_0 airplane +Iuw0f-Y8t6I_1 airplane +Iu26NyEUoGY_2 boat +Iu5GqI9oVnk_0 motorcycle +IvJLhgaveaw_0 skateboard +IvMiQ2e-5hQ_0 bus +IvMiQ2e-5hQ_1 bus +IvX1MeQN-e0_0 cat +IvZSk33MtAc_0 motorcycle +IvZqPTK9DEQ_0 motorcycle +IvZqPTK9DEQ_4 motorcycle +IvZqPTK9DEQ_3 motorcycle +IvfWyYn_ifg_0 elephant +IvjNeTpV6hs_0 horse +IvyftS2bPuo_10 airplane +IvyftS2bPuo_0 airplane +IvyftS2bPuo_2 airplane +IvyftS2bPuo_6 airplane +IvyftS2bPuo_7 airplane +IvyftS2bPuo_9 airplane +IwcC1J_ImAs_0 car +Iwd7i4kvS5c_0 car +IwfpNUPSvpw_0 motorcycle +IwgX5DfmIQo_0 bicycle +Iwhf27USDD4_0 motorcycle +IwmwVP_e5Ag_0 bus +IwxmbUX4fcg_0 cow +Iw6-0LYvEmQ_0 bird +Iw6-0LYvEmQ_1 bird +Iw7zBsW9W5Y_0 train +IxLbLqfxrhg_1 boat +IxNA0hdkWGg_0 cow +IxObyCZ6OfY_4 giraffe +Ix8eS24W75g_4 airplane +Ix8eS24W75g_5 airplane +Ix8eS24W75g_0 airplane +Ix8eS24W75g_1 airplane +Ix8eS24W75g_2 airplane +Ix8eS24W75g_3 airplane +IyNmzxdv8-Q_0 bird +IyQlh0wdd9I_8 boat +IyQlh0wdd9I_7 boat +IyU3NizvZuM_0 horse +IyU3NizvZuM_5 horse +Iyj9D6cwI5o_0 bicycle +Iyk9-k1RP-M_0 car +Iyk9-k1RP-M_1 car +Iyk9-k1RP-M_2 car +Iys_rL0bPcc_4 boat +Iy4SrujSLuQ_1 elephant +Iy4SrujSLuQ_5 elephant +Iy4SrujSLuQ_6 elephant +Iy4SrujSLuQ_3 elephant +IzC8vjFriRE_0 horse +IzPS29ghTxo_0 knife +IzQjjBqimYw_5 elephant +IzQjjBqimYw_10 elephant +IzQjjBqimYw_11 elephant +IzQjjBqimYw_0 elephant +IzQjjBqimYw_1 elephant +IzQjjBqimYw_2 elephant +IzQjjBqimYw_3 elephant +IzQjjBqimYw_4 elephant +IzQjjBqimYw_6 elephant +IzQjjBqimYw_7 elephant +IzQjjBqimYw_9 elephant +Iz4_9EtiVXc_0 motorcycle +Iz8cco4VLow_0 cow +Iz8gKIZcfqo_0 bear +Iz8uzZuBiXs_0 bird +I0eY-kKi2FM_0 umbrella +I0iEaW1Qg_o_1 bear +I0oVkr613Rw_0 skateboard +I0voLEPKkG8_0 horse +I0voLEPKkG8_1 horse +I0voLEPKkG8_2 horse +I0voLEPKkG8_3 horse +I0voLEPKkG8_4 horse +hAplCSSZqAs_0 airplane +hAplCSSZqAs_1 airplane +hAteY2rkmVg_8 bus +hAteY2rkmVg_1 bus +hAuFEp75jVo_0 train +hAzefhyFMN4_0 truck +hAzsdnh5Iq8_0 elephant +hA_YzyjSVZM_0 bicycle +hBDc0K6CvHg_0 bus +hBDvdp2RCCw_1 airplane +hBDvdp2RCCw_2 airplane +hBDvdp2RCCw_3 airplane +hBDvdp2RCCw_5 airplane +hBDvdp2RCCw_7 airplane +hBKuHV_S8lM_0 skateboard +hBOhA_sljfE_0 umbrella +hBcYx5Uc-vw_0 car +hBcZZeXsCaw_0 bicycle +hBgxILtRUIc_0 cat +hB23PCerELA_0 skateboard +hB-M9w3C_Tw_0 boat +hCB731pKdcg_1 train +hChqLLLAmF4_1 bird +hChqLLLAmF4_0 bird +hCkn4pJxSkk_0 bear +hCrrYhe3x9Q_0 train +hCsCAXkiQ4Y_2 train +hCynNRrrTKI_0 cow +hC5Wac-AzgM_1 elephant +hC5Wac-AzgM_2 elephant +hC5Wac-AzgM_3 elephant +hC5augWtBcQ_1 bicycle +hDAv3aPvZjc_1 truck +hDLAKS4hCfc_0 car +hDM4sCvlRoA_1 airplane +hDVx_yYysaA_0 cow +hDXpSU7bq44_0 bicycle +hDYV-Vz3xwA_1 dog +hEAQZIsaIew_1 train +hERCXzHI2nA_1 elephant +hERyFpl4aDk_0 dog +hEWJZ4dCcIY_2 cow +hEZt4InN7Eo_0 elephant +hEZt4InN7Eo_1 elephant +hEZt4InN7Eo_2 elephant +hEdpC8HEa-A_0 motorcycle +hE04tUrJzXo_0 truck +hE7N0N5vik0_0 bird +hE7N0N5vik0_1 bird +hE-VIrAVcBA_2 bus +hFFrC0_rJYA_0 airplane +hFTTcrUxPeg_0 cow +hFTTcrUxPeg_3 cow +hFdi9yxVkys_0 motorcycle +hFdi9yxVkys_1 motorcycle +hFixbos35O4_0 truck +hFnKIVp-Dcc_0 cow +hFnKIVp-Dcc_1 cow +hFzR4bgxihU_0 bicycle +hGH72iljdzU_0 bear +hGRdOlSIQRU_1 train +hGRdOlSIQRU_2 train +hGRdOlSIQRU_0 train +hGiCVP3Z8l0_0 umbrella +hG6vW_xUZgA_0 train +hG6vW_xUZgA_1 train +hG959XPTh_8_0 bear +hG-quo0MZM8_0 elephant +hG-quo0MZM8_1 elephant +hHEIEEdrXYE_0 cow +hHIyy4Vda6M_0 cat +hHjzciM78AA_0 cow +hHtOM5_wiWM_0 truck +hHtqPiAg32Q_0 umbrella +hH_akvS98jo_0 skateboard +hIH6LuoXbpE_0 cat +hIXTbG6ho4E_0 person +hIXTbG6ho4E_1 person +hIXTbG6ho4E_2 person +hIz3ONvP-Bo_0 zebra +hI3P4BxIr-o_0 bear +hI3eGFKYRuc_1 horse +hJP8qg-kSZA_0 cow +hJTl4NJ0qIs_0 person +hJhBQsD0_hw_0 bus +hJkgoq_T4Pk_0 train +hJmxsYAKHdc_0 umbrella +hJtloiw4D-M_0 car +hJ_uvoDrzkI_0 giraffe +hKJQH8VbGk4_0 airplane +hKJQH8VbGk4_1 airplane +hKYJZqP-44M_0 airplane +hKYJZqP-44M_1 airplane +hKgtNPTirdc_2 elephant +hKgtNPTirdc_3 elephant +hKlKPyuUYps_0 bus +hKtHZYDaoXA_1 train +hKtHZYDaoXA_2 train +hKtHZYDaoXA_3 train +hKtHZYDaoXA_0 train +hK6w0B1cu-I_0 cow +hK7VoN3cI74_0 cat +hLGnjjoilbo_0 skateboard +hLHaPstpghQ_0 motorcycle +hLKzDOp8XLc_1 zebra +hLNcuJAwfDo_0 cow +hLVZsqfElxI_0 dog +hLX1LeVKgi8_0 cat +hLjDO37EQ60_2 dog +hLjDO37EQ60_1 dog +hLscdjfkeho_0 cow +hLte0Y4VWR0_0 knife +hL_QAgWBkJ4_0 cow +hL_noZA6D8E_0 truck +hMGVdq71lME_1 horse +hMLkMrqUtA0_0 horse +hMRIDt-1dY4_0 train +hMgp2oyTB80_0 cow +hMjke9g_Ysw_0 horse +hMuO0MHPIOQ_0 elephant +hMuO0MHPIOQ_1 elephant +hMusKbJqZDY_0 skateboard +hNHGh8N1XGg_0 knife +hN_-56Oxma0_0 dog +hOJJ65CVNuM_0 bird +hOOwQSSrFVc_1 cow +hOid-qo2Ozw_0 cow +hOky3qIMxRY_0 skateboard +hOpJoO7UciM_1 bicycle +hOrAXl-jATo_0 airplane +hOxMkI1d3oc_1 airplane +hOxMkI1d3oc_3 airplane +hOxMkI1d3oc_4 airplane +hOxMkI1d3oc_6 airplane +hOxMkI1d3oc_7 airplane +hOxMkI1d3oc_9 airplane +hPEsz5u87CI_0 bus +hPIDFIwLI8c_0 car +hPWhKQfDoXg_0 airplane +hPWhKQfDoXg_1 airplane +hPW2NpCU668_2 elephant +hPW2NpCU668_0 elephant +hPW2NpCU668_3 elephant +hPW2NpCU668_5 elephant +hPW2NpCU668_6 elephant +hPW2NpCU668_7 elephant +hPW2NpCU668_8 elephant +hPa5hUze91s_0 elephant +hPa5hUze91s_1 elephant +hPb_Rq2yKRA_0 cow +hPo5Wd-otbY_0 dog +I0yz1LGLl08_0 elephant +I1Ejpa2UWSk_1 bird +I1Pdo-p11tI_0 motorcycle +I1Quuhyu2UI_1 motorcycle +I1YfOiyQW_8_0 truck +I1wfW86V8So_0 dog +I1wfW86V8So_2 dog +I14JWDgkllE_0 truck +I14JWDgkllE_1 truck +I19kQsgjFRA_0 bicycle +I2IfiPw2aKE_0 elephant +I2OQlELjXvU_1 truck +I2OQlELjXvU_2 truck +I2OQlELjXvU_3 truck +I2hmFe1pYes_0 horse +I2o_4OyrJlI_0 horse +I3DSZk-7nG8_0 train +I3JCCqGY3c8_0 truck +I3KJj6GQ5QE_0 cat +I3OWw4AK0MI_0 dog +I330kG5lk5A_0 knife +I3-xBh-IrIo_0 airplane +I3_lU2I_AaU_0 bicycle +I4BMptNse7c_1 train +I4BMptNse7c_0 train +I4CMNv-VRDo_0 bird +I4Gi7kq5XAs_0 horse +I4HuQ8DDxoM_0 skateboard +I4WNAfBvm5E_1 skateboard +I4z-3IGHMW4_0 dog +I5KNdt1NT8g_0 skateboard +I5QNP3-QHLw_0 cow +I5SA8N1JKwM_0 cat +I5WNgPfoaZQ_2 motorcycle +I5pU9zWz4Fg_0 motorcycle +I6fJWB7DpAM_0 bus +I6oT6dLeq7A_0 motorcycle +I6wEvIOC-Pk_0 train +I7GbkWE2A0M_0 bus +I7aUrrDieE4_0 cow +I7bKlZxD6Fs_0 bicycle +I7xOURJQUps_0 train +I7xOURJQUps_1 train +I7x_od8h4iw_0 cow +I7-iLB-NVGg_0 dog +I8FoWQrnHGY_0 bird +I8Ms0rXjfXU_0 skateboard +I8Ms0rXjfXU_1 skateboard +I8Ms0rXjfXU_2 skateboard +I8Qx-qd0eLg_0 boat +I8Qx-qd0eLg_1 boat +I8UlumMtAG8_0 horse +I8Vr0DzHV9U_0 cow +I8rww3UUjYI_0 person +I9AGRokco_M_0 train +I9FPkgdc-5E_1 cow +I9XcFcBW-HM_0 motorcycle +I9oAq_x5pqg_0 bus +I9yrFs_JpWc_1 skateboard +I94qZUJmKP8_1 bicycle +I94qZUJmKP8_2 bicycle +I-SRTsDkhLM_0 cow +I-TshjRdh74_1 knife +I-blRAakQjM_0 boat +I-h3cTJlsRc_0 dog +I-nb60BTO_g_0 train +I-raj-aLy8s_8 horse +I-ywD5MDZZ4_3 cow +I-ywD5MDZZ4_4 cow +I_LhSNsRHMs_0 elephant +I_kI39ZHymk_0 horse +JAEzOCIew2Q_0 airplane +JAEzOCIew2Q_1 airplane +JAb3p7VYLzI_0 bear +JAb3p7VYLzI_1 bear +JAcHxxzG1vA_0 motorcycle +JAf3nC1hYS4_0 dog +JAp2_UJfFao_0 person +JAqAH7n-3lA_0 bus +JAzD-VzDxfc_2 bicycle +JAzD-VzDxfc_4 bicycle +JAzD-VzDxfc_5 bicycle +JAzD-VzDxfc_8 bicycle +JAzD-VzDxfc_11 bicycle +JAzD-VzDxfc_13 bicycle +JAzD-VzDxfc_17 bicycle +JAzD-VzDxfc_18 bicycle +JAzD-VzDxfc_19 bicycle +JA2PLZmRABc_1 umbrella +JBGewEMeWIs_1 dog +JBGewEMeWIs_5 dog +JBKG_tl08RU_0 cow +JBMhOrDLcho_0 cat +JBYr3VbJLoM_0 person +JBkymGnh5mA_1 bicycle +JBkymGnh5mA_2 bicycle +JBkymGnh5mA_3 bicycle +JBkymGnh5mA_4 bicycle +JBlCFCV4sdw_0 horse +JBlCFCV4sdw_1 horse +JBxFgwl0To8_0 cow +JB0SELYSRXA_1 bear +JB-hzl-gILo_2 truck +JCIJbwBevro_2 bird +JCSRBZQpYCw_1 bear +JCSRBZQpYCw_5 bear +JCTYAwT6ppk_0 motorcycle +JCTYAwT6ppk_1 motorcycle +JCTYAwT6ppk_2 motorcycle +JCciDn0O6X0_0 airplane +JChsfz-p2KI_0 cat +JCuE5X37xIE_3 boat +JCuE5X37xIE_4 boat +JDJWapHD_kM_0 boat +hP8Jfo1RaSk_0 elephant +hP8Jfo1RaSk_1 elephant +hP8Jfo1RaSk_2 elephant +hQWcyTkfPeU_1 dog +hQZDg__nxQA_4 bear +hQZ5lNlAXBI_0 truck +hQe3_1EvqIY_0 cow +hQfYabI9_ec_0 bird +hQkbXGwGwyg_0 skateboard +hQve0ugvy6s_0 motorcycle +hRAbtgVJiWI_0 bear +hRJ0Qk_qdAY_0 airplane +hRS45wmOq9c_0 elephant +hSR-ZVA-vMU_0 dog +hSWyYOzvh0g_0 dog +hSf3uEm8r9M_0 bus +hShwtMLieCc_0 boat +hSiozs1nz7o_1 motorcycle +hSzgOCvRfq4_0 bear +hS-h8AUEibc_0 cow +hS-h8AUEibc_1 cow +hS-h8AUEibc_2 cow +hTHBMsKC5ZI_0 cat +hTZr7OF0VuY_5 dog +hUJMSp4rMrc_0 train +hU0EbblT2vQ_2 airplane +hU388mZGPGg_0 cat +hU9B31AVZNg_0 bus +hVJjOdU5-yQ_0 car +hVNKN_qFEUA_0 bicycle +hVOImOLBY1g_0 skateboard +hVdb-Q3aJ9E_0 dog +hVhNOzZA40E_0 cat +hVnD8rlLRgM_0 bird +hVq6NOrBwlM_1 motorcycle +hVsAAQqAHyI_1 skateboard +hWHUct-PLfY_1 motorcycle +hWHUct-PLfY_0 motorcycle +hWNyVxx4a94_0 cat +hWn0ddeHF0I_2 zebra +hXAQH1xVKB8_0 cow +hXWQ710-JZQ_0 motorcycle +hXagj4A6N-s_1 elephant +hXbMo03RQWk_0 train +hXflTk4WVAA_1 bear +hXf7dimd2bo_2 cat +hXhtGcCMf5Q_0 airplane +hXsCNMb3eTc_0 bicycle +hYD7HKMKa3k_0 elephant +hYFW5XhMxyg_1 knife +hYIPy3eyC9k_0 cat +hYQBaiC8d6Y_0 horse +hYTIV5X87S4_0 horse +hYgzs0gDiiU_0 elephant +hYkPL7spYMo_1 elephant +hYlmhAuVVh8_0 bird +hYtFyx0799o_0 boat +hY0vkwEtjLM_1 bear +hZAOhuPJTho_0 horse +hZAXlQqCmCI_2 train +hZCGOP3PHOM_2 knife +hZHjTTvcQ88_2 bicycle +hZOhuOcxTP8_0 skateboard +hZPYHGzIYh0_0 cow +hZeekc0i_b8_0 motorcycle +hZiXqP-WaQk_3 bird +hZiXqP-WaQk_0 bird +hZiXqP-WaQk_1 bird +hZiXqP-WaQk_2 bird +hZygBhv-nDg_0 motorcycle +haC0TZbvBEU_0 cat +haMtzn-TnOQ_0 boat +haTl-PeSssc_0 dog +hakWXvIYvzo_1 dog +hanKUxPHFbA_1 car +hanKUxPHFbA_0 car +haxabA27SnU_0 horse +ha3C2hPzaiw_0 dog +ha8hX-68TqI_0 bear +ha8hX-68TqI_2 bear +hbKjt5OBryI_0 truck +hbKjt5OBryI_2 truck +hbKjt5OBryI_1 truck +hbfiyMHycSs_3 knife +hbvJ3t9lpUo_0 truck +hcXtsyICD30_1 skateboard +hcpMT5qGQ0U_0 bus +hdZkNo0t6wg_0 boat +hdbKePdCemQ_0 cow +hdqiOcfXejc_1 zebra +hdwZF4C-vYs_0 cow +hd_yXL53Z9E_0 elephant +heQRV9di86s_0 train +heTgOW6o1ho_0 zebra +hedgcDGNngs_0 bicycle +heucaATRtbI_0 cat +he_j-GZdCNs_0 person +hfCbKe627p0_0 airplane +hfEl_mnX9X4_0 skateboard +hfGEkaEADUw_0 motorcycle +hfGEkaEADUw_1 motorcycle +hfGEkaEADUw_2 motorcycle +hfcKFLBuJ_g_1 dog +JDcAM9ieTp8_0 bicycle +JDe9ulv2Nmo_0 elephant +JD_njBej6V0_0 truck +JD_njBej6V0_2 truck +JEU2rZzAxRU_0 skateboard +JEbIHUJTFsM_0 airplane +JEdl8GROiQM_0 truck +JExlAUEYZwc_0 cat +JE8SV6FOlC0_0 truck +JFH3n9kI6aA_0 boat +JFO_Qz1y8-s_4 elephant +JFQ_GztsLs0_0 cow +JFQ_GztsLs0_3 cow +JFZG_ebR2mk_0 elephant +JFZpmduYfv4_0 motorcycle +JFfYNQ2FmHU_0 cow +JFk4Qyn58CY_0 train +JFvQ7wc6c0o_0 airplane +JGDf9kSc-v4_13 dog +JGDf9kSc-v4_15 dog +JGDf9kSc-v4_17 dog +JGDf9kSc-v4_19 dog +JGDf9kSc-v4_1 dog +JGDf9kSc-v4_2 dog +JGDf9kSc-v4_6 dog +JGGj1z6Kujc_0 dog +JGGj1z6Kujc_1 dog +JGMfEFj5PVM_1 truck +JGWBjvjqVhw_4 skateboard +JGanm9yGTJk_0 truck +JGanm9yGTJk_1 truck +JGanm9yGTJk_2 truck +JGmHpQtJzic_0 horse +JGn6Ifa5bWI_0 bird +JG0B4rV4KEI_0 dog +JG6H3R9rErg_8 airplane +JG6H3R9rErg_0 airplane +JG6H3R9rErg_1 airplane +JG6H3R9rErg_2 airplane +JG6H3R9rErg_3 airplane +JG6H3R9rErg_4 airplane +JG6H3R9rErg_5 airplane +JG6H3R9rErg_7 airplane +JG6sceNvlnI_3 boat +JG6sceNvlnI_2 boat +JG872iaucFc_0 umbrella +JHBhDpq4HNs_0 cat +JHBtawKoltc_0 car +JHTt9PSzrhU_0 elephant +JHb8IVsjgMs_1 bus +JHdc9jvf4qA_0 motorcycle +JHmG34eTWow_0 train +JHr57YE7IRs_1 airplane +JHy85i0So5U_1 dog +JH0Jzb0wOXw_3 elephant +JH0Jzb0wOXw_4 elephant +JH0Jzb0wOXw_2 elephant +JISA50Bfj4U_0 boat +JIamGji7w9U_3 bird +JIiA0pG-MKk_0 skateboard +JI6MyG7aTvM_0 bird +JJSp2fu3lk8_4 dog +JJSp2fu3lk8_3 dog +JJq7YAYUado_0 umbrella +JJx7GdAuDQY_0 skateboard +JJyJR7TlQ7o_0 motorcycle +JJ0Ja1ju2ec_1 horse +JJ0NBly53IU_0 cat +JJ8Vv2hiCCA_0 cow +JJ8Vv2hiCCA_1 cow +JKBJuICyV50_1 train +JKBJuICyV50_0 train +JKCFS8k_Qis_3 bus +JKGV5hbm5g8_0 skateboard +JKJQPHspLBs_0 bird +JKJQPHspLBs_1 bird +JKNRKGSvtsQ_0 elephant +JKYPluJPL7c_0 dog +JKa7rPKrAwY_0 train +JKgPYc0K_hI_4 car +JKgPYc0K_hI_1 car +JKuhG9WLM2k_0 airplane +JK42K36SYLs_0 bird +JLE_jNuNoA0_0 cow +JLHP-3UxtMU_0 boat +JLb2dnuNhqs_0 bus +JLoS7DZH_ik_2 airplane +JLoS7DZH_ik_1 airplane +JLsEcZUU7FM_2 truck +JL64rU6Jvmw_1 giraffe +JL71b_9Cy9I_1 umbrella +JMDFSes_w0E_0 cow +JMMmrEdfRbk_0 boat +JMPKtdq9b0Y_0 train +JMR4IvE2sDo_0 bus +JMaahZTxRLk_6 boat +JMgbgNPBIJI_0 bird +JMnp6FLLbtw_0 horse +JMnp6FLLbtw_4 horse +JM1jSU4FEPw_2 airplane +JM4yr2pj-zg_0 airplane +JNDZBgXZBU8_0 knife +JNDZBgXZBU8_3 knife +JNDdt_ZPl1s_3 elephant +JNNbk6jVfB4_0 cat +JNZDx8Ro_mM_0 truck +JNe7ZednqQc_2 horse +JNkz_3Qtdfc_0 horse +JNnnm9ixKrM_3 car +JNnnm9ixKrM_4 car +JNnnm9ixKrM_5 car +JNpuJeqVFxk_0 motorcycle +JONF8-3gEoY_0 giraffe +JONF8-3gEoY_1 giraffe +JONF8-3gEoY_2 giraffe +JObYghNlZas_6 train +JObYghNlZas_7 train +JOmeD6G33Dc_1 horse +JOoNVY1C6qI_0 train +JOoNVY1C6qI_2 train +JOqHfu-WVu8_2 horse +JOuB1UkVvKI_0 airplane +JOue8LphKc4_0 truck +JOztmtwKz-k_0 cow +JPAjGBsi-rE_0 bird +JPMFXg-BXDE_2 car +JPTFJk9f2nM_0 dog +JPevMGnX92M_0 airplane +JPiSmPAIpOI_0 knife +JPlZOEew4wg_0 elephant +JPuDmwlAXzI_0 skateboard +JPwUpTvlZDA_0 person +JPwUpTvlZDA_3 horse +JPw4R6t-0j4_1 bird +JQDX7gVR0qM_2 knife +JQDX7gVR0qM_0 knife +JQKDDMvCtt8_1 horse +JQNsIqNLn40_0 truck +JQRxu6RVGMg_0 car +hfwhbInEJAk_3 train +hfwhbInEJAk_2 train +hgFfz_RTcx4_0 truck +hgFfz_RTcx4_1 truck +hgxvhMjH_68_0 motorcycle +hg6Z6JIwRMU_0 elephant +hg6Z6JIwRMU_1 elephant +hhM2TSF2GhA_1 horse +hhNlkY3SS6w_1 bus +hhYOJb0v5Yw_0 cat +hhlt4dfZmFE_0 horse +hhyzKC353Jo_1 car +hiJ-OdPj_8c_0 bird +hiPDdAi1Qs8_0 motorcycle +hiUH1zOfsfo_0 cat +hiZLv2E5zI8_0 elephant +hjBLAHakI9c_0 boat +hjRlztwK-vg_2 bicycle +hjhbMbrRUWI_0 truck +hj2P25O-nIk_0 skateboard +hkR10EU8YPI_0 train +hk0cDE4A_b0_0 boat +hk7M3PGcOhw_0 train +hk-IVoljyKE_0 elephant +hk-IVoljyKE_1 elephant +hlFPCpe8Akk_0 airplane +hlLrYrrOcY4_0 dog +hlNOQO4BIHg_0 train +hlnNVsSGjxA_3 car +hlnNVsSGjxA_1 car +hl4yLAJiWjQ_0 elephant +hl7z1gnPPW0_0 knife +hl_YHwW5mrM_1 bird +hl_YHwW5mrM_0 bird +hmThCl2HK8E_0 skateboard +hmThCl2HK8E_1 skateboard +hmdH0Olcbx4_0 bicycle +hm98pilx9dE_5 horse +hm98pilx9dE_1 horse +hm98pilx9dE_2 horse +hm98pilx9dE_3 horse +hm98pilx9dE_4 horse +hnJ2wDmXD6w_1 bicycle +hnbZY12P-7g_1 elephant +hne72NMSPuc_0 bird +hnffUBbBFoQ_1 horse +hnrSBT9miTE_1 bird +hnvbE27mWwI_2 train +hnvbE27mWwI_0 train +hn19XaR_wIs_0 knife +hn7ollCkAy4_5 bicycle +hn-1W1O8kZs_0 boat +hoLnPrkJ6sE_0 horse +hoLnPrkJ6sE_3 horse +hoNPAcq_5Ac_1 bird +hoNPAcq_5Ac_0 bird +hoYDTU50MTk_0 cow +hoe88GhFhq0_0 truck +homQXuwbe04_0 cow +homx5sSuNr4_2 bear +hoozxxjd57c_1 bus +hotrXXenVAk_0 cat +ho5YZstr1XE_1 cow +ho7yo7nJk3o_1 elephant +hpG2eG_hduA_0 motorcycle +hpRxBuFhZ4M_0 train +hpRxBuFhZ4M_1 train +hpRxBuFhZ4M_2 train +hpRxBuFhZ4M_4 train +hpkXlhfYZfw_2 motorcycle +hpkXlhfYZfw_1 motorcycle +hpmC3OjLnZM_2 boat +hpmC3OjLnZM_0 boat +hpo-lwBTbFw_1 dog +hp3aTxzS9ms_0 skateboard +hqGhmP1u07Y_0 elephant +hqoQm68UbGo_3 airplane +hqoQm68UbGo_2 airplane +hqsoIR9v8IY_0 motorcycle +hq7f1_o4eFg_0 airplane +hrLkVz3_xGw_2 bus +hrW-pkK9osE_2 bicycle +hrW-pkK9osE_3 bicycle +hrgh69NXZqw_0 cow +hrj6I8n8nAc_0 bicycle +hrj6I8n8nAc_1 bicycle +hrrpTPwLZHA_0 bird +hrtiCeqnqLg_0 cow +hrziTee4b2c_0 airplane +hr5Q08OMeAU_0 train +hr7wUBMikww_0 zebra +hr7wUBMikww_1 zebra +hsMptx7tOLo_0 elephant +hsMptx7tOLo_1 elephant +hsMptx7tOLo_2 elephant +hsM1eKbrqLs_0 cat +hsPK4wlNtI8_0 cow +hsYL355Fzio_0 truck +hsfS5oT1y5M_2 boat +hskEM8GUmDE_2 train +hsmxUKxzapo_2 skateboard +hsmxUKxzapo_0 skateboard +hsyCfsJx7DI_2 skateboard +hsyCfsJx7DI_1 skateboard +hs2foQ_Xo8A_0 skateboard +hs-OEgnsLZs_0 train +htDilkoPA-M_0 airplane +htSBZwTBX98_0 horse +hteze9Fz1dc_0 knife +htkybhLm0uk_0 umbrella +htwBHgatd9c_2 horse +htwBHgatd9c_3 horse +htwBHgatd9c_0 horse +huCxpuVT4GI_0 dog +huDCqh-KRy4_8 bicycle +huDCqh-KRy4_2 bicycle +huDCqh-KRy4_3 bicycle +huDCqh-KRy4_4 bicycle +JQnf7j7HpKY_0 cow +JQpJv-SOMS0_0 dog +JQ9LtiJVsd8_0 cat +JQ_dyIlBnGM_0 cow +JQ_6xcOuEfU_4 cow +JQ_6xcOuEfU_1 cow +JRA3LCwRGu0_0 knife +JRBLFsevgg0_0 train +JRJjI6mFa6s_1 skateboard +JRJnSf2qOXA_0 airplane +JRT0FH2KEsc_0 cow +JRcTFvzRC10_0 bird +JRcTFvzRC10_1 bird +JRsNcoTJJjE_0 cat +JRsn1likB7c_0 boat +JRyc_lxMJzs_0 skateboard +JR6JAx7xdGg_0 cat +JSA0JWvQbJg_2 train +JSdEdTcUHHI_0 knife +JSfXE4ExZ1U_0 bird +JSfXE4ExZ1U_2 bird +JSs6Sa8zR6c_0 horse +JS2cbpFwahY_0 skateboard +JTE0ABGzb30_1 skateboard +JTE0ABGzb30_2 skateboard +JTJgZcBM93k_1 knife +JTa9HkbXfSw_0 cow +JThBohLxRSc_0 cow +JTi4Oy6v9mM_1 horse +JTi4Oy6v9mM_2 horse +JTtjfwrK4Ls_0 dog +JT5zUQio3B0_0 bus +JUHMTmjUswE_0 knife +JUVHXeFTe3Q_0 horse +JUVHXeFTe3Q_3 horse +JUbPqBVbGQQ_1 truck +JUpxTW6_BAI_0 cow +JUtd4FLjXio_0 horse +JU1N1nqXjII_0 train +JVKkxo7adX8_1 knife +JVQ6Gx2hGxs_0 airplane +JVTIzApj2UA_0 giraffe +JVVtcOIACz0_0 giraffe +JVg62b0T408_2 train +JVg62b0T408_0 train +JV2A3zWMRj8_0 umbrella +JV3Tbp30yp4_2 motorcycle +JV3Tbp30yp4_1 motorcycle +JV3Tbp30yp4_3 motorcycle +JV-OfjEsQDs_0 umbrella +JWKZlCk_cts_0 train +JWXSXvHgoo4_0 car +JXEyPb4Nzro_0 skateboard +JXP_CNg8grg_0 cat +JXi5KrVPz0M_1 bird +JXj_lj5QUp8_0 person +JXmBBTT0YXQ_0 cat +JXobiO1_7Ts_0 train +JXwfPpl53Fs_0 dog +JYYAwimr2XQ_0 truck +JYi7bWDL5os_0 person +JYsWtLH_mjM_0 bus +JYsWtLH_mjM_1 bus +JYsWtLH_mjM_2 bus +JYvBo5FwjSg_0 elephant +JYvBo5FwjSg_2 elephant +JY2d1dohCDs_0 elephant +JY3rSX-blgA_0 cow +JZBJ35lKlXw_0 truck +JZOZuTiifHM_2 boat +JZXr-dGLkpU_0 boat +JZcy1T--d4M_0 skateboard +JZ_ri3awsso_0 cat +JaI9UR2n7ZE_0 horse +JaLswoS3xO8_0 knife +Jaumrq8clZY_0 truck +Ja9rAQpB2_M_0 cat +Ja_ofQ1ynAc_1 airplane +Ja_ofQ1ynAc_2 airplane +Ja_ofQ1ynAc_4 airplane +JbA11YWHpW0_1 skateboard +JbBxvvoOvpg_0 bear +JbK17NE3dvk_1 train +JbK17NE3dvk_0 train +JbK17NE3dvk_2 train +JbK17NE3dvk_3 train +JbPP4AwiNEc_0 cat +JbSkoHG6Vq4_0 airplane +Jbfzd9wIyi4_0 cat +Jbw0KUJqWpE_0 train +Jb03yqEB5WI_1 bus +Jb03yqEB5WI_4 bus +Jb5lFDvKqXA_0 bus +Jb6FIuynIuw_0 bicycle +Jb-q7z_Mygg_0 truck +JcJKjdDKuc4_0 train +JcRvhoBwgNg_0 cow +JcU-cdQmKV8_3 bus +JcU-cdQmKV8_1 bus +JcixSQRUnY4_1 elephant +JcmTLrQZ7sE_1 cow +JcmTLrQZ7sE_0 cow +Jcwl0kCsUTw_0 umbrella +Jc5PS0Ejejw_1 elephant +Jc8eE1ayaX8_0 cow +Jc9PdqC1rpg_0 train +JdUehtxAfys_1 bicycle +JdUehtxAfys_7 bicycle +JdwSAFvKg74_0 car +JeAykU3MiKg_2 airplane +JeET8zb_gPQ_4 knife +JeNu9WVQOHY_4 bicycle +JeNu9WVQOHY_1 bicycle +JeNu9WVQOHY_7 bicycle +JeYCd0VP5EY_0 horse +Jeb4SSyyZD8_0 dog +Je_fuH6-34I_0 skateboard +hujF3CEgAXI_0 skateboard +hulFEZUNu10_0 train +hutTW7ORN8g_0 bicycle +hutTW7ORN8g_1 bicycle +huy9NXPynro_0 cat +hu6nRmzUcAw_0 train +hvWHb1kiV5g_0 dog +hvWs1FhyQlw_0 umbrella +hvhWoRQZMUU_0 cat +hvjNVTle8bQ_6 airplane +hvjNVTle8bQ_0 airplane +hvjNVTle8bQ_1 airplane +hvjNVTle8bQ_2 airplane +hvjNVTle8bQ_3 airplane +hvjNVTle8bQ_4 airplane +hvjNVTle8bQ_5 airplane +hvkIo-dZUUY_1 bird +hvlXyPikLUY_0 bus +hv49V2RzgHw_0 horse +hv7b1I-cRvI_0 truck +hwOL2G-Lo54_0 umbrella +hwPkgOB1mEU_0 cow +hwTVAkfjjCY_0 cat +hwikEC2Jc0c_1 horse +hxC7dFDqfXo_0 car +hxUn2A7Ko2g_0 cow +hyMlfx_ZEeI_0 train +hyMlfx_ZEeI_1 train +hyX6rKHZcLs_0 person +hyb_qBoKG9Y_0 train +hyjjdUcyanE_1 dog +hyj8BJ_PMgQ_2 elephant +hyrBL1wMHts_1 truck +hy9Ml-3zAtM_2 knife +hy9jrpamopE_0 umbrella +hzBqPVIC7IQ_0 train +hzUTA7mGyKE_0 bicycle +hzeHyMcUmO4_0 motorcycle +hzeHyMcUmO4_1 motorcycle +hzz9JBRYjFs_0 bicycle +hzz9JBRYjFs_1 bicycle +hz5anqtArdI_0 train +hz5anqtArdI_1 train +hz7PXI6R6DI_0 train +h0IiMbTwz1Q_0 truck +h0IiMbTwz1Q_1 truck +h0hIpf9O0Vg_0 bus +h1MxYGy1SBc_0 dog +h1XtVmXF7CQ_1 elephant +h19z0Ap_5Pc_0 bus +h2R46pcCEVg_0 cow +h2SNrfK0yQQ_2 bus +h2X0to3hDA4_0 bicycle +h2b9t_pnnNA_0 cow +h22FyeO_lyE_0 umbrella +h23R8X1WKjU_1 horse +h24uuiI34yI_0 skateboard +h27DK_oMwYY_0 dog +h3FnAKBB9Xc_1 elephant +h3Lz61ficjc_2 motorcycle +h3aEao1bRIY_0 cat +h3aZGHTjBwc_0 elephant +h3o5ZykGOxI_4 elephant +h3o5ZykGOxI_2 elephant +h3o5ZykGOxI_3 elephant +h3qOwaRYAi8_1 bear +h3uPELFKoCc_3 knife +h3uR99WtOh4_4 bear +h3_cWsxi4Qw_1 skateboard +h4CySJb83XI_2 elephant +h4KXG16xA_Y_0 dog +h4LE2YVwHL0_0 motorcycle +h4jU8ZrDZd8_0 skateboard +h4kmvN6NmyA_3 train +h4kmvN6NmyA_2 train +h4wsDcj7kcE_0 cow +h45-zE2gKFA_2 person +h45-zE2gKFA_3 elephant +h47dExP6oXQ_0 elephant +h5C2RKknWfg_3 bicycle +h5C2RKknWfg_5 bicycle +h5C2RKknWfg_6 bicycle +h5KSLdybLIE_5 bicycle +h5KSLdybLIE_1 bicycle +h5KSLdybLIE_3 bicycle +h5dsU3N4joc_0 cow +h5hkvWWp7Qg_0 knife +h55Exp2rpSM_0 knife +h6FtP-5VnYM_2 cow +h6FtP-5VnYM_1 cow +h6McnZDPX3I_12 elephant +h6McnZDPX3I_1 elephant +h6McnZDPX3I_2 elephant +h6McnZDPX3I_6 elephant +h6McnZDPX3I_7 elephant +h6McnZDPX3I_9 elephant +h6McnZDPX3I_10 elephant +h6Mvzt5e_eE_0 horse +h6jGPQLkE48_0 person +h6ztcoDHYaY_0 cat +h62bO9Mfl9Y_0 cat +h64dmoPNWw0_0 car +h7OZUnDKWbA_0 truck +h7cXxMNxlcY_0 horse +h7uwd7opKjI_0 motorcycle +h7uwd7opKjI_1 motorcycle +h8BDqFH8e_w_0 train +h8BDqFH8e_w_1 train +h8BDqFH8e_w_2 train +h8EHrA_OM7c_0 person +h8LiHNo4904_4 airplane +h8LiHNo4904_5 airplane +h8LiHNo4904_6 airplane +Jfb3XGdt6VE_0 cat +JfdoYsRxF5k_2 knife +JfnHVMyUT0E_4 bicycle +JfqHeWyD5DQ_0 skateboard +JgLXpgcnjAA_0 cow +JgQbvDmM2Nk_0 bird +JggJWWHhlc4_0 umbrella +Jg8FXSKMvTQ_1 elephant +JhDNC6XRVG8_0 cow +JhDNC6XRVG8_1 cow +JhFvJHfP_NY_0 car +JhPLC0PS9I0_0 knife +Jh87zKRgN68_2 boat +JiMyZFGmGgM_0 dog +Jifa2spqYV8_0 airplane +JijtEhm-Dk8_0 bus +JikSLpJ2xKw_0 cow +JinIHVE4_MI_1 bear +JioS9DumyIM_1 car +Jixd9HKGzWA_0 train +Ji6bpPIPScI_0 umbrella +JjIvWQ-198c_0 knife +Jja500M50Yw_0 cow +Jja500M50Yw_1 cow +Jj4KvC3TXro_0 car +Jj4KvC3TXro_1 car +JkC1Udoysk8_1 cat +JkC4nV8LcTE_1 bicycle +JkH8ZtuvzDQ_0 dog +JkpQkpiRpVI_0 bird +JkzNUiOu1GI_0 bus +Jk28bpr063o_4 airplane +Jk28bpr063o_0 airplane +JlJQlaoy3ec_0 cat +JlrPaJIAP9k_1 horse +JluvPpeI2DY_0 train +JluvPpeI2DY_1 train +JlzsUphxgIY_0 truck +Jl1bEdoRG9I_0 cow +Jl6gTtZcQH0_3 horse +Jl6gTtZcQH0_0 horse +Jl6gTtZcQH0_2 horse +Jmblo1iMURo_0 motorcycle +JmdMhGsyZvk_0 boat +JmvNubLPYGo_0 bird +JmxixgKAKzc_0 truck +Jm0S-kE2yVc_0 truck +Jm3dtu8GTos_0 dog +JnAaSoaN3FI_4 boat +JnHUNCeHEDc_0 bird +JnMkFSGB6Vw_0 truck +JnXmNI53DWE_0 person +JnrrNu9udj0_0 bear +JnvIx5y-ijs_1 umbrella +Jnysuevt_4A_0 train +Jn1gvGhxU5U_0 bear +JocAgPv-ZJo_0 skateboard +JohmecnKktI_0 boat +JopGEGMo-DQ_0 dog +Jo50LBwjHIk_0 bicycle +Jo50LBwjHIk_2 bicycle +JpDOBaNBwkc_0 truck +JpFiApmpoHA_0 cow +JpL4Mv-uFi4_1 dog +JpRMc6MtCH8_0 truck +JpWh1yQThRo_0 train +JpZwF6hOCDg_1 truck +JpjAxQ_vsZw_7 bicycle +JpjAxQ_vsZw_1 bicycle +JpsOsewgXAg_1 bird +JpuCWzsE35k_1 bird +Jp0GKZ9vA0c_0 airplane +Jp1tvS1y4eI_0 boat +JqCaTxH5Ovk_0 motorcycle +JqC81ViWFeE_0 bear +JqPkaGRIz6c_2 elephant +JqT_Bx4fd1Q_0 cow +Jqauh1bsJy4_0 bear +Jq2ml2xQkHg_0 cat +Jq8D628IlV8_1 skateboard +Jq8D628IlV8_2 skateboard +Jq8OMvgG6wc_0 cow +JrAvVMnkKEo_3 bear +JrKxxhHGR7E_0 giraffe +JrZTstVj2wg_0 horse +JrbrXXDuxnc_0 horse +JrmyPAW-ItI_0 dog +JsNQXxg1PvE_0 person +JsPtP21j3f8_3 bear +JsPtP21j3f8_1 bear +JscnB4QfAhY_0 train +JsiSPt3nv1Y_0 cow +JsiSPt3nv1Y_2 cow +Js2ZDfWZWtc_0 cat +Js69iFgcic0_2 bus +JtMMD0aJnPI_0 train +JtMMD0aJnPI_1 train +JtQzeWNt8IA_0 umbrella +JtQzeWNt8IA_2 umbrella +Jtfp49L4LHg_0 train +Jt1zVsUQGhI_2 elephant +Jt1zVsUQGhI_3 elephant +Jt8ikZGW768_0 bicycle +JuGusvu6Z7o_0 skateboard +JuKJKHykMKM_0 horse +JuKgukJ63eM_4 skateboard +JuME8_jaVdE_2 car +JuME8_jaVdE_3 car +JuMNRsOc0nU_1 cat +JuMNRsOc0nU_0 cat +JuNubQtCvrU_0 bird +JuNubQtCvrU_1 bird +JuO7qvp2GBs_0 knife +JuXqLoCgK4o_0 bear +h8OcTR0Z4yo_1 airplane +h8OcTR0Z4yo_2 airplane +h8OiIYhIPTs_2 train +h8PJps4Sj1E_0 airplane +h8PmDAKiKVc_0 dog +h8oTFl4XWTc_0 bus +h8ysn_L9udY_0 train +h8ysn_L9udY_1 train +h9FtsOFR3p8_0 cat +h9veoEpzRH8_0 cow +h9w20ChZ_7Y_0 bicycle +h9w20ChZ_7Y_1 bicycle +h96rR-VkJZA_1 bear +h96rR-VkJZA_2 bear +h966cxQyjvc_1 airplane +h-PS5v6ZTBY_0 truck +h-VSmS49g5M_0 skateboard +h-npKkPbHSA_0 boat +h-qRpUteJV4_0 bird +h-vGllteZnI_0 train +h-1NdCqoxdU_1 bird +h-2DBPzbKUM_0 cow +h-27oWBBirE_0 dog +h-9WCj8sB6o_7 airplane +h-9WCj8sB6o_8 airplane +h-9WCj8sB6o_10 airplane +h-9WCj8sB6o_11 airplane +h-9WCj8sB6o_12 airplane +h-9WCj8sB6o_0 airplane +h-9WCj8sB6o_1 airplane +h-9WCj8sB6o_3 airplane +h-9WCj8sB6o_5 airplane +h_DH9wUjJZA_0 cow +h_Ey7gQJCSc_0 cow +h_KKvY3cK4o_0 cow +h_KKvY3cK4o_1 cow +h_XHdrNdD98_0 bus +h_tQ-ZVYe1M_0 bird +h_6GMOpsIOk_0 cat +iACKPRGNEOU_0 bus +iADpOEGdwQI_3 bird +iALubFRPBXQ_1 knife +iAL5KD5BwGQ_0 horse +iAuV09oxF_c_0 bus +iAzvkn-2C9s_4 horse +iA_tYzSGuVg_0 dog +iBDVD9if3VA_1 bear +iBDVD9if3VA_3 bear +iBDVD9if3VA_4 bear +iBF1Cfv7RpE_2 train +iBF1Cfv7RpE_3 train +iBO6oNBr4hM_2 train +iBmHl4vB2p8_0 boat +iBmHl4vB2p8_1 boat +iB2e_0wI6Cs_1 bird +iCA5LKIvUak_0 horse +iCUmfkHj2MM_0 elephant +iCWBysiT4fE_0 airplane +iCoklLBZGi0_0 truck +iC-r2odD6Ss_0 dog +iDBWSSj3Yag_0 bus +iDMMfw0zrvQ_0 cow +iDy5BzJGt50_0 skateboard +iD0ptJ7ucww_0 horse +iD0ptJ7ucww_2 horse +iECVUNZOPOM_0 cow +iEIRSDANY7g_0 bird +iEcsL-BdEp8_0 skateboard +iEeZD9_-mw4_1 train +iEe9Qed4A6w_0 elephant +iEfRHR6In04_1 dog +iEnwhpHkWPA_0 dog +iErN5WNQuZ8_1 bear +iFLG6c3XcMw_1 knife +iFgR4_OYpgU_0 boat +iFk_jNFfItI_0 car +iFsAXsW8t-8_1 bus +iFsAXsW8t-8_2 bus +iGB1OkMGELk_1 elephant +iGE04YY7P68_0 motorcycle +iGE8oPBzavo_0 airplane +iGKh6_bzEe8_9 airplane +iGKh6_bzEe8_5 airplane +iGWCy-zysHU_7 horse +iGWCy-zysHU_0 horse +iGWCy-zysHU_2 horse +iGWCy-zysHU_5 horse +iGf0rCvWhZE_1 bird +iGivgJkDWVo_0 elephant +iGivgJkDWVo_4 elephant +iGivgJkDWVo_5 elephant +iGivgJkDWVo_1 elephant +iGivgJkDWVo_2 elephant +iGmHR-MYdts_2 skateboard +iGtwAlGgpuQ_0 motorcycle +iG3IZAIpSos_0 cat +iG4w2A16Qy0_3 boat +iG4w2A16Qy0_0 boat +iG7OG-yAmkg_1 boat +iHNSjj9GO9k_0 horse +iHZNqzCjd7k_0 train +iHbirUiASog_0 skateboard +iH0SvXt_QEE_0 cow +iH9qrmQO5wg_3 horse +iH9qrmQO5wg_1 horse +iH_5naROy0I_0 motorcycle +iIYyUq4tPbc_0 cow +iIZw5oU3kz4_0 dog +iIa2i3Fyyp8_0 cat +iIgi9EuB83A_0 train +iIlu4DSMMwM_0 skateboard +iIoEhVh0sac_0 bird +iIoEhVh0sac_3 bird +iIoEhVh0sac_1 bird +iIwKnWnoXd0_0 skateboard +iI66ySv1M1E_0 bear +iJcYkYS6CgE_4 airplane +iJcYkYS6CgE_0 airplane +iJcYkYS6CgE_3 airplane +iJqRpAI5q0M_0 cow +iJ0Pe8-N6i4_0 bus +iJ5fEZLxnPw_0 knife +iJ5fEZLxnPw_2 knife +iKLuvvisn6Y_0 airplane +JvHU5ncnmtc_1 cow +Jvkp32eVZyc_0 cat +Jvm2k8MgJ5k_0 cat +Jv1ayezpka4_0 bird +Jv6b9zItltw_3 bird +Jv6b9zItltw_0 bird +JwNWcW7nUBE_0 elephant +JwNWcW7nUBE_2 elephant +JwaPyA7kWhc_0 cow +JwnMWPlx6KU_0 cow +Jw_nc2U4pKs_0 skateboard +JxKJB-QdFUA_1 umbrella +JxRKwF7KNOA_0 bird +JxSYbvgXcT8_0 car +JxVoSlh710g_2 bird +Jxc3ArJpyuY_0 motorcycle +Jxc3ArJpyuY_3 motorcycle +JxdIZhohCtg_0 cow +JxlB8wLncYc_0 elephant +JxzCLy2VyJA_0 skateboard +Jx03EEph0bw_1 truck +Jx2PgBxlrLY_3 airplane +Jx6xyX5sPMk_0 cat +JyKJFochwIQ_0 truck +JyLFLF4shyY_0 airplane +JyLqTlaGOww_0 knife +JyM0FDmoMyQ_0 airplane +JyePA4nzTx8_0 truck +JyhAOfW608o_0 cow +JyliijVyyUc_0 elephant +JyliijVyyUc_1 elephant +Jy1hmMPCNks_0 dog +Jy1hmMPCNks_1 dog +Jy37u1dt8Qc_0 dog +Jy_3PqINBss_1 bird +JzGkRevP9mU_1 truck +JzNvJYTN1Pw_1 bus +JzNvJYTN1Pw_0 bus +JzNvJYTN1Pw_2 bus +JzNvJYTN1Pw_4 bus +JzNvJYTN1Pw_7 bus +Jzm0H_o-LyA_1 bicycle +JzwF2_O5qho_0 cow +JzwF2_O5qho_1 cow +JzwF2_O5qho_2 cow +J0Gb34OfhGs_0 airplane +J0m2haAO_Pg_0 truck +J0uOEHqVD0g_1 elephant +J01a05fNHz8_0 airplane +J05eYTq5pFE_0 cow +J1BVFlR3Pzc_2 bicycle +J1VVax1uIGc_0 elephant +J1YSacTJR64_0 bear +J1YqrkAsUIs_1 truck +J1YqrkAsUIs_2 truck +J1YqrkAsUIs_3 truck +J1rYOpOlNqs_0 cat +J1reV7ZinzE_2 truck +J1sQZHaGRVY_0 cow +J1uF4oCMmtU_0 car +J10PTSVhLnQ_0 car +J10PTSVhLnQ_1 car +J10PTSVhLnQ_2 car +J142X1ly-gY_0 cow +J17uKo2HgxY_0 bird +J2R5C_XNnek_0 train +J2Sh2XKvWOA_2 horse +J3EToJg72Es_0 horse +J3d48McH1L0_0 elephant +J3gk0p9Hm0o_0 knife +J3hgEqlUzpg_0 bus +J3hva1l0CWM_1 horse +J3jOAuADP44_0 boat +J3sMC-99CWs_1 cow +J3zIT2YwDdY_0 bicycle +J315ju7gD8Q_2 train +J4eK5nQv9E0_0 motorcycle +J4hu4X1Hr7k_0 bear +J4ithFdbyKY_0 train +J4mDzsuGR1M_2 bear +J43AWiRkRAI_0 skateboard +J46c4FEAjQ8_0 horse +J46c4FEAjQ8_2 horse +J5CA6t8d7uA_0 truck +J5JNgpMvPks_0 horse +J5Ss-cEKg9o_0 skateboard +J5TS-1YKlWE_0 elephant +J5TS-1YKlWE_1 elephant +J51qDcGqOV8_0 airplane +J5-O6tDEZO0_0 horse +J5_8xLaPuIU_0 cat +J6AHeX1RqWk_0 bus +J6nRLSf9kms_1 dog +J61MSyhI5Xg_0 bird +J68NptJ9oRE_0 skateboard +J7h1DaonvHY_1 horse +J7jTtirQ85g_0 motorcycle +J7vNGyyYQ30_0 dog +J73WpGWHEuE_0 giraffe +J73WpGWHEuE_15 giraffe +J73WpGWHEuE_1 giraffe +J73WpGWHEuE_2 giraffe +J73WpGWHEuE_14 giraffe +J79qVoBV6TM_0 car +J8Akt0d4r_k_0 train +J8Akt0d4r_k_1 train +J8dIP05jqRw_2 truck +J8dIP05jqRw_5 truck +J9SzI8MQm6Y_0 airplane +J9ZGJucbLiw_0 airplane +J9mX4rrWQto_0 knife +J9n9_-FSk4Y_0 dog +J916-YD5Qms_0 elephant +J-sHEYA-20k_1 giraffe +iKjaiW6gHPQ_1 elephant +iKjaiW6gHPQ_0 elephant +iKlCbkZsFzE_1 cow +iLeUN6d8Aew_0 giraffe +iLeUN6d8Aew_1 giraffe +iLk3v-m1Z0U_0 horse +iLvLOw8Jigg_0 motorcycle +iL0GMZ7iO3c_0 dog +iL5OOut4Jek_3 bus +iL9TAERxS4A_1 bicycle +iL9hLZ_cXaI_0 person +iMfVd5_HBcE_0 bus +iMqYyOcO4Fw_0 umbrella +iMtt9-ROv_o_0 dog +iMukpec9Vmo_0 airplane +iMukpec9Vmo_2 airplane +iMxzNRMiKMA_0 truck +iM3tOs60qxk_1 airplane +iM8Lua_zTug_2 train +iNQNSmu2BD8_0 skateboard +iNWrFmCCfXw_1 bear +iNa2jg_1Vyc_0 cat +iNghTa86iWY_0 cat +iN-bJwlR2i8_1 bicycle +iOEuAB0dIs8_0 dog +iOH00pYaMhY_0 cow +iOJiYp298qc_3 airplane +iOJiYp298qc_1 airplane +iOd4NCiEBLw_4 airplane +iOd4NCiEBLw_2 airplane +iOgScMDTX_I_0 skateboard +iOvWAp7U61k_0 cow +iOzYv5IpFng_0 horse +iO7wHeFO6Js_1 cow +iO7wHeFO6Js_2 cow +iPWL6FSzmS8_0 umbrella +iPbg6G7tUVo_1 horse +iP98M3c1PJw_0 elephant +iQB9bgZJCwA_0 motorcycle +iQPn_3iB6aU_0 umbrella +iQYiakvHwnk_0 bicycle +iQZ1QN-A3JQ_0 elephant +iQfs0MyXA-s_0 airplane +iQxGihgbiM8_0 cow +iQ_2xA5J-Zg_4 bird +iQ_2xA5J-Zg_5 bird +iQ_2xA5J-Zg_1 bird +iQ_2xA5J-Zg_2 bird +iRI3AkfYykI_0 knife +iRLMFxqd6Vk_0 bear +iRTTlG8M9FE_0 car +iRTTlG8M9FE_2 car +iRTTlG8M9FE_1 car +iRWWnw104cE_0 bicycle +iRklgBUz8ME_0 bus +iRk0aHyYWdM_0 bird +iRlBKC_jfE0_1 horse +iRlBKC_jfE0_2 horse +iRlBKC_jfE0_4 horse +iRmfa0b6jJk_0 car +iRpibBNFoiY_0 knife +iRv5dyfU3ZQ_1 car +iRv5dyfU3ZQ_2 car +iRw-TCiikqw_0 horse +iRw-TCiikqw_1 horse +iR3sRTxVGtg_0 airplane +iR4rImxKjK0_0 car +iR4rImxKjK0_1 car +iR5Zew8NcYU_0 truck +iR5Zew8NcYU_1 truck +iR5Zew8NcYU_2 truck +iR5Zew8NcYU_3 truck +iR5Zew8NcYU_4 truck +iR5Zew8NcYU_5 truck +iR5Zew8NcYU_6 truck +iR5Zew8NcYU_7 truck +iR5Zew8NcYU_8 truck +iR5Zew8NcYU_9 truck +iSCFoiWm7Xk_0 bear +iSLNkNnHOXQ_0 bicycle +iSYNvKIuAXc_0 motorcycle +iSbXpgu-7qA_0 bicycle +iSeR1wQ4sl0_0 train +iTF1bWOtrew_1 bus +iTF1bWOtrew_2 bus +iTWyYCJO0FI_2 truck +iTbEmIOM3Bg_2 car +iTbEmIOM3Bg_0 car +iTbEmIOM3Bg_1 car +iT3LIkn9wh4_0 car +iT5clmXCTEc_0 elephant +iUDGzAPkGLI_1 airplane +iUEEnhAvRoY_0 cow +iUSZKTFqatw_0 airplane +iUX8ST-BSFg_1 bus +iUZnCaGp148_0 dog +iVH9ehKyau0_0 giraffe +iVRs9h04NcM_0 cat +iVzRc0RW_Y4_0 bird +iV4UGeMqQeY_0 dog +iV8NpvUXve4_0 elephant +iV8NpvUXve4_1 elephant +iV9CFIQTmfs_2 bicycle +iWP_wo9OSe4_0 bird +iWo66ztRt0o_3 boat +iWtj7if5cK8_1 boat +iWv1rxdhH1E_0 bear +iW1aIV39PQo_0 motorcycle +iW2g2j2VhbM_1 skateboard +iW2g2j2VhbM_2 skateboard +iXKQX0UfOqA_0 cow +iXKQX0UfOqA_1 cow +iXKQX0UfOqA_3 cow +iXh4-KWp9S4_0 horse +iXl114K8Y1E_0 car +iXxi1CQpbBk_2 cow +iXzEoHyipJM_0 truck +iX7b9tWhoKg_0 giraffe +iYGSi3t8Do0_2 cow +iYO5SD120r4_0 elephant +iYYdiX4oGjM_0 skateboard +iYjiqdn7fVk_0 bird +iYsgKLWI96c_2 knife +iYtDe_tT_wo_1 train +J-6KxfbaI6M_2 cow +J_HdQVHBeco_0 motorcycle +J_l7W4IMhJo_0 dog +J_n_3-KXet0_0 dog +KAGadYR0_LM_4 bird +KAGadYR0_LM_6 bird +KAGadYR0_LM_8 bird +KAKn8JmKESU_0 train +KAjM8ENV-F4_4 skateboard +KAxsc-ratJ4_0 horse +KA1A0hH1nVQ_0 train +KBIGw8UrUG8_0 cow +KBKaaEaIPRc_0 cow +KBNqKcj0xoc_0 train +KBP3moB3vz4_0 bird +KBRkCaaDjxU_3 bus +KBRkCaaDjxU_0 bus +KBe3_8RL_MI_0 person +KBoY6Pa8f_M_0 cow +KCbzyGKBwC8_0 train +KCdR8nTa3p4_0 skateboard +KCipBL5_e5M_0 horse +KCy-RKy_KN0_0 bicycle +KC1md4Q_DlQ_0 skateboard +KDSxlGW6eRc_0 umbrella +KDZsS4MjllY_0 motorcycle +KDaVTe3RbUY_0 horse +KDyYkCLIImM_0 knife +KD0Qm4z53a0_0 truck +KD0Qm4z53a0_5 truck +KD5LwDdfw0o_0 horse +KD9qqVSiPu0_0 train +KEGLFAbfrxs_0 motorcycle +KERo3bKldwM_0 elephant +KEW0fAHE_74_0 bus +KEW0fAHE_74_2 bus +KEagowlFwzI_0 cow +KEll3gbyIsk_0 truck +KEll3gbyIsk_1 truck +KEll3gbyIsk_2 truck +KExfLNe3IbY_0 airplane +KE2StZtSBfk_0 airplane +KE3O7h2RC-s_1 train +KE_UJpQulNU_0 horse +KFEorB8NRcE_0 boat +KFFTHBaYcbw_0 bear +KFJtVwXfusI_0 boat +KFRZOFB41Jk_0 train +KFk_7p6X-zI_6 car +KFk_7p6X-zI_1 car +KFk_7p6X-zI_2 car +KFk_7p6X-zI_4 car +KFk_7p6X-zI_5 car +KFnvvsS8eIE_1 knife +KGYrelsyNbk_0 airplane +KGbYHbiOfd8_0 giraffe +KGwEL4VozSA_0 boat +KG8zBA9Gudg_0 knife +KHBsJZVKzks_0 truck +KHG1hZsfjwQ_0 train +KHHyhgm1jZ0_3 skateboard +KHSjivlhX30_1 bear +KHcEC33udEg_0 cow +KHgLQP4XH9Q_0 skateboard +KHsYYKcSCSI_1 cow +KH0F1sJXKss_3 elephant +KH0k5jfUZGg_0 bicycle +KH8QlsYIT1M_1 bear +KIPptA8AzYg_0 horse +KIjf6QGqdsw_0 truck +KIjf6QGqdsw_1 truck +KIqePeskBSk_0 truck +KIy2LK1jsQ8_0 person +KI8Arf5-ekw_1 truck +KI8Arf5-ekw_4 truck +KJIBdy7_10k_1 bus +KJIBdy7_10k_2 bus +KJJBVXnnqIw_0 zebra +KJcXjJ5S9yA_1 dog +KJrPyuVxWRg_0 airplane +KJrPyuVxWRg_1 airplane +KJvAK-5ExwY_2 truck +KJ30mU3h4f4_0 bear +KJ7PQiJAKRM_0 elephant +KKKiTv_k23A_0 giraffe +KKO1QGoVQYU_0 elephant +KKpwJEMQYv8_0 dog +KKsKKMjHYGM_0 horse +KK06xbUhklk_1 bus +KLC8OgkQnNQ_0 boat +KLEKnTRMmo0_1 cow +KLGAT1GQYGA_2 bird +KLMz6_P5QmA_0 horse +KLNmQqyAs54_0 cow +KLUTy4pqLZ0_0 bicycle +KLVZqPfRuTg_2 bear +KLVZqPfRuTg_7 bear +KLlN4H-eGYI_1 skateboard +KL6-Iu09-C8_0 cat +KMNaWZZK2Os_0 skateboard +KMOOcO5yE9E_1 horse +KMXuGjMAt7k_5 bicycle +KMXuGjMAt7k_6 bicycle +KMXuGjMAt7k_3 bicycle +KMajGvVnol0_1 airplane +KMajGvVnol0_4 airplane +KMajGvVnol0_5 airplane +KMajGvVnol0_6 airplane +KMajGvVnol0_7 airplane +KMiZgk_f50g_0 dog +KMlZbzTdutw_1 car +KMlZbzTdutw_2 car +KMsL64iYfOA_0 car +KMtu1xThH2k_2 elephant +KMyoO6YYfZk_0 elephant +KNaoNUMT7m0_1 car +KNg4K_bbY5Q_0 train +KN5hxi96gW0_0 cat +KN-_uhPPfoE_0 cow +KOKdrC_foXo_0 airplane +KOOd5IO8seo_0 boat +KOSUWuFIQjQ_1 airplane +KOVZk2ixqc0_0 truck +KOgmgqcT21Y_1 bird +KOl1EDiK2e8_0 motorcycle +KO6T6QdloiM_0 bus +KO7Ncyx1-9c_0 train +KPJDHcE-qeQ_0 bicycle +KPYtlDJa43o_0 skateboard +KPfbBNvFcmA_0 skateboard +KPj_wrsubOE_2 bear +KPkzyHL7IPg_0 cow +KPmvpNEHsPk_0 skateboard +KPzWIuvRlr0_1 skateboard +KP4ApNQiIEI_0 cat +KQB-ZyriFmI_0 boat +KQg6eO2jr_Y_0 umbrella +KQ5mchVgTXo_0 truck +KRCLiP-JUsc_0 truck +KRCLiP-JUsc_2 truck +KRCLiP-JUsc_1 truck +KRW0HyqDLg8_0 dog +KRjN1nx8mcE_0 airplane +KSDxU99SF6g_0 motorcycle +KSHVle4SAM4_0 elephant +KSZ7nkMWOsU_0 skateboard +KSZ7nkMWOsU_1 skateboard +KSj7hZ7oO18_0 cow +KS1ge4vlv64_0 bicycle +KS4vsIYGaCM_4 truck +KS4vsIYGaCM_0 truck +KS8UAlyHoCg_0 dog +KS_fak2guWU_1 dog +KTAMaZKxpF8_2 train +KTDhNtr8XF4_0 airplane +KTDzrCvIVQs_0 dog +KTQQtbUbWbA_0 airplane +KTZ2Jsj6_ig_0 truck +KTdzxOjJNgI_0 car +KTsTGNqrFuE_0 umbrella +KT7YiBWXqNk_0 airplane +KUZxnRyU2e8_0 cat +KUbSnz1yWxc_0 knife +KUc8Kw30V1Q_2 truck +KUc8Kw30V1Q_3 truck +KUc8Kw30V1Q_4 truck +KUgY_2bsBC0_1 skateboard +KUhzqYZoYCI_0 cow +KUkcrqulhqg_0 cow +KUlpA-cpCpM_0 horse +KUumLype4AE_0 elephant +KVFlTVdKQVw_0 horse +KVJCkQzQbMs_0 person +KVmS-yiYu2c_0 bicycle +KVzW5MPT25A_0 airplane +KV0o55FO4XA_0 skateboard +KV3jtdzXA9U_0 dog +KV__RQ75-vw_1 cow +KWJiCsomGTA_0 cow +KWLl4vVumIs_0 truck +KWSDQebY3dA_0 cat +KWwbFKgHqW0_0 car +KWxd8IQ9_a0_0 cat +KW10UlO19uo_0 bus +KW4ovUCg7uU_0 bicycle +KW4ovUCg7uU_1 bicycle +KW5S4gsTVaQ_0 knife +KW7gAr7kgow_0 dog +KW_6RyjLGPI_3 horse +KXCQuD9phb4_1 bird +KXENib5sk78_0 cat +KXLWiz5ZUh0_1 train +KXLWiz5ZUh0_2 train +KXdF5__0yVQ_0 cow +KXf6k7PrX7E_1 elephant +KXf6k7PrX7E_2 elephant +KXrQkw1WPnk_0 bird +KXzu3MDaZn8_0 car +KYK_Wg8JlTg_0 skateboard +KYK_Wg8JlTg_1 skateboard +KYTRCD2p-8Y_0 motorcycle +KYZzKKYD7Yc_1 horse +KYaB_EEk344_0 cat +KYc__uUZkwc_3 bicycle +KYd6wCR0jVc_1 horse +KYd6wCR0jVc_0 horse +KYs4hm9X1Rg_1 bicycle +KYvXJXEbUMg_0 bird +KY0x7p41Q_A_0 cat +KY04L4VTsXc_1 airplane +KY04L4VTsXc_2 airplane +KY7D2Y5MQSo_0 horse +KZAf2uPS-us_1 horse +KZAf2uPS-us_0 horse +KZFniGi-fes_0 dog +KZJcgoY3r3U_0 airplane +KZSLQpdbGps_0 motorcycle +KZYe6pqrLaQ_1 dog +KZhX7tDfYIA_0 bus +KZl_XArvSXk_0 horse +KZ4OuA1t3ZY_0 elephant +KaUGkf-3N-4_0 horse +KaiX3d83DWA_0 zebra +Kaj5B4nrWJU_0 skateboard +KapwOqVyzUk_0 cat +KaqToIfNxMY_1 bicycle +KauPg8P2kC4_1 airplane +KazepPKQz1M_1 cow +KazepPKQz1M_3 cow +KazepPKQz1M_4 cow +Ka978At0k0Y_0 airplane +Ka-4ZfE0GMQ_0 motorcycle +KbA6UDJg1LE_0 train +KbA6UDJg1LE_1 train +KbGl5jqOQ7o_0 cat +KbRIbBeLBsM_3 motorcycle +KbosOWR7ZSg_1 boat +Kb3lxArGO8Y_0 bicycle +Kb3lxArGO8Y_1 bicycle +KcDpzG8kKho_0 cat +KcL-zz1sb6I_0 dog +KceqMsKO-zc_0 cat +KcpGWNCD-uk_0 cat +Kct9k6Q2YM8_0 car +KcuEc9WwYSQ_0 cow +KcuEc9WwYSQ_1 cow +KcyLR4RxylE_0 cow +KcyMYgt62Go_0 horse +iY5Sh73Lem0_0 bird +iY6eEC8uY4E_2 train +iY6eEC8uY4E_1 train +iY9QlFmEBFY_0 motorcycle +iZsSK_iIOoA_0 horse +iaGO2mTgoPo_1 bicycle +iaGO2mTgoPo_3 bicycle +iaWSU1ISWXQ_2 airplane +iaWSU1ISWXQ_0 airplane +iaflfMXT7QQ_0 boat +iamGAsKNRhY_0 train +iana0Lz1gs0_1 motorcycle +iasZRb9p3lg_0 motorcycle +ia1XmqAwn7M_0 bus +ia6R3fqdlnE_0 bear +ibcBDIGpMfo_1 bus +ibd-Wxcr_x4_0 horse +ibpj369yzbw_0 umbrella +ibxmk7cGhTQ_3 horse +ib5fWzJWV5A_0 cow +icDyRH3P-nM_0 airplane +icGjENlINL4_3 skateboard +ich9rXZWjGY_0 car +icic9NkCnf0_0 cow +icnuBKQZNBg_2 bus +icnuBKQZNBg_0 bus +icnuBKQZNBg_1 bus +icxOfJQ-l9I_0 car +icxOfJQ-l9I_1 car +icy3pC1Q0eA_0 cat +ic7k8fkUDXs_0 cow +idnOwkwaCm4_0 horse +idnSzg_rV_k_3 bicycle +idoGYHCXGJs_0 elephant +idq0Jqw8Oa0_2 elephant +id1yzZ3HkTs_1 knife +ieCL4lz7IJw_1 boat +ieOpqoYhMOQ_0 truck +ieOpqoYhMOQ_1 truck +ieOpqoYhMOQ_2 truck +ieULzTIs9ls_0 cow +iedgnWefCA0_0 airplane +iedgnWefCA0_2 airplane +iedgnWefCA0_3 airplane +iewlg5CteEs_1 airplane +ie8gkh6nQcA_0 train +ifKKR-gCLSk_0 cat +ifRQKBKIRSI_0 dog +iff3KW8leKw_0 airplane +iff3KW8leKw_1 airplane +ifghH4Jo8D8_0 truck +if31ci9xz_8_4 bicycle +if31ci9xz_8_1 bicycle +if31ci9xz_8_2 bicycle +igGtS-jZCQM_2 car +igGtS-jZCQM_0 car +igLVqNKw-yE_0 bird +igMWvnK1jEE_0 giraffe +igMWvnK1jEE_3 giraffe +igMWvnK1jEE_1 giraffe +igQUACDrluw_0 horse +igU61tmxeE4_2 skateboard +igWsPt0nelg_1 bus +igcpSvypduQ_0 truck +igcpSvypduQ_1 truck +igdqmLfZ_cw_0 airplane +igjBIRwjlko_1 dog +igm6X4CZLmk_1 bus +ignREcFRyaQ_7 airplane +ignREcFRyaQ_8 airplane +igwghbZYjgg_0 airplane +ihMDaxeTpZs_1 horse +ihTjIMWOjuQ_1 motorcycle +ihUpF22zo4M_0 train +ihUpF22zo4M_1 train +ihWWle00xEE_0 motorcycle +ihh0J0AaWBs_0 train +ihh0J0AaWBs_2 train +iiA0hIRwwJA_0 train +iiSWvRk3YfU_0 bird +iiextKoe48U_0 cat +iigPPpoo0W8_0 knife +iiiOUcmwJPw_0 cow +ii0PDMs-a0o_2 car +ii2ghwDAI3w_1 airplane +ii_sG2SkeXM_0 cat +ijB2Yh71VIg_2 bear +ijJAWtORd2w_0 truck +ijJAWtORd2w_1 truck +ijVpcnt8HN8_0 bus +ijXmwWOLvpM_2 horse +ijXmwWOLvpM_1 horse +ijdipMmraWc_0 truck +ijwhkKzyWE8_0 airplane +ij0zLKtr0sA_0 bird +ikGzd6ivk64_0 motorcycle +ikKFRS8Hivk_0 bear +ikVu6XfZ3_A_1 bicycle +ikafEc8p6rI_0 bicycle +ikafEc8p6rI_5 bicycle +ikafEc8p6rI_1 bicycle +ikafEc8p6rI_3 bicycle +ikafEc8p6rI_4 bicycle +ikfmjumoUlM_2 train +ik868nOtrZo_4 bus +ik-jgdZW4Ek_0 horse +ik__zZ1HZNg_1 giraffe +ilKErQ8ojz0_0 umbrella +ilKErQ8ojz0_2 umbrella +ilKErQ8ojz0_3 umbrella +ilKW98Qvobg_0 skateboard +ilvsheh1Cqs_0 dog +ilxXSgvtFgw_0 cow +imEWC_Q-BSg_1 car +imcRxs0K7H8_0 bus +immhpBi8eWw_6 skateboard +im_FneG303c_0 dog +inEZ7ZLAS7s_5 skateboard +inJLKInP5kw_0 dog +inZmM8c-9NI_3 horse +inedUh-74-A_4 truck +inodVLfFogA_0 train +inynAJrGhVU_0 motorcycle +in061qZJjWI_0 dog +Kc8WMzLKvvk_0 cow +Kc-f3X7O-pw_0 cat +Kc-x73DCumI_0 truck +KdGgVhM0Ihg_0 bird +KdKlI0ZN6qo_0 airplane +KdQQqsAuU7o_1 bicycle +KdUSJz6UWLQ_0 giraffe +KdXRnPKKeTU_0 bird +KddQJwFfv9s_2 skateboard +KdjMgSuON5w_5 bear +KdpUjVhfjG0_0 person +KdyadP7Y1nU_0 car +Kd9Em2ABfN8_0 cat +Kd-jTE5-2uE_1 motorcycle +KeMITKdjHtk_0 cat +KenV2bIQf1o_0 bicycle +KevYmLAAigc_1 train +Ke3R9FrGLcY_0 dog +KfJU66erPWo_2 knife +KfMO45jz-68_0 boat +KfS_UKkbQAA_0 bird +KfTV1TFY2b8_0 bird +KfaTw0euPQA_0 motorcycle +KfjmKiZzSlY_0 cow +KfjmKiZzSlY_5 cow +KfkKe7q45KA_1 motorcycle +KfkKe7q45KA_2 motorcycle +KfkKe7q45KA_3 motorcycle +KfpCncLoqOw_0 cow +KfwbVpPI0nU_1 motorcycle +KgAFD_JvgrQ_0 cow +KgD3H0APDy0_0 bear +KgNS5HwFF_c_1 elephant +KgVEQYicksA_0 cow +KgY5OrVnzv4_0 cow +Kgo7SWtDdz4_1 dog +Kg3xuyjNU7w_0 umbrella +Kg7Qk4Gx9n0_0 motorcycle +KhKZwdKiqms_0 cow +KhKcHaH_ALo_0 horse +KhPKq8O30VM_0 bicycle +KhPKq8O30VM_2 bicycle +KhPKq8O30VM_4 bicycle +KhuC9snWfpI_0 cow +Kh7rAO7jCGc_0 airplane +Kh_KwBHfGQ8_0 cow +KiHy8IMQ6zA_0 airplane +KiaUDlPLxzk_1 bear +Kixl-Wmj3kg_0 motorcycle +Kjaag6B-MIQ_1 skateboard +Kjca1u6P3NE_0 cow +KjiI2E3l3Mk_1 truck +KjiI2E3l3Mk_2 truck +KjqaJ25GUBI_0 bus +Kj3dRtd4xQI_1 cow +Kj3dRtd4xQI_0 cow +KkD23XYUG9c_0 umbrella +KkMNGzvNkg4_9 bird +KkNYBz9ZaVA_0 bird +KkNYBz9ZaVA_1 bird +KkPf9AB1HZo_1 elephant +KkRq1ogJq-4_0 skateboard +KkXTT9C4xfc_0 cow +KkdSKHS7P50_1 skateboard +Kks6eJqnZLQ_0 dog +Kks6eJqnZLQ_2 dog +Kks6eJqnZLQ_3 dog +Kks6eJqnZLQ_4 dog +Kks6eJqnZLQ_5 dog +Kk6BgYl9OjA_7 bicycle +KlEK-vv3DVo_0 bear +KlENnLskuCU_0 cat +KlG0czACle4_1 cow +KlG0czACle4_0 cow +KlG0czACle4_2 cow +KlG0czACle4_3 cow +KlqbHICh4G4_0 train +KmJhshcviXA_0 knife +KmbMzgXFdKs_1 airplane +KmbMzgXFdKs_2 airplane +KmbMzgXFdKs_0 airplane +KmfmqwmQneM_0 bird +Kmr5uVYVSDo_0 car +KmuV8XfAjvw_0 horse +Km3GmgNJlL8_0 train +Km3GmgNJlL8_1 train +Km3GmgNJlL8_4 train +Km7w520V5vs_0 airplane +KnIxVxIho9w_1 bird +KnN2yDre-aM_0 boat +KnTu6keaGs0_2 elephant +KnTu6keaGs0_0 elephant +KnXPxa1RzmU_0 cow +KncYvkV6rwc_0 boat +Knql8E5Khc8_0 elephant +KnuD87lrS8w_0 skateboard +KnvGRqLQ5iM_1 train +KoA6bPmALeA_0 cat +KoXgGmdVCBM_1 bicycle +KoXgGmdVCBM_10 bicycle +KoXgGmdVCBM_2 bicycle +KoXgGmdVCBM_3 bicycle +KoXgGmdVCBM_4 bicycle +KoXgGmdVCBM_5 bicycle +KoXgGmdVCBM_6 bicycle +KoXgGmdVCBM_7 bicycle +KoXgGmdVCBM_8 bicycle +Kosi26dm76A_0 horse +Ko5wlBGl200_0 horse +Ko_Nx24OGxM_2 airplane +KpDzoM2xtwc_2 truck +KpDzoM2xtwc_3 truck +KpDzoM2xtwc_5 truck +KpHFaYsgWrg_2 elephant +KpHFaYsgWrg_1 elephant +KpVflkpC7d4_3 bus +KpVflkpC7d4_5 bus +KpVflkpC7d4_0 bus +KpVflkpC7d4_2 bus +KpXxo2n6AYw_1 motorcycle +Kphl0WRacss_0 knife +KqAvXx4bN5k_0 cat +KqQgFUEAS-M_0 train +KqavxpR698k_6 dog +KqavxpR698k_0 dog +KqavxpR698k_1 dog +Kqfo6_qcthc_0 car +KqjhaIJMY5U_0 cat +KqnqyAczaqs_4 bus +KqqyldSpJh4_0 horse +KqqyldSpJh4_1 horse +KqzkADa-Lqw_1 train +Kq1x16QvM1g_0 dog +KrGJjt0yq-s_1 bus +KriNb3dhqVQ_1 skateboard +in9LFcixPXo_0 skateboard +ioEMtB2bP6o_0 bird +ioESr4H79KY_0 boat +ioGc_R8NJow_0 cow +ioKahF3aFWw_0 horse +ioKahF3aFWw_1 horse +ioOHxrHumIk_1 airplane +iobYquCNk5k_0 cow +iojaZ646ie8_0 skateboard +ipLnwxta1Jc_0 boat +ipOJVFLMLIk_2 bird +ipOJVFLMLIk_0 bird +ipgB9KXnzK8_0 horse +ipg_y1T2OsM_0 cow +ipg_y1T2OsM_1 cow +ipqQlNsINy8_2 airplane +ipt6gWgCgis_0 truck +ip5xVRJOpP8_0 umbrella +ip8BFE94TKo_0 airplane +ip8BFE94TKo_2 airplane +iqDJJqLVBBk_1 elephant +iqExYW2fPfc_0 bear +iqicuLBaF_g_0 truck +iqlKzflOl00_1 bus +iq1FaWFylpI_0 motorcycle +iq6izTYp-DU_0 motorcycle +irBsER6ITHw_2 skateboard +irDs_vWExnM_1 bicycle +irDs_vWExnM_2 bicycle +irU_BJXoU9I_1 cow +irWY8s-JuBs_3 airplane +irWY8s-JuBs_0 airplane +irWY8s-JuBs_1 airplane +irWY8s-JuBs_2 airplane +iramP9ihj_w_1 bird +irgacv6LobE_0 motorcycle +iri1MtEgOjQ_0 bear +irs2O6YOB5I_3 elephant +irs2O6YOB5I_5 elephant +irs2O6YOB5I_1 elephant +iruY-BU0rpg_4 elephant +irzcPf--6uQ_0 train +irzcPf--6uQ_4 train +irzcPf--6uQ_5 train +ir4EYn7Fz5A_0 dog +ir5E9O2Tonk_0 boat +ir7Dq5dPxOQ_0 horse +isPplb7aotI_0 boat +isPplb7aotI_3 boat +isU4229ndXM_0 cat +isfwmnXNmeM_2 cow +islz_HxqOnI_0 bird +isvvRHvNuIw_4 umbrella +isynk11V9s8_3 airplane +isynk11V9s8_1 airplane +isypXPZMgns_2 boat +isypXPZMgns_3 boat +itKyPMv5z0Y_0 umbrella +itKyPMv5z0Y_2 umbrella +itc-A2zwSGM_0 dog +itrvgHryhIY_0 train +its4C4ty2oA_0 skateboard +ittQcsrECUE_1 bear +ittQcsrECUE_2 bear +it1EatlrBkg_0 cat +it3KS-r39EQ_1 knife +it3hCzfmyfs_0 cow +it6DtEGdhas_0 cat +it8Fid-mqRQ_0 truck +iuEbY8B4Qo4_0 cow +iuEbY8B4Qo4_1 cow +iuFmdispR2U_0 bicycle +iuRmu4BN6bw_0 train +iumTd9IGDho_0 train +iusgUMlrYFA_0 airplane +iutdZMWA8f0_0 person +iuumrgHW8zM_0 umbrella +iu3sd1qnr8g_0 car +iu9Av4HCmiw_0 knife +ivDeIaJYIlE_0 truck +ivT103z2bwc_0 giraffe +ivdfO5VqKo4_0 cat +ivgTXhIqccY_0 cat +ivi1frbFnGw_1 giraffe +iwFO7lcVjKc_2 cow +iwFO7lcVjKc_0 cow +iwFO7lcVjKc_1 cow +iwX4cgfQn5s_0 bird +iwczN64AC9Y_0 bus +iwp5aVOXWaM_0 airplane +ix8S6CRuUFg_3 bear +iyAvqfMVOeA_0 cat +iyLZZlL-B80_0 cow +iyMbIICjtcg_0 cow +iybJfH6iVdU_0 bus +iygW3-Ovcic_0 cow +iyn1OZFmvXE_2 bird +iyz9Lq13Mcg_0 cow +izbTUTqkG7c_0 cow +izx70OqPYBc_0 dog +iz9-Vl4e9po_0 train +iz9-Vl4e9po_2 train +iz9-Vl4e9po_3 train +iz-BT0NAs6k_1 knife +i0Eg02B3JoM_0 elephant +i0Ez1KT7sTo_0 horse +i0ZE0kXl5oU_1 skateboard +i0eMgZ0riHI_2 bird +i0gg-mJNKlU_0 cow +i05OPAsrmJI_3 elephant +i05OPAsrmJI_1 elephant +i05OPAsrmJI_2 elephant +i09cuoC14q4_0 bear +i1DfyWe0Jh4_0 cow +i1DfyWe0Jh4_1 cow +i1NfFxZmBSA_0 bus +KrvsSuIgrJQ_4 horse +KrvsSuIgrJQ_1 horse +KsT2_VxPkb4_0 knife +KsXzFCpHMPU_0 giraffe +Ksyud0_i1zI_0 bus +KtINrfbQSXk_0 knife +KtV59qZg7BU_0 truck +KtX4x9k3J2A_0 train +Kthi3i2WM3s_1 skateboard +KtkN77asAj4_0 horse +KtplZx6_ecU_1 knife +KtqvSap6uig_0 skateboard +Ktxb4OmaAjA_0 car +Kt3uQcxNltk_0 zebra +Kt9neWWjkHM_2 bear +KuBa9tep8xk_0 bear +KuQgP71vfZ0_0 train +KuYBJ90zNYw_0 umbrella +KuYjBUvU-ws_0 umbrella +KuYrzelSfIw_0 car +Kulks153IS8_0 truck +Kulks153IS8_1 truck +Ku0XhH2YeG4_0 bear +KvH6JyHG3H8_0 motorcycle +KvH6JyHG3H8_1 motorcycle +KvLXxaGooPk_0 cow +KvPLPO4A5R8_0 knife +KvRsu4xefwo_0 person +KvcxzJxNkkU_1 bird +KveRZ7dBNGU_0 boat +KvgupPBw5rc_0 cat +KvjDDIthDDM_0 cow +KvkOTtqxJlo_1 cat +KvsaKWirK7Y_0 skateboard +Kv0ui3mEWGE_0 horse +Kv0ui3mEWGE_4 horse +Kv0ui3mEWGE_1 horse +Kv0ui3mEWGE_2 horse +KwkcPYl8Lv4_0 cow +Kw7t6l8h2Ns_0 bear +Kw7t6l8h2Ns_1 bear +Kw8037OwDjc_0 truck +KxWI3M2FGOw_0 horse +KxZXot9AIY4_0 truck +KxflrYttp20_0 bird +KxlTxdqDDzo_0 cat +Kxuqb_htGwY_0 giraffe +Kxuqb_htGwY_2 giraffe +Kx40to29YnE_0 skateboard +KyDXCruNNj4_0 horse +KyUM64yfNCA_0 horse +KyWUn_bj5rM_0 motorcycle +KyZWWIsQUbg_0 skateboard +KyZWWIsQUbg_1 skateboard +KyaKfhOfKhE_1 bird +Kyt325n06oI_0 cat +KywHhzvsm3Y_0 bird +KyyS9PYJ9Zo_0 truck +KzK3iwncxbY_0 bicycle +KzK3iwncxbY_1 bicycle +Kzc17TzutkM_0 skateboard +Kzc17TzutkM_1 skateboard +KzyD-e7N2D4_0 train +KzyD-e7N2D4_1 train +Kz3zulHzEE4_1 train +K0CwoXVMp0M_0 bicycle +K0L3_2UquEY_0 boat +K0Zt-EcXkj8_1 airplane +K0cgwgX_8fo_2 boat +K0xs4bH65_Q_1 motorcycle +K02fUURwCiY_2 car +K02fUURwCiY_0 car +K02fUURwCiY_1 car +K1Qbgm__2iE_0 cat +K1ccfBgR_kg_0 truck +K1-s4sk63R4_0 horse +K1_J3d_yH64_0 motorcycle +K2F6TCgVfR0_0 boat +K2hV4KVruLc_0 airplane +K2my8qWjyn4_0 cat +K2yjgwFV15k_1 motorcycle +K2yjgwFV15k_0 motorcycle +K26jSjClwaQ_0 skateboard +K3Cgw_EFdbw_1 motorcycle +K3DniaFnn9E_0 cat +K3KhxEuf8mY_0 horse +K3KhxEuf8mY_5 horse +K3Ov5rPJ2LE_1 horse +K3XsEMr7Qt4_0 person +K3qgW4Y3yrk_0 motorcycle +K30LSGFu6hs_0 motorcycle +K4RE7AZWGv0_0 car +K4U_AmqQFDY_0 bear +K4VnWy2-8xQ_3 car +K4ec2MqDkPw_0 train +K4fCUNjbdf8_0 motorcycle +K4wp52Zn5d4_0 horse +K5NooGgwD1E_0 horse +K5NooGgwD1E_1 horse +K5pBkPv_1sg_5 car +i12y-zJl-nA_0 cat +i17EaDmRPCg_0 umbrella +i2Yjl6kF8iY_2 airplane +i2Yjl6kF8iY_0 airplane +i2cujNbMSKc_1 skateboard +i2diIHrCsbk_1 bird +i3AK_cujBxY_1 motorcycle +i3BpSeFJdgo_0 cat +i3HeGqUyibM_4 bicycle +i3HeGqUyibM_9 bicycle +i3HeGqUyibM_12 bicycle +i3LFAemLFW0_0 horse +i3Z5pFF2dH0_0 bird +i3a4U770GtE_0 person +i31nG3E36WE_0 knife +i32p4KoRD2o_0 train +i33S_D8TBc4_0 dog +i35wpbpl8qY_2 boat +i38dpYWvJN8_0 umbrella +i38dpYWvJN8_1 umbrella +i4CFI7MtlRs_0 cat +i4ExemfAEO8_0 bicycle +i4IpgDIqTrs_0 boat +i4RZtd1cCw8_0 umbrella +i4bRNqQ32MI_0 cat +i4clJpNvw4M_2 bus +i4hqN47R0oU_1 train +i45JoRzDdI0_0 cow +i46jok5cjyY_0 horse +i5GJ6mIp8zc_0 boat +i5G6RkcL4m0_0 cat +i5OdBE4QG6c_0 train +i5g87UeVkBU_0 horse +i5g87UeVkBU_1 horse +i5sT2ifoPyM_0 knife +i6MF-PGtJiE_1 train +i6WTNPwIjW8_0 cat +i6aJqhBh5wg_0 skateboard +i6j6P7ITxYg_0 cow +i6vwTWezXmU_1 boat +i66Gsq6zzqI_0 motorcycle +i6-YQ6rSnDI_0 cat +i6_oBTD2-YA_5 bird +i7P2tq4TS_4_2 bus +i7UQGL5uxvw_1 skateboard +i7WeV3CfJV8_0 knife +i7a8sQcVRgE_0 truck +i7umCLnxVXw_0 cat +i791If0qoBU_5 knife +i8KQCu2cMAc_2 bicycle +i8KQCu2cMAc_4 bicycle +i8bVI1667K4_1 truck +i8hjK42sseE_0 motorcycle +i8lG7Ux3wlc_0 dog +i8nbuADJjmE_0 car +i8nbuADJjmE_1 car +i8nbuADJjmE_2 car +i9PUn4sF30g_0 motorcycle +i9T-NwSBqPE_1 knife +i9VWkuQHBls_0 horse +i9nmvkDiFGc_0 cow +i9sP7mWuQ_8_2 motorcycle +i9sP7mWuQ_8_1 motorcycle +i9u4vsQUBTQ_0 horse +i90TDb7evCY_0 truck +i9_FG4-2VIM_0 skateboard +i-CQVFq1JI8_1 bicycle +i-CQVFq1JI8_3 bicycle +i-T9Q2g8xbk_0 airplane +i-kodOT_ufM_0 cow +i-nP7aFTZb8_0 bird +i-xdWDN7Eys_2 knife +i-3aAuwOmxc_0 truck +i-8W-K4y3nY_0 train +i_HHc85mP4Q_0 train +i_h0vOCrd_U_0 airplane +i_h0vOCrd_U_1 airplane +i_iXTMX4Vls_0 cat +i_nZ8ImBf18_1 bicycle +i_nwFUP7QJM_0 knife +i_4c71HPXOI_0 giraffe +i_-PIEIGkQE_0 horse +i_-PIEIGkQE_1 horse +jAH-80rHWKY_3 bear +jAW8iLGAgdQ_1 bear +jAW8iLGAgdQ_0 bear +jAh4oBD0Bsw_0 train +jAnV_6fFGnI_0 cow +jAy3VhkJauE_2 knife +jAy3VhkJauE_5 knife +jA6aZl1f4Wg_0 bicycle +jBMmFLPc7nA_6 bus +jBMmFLPc7nA_0 bus +jBMmFLPc7nA_3 bus +jBMmFLPc7nA_5 bus +jBTJgbVspOA_0 airplane +jBl50J7bOEw_1 airplane +jB1IT1aBj-Y_0 dog +jCDFU72N7Mc_1 skateboard +jCJGjjNBSk8_1 airplane +jCJGjjNBSk8_0 airplane +jCMWNtCzuqU_0 knife +jCUnLxCoYMA_0 motorcycle +jCY67ybfyqU_1 cow +jCZx5dn_4KA_0 bear +jCcW1MW6PTE_0 truck +jCcW1MW6PTE_1 truck +jCiwgfC1uN0_0 dog +jCtFgJ1qhJE_0 bird +jC5Px208OVY_4 horse +jC5Px208OVY_5 horse +jC5YGckTiIU_2 train +jDFqxB4rC7M_0 cat +jDJNC5fzvfA_1 motorcycle +jDYks7hSKbg_0 truck +jDbHjQZ5R70_0 airplane +jDbHjQZ5R70_1 airplane +jDdFavN2eWY_0 dog +jDgpggXdBIc_1 motorcycle +jDgpggXdBIc_2 motorcycle +jD2RjyxG6ow_0 motorcycle +jD4621IQz3w_0 dog +jD4621IQz3w_1 dog +jEASZOuNSS0_3 skateboard +jEASZOuNSS0_0 skateboard +jEASZOuNSS0_2 skateboard +jEEOkCjU9y0_0 bear +jEJZ76_xhog_2 bear +jEQDhb_Zewo_0 cat +jEYG-qIv34o_1 cat +jEYG-qIv34o_0 cat +jEfwj-JzFXo_0 person +jE1Rq_Ot02M_0 dog +jFAm4tikj6E_0 horse +jFSIX_KuRK8_0 horse +K5p31PQkx3I_1 horse +K5q4FoXnLwI_0 train +K5sQWplX-D8_1 skateboard +K5sQWplX-D8_2 skateboard +K6JHTga6VU8_0 airplane +K6SFafS3Zv8_0 car +K6SFafS3Zv8_2 car +K6jf51to7dU_0 horse +K6jf51to7dU_1 horse +K6sKjN_MOsE_1 bear +K6srgkSvZdw_1 skateboard +K6srgkSvZdw_2 skateboard +K6vEY0vOlSg_1 train +K66dqG9OJuo_1 dog +K66dqG9OJuo_0 dog +K6_WEh-eizw_1 airplane +K6_WEh-eizw_2 airplane +K6_WEh-eizw_4 airplane +K7uSHqISah0_0 train +K702Tx5vkp4_0 horse +K78iEUHTTZc_1 cat +K8aa-7brUTs_0 bear +K8vGdEhh_jU_0 bicycle +K81vEhukX4U_0 motorcycle +K9LhqtvfZ10_0 dog +K9LhqtvfZ10_3 dog +K9LhqtvfZ10_4 dog +K9LhqtvfZ10_5 dog +K9TPOifKCmU_0 motorcycle +K9hTkmr_71A_2 car +K9jCx7G3_Mw_0 knife +K9kNamc2c5Y_1 dog +K9kNamc2c5Y_0 dog +K9wE7VzJD00_0 train +K-Dz6gr96Lo_0 dog +K-s8RPMLRw4_0 bird +K-s8RPMLRw4_2 bird +K-x3x3kGGqg_0 dog +K_PGa9Eo6mo_1 dog +K_VS3tyB-Cc_0 person +K_Z28TO4stg_0 bird +K_h1L3P_j1M_0 bird +K_pO-MBS7lI_0 dog +K_qFWKniImU_0 skateboard +LAKF499FHX0_0 train +LAKF499FHX0_4 train +LAKF499FHX0_1 train +LAKF499FHX0_2 train +LAKF499FHX0_3 train +LARRHwtW8fE_1 dog +LAZoyKF7lbQ_0 truck +LAZoyKF7lbQ_2 truck +LAZoyKF7lbQ_3 truck +LBJEbJfzvW4_1 skateboard +LBOXDMZvtBY_1 train +LBnsLkuQ8kE_0 person +LBwm49n5rKo_0 motorcycle +LB6fi4oTKvQ_2 dog +LB8Wc8hU4Hc_0 airplane +LCGZmNGyPhM_0 boat +LCghaNtVeM0_1 knife +LCjQb5zLTCs_0 train +LCoIwiCBlW4_0 dog +LCxiwbrpEFI_2 bus +LC5Qly11BZs_0 train +LC5q2G2pxT0_0 bus +LDEju5sQWOU_1 bear +LDH_eiO0aFE_0 boat +LDJ9xB-n5Sg_0 dog +LDJ9xB-n5Sg_1 dog +LDQiOOCMhs4_0 truck +LDQqhsLKyjs_0 train +LDYFndJjRGA_0 skateboard +LDgpZlJ_QYM_0 boat +LDh-8GoBSLw_0 bear +LDlR_gDbVFk_0 airplane +LDvN2rB8p44_0 train +LD-8yzPoOIQ_0 car +LD-8yzPoOIQ_1 car +LD-8yzPoOIQ_2 car +LEH61oMv2So_1 train +LEIkLV_S5yA_0 cat +LEP6ZOl5iw0_0 horse +LEUCQjNIm9E_0 knife +LEYBNQUwruU_0 dog +LEiolk6i9RI_0 horse +LEmU61Tdqxs_1 motorcycle +LEverFsHygc_1 airplane +LE2ks85I17U_0 bird +LFDqskJozig_1 skateboard +LFMUePhHPAk_1 car +LFZYYpjP3FA_0 knife +LF4xVBfV5SI_1 bird +LGRkVRP-RTs_0 car +LGgzD_ng3aA_1 bear +LGrMlBi0l6Y_1 boat +LGuSLUeKcTo_0 bird +LG0w1oTdXgY_0 bird +LHEuYW96FG0_0 bear +LHEuYW96FG0_4 bear +LHbVe_bjGp0_2 dog +LHbVe_bjGp0_0 dog +LHbVe_bjGp0_1 dog +LHmvAqv6kYE_0 zebra +jFneoJr36o8_0 car +jGCw13fkf0Q_2 motorcycle +jGPtq4pO8Ug_0 car +jGTNsTUkNUw_0 cat +jGTr1LSaGGw_1 bicycle +jGTr1LSaGGw_2 bicycle +jGTr1LSaGGw_0 bicycle +jGlNsqDOz8Y_0 horse +jGqRX9IwGI0_8 bear +jHK3JYa_Ypg_0 umbrella +jHM867g1K8k_1 horse +jHM867g1K8k_0 person +jHy5deaCjQE_0 dog +jH_YxkU_JwE_0 motorcycle +jINuUqU6sJI_0 dog +jIP9FdmB0_E_0 train +jIbmC5sed8I_1 airplane +jIjEX8I5SHo_1 bird +jIjEX8I5SHo_2 bird +jInMbuzvtiQ_0 umbrella +jInMbuzvtiQ_1 umbrella +jI0xgoZ8QDA_0 boat +jI1Swlwj_wc_0 horse +jJMefDe4r9w_1 skateboard +jJR-emvmi9s_0 bear +jJR-emvmi9s_1 bear +jJf_N_p-Gjo_1 skateboard +jJnz3tS1uME_0 motorcycle +jKBU4c1AdSQ_0 cat +jKv6Q1RRxVM_1 boat +jLBSOa5iDgE_0 horse +jLR7LmbNekc_0 motorcycle +jLXuZdAveV0_2 boat +jLXuZdAveV0_0 boat +jMNaKigE1eI_0 truck +jMNaKigE1eI_1 truck +jMVeJ3RbcH4_0 car +jMaYIgpjxlk_0 dog +jMmjaxXWaUk_1 bus +jMo01X2mBq0_0 bus +jM79QETqts8_1 horse +jNCq29f3J8Y_0 airplane +jNE_FcqbQN8_0 motorcycle +jNJJgAg79KA_1 airplane +jNJJgAg79KA_0 airplane +jNKO9msLe34_1 airplane +jNKO9msLe34_0 airplane +jNSTcIQwl_g_3 train +jNSTcIQwl_g_1 train +jNSTcIQwl_g_2 train +jNllRQ66Re4_3 dog +jNn7v2MFg_U_0 truck +jNsEePln1_U_0 bird +jNsEePln1_U_1 bird +jNt8Vn-WKRI_1 horse +jN-BXoM15Qs_0 cat +jOQ0W0Z_-Uo_0 dog +jOl4m5QdOZQ_0 bus +jPaVdR2IRu8_0 airplane +jPiVFMGvHbM_0 train +jPiVFMGvHbM_1 train +jPrY_Xz0CDM_0 knife +jP5RhcwO4E4_1 dog +jP7mwBStU3w_0 dog +jQBc1CqjGOk_0 skateboard +jQCrA8Bjbp8_0 bird +jQXYSlXk7_c_3 bear +jQXYSlXk7_c_1 bear +jRIy_wUojcs_0 car +jRR6sU59uTo_0 airplane +jRTkny0bdY0_2 motorcycle +jRTkny0bdY0_1 motorcycle +jRh5WphQGDI_0 horse +jRqdnQ8HlwQ_0 airplane +jR7eq8CAmbs_0 airplane +jR-Cbp3qBJI_2 horse +jR-Cbp3qBJI_0 horse +jSS6b2iz2hk_0 knife +jSk-3X-hjyg_1 knife +jStwl7WfsVE_0 skateboard +jTAz5HO8mQw_0 cat +jTHDoLyfTLc_0 dog +jTQ5A95TKw8_0 cat +jTYsK4JKns8_0 giraffe +jT1mDaHStHU_0 train +jUDnkkvVKNo_0 airplane +LIw68irBLtE_3 airplane +LIzgqx7Ykxw_0 airplane +LI286rLHd0I_0 bird +LJGQA810BtE_0 bus +LJJuw5mLJ4Q_0 skateboard +LJhCGLht3Rw_0 train +LJhCGLht3Rw_1 train +LKe9a7L3vkk_0 bird +LKhjmARDv7k_4 bear +LKhjmARDv7k_6 bear +LKoaXogFTbc_0 dog +LKyQ2fBNVmw_3 skateboard +LK2-EMocZQs_6 dog +LK2-EMocZQs_1 dog +LK2-EMocZQs_3 dog +LK9zoUrrEHc_0 skateboard +LLJiqe0d06I_0 train +LLOwSRx9hxo_0 bird +LLVr7tG42kw_0 motorcycle +LLW1jx3S-Hw_0 train +LLjDNseEw0c_0 skateboard +LL_DiAJ71rc_0 bird +LMGo4BXG4Yw_8 knife +LMRH29tlDrM_0 cat +LMrDuKEYJ3k_0 truck +LM1djNtENzA_0 cat +LNQHybwdHRk_0 airplane +LNX244qUx7M_0 dog +LNntRLW2bHA_3 skateboard +LNntRLW2bHA_0 skateboard +LNntRLW2bHA_2 skateboard +LN6DT1DOaTg_5 skateboard +LOBD9yc5YPM_1 skateboard +LOMTlGqGyHc_0 motorcycle +LOjc-npcSjs_0 airplane +LOjc-npcSjs_2 airplane +LOjc-npcSjs_4 airplane +LOjc-npcSjs_9 airplane +LOlUKQgr7Qg_0 boat +LOosqz3z8Xw_0 train +LOzh9vxSHPg_0 dog +LPQv6LdOZHo_2 motorcycle +LPQv6LdOZHo_1 motorcycle +LPZjxIqs8Uw_2 airplane +LPd_Y8gk5uI_1 train +LPgmaebC-L0_2 boat +LPtcpZXDhHw_0 knife +LPvsAAlZI_8_1 bus +LP3a2L1ZCyg_2 dog +LP8dyCxmCrI_2 train +LQAF34GzpMY_0 airplane +LQO68Aj4ons_0 car +LQRuelaTZd4_0 bear +LQRuelaTZd4_1 bear +LQT4GnnPhA8_1 dog +LQbQVeZrwEk_0 motorcycle +LQdP4gNX9Aw_0 bird +LQjzonTrY2o_0 bear +LQr5vK-X1fQ_0 cat +LQ2EDJSNIN0_1 dog +LQ2EDJSNIN0_3 dog +LQ4z96EA6co_2 bird +LRSii99-QIo_1 zebra +LRgsl5_TJVg_2 skateboard +LRgsl5_TJVg_0 skateboard +LRgsl5_TJVg_1 skateboard +LRtLr32oPAw_0 skateboard +LR7IHIbXtrE_0 bird +LSE0KHhFxps_0 train +LSMKaXjXnhE_1 boat +LSi1i5lSUjA_0 dog +LSqIpguEI04_0 motorcycle +LSqIpguEI04_1 motorcycle +LSvVMD-SF48_1 bus +LS8qQoB3Uw8_0 dog +LS8qQoB3Uw8_1 dog +LTEyQSswTVI_0 bus +LTQPc_WVFOw_0 airplane +LTQPc_WVFOw_1 airplane +LTQPc_WVFOw_2 airplane +LTQPc_WVFOw_3 airplane +LTaExiLK2S0_2 bear +LTaExiLK2S0_3 bear +LTaExiLK2S0_4 bear +LTaExiLK2S0_6 bear +LTaExiLK2S0_7 bear +LTjSA_-Q5DU_1 knife +LTkuM5IoNV4_0 motorcycle +LUCDeZOOhlg_0 cat +LUUYKUhaYZs_0 bus +LUjqWGI9KSo_2 truck +LUphe242a5g_0 train +LU4-QjhixQU_0 motorcycle +LU4-QjhixQU_1 motorcycle +LU__7PPUMTo_0 skateboard +LVCMA3LXlkc_0 airplane +LVfXvn7elFI_0 person +LVfrWLnu7T8_0 train +LWHshdXjBCY_0 truck +LWQhidgjZno_0 motorcycle +LWRXboX1o5Y_0 motorcycle +LWTYrbFCPl0_0 dog +LWY9Y2YVtHA_1 truck +jUQUg-qsfgI_0 motorcycle +jUWm1Mc1Tno_0 airplane +jVEM2JpS4sE_0 truck +jVZhyibQ31g_0 cat +jV9-Lr_rsf0_0 bicycle +jWCpff7m0LE_1 airplane +jWCpff7m0LE_8 airplane +jWCpff7m0LE_0 airplane +jWCpff7m0LE_2 airplane +jWCpff7m0LE_10 airplane +jWGulD3X0qw_0 car +jWIFscsXRmo_0 skateboard +jWLv1BQ4PsA_0 bear +jWawsbm6dCc_0 bear +jWfItNlOURk_0 motorcycle +jWfItNlOURk_1 motorcycle +jWruD-mHxrQ_0 cat +jW4VRs_uVZw_2 airplane +jW4VRs_uVZw_5 airplane +jW4VRs_uVZw_0 airplane +jW4VRs_uVZw_4 airplane +jXBBnV6cop0_0 car +jXDxesHRKAc_0 umbrella +jXLUgu4rET0_1 cat +jXkzrsfYgbs_0 dog +jX84bwkb-r0_3 bus +jYBgSw-woGw_2 bear +jYIWAGlIq9c_0 skateboard +jYZmjlzKhL8_1 skateboard +jYhAd9FFxqI_0 umbrella +jY37CiJCKJk_0 cat +jY9ihstGQwU_0 cat +jZWITYFghgA_0 cat +jZZBR49_vR0_0 motorcycle +jZiuOZwq7gQ_0 motorcycle +jaS19NIXdrk_0 motorcycle +jaVgyhuxK_4_3 skateboard +jaVgyhuxK_4_0 skateboard +jalIqFA40pI_1 motorcycle +jalIqFA40pI_2 motorcycle +jaoXgM9c7u4_1 car +jaovVHNORuA_0 cat +jauLT1ElBPc_1 train +jauLT1ElBPc_2 train +jbN4y-wz5-s_13 giraffe +jbN4y-wz5-s_1 giraffe +jbN4y-wz5-s_4 giraffe +jbN4y-wz5-s_5 giraffe +jbN4y-wz5-s_11 giraffe +jbhxM5eNgO0_0 train +jboQE0Z0280_0 truck +jbrhKjPDzhE_1 train +jbwSKNFH66s_0 dog +jb23jXcxaHE_1 train +jb23jXcxaHE_2 train +jb23jXcxaHE_8 train +jb23jXcxaHE_9 train +jb3uct7NumU_0 train +jb4crk58m88_0 skateboard +jb4672rSRIs_0 dog +jcLbvoEUbj0_0 airplane +jc2fijpD8vI_0 bicycle +jc-IKl7He7U_0 knife +jduOxfYHRGQ_0 person +jeBcjSSkUhw_0 cat +jeFFdyPLUts_1 boat +jeWf_4ARan0_1 bicycle +je8cw_bajbc_1 cat +jfENtrpYNKE_2 bear +jfENtrpYNKE_1 bear +jfixAXjax5I_1 motorcycle +jfixAXjax5I_2 motorcycle +jfixAXjax5I_0 person +jgAt3qPg7A8_2 truck +jgD77Vh-X28_0 motorcycle +jgGLyRuFOdk_0 bus +jglg4qcOpWw_0 skateboard +jg7I2TXyQ2Y_2 bus +jhQ4iIJ42Yw_0 cat +jhSH0EjNy0k_0 car +jhjKdc7FtE0_5 airplane +jiAVTB1keAQ_0 bicycle +jiCp6fAMISg_0 cat +jiJWjndM8hI_0 knife +jjDZnXMMhEA_0 train +jjKsYbTw1qk_0 truck +jjNxX05CDNc_0 bird +LWv0LbGIDi8_0 car +LWxkJ4fux_I_0 knife +LWy-Lhb3YEk_0 bear +LWy-Lhb3YEk_1 bear +LW3bZPt1qrw_5 boat +LW7XQWZjBIw_0 dog +LXLI-Bzcsf4_2 knife +LXLmpEVYE5E_0 train +LXgItdZ5DXo_0 airplane +LYLuXQRCIJ4_0 car +LYXMPTRr40M_0 dog +LYXMPTRr40M_2 dog +LYmsSNBP634_0 knife +LY-hwswMG4g_0 cat +LZJjKCpcAWA_1 knife +LZ_qufxYP3I_0 cat +LaA51BrvHGw_1 truck +LaA51BrvHGw_2 truck +Lam8oTdJids_0 car +LanX2twvMmw_1 airplane +LanX2twvMmw_0 airplane +Lan3os3aUl8_0 boat +LbC7nqh0Uyg_2 train +LbEPmGgzUIE_0 truck +LbvEMq_DQTU_1 train +Lbv8FZelQCM_0 truck +LcD_I0Lkw3k_0 train +LcD_I0Lkw3k_2 train +LceJwFxs3q8_0 dog +LdEeXsYfzE0_0 car +LdLtHx09mII_0 skateboard +LdL-cFGaJqU_0 bird +LdRX8-r4Cpc_0 car +LdggIc_gAew_0 motorcycle +LeAl87F6eS0_2 umbrella +LeOCD9rZsSI_0 bird +LeX-zqgzN3k_1 bird +LeljDmw2CGU_0 skateboard +LfAbAKrmMq0_6 giraffe +LfAbAKrmMq0_7 giraffe +LfAbAKrmMq0_1 giraffe +LfatUu2cH3Y_0 car +LfbQRAjsucU_0 cat +Lf5ebV_NH78_0 train +LgVi03EiPlQ_2 train +LgVi03EiPlQ_0 train +LgZrI3dxws4_0 motorcycle +LgrPr2OxWcw_0 giraffe +Lgyj-vOk72M_0 umbrella +LhdXtQ8SbGE_1 bird +LhgyObbNmLI_0 bus +LhhzzaKmVO4_2 motorcycle +Lhm6JF_1lQg_1 train +LhnNboAgtNg_0 cat +LhtrfEijGHU_0 airplane +LiMriWExmQM_0 boat +LiZxvVZfUdU_2 umbrella +LiwliE18fA4_0 motorcycle +LiwliE18fA4_1 motorcycle +LiwliE18fA4_2 motorcycle +Lizh5Kae5Nk_2 knife +Lizh5Kae5Nk_4 knife +LiznFL6_r2A_0 motorcycle +LjLWamF9HyA_0 giraffe +LjjGe9bnQ3Q_0 train +Lj0zBxRWoIU_0 skateboard +LkFbAjpWRAw_1 giraffe +LkFlT3d8MuQ_0 airplane +LkmioXgRyo4_0 cat +Lk7Z-AUDCuQ_0 cat +LlA5ioDqRns_2 bus +LlA5ioDqRns_1 bus +LlNCPsiSjOU_0 airplane +LlS3_VvB4Nw_0 truck +LlfRY71K2AU_0 truck +LliRBHO1A_E_0 train +LlplZ9JJtQw_0 dog +LlplZ9JJtQw_2 dog +LmFx-lJ6-_M_1 truck +LmR0Ur4owgw_0 bicycle +LmT8BFH5c7k_0 umbrella +LmYKmKucl28_0 truck +Lm4mghtFu-I_0 train +Lm5GStt7KBw_0 truck +Lm5GStt7KBw_1 truck +LnGeYd1AsoA_1 bicycle +LnKLql5jAXo_0 train +LnLlD-mNTtE_0 bear +LnPyjqgA37I_0 giraffe +LndUw9o_3ME_0 skateboard +LnhmeU6oRBE_0 bus +Lntuuj_mi9c_3 knife +LnyfbZ7-fP4_1 umbrella +LnyfbZ7-fP4_0 umbrella +LnyfbZ7-fP4_2 umbrella +LnyfbZ7-fP4_3 umbrella +Ln_tNsQVuwc_0 dog +LomkA_DJyEM_1 bird +Lo2GqBe8-Qc_0 bus +Lo8Q0MdVi9A_1 bear +Lo8ZEKusM1o_0 dog +LpXfY3oQDIc_0 skateboard +LpXfY3oQDIc_1 skateboard +LpnkxmohHZ8_1 airplane +Lpt6bE36Uuw_0 train +Lpt8i9V2MK0_1 train +Lp88aaB29zE_0 zebra +LqOv_DqIWEk_0 boat +Lqf8Q1pPNFg_1 knife +LrIVNsObdso_0 bird +LrKKU5rjq38_2 zebra +Lr-9DI7T7JE_0 bird +Lr-9DI7T7JE_6 bird +LsdHOclMPh4_0 dog +LshP_zqoBc0_0 knife +LsuQhEjteSE_0 dog +LtGXT385l_I_1 dog +LtabCE1oaCw_0 bird +Ltt24ke9SIA_0 bicycle +LtyHCo5uPrQ_0 umbrella +LuA9aRIic7s_1 bird +LuM1ie5yy70_1 umbrella +LuM1ie5yy70_3 umbrella +LuQiLJ7-B-8_0 cat +LuQxQm7FqD0_0 cat +Lua1id9drCA_1 giraffe +Luv05fYUS1Y_0 skateboard +Lu6WLASNWIM_0 truck +Lu6rn2EQSEM_0 motorcycle +Lu6rn2EQSEM_2 motorcycle +LvPDEznT9Yo_1 bird +LvgprOdn070_2 truck +LvhxnDPWfXw_0 knife +Lvv3Ei45X_4_1 knife +Lvz3fP96sew_0 dog +Lv7JaIYWXV4_1 dog +Lv8u2aPVHmc_2 bird +LwChAirlUno_0 skateboard +LwMepJ25LgQ_0 bear +LwPB4qPCelk_2 car +LwPB4qPCelk_0 car +LwgyjrFlc5M_0 bicycle +LwiTfwL3bCs_0 car +LxAhZAbzn7k_2 bird +LxjlAGLccRw_0 motorcycle +Lxlu3NusDCM_0 bicycle +Lx0IybSITTc_0 boat +Lx25sZ_GeqA_0 motorcycle +LyOo_B0KLAs_0 car +LyReFCR-oq8_1 bicycle +LyReFCR-oq8_0 bicycle +LyiT3ute8W0_0 bird +LyiT3ute8W0_1 bird +LyiT3ute8W0_3 bird +LyiT3ute8W0_4 bird +LyiT3ute8W0_5 bird +Ly-uIzZCdn0_1 bus +LzMxggGTH1I_0 motorcycle +LzP0t153jKw_0 skateboard +LzY_TxIbKpw_0 train +Lzk6uj8FMsE_0 cat +Lzp-Yej0-7E_1 bird +LztNNlg_fXs_0 knife +Lz0Gxxs0FUE_2 bus +L0IXFlnu6Qg_0 motorcycle +L0US3Aiu1q0_0 truck +L0kRKO8zzsI_0 bird +L0kRKO8zzsI_3 bird +L0kRKO8zzsI_1 bird +L1EZ_RVwD8E_0 cat +L1LQOPj7NBs_0 truck +L1U2YrjRao0_0 bear +L1VgJBGpBz8_0 bird +L1iiOGDSByA_0 motorcycle +L19ZzBwAHrU_0 knife +L1_86Xd176w_3 knife +L2Efv5kJpc0_0 skateboard +L2FE5Lr0wnY_3 bicycle +L2FE5Lr0wnY_4 bicycle +jjZl3tMuO6w_0 dog +jjcoVigCzgg_0 skateboard +jjk9P9gQq3E_0 bus +jj-p0K2XoQY_0 boat +jj_pv9SFrnU_1 umbrella +jj_pv9SFrnU_0 umbrella +jkGvuOC8azU_0 motorcycle +jkGvuOC8azU_1 motorcycle +jkKU7T0wpj4_0 bus +jkdEq1MRNws_0 cat +jkkk9vsCYVA_0 car +jkqKyvow-ww_1 skateboard +jkqKyvow-ww_0 skateboard +jk2gGx6dIWA_0 train +jlA3_oF9j-Q_0 motorcycle +jluiJgeyCa4_0 truck +jluiJgeyCa4_1 truck +jlu4Ry8dDus_0 cat +jmXmA9egY4s_0 bird +jmXmA9egY4s_1 bird +jmeVwD4p83w_0 umbrella +jm8AZ0aSF0U_0 motorcycle +jnD_9KMnzpk_2 skateboard +jnD_9KMnzpk_1 skateboard +jnQYikiCbAM_0 bicycle +jnQgVTaiaXk_0 train +jnSm3vCtu1k_0 dog +jnu28BEM2j0_0 bird +jnwQHd-sNW0_0 cat +jous_VGiSK0_0 bicycle +joxEhiwL-qg_1 skateboard +jpBcdceCHgY_0 skateboard +jpCdMdRzmuY_0 cat +jpuFdyVJJwQ_0 motorcycle +jpuFdyVJJwQ_1 motorcycle +jpyidnScqNQ_0 umbrella +jpzKefnhMA4_0 train +jqHtlrHk5Cw_0 dog +jqO4FvS_v54_0 boat +jqRXcc7rPaY_0 cat +jqWXHWqSVX8_0 train +jqu6Gjc1hCE_0 person +jq9ZPuTO7Rc_0 umbrella +jrAyEPgy1LM_1 truck +jrLRiCFtlvY_0 skateboard +jrNGiQLJ0ug_1 train +jrg8oKSN6bk_1 bird +jrg8oKSN6bk_0 bird +jsJprPZCPvA_0 boat +jskm6kDOao0_0 cat +jslKL8yQ7v4_0 bird +jslKL8yQ7v4_1 bird +jsp_sWu7g7Q_1 bear +jsx0cE948y8_2 train +jtQGgQPHofk_0 boat +jtWerSK0atA_0 umbrella +jtqUFmuGnVs_0 person +jtx5yVxuLzA_0 bicycle +jtx5yVxuLzA_2 bicycle +juC5lVOX-R8_0 bear +juC5lVOX-R8_1 bear +juMoEfLbbI4_11 bicycle +juUIMSiDGm0_0 umbrella +juownJlkGfA_0 train +ju08Y0j4rAI_1 car +jvKKm9UbcbE_0 cat +jvKqk7Yfq5Q_0 truck +jvdYM-W5Kmo_2 bear +jvxjOOQa_JQ_3 truck +jwxSjxJVyOc_0 dog +jxIyftPYPsc_0 cat +jxIyftPYPsc_1 cat +jxlDJ0D2Tec_0 bicycle +jxn5iX8buaE_0 truck +L2XOsdnKegA_0 dog +L2bV5Mh6tLM_0 dog +L2e6nVyZ33k_0 car +L2gSKheIL48_0 dog +L2zsyBTtcqE_0 bird +L21bM4j4bEc_0 motorcycle +L21bM4j4bEc_4 motorcycle +L21sWlIIkHA_1 skateboard +L28I6_ASmq0_0 motorcycle +L3F2ir5MPj4_3 skateboard +L3Q42kZ8Ap8_0 bus +L3oyk4iYySM_0 boat +L3urWJiuom8_0 bear +L32hlxmCYZU_3 bicycle +L32hlxmCYZU_6 bicycle +L32hlxmCYZU_7 bicycle +L32hlxmCYZU_14 bicycle +L4NZ3vAx87A_0 boat +L4kK9gTKA3Q_2 bear +L4w-P2UsvBE_0 bird +L5VC4bXm6Kc_0 dog +L508o9A8028_0 bicycle +L52ZiKJ5NLM_0 truck +L5499EWzDaQ_0 motorcycle +L6QaXTuDftA_0 bird +L6vLixMpRZg_1 dog +L6vLixMpRZg_0 person +L63p00d7BPY_0 car +L7TR8yCVhN0_0 cat +L7ZTQMPeHYo_1 knife +L7iHAg6bHw4_0 bicycle +L7rQQ4IVPrU_1 skateboard +L70Zv9DFAhc_0 skateboard +L71JgB-L1mA_0 motorcycle +L779-Nw9GV4_0 cat +L780lAoEC2M_0 giraffe +L780lAoEC2M_1 giraffe +L8H_7qqaEOM_1 motorcycle +L8SF7xF6Ucs_8 bird +L8h9dw2kYRA_2 knife +L9EAUBlNvLU_1 truck +L9LWOPIuvcE_0 train +L9L-OlYNdL0_6 knife +L9Tx4-RNDqo_2 motorcycle +L9Tx4-RNDqo_3 motorcycle +L9Tx4-RNDqo_1 motorcycle +L9Vt1klujtA_0 dog +L90g72YGdVA_0 cat +L97eqv7bBCE_0 dog +L985IUAQ8u8_1 skateboard +L-S4CNhlvlM_0 cat +L-w35NTF7vA_0 car +L-0JgkugTvw_0 giraffe +L_AcMGC96O8_0 motorcycle +L_ZdaWupJcU_1 boat +L_xPWB4viT8_1 dog +L_xPWB4viT8_0 dog +MAJonEdmXNA_0 truck +MAVqUxAjlbg_0 skateboard +MBAPF4RVq7E_0 car +MBLHIupmPNk_2 truck +MBLHIupmPNk_5 truck +MBl4bkFRZUY_2 truck +MBl4bkFRZUY_0 truck +MBuwlS32gjE_0 dog +MC8Lal5Lp5Y_0 cat +MC-KkFD07Ts_0 dog +MDxAuy6D1ks_0 skateboard +MD5P0EFFnUQ_1 skateboard +MD8RTKTEaM0_1 motorcycle +MEi_ikuUJoQ_0 skateboard +ME0CETCuaK0_0 boat +jyY5W5HiWUQ_1 cat +jyeqCulSuVM_0 truck +jy_Dr_R-svo_1 umbrella +jy_Dr_R-svo_3 umbrella +jzRWRRcWffo_0 skateboard +j0BXwDs11NY_0 train +j0OALCZbAJQ_0 bus +j0ii12pbeag_0 knife +j0yk2O6HAHA_0 bird +j0_9iwi_dm8_0 dog +j1CQLHBLwew_0 car +j1NePJe1agU_0 bird +j1XwtnPy1Ik_1 bear +j1rU13Z_fxc_0 bicycle +j1utZs4pDTc_0 bicycle +j10ev-4-0Fg_0 motorcycle +j11_jPnp4Pc_0 cat +j2-VEpDwbyo_0 dog +j3X6elDpZ-Q_0 bicycle +j4K9kM9p16o_1 bear +j4Qv6RH4lPk_1 bird +j4U8EcQ8K34_0 umbrella +j4daTphUuBw_0 cat +j4mpJ3QE8VU_1 cat +j4ofs57G2Uk_0 skateboard +j4rMKhohDps_0 bicycle +j4zZbJTAcC4_0 train +j4zZbJTAcC4_1 train +j5EP2UNErRE_0 dog +j5Evt1HJ2ck_0 skateboard +j5ayq3AbImg_2 bird +j5uxE5IUOhk_0 dog +j6GdrMPrcNU_0 train +j6P1j6Ed1Hg_0 boat +j6Ybo1yk-lE_0 motorcycle +j7v1htyJtdo_1 boat +j7v1htyJtdo_2 boat +j7xvqf1mrUo_2 bird +j707fRdtbEE_0 train +j8jip_gthjs_0 train +j8s5sMFYoiM_3 train +j8s5sMFYoiM_1 train +j82ZCaABxl8_0 truck +j8-maioFCxo_2 boat +j924hdZilyY_0 cat +j-MwElKg8Tw_0 cat +j-VN0PFvkDg_0 train +j-a26pZGsKA_5 bicycle +j-r3lQdwYeI_0 boat +j-r3lQdwYeI_3 boat +j-x8lbwsObQ_0 motorcycle +j-0kVn7sEvQ_0 motorcycle +j-0-IDS-OD4_1 truck +j_DE_vsqSZg_0 motorcycle +j_D7oxUpZqs_0 bicycle +j_D7oxUpZqs_1 bicycle +j_FCzH1rLDw_0 train +kABwo7h7ILg_18 bicycle +kABwo7h7ILg_13 bicycle +kANh1n3sh5M_0 giraffe +kANh1n3sh5M_3 giraffe +kAekmn2pgpc_0 skateboard +kAekmn2pgpc_1 skateboard +kAhVhIYl-GE_0 motorcycle +kAhVhIYl-GE_1 motorcycle +MFw-_3fTBzA_0 bicycle +MF06s9T8iJA_0 skateboard +MF06s9T8iJA_1 skateboard +MGFx6Irt70E_0 knife +MGMJ6ocyKXQ_2 boat +MGQw41RhBfc_0 motorcycle +MG9MouhNLjY_1 knife +MG96iokcNoY_0 car +MG96iokcNoY_1 car +MHIEOK-O3Q4_1 bird +MHT9BbNzNJo_0 knife +MHqZCkvaub8_1 car +MHsxwUMk-_s_8 umbrella +MIHg2KAYh5c_0 train +MIHg2KAYh5c_3 train +MIHg2KAYh5c_1 train +MIKCpSFDh4M_0 bear +MIKCpSFDh4M_1 bear +MIKCpSFDh4M_2 bear +MIKCpSFDh4M_3 bear +MInom2mFpwg_0 skateboard +MI2d7Rd8_Zs_9 bicycle +MI2d7Rd8_Zs_10 bicycle +MI2d7Rd8_Zs_2 bicycle +MI2d7Rd8_Zs_4 bicycle +MI2d7Rd8_Zs_5 bicycle +MJOztUhgARo_1 bear +MJvPtT5tzRI_0 motorcycle +MJ3I-JfOG48_0 train +MJ6b6iOY7CI_0 car +MK2aqzY-UTQ_0 cat +MLXY5iff2rU_0 truck +MLZ5bpXr5fk_0 bicycle +MLrWgAcIumk_3 knife +MLrWgAcIumk_1 knife +MLtRUMzqhDk_1 dog +MLwCW5HBfWQ_0 bicycle +MLwCW5HBfWQ_1 bicycle +MLyrsP65yc8_0 cat +MMGw177uo60_8 bicycle +MMGw177uo60_11 bicycle +MMGw177uo60_0 bicycle +MMGw177uo60_1 bicycle +MMGw177uo60_2 bicycle +MMGw177uo60_4 bicycle +MMGw177uo60_6 bicycle +MMX4my6X-xg_0 car +MMfLN7_khoc_0 skateboard +MMwk9bxedYo_1 bird +MMxfwNbWaxc_0 bus +MMxfwNbWaxc_1 bus +MMzNcR3qtX0_0 knife +MM9D2A52FM4_0 cat +MNBfv2S-yco_0 dog +MNDWyaUDfAM_0 truck +MNKwR4IK04k_0 bus +MNnYExmY67E_0 bus +MNnYExmY67E_3 bus +MNuhuq3FP5Q_0 motorcycle +MNuhuq3FP5Q_1 motorcycle +MNuhuq3FP5Q_2 motorcycle +MORtJq8MelU_2 dog +MORtJq8MelU_3 dog +MORtJq8MelU_0 dog +MORtJq8MelU_1 dog +MOR6ErlJIp8_0 giraffe +MOcTGHSkER0_0 car +MOgN13g3SzU_1 motorcycle +MOxIwc0MqZ0_1 car +MO5aNU1mc1s_2 boat +MPQqmw9gvF0_0 dog +MP8ETGMyhnU_0 dog +MQAJWDp31ag_0 cat +MQimJolkMRI_0 cat +MQ5mTW70Ebs_1 train +MRzphcX41T8_0 umbrella +MSWR-YqRwqk_0 cat +MSjYJFNM2HU_0 boat +MSjYJFNM2HU_3 boat +MSonF1662RI_3 skateboard +MSp3-aHmNP4_1 truck +MSp3-aHmNP4_2 truck +MSvmSEk-UJ0_0 bicycle +MSxdHgV7e6o_0 car +MS7Emoy0Foc_1 boat +MTDl42dubw8_0 bear +MTr54KYSQBw_0 person +MTvLNcYmHhQ_0 car +MT-VkX2ZUYs_1 bear +MT-VkX2ZUYs_2 bear +MT_GWiXfC2k_0 knife +MUAuC-rgc9Q_0 dog +MUPAcFVQjlE_0 zebra +kAkZoxVhM3I_4 train +kAkZoxVhM3I_1 train +kAkZoxVhM3I_2 train +kAkZoxVhM3I_3 train +kAmtMpdj5F8_0 dog +kAsA28fm6YM_0 dog +kBZZqBNk68M_0 cat +kBg_1xTx4Dw_0 car +kBsc-5sxeTw_1 knife +kBsc-5sxeTw_3 knife +kCWupS0PNHk_0 car +kC0y-y4Y9zQ_0 knife +kC4_7iM24Uw_0 truck +kC7fdR62Lto_0 person +kDU_m-Zhi-I_2 bicycle +kDsGVRUxg9s_3 bicycle +kDsGVRUxg9s_4 bicycle +kDvYbh9_fvY_0 dog +kDwVR3eWyA4_0 train +kD0shq5M7Xw_1 skateboard +kD_zeOiIsTM_0 train +kEw-F2KrxLQ_0 train +kE3cb1gtxpM_0 person +kFihVzuPlGI_0 truck +kF9uWuyPP8g_0 skateboard +kGB7yQn8jpQ_0 bicycle +kGkvBOa6Ao0_0 motorcycle +kHCbADkGOsE_0 skateboard +kHEfe-TDtS0_0 motorcycle +kHkZCi873e4_1 motorcycle +kH2Vmad_zzc_0 train +kH9YVTvwmpM_0 bicycle +kIGuIdHDwIw_0 truck +kIasEX-cJb8_0 cat +kIqavvGxvh0_0 bird +kIyZZm3zk5M_0 train +kIyZZm3zk5M_1 train +kIyZZm3zk5M_2 train +kI14RuB6ab4_1 boat +kI9E5m5l4Uo_2 bird +kJFQOFR0l0w_0 motorcycle +kJJuX1cGFYg_0 truck +kJJuX1cGFYg_3 truck +kJR59i4f5HA_0 train +kJR59i4f5HA_2 train +kJR59i4f5HA_4 train +kJR59i4f5HA_1 train +kJUDpKKsNQ8_3 boat +kJYZ-XE8ZEQ_0 cat +kJuBcbws_zM_2 car +kJuuymSuBLA_3 boat +kJ2eEJ07dR8_0 cat +kJ4rlYx4HDQ_0 motorcycle +kKJAqMzsMHo_0 train +kKOKJLrWCro_0 motorcycle +kKSyjiL5foc_0 skateboard +kKTvKA8cd-c_0 bird +kKTvKA8cd-c_2 bird +kKeaUBfwuG4_0 dog +kKfiOXnjX0E_1 bird +kKtawdL8xDU_0 umbrella +kLL_YMFYoQw_1 car +kLL_YMFYoQw_3 car +kLgtAl-xGI0_0 bus +kL3r_JUstGU_0 bus +kL7sfsNuNVw_0 giraffe +kL7sfsNuNVw_1 giraffe +kL777xHctO4_0 truck +kMMe5H6THlA_1 boat +kMuQLvHlZM8_1 skateboard +kMuQLvHlZM8_2 skateboard +kM3Ml3gsG1g_0 boat +kM3yM5qONQc_0 person +kNNLDq_wPc4_0 dog +kNQYLVUS5ag_1 train +kNQYLVUS5ag_0 train +kNTqRDpy6Jg_0 bicycle +kNVh6uD0bMs_0 car +kNlVF3ROFLs_0 dog +kOOlwQ0DrQU_1 cat +kOjjXFA4JLo_0 bicycle +kOksVTxs6S0_0 truck +kPEf41FB6w4_2 bear +kPH88UubFMg_0 bird +kPLn0enV644_0 motorcycle +kPPya6oadAk_0 truck +kPSuwjI94G8_1 bus +kP4KkSrY81s_0 motorcycle +kP4KkSrY81s_1 motorcycle +kP7xV2Efw9c_0 car +kQBqt_vvAUc_0 truck +kQHn-cRLiDk_1 cat +MVG65Om9g1k_0 cat +MVG65Om9g1k_1 cat +MVPQRjLFz6E_0 boat +MVRf770zXL0_0 bus +MVZinfPagDI_0 bicycle +MVhsNNsDFWo_0 knife +MVxJBHYueGI_0 boat +MVxJBHYueGI_1 boat +MV5174rsbEY_0 bus +MV-CnX4Gf7A_0 truck +MWGRoXhqRgQ_0 boat +MW78cTfzq0c_0 cat +MXGO41E37k0_1 train +MXVOVBJlezc_1 train +MXW5J8Fq8aw_0 bicycle +MYW0loI0g8M_0 dog +MZJtj9J3P2w_0 knife +MZU8lpmJhxg_0 bus +MZaYMDyaATI_5 skateboard +MZaYMDyaATI_0 skateboard +MZfxKiKSuFU_0 train +MZfxKiKSuFU_1 train +MZfxKiKSuFU_2 train +MZr4cAj7j28_0 motorcycle +MZtheeh470g_0 car +MZxz9C8nBdA_0 bus +MZ4A6ItKCn0_2 knife +MaApAnpbJwE_0 motorcycle +MaNGPVuxXqo_0 bicycle +MaUrOzoC1qE_0 motorcycle +MaV9LY8Yf7c_1 skateboard +MaeWb_sv_KU_9 bus +MaeWb_sv_KU_10 bus +MaeWb_sv_KU_1 bus +MaeWb_sv_KU_7 bus +MaeWb_sv_KU_8 bus +MalEpweFuSM_0 motorcycle +MarA93dcZrA_0 train +MbCJqlLjY_o_2 knife +MbK94OERQUw_1 bicycle +MbK-28LCQ1g_0 boat +McV3_FGrKNw_1 boat +MccB4r2uPG8_2 bus +MctKaOAWQ2g_0 skateboard +Mc_qufFsRZQ_0 train +MdP8tqMgy-c_0 boat +MdcfoMlgxyI_0 boat +MdcfoMlgxyI_7 boat +MdcfoMlgxyI_6 boat +MeGIovLiBUs_0 cat +MeNT1BqRoSk_0 skateboard +MeR6T05EfeY_4 train +MeR6T05EfeY_5 train +MedPaDPXclw_0 train +Me6y3gzfhGA_1 cat +Me7wQZBbtkw_1 truck +Me9X6zA_WSI_2 car +Me9X6zA_WSI_3 car +Me9X6zA_WSI_0 car +Me9X6zA_WSI_1 car +MfEA9RwWf8s_1 car +MfKpwmhyptQ_6 knife +MfQe_WreL6U_0 cat +MfVLnZLXmvw_0 boat +MfYYHsKxgn0_0 cat +MfYYHsKxgn0_1 cat +MfaYiIkR0D8_10 dog +Mfe3mmOd7co_0 skateboard +MflUSzEyPQA_0 dog +Mf1njOx66R4_0 knife +Mf1njOx66R4_1 knife +MgR0ON5CM-E_1 dog +MgR0ON5CM-E_0 dog +Mg7Ve43Durw_0 zebra +Mg9oRrgGKv0_0 skateboard +MhFgGvNvIPU_1 motorcycle +MhOdsv74XK4_0 bicycle +MhPIl5JGvTQ_2 dog +MhdkxaMWwb4_0 dog +MhfYe7VajGQ_1 train +MijD0ZqMorA_3 bear +MijD0ZqMorA_4 bear +MixmJ2mkl18_5 motorcycle +kQhvp8FqRRI_0 motorcycle +kQ0WAbN3uvE_2 bicycle +kQ0qYUhkgXE_0 zebra +kQ0qYUhkgXE_2 zebra +kQ27FYyayCg_0 umbrella +kQ9C8T343Bg_0 umbrella +kQ97WPM3Qw4_0 skateboard +kROqNf1kadg_0 bicycle +kRWaghM9Bng_4 knife +kRYejzNzz-k_0 bird +kRYejzNzz-k_2 bird +kRYejzNzz-k_5 bird +kRtAJBnrb0o_0 cat +kSnUCbQ4k4c_1 giraffe +kSxPGqWydhQ_0 car +kSxPGqWydhQ_1 car +kTBAPJCn4AI_1 car +kTNOY900Hbk_0 cat +kTVuc-2UjPI_0 umbrella +kTbS3XR-Xhc_7 bear +kTdT3aGZVmo_0 train +kTm1R3GaJzg_1 umbrella +kTyJyGREDR8_0 boat +kUX28ytNCwc_0 car +kUcErGH2rjs_0 dog +kU8IsLpAlXg_0 motorcycle +kU8IsLpAlXg_1 motorcycle +kVCic6S6ITo_0 knife +kVmUxntjOEk_1 skateboard +kVxw5-K9zZk_0 motorcycle +kVyJVrTWLwo_0 cat +kVzNGKIHA44_5 giraffe +kVzNGKIHA44_2 giraffe +kVzNGKIHA44_3 giraffe +kVzNGKIHA44_4 giraffe +kWHw0OdDAes_0 boat +kWHw0OdDAes_1 boat +kWo2PlJB2Nc_0 motorcycle +kWxJX4oVzMo_3 train +kXKTNNclCns_0 dog +kXOYPLKJDdI_0 knife +kXOYPLKJDdI_2 knife +kXVHu_jzgek_0 knife +kXj4YpwnHVs_0 car +kXliGVQWoAE_0 motorcycle +kXwzICrP2CA_1 dog +kX-rqtb_n5w_0 boat +kYAGyQOUOAw_5 train +kYAGyQOUOAw_6 train +kYAGyQOUOAw_9 train +kYRvBDpWk_0_0 skateboard +kYd1dxkZ7Q8_0 dog +kYh89aM71_c_0 bicycle +kYie2clM8Jg_0 motorcycle +kYjiRbFWFuE_0 umbrella +kYwzLhWdjYc_0 bird +kY1mYWiL24M_2 train +kY1mYWiL24M_11 train +kY1mYWiL24M_0 train +kY1mYWiL24M_1 train +kY1mYWiL24M_3 train +kY1mYWiL24M_4 train +kY1mYWiL24M_5 train +kY9lrTOcuxY_1 knife +kZNZbhh6P3g_0 cat +kZrG7mMww7I_0 truck +kZrgKUm3pUs_0 boat +kZ1L8FBg_P4_0 cat +kZ3A6bY6RHo_0 motorcycle +kaKhLfdT3z4_0 truck +kaNpALWiNSQ_0 car +kadq7fGv_zg_1 motorcycle +kao854-T3zw_0 bear +kaxFMN_9CfM_0 bear +kaxFMN_9CfM_1 bear +kazbC0JbsUY_1 boat +kazbC0JbsUY_0 boat +ka1HMN9Mxho_1 car +ka8YGdEujsQ_0 motorcycle +kbEenS2dRTc_0 cat +kbF3h-YQ7m8_0 skateboard +kbuWFd9Vthc_1 umbrella +kb2LQHXd2zk_0 car +kb-A8wbnvQg_0 bicycle +kcBIvi6fhUo_1 bus +kcTwHA-N1cg_0 bird +kcip1032v3E_1 skateboard +kco1LYK4z_w_0 person +kdIBzH30zKA_0 dog +kdIBzH30zKA_1 dog +kdP5V_afg7E_0 skateboard +kdRLqCUbWts_0 bird +kdUrK5I-cNo_0 car +kdU-XJEwZsQ_1 bird +kd3DLyL1JMw_0 bicycle +keGrBBWcGE4_1 bus +keGrBBWcGE4_0 bus +kePvCa53REA_0 giraffe +kePvCa53REA_1 giraffe +kea2UOTXlhs_0 cat +kea4eM8Blz8_0 dog +ketFGT3U5D0_0 bicycle +kexKkPOprms_0 cat +ke3yWKL94kE_0 skateboard +Mi4HJYsPBPk_0 skateboard +MjGAi_5coGY_0 bicycle +MjGAi_5coGY_7 bicycle +MjGAi_5coGY_5 bicycle +MjGAi_5coGY_6 bicycle +MjxkMQcgRss_1 car +MkF-jfvzRJU_0 bus +MkGLvilh-P4_2 dog +MkIK8kdqU2I_0 motorcycle +MkQzgwai9zk_0 zebra +MkYtT0L4_3A_0 truck +MktDGOflp1w_0 truck +MktDGOflp1w_1 truck +Mk82qF_xfzI_1 motorcycle +Mk9tGnGNkkE_0 bird +MlLHwysBUiY_0 knife +MlVr20XSJMY_1 dog +MmQIeOEPu9g_2 skateboard +MmQIeOEPu9g_0 skateboard +MmQIeOEPu9g_1 skateboard +MnE1EjTWbTA_2 skateboard +MnGGl7pusvI_0 motorcycle +MnGGl7pusvI_1 motorcycle +Mnd7aZxjoEg_0 bird +Mnvqegl_fME_1 car +Mnvqegl_fME_3 car +Mnvqegl_fME_8 car +MnyV8-43fRY_0 bicycle +Mn2Nul_w66I_1 motorcycle +Mn2Nul_w66I_3 motorcycle +Mn2_fRbVluE_0 knife +MoHDZuwBO4E_0 cat +Mog-qUf6B1c_1 cat +Mo6Q7lGmAw0_0 skateboard +Mp42DoVxbWY_0 motorcycle +Mp91b_edytM_1 dog +Mp91b_edytM_0 dog +MqAlMygAZto_0 cat +MqPKFAIxZpE_0 dog +MqlxERdGjdg_0 motorcycle +MqvfJOEW4oE_0 cat +MrsXy6DL4DA_0 truck +MrssB6CtGrM_1 giraffe +MrvbaDZm6gY_7 knife +MrvbaDZm6gY_8 knife +Mrwi7WoPJSs_0 cat +MrxYHk0ghfM_0 boat +Mr1A4et0ESg_0 bird +MsFvL8N-3ds_0 umbrella +MsQJkEOyREY_0 bicycle +MsY_zz2OeKU_0 motorcycle +Ms8x8pjN7Fw_1 bicycle +Ms8x8pjN7Fw_0 bicycle +MtIjkcXspsU_2 motorcycle +MtfpgvzOlW8_0 person +MtiQjguNpH0_2 boat +MtiQjguNpH0_0 boat +Mt_4bFjyYuU_0 cat +MuLk_dOouJY_0 knife +MuOG8PoK21o_0 bus +MuVtFYK_nH0_0 bird +MuYixry0epc_2 motorcycle +MuYixry0epc_0 motorcycle +MuYixry0epc_1 motorcycle +Mu51W-lkSEc_0 car +MvIYOnRinSo_0 bicycle +MvxRpbl0BBk_0 bus +Mv6v4w7VDFk_1 car +Mv_9l8fWiP4_0 truck +MwAM4o2GCuM_0 car +MwHQb6ZryRA_0 skateboard +MwIKOqSMRwk_0 cat +MwLnGflxcqc_2 zebra +MwNsM6f6fNY_3 bicycle +MwNsM6f6fNY_5 bicycle +MwN7iYEim6k_0 bird +MwW14_GuwLg_1 bus +MwdX3PbgC34_0 giraffe +Mwjq136uMe0_0 car +kfInF5cUU98_0 motorcycle +kfInF5cUU98_1 motorcycle +kfLnoXlGBvU_0 dog +kfhspLhCU5Y_0 cat +kgDOVDDZ9eQ_0 cat +kgONObiF8Hg_0 cat +kgT-NsRkv1c_0 car +kgco3sZv7BY_0 cat +kgi1KajW_ZU_0 truck +kglv-2P5ow4_4 bus +kgrFzgXO9Q8_0 skateboard +kgsyAMgjuL4_0 bus +kgxQ03-tSek_0 bear +kg6RFppR4MM_0 knife +khUURgtFYBY_1 bicycle +khUURgtFYBY_0 bicycle +khVST8w3Zzw_0 skateboard +khlqzkfBCfc_0 cat +khpJlBWPPr4_1 cat +kimZApwsJEY_5 bicycle +kimZApwsJEY_6 bicycle +kimZApwsJEY_0 bicycle +kimZApwsJEY_2 bicycle +kimZApwsJEY_3 bicycle +kimZApwsJEY_4 bicycle +kizrM5CZzPk_0 truck +kjBdTAkRijw_2 bus +kjM0hJl-L44_0 skateboard +kjtOW8OAIeY_0 motorcycle +kkC5lqQb0t0_0 umbrella +kkR7pnou7hc_0 knife +kkeBMT1ixs4_0 boat +kkkc9xwKGp8_1 skateboard +kkvU3dvMkSI_0 truck +kk4KuU5X6Lk_0 car +klGHWdeD-qw_2 bear +kldR5yJFeOo_1 bicycle +kldR5yJFeOo_3 bicycle +klgANznh5x0_1 bicycle +kl2buVrYbX8_0 skateboard +kl3_w8_h6ts_0 skateboard +kl4RYG6OCIY_2 knife +kmZFQEGncaI_2 bicycle +kmZFQEGncaI_0 bicycle +kmllekf2nKc_0 cat +kmoaGUqL6bI_0 skateboard +kmvCtYXRUhM_0 truck +km7aR2fTJlA_2 knife +km-3wnNLVYY_0 boat +knDRZU9u-Lw_1 boat +knVcB-GeINU_0 car +knqi3OAHNO8_0 boat +koOxoaMnXZc_0 skateboard +koOxoaMnXZc_1 skateboard +kphV7yVMBOQ_0 bicycle +kphV7yVMBOQ_2 bicycle +kqDbbFz-XQQ_0 bird +kqDxyoQKFfE_0 cat +kqVaHPJzEro_0 dog +kq4tOnX3m2Y_3 bus +kq4tOnX3m2Y_0 truck +krSKV36ocSs_0 bear +krvyahlS1z4_0 bus +kryv5em-VHk_2 bear +ksB15ebtJeM_0 umbrella +ksCempldLAA_0 skateboard +ksCempldLAA_1 skateboard +ksCjOk8r4rU_0 person +ksSVtTRXRyI_1 bicycle +ksk5uCVKU7Y_0 skateboard +ksxTUcFqlZw_0 knife +ksx219-g47A_0 cat +ktHzii2XMh4_0 boat +ktPLKpH7-mk_5 dog +ktcodoKjIvE_3 bicycle +ktcodoKjIvE_4 bicycle +ktcodoKjIvE_5 bicycle +MwtWyQiagOk_0 bicycle +MwvYg837DFU_0 motorcycle +MxEjkI5fRh0_0 dog +MxHBWltYQX0_0 boat +MxKuZbSiZ4s_0 skateboard +MxK1dXmYQU8_0 knife +Mxr-1toRi3s_0 skateboard +MyS7UVUc55M_0 car +Mybir4gfQaU_3 bird +MzB160hQlFE_9 giraffe +MzB160hQlFE_2 giraffe +MzB160hQlFE_4 giraffe +MzB160hQlFE_5 giraffe +MzB160hQlFE_6 giraffe +MzB160hQlFE_7 giraffe +Mz9ZTHPYJxk_0 dog +M0Ga521uzoA_0 dog +M0qQQArQdTU_0 bird +M088XJeXBS0_0 cat +M1UsEMPrCc4_0 knife +M1cuEQppjNk_0 bus +M1p1DBTuqmk_3 bird +M1p1DBTuqmk_1 bird +M1xxFVktlzw_1 bird +M1zDeqozcU4_1 bus +M2R_9l38IUQ_0 bus +M2uSqd8ohUk_0 bus +M3CUpLmpRBo_0 cat +M3OhLKUgQho_0 cat +M3P38sLk0pc_0 dog +M3tK5YBjyKI_0 truck +M3tK5YBjyKI_1 truck +M3tK5YBjyKI_2 truck +M4CENhQ5vWo_0 cat +M4Hqq89bZiE_1 dog +M40QOQPocV4_1 car +M45MyaeogPU_0 car +M5BEqJFfJYw_0 skateboard +M5NRM7UQv5c_0 cat +M5bLnqKDa1U_0 bear +M5kj9SEKNAo_0 bus +M6POMFHs-ec_0 bus +M6bin6X9FSI_0 knife +M6eRY9q89aQ_2 truck +M6tXmkLy-2Y_1 bird +M7465rUWBzY_1 bicycle +M8Lhm-CgqH4_0 cat +M8cFdveIy4g_0 cat +M8drJLCDOL8_0 cat +M8ea7gWeDQ0_0 bird +M8f0VhN1ZnY_0 umbrella +M8i-DGTEw9M_3 skateboard +M8i-DGTEw9M_1 skateboard +M8sMZ15CLIU_0 skateboard +M9McwXGtZnI_0 cat +M9QtHKxypyI_1 knife +M9UrZSSK1MA_2 motorcycle +M9eiVambl5s_1 dog +kuRfhOqyXeY_0 umbrella +kuzyHmE3SI0_1 knife +ku68PhgE8bk_0 bird +ku7gA5ZLk1Q_0 cat +kvFSzJHIsVg_1 knife +kwDNLBoEQq8_0 skateboard +kwDX0_2B3A0_0 umbrella +kwGGXvXtsjI_0 truck +kwY370WQYUg_0 car +kwbt-wHLPkY_1 car +kwlcEg9G1bE_0 knife +kwsp30ykR4U_0 boat +kxeSYfuQl-I_0 bird +kx1bCqhLcbY_0 bus +kx5tIvM-9dE_0 knife +kyAEyX8zMWQ_0 truck +kyPXCwNh7Rg_0 cat +kyW_f8sv5iw_1 giraffe +kye1Q_k-_Gc_0 bicycle +ky1FAcaT3UE_0 dog +ky6uivneqIg_0 bird +kzblQQcpTdk_0 skateboard +kzblQQcpTdk_1 skateboard +kzfxn1c7_xc_10 bicycle +kzg7y0rERTY_0 bicycle +kzi3zDJR9Bc_0 dog +kzpJkBQxgE0_1 bicycle +kzp3UEwOkJA_0 knife +kzw5a8z9cXs_0 bird +kz6HYpF3pLo_0 dog +k0cUZwgJzB4_0 umbrella +k0uDHQea9sg_1 dog +k00mpKYHsuU_0 skateboard +k1F_TFA3Bbk_0 bicycle +k1LrJEfFKag_0 motorcycle +k1NVg8uaPE4_1 skateboard +k1Q5wms4euk_0 bird +k1TOwPACsvY_2 giraffe +k1TOwPACsvY_3 giraffe +k1vz1ZSBSoo_0 bicycle +k2O0XiVn5kw_0 skateboard +k2QiX8c3t50_0 bird +k2SEBRgras8_3 car +k2Z0W54JwB4_0 skateboard +k2bQG12smw0_0 cat +k2imYphEfo0_0 car +k2ocqQxARpQ_0 skateboard +k2yx7C__3wY_1 cat +k3HKP8CV3CY_0 bus +k3LnBcn5zlU_0 boat +k3QuANDFgVQ_2 boat +k3QuANDFgVQ_3 boat +k3QuANDFgVQ_5 boat +k3fZgTTMj1g_0 giraffe +k3fZgTTMj1g_1 giraffe +k3im7HEvSCI_1 bear +k4D-Ql4Fg7c_1 bird +k4PWQfz5NGo_0 motorcycle +k4U1AP6KV4E_1 skateboard +k4c6D3ZsdL4_0 truck +k5Pp6BYXono_3 bear +k5R3cUyyyWo_0 car +k5nvWBLlS2c_1 boat +k5nvWBLlS2c_2 boat +k5vlZTySXDk_0 knife +k5yJqWnvZzg_1 bus +k5yyV32-nOM_0 motorcycle +k5yyV32-nOM_2 motorcycle +k55nlQZwGz0_1 boat +k57rVPEq54k_1 bear +k57rVPEq54k_2 bear +k6Bwd6af64Y_2 bear +k6gc4du1FqU_0 truck +k6l0hwjaeMA_0 motorcycle +k6l0hwjaeMA_1 motorcycle +k6l0hwjaeMA_2 motorcycle +k60P5osD0rU_0 bus +k64DU45ej5M_6 car +k64DU45ej5M_0 car +k64DU45ej5M_1 car +k64DU45ej5M_2 car +k64DU45ej5M_3 car +k64DU45ej5M_5 car +k640Wtpq-mU_3 umbrella +k640Wtpq-mU_0 umbrella +k640Wtpq-mU_1 umbrella +k7TCyTff1aM_0 truck +k7uTiiG-Ez0_0 bus +M-8Zbj9mU9U_0 boat +M_miIFgy1Ro_0 bear +NAGKrEjU7Sk_3 bird +NAGKrEjU7Sk_2 bird +NAkFaQBgOvo_0 truck +NA9hxGtSLCM_0 bird +NA_DgxP18c4_2 motorcycle +NBE97NAHACk_0 giraffe +NBdhmPgSS2o_1 motorcycle +NCNgKQCU8BM_1 bird +NCP6Cna8jtY_0 skateboard +NCQ5340WhY8_0 car +NCSygygs2Dw_0 skateboard +NCWp95If4uM_0 motorcycle +NCazYWutlOc_0 boat +NCoJmkRt2nE_0 bicycle +NDUhlmH9Rz4_0 cat +NDYT9jTE54Q_0 bus +NDYT9jTE54Q_1 bus +ND_GyhH6zgI_0 motorcycle +NEQIR06VuP4_1 giraffe +NEQOLn6QBuE_8 bird +NESQ70PhJU0_1 boat +NElB9jKqhLc_0 dog +NFjb4XxSoHI_0 skateboard +NFye-cUktCg_0 bicycle +NFz_zzAU_Hc_2 skateboard +NFz_zzAU_Hc_0 skateboard +NFz_zzAU_Hc_1 skateboard +NF_o01qBrtI_0 skateboard +NF_o01qBrtI_1 skateboard +NGCjiEfG4C8_0 skateboard +NGM0enFRa7E_0 car +NGO_7sJEeyk_0 bus +NGRBYn2OatE_0 motorcycle +NGU-5KGKEJ0_0 bear +NGmJtkXyJpc_0 cat +NGmKyRRNL_E_0 bird +NGw5-auup1k_0 car +NG7FgzWn8Gw_1 giraffe +NG9SIDqXvic_0 knife +NHlayOfSZJc_0 dog +NHlsNDcNZqU_0 cat +NHmxckr22ws_0 skateboard +NIPnaoHgzdU_0 bird +NIPnaoHgzdU_1 bird +NIPnaoHgzdU_2 bird +NIvYcbJIYdA_0 cat +NI_YQKOQEvM_1 bird +NJeNAw2RnNc_0 bus +NJeNAw2RnNc_1 bus +NJeNAw2RnNc_3 bus +NJeNAw2RnNc_4 bus +NJ0O48Pkn2k_0 bird +NJ9DpLHaGl8_0 skateboard +NKLemqoJ_hA_0 cat +NK4942wyYgk_0 bus +NLKK4VUbuuI_5 bear +NLp8voZylqM_1 knife +NLsGPrwnRug_1 bus +NLsGPrwnRug_2 bus +NL3CG8KGwis_3 giraffe +NL5j52SH-yQ_0 bus +NL9o4JgV25A_0 dog +NMJB2K_UOLc_0 dog +NMJLv-oYyNc_1 truck +NMJLv-oYyNc_0 truck +NMecCV-gtK8_1 dog +NM7OVTITkaA_0 cat +NNCjf9Qu2RI_0 bear +NNHOtBx0FOY_0 motorcycle +NNkLZRrMEv4_6 boat +NNl4nD5_b_o_0 skateboard +k8NHRbiB2Dc_0 dog +k8OEoDpqSLk_0 truck +k857sWPtmcs_0 cat +k9BuU6A21DQ_0 skateboard +k9HxprAZods_0 umbrella +k9KmR4MNI7o_0 cat +k9KtLV0IMgI_0 dog +k9PCp-8PFZ0_0 dog +k9PX9l8Fnlw_8 bus +k9PX9l8Fnlw_0 bus +k9PX9l8Fnlw_2 bus +k9PX9l8Fnlw_4 bus +k9PX9l8Fnlw_5 bus +k9VDPqCbqj0_0 bear +k9VVUD9wVxk_1 boat +k9zLR7VKKpE_0 skateboard +k9-PLHxxGHc_0 car +k-DOe-pD_MY_0 dog +k-Nl-39bZnw_1 skateboard +k-SqR4BEw3s_4 motorcycle +k-SqR4BEw3s_1 motorcycle +k-izgq4Wj4E_0 dog +k-izgq4Wj4E_1 dog +k_X3oj841SQ_1 motorcycle +k_e_YVhclfg_4 truck +k_e_YVhclfg_3 truck +k_iI2BJQpqo_0 cat +k_jXopyxdo0_1 boat +k_sLp7QKSu8_0 boat +k_tkXRmI_O0_1 skateboard +k_tkXRmI_O0_0 skateboard +k_vnzrtDfAw_1 cat +k_5e1d-vpBU_3 umbrella +k_5e1d-vpBU_4 umbrella +lAA5eXeYwpo_0 cat +lAFonTk_uSA_1 bear +lAI9mfwKMM8_1 dog +lAQxdRz4PlQ_0 bear +lA3btp7QIxg_0 bus +lBH0KOGRswc_0 car +lBXWSN3ciPY_0 motorcycle +lBsOiAR5dAk_2 bird +lBsOiAR5dAk_3 bird +lBsOiAR5dAk_4 bird +lBsOiAR5dAk_7 bird +lBsOiAR5dAk_8 bird +lByHH7yvxpA_0 boat +lB7j8Z4gGtQ_0 car +lB_bnqdnexA_5 bird +lB_bnqdnexA_1 bird +lB_bnqdnexA_4 bird +lCYwepuY9qY_0 truck +lCZry6FRpsk_0 bicycle +lCf6uL_GkYw_2 bear +lC0yidNH6B8_2 bear +lC4BoFWvHs4_3 bear +lDLYtKqlr5M_0 bus +lDf9b9Kr-24_1 truck +lDgzFjqokik_0 boat +lDqk6pRbY3M_0 bus +lDybC3N70so_0 car +lD63JOjqTDg_5 bear +lD63JOjqTDg_9 bear +lD63JOjqTDg_10 bear +lD63JOjqTDg_0 bear +lEG4DGADyEU_0 bird +lEIbERGmlJw_0 umbrella +lEWOScSt-Ks_0 dog +lEaMfPfi9wI_0 truck +lEwJRP_FRW0_0 dog +lFYONMOuW_o_0 truck +lFqrTC4j9AU_0 cat +lF3vWAJRnek_0 motorcycle +lGPyv8wlqaw_1 knife +lGaQV9YhOac_0 motorcycle +lGrVM91Cav8_0 person +lG5xlt4odEs_0 truck +lHKKhuJtJ9A_0 knife +lHXHAD73KC4_0 motorcycle +lHX5VdjDPMg_0 knife +lHuiaqmISAM_0 motorcycle +lHyHQQF-8K0_0 car +lIE0SbW_gCY_0 dog +lIH_in2H5ds_0 knife +lIrvgqkirS4_0 car +lIrvgqkirS4_1 car +lI6hnnAL_54_1 skateboard +lI7VzYQQ8DY_1 bus +lJBeZTzXuSk_0 umbrella +lJJU-pzIbgs_0 boat +lJKxeHgRugQ_0 bicycle +lJa2bLMFljk_0 knife +lJa2bLMFljk_1 knife +lJa2bLMFljk_2 knife +lKC5LtWPL6s_0 boat +lKEgqjR4HeU_0 bicycle +lKEgqjR4HeU_1 bicycle +lKJZ4AYoO9g_0 car +lKJZ4AYoO9g_1 car +lKJZ4AYoO9g_3 car +lKJZ4AYoO9g_4 car +lKJZ4AYoO9g_5 car +lKJZ4AYoO9g_6 car +lKJZ4AYoO9g_7 car +NOEix5l-1TE_1 bear +NOVqPOoUWiM_2 bear +NOmc38WuhVA_1 zebra +NOmc38WuhVA_2 zebra +NPX9qxaZXGQ_1 boat +NPc_EhpqV9I_0 cat +NPlhHkKnD-o_3 bird +NPlhHkKnD-o_1 bird +NPnIcXU4TO4_0 truck +NPnJoNuZw64_0 bicycle +NP2YBNp1eMo_0 bus +NP8MrtR7UMQ_0 skateboard +NQRWmK2DAwo_1 skateboard +NQ7XVf2jPCk_1 bear +NRBtrgg-ACI_0 umbrella +NRGqiXyM4H0_0 bus +NRRxMVw0Fv0_0 umbrella +NRV62o4HAaI_0 dog +NRkeO8cWvlY_0 skateboard +NSEdAs2W7io_1 bus +NSrCO0JVjrQ_0 bus +NS6Z7neTE58_2 bear +NS7vapDr5vE_0 dog +NTJsuoSzIX0_8 boat +NTi-7LowE5E_4 bicycle +NTi-7LowE5E_0 bicycle +NTurL251ndw_0 bird +NTyAmrmpD-w_0 cat +NUOXJlGoyJk_0 motorcycle +NURGtF3McGo_0 knife +NUU3df9bDmc_0 motorcycle +NUhIeMVykto_0 truck +NUkuVMR_rDA_0 truck +NUkuVMR_rDA_1 truck +NUo3_VxkQWs_0 truck +NUo3_VxkQWs_1 truck +NU5WfPjxGO4_1 cat +NU60EZnPyy8_0 bird +NVAF-TWNge8_0 boat +NVeRtjaMVVM_0 car +NVz1RXwlQQM_0 skateboard +NWOVEKbfu_M_2 cat +NWwoSS6oanE_0 bus +NW6ZEfS5YY0_0 dog +NXHWi70uXME_0 motorcycle +NXU1Yxq08KQ_0 skateboard +NXe33k8YYzQ_4 truck +NXe6DkOAbbo_0 cat +NX2FQE2RlgI_0 dog +NX2FQE2RlgI_1 dog +NYBxFsoPtLU_7 knife +NYBxFsoPtLU_2 knife +NYVtLPBMGDA_1 dog +NYVtLPBMGDA_2 dog +NYpkdx_Wzos_0 bicycle +NYrd2o8DQhw_0 bird +NYsYKDH1T0Y_0 bear +NYs9voRwmTk_2 motorcycle +NZGyAc3mNmM_1 skateboard +NZOBtVvtpfo_0 bird +NZoU9njpjBc_2 bird +NZoU9njpjBc_1 bird +NaOwM5jaBb0_0 bear +NaTP9E6Ee6k_0 motorcycle +NahvbbnqXN0_0 knife +NaszpQMnSmM_0 skateboard +NbXn5vr55Ik_0 motorcycle +NbnAyKWQOgU_2 truck +NbnAyKWQOgU_3 truck +Nbz45at2suY_0 bird +Nb1nL_IG2Tc_0 umbrella +Nb4FhqzK_80_0 bird +Nb9Ee0cdc90_4 knife +Nb9Ee0cdc90_0 knife +NcD7EzR9VKc_0 cat +NcODwqAl8wA_0 bird +NcODwqAl8wA_1 bird +NcnPt-ksZkA_0 motorcycle +Ncnr9xhL4RE_1 bird +Ncnr9xhL4RE_5 bird +Nco2IqVnrXc_0 cat +lKiN4UeEuCQ_0 car +lKrgSHU_lF4_0 motorcycle +lKrgSHU_lF4_1 motorcycle +lL9OwfLG-LQ_0 skateboard +lMPus-gGijc_0 train +lMw3GHYr5nI_3 bear +lM2lr9vONXE_1 bird +lNDNEdNtW4w_0 umbrella +lNLvw0Ga8IY_1 skateboard +lNLvw0Ga8IY_2 skateboard +lNLvw0Ga8IY_0 skateboard +lNShteFjBFI_0 bird +lNh4Dhf0JC8_0 truck +lNj5zp4Gbsw_1 bird +lOGti3Hfk6A_2 bird +lOglyCevyZo_0 motorcycle +lOzlZJwo_U8_0 motorcycle +lO0DJaFrguw_0 motorcycle +lO0Nas9ogL0_0 bird +lPG5xsRX0U0_0 bird +lP3Jv00bEG8_0 bear +lQf2-zTERI8_0 motorcycle +lQ8AFjrjX64_0 umbrella +lRSTcmXYwzM_2 knife +lRyY7rtPGJ0_1 dog +lRyY7rtPGJ0_0 dog +lR-HPtCgbFY_0 car +lSefRz_ad2I_0 person +lS7IFw-rHNE_0 car +lTNivynkdBQ_0 bear +lTNivynkdBQ_2 bear +lTW53YPXtYw_0 umbrella +lTgxSRoCADM_1 boat +lTgxSRoCADM_2 boat +lTgxSRoCADM_3 boat +lTgxSRoCADM_0 boat +lTyeSMENfFI_0 dog +lT1oYaEt3l0_0 skateboard +lT1oYaEt3l0_2 skateboard +lT1oYaEt3l0_1 skateboard +lUEz6tmtuxs_0 dog +lUQr1JtEFAM_0 cat +lUSPy6WOhvw_1 boat +lUk_G-9RjSE_0 bird +lUq042i-r3E_1 dog +lUq042i-r3E_2 dog +lVCS7_AhLDg_0 cat +lVKT0DahELk_0 bus +lVKT0DahELk_2 bus +lVOqUh5DjZE_0 bicycle +lVWFKjMWyF8_0 truck +lVWFKjMWyF8_1 truck +lVWFKjMWyF8_2 truck +lVoO_SiGxpw_0 cat +lVohP88BOwU_1 giraffe +lWDh4SPr76A_1 train +lWGBmSVTvwo_2 skateboard +lWLYqz3RhXs_0 truck +lWkC8ABD6YI_0 knife +lWnVG1WyzTQ_0 dog +lW8axrSg7EY_0 dog +lXJGVOcVinA_1 truck +lXkkzYM416M_12 knife +lXkkzYM416M_8 knife +lXkkzYM416M_11 knife +lXshoTSoReY_0 motorcycle +lXshoTSoReY_1 motorcycle +lXshoTSoReY_2 motorcycle +lYC47pEoyKc_2 skateboard +lYEiGk0pa9w_1 dog +lYP4KB7dANc_0 truck +lYcCLy33mJA_0 truck +lYcCLy33mJA_1 truck +lYrLCKi7wHw_0 knife +lYrvoVOM7i8_1 truck +lYrvoVOM7i8_2 truck +lYzirpo9X4Q_2 knife +lY38gkpHWQA_0 dog +lZWg3rt2bp4_0 truck +lZWg3rt2bp4_1 truck +lZWg3rt2bp4_2 truck +lZgIg28WsqA_1 dog +Ncs0SIaAZjk_0 skateboard +NdDPhB7JjOc_1 car +NdFMcVN8fkc_0 skateboard +NdFMcVN8fkc_1 skateboard +Nd2smOOuPs4_0 truck +Nd5Cyi1P2AQ_0 person +Nd5Cyi1P2AQ_1 motorcycle +NesRw9JE-bc_4 dog +NesRw9JE-bc_0 dog +NesRw9JE-bc_1 dog +Ne_T9PyoaOA_0 truck +Ne_T9PyoaOA_2 truck +NfQ_F7iyFT4_0 bus +Nfoq-vLwXMs_0 cat +NfuM3ceM9Lg_0 bird +Nf4iPszryRI_1 truck +NgA6Mi5Qj6Y_1 car +NgHJhpedfLw_0 cat +NgfJ42fUH10_0 skateboard +NglZtOBkn1M_0 boat +Ngp2Yvug4N4_0 skateboard +Ng7YPssESZs_1 umbrella +NhDdHfwovA0_1 truck +NhHYQ1QBPq4_0 cat +NhJWY87UJGA_0 motorcycle +NhKgTGZXrk4_0 motorcycle +NiN42Yupn8k_0 motorcycle +NiQLFJ_8gI0_1 bird +NifFA8VfbMY_0 truck +NjPnw9Ofph8_1 bicycle +Njr2CQDoQ0w_2 boat +Nj1tu2uzjf8_0 umbrella +Nj4IqLuQBd0_0 car +NkHiSqSViG4_3 truck +NkSVC1QmlzA_2 boat +NkXF30FQWUs_0 bicycle +NkajkrLx-Pg_1 giraffe +NkdGD4jRmVk_2 skateboard +NkdGD4jRmVk_3 skateboard +NkdGD4jRmVk_4 skateboard +NkvfxcYCIfg_0 person +Nkxm_Grldgg_0 boat +NlKX0Q_a4qM_0 bicycle +Nl2e8ERoEYk_1 skateboard +Nl27zjpvGZk_0 cat +NmCxdejUxjE_2 umbrella +NmGnWjSHIGc_1 dog +NmGnWjSHIGc_3 dog +NmGnWjSHIGc_0 dog +NmHo6hH22gY_0 cat +NmRjRjuwWGU_0 umbrella +Nmm4H7xWWeE_0 giraffe +NmnOIU5yzmo_0 truck +Nm3Wkz8ClY8_4 bicycle +Nm3Wkz8ClY8_0 bicycle +Nm3Wkz8ClY8_3 bicycle +NnQubFQHcUU_0 cat +NnSwVsUnfj8_0 dog +NnV7SskfNiQ_1 bicycle +NnYCP4YouSI_0 skateboard +NnYCP4YouSI_1 skateboard +NncDYgsTFic_0 motorcycle +Nn1fsXlRDQg_7 bird +NoKz0p_h8xA_0 car +NoRnxJ4D8OY_0 motorcycle +NoglbvaRxAM_1 car +NoglbvaRxAM_2 car +NopFymjXZBE_0 car +NosN0T3He9Y_2 knife +NowQILLv6pM_1 motorcycle +NoxncYznLDw_0 motorcycle +NoxncYznLDw_2 motorcycle +NoxncYznLDw_3 motorcycle +NoxncYznLDw_5 motorcycle +NpbXizTCNgs_0 motorcycle +NpciaYlS9Bs_2 skateboard +NpptiWtuy7U_1 bird +Np0p_ITfRiE_0 boat +Np0p_ITfRiE_2 boat +NqA0sKGQZbc_0 bird +NqD8w0_R9y8_1 motorcycle +NqLEhuNiS-A_0 knife +NqzZbJJl3E4_0 truck +NqzZbJJl3E4_2 truck +Nq-mC-BLk1c_0 bird +NrGByfXIMJc_0 dog +NrGHtOFFLxU_0 motorcycle +NrJIz8M3oNM_0 boat +laSVNAwUDQc_0 giraffe +laiFgjfWMS8_1 bird +lajujsJ1J4k_0 bird +lajujsJ1J4k_1 bird +lauIpA9lVMo_0 skateboard +la0ygpbR6t4_0 dog +la0ygpbR6t4_1 dog +lbCW72FyaQ8_0 umbrella +lbC8rsjkZ8Y_1 truck +lbDdPmkMwnw_0 motorcycle +lbSldeZXn6I_0 skateboard +lbZo-rTovyc_0 skateboard +lbod3X-5Z40_4 bus +lbod3X-5Z40_5 bus +lbzHPZpNNjg_0 dog +lcSqXrVIbwo_0 motorcycle +lcWTw6rAYfI_0 cat +lcv8jXnPWQU_0 cat +lc6jM9I3ffc_0 motorcycle +lc8hZxMLAr4_0 truck +ldjVc4u8LUc_1 motorcycle +ldqpSPYa-3U_1 bicycle +ld5g39_bixY_1 skateboard +ld5g39_bixY_2 skateboard +lew1kgMUujc_0 car +lfPmXUBRa-k_1 bird +lfVb7VtGUAI_0 person +lfYoLXfvmyo_0 bus +lf29DRtjGcY_1 truck +lf29DRtjGcY_2 truck +lf4Xwro4NOQ_5 bus +lgLHq8p_CnA_0 truck +lgVXhalKM3w_0 boat +lgne-5wGRTg_4 bird +lgwnVArDAa0_2 bear +lg3udJdBBoI_0 dog +lg_4H9FLVog_0 dog +lhBsZjQzf8Q_0 motorcycle +lhEN_T9FduQ_0 knife +lhoMpa49rvU_0 umbrella +lh1Brsyb0aE_0 bicycle +lh21_LSx_G8_1 dog +liDzsyAmMJQ_0 motorcycle +liThgzeBkVY_0 cat +lite73A-c3o_0 bicycle +li8IvNy_DW4_1 bird +ljrwXgV0j9o_0 motorcycle +lj3DWkRI_HM_2 bear +lj3mqLiqSRw_0 knife +lj5bI1M_0ZA_0 skateboard +lj-BTMsCDdY_0 dog +lj-BTMsCDdY_1 dog +lkOFpGLmX9s_0 cat +lkYuyUsRfWE_1 dog +lkg_nXf_W88_0 bicycle +llBtQEKaglQ_2 bird +llFPEcbP7m8_0 car +llWG8M6Fsrg_1 skateboard +llu7uI6yzns_0 motorcycle +llu7uI6yzns_1 motorcycle +llu7uI6yzns_2 motorcycle +lmCsOrgM7zE_0 cat +lmVNyKFiuQw_3 knife +lmVNyKFiuQw_2 knife +lm-deiNDAW4_0 motorcycle +lnFmVwj7oMg_1 cat +lnk0OtCMbBc_0 cat +ln5IAoaoPHc_0 dog +NrX1AnOpS98_0 bus +NroEppStyZI_0 bicycle +NrvQhlD_Fuw_0 dog +NrvQhlD_Fuw_1 dog +NsCdsMqUNFc_0 bicycle +NsaAbiSbaCc_0 cat +NsdCvelNA0g_0 motorcycle +NsgZVfgUWco_0 skateboard +NsgZVfgUWco_1 skateboard +Ns78CA77Hmk_0 bird +NtHFEE2Ii0o_0 knife +NtQSi_L3_e4_0 bear +NttRY9GKNOE_1 car +Nt38ikEgqJg_1 dog +Nt-UKy4Uq0o_0 car +NuOq_HSf26I_0 boat +Nucr0ksCppE_0 dog +NumUCmB1MLA_0 bus +Nu6g6OfLbKU_0 zebra +Nu6g6OfLbKU_1 zebra +Nu-gGh3BQo0_0 skateboard +NvDafPMMZtg_1 cat +NvDafPMMZtg_0 cat +NvFUKJ9Y500_0 bicycle +NvTRLNn1Tk4_0 cat +NwC3jHQ65I0_0 bear +NwG3zY4-qHs_0 skateboard +NwHv08KS8WU_0 truck +NwHv08KS8WU_2 truck +NwgEA2yRlYk_0 bird +NwgEA2yRlYk_5 bird +NwlCLmmFUzM_0 truck +NwoCpDkRUOc_0 skateboard +NwzkWW45Qx0_6 bird +Nw1pLrkHm1E_1 cat +Nw8ZySxnzIA_0 cat +NxPgLux4spk_0 motorcycle +Nxgst3FR84g_0 car +NyOC1kV5fqc_2 knife +NyOVnxlZw44_0 truck +NyQlYlDdA1Y_2 skateboard +Nyg0BliJTCI_2 umbrella +Ny14oMm9C9k_6 skateboard +NzIOn70DDCU_0 bicycle +NzfwqHNApI8_0 bear +Nzqr9pq3W0g_0 bus +Nzwcia0dVls_0 bear +Nz5AnTEPNKY_3 bird +Nz_Dn60wY8c_0 dog +N0p_wrAammI_1 bird +N0wFxDTDhrA_0 truck +N0yYt90fBGo_0 boat +N049Vl1eC9E_0 truck +N1C5Wk1HQEk_0 cat +N1jUvtD_RyY_0 umbrella +N1xm5YdzSfQ_0 bird +N13r5ZKqAZI_1 boat +N2GiHfyj2sY_0 knife +N2Y3LmbOWhM_1 cat +N2Y3LmbOWhM_2 cat +N2e24fXBD58_0 boat +N2u1zVHzrfc_0 cat +N3D5PnaCpHs_1 knife +N3D5PnaCpHs_2 knife +N3Iy7f2RrrQ_0 motorcycle +N3OIM_qi7dY_0 cat +N3VKNNdiRhs_0 umbrella +N3ZGT5VDX7A_0 dog +N3vCQPsPb7k_0 cat +N3x4Fw8PZ04_1 bird +N4BazwxnEJU_1 umbrella +N4T6B8WAeyw_1 bear +N4bUNLwIt-I_0 bicycle +N4gBOlxfYUI_0 giraffe +N5T8bgYdTg8_0 bird +N5cC5-506Yg_0 motorcycle +N5uwMT9YWA8_2 umbrella +N6FCEWFj0vc_0 truck +N6XH-20xsPk_0 bus +N6Xl8e3GRcY_0 bird +N6gcbwR93B4_1 motorcycle +N6rvYTX52x4_0 car +loFhsa4OXsA_0 zebra +loFhsa4OXsA_1 zebra +loFhsa4OXsA_2 zebra +loS5Iy7HDhY_2 car +loyp0oi9idU_0 cat +lpPnun9oDq4_1 boat +lqEgRMyazN4_0 dog +lqi9uYhr1lU_3 boat +lqybkPUTuGk_4 bird +lqybkPUTuGk_0 bird +lqybkPUTuGk_1 bird +lqybkPUTuGk_3 bird +lrbJ-8myxJA_1 skateboard +lrd8TXYq2Co_0 zebra +lrgLAWtIFbQ_0 bird +lrk-LSpxnaQ_0 bus +lrsspehYW2Q_0 cat +lrusc_A2xpY_1 skateboard +lsQ4p_XwS3U_1 skateboard +lsW8rve_6F0_0 bird +lsslg2HK3as_1 bird +ls7K9Ga_TDo_0 cat +ls8cJ6QPPdI_0 truck +ltfbVFmlGNs_0 motorcycle +ltfbVFmlGNs_1 motorcycle +lti3EMrk6hA_0 bird +ltyDB0DzJ4o_0 bear +luZpSqhxjzc_0 skateboard +lujnNrfylcM_0 truck +lu4gOMv2LmA_0 dog +lvW9JvQnv_U_0 cat +lvXow0J0_Z8_5 boat +lvpmaJx7Ydo_0 motorcycle +lvxwGSPs5eo_0 truck +lvxwGSPs5eo_1 truck +lv79L0E9KbU_0 cat +lv8ApAxhQxg_9 dog +lwIzp1ny_cc_0 bicycle +lwqQ1SyQ6oc_0 bird +lwu1229kxGE_0 umbrella +lw-_X5H5dsA_1 skateboard +lxfLak4qc0w_3 truck +lxxazO-lUhg_0 skateboard +lxz5eN6gYvE_0 skateboard +lx4WDd9A1jM_0 cat +lyBbm0su2N8_0 dog +lyDsv_jEl3M_0 motorcycle +lylbDiRYA18_0 skateboard +lym5pBjKK44_1 boat +lyx_DnTpBx4_0 bird +lzAGCQoeAug_1 boat +lzISnRATBZY_0 motorcycle +lzrv6Lmaqhc_0 bicycle +lz9wsaAdD3g_0 dog +l0HBjPE-vp4_0 bicycle +l0LztA4KLq8_1 umbrella +l0TccajPnLs_0 cat +l0YyZLT2r0Q_0 dog +l0dbu61iEXU_0 cat +l0kogcjKlvI_0 bird +l01YbT30Uzw_0 car +l1PoAFZPnAI_0 cat +l1cfghmMFfA_0 motorcycle +l1dkS9dCOZs_0 truck +l1eSoNjG7g4_3 car +l1smSqKCK4k_0 person +l1wXtZDVtTw_0 bear +l120CJB_tWI_0 car +l2Cytaq3_MU_0 bird +l2d3stMmMjs_0 cat +l2pGQEcySt4_0 giraffe +l23teWgsK_Q_1 skateboard +l23teWgsK_Q_0 skateboard +N7HX62OM1Jo_1 car +N7WtVRWgYEs_0 bird +N8RE_7TdVGo_0 skateboard +N8wDSOXX8q4_0 cat +N9TwNh9IZug_0 truck +N9TwNh9IZug_2 truck +N-bSoL4tlX0_0 cat +N-ehGzRtoj8_0 bird +N-4XvHMsGCk_0 person +N-9RtI_ifsk_0 motorcycle +N_MWs_Dxjio_0 knife +OAJTjsjrFlQ_0 cat +OATLx4-34zQ_0 dog +OAtOdcwMjgs_0 skateboard +OBDA-yKAC_k_0 umbrella +OBDA-yKAC_k_2 umbrella +OBLc4YWkCqU_0 motorcycle +OBYJdeMHD3g_0 motorcycle +OBlj7XKW4lc_1 boat +OBlj7XKW4lc_0 boat +OBti9g_xdjg_0 bus +OBuDg5pF8EM_0 motorcycle +OBvMQQZSs6Q_0 truck +OCEGSfdedcM_1 dog +OCYvV1-sQQQ_1 truck +OCYvV1-sQQQ_0 truck +OCijTz38zrU_0 truck +OCpuPcuJN68_1 car +OCp5hNHBPpU_6 knife +OC3VHGBHbMY_1 dog +OC3VHGBHbMY_2 dog +ODXPmCSXZDc_1 truck +ODXPmCSXZDc_2 truck +ODbUQUd4jSU_0 skateboard +ODdK6tzKWWs_2 bicycle +ODdK6tzKWWs_3 bicycle +ODlDtYOtoQs_0 truck +ODo-zlQ_GB0_0 truck +ODp6c6uSvaU_0 giraffe +ODuka2U9fkA_0 bird +OD4XXIos2Zo_0 dog +OEJox-XKatw_0 knife +OEJox-XKatw_1 knife +OEMh8A9j_pg_3 bear +OEQV-Uetx8M_0 truck +OE0tYMQn8GU_1 bird +OFA22Poj7lQ_0 bicycle +OFA22Poj7lQ_1 bicycle +OFbK3M6Z_QU_2 dog +OFbK3M6Z_QU_1 dog +OFdr0zUfrlE_0 bus +OF2H-LBDSPk_2 bird +OF2H-LBDSPk_1 bird +OF6Up9vV9Qc_3 truck +OGMTfwEYzHA_0 knife +OGNQnbR2jAw_1 bear +OGVemy4LnsA_0 truck +OGbVuwjdEDU_0 motorcycle +OGnQhL7HZyI_0 bus +OGsEC0i33BY_0 knife +OG7Gqq0yNXc_0 skateboard +OHWx9W6ECl8_0 giraffe +OJ0c10BvtRY_0 dog +l3U_T7n5YD8_0 bicycle +l3YBS5nRxUY_0 truck +l3lkSnsgzx4_0 umbrella +l3qhbFnoRvI_0 car +l31h7cMiU1I_0 bear +l4LQx_ua4m0_0 bus +l4MLa-2lkQI_0 bus +l4dzsbhTXr4_2 bird +l4lv0qkvs10_6 bear +l43lNQ5Vq_s_0 bird +l4-nRuAZNyY_2 car +l5FUU1e4Y60_2 bicycle +l5ecq1OhBsk_1 skateboard +l5ecq1OhBsk_0 skateboard +l508a0nbyQI_6 bicycle +l508a0nbyQI_13 bicycle +l508a0nbyQI_14 bicycle +l508a0nbyQI_18 bicycle +l6NgJ2NHnt4_1 bear +l6S8h_QnD7U_0 cat +l63MzTHehFQ_0 cat +l7p6AfqPX2Y_1 motorcycle +l7p6AfqPX2Y_0 motorcycle +l8-hpsjvPaw_1 truck +l8-hpsjvPaw_2 truck +l9PH4iTXdYs_0 skateboard +l9ZtaPU3mB8_0 knife +l9j2X0rGhIY_0 bird +l9qm2_xBYHQ_0 cat +l9urEyEnxnU_1 knife +l96fQdjYlLs_0 knife +l-MCmCPjH7k_0 bicycle +l-QCC522u8A_0 car +l-eNrq-WUQo_0 boat +l-98mL8hxMY_0 bicycle +l-98mL8hxMY_8 bicycle +l_DmnPQxj7k_0 zebra +l_scPJDEOuI_0 bird +mAE8hqG3eSk_0 bus +mAPlm5rMa-w_0 motorcycle +mA5ZTSfwetI_0 truck +mBEMpccxmBw_1 motorcycle +mBEMpccxmBw_0 motorcycle +mBTsr9NKqos_0 dog +mBTsr9NKqos_1 dog +mBTsr9NKqos_2 dog +mBivNgtX2dc_1 skateboard +mB2K7Cqy5sA_0 knife +mB2K7Cqy5sA_1 knife +mB2K7Cqy5sA_2 knife +mCA3YMqp59Y_0 truck +mCVUS1SHxdc_1 bicycle +mCaHiS25d_c_0 bird +mCipOiHzL24_0 car +mCnfYEJ7_nM_1 boat +mCplUoipq_M_0 umbrella +mCshfLJNDZc_0 truck +mC9gh-poTgc_1 bus +mC_yfZI-Kfw_0 car +mC_8_BVmM48_0 bus +mDOnks0KH3c_0 bus +mDO2Jg5oyPM_1 umbrella +mDTcvH2cBAk_0 truck +mDTxktaf2Z0_0 cat +mDio2Blh76Y_3 knife +mDio2Blh76Y_0 knife +mDio2Blh76Y_2 knife +mDoksuME2bk_0 knife +mECu0xa8vxM_0 bird +mEFIkGBIFT4_0 umbrella +OKHhm13mZYw_0 bicycle +OKJlHLunIJ4_5 truck +OKL9IGXZDqg_0 cat +OKOBYUJfsW0_3 bus +OKVeF8WX7nM_1 dog +OKXlOHWMVYI_0 bicycle +OKXlOHWMVYI_2 bicycle +OKniUxVle4E_0 dog +OK1lt5Hbk8U_0 bird +OK1lt5Hbk8U_1 bird +OK72g05p_nY_0 bird +OLWhwdr2s3U_0 motorcycle +OLqz23zKUZ0_0 skateboard +OMJA4N9BRjk_0 bus +OMJA4N9BRjk_1 bus +OMROj6nJzNU_0 umbrella +OMscf19CmfE_0 cat +OMszUYfxt-k_0 dog +OM7YDn8Aj8U_0 cat +ONQt1uMKjzM_0 cat +ONQ7_XR_YoE_0 car +ONvq-WMS04Q_0 bus +ON25DCtbtZI_0 bird +ON25DCtbtZI_1 bird +OOOsedHMhFE_0 dog +OPFx79LTPYQ_0 knife +OPFx79LTPYQ_1 knife +OPNrGuEJKfQ_0 cat +OPRxB1VUSzc_0 bus +OPZI6LUwe80_0 truck +OPny4vHo5EQ_1 motorcycle +OQWmlKTZbJA_1 boat +OQh45xm5OzM_0 car +OQlHcCttP0Y_0 motorcycle +OQ5Q0IvSVJw_0 skateboard +OROW-2FDArE_0 knife +ORjDIPVlrpY_3 boat +ORyOEpNkmQU_0 bicycle +ORyOEpNkmQU_1 bicycle +OR1UJ2WJswk_0 umbrella +OR8th1OG-XE_0 umbrella +OSia7sePfOs_0 dog +OS2Ga4W91oU_0 boat +OTGZvd8HEBs_6 umbrella +OTGZvd8HEBs_1 umbrella +OTGZvd8HEBs_5 umbrella +OTK2nAcxHMw_0 truck +OTSLZbr15Rk_0 truck +OTXkN6YTPBY_2 bear +OTvtQllL8ho_0 giraffe +OT1tUDnxHUY_1 bird +OT1tUDnxHUY_0 bird +OUDo6Wi3Mx0_0 bicycle +OUaP4Qe7K_k_0 skateboard +OU9OQRs4Ff4_3 truck +OU9OQRs4Ff4_0 truck +OVBUoFuLqko_3 boat +OVBUoFuLqko_4 boat +OVBUoFuLqko_5 boat +OVBUoFuLqko_0 boat +OVBUoFuLqko_1 boat +OV8AfAYiWos_3 truck +OWe4Ah3rUkU_3 truck +OWe4Ah3rUkU_4 truck +OWwYp5TMtyo_0 dog +OW09PhbCZ2c_0 cat +OW9poTV3Pw0_0 motorcycle +OXDBegRD_hY_4 bear +OXleFWP00RU_0 skateboard +OXn_z6r4tTM_0 bicycle +OX46gFmob50_0 boat +OYAOM3GxoFs_0 umbrella +mEhLlaG7ivE_0 car +mEyJVUti9TA_0 bird +mFCrAjplP-s_1 truck +mFQSD32phtQ_0 motorcycle +mFoVk3mdfVs_0 boat +mFpufihJP34_0 truck +mF3uYMbMsrA_1 truck +mGAgv6gfUIA_1 giraffe +mGP0JfjwxXU_0 car +mGP0JfjwxXU_1 car +mGwC1aGK8EQ_1 motorcycle +mGwC1aGK8EQ_0 motorcycle +mG6Uz7wciew_0 truck +mHNOyEXbwsg_4 bear +mHORHQS-7WE_0 motorcycle +mHPMxlukQ30_0 motorcycle +mHfy3z8lzZY_0 bus +mHicqYMm5B8_0 bird +mHicqYMm5B8_1 bird +mHtWCmdt2ck_0 cat +mHwCC0jnHbI_0 bear +mHwgF2IQCd8_0 motorcycle +mIn-Tkvx0xg_0 truck +mIx7ZeZ2Vv8_1 truck +mJ0xD-4leB8_0 cat +mKRUuWYJC2k_0 motorcycle +mKRUuWYJC2k_1 motorcycle +mKRUuWYJC2k_2 motorcycle +mKRUuWYJC2k_3 motorcycle +mKWmMLNNRAQ_0 zebra +mKgld1efJss_0 bus +mKu97ivRVSM_0 knife +mKu97ivRVSM_1 knife +mLDjtK6d-W0_0 knife +mLGU-BL1agI_1 cat +mLG8EyllDhA_0 car +mLIp-YLvQaA_0 zebra +mLgNPTUe_XI_0 cat +mLmtVR-AGCk_0 bear +mLpoizHo-v4_0 dog +mMG1DT2mUAo_0 skateboard +mMUflfP_ZMY_0 cat +mMXGos8VYQI_1 dog +mMt-gdadsY4_1 dog +mNFkEphgV18_1 bicycle +mNdM6zfb6FA_0 cat +mNeHO27e_i4_0 bus +mNeHO27e_i4_1 bus +mOMvL5XuAZs_0 truck +mOVza6TV55E_0 bicycle +mOcxsTLCyfM_0 umbrella +mOjLK3sW2lA_0 skateboard +mO3CzDojFYs_0 dog +mO8cYs6iJlE_0 cat +mPCBb4ndGx0_3 car +mPCBb4ndGx0_2 car +mPPaPa0iD_c_0 dog +mPV3eyH3uiY_0 bicycle +mPW-nXWaC4U_0 cat +mP223OT32Rc_0 knife +mP223OT32Rc_1 knife +mP553XrHpVs_0 motorcycle +mQD1eeRC1Q4_0 knife +mQf2FppJTEM_0 bird +mRFdLfB4a1s_3 bear +mRI6bXmeH0U_0 knife +mRMc_QxifPU_0 truck +mRMc_QxifPU_1 truck +mROsO1LIGpo_0 truck +mRYB4i5ld-k_0 dog +mRkf0ciWPgI_9 bird +mRl54j1LWx8_0 person +mRyO8jtjseY_1 car +mRyO8jtjseY_2 car +mR0m08J8B08_4 boat +mR0m08J8B08_0 boat +mR0m08J8B08_1 boat +mR0m08J8B08_2 boat +mSTIz-CdXqU_0 truck +mSf7pQlzXuw_0 giraffe +mSgbTXZAzDk_1 umbrella +mSvLPzkZzps_0 knife +mSxrYqw4oqg_1 umbrella +mSztwZ01Pck_0 bus +OYIPropF-hA_2 knife +OYTwB7sOFYE_0 bird +OYa8DOvcJkU_0 cat +OYf6rSUrwxc_0 dog +OYnjEcx19SM_0 cat +OZBLMb8bGX8_0 zebra +OZcS8vrufig_0 dog +OZeialzVvBQ_0 bird +OZqsh8FFeFo_0 truck +OZqsh8FFeFo_3 truck +OZqsh8FFeFo_4 truck +OZstdGSfBBw_0 bird +OZ2Xf6zzI5Q_1 skateboard +OZ2Xf6zzI5Q_0 skateboard +OaR_KKoBRYA_0 boat +Oai5vIFRADY_0 truck +Oaxb1TjNF5A_0 boat +ObG3TG10dF0_0 dog +ObLBCGg01UY_5 skateboard +ObLBCGg01UY_1 skateboard +ObLBCGg01UY_2 skateboard +ObLBCGg01UY_3 skateboard +ObLBCGg01UY_4 skateboard +ObMci_3wRII_0 boat +Obmxs3FqVc0_0 truck +Obol9FzC6qw_0 boat +OburzWcRnbc_0 skateboard +Ob5o_Ufzxvo_0 umbrella +Ob6-UrKFrTY_5 boat +OcFGISpeAn0_0 skateboard +OcQBa7E9-AI_1 car +OcZG24cCgsU_2 boat +OchOHb4q-iE_0 bicycle +OcmRyP_n53E_0 truck +OcuYOC6GylA_0 car +Oc1tfJzLD3o_1 bus +Oc1tfJzLD3o_2 bus +Oc1tfJzLD3o_0 bus +OdGHHAUYow4_0 boat +Odl4k8y8GfI_1 skateboard +Odo1ZvyEbqs_3 bear +Odo1ZvyEbqs_6 bear +Odo1ZvyEbqs_7 bear +OeJet0TZ0Ns_0 cat +OecO1BnSygU_0 umbrella +OecO1BnSygU_1 umbrella +OepCeq6zNOc_0 umbrella +OevlneuqSNg_0 skateboard +Oe3qCUtDCoI_0 bear +OfD7c6vcSKc_0 motorcycle +OfFZrl_Ltoo_0 dog +OfQ3Y3DEgNI_0 skateboard +OfZ9wyeuMaU_0 skateboard +Ofcr6xsiMGY_1 knife +OfmW_n1WB-0_0 bird +OfpLj-uw2VM_0 skateboard +Ofv2SMoyg_8_0 boat +OgG3xES-A9s_0 bicycle +OgG3xES-A9s_1 bicycle +OgtTZgAAtrk_0 bear +Og77fxfsfzI_0 skateboard +Og83XjWPr30_0 bird +Og_sRGRP2fw_0 motorcycle +OhQqfPIVR_o_0 truck +Ohh5X9j8-P4_0 skateboard +OhvnlA9rzUA_0 umbrella +Oh4vuNdjqGg_1 boat +Oh4vuNdjqGg_3 boat +Oh79QNRx0m0_0 bus +OiHa7vhbW0g_0 umbrella +OiT0hP6IU_0_1 car +OidiasYmhhk_0 dog +Oiuo__vi77s_0 motorcycle +Oi3BJVuj3f8_0 bus +Ojst9j_7TPs_0 motorcycle +OjxLYDs9O2w_1 skateboard +Okd1qAIUuZo_0 skateboard +Okd1qAIUuZo_2 skateboard +OlO9xdVfniA_0 bus +OlPObAsvFRE_0 bear +OlQykWy5_d0_0 skateboard +OlVZS0O7Xcc_0 bus +OlVZS0O7Xcc_1 bus +OlVofey46c8_2 giraffe +OlVofey46c8_0 giraffe +Oldv3-_fn3E_0 motorcycle +OlufwgkC9nA_0 cat +Ol3C5MWakic_0 bus +Ol63TPS0wjE_0 skateboard +OmTHe4jPR30_0 umbrella +mTnSFF649v4_0 motorcycle +mTtOhVJYmco_0 bicycle +mTuXb1mo6ms_1 motorcycle +mTwbZIC2mjs_0 umbrella +mUllN4tCjhg_0 car +mVWf8BrbbQc_0 skateboard +mVZVZPz-0uk_0 knife +mVztYl0hyR0_1 bird +mWOuUa5VTIU_4 bird +mWSWZi7ef2Q_0 bus +mWULzZ-r0BE_10 bear +mWULzZ-r0BE_0 bear +mWULzZ-r0BE_1 bear +mWULzZ-r0BE_3 bear +mWULzZ-r0BE_6 bear +mWULzZ-r0BE_7 bear +mWULzZ-r0BE_9 bear +mW85x5O3sQM_1 bus +mXYQlH9le8Y_0 dog +mXt-xLcVJTM_0 knife +mXuPzw4I-wQ_0 dog +mXu238CeGfQ_0 motorcycle +mXu238CeGfQ_1 motorcycle +mX3SlrHHN8A_2 knife +mX3SlrHHN8A_3 knife +mYFsdZ6ZiHg_0 skateboard +mYYLIkI65fA_0 cat +mYgcUWeYKeE_0 cat +mYhujznmuic_0 motorcycle +mYtEL2P4G64_2 truck +mYtEL2P4G64_0 truck +mY6M_QMVm6A_0 dog +mY6M_QMVm6A_1 dog +mY6M_QMVm6A_2 dog +mY6M_QMVm6A_3 dog +mZEPBKLKQLU_0 skateboard +mZStBRJGz0o_0 bird +mZWugKrC8fs_0 truck +mZ0LxtaLk9s_0 bicycle +mZ0LxtaLk9s_1 bicycle +mZ1ae3QtMqY_1 skateboard +mZ6SXifL_5I_0 cat +maANeKOpibc_0 bus +maATqEbCdmA_0 boat +maOsv3Gen0Q_0 motorcycle +magDXuphf6E_0 truck +mavzqjj21eQ_0 motorcycle +mbFrW58khSM_0 motorcycle +mbtyAyprPhQ_0 motorcycle +mbuozxoOynA_0 bus +mb9G4GF56RA_1 umbrella +mb9G4GF56RA_2 umbrella +mb-nes45JeE_1 bird +mb-nes45JeE_0 bird +mcCOvhuC86Q_0 cat +mcxoHsKM444_0 cat +mc0A1NsuIBI_0 bird +mdDoBuc7jag_0 boat +mdZbK8mOA5Y_0 motorcycle +mdxbRZzm2Fo_4 truck +mdzJDnEx5AI_2 boat +md8Xi01GJ0Q_3 bird +meRJPfPZTpw_3 bird +mebu5O8auic_1 bird +mehKWfZTJQE_0 bird +mfPFvq57cxM_0 skateboard +mf4LyMZ6wyY_0 skateboard +mgEZVZrBkrg_0 bicycle +mgEkK74q1Lo_0 motorcycle +mgTCPe8eM00_1 umbrella +mgVB0o0U17w_1 skateboard +mgVB0o0U17w_0 skateboard +mhSSgOcQwd8_0 cat +mhqhGszzAR8_0 cat +miC3NPxHofU_1 bird +miQyhDocW3I_1 dog +Om1q-9YbJu0_0 bus +Om-NvWZY9XM_0 bear +OnKqSIvDmuM_0 skateboard +OnemsYazBrQ_0 truck +OnemsYazBrQ_5 truck +OnemsYazBrQ_1 truck +OnemsYazBrQ_2 truck +OnemsYazBrQ_3 truck +On3Yd3AHFp0_0 dog +On3b0cn9QYE_0 bear +On-GcAXLGZ0_0 motorcycle +On_5UKUJi7U_0 car +OohVLB8HrmU_0 bear +Oo2Ux9rWYGo_0 skateboard +Oo8VLA_C0ho_5 bicycle +OpAPsb8a7ck_1 bicycle +OpD07kt9gdg_0 motorcycle +OplcFe9OOMA_0 boat +OplcFe9OOMA_1 boat +OpqmXBQU87o_0 truck +Op3764NveuQ_1 bicycle +OqKwAAWtANM_0 cat +OqPOCcEAHqk_0 skateboard +OqbhEJlCp48_0 skateboard +Oqc407hvhn8_0 skateboard +Oqjbl3c9LYU_0 bear +Oqo2P7az_Jw_2 motorcycle +OrhDfcZqq1E_0 cat +OrhipZ8lZHo_2 bird +OrhipZ8lZHo_3 bird +OrhipZ8lZHo_1 bird +OrmkaB0vrG8_0 dog +Or-E2m2p4X8_0 motorcycle +Or--toMjK3I_3 boat +OsvYa6TnsFI_2 car +OtIV8clF1-o_0 bird +OtIV8clF1-o_2 bird +OtKIh5W3Uro_0 bird +Otw43WNrlsM_1 bicycle +Otw43WNrlsM_2 bicycle +OtyYn5vEHbM_2 skateboard +OuBzZzA9Q7o_0 bicycle +OuJMq2UqA-s_0 dog +OuVznEsiyyA_1 motorcycle +Oui9ZgfJiJE_0 skateboard +Ou1yCmmAuSY_0 cat +OvEJdKYqvF4_2 dog +OvEJdKYqvF4_5 dog +OvZguhO8UVQ_1 bird +OvlqAWflXBs_1 bus +OwQktS0dM3k_1 truck +OwUWoVRKf7E_2 zebra +OxADHlAb7dM_0 boat +OxInmNOeLHY_0 bicycle +OxInmNOeLHY_1 bicycle +OxInmNOeLHY_2 bicycle +OxInmNOeLHY_3 bicycle +OxInmNOeLHY_5 bicycle +OxInmNOeLHY_6 bicycle +OxInmNOeLHY_7 bicycle +OxZdEZCJtcw_1 motorcycle +Oxkx4bWzOMo_0 skateboard +Oxp9w62kg0Y_2 knife +Oxp9w62kg0Y_3 knife +Ox1idrJvs2E_0 cat +Ox_8K3szIs0_0 cat +OyGSbm149i8_0 boat +OzBFCX0vpiU_0 motorcycle +OzCvvptC7o8_1 bicycle +OzHYG5kpMbw_0 car +OzItTAjpb9U_1 knife +OzwlwZq46z8_3 bus +Oz89_rVdBV0_0 knife +Oz89_rVdBV0_1 knife +O0JwQIk5pZY_5 knife +O0Xl3AF_T0s_0 dog +O0dforbCqKM_0 cat +O0lfImzhCM4_0 dog +O0p5eAP2AyA_0 boat +O0rSIIipDT0_0 truck +O02oVGyCZDI_0 motorcycle +O0_GC-1pCYk_0 bear +mj155rqWO3k_0 motorcycle +mj5oMHI4Ch0_1 skateboard +mkPWdHTd5X8_0 bear +mkVYY1EvetE_1 bicycle +mkZA72VL1oI_0 zebra +mlAzMb61fYU_0 cat +mlJYoZVHztc_0 bear +mlT2XD9k5Ro_2 bird +mlophh4mK4A_2 bicycle +mluR2OjQTmU_0 car +mlwpiHjyzIA_1 motorcycle +ml4BVi7cCV4_0 bird +mmnFugXdqlQ_1 truck +mmnFugXdqlQ_0 truck +mmojCWiaNYI_0 cat +mm_Udf1FG0s_0 cat +mnB2hBuySsI_1 bear +mnB2hBuySsI_2 bear +mn_cuBRZu8M_0 cat +moZR-AtZJnI_0 cat +mobg7uEQTmo_0 umbrella +mogyHm8Jiok_0 bird +moh4TWSe9Fc_0 umbrella +motFo9G-GLs_0 skateboard +moyxRLHHeiI_0 bus +mo5ZpMFELUQ_0 motorcycle +mpO9dBwTeW4_0 bicycle +mpYAM0x6L5M_0 motorcycle +mphFmT6TzLM_1 knife +mphFmT6TzLM_2 knife +mphFmT6TzLM_3 knife +mp25XfIJhQY_0 cat +mp8USuQKinc_0 bird +mqUyhzbCpig_0 motorcycle +mqjilBZByTI_0 skateboard +mq5DqmYGVM4_0 person +mrJAakc7Fj8_0 bus +mrOsDCuEdRQ_1 dog +mrY8gIFiUhE_0 car +mrhfyNpFMq4_1 truck +mryDGEujJno_0 motorcycle +msNXnb1a02o_0 knife +msbOXFTsSVU_0 giraffe +mszokIKsdUk_0 bus +ms0_k1aLULU_0 truck +mtITgRv95Sw_0 dog +mtU7bHAsI8Y_0 cat +mtZHgLGJiu4_0 skateboard +mtmzPf2AZuI_0 skateboard +mtnURpE0wyE_0 bicycle +mtnURpE0wyE_1 bicycle +mtnURpE0wyE_2 bicycle +mtpTPJtG8F4_0 motorcycle +mt_LZ5UsG_w_5 knife +mt_LZ5UsG_w_1 knife +muKQy-1p4fg_0 truck +muWIt0X4pKQ_0 dog +muZ7xPF8odU_2 bicycle +mueRS6nKTdA_0 bicycle +mujGcuAzOdo_1 bear +mujGcuAzOdo_4 bear +mulQIomc988_1 bicycle +mulQIomc988_3 bicycle +muoqLEyrhhI_0 dog +mursOuNatdc_0 boat +mu65YolQZds_0 knife +mvEcWlHP6u4_0 bicycle +mvYBfdZkCe8_0 dog +mvb5jVJeuGE_0 person +mvhEFfQeFCY_0 bear +mv2FHxOHSR0_1 truck +mwAPVTEbZGM_0 skateboard +mwAPVTEbZGM_1 skateboard +mwBKrjOpxkY_0 skateboard +mwIroQ9RbXA_0 bird +mwrxbdZraRk_0 car +mw5fQZ8EB5I_0 knife +O1KrpGSvXAY_0 knife +O19Mlhhzqgc_2 bear +O2ZR7HPYZCo_0 cat +O2u5126JYpY_2 motorcycle +O3DA7qzf2s8_1 bus +O3DA7qzf2s8_0 bus +O3y2taxKvCA_2 boat +O4CfuT5BDcc_0 skateboard +O4VQQaJ07zY_0 cat +O5b3XcEGZ4M_0 car +O54XRvo6VU0_2 motorcycle +O54XRvo6VU0_0 motorcycle +O59A3lMogSo_0 giraffe +O59A3lMogSo_1 giraffe +O6BXRuq_YcE_0 dog +O6BXRuq_YcE_2 dog +O6EtCByhFZI_0 truck +O6Jf2yxCTuI_0 cat +O6Uln7GkqDA_0 skateboard +O6b3a--pX3E_0 bird +O6kqsEuKhis_0 bird +O69gCmR0LvA_2 motorcycle +O69gCmR0LvA_3 motorcycle +O7ReHsig5IQ_1 knife +O7Wrpfzb8_g_0 bear +O7lvzdzmX5k_2 bicycle +O8BNclEPo5w_2 dog +O8BNclEPo5w_1 dog +O8f0Dhn1as0_0 umbrella +O8sB46kfM28_7 umbrella +O8sB46kfM28_6 umbrella +O8sB46kfM28_13 umbrella +O9Duu2Un8AE_0 skateboard +O9Duu2Un8AE_1 skateboard +O9Duu2Un8AE_2 skateboard +O9EqKcj_CPs_0 umbrella +O9iWg3ZqLcU_2 bear +O-NZJ4-eoQ8_0 bus +O-ZUr1bQzp4_6 umbrella +O-kJ078YJq4_7 truck +O-2S79hisI8_0 zebra +O-4CV4-x7Tk_0 dog +O_D7M00pmjQ_0 motorcycle +O_PCiV3NICw_0 dog +O_bAX_ruSNQ_0 skateboard +O_fZm7Mblgg_0 knife +O_mRo8YLc50_0 umbrella +O_3VssPsSVQ_5 bicycle +PABLxf3U8qc_2 bicycle +PABLxf3U8qc_4 bicycle +PABLxf3U8qc_1 bicycle +PASMcbnOtUM_1 bird +PAZBEMKPQEw_4 boat +PAbB9I6MC_o_2 boat +PBD1IW-vA6Y_0 dog +PBD1IW-vA6Y_1 dog +PBQjiKBWtao_1 bicycle +PBQjiKBWtao_3 bicycle +PBqIT1T_Tl4_2 umbrella +PByJb40LNJ4_28 bicycle +PByJb40LNJ4_30 bicycle +PByJb40LNJ4_3 bicycle +PByJb40LNJ4_13 bicycle +PByJb40LNJ4_18 bicycle +PByJb40LNJ4_22 bicycle +PB8sWVNFkDw_1 motorcycle +mxA8JbJ0Do8_0 car +mxFga0703Mc_0 bird +mxMCBmJ5owQ_2 truck +mxXH5aZCSJ8_0 truck +mxYl5Y1KAiY_0 dog +mxZgNkjbyxk_1 knife +mxeuMHAWMxo_6 knife +mxeuMHAWMxo_7 knife +mxeuMHAWMxo_9 knife +mxsTfEQlVgM_0 motorcycle +mxvG6gSVYuo_0 bicycle +mxwmtm7rKF8_0 car +mxxiqhZzhEE_0 motorcycle +mxyHDUSMhLs_0 cat +mx2i3CYeEEE_0 bear +myRelcztkqo_1 knife +myWzn06fmDI_0 dog +myY1Ijlbknw_1 bicycle +myY1Ijlbknw_4 bicycle +myY1Ijlbknw_5 bicycle +myY1Ijlbknw_2 bicycle +mymtiyldysk_0 truck +mzGmbowEFfA_1 knife +mzMgXA_v8q4_0 motorcycle +mzYPSSUS--w_2 boat +mzYPSSUS--w_0 boat +mzdD_0CKekQ_0 motorcycle +mzfrEqAhHeY_0 bus +mzm_D3J8zqQ_0 umbrella +mzyu28WsuFs_0 motorcycle +m0MVwwL_0MM_0 bicycle +m0gukhoxW0Q_0 skateboard +m0gukhoxW0Q_1 skateboard +m0gukhoxW0Q_2 skateboard +m08CnM1FBR0_0 cat +m0_tPmnque0_0 bicycle +m0_tPmnque0_1 bicycle +m1Qhj9jYohk_0 bus +m1pFyDGuVzk_1 skateboard +m1pFyDGuVzk_2 skateboard +m2StZDAc1yw_0 bird +m2uQowbhYDc_1 bear +m3AM4AQLDo0_0 zebra +m3AM4AQLDo0_1 zebra +m3RCOnTUyMY_0 boat +m3RCOnTUyMY_1 boat +m3SOT8NCOEY_0 bicycle +m3cgfDs0_G8_2 dog +m3fctWcU4as_0 motorcycle +m3sztS1QC3s_0 cat +m3uDjNrfbD8_1 bear +m35CwgXROHw_0 car +m4qZSrgBZkc_0 bird +m4qZSrgBZkc_1 bird +m6NemUzZQFc_1 motorcycle +m6NemUzZQFc_0 motorcycle +m6S6MEQgo2E_2 motorcycle +m6S6MEQgo2E_4 motorcycle +m6hQABEUkQQ_4 boat +m6z3sbKYwcc_3 bus +m6z3sbKYwcc_4 bus +m669S-54lMc_0 motorcycle +m669S-54lMc_1 motorcycle +m7djLwb_a5k_0 car +m7k5fJXTZPI_5 bird +m7xUarlXKEw_0 umbrella +m7xUarlXKEw_4 umbrella +m7xUarlXKEw_1 umbrella +m7xUarlXKEw_2 umbrella +m8B-pb1I7nc_0 cat +m8YA8dXocmg_2 boat +m8t6gPBCxr8_0 truck +m9HGLakPqSo_1 bear +m-NEL2Jq0nQ_2 car +m-dKTMwfPqo_0 truck +m_JHW_eCKY0_0 umbrella +m_dOsn1chuA_1 bus +m_dOsn1chuA_2 bus +PCC9sJ4Gdxw_0 car +PCeoeGBYrJU_0 dog +PCqa_yHJ32g_2 bicycle +PC2plr6JdQg_0 umbrella +PC_wbEzLNLQ_0 bicycle +PC_wbEzLNLQ_1 bicycle +PDU92To89cE_1 bird +PDlKUKo06lI_0 knife +PDvSiH5Pf_0_0 bus +PEC7E1t79A8_0 car +PEJFRzyvIBc_0 bird +PEJvGdLGOjU_0 zebra +PEY59JrOz5I_1 bird +PEY59JrOz5I_0 bird +PEfpmwboH3w_0 bus +PEtsR4S5Zzg_0 bicycle +PE_zE5T1ayo_0 cat +PFJiRWGaPaw_0 car +PFJiRWGaPaw_1 car +PFa_RCiQVjA_0 skateboard +PFjuIzuDmJs_1 knife +PF8HAptOIC8_1 car +PGEM0ys1sGE_0 knife +PGMimFwsl54_0 cat +PGP0PEOv3zw_2 bear +PGP0PEOv3zw_0 bear +PGipyYSRHso_0 bicycle +PGn623RKWNA_1 car +PG8bMx6DuSo_0 knife +PHeQ1xoUBgg_1 boat +PHmnvFIAtHo_0 bus +PHxuey2u6UE_0 skateboard +PIDvuyKFIJ8_0 cat +PIT2XsuODRE_0 bird +PIa767e6xuQ_0 cat +PIkhnCxrF9g_0 cat +PInIdEVTPn0_7 truck +PI5ROW9ewOg_0 cat +PJoSJpMWo0Y_3 skateboard +PKTJIVIuSFw_0 truck +PKZXF6Hj0kw_0 bird +PKZXF6Hj0kw_2 bird +PKZXF6Hj0kw_1 bird +PKtfgOMwx4A_0 dog +PK-4bXZDtlA_1 skateboard +PLO2xY76oh4_0 motorcycle +PLVEvFhXHAE_0 truck +PLVEvFhXHAE_1 truck +PLd8HlO4HYo_1 cat +PLd8HlO4HYo_0 cat +PLwQ0AHwZgg_1 skateboard +PLwQ0AHwZgg_2 skateboard +PL2FcMREy_0_0 bicycle +PMRnsvlMF4A_0 skateboard +PMUqAknVm2Q_0 motorcycle +PMXmKup8jy4_0 boat +PMkiPjm9XdY_1 motorcycle +PM028PEyjv0_4 bear +PNpDnymoq8w_0 truck +PN6PB668zV4_0 truck +PN86cQumWDU_0 motorcycle +PN_b6R9HxwQ_2 cat +POQalChDjmU_0 skateboard +POW6F8MZMTQ_1 bird +PO-OnjGHjDk_0 bus +PPI6aG2QFaM_0 bird +PPdV273cZC8_0 skateboard +PPhYyYHNaQ4_2 boat +PPhYyYHNaQ4_3 boat +PP5_L_EZsmE_0 bird +PQI2zG7I8jI_1 bus +PQjM0fGHXds_0 bird +nARlDpJ1mzQ_1 dog +nAmX6FEKmTg_0 truck +nAsHFcuT16U_0 skateboard +nAsHFcuT16U_1 skateboard +nBLWjCuzp2g_0 dog +nBPhMvA4QIs_0 dog +nBXKLM2hLN0_1 car +nBtF1BDR8wE_0 motorcycle +nCKBmlhUPYg_0 cat +nCPhfqQsjIQ_0 motorcycle +nCPhfqQsjIQ_1 motorcycle +nCe_XQHu77g_0 truck +nCgjbB7wxoE_0 bus +nDsb271W8XU_1 car +nEFtdboPB2w_1 bear +nEIawnnD8V8_0 truck +nELgP3wAnm8_0 dog +nEM7mY_k1_4_0 boat +nEVFHD_9xCw_1 bird +nEtqWL5nz_U_0 bus +nEtqWL5nz_U_1 bus +nEyJKW3bMCc_0 dog +nE6lY5G16lE_1 bicycle +nE6lY5G16lE_2 bicycle +nE6lY5G16lE_0 bicycle +nFQvQPqMjpk_0 car +nFZrdv6K4pg_0 motorcycle +nFa5TGw-b5Y_0 bicycle +nF28ACSGHM8_0 boat +nF444n6UUJE_0 bear +nF444n6UUJE_4 bear +nGQ3Hq6P5tM_0 car +nGnDoylbNm8_1 bear +nHAF0LI8CPk_0 truck +nHAF0LI8CPk_1 truck +nHAF0LI8CPk_2 truck +nHApjxTb0fI_0 umbrella +nHAt_MmKZtA_0 dog +nHRioXgb-Fo_0 bird +nHbHOfTnrtg_0 dog +nHbHOfTnrtg_2 dog +nHe8j-osZck_0 dog +nH9AXssn9vw_0 umbrella +nIIQLgiJpz4_0 motorcycle +nIqnT8pJFz0_0 knife +nJF2wWsJCd8_0 cat +nJuhir_bIpw_0 cat +nJ6iwd_XQso_0 umbrella +nJ6uR6SE01w_0 bicycle +nKM_iCO6bKs_0 bus +nKS1tzA_Hrk_0 skateboard +nKUBzJ38GgY_1 boat +nK-2zxkNCuA_0 cat +nLED5Us6rMo_0 motorcycle +nLL3PMe48dQ_0 boat +nLXX8_SfZs0_0 cat +nLn2LN33uxg_0 cat +nLx78Uv2dmc_3 skateboard +nMbLyO3605c_0 knife +nMo_-oHL7bU_0 knife +nMtxrG4hH5M_0 skateboard +nMyhi847s6A_0 knife +nNNF1j89RS0_0 bear +nNScwJL6ym0_0 motorcycle +nNeaR2o9KMY_0 boat +nNwEBFJZT8U_0 bird +nOe7o_AaOUs_3 skateboard +nOfyHwhf35s_0 bus +nPBFLS60OYk_5 truck +nPhpYRGfHlw_0 bear +nP5wigEk-3A_3 knife +PQsHE_w_Q5I_1 knife +PQuYVLwcT7k_0 skateboard +PQ4gPP2l3RY_0 bus +PQ9ZEkeKIzs_0 skateboard +PRIJbfolHpE_0 umbrella +PRIw6kIS_oM_0 motorcycle +PRg6CE_exgE_2 dog +PRoAGpjxUIQ_1 dog +PSdh0lzfg3M_0 bus +PSrvUaBxbgU_0 motorcycle +PS_CABKe3Yk_0 motorcycle +PTKnZd28Sac_2 dog +PTORa3OCyoU_1 truck +PTxm2ZRQbNg_0 skateboard +PTxm2ZRQbNg_5 skateboard +PTxm2ZRQbNg_1 skateboard +PTxm2ZRQbNg_2 skateboard +PT2XxI2FufM_0 bus +PT3felQmrwU_1 bear +PT6KXLLxhes_0 bird +PUFo51ngpe8_0 bus +PUeS5CCMoa4_1 zebra +PUgpXWoI6nw_2 bird +PUiSf8EuinE_2 bear +PU3x1IpbndQ_0 knife +PU5v_AtaKKw_9 bird +PU5v_AtaKKw_2 bird +PU5v_AtaKKw_3 bird +PU5v_AtaKKw_4 bird +PU5v_AtaKKw_5 bird +PU5v_AtaKKw_7 bird +PU-lRdkaqdg_0 cat +PVV-saboi8Q_0 truck +PVXtjPyNMms_0 dog +PV6mXKbH058_0 skateboard +PWIWGwJZENs_0 dog +PWQGxn3c5iQ_2 knife +PWQGxn3c5iQ_0 knife +PWs7zuWiKZo_0 bus +PW7XGdRhgKI_0 cat +PW97rAj3_84_0 truck +PXb9PHJghpA_0 cat +PYH5FxLfm3M_0 bus +PYOwGQUBJXY_1 boat +PYWfE8WhDKk_1 knife +PYohJALR7DA_1 motorcycle +PYohJALR7DA_2 motorcycle +PYsiftgJNrs_0 motorcycle +PZEun35Hcoo_1 dog +PZNXXWorkrY_0 motorcycle +PZSGccVPUm8_1 bird +PZjQiLyqHkw_0 truck +PZoM9dv8P3A_1 bear +PZuGSUZ1N2w_0 skateboard +PZz86aIvTWU_0 skateboard +PZ3PfRXk2rQ_0 cat +PZ9YkHds_00_0 dog +PaVPMVUQwtM_7 boat +PaVPMVUQwtM_2 boat +PatPjxyHqvY_0 boat +PbPu-cnEMqo_0 cat +PbUb1IktyM0_0 motorcycle +PbdnWP3AnKQ_1 person +PbhIhdwp7nI_5 knife +PceERP83N7g_1 dog +PceERP83N7g_2 dog +PdER58jIvPg_0 cat +PdRRvS5p7TM_4 bicycle +PdRRvS5p7TM_0 bicycle +PdRRvS5p7TM_1 bicycle +PdgOy1B6ByE_0 person +PdgOy1B6ByE_1 motorcycle +PdkRSALRJOE_1 truck +Pdne4jISJMk_0 bird +PeXODrjPJpU_0 motorcycle +PecvaJstdYE_0 knife +Pejvg4LHBXw_1 skateboard +Peur7tMeMNc_11 bicycle +Peur7tMeMNc_12 bicycle +Peur7tMeMNc_20 bicycle +Peur7tMeMNc_21 bicycle +Peur7tMeMNc_5 bicycle +Pew5sug67ao_0 dog +PfKS2L_bxBc_0 cat +PfOYq_uyVF8_1 bird +nQPFPYvmWtU_0 skateboard +nQd33JTaurM_0 bird +nQd33JTaurM_2 bird +nQmH_VIOI4o_0 cat +nRG70FCdevw_0 bus +nRP28gcIe5Y_0 bird +nRP8SwdbUGw_1 bear +nRr5gMvJ77k_0 skateboard +nSgcLfwMJu4_0 dog +nSvaQz0i9i8_1 skateboard +nSvaQz0i9i8_0 skateboard +nSz_BdDSYsk_1 bear +nS_SY6iDJ2U_3 bear +nTjbCPXR408_1 truck +nTjbCPXR408_2 truck +nTjbCPXR408_3 truck +nTjbCPXR408_4 truck +nTz3LA23B4U_0 skateboard +nUBgjOAcKBw_0 truck +nUDvay-MfVs_0 truck +nUVSuT7wfDs_0 motorcycle +nUdbTm-FW0I_0 bus +nVAOU6r15Ww_3 knife +nVTMM3F16j0_1 boat +nVi9QbrUrjE_0 motorcycle +nWvR8fiLxGw_0 truck +nXD-zvpjC50_0 car +nXG_fwbJQ-E_0 car +nXjIIWFPSd4_0 cat +nXlSVy8CmMk_0 truck +nXpq0p9VBXc_0 boat +nXqE-XROi78_0 bear +nXqQPuJmTZo_0 cat +nYYFquwhxeI_0 cat +nYqRuOF_Uao_2 car +nYqRuOF_Uao_0 car +nYqRuOF_Uao_1 car +nYut3zBSbuM_0 bear +nY0xtzTME34_1 cat +nY2XarSrm7Y_0 boat +nY2XarSrm7Y_1 boat +nY3BS_3Mq6o_0 motorcycle +nY3fRfvoh9w_4 bear +nY3fRfvoh9w_0 bear +nY_icz32gn8_0 cat +nZHGbmVkhrE_0 cat +nZn4xAbcGSk_0 cat +naE1svJuCTw_0 truck +naE1svJuCTw_1 truck +naR-9rNf5fE_0 skateboard +nalqTKM6890_0 umbrella +nalqTKM6890_1 umbrella +nalqTKM6890_3 umbrella +nbCix4zvF_E_0 umbrella +nbcH6NfapD0_0 boat +ncuqh0iglYU_2 skateboard +ncu8gbqMkMc_0 cat +nc9aHs1_xzs_2 motorcycle +ndBPYFAVIiM_0 bird +ndJ2_mPZktw_2 bear +ndJ2_mPZktw_1 bear +ndMfXyYPfAM_0 bird +ndNs3q8tY9U_0 bus +ndO2b-r-Krs_0 motorcycle +ndO2b-r-Krs_1 motorcycle +ndj7VTH_PhE_0 bird +Pfi9ZEQtgjY_0 knife +PfnFeL4ArA8_0 skateboard +PfpTZKfKeKY_2 truck +PfpTZKfKeKY_0 truck +PfpTZKfKeKY_1 truck +PgBMaMqbYqA_0 motorcycle +PgE6BAQmVQQ_0 umbrella +PhFFfxYo2_o_1 dog +PhJOcszed6A_1 car +PhJ5rQ5VmeY_0 skateboard +PhjPRYTcJwQ_1 car +PhyQoxFlTMU_0 truck +Ph8Vag9VxRU_0 zebra +Ph8Vag9VxRU_4 zebra +Ph8Vag9VxRU_1 zebra +Ph8Vag9VxRU_2 zebra +Ph8Vag9VxRU_3 zebra +PiO6F4X8k_M_1 truck +PiO6F4X8k_M_2 truck +PiRy-T8d0gQ_1 skateboard +PiRy-T8d0gQ_0 skateboard +Pi_aEuQD5gA_5 umbrella +Pi_aEuQD5gA_8 umbrella +PjAWqdid4rw_1 umbrella +PjBOLvrlicY_0 car +PjBOLvrlicY_1 car +PjBOLvrlicY_2 car +PjTtsfl7KZ4_0 cat +PjjO6IaSiuo_0 skateboard +PjjV-pCjgqc_1 bird +Pjk0d9eP2gI_0 dog +Pjm-ptGWuWU_0 dog +PjpGwiZ8mK8_0 bus +PjuUsIXzSzQ_0 truck +PjwfhUvbBNI_0 skateboard +Pj9588RHCHM_1 car +PkktNSL9IjE_0 bird +PlKRGU_XIzs_3 boat +PlfCXfMXcs0_0 skateboard +PlfCXfMXcs0_1 skateboard +PltDcKetGYw_0 knife +Pl6ja9eNHzE_3 skateboard +Pl6ja9eNHzE_4 skateboard +Pl6ja9eNHzE_1 skateboard +Pl6ja9eNHzE_2 skateboard +Pml224S87BE_0 bird +Pm_2At7P8Yo_0 bus +Pnt2XmUpT8Q_1 bear +Pnt2g-tHwK4_0 truck +Pn1VFdKk5vQ_0 truck +PoL9E8Yc2vo_0 car +PoL9E8Yc2vo_1 car +PoUPC9WCdiE_5 dog +PoV7Wn66UTo_0 bird +PolaH6r1Qds_4 truck +PolaH6r1Qds_2 truck +PpI7DZdWcfc_0 person +PpZHxI0N3Wo_1 motorcycle +PptqwylntWQ_1 boat +Pp6vch1kMqE_0 cat +PqJOWTjp0ww_0 cat +PqKlF5nnOFs_0 motorcycle +PqNDvGH2-iM_0 truck +Pq7tfwAqhIM_0 motorcycle +PrV4kyVAwWE_0 bear +Prynn7mNQdQ_0 knife +PsVhOsDIopI_0 umbrella +PsfddppUmSk_0 skateboard +PsgPXqr-N7A_0 skateboard +PsvVwYAeKEc_1 boat +PsytJKFxV8c_0 boat +PszGWhekz-Y_0 umbrella +Ps9ReRjYLVk_0 bird +Ps9f-iFqX4M_0 skateboard +PtL5k4ew4q0_0 car +PtR7vRI9mn0_0 motorcycle +PtVUPVUYld8_1 skateboard +PtnFOxat4hE_0 bear +Ptq7-B4P9Bw_0 skateboard +Pt04IRhfVFk_0 boat +Pt1vVuKH3fk_1 skateboard +PuV7SV-FwOU_1 skateboard +neA0T50G8TU_0 car +neA0T50G8TU_1 car +neA0T50G8TU_3 car +newqX6GTbrA_0 car +ne8K6jHnOT8_0 boat +nfnKsQItZjE_0 skateboard +nfxMe31pjec_4 truck +ngAKsr62ACQ_0 knife +ngOtFD7Fxd4_2 boat +ngZtMG--t4I_2 bear +nga4aEZQhJw_0 knife +ngslQPG3kEI_1 bird +nhI3C5y85gw_0 truck +nhdMHfvazLY_0 umbrella +nhoO0Evj7OQ_0 umbrella +nhoO0Evj7OQ_2 umbrella +nh56dQ3T3Mc_2 boat +nh56dQ3T3Mc_3 boat +niBK6HGH16U_0 cat +ni3trEPOXck_0 bird +njBEUyoUzlQ_0 bird +njK1OLFCvv4_0 cat +njMC5HAlnMU_1 umbrella +njnGmGuXNdE_1 knife +njn4TkIDn0k_0 truck +nkJxMYiG9Ho_0 bus +nkSvwnLvBmw_4 motorcycle +nkSvwnLvBmw_0 motorcycle +nkSvwnLvBmw_2 motorcycle +nkVPvJ3Smrg_0 cat +nkZ6NDOt4r4_0 cat +nkv5eof4q_M_0 knife +nlAePf94uwk_0 cat +nlupdJzbyKs_1 bird +nl83jp96h9s_2 knife +nmmeE-Dfds8_0 bus +nmwFYDopqBc_0 dog +nmwFYDopqBc_1 dog +nnIGNFEnlw8_0 car +nnNkJ09YO9M_0 motorcycle +nnUkcXbXbFM_0 umbrella +nnhUxSjBHP8_0 umbrella +noCrLkdGSXw_0 bus +noGmFOxKIr0_0 person +noIHydna8tw_3 truck +nonoyrFpKVA_1 zebra +nonoyrFpKVA_4 zebra +nonoyrFpKVA_5 zebra +nonoyrFpKVA_0 zebra +nosbeVXMgAk_0 knife +nqN2uJfit8o_1 car +nqPkd_Quci0_0 truck +nqWs5hqd8Ps_0 bus +nqbsnsBZULc_0 truck +nqnjh-NO9go_0 bus +nq8oHNlU_BQ_0 truck +nrJURcGigjE_0 motorcycle +nrlcROgdPlI_1 cat +PumbYcoJ5zE_0 truck +Pu8rYMOC0Iw_0 dog +Pu_KMtdCGZY_1 truck +PvSzSsQ4YCY_0 cat +PvuGk2XhJW8_0 bird +Pv77ig8kBgE_0 cat +PwBNm2_oKbQ_1 zebra +PwE-w-S8nQc_0 cat +PwRb6q11-rw_7 bear +PwRb6q11-rw_0 bear +PwRb6q11-rw_3 bear +PwRb6q11-rw_4 bear +PwRb6q11-rw_5 bear +PwgxDMnN1SA_0 truck +PwmBtcc64nM_0 zebra +PwmBtcc64nM_1 zebra +PxN14d54as8_0 truck +PxOYpOxjFFc_0 cat +Px02MS-Ywo0_0 knife +PyevrWYsc8k_0 motorcycle +Pyr-sHCH2wc_4 truck +PyvyP3J13FI_0 knife +PyvyP3J13FI_2 knife +Py6rKt-beyk_0 knife +Py-bAIGcQ1Y_1 boat +PzZ-Jr7jMk8_0 bus +P0S7eBa6_S4_0 dog +P0e6zPkZO5s_1 knife +P1_bfvyTku0_0 truck +P2NRNopueuo_0 umbrella +P2SgXG0mMWU_0 truck +P2Wv0vXNCqQ_0 zebra +P2kLj1DZq3I_1 bird +P2kLj1DZq3I_0 bird +P2ldC-_7nrs_1 boat +P256TqMIJZk_0 dog +P3MLJSbWlpg_1 motorcycle +P3jB1tXpVMw_0 bird +P3q6jIrZyo4_1 dog +P4jpdzY2as8_0 dog +P43doVXj3y0_0 cat +P5DcP_VLnP4_0 bear +P5Gd_8k2O5s_0 truck +P5VAaJj-1Rc_0 dog +P5kFeiFmPxw_0 person +P5xsJqm2v6c_1 motorcycle +P5xsJqm2v6c_2 motorcycle +P5xsJqm2v6c_0 motorcycle +P5yrLRVD86M_0 dog +P6Qm9u9GIE4_0 motorcycle +P72vKWjKtik_0 truck +P741OzHLvig_0 dog +P8BX8WSWRm8_0 bus +P8K2yXmSMwY_0 bird +P8MCMBcqM00_0 motorcycle +P8MCMBcqM00_1 motorcycle +P8h9iD7kPRQ_0 bear +P80sglFzhRI_0 bear +nsS9iSqNMew_1 bus +ntO6br-N89w_0 cat +ntVDuucoRIk_0 cat +nuVxM9m1nb8_0 motorcycle +nuVxM9m1nb8_2 motorcycle +nvIi1SvX-sU_0 dog +nvXKI_MhTTE_4 knife +nvYTcYLFUvc_2 dog +nvdIoQ5mj64_0 knife +nvxwnGRXwZY_1 dog +nxJkhdCqhc0_0 dog +nxUe9yoeHvs_0 bear +nxYGMvfgi8g_0 person +nxj_aavOM50_0 boat +nxmr9gg0ses_1 bear +nx9Uisdggps_3 knife +nx9Uisdggps_0 knife +nyOaHbw3DLo_0 cat +ny2pC-BfLT0_2 dog +ny2pC-BfLT0_0 dog +ny2pC-BfLT0_1 dog +ny3nZLL4cQ0_3 motorcycle +nzGPh9yFDTI_5 truck +nzQqdKnkQ9I_0 zebra +nzppX26-51c_0 boat +nzytVTFaYvs_0 knife +nzytVTFaYvs_1 knife +nzytVTFaYvs_3 knife +nz9DMQ9cPrw_0 cat +nz_YTLNErSY_1 truck +n0P8wVonqY4_0 motorcycle +n0T51DP8868_0 bird +n1VbuQk_3JY_0 bird +n1ZrqU8VSBA_2 bus +n2Xd8e_vz0w_0 cat +n2Xrvmq2r2I_0 cat +n2jvWkboChM_11 bus +n2jvWkboChM_10 bus +n2jvWkboChM_14 bus +n3EKpxnV5U8_0 car +n3bFZVLqNvI_0 umbrella +n3iNRmzhO1U_0 motorcycle +n3pRNFU0ovc_0 bear +n3pRNFU0ovc_1 bear +n38NmPI7Sss_0 boat +n4cdQF8d8UI_0 knife +n4mWuEmbbEM_0 bird +n5J7UxAi_70_5 car +n5J7UxAi_70_1 car +n5J7UxAi_70_3 car +n5J7UxAi_70_4 car +n5i5aZXPgok_1 bus +n5ojrsEczYM_1 truck +n5wZ3Zin9uQ_0 bus +n5wZ3Zin9uQ_1 bus +n6cpTMT-Ci0_1 car +n6sMWDd_j1c_0 cat +n6wMhru1Mx0_2 car +n7HaOXaXWJw_2 truck +n7NWTiq_W-c_0 boat +P9sfOBt9FI8_1 bird +P95Pyq4kglE_0 knife +P95Pyq4kglE_1 knife +P-EecPZ9zV4_0 motorcycle +P-JbMZ89Hac_0 car +P-SIr3rYBzg_0 umbrella +P-lf6syyjAs_0 cat +P-tXkGlSa_8_0 motorcycle +P_A56tkbbmk_8 umbrella +P_A56tkbbmk_1 umbrella +P_A56tkbbmk_7 umbrella +P_un1_qBDWo_0 umbrella +QATQMMA9vo4_2 motorcycle +QATjEG1LPL0_0 bear +QA4LOoc1Crg_0 truck +QA__knfzZZM_0 bird +QBZUbx6SUyU_2 bear +QBbAz7q7E9c_0 bus +QCDUv9KNiWQ_2 dog +QCKzW_uA3vY_0 motorcycle +QCl4OGNJdos_1 bus +QCqvd4xHZLs_0 cat +QCzgTA2cABU_0 boat +QDQgSF9ciHk_4 knife +QD4ioxu8LAk_0 cat +QEMoyw7o_f8_0 dog +QEQfoQOU_F8_1 bird +QFB5gDukoqg_0 bus +QGDhzG35q8c_0 dog +QGDhzG35q8c_1 dog +QGDhzG35q8c_2 dog +QGDhzG35q8c_3 dog +QGFSTul5MDQ_0 knife +QGcd6O1NAkY_1 bus +QGcd6O1NAkY_2 bus +QGv8jcDgmBY_0 motorcycle +QG25-t2CqY0_0 bus +QG5tLrHw5Hk_0 cat +QHVkPy7f680_0 car +QHVkPy7f680_2 car +QHhXgNBSjV0_0 umbrella +QH2Vo_5h-x8_0 car +QIe7ky6mJO8_0 bear +QIqf221MKYo_0 bird +QItwshU9sAQ_0 car +QI65w7sMLtA_0 cat +QJIgRLU_fU8_0 motorcycle +QJfS9bR2S4I_0 cat +QJsyPZ31U-0_0 cat +QKG7PXh0UoU_1 bus +QKG7PXh0UoU_5 bus +QKG7PXh0UoU_6 bus +QK9WWQe1WQU_0 bus +QLTztdEJ8Ts_0 motorcycle +n7dIhGKEzWM_2 boat +n7hFNcaW9rw_0 knife +n77hlwjlW_Y_0 dog +n8IsRKE9S6k_0 motorcycle +n8kFOAqnMao_0 motorcycle +n9RozRHi7iI_1 knife +n9RozRHi7iI_3 knife +n9xiuvCd5Lw_1 bear +n-fT4fcLulk_0 bear +n-fT4fcLulk_4 bear +n-gEIxTHjBk_3 bear +n_EpRXVan0M_0 cat +n_J23TUQdl0_1 bear +n_PRUX4zrLw_0 car +n_bIC-prc2E_0 motorcycle +oARh23g1-LA_0 cat +oAhYK7brhk0_0 dog +oAhYK7brhk0_2 dog +oBDdj5mkGyc_1 knife +oBraEPvaSi0_0 bird +oBuzx2dwA_Q_2 knife +oBzhDbxL57k_0 bird +oCUkN7ySpf8_0 motorcycle +oCZ3WCK5BZU_1 motorcycle +oCf-LgXx6Dw_0 bird +oDHO9J7vFwI_0 boat +oDUJYHwNuS8_0 bus +oDsRL8dvgLA_1 bus +oDsRL8dvgLA_2 bus +oF81nMQlA-4_2 umbrella +oGMlnXjD9R0_0 bird +oGuIyQiDsy0_2 boat +oGuIyQiDsy0_0 boat +oH-XJADp0FM_1 bear +oH-XJADp0FM_2 bear +oH-XJADp0FM_4 bear +oH-XJADp0FM_5 bear +oI5l1By4H7U_0 car +oI_peuU5xk8_5 motorcycle +oI_peuU5xk8_0 motorcycle +oI_peuU5xk8_3 motorcycle +oJD17uQnW_o_0 dog +oJK_TUb7HoQ_3 knife +oJLVcOe7CEU_0 motorcycle +oJervxxOCvY_0 dog +oKTgwWf3FKA_0 dog +QLxMt8F3oYA_0 cat +QL4uK4sZxIU_0 cat +QL-hkYCV0BQ_0 motorcycle +QMEIKO8LcEU_0 motorcycle +QMGNMAZLRFY_1 knife +QMGNMAZLRFY_0 knife +QMHCb6-qyQE_4 bird +QMHCb6-qyQE_0 bird +QMHCb6-qyQE_3 bird +QMJHMIdkS0w_0 boat +QMVKAdAOrNY_0 dog +QNUGl2q9luk_6 dog +QNVeq1dY-gY_0 bus +QNV_xE7TePM_0 umbrella +QNV_xE7TePM_1 umbrella +QNaFT-Ch0Oc_1 bird +QNgnQe-MASw_0 bus +QNgnQe-MASw_2 bus +QNibPLG3_Q0_0 dog +QNibPLG3_Q0_1 dog +QNibPLG3_Q0_2 dog +QNrg73bCl7M_0 bus +QN5joVuigKw_0 dog +QOCUHjNieAs_0 cat +QOGKQmMhYE0_2 knife +QOQU7N2vIdQ_0 dog +QOcPhbRnGh4_0 bird +QOm8zog21wI_0 bear +QOp31EvHfRU_0 cat +QOs2s2r3hpY_2 bird +QOs2s2r3hpY_3 bird +QO1T0Gc_cJk_0 bird +QPwnbNFbZyY_0 motorcycle +QQAQLPTkDwg_2 bird +QQAQLPTkDwg_0 bird +QQh4Cpr7tpM_0 bear +QQ7EaN8ArmM_0 motorcycle +QQ-MUe-ni48_2 motorcycle +QRXtuZBCXtA_0 umbrella +QRZ_xQK1gx8_0 bus +QRZ_xQK1gx8_1 bus +QR3BO_SYrpQ_0 bird +QR5EuXvYbms_0 car +QSK1oOt_5R4_0 knife +QSld_dZQvpY_0 bear +QTPAOir-oYM_1 knife +QThuW0gGa20_0 dog +QTlzTtcPjwk_3 car +QT0-oUhQtbk_0 dog +QT17xRXmBGA_0 umbrella +QVCd5pTgbds_0 boat +QVRM0OueKFY_0 dog +QVXv0Z1FCdg_0 motorcycle +QVXzwEenImE_0 bus +QWBwnViynQA_0 motorcycle +QWFR4XdQv2Y_0 umbrella +QWPkooq95So_1 knife +QWPkooq95So_2 knife +QWSsyFwwdO8_0 dog +QWl839SnUOs_0 dog +QW1BlOtH1bo_0 cat +QXAw2xD7Sgc_0 motorcycle +QXB7sLTVqfM_0 bear +QXIGeVZ6Uqk_0 bear +QXVQ8S7aUB4_0 knife +QXjfaOwHSFo_1 motorcycle +QXwh-lAa3Pk_0 knife +QXwh-lAa3Pk_4 knife +QXwh-lAa3Pk_5 knife +QY2pVib4cZE_0 motorcycle +QZOPux7sysI_1 dog +QZOPux7sysI_0 dog +QZhaeUKdGYk_0 motorcycle +QZpfX1aipco_1 car +QZui5buTy7k_0 bus +QZ3FD2qszF8_0 motorcycle +QZ3MWq6qwJI_0 bus +QaGjoVfIWLQ_0 motorcycle +QaM6ny5gEFQ_0 cat +oKY-KsLfJe4_0 bird +oKY-KsLfJe4_1 bird +oKbCNTwLJoI_0 dog +oKe3Rcvn_TU_2 cat +oK9TjDSQdSs_0 cat +oK9erjaiRq4_0 bus +oLRDfgRIJ-A_1 bus +oLSjl-qN4M8_0 dog +oLrou9S3K-0_1 motorcycle +oM_FQGUvPIk_1 motorcycle +oNFmLa8pU3A_0 knife +oNLkf1j-v6Q_0 cat +oNZOg6XoSrY_1 dog +oNbWPkOIdxg_5 car +oNbWPkOIdxg_4 car +oNyfqJGJhrY_0 motorcycle +oPhE3ECqxf0_0 bear +oPlhh62giKI_0 car +oPrG5_acHVU_2 bird +oP0yHq-dlRY_0 motorcycle +oQV827pXDXA_0 motorcycle +oQXdls5ffZc_2 bear +oQXdls5ffZc_0 bear +oQXdls5ffZc_1 bear +oQ7ARK51eHE_1 dog +oQ7ARK51eHE_0 dog +oR-7d677bYw_0 motorcycle +oSPVZs6_Bd4_0 motorcycle +oSVes8uNT5E_0 motorcycle +oSao8txZd7A_0 motorcycle +oSb17xrITtY_0 motorcycle +oSqq5UHBveo_0 bear +oSxoAvNHNB0_0 motorcycle +oS60CV9BFs8_4 bear +oTYr-qD5JOE_0 bird +oTj1e8RI67A_0 boat +oTlwKNdm3rE_0 dog +oTuVBf1jiPM_3 bear +oTuVBf1jiPM_0 bear +oUHa0FV0wwM_1 dog +oUVJrf3WBrs_1 bus +oUVJrf3WBrs_3 bus +oUuQYVAvtgs_0 bird +oVUE-0XhhsQ_0 car +oVUE-0XhhsQ_2 car +oVUE-0XhhsQ_3 car +oV1vhE0ypUE_0 cat +oV6wthYHnKA_3 knife +oWFO_yss01s_0 cat +oWI2O83zUJk_1 car +oWI2O83zUJk_0 car +oWYSJgX0THI_1 dog +oXMW3YjDAqQ_2 boat +oXaieymppqU_0 cat +oX4YRc-No7Q_0 dog +oYY_svQfTs0_1 boat +QahJqWjC1v0_0 motorcycle +QakBz4K6hqw_0 umbrella +QbHAXTRKk8w_0 knife +QbHAXTRKk8w_1 knife +QbNU92uEUSc_0 cat +Qbk_YIfY5q4_7 knife +QcLZ-b-0PxY_0 boat +QcU2S6m_GJk_0 dog +QcuHNJWb-AY_0 car +Qc0kbcpophI_0 car +Qc5ZW-ni9ZQ_0 boat +QeRfpcI_TTQ_0 bear +QebJi8pjWkk_0 car +QeeG_4eNyg0_0 dog +Qe1-M3oVaFs_1 knife +QfOdxYnCAKc_0 bear +QfOdxYnCAKc_2 bear +QfaVCQOGlMM_0 motorcycle +QfgJh_s9H0I_1 bird +QfgJh_s9H0I_2 bird +Qfr5Fc1k7Ic_0 knife +QfwCa3YapRg_0 cat +QgRbpAz8TuI_0 bear +QgRbpAz8TuI_5 bear +QgRbpAz8TuI_2 bear +QgXjMUMIe4Q_0 cat +QhbwOw5dHPg_0 cat +Qhc3Bb_6Uq4_1 motorcycle +Qhc3Bb_6Uq4_0 motorcycle +QhnEXqWFBuw_0 bird +Qhxv39Tkzbs_1 dog +QiHJ2uYByjM_0 motorcycle +QjV-g1D6Be0_0 motorcycle +QjV-g1D6Be0_3 motorcycle +QjV-g1D6Be0_1 motorcycle +QjV-g1D6Be0_2 motorcycle +QjdGUh1FtN4_1 bus +QjqhhoIx6nQ_0 boat +Qj4Mfd45GOE_3 bus +Qj4Mfd45GOE_0 bus +QkPH2LBso5c_0 umbrella +QkPLEWaH1bo_0 cat +QkkuZ_G7t48_0 boat +QkwI5-_QspU_0 cat +Qk6G7eAHlCs_0 dog +QlcaO8pkzd4_0 bear +QliTvc637Yk_2 boat +QlieDL9xPyU_1 motorcycle +QlxQKy1yzyI_3 motorcycle +QmP4xj9S0mQ_0 motorcycle +QmR3bvWDA1s_0 boat +QngGa73C1G8_0 cat +QnnV6lKKIgI_1 knife +QnuD7a8BM30_0 dog +Qn9CU5O4FHU_0 bus +Qn9Z0LVIxbo_0 car +QoTopiP9k2o_2 bus +oZLdU13R4uU_0 motorcycle +oZoTyJNjCJI_0 bus +oZ6Py8Tx-sA_0 dog +oZ9qkN9Q1X4_1 bird +oaXGm1MdDoA_0 cat +oajaYAOs_oI_1 knife +oa_73oVbH38_0 bird +oa_73oVbH38_1 bird +obbzKGrHOP0_0 bird +ob70dcN35yg_0 bird +ocNVbpQhB5g_0 cat +ocPgZeXuFqs_0 car +ocj3mV2T-ls_1 bird +oc4RRoFoUo0_0 boat +odsCgfz0yM8_0 motorcycle +oeIBPeBAEv8_0 dog +oeVUkEvC3To_0 boat +ofDmsqy24k0_0 car +ofJOKOICGco_0 motorcycle +ofvHImJKiAg_1 bear +ofy3Sid451s_1 bear +ogIewcLFxLo_0 dog +ogLOXI-Kvcg_0 knife +ogzWVQ5TC80_0 cat +oh7uEf_YE40_1 dog +oiItk_51540_5 motorcycle +oiKC4SxYNJE_0 bus +oiRnmB7WQjQ_0 bird +oiu_53B5AAc_0 motorcycle +ojFBoKltgfQ_0 bus +ojFBoKltgfQ_1 bus +ojFBoKltgfQ_2 bus +ojQfL_XgMM0_2 boat +ojz2xLrH-Ts_7 car +okKrvzNb9IU_0 car +okiIzmV8YLw_0 cat +okiIzmV8YLw_1 cat +okzrd8v1G-w_3 boat +omGx_muz0SY_1 boat +omngVtTFM1I_0 umbrella +oms2XkgghV8_0 boat +QoqeX-W0RFw_0 boat +QoqeX-W0RFw_2 boat +Qo0mxFOMVGc_0 dog +QpAWeYA1pc8_0 car +QpDm5g1dELc_0 bus +QpD7CVh2Z_c_3 knife +QqdW9IMDHgs_0 boat +QqdW9IMDHgs_2 boat +QqdW9IMDHgs_3 boat +QqhZnuITXs8_2 bird +QqhZnuITXs8_3 bird +QqkblYN1YOg_0 bus +QrEjYyinITM_0 car +QsQFhUd04jI_0 motorcycle +QsQFhUd04jI_1 motorcycle +QsV9BTogrKc_0 knife +Qt78_24lkeM_0 boat +Qu8xNQ6Vd04_0 cat +QvgmjwKuAeM_0 umbrella +QvqNodq3NxA_3 bear +QvsjDkJ_oho_0 cat +QwALBOsUby0_1 knife +QwYxgsacjx0_0 knife +Qw9UvjSO9_Q_0 bird +Qxx3WjrGmtE_2 bear +Qyc0xSSPT1E_0 dog +QzCvBtKWPjg_0 person +QzPFEeJYDcE_0 umbrella +Qz1R2sk37qg_3 bear +Qz1R2sk37qg_5 bear +Qz1R2sk37qg_6 bear +Qz1R2sk37qg_7 bear +Q0HX6Jfnnb8_0 bird +Q0J1QbF_Vis_0 bird +Q0KhMTnvbxM_0 bus +Q01P6P7bm7E_0 motorcycle +Q0-7SsSXMV0_0 knife +Q0-7SsSXMV0_2 knife +Q1RqyDERgxM_1 bird +Q1VXWNHzPqI_1 cat +Q1VXWNHzPqI_2 cat +Q197NAaQodY_0 dog +Q2Sop28spdM_0 knife +Q2bha73kLKM_0 motorcycle +Q2vBCDtNAGI_0 motorcycle +Q2zRXVl7bLI_0 motorcycle +Q3ZxsgPKTGY_2 bird +Q3ZxsgPKTGY_3 bird +onoO4tamBlA_0 knife +onpRejbK_VE_0 umbrella +ooJg7-nxmUw_0 motorcycle +opOHceUyoXk_0 cat +opb_qoqO05s_0 bird +oqUbqkDsSzI_1 knife +oqvnxRx-0J4_1 bird +oq4KPP5PYAo_1 motorcycle +orQkUDPfTg8_0 boat +orTFjuPHzxU_3 dog +orcE_uPKO_c_0 bird +ormZXNXni-U_0 dog +osYgSn6yOG0_0 cat +os3H6KzvGEg_1 knife +otHFt4YAKeI_2 dog +otvQKWvIXAE_0 bus +ouFwG2YU59c_0 motorcycle +ouNsmVT6GRU_0 car +ouqFEe0ud_U_0 motorcycle +ovHCJGK35r0_0 knife +ovHCJGK35r0_1 knife +ovQY7VA36gU_0 bird +ovRBelXjQ-A_0 bird +ovaFSf6jda4_1 boat +ovnkb_MuAlg_0 bus +ov9yaGUtSEw_0 bear +ov9yaGUtSEw_1 bear +owKiuZVov4U_2 dog +owaIraEDvqI_0 umbrella +owaIraEDvqI_1 umbrella +owb-43QL8Dc_0 cat +oxKhcqfQV7k_0 umbrella +oxZ42ECABUo_0 motorcycle +oxdCJK5GPS8_0 dog +oxyS9oNIBaQ_2 boat +oy52khlb79k_0 cat +oy885M8rmDM_0 bus +oy_Efqu_Zhk_0 knife +o0CsAQaDp1k_0 boat +o0VArHW9gpE_2 dog +o0yyk1GchoE_2 knife +o06poedEjtM_2 knife +o1RqDbHx0IA_0 umbrella +o12Lc5yZNco_1 bear +o2E2ypLvzOo_1 car +Q34_kBWh3QU_0 motorcycle +Q4IH3ZOVKFQ_5 bus +Q4TELEHdcjA_0 motorcycle +Q4YD_lW8JFE_1 knife +Q4afI-fku0A_0 knife +Q4d0z-q-UXQ_0 bird +Q4jZeoLzZXs_2 bird +Q5DrYh7pcTg_0 cat +Q5RabF9bK3o_0 car +Q5cY3mt9NHI_1 car +Q5cY3mt9NHI_3 car +Q6Lg4c8W2XQ_0 bus +Q7SXsNoT9cc_1 boat +Q7TDTHQoPGc_0 bird +Q7TZ3TlDNzI_0 bird +Q7V8JjnLW_A_0 person +Q7a4tWAU7-o_0 dog +Q8gHTSzR6h0_0 cat +Q807ZgwscUk_0 cat +Q9LvGsq1Mas_2 bird +Q9fbeFbARPY_0 bird +Q9qA-2ofuFc_0 dog +Q9qA-2ofuFc_1 dog +Q-JQokKqXZM_0 motorcycle +Q-STF8c8RSE_0 motorcycle +Q-S6ypfxn4w_1 bus +Q-VqbNMPAjE_0 dog +Q_a7bRv2dM0_1 cat +RAQAfTprH5s_0 cat +RAc8MyscjAA_4 bear +RAc8MyscjAA_0 bear +RAc8MyscjAA_3 bear +RAqMmf5FS_Y_0 dog +RBNNklw-NjE_0 car +RBNNklw-NjE_1 car +RBdpxD5mMy8_0 cat +RBssHo0ygdI_2 car +RBssHo0ygdI_1 car +RBvocl1t9qM_0 car +RBvocl1t9qM_1 car +RCzBVv_Vddo_0 dog +RC444E40nLY_0 cat +RC_ckl7o7sc_0 dog +RDq9wvYEiSI_0 umbrella +RD8OUO8u7oQ_0 person +REBpFtJosSc_3 bear +REBpFtJosSc_4 bear +REBpFtJosSc_0 bear +REbm5i5vhcQ_0 umbrella +REbm5i5vhcQ_1 umbrella +REiwqNPkmew_4 bear +REiwqNPkmew_3 bear +REjT99mHV_g_0 cat +RFIE-agz3SA_0 dog +RFUZkHtGWvg_2 bird +RFUZkHtGWvg_1 bird +RFZG72_XG3U_0 motorcycle +RFcz2p3w1oc_0 bus +RFhEq5WF9Io_0 motorcycle +RFqSKdzXQFQ_0 bus +o2z2zu4L1Ho_0 cat +o3OdAgJnYlw_0 umbrella +o3TpeQ7mhIQ_0 bear +o4It_gqHKoM_0 bus +o4It_gqHKoM_4 bus +o4It_gqHKoM_5 bus +o4bpCoFINtY_0 bird +o4yKF7ZQge8_0 cat +o4yxnKhoWrQ_0 cat +o49yvv0vmJQ_0 knife +o5TWf69h978_0 motorcycle +o5bJmNSZmGE_0 cat +o6vw6_1pc_g_1 person +o6x94jhuMEw_0 cat +o7UXYGmFww0_0 knife +o8BqJTsAjnI_0 boat +o8BqJTsAjnI_2 boat +o8Gr9wZzcA0_0 knife +o83uI_tdkrE_2 car +o9UpoUWgJWw_1 motorcycle +o9YqiVSTBVs_0 motorcycle +o9qB9kYt9Bc_0 motorcycle +o9vRwcqz30w_2 bear +o98cAmKOAtk_2 truck +o_BpJHlv8bY_0 cat +o_NYHfqWzBw_0 cat +pAP3j2UmTAA_0 car +pAuz372kMrs_0 boat +pAvBjM_cSCk_0 umbrella +pA_f-DZ2FdI_1 bus +pBj4KFDTwGg_0 cat +pCPwOGObTcs_0 umbrella +pCXmnj6vY7o_1 knife +pCa3Tf27TcY_3 bear +pCdwcy8npiE_2 bear +pCfA0E-TIXo_0 motorcycle +pC9mu-CQ9fg_0 cat +pDjjH1_G6Z0_1 motorcycle +pDjjH1_G6Z0_0 person +RGT-FumEK7I_0 car +RGXgv5gqM8k_0 umbrella +RGiE9-CME30_0 motorcycle +RG6y27UUUMI_0 knife +RHHOcUqVF80_0 knife +RHSfZLRz95o_0 boat +RHrnX__15lI_0 car +RIBigSX5_90_1 bear +RImslgwYbYk_2 boat +RIwUvnURoqs_0 cat +RI14PaJgb7E_0 umbrella +RJ95URcz63g_1 motorcycle +RJ95URcz63g_0 motorcycle +RKZ4YVnDywQ_0 knife +RKa1tJXFTAw_1 cat +RK8ZJaF2QHQ_5 bear +RK8ZJaF2QHQ_6 bear +RLP9M0bfpWo_0 umbrella +RMapunE2wEc_0 boat +RNPKsQSr2o8_0 knife +ROfxuPZWET8_2 bear +ROkJ79Y9T7s_0 motorcycle +RPJ0SJeC5ck_1 car +RPJ0SJeC5ck_2 car +RPWms_VL6wY_0 bus +RPhdhEKBBAM_0 motorcycle +RP81F6rIP4w_0 motorcycle +RQ5liX_fOJw_0 umbrella +RREV1E0Mbhs_1 knife +RSXIvkOJQq0_1 knife +RSq71vJH9yc_0 bus +RStmsJCm7mo_1 car +RSztnKS1IYI_0 car +RTTysK1hBpg_0 boat +RTvVXaA35DI_0 motorcycle +RT0tTVP14XE_1 umbrella +RT0tTVP14XE_4 umbrella +RT0tTVP14XE_6 umbrella +pFCVfOX_UJ0_0 umbrella +pGJMt9Jmk_Y_0 car +pGnZDXcCjSc_0 bus +pHC850dBc-E_1 car +pHf0EP0QU9Y_0 cat +pHueI1IUqzg_0 car +pIhqwiD8cks_0 bus +pJXxn2DRWyI_0 bus +pJYetmKuiE0_4 bear +pJj28cMLcZc_0 knife +pJl14EZ6-Mc_0 umbrella +pKPRv5lL_DQ_1 motorcycle +pKz_g-J2O-A_1 bus +pK1umZxS4nE_0 knife +pLEV-uFmv6I_0 cat +pLI_HgRsRow_4 bus +pLQDtquQaSE_0 bear +pLp7vmowqNs_0 motorcycle +pMHRlQ2NxeA_1 boat +pMaT7qWMaV4_1 bear +pMg2xwjkfVc_4 umbrella +pNHKmiurxTg_0 knife +pOCvwILBOCY_0 boat +pOjuNMevoaM_0 car +pOq6RrgrXWY_0 motorcycle +pPyL4U8gYpM_0 cat +pP22coNl6r4_0 bus +pP5q-Bszfh0_0 motorcycle +pQMkOOTP0Lk_0 cat +pSJypg6az1w_0 bus +pSjKd_x9ycU_1 boat +pSz961UYSrY_0 motorcycle +RVvfyYc8jws_0 umbrella +RXAW31Vm7pU_0 motorcycle +RXQ-E6_Y__c_1 car +RZAlTTj0Z4o_0 motorcycle +RZAlTTj0Z4o_1 motorcycle +RZL2H_-y3vE_0 umbrella +RZrAehHE8aA_2 knife +RZrAehHE8aA_0 knife +RZ0yQkyeSd8_0 boat +RaZy_JiiJ3E_0 motorcycle +Ra48MJPLmUw_2 motorcycle +Ra48MJPLmUw_0 motorcycle +Ra48MJPLmUw_1 motorcycle +RbQTcoldE8M_0 bus +RbRqkcC6l_A_0 knife +Rb5tGSqtlFU_1 motorcycle +RcSm0O0Ylc0_0 cat +RdNjlTlNbEA_0 bus +RdP6hW5p6ys_4 car +RdUjywh70lM_1 cat +RdlWUo9fYmA_0 motorcycle +Rd4TvDZNwHs_0 umbrella +RfNyu5aooJs_0 car +RfrtTbza00c_0 boat +RgBWTOo9hqo_0 cat +RgC0rdZCy2c_0 motorcycle +RgFR8z8IzAQ_0 cat +RgUwlXzmX4Q_0 boat +RhYw3jSi0xY_0 bus +Rhqz5maRjNs_0 cat +Rh0zI8vpRWk_2 knife +Rh7Y69j41EY_0 bus +RiCptCjnrqk_0 cat +RiOw5wO0xTg_3 knife +Rid6twPtgIo_0 cat +pTGbMPGsbCU_0 car +pTSbrP23T0s_0 motorcycle +pVCT-jEaSPE_1 bear +pV8hPodV-zY_0 motorcycle +pXBltXzZZe0_0 car +pXcoix_wq4E_0 cat +pZC4kceO-0g_0 bus +pZJDlV5VS3Y_0 motorcycle +pZ7RohF8JgE_1 knife +paF1hQf-YFk_0 boat +palM4nIm6GU_0 motorcycle +pba0HVNnmbc_1 motorcycle +pcOsY0MSbh0_0 bus +pcb_jPcg_U8_0 bus +pcpHHo_gp-Q_0 cat +pc2aHxzJDtQ_0 cat +pdDVE4LsX54_4 car +pdDVE4LsX54_0 car +pdDVE4LsX54_1 car +pdDVE4LsX54_2 car +pdDVE4LsX54_3 car +pdDVE4LsX54_5 car +pd0IEWCwpUY_0 bear +pd1BZjvbFNI_0 knife +pgKdcFb2680_1 motorcycle +pg4m5Fi0Mhc_1 car +Riq87Q_unPU_0 cat +RjDo0UDX9Ws_1 knife +RjItZnZQBKk_0 car +RjqDxu3wf5o_0 cat +RkSzsg-k14I_0 boat +RktoQu-Wk0M_0 cat +RmFxIMl1tSU_0 bear +Rmpv0oMhUCc_0 bus +RnEWcQNxWGY_0 motorcycle +RnPY8wgKxj4_1 cat +RnQ-v8AJQbc_0 motorcycle +RnjU70B_0cU_0 bear +RpTRF_oB1-I_2 bear +Rpn1EcI_ESo_0 knife +Rp8euBdhkR0_0 motorcycle +Rp8euBdhkR0_1 motorcycle +Rqs856i0jbs_0 umbrella +Rrj0e5VSIgY_0 car +Rsw947loMaA_0 cat +RtSEfWF3PdI_1 knife +Rtng6SCToEM_0 car +RufUHX-TjyM_0 bear +RvHvTQC9Kr4_0 bear +RwC5kkt5VDU_1 person +RwC5kkt5VDU_5 motorcycle +RwVgY7zgnYM_0 knife +RwVgY7zgnYM_1 knife +RwYiNSlAYcE_0 car +RwpY0u7t3vE_0 umbrella +Rwp_dTfFI28_4 boat +Rwz5T35lNgY_0 cat +Rw5dzv79c-M_1 motorcycle +RxLwy_iZqKg_1 bear +RxWhDOyHYNo_0 cat +phJS1iN6HFo_0 umbrella +phTyZcbKeQw_5 bus +pihR4mhfwxM_0 motorcycle +pim0lzR8i1g_0 cat +pix5Cxt_fUM_3 knife +pjgi60dJalw_0 car +pjgi60dJalw_1 car +pjhNnA0142Y_0 motorcycle +pmszdloBDwA_0 bear +pmszdloBDwA_2 bear +pmszdloBDwA_5 bear +pnMd28rPX7M_0 motorcycle +pncTBxEM4WM_0 bus +pnjPhdpuKGc_0 motorcycle +pn0ZChK2ASs_0 bear +ppAj6dnl62Y_0 knife +ppAj6dnl62Y_1 knife +ppJXGy7snUw_1 knife +ppwjIgwParM_0 boat +pq1swOh85gc_0 boat +pq1swOh85gc_2 boat +pq1swOh85gc_1 boat +priwWNrQnkI_1 bear +prwglbuvyZ8_1 knife +prw0IWDYBUM_0 cat +pr3LOwTWNnk_1 bus +psOuOLCJNk8_0 cat +psTqTt0np_I_11 bear +psTqTt0np_I_3 bear +psTqTt0np_I_6 bear +psUASBNRwIE_0 car +psUASBNRwIE_2 car +psUASBNRwIE_4 car +ptCx-L_n2Yg_2 bear +ptNC5ou_rOQ_1 motorcycle +puZUIBS4Ceg_0 cat +puw9BfAKOHU_0 bus +RxiBbfFH3is_0 knife +RxiE2beIvjQ_0 bear +RyWLXS1Vrco_0 knife +Ry4q0UokRjo_0 motorcycle +RzWczJnyzmg_0 cat +RzWdM4_lg2c_4 bear +Rzj5xv434WA_0 bear +RzrQOptkjFM_0 motorcycle +RzrQOptkjFM_1 motorcycle +R0hj1kAnMgs_0 car +R0w6j1wmwo0_2 knife +R0w6j1wmwo0_3 knife +R1Fkwaa8CxU_0 motorcycle +R2FlyNrjZBQ_2 boat +R2FlyNrjZBQ_1 boat +R2Fps165H9g_2 knife +R2XiIC1qbAM_0 bear +R2YmjDNC8oo_0 bear +R2duXYQhnFA_0 car +R2sy6qbPc4c_0 car +R23ZSmBA2Rg_0 knife +R3zhr1iboG0_0 bus +R4ktPNCb564_1 bus +R4vLajpLSMk_0 cat +R5CBlOfUL4w_0 person +R5cIoEcqZ9E_1 knife +R5r3AIx_BoU_1 knife +R5r3AIx_BoU_2 knife +R6PuHPDiwPs_1 car +R6f_t-MqO_s_0 bus +R6tsNuvoTus_0 car +R6uZ5JpxQ88_0 cat +R6wk6JHQSeI_0 knife +R6wsV6cYN_w_1 bus +R7w-mdDyhG8_2 knife +R8TV702EIqs_0 knife +R8j0mjQR4lI_4 boat +R84Bj4PKOvE_0 bear +R84Bj4PKOvE_1 bear +R9LK4x3pO0Y_0 cat +R9L1I9EEE0g_0 motorcycle +R9zDzUslz9g_0 car +R9607CioN3U_0 car +R99fGQRB6rM_1 car +R-UGxl6KGoo_1 bus +R_LEKDTlVvs_5 boat +R_NxqXdz3RA_0 car +R_UPR78XIvA_0 knife +SAFptHT-UpM_1 boat +SAFptHT-UpM_2 boat +pvrO7c2imos_4 car +pwgqJO3yKHI_0 cat +pwwdlKxLCqQ_1 knife +pxBtDlmwesI_0 car +pxIlEGkEw5U_0 cat +pxwl3iVkx08_0 boat +pyAuY2v2U0I_0 cat +pyTXP2GZRuM_0 knife +pyTXP2GZRuM_1 knife +pyTXP2GZRuM_2 knife +py0K3KEYfjA_2 umbrella +py0K3KEYfjA_4 umbrella +pzZvI_g1S8M_0 motorcycle +p03u2BJIvyE_0 bear +p03u2BJIvyE_1 bear +p1p9QUFIi_8_0 bus +p1_thBtA2-g_1 bear +p2pRN03gXFk_0 cat +p26eBX5AGCo_0 boat +p3MF-uxvtWk_0 bear +p32jOqTS5ec_0 cat +p4MmW7gFlLI_0 motorcycle +p4MmW7gFlLI_1 motorcycle +p5NxEAfgmro_0 motorcycle +p5bLvlU8ua0_0 motorcycle +p5lUPYsz-HE_0 cat +p5vt7l9pW-0_1 motorcycle +p5vt7l9pW-0_0 person +p5_O08ZNK_c_0 motorcycle +p6GkhJZsCi8_0 cat +p6Rtu645O08_1 motorcycle +p6Rtu645O08_0 motorcycle +p6dBx3tBRr4_5 bear +p6dCoZRaQOA_0 boat +p6dCoZRaQOA_1 boat +p6dCoZRaQOA_2 boat +p7OlEbiu5to_0 cat +p7WwUD62qfY_0 motorcycle +p7gjVQyX07A_0 cat +p7pnYAaDqPI_0 umbrella +p7sHze5SC0g_4 bear +p8MEDllYMKg_0 cat +p8RUtiaGu5U_0 cat +p8ZUCNMnKpE_0 car +p89fuT8e_zk_0 cat +p8-8JqAgtv0_0 motorcycle +p9XjLjpQX-8_0 cat +p9by0qLqHOQ_0 knife +SAkHT1Ozg1c_0 motorcycle +SAkHT1Ozg1c_2 motorcycle +SA1Tb1XbngU_0 cat +SB1UBp1PVf4_2 bus +SDKsL-L7GbI_0 knife +SDbe9JVnITk_0 knife +SDk3Y3jzalg_0 knife +SEp92WMharw_0 bus +SExW2mVb1Mc_2 car +SExW2mVb1Mc_0 car +SExW2mVb1Mc_1 car +SE5Rg8Qpb8c_1 knife +SFB2FGuZb6w_0 motorcycle +SFMc-UCkcT8_0 cat +SF8c7EeFPPk_0 motorcycle +SHcJfBJBQe4_0 bear +SHxyKRdKRc8_0 cat +SHxyKRdKRc8_1 cat +SH1noq6GrKw_0 knife +SISqo1FBefA_0 bus +SIbLAYX2J_A_0 bear +SJAZnOnRtag_1 bear +SJsxWsiEuTg_0 motorcycle +SKNl4frouUY_1 knife +SLEOr8bmm2w_0 motorcycle +SLEOr8bmm2w_1 motorcycle +SLzqvins4p8_0 bear +SMYpv_Ea3w8_0 person +SM6BtnyDz5w_0 cat +SNZ0xGGmZvU_0 knife +SNhnfqJHoI4_0 motorcycle +SNl4Gq_2aVQ_0 bear +SNrosAtwG2k_4 bus +SOYkQc-toMU_0 bear +SOYkQc-toMU_2 bear +p-J0yyoF0lU_0 motorcycle +p_C9Zwt3N5c_0 umbrella +qAJSLnflSrQ_0 cat +qA5rC8MxCoA_2 bear +qCzILENpEWk_0 boat +qCz4ft26CAw_2 knife +qDobzjbo_aM_0 cat +qEcNn2_TQC8_0 cat +qEei5YCRiHA_0 car +qEj3r8dtvKg_0 boat +qE5fKHWTLMw_1 bear +qFR-yuWiHVk_3 knife +qFR-yuWiHVk_4 knife +qFwugOO0pC0_0 knife +qGjYX-iNrPE_0 boat +qGohF2oMPS0_0 motorcycle +qGxfRwBmBEc_0 motorcycle +qGxfRwBmBEc_1 motorcycle +qHKwI-35nNU_0 motorcycle +qIIu-MIIYIE_0 boat +qINDYDOlPLA_0 motorcycle +qIPydTwqwmI_3 car +qIPydTwqwmI_0 car +qIPydTwqwmI_1 car +qIPydTwqwmI_2 car +qIkNPwKd6ag_0 knife +qIkNPwKd6ag_1 knife +qInP3tWVtWE_0 cat +qJMxoAbx9YU_0 boat +qKxQVpaLChg_0 bear +qLfa8e4ffQY_0 bus +qL6LVXg4Vt4_0 cat +qMEMl1FFVIM_2 umbrella +SPRByN4TiFg_1 boat +SPsOjXxZymk_1 boat +SQ_ChhUwWng_0 bus +SRUB2kzDBTk_0 person +SSFOqr1ARgI_1 umbrella +SSaN8vntuYs_0 bear +STTRwCtQ8_8_0 boat +ST6aA292Pos_0 motorcycle +SUMc-5fiNzQ_0 motorcycle +SUnPNgAE_ho_2 boat +SUyRs3xvc9c_0 cat +SVBc-W37yW0_0 umbrella +SVSMGxy8Z6I_0 cat +SVXaBPnNWO0_0 knife +SVXaBPnNWO0_2 knife +SVt7vQ8LYZU_0 bear +SV70cwNA6o8_0 knife +SWJyq_mITbE_0 boat +SXmy9BLHr84_0 bus +SXvXN3waFWs_6 bear +SYCg5NuWc60_0 motorcycle +SaHw7yyoeJg_0 cat +SaSgclGWGwE_1 motorcycle +SaSgclGWGwE_3 motorcycle +Sa1iRLR4d_c_0 bus +Sa4L2rdyD10_0 knife +SbWCXCuXBqY_1 bear +Se3XbBA4N4o_3 knife +Se3wtx4DzwE_5 bus +Se3wtx4DzwE_1 bus +Se3wtx4DzwE_2 bus +qMlYXZy1Tow_0 bus +qNfS9Y5zs-Y_0 car +qOaABf_zb9U_1 boat +qO7qHolBYj4_0 bus +qO8D0E7MjOI_0 cat +qPGkJRPae6A_0 bus +qPMDgkgSTnA_2 motorcycle +qPaox7otsVI_0 knife +qPwAWEtJBqA_2 motorcycle +qPwAWEtJBqA_0 motorcycle +qPwAWEtJBqA_1 motorcycle +qPyR7CpZ6l0_0 knife +qP88t7GfZc8_0 knife +qQaIW7IjCZo_3 motorcycle +qQaIW7IjCZo_0 motorcycle +qQaIW7IjCZo_1 motorcycle +qQdtuBd-SgI_0 knife +qQlsMjenbfE_2 knife +qQ5tf8s7KrE_0 bus +qRO6U_tg6SE_0 cat +qR4kw8rf-FU_0 motorcycle +qSQGG-K89mg_1 knife +qSgOYqBt_8k_0 bus +qSnoKy6T22k_0 motorcycle +qTKtODdEZIg_0 cat +qTut_O_LppA_0 bear +qT00uOC9JpQ_0 car +qUuTEKdKNNg_0 car +qU7DT4ipQHw_0 cat +qVSnhT0Luh8_0 cat +qVyAlx4rMTo_2 bear +qV7U9CRjZGI_0 cat +qWN8i7sJyVg_4 umbrella +qWcXQWy7yw8_1 bus +qW-zRq8VTV0_0 boat +qX8RcjE0tjs_0 motorcycle +qX-YEHlu0Kg_2 knife +qZWxhCk8AX0_0 knife +qZf1fw737A8_1 car +qZyxILyLOv0_0 knife +SfZLu5uG7mc_0 car +SgDdyLB3fFo_1 motorcycle +SgHH9KN_nkY_2 motorcycle +SgOvlqqKbEI_0 bear +SgSsk-eeClA_0 cat +ShHLzcBozxo_1 boat +ShPl28Zw1kU_8 car +ShPl28Zw1kU_3 car +ShPl28Zw1kU_7 car +ShPl28Zw1kU_9 car +ShaLoFJZv-M_1 knife +ShhC84AwZ04_0 bus +Sh6uHJRUnP4_0 cat +SiSP3Kko4VM_0 bus +Si3psXQA46c_0 bus +SjLNVLIdpbc_0 cat +Sj0pcvct_3k_0 motorcycle +SkLwUmczAMo_2 knife +SkLwUmczAMo_1 knife +SkVIH0IZI1I_0 motorcycle +SlBZM22tlSU_0 knife +SlIzgQZ63h4_1 knife +SlWmnHWeqIE_0 boat +SlYqzpZkWho_0 bear +SmCvuBfyU5o_0 motorcycle +SmCvuBfyU5o_1 motorcycle +Sn8nb_cv5K4_0 motorcycle +Sn8nb_cv5K4_1 motorcycle +So5dCmgNRtU_0 bear +So-dFj7N07Y_0 car +SpGfQe7sWIQ_0 motorcycle +SpuAy2Z1ejE_0 boat +Spx8fHkY0Ac_0 bear +SqUzKvBRVmQ_0 cat +SqkoepvLN3c_0 motorcycle +SqkoepvLN3c_1 motorcycle +Sq-LvVdVwhc_4 bear +SrBwCHcEe4g_0 cat +SrPgW-L7Gps_0 bear +SrTxMAryank_0 knife +SsQb12lMU_w_1 car +SsQb12lMU_w_2 car +qZ0egYy10zs_0 cat +qaKYHGIZ8tU_0 cat +qantWNz3Z-k_0 bus +qc1U41zjMfI_0 knife +qeSfa-Xin3s_0 bear +qfZHHSjai5Q_3 motorcycle +qfZHHSjai5Q_5 motorcycle +qfZHHSjai5Q_0 motorcycle +qfZHHSjai5Q_4 motorcycle +qfZHHSjai5Q_6 motorcycle +qf4dZ323eu4_0 cat +qf5FQP-vjpY_3 bus +qgYBD0GBerg_0 knife +qglTXvFe5vw_0 motorcycle +qgr1pdkQkKM_1 knife +qhTOaoL2B54_0 bus +qhgQ0_y6Jr8_0 motorcycle +qhyihSkbubs_1 bus +qiW4cUVZCJA_0 motorcycle +qjfkIHC3sNA_0 bus +qj1y76m_WFg_1 car +qklXdTo1CKQ_0 truck +qlGmmBY7ITI_0 cat +qlGmmBY7ITI_1 cat +qlfCKWLj_xU_0 boat +qlvwUVksAC4_0 cat +qnaQOGGmyhI_1 motorcycle +qo2tG-wOpLI_3 car +qpBRU2SONe0_4 bear +qpNPlLO7Wdo_6 bus +SsWwZCQR8pA_1 bus +Ss6lM7iutJ0_2 boat +Ss-ENa079_Y_0 car +Stg0xs4yv5A_3 bus +Stg0xs4yv5A_1 bus +Stg0xs4yv5A_2 bus +StoHoHg6XHo_0 motorcycle +SuoVrAXkHsM_1 boat +Sv-Xsjm8Seo_0 boat +Swfda4hcQzo_18 umbrella +Swfda4hcQzo_0 umbrella +Swfda4hcQzo_3 umbrella +SwrxLGIVuNg_1 bus +Sw01FqLPH0o_0 motorcycle +SxxBAhDGWzU_1 car +SybtH9db7tI_1 boat +SybtH9db7tI_6 boat +SybtH9db7tI_0 boat +SybtH9db7tI_4 boat +SybtH9db7tI_5 boat +Syk5Jc9_tQA_1 boat +SywBQoMh8Q8_1 car +SzD0AW8MKxY_1 car +Sz3ay4xexe0_0 motorcycle +Sz3oWSS6V3s_0 bus +S0AoM2Xz64Y_0 motorcycle +S09dKnW798o_0 cat +S12WKCebYHg_0 boat +S2YoTKzOHW8_0 umbrella +S3O_xjPQToU_0 knife +S4lNN0zJE4A_0 cat +S49Hdfpc-SI_1 boat +S5VjgUVKjV0_0 cat +S5Z4g_SORHc_3 knife +S5Z4g_SORHc_4 knife +S6crKzUWKYI_0 umbrella +S6ksiMdECu8_0 umbrella +qp11ZgRmeck_1 motorcycle +qqd7FMwn5Ks_0 cat +qqmk0BKAubw_0 boat +qqo83uqRldw_0 motorcycle +qqumKQ_igJQ_0 motorcycle +qqumKQ_igJQ_1 motorcycle +qrHPEAVq_yE_1 boat +qrJljeVBE-k_0 boat +qrJljeVBE-k_2 boat +qrTOqXRwHqM_1 bear +qrTm-7zA5FM_1 motorcycle +qrU7MAMf42A_0 motorcycle +qrfZoDvW7wI_2 bus +qsFkwL9ikBE_6 umbrella +qsFkwL9ikBE_0 umbrella +qsbpGZepU_4_0 motorcycle +qs4ACjrDQvo_0 cat +qtEJPGYfmb0_0 motorcycle +qtQNJD43Z30_0 knife +qthVtX1KeJY_0 cat +qtmXJD337Sg_0 cat +quMSh4JZfSE_0 bear +quSzbk4CkBE_0 car +quZjkqmOTys_0 cat +qvAPzGCqVG0_0 bus +qvAPzGCqVG0_1 bus +qvCVL7reF8g_2 bear +qwBsDRYIhwg_0 cat +qwI3fCK486I_0 cat +qwZ_bpVY018_1 bear +qwcgkEVHQS4_1 motorcycle +qxwgvTIA0Oc_0 umbrella +qykj452YYlU_0 boat +qzjG5RMNfB0_0 cat +q0tjDTtHr00_3 knife +q1LbqldHuM0_0 knife +q1QElQCedrc_0 umbrella +q15Lr3-V3qI_2 motorcycle +q2K3ctdaVGU_0 knife +q2MasRNKQxI_0 bus +q2NfowB59fs_0 motorcycle +q3J7hUfBGGQ_0 cat +q4EXWy685Wo_0 person +q4EXWy685Wo_3 motorcycle +q4EXWy685Wo_6 motorcycle +q4EXWy685Wo_7 motorcycle +S7SEfKdokC0_1 bus +S7-k1XdAR7Q_0 cat +S8BbQRnxfqY_0 cat +S8WFgIrdEyI_0 car +S9LooqaA-VA_0 cat +S9wDiwQMla8_0 person +S9wDiwQMla8_1 motorcycle +S9wDiwQMla8_2 motorcycle +S9xCWTCFhNc_0 motorcycle +S-T-e07Bgys_0 motorcycle +S_K_nwYUS2o_0 cat +S_09gd9e0zE_0 boat +S_5w6lmw0DI_0 knife +TAzjOrAfzFM_0 cat +TA1NbMN7gNo_0 motorcycle +TBvuwl0phUE_0 motorcycle +TBy---hD-FA_0 bear +TB9qJG8A-H4_0 car +TCS6svwO2AE_0 boat +TCVj-PtxnsQ_0 bear +TDSmQkKnGFU_1 car +TENive2WCAw_0 cat +TFUV5Dy2MvE_0 motorcycle +TFu5bNUW02Q_0 bus +TIZr3Y-PLQM_1 knife +TIpoS2Jymv8_2 knife +TJJgVPay9LE_0 bus +q4zFevdC3-w_1 knife +q5D67534lFM_0 motorcycle +q5ESvcujAps_0 person +q5wOimcVyaI_0 cat +q6YyhMSTSjg_2 bus +q6YyhMSTSjg_3 bus +q65QzEDi_jo_1 motorcycle +q8nG4OvfGhY_0 cat +q8oKL5zvWZw_0 cat +q9QycGD31Co_0 cat +q9ZSVLXRUx8_1 cat +q9p4QZdwQ0I_0 boat +q-Sw3Dx1Xb0_0 knife +q-lbxXK_UY8_0 bear +q-nt9k61jqQ_2 boat +q_NnyABqOFg_3 boat +rAcvNOp95pA_0 car +rApBsMx8ZjU_1 umbrella +rAtKVQ_h94Q_1 car +rBLqbf-KdaY_0 car +rBjCxCwLz84_0 car +rBl7T312SPQ_0 cat +rBnSmzTRsqE_0 car +rCAA1xoobto_0 car +rCOxllaoO64_0 bear +rCrQRhaJeAA_0 bus +rDEW_AdTSH4_1 cat +rDEdeXsgOdU_0 umbrella +rEL7A7rKARs_3 knife +rFF0purpqAU_2 knife +rGgvqpRsaew_0 bus +rGlpoWppAfU_0 car +rG4cDTukyNw_0 car +rG4ld81Rxt8_0 car +rHHUlsaTde8_2 bus +TKCXvzTT2ws_0 umbrella +TMyv9XNlPGQ_0 bus +TQWq_YDrKc0_2 knife +TQm0C-2ersM_8 boat +TQm0C-2ersM_10 boat +TQm0C-2ersM_1 boat +TQm0C-2ersM_5 boat +TQm0C-2ersM_6 boat +TREARdQ16GQ_0 car +TREARdQ16GQ_1 car +TSQwlIeADdw_0 bear +TSQwlIeADdw_1 bear +TSQwlIeADdw_2 bear +TSpUcayboiM_0 car +TS7UuEszy9E_0 car +TTQQky-HcCs_0 knife +TTdbV_lHq_s_0 cat +TUrnPZr3eXs_0 bus +TVjvTR7CrNE_0 knife +TVvo40ERO9Y_0 cat +TW6cU7OYa60_1 cat +TXrnNVUe53o_0 boat +TXsQGHJjWhI_2 knife +TX2BAlXe5IA_0 boat +TX2BAlXe5IA_2 boat +rIUepAhKVnM_0 cat +rIc3ZEnqjQA_0 umbrella +rIezbmq7N9U_3 bear +rI79TJwwnW4_3 knife +rJGGo2bI150_0 bear +rJGGo2bI150_1 bear +rJGGo2bI150_2 bear +rKiQjOPzf0s_0 cat +rKs2bGgU29k_0 cat +rLm1866Q28U_3 umbrella +rLm1866Q28U_0 umbrella +rLm1866Q28U_1 umbrella +rNlm7i1BcaQ_0 cat +rNw1jiERG4I_1 car +rOtd7pdh-zY_0 cat +rO0qo7r4TTc_0 cat +rPCOxxRwiTM_0 bus +rP6vb-cxVcI_0 bus +rQBwAWkz3Ao_2 boat +rQBwAWkz3Ao_0 boat +rQBwAWkz3Ao_1 boat +rRL4f466oNQ_0 umbrella +rR9vwlyXtYs_0 bus +rSNfdcbzEhE_1 boat +rSNfdcbzEhE_2 boat +rSNfdcbzEhE_3 boat +rSNfdcbzEhE_6 boat +rSNzuWEgSeg_0 cat +rSWYvSf29vQ_1 cat +rTM-3OYHQZA_0 bear +rTM-3OYHQZA_9 bear +rTreVVS3XVg_0 umbrella +rUcsGq10bCk_0 umbrella +rWLG9njOx1k_0 car +TYuoW3gezZ4_1 car +TZFETDh9bQo_1 bear +TZFETDh9bQo_3 bear +Tain2YW14ok_0 umbrella +Tb943q0WnTY_0 car +TcfdUbzZcIc_0 knife +TcnKT-jCrxQ_1 bus +TcnKT-jCrxQ_0 bus +TcnKT-jCrxQ_4 bus +TdmeXkKeGmE_0 knife +Tdxsosl1CIk_0 umbrella +TeF2gxyzjF8_4 knife +TeM8oPJR8nM_2 bus +TeM8oPJR8nM_4 bus +TeM8oPJR8nM_7 bus +TeSMF-Tw8b8_0 bus +Tf8ZmK4GZYU_0 bus +Tf9piH7b4Js_1 bus +TihSkV4th6I_0 umbrella +TimXSaV1u4M_2 bus +Tjs55_3zB_o_0 knife +TjvHNNlcym8_0 knife +TjvHNNlcym8_4 knife +Tj-U_ZtaHe0_0 boat +TkmEiKe_Uto_0 boat +TkuUMAPSGiU_1 car +TnN1RBRfLnE_0 umbrella +TnN1RBRfLnE_1 umbrella +TnXDBpRvE_U_0 bear +rWw_OZqgPk8_3 bus +rYlL6avPERw_0 car +rZDchhWp8lc_1 bus +rZ7XejB4nyk_0 boat +rawi3Ka9Oew_1 car +rawi3Ka9Oew_0 car +rbONk59p13Q_0 bear +rbWOxoprQ2M_0 bear +rbXmAC9QV2A_0 car +rbjK97ECn_A_0 boat +rcrE_BJU-n4_0 knife +rcrE_BJU-n4_2 knife +rfksy8z9X40_0 car +rgWglS6-TTw_1 knife +rhIa7DWBXUM_1 car +rjVLfZDg-1g_0 boat +rk9SO8fR7-0_1 bus +rk9SO8fR7-0_4 bus +rlBfiB0epGw_1 knife +rlLJTjn9vkk_0 umbrella +ToclpwxGMe8_0 bus +TpKpXHgy7yw_2 knife +TpKpXHgy7yw_5 knife +TqPnQuSGm2Y_0 bus +TqZZfXdm7D0_0 car +Tqnj4qeawHg_0 boat +TqsQOw3CqXo_0 bus +TrXkieSIkII_0 boat +TsfcgwFff0k_0 bear +TsrQwMo3niY_1 bear +Ts8Wofx6QYY_0 car +TusmYht5g7o_0 bus +TvbiwdoAnv8_0 boat +TvvBAOBoHFU_1 umbrella +TwEihF94LGQ_0 umbrella +TwSkZlbuaEU_0 bus +TxUm-m-jFQM_0 knife +TyV9inNHHAE_0 bus +Ty_FDwb_nLY_2 car +T0Mp-gJmMlU_2 bear +T0Mp-gJmMlU_3 bear +T0tT7l2X1_g_0 bus +T1Zywya-PcI_2 car +T1Zywya-PcI_3 car +T1Zywya-PcI_1 car +roNPRQwafcU_2 bus +roNPRQwafcU_5 bus +roW8_xIYVAk_0 knife +roXQ3vv08_A_0 bear +rqA8P346qIQ_1 boat +rqDqbsbIcc8_0 bus +rq5jwk8hqYA_0 bus +rq5jwk8hqYA_1 bus +rriv5ZJYcJI_1 knife +rsMmhzkVg_0_0 boat +rta_HO-3L_A_3 bus +rwH7x0MR_38_0 boat +rwS5mEyV7Go_1 knife +rwS5mEyV7Go_2 knife +rwcVAIM0TvE_0 bus +rwcVAIM0TvE_1 bus +rwu0xKkvzvA_0 knife +rxRxMZ6DIjw_2 umbrella +rxSJHCdoi0c_0 bear +rxm15TcjWqQ_0 knife +ryBGF3WFvsY_0 bus +ryBGF3WFvsY_1 bus +ry0Pnb8VkxU_0 bus +ry0Pnb8VkxU_1 bus +ry0Pnb8VkxU_3 bus +rzDa9eW_dpg_3 car +rzDa9eW_dpg_5 car +rzOhM6n6Amc_0 boat +T21Uim3jGuo_1 bear +T3wZwUQ_7q4_0 umbrella +T5ZgfFcAd94_0 bus +T6QiKZd4bH0_0 knife +T7h2fJLtABk_0 knife +T8C-sLfGg3A_0 boat +T-5AESRu0pM_0 car +UAptbKXXoJI_1 bear +UBk45sVKl_o_0 umbrella +UCnTA86V3o0_0 knife +UDmjHWk8iRk_1 bear +UE1kUiVy7LA_1 car +UFPrfB6_TJY_0 bear +UFQmHju3MrM_0 bear +r1JK0UIvyoM_0 bus +r1YNttJqXjI_1 bear +r2GN4IDacgM_0 boat +r2GN4IDacgM_1 boat +r2GN4IDacgM_2 boat +r2GN4IDacgM_3 boat +r2sw-3mWNEQ_1 boat +r4U8cMe6_Uo_0 umbrella +r4cneWcmGJc_0 bear +r4cneWcmGJc_1 bear +r43KKtRQNxw_0 knife +r5c09tdbF3U_0 knife +r6HzXMpwuOg_0 boat +r7V8M9vMX8I_0 boat +r8oV5neCRZc_1 bear +r-Wqqn-oS_0_0 bear +r_squ5DWzV0_0 bus +sAa0aLc0rvM_0 bus +sAo-z30biYY_0 car +sAqB_9DrpiU_0 boat +sCGJB9oAeHo_0 car +sCX1zbdQvbE_0 boat +UHvwjd6eSDY_0 car +UH6GKx07mu0_2 bear +UIlo6WvfABM_0 boat +UJ7xasCu9yw_0 knife +UKdl8BrKy4g_0 knife +ULTTzu_-eQI_2 bus +ULgPda0ny1Q_0 boat +ULxGPhbhuwI_0 umbrella +UMQ6fAZTiLo_0 umbrella +UNfKxOwP1V8_0 bear +UNyq1SNbNPk_1 bear +UP2WXifDFc0_0 bus +UQdjo1v_Hv0_0 car +UQrP0Wa7bfA_0 bus +UQ90qkTMSes_0 umbrella +URiNDCZBU7E_1 car +URmMAndDPfQ_0 boat +USYudaDNkeU_2 knife +USYudaDNkeU_3 knife +UTx1Fw7nQcQ_0 bus +UVGq9IRroYo_0 boat +sDSmkWE8qw4_0 knife +sEnhkLttWlw_0 bus +sFgXir9g_Os_0 car +sF2EQhRNlQc_0 umbrella +sGpQTqemybM_0 bear +sGzXdAI4YSQ_0 bear +sG_AruJlxiw_0 umbrella +sJA7-N7htNo_0 bear +sJL716urwpY_1 car +sJL716urwpY_0 car +sJTLB7bgb0k_1 knife +sJsEpKneYMs_1 bus +sMm8f8vBx7c_0 umbrella +sOQWtx6GiR4_1 umbrella +sOQWtx6GiR4_0 umbrella +sOvnHbg6d_8_0 umbrella +sPDY-ey2kNA_0 umbrella +sPDY-ey2kNA_1 umbrella +sQEBpH647Mw_0 umbrella +sQJr7LooP_s_1 boat +sQftML4HXiU_1 knife +sQvi3OxMoKU_0 bear +sQvi3OxMoKU_1 bear +sQvi3OxMoKU_2 bear +UWJIq_1uAnA_0 boat +UXDmIQTthAE_0 knife +UYRhIhbuh34_0 boat +UanzlUcmoJY_1 bus +Ubj2t-7KcJk_2 car +Ub5O76sDojg_0 car +UcBLQsI3Dzs_0 car +UcKyiCjpXoA_3 bear +UdFEBlYt9tM_0 umbrella +UdaAkO2f_pU_0 bus +UeQLdrnbe8E_1 bear +UeQLdrnbe8E_3 bear +UgHNBgeg9cY_3 knife +Ugh33I0Qxi4_0 umbrella +UgkXJsrPys0_0 umbrella +UhgJaZWsdCQ_0 knife +UhupGJ7k3Q0_0 knife +UhvhrEMHY0E_0 boat +UhwOdFtF8os_0 bus +UiZ3tYMpOic_1 umbrella +UjTdR_85bTo_0 umbrella +sSPe9VqmSuU_2 bear +sS-GtompdcQ_1 boat +sUhpJsSmrzA_4 boat +sU-mmzCCGmg_0 bus +sVbrxAG6jtA_0 car +sVkPUjUh0UQ_0 knife +sV9ymK-zZ8A_4 bus +sV9ymK-zZ8A_6 bus +sWfQh6SsvG0_1 boat +sW7n8r3vvl8_1 knife +sXwrjhXbAwA_0 umbrella +sYE45Xnof5I_3 bear +sY1i3-cQv70_2 boat +sY3G5eOlysI_0 bus +sY_jGNxKdYw_0 knife +sY_jGNxKdYw_2 knife +saBAx3Xw2PE_0 bus +sbR26E99_A8_0 bus +sbmsWqsHD9M_0 bus +sb1unJ1sby8_0 knife +sb1unJ1sby8_4 knife +scFiRRTU5jg_1 bear +scJFbu3WboQ_1 car +sc-BJ-WirDo_0 bus +sdHNJK0mfWQ_3 bus +sdd5ViCUDwY_1 bus +sfVwMcMm77E_1 umbrella +sfVwMcMm77E_2 umbrella +UjxwNRWfxBo_2 bear +UkBlnrNOssQ_1 bus +UlLwBfXpz4A_1 bus +UmAOVqCB6UM_0 bear +UmBxMf5cHV4_0 knife +UmewKWpE2qE_0 car +UrRiUQPaxic_0 umbrella +UrxeEW4FBq4_1 umbrella +Utvo55GUNyg_1 bear +UutgI7H2EPc_0 bus +UutgI7H2EPc_2 bus +UutgI7H2EPc_4 bus +UutgI7H2EPc_5 bus +UutgI7H2EPc_6 bus +UvsMOU9XGYk_0 car +Uvsup5BdpLM_0 car +Uwlk3sF-l38_0 knife +UxD-6ScNF1U_0 bus +Ux3oyD0wLig_0 boat +Ux_-m16Ntqs_0 bear +sgDzqYTo0GI_0 car +sgDzqYTo0GI_2 car +sghMPNg9wB0_0 bus +shgKQ2FcjfM_1 knife +siNixoeB9Ew_0 car +si8Uk6frpqI_3 knife +sjBWnj8kKVs_1 bear +sjESht-PXb0_2 bus +sje-nlCBYAk_0 bear +sk5gj6VnXds_0 boat +slGCyLNlI3w_0 umbrella +slgsRri0IUU_0 bus +sli0aHrS-l4_0 knife +soPkYPTLD-Q_1 boat +soe3qmwZTEE_3 knife +soe3qmwZTEE_4 knife +splTIYA-rtY_3 knife +srUGXKwzLf0_0 bear +U0G9nt_JMp4_3 knife +U1jXflUgiSo_2 knife +U1p1HQ3ZsUo_2 car +U1tGGfRyOzY_1 car +U3BQYG5-Koc_0 bus +U3pwXnANDgk_0 knife +U3pwXnANDgk_6 knife +U4nccTmpY0A_1 bus +U7N--AsibJc_1 knife +U7fW1r0kRYw_1 car +U7-_NQlr8l0_1 bus +U8EGQyjwfEQ_0 car +U85wCYoCIZ4_0 knife +U-B7Xkx_rF0_1 knife +suQJeplwaco_1 bus +svZPjH3EGcI_3 car +swj8kdhr03w_0 bus +swkyfcVE17I_1 umbrella +syJ4LBRPwjs_1 knife +syY8MaSUvJI_0 car +syfJEZrVzqA_0 bus +sy9XCn-ebrE_0 car +szClXDUETvQ_0 umbrella +szW2Gonojss_0 knife +szXVjlTlt3w_0 bear +sziUCgMKvrM_0 bus +sznHM_K2obc_1 bus +sz6Zoh7MfnA_0 bus +s0ABooHpZjo_0 knife +s09Dr7gZ5G8_0 boat +s1t73kIOSQU_2 bus +s2BVmX4vImY_0 knife +s2gkrcGsOxU_1 bear +s2nioy3J4RY_3 boat +s2nioy3J4RY_1 boat +s2nioy3J4RY_2 boat +s2qgkHBVQxo_0 bear +s2qgkHBVQxo_1 bear +s3lwoM0rD2U_2 boat +s3-sF0tSY8w_0 umbrella +s6BicsP9eBk_0 knife +VA3OWlsrD28_0 umbrella +VBPWsv5FfbU_0 bus +VBPWsv5FfbU_1 bus +VBr3P_OGawE_0 knife +VB6eUS7LSfM_1 boat +VCCevTa32Ng_0 car +VDz1RZU6x5c_0 bear +VESEWamKy10_0 car +VFv1UuT7klg_2 knife +VGAYYimByOM_0 car +VGwSM3IXcJ0_0 boat +VG_OHq6R1AE_0 bear +VHiMLGyNYgQ_0 car +VIASAf569_k_0 car +VIxj6BV3kgM_0 umbrella +VJZpavOgVEo_0 umbrella +VLaCK3u84vI_0 umbrella +VMLuyFD54AQ_2 boat +VMXrHUjXjyQ_0 boat +VMXrHUjXjyQ_1 boat +VMi5mAdZyZI_1 knife +VMs0jemUzI0_0 knife +VNuYRPiFrus_0 bear +VN-BCqBlrhs_0 car +s8vzssNUlOA_0 knife +tAOx6NFDD9I_0 knife +tAxbjy_edDI_0 umbrella +tBOSPNFbuv8_0 umbrella +tBQRfKeIYZc_2 bear +tBgtSnOMOwM_0 bear +tBh6HxQHmrs_0 knife +tCZLl-MZJp8_0 car +tDYPtg0At_Y_0 bear +tE42n_1PW6w_0 bus +tFfqpeBbvr0_0 umbrella +tFjlTZqwoWI_0 bear +tGycfa97LVU_1 bear +tIX4eIYzfD8_0 knife +tIX4eIYzfD8_1 knife +tIs05U9pd04_3 knife +tIs05U9pd04_1 knife +tIs05U9pd04_4 knife +tIs05U9pd04_5 knife +tJXbZyaUOD4_0 car +tJhfshKvRmE_1 bus +tJhfshKvRmE_4 bus +tJ01Y3R3Qmg_0 umbrella +VOcplsa6Gq4_2 knife +VOcplsa6Gq4_5 knife +VPI_Nm3GHHc_5 bear +VPI_Nm3GHHc_2 bear +VP0u_E6FOsY_1 car +VR_V9WaFYn0_0 umbrella +VSj9dXwt7zI_0 bus +VSxoLvaJN2Q_1 bus +VUcCABjVSO0_0 car +VU2lUX4NdkM_0 knife +VU2lUX4NdkM_1 knife +VVg7sbsw9vY_0 bus +VWpm6_Uhis0_2 boat +VX9TPrjMcOg_0 knife +VX9TPrjMcOg_4 knife +VZ5r0BHRf84_0 boat +VaW7Go5pX-c_0 umbrella +Va50KanUO94_0 umbrella +VbA0B1JcpNY_2 knife +VbeIRLOQ5pI_0 bear +tKCjJuulqx4_2 bear +tKCjJuulqx4_3 bear +tKCjJuulqx4_4 bear +tKN3Qo0oUoc_3 knife +tNvGTzks1yw_0 car +tNvGTzks1yw_1 car +tO0igm1AwqU_0 bus +tPae9uGqDog_2 bear +tPzWEC_9_H4_3 knife +tQpyrprwwc0_0 umbrella +tR2sDFGND7g_0 bear +tSEneDiCrqg_0 bear +tTFTWquOTi8_0 bus +tTjbx39rZMk_0 bus +tT2pUZ0W33A_0 bear +tUHf6Ynx_vI_0 knife +tVJE-0uNX1s_0 boat +tVTkAh80t5I_0 umbrella +tVuL82POt-I_1 car +tXMBGjGduCM_2 knife +tXsMGHCKw7U_1 boat +tXwfqREzEtI_0 boat +tYGp2PFiAUE_0 knife +tYas1z25M_4_2 knife +tYcNeSisfpI_0 bear +tYdhIaTDwiE_1 knife +VdLohVQNC5Q_0 knife +VdLohVQNC5Q_1 knife +VdLohVQNC5Q_5 knife +VdLohVQNC5Q_6 knife +VeUIJlyGjkY_0 car +Vekx17G8mkk_0 bear +VfBqMWT6aRM_0 knife +VfKgW5eSGsk_0 umbrella +Vhmj1OGGQuc_1 bear +Vhn-8bCU70s_0 bus +Vh21adwevRU_0 bear +ViXmx_D5BAY_0 knife +ViXmx_D5BAY_3 knife +VizxeIzWEFw_0 car +VjF-G6FQooU_0 boat +VjS5w2pc0tA_1 boat +VjvpOU349zY_0 bear +VkDn2-1H23o_0 umbrella +VkDn2-1H23o_3 umbrella +Vk43AD4O_hc_0 boat +Vnrw6Fjmj8I_0 bus +VnwwgTO4w_k_0 umbrella +Vn4aKSlYXX4_3 bus +VppPgMZqfEQ_0 boat +Vp0kah4_m6w_0 boat +Vp0kah4_m6w_2 boat +VqHSuVVKfjs_0 bus +Vqo2RiAzLnU_1 car +Vrnm_kf7OCs_0 boat +VsDgOcOWqXw_0 bear +tYofvh4_3K4_0 bear +tadYkEU5suY_1 knife +tbIUesoKv9Q_1 bus +tb_hKPkH2co_0 knife +tcFQ5kE3PKM_0 car +tcFQ5kE3PKM_1 car +tcSHrlGTFJc_0 knife +tc912gGdckQ_0 boat +tdjDSO8NFx4_0 knife +tdpAPPsHlDQ_1 bear +teJyM5tywno_1 bus +teQkZqDa1lw_0 knife +teb83RDwop4_0 bear +tgSfan8G7wo_0 car +tgVXG7H_acI_0 umbrella +ti3J-8aWPcw_0 bear +tjldcvPuif8_0 bear +tj4mnSXX2DM_0 car +tm2bmSBR4uE_0 knife +toiMoCxSyKY_2 boat +tos1ELGZH0M_2 umbrella +Vs3Mi3Ch_EQ_0 bear +VtHzTaDh4WM_0 bear +VtHzTaDh4WM_1 bear +Vt8DAmG3nHs_0 car +Vu4xkIEs6U8_0 boat +VvXxRawsOCs_1 knife +VvXxRawsOCs_4 knife +VwYEgB5HOD0_1 bus +VxdUG7Sinyw_0 car +VyDNhpvCuc8_0 bus +VyfIuIcelhc_0 umbrella +Vz3wJsLA_gI_0 bus +V0NnR8HLSbo_0 umbrella +V0o8kxcOZRc_2 bear +V1a9QcSegdw_2 umbrella +V1dqjmHNyIY_0 boat +V23vmoZYoVw_0 bear +V4o7I9cLp-g_0 bus +V6nKvvfzWpg_0 boat +V64pvhB8sKU_0 car +trAReSHvUdQ_0 car +trAReSHvUdQ_5 car +trAReSHvUdQ_6 car +trAReSHvUdQ_1 car +trAReSHvUdQ_2 car +trAReSHvUdQ_3 car +trAReSHvUdQ_4 car +tsNhgDUKwHw_3 knife +ttdTnGOIBmA_0 umbrella +ttdTnGOIBmA_3 umbrella +tvVLkJ0HTQQ_3 car +tvew-P2UPL4_0 umbrella +twiEfNprSoE_0 knife +twiEfNprSoE_1 knife +tw7jf9U2-kM_2 bus +txpIIsM1T8U_0 bear +tx2dZF1Ckxk_0 knife +tx5tKODiGuo_0 knife +tx5tKODiGuo_1 knife +tyO37NBAS1Y_0 bus +t1UtwxOBGvE_1 knife +t1vrE0cEB80_0 bus +t10FRgv9o5M_0 bear +t10FRgv9o5M_4 bear +t14PUW9SINk_0 knife +t31z17N5skw_0 knife +t31z17N5skw_1 knife +t31z17N5skw_3 knife +t31z17N5skw_4 knife +t33TQH8-7tg_2 boat +V9UCv2qhsxc_0 car +V9ulnUIQGJU_0 bus +V9ulnUIQGJU_6 bus +V-KNIu_PsaQ_0 bus +V-NvBHig1i0_0 bear +V-tMggTxBu4_0 knife +V_Bb7A55f-c_0 car +V_dJ2KuqfOA_0 boat +V_dJ2KuqfOA_1 boat +V_t8pbEf8bA_1 boat +WB7fT2tI7Pg_5 car +WCSEuwFm7KU_1 car +WCfc8YGLu1o_1 bear +WCfc8YGLu1o_3 bear +WDgLmrXq4vg_0 umbrella +WHLIJlNh3TQ_1 knife +WHQXE5tuTXk_0 car +WHUaoqVF57g_0 car +WIdj4ovuDWQ_0 bear +WIdj4ovuDWQ_1 bear +t4oaGCoTBZc_0 car +t42tnyTtYWE_0 boat +t7OKXKxjHls_6 bear +t8X-x_7pv94_0 car +t_-dK1Xhg90_0 knife +uAjqm8B-aio_0 knife +uB_Hurzj4s0_0 car +uGEDuDcqqvU_0 boat +WJ2A2XRRTw4_1 bus +WJ_vIH7FJsQ_0 car +WKDhXr_5mbI_0 knife +WKKFM7oRSd0_0 bear +WKS6aq75gk0_3 knife +WKV4j8-G1Nc_0 knife +WKfQfA_YQTY_3 knife +WKubVTrND7s_1 knife +WKzUT3zOIU8_0 knife +WLxzHH6iJlk_4 boat +WMSu-XOQe5w_4 bus +WMSu-XOQe5w_0 bus +WMgP1z0x0Io_0 bus +WOVTnN-HcZ0_1 bus +WOxTA78OlZU_0 knife +WPqEyeVtih8_0 bus +WPuItCUuEkY_1 knife +WQAr1enuPKw_1 bear +WQX6ptTAKHg_0 knife +WSc0kYKLGTg_0 bus +WStgEyiPBBE_0 car +WSvHn5XJq0Q_0 knife +WS0DayzAv80_1 boat +WS0DayzAv80_2 boat +WTXytzbF5lU_0 umbrella +WT69VoU2Hps_0 car +WVx9vOoutGo_0 bus +WWKuCF2FuYk_0 car +WWm9iMkKk-g_0 knife +WW7ib8XAVz0_0 boat +uHqj6xQGOYg_3 bus +uHqj6xQGOYg_4 bus +uHqj6xQGOYg_6 bus +uHqj6xQGOYg_7 bus +uIKZlXUoHOc_0 bear +uJMFDY-BKiQ_1 bear +uJMFDY-BKiQ_4 bear +uKdOuLYJjrg_0 knife +uK-zcpEE8nE_5 boat +uLdXkXRsHok_0 umbrella +uMK6b2TG8rc_0 bear +uMV37U-DNUQ_0 car +uMciOwjd0GU_0 car +uMciOwjd0GU_1 car +uMd1DmjxAZQ_1 car +uMj3V0s7mUo_0 bus +uM_jxm7bFp8_0 boat +uNDkbmlEYeQ_0 bear +uO7OtV3J1AY_0 bear +uPE1o5dCYDc_0 bus +uQhMkVrdghM_0 bear +uRLAyu-3l0A_0 knife +uStpLanz0fU_0 car +uTAqzBGMDOc_0 bus +WYwRW_t4jb8_0 car +WZK5IqBtpGE_3 knife +WZgxjIvc2nk_0 boat +WaEyVBSggwQ_1 bear +WaaW6bElWCM_0 car +Wb20JaIrr8M_0 knife +Wb20JaIrr8M_2 knife +WcNlbTBZM64_0 umbrella +WdIATjW74Pc_0 boat +WdYFXDv4TEo_1 car +WdgTHJurLx0_0 umbrella +Wd0xTEH2d9k_0 boat +WejCws8AoxE_1 knife +WejCws8AoxE_2 knife +WejCws8AoxE_3 knife +We4_tuFKyGE_0 knife +Wf6hHpxRW_Y_4 knife +Wgx6hhiRLoA_0 potted plant +WjiMUA6_CkY_0 boat +Wlm2mLKCMlM_1 bus +WlsN6HURFTc_0 bear +WmFqo8n67Ok_0 bus +uWi9-84kTFQ_1 bear +uXHJHV0bwUk_2 bear +uXe9WOlTFcs_0 bus +uXe9WOlTFcs_1 bus +uZgcOYmazsw_0 bus +uaJ1g0xJ4QY_0 bus +ual32V7-KJo_0 boat +ua_5GosOa-c_1 bear +ubFoUAh6d4g_1 knife +ubOiomYqbNs_2 knife +udSE-6UkgwM_5 umbrella +ue1CIlwhPEs_0 umbrella +ufFT2BWh3BQ_0 bear +ugWs4v6DbUw_0 bear +ugsJ5cOmFTg_1 boat +uhXcL98XNCY_5 umbrella +uhXcL98XNCY_1 umbrella +WoxbRmDfLeI_0 umbrella +WoxbRmDfLeI_1 umbrella +WpCyx-QCMec_0 bus +WplsTumdQf8_0 boat +WqFFUvf-YJk_0 knife +WqxU9aIFmNY_0 umbrella +Wr5BjrtC4Ts_1 knife +WsEiHZFGeFs_3 umbrella +WsaP8FyRUCc_0 car +Wses8y3NyJ4_1 bus +Ws9V_B7mqJI_0 knife +WuTHL7GtG-8_3 knife +WvGzCV5ICZM_1 boat +WvuZRZqhxk4_3 knife +WvuZRZqhxk4_5 knife +Wvv8cOXaAZI_0 bus +Wv-Weuc4E1A_0 umbrella +WwLtxfDC7ok_0 boat +WxWXB9hf7n0_0 car +W0kDpFkg6xU_0 boat +W1z3EAv-eJw_0 bus +ujnUCtI7gzI_0 bus +uj4TRH5r_ww_6 bus +uklsFjegS-w_0 bus +ulzto7-Hl64_3 bus +ul__w-oqHrw_0 bus +umjU9X1kuYg_2 car +umjU9X1kuYg_4 car +umjU9X1kuYg_1 car +uoGBYfJo5Xg_0 car +uo1J9BUgQmk_0 boat +urRNkZvzuHI_2 knife +urmSoxyi9Vo_0 boat +urmSoxyi9Vo_2 boat +utmsGeHFdvI_0 boat +uuBKDGoTmGY_1 car +uu-UptVYr_A_3 car +uvV7cblR4qc_5 umbrella +uvZOzZjBKXY_0 bus +uwL5LYln0EM_3 bus +uwL5LYln0EM_4 bus +uwL5LYln0EM_5 bus +uwL5LYln0EM_6 bus +uwx7UKo4jcg_1 boat +uwx7UKo4jcg_0 boat +uwzHiGF1YMM_0 boat +W2z3SxorVnI_0 knife +W2z3SxorVnI_1 knife +W38vB3cw2fA_2 boat +W4Is7CI2Sfo_1 umbrella +W47ZA0onzb4_0 knife +W5dSTfMCj-U_0 boat +W5zIkmZyS18_0 bus +W51Spbo8SQQ_0 knife +W6YCv9ZVVOc_3 boat +W6uCEMEi7_E_0 bus +W7JkNuRYNr0_2 knife +W7JkNuRYNr0_3 knife +W7JkNuRYNr0_4 knife +W7JkNuRYNr0_5 knife +W7yqHDA_RMU_0 knife +W8EKt6cG0E8_3 bus +W8EKt6cG0E8_7 bus +W8EKt6cG0E8_1 bus +W8xqW-QD_B4_0 knife +W87M2lQeWNk_0 bear +W87M2lQeWNk_1 bear +W-ZpC_K7Df8_0 car +W-x__78AyrI_0 boat +W_Wc7lFraRg_0 bus +W_v5wpcibRM_0 boat +W_2LqiQ_ico_1 knife +XAa2L1v8iJM_1 umbrella +XBAOFn8KXFo_0 bear +XBn6P-IKuis_0 person +XBssw3bqXL0_2 bear +XCZv_AjZo08_0 knife +XCu0Ea4zHuQ_2 bear +XDtfr902CVM_0 bus +XD1OYmmeKic_0 umbrella +XD1OYmmeKic_2 umbrella +uxFX6p61oPY_0 knife +uxlDad59mFc_0 boat +uyWVUOcgZHg_0 bear +u1OhTXTmuWM_5 bear +u1TvbkpmEbs_0 car +u1vMDzyFxzI_0 bus +u2BVfAFQ1zU_3 knife +u2BVfAFQ1zU_2 knife +u2EDuPJijZ8_4 boat +u4K3jRl7Gag_0 car +u4S9mlFpt0s_0 bear +u4uwaq4uf54_3 car +u4uwaq4uf54_0 car +u6XGBXhCJ18_1 knife +u7STs8FCy_g_0 bus +u-1HZJXwFHo_0 umbrella +XF8B5xjRCF0_0 car +XF8B5xjRCF0_2 car +XF_oHXRGd1o_0 boat +XGRZLrZC9zY_0 boat +XIlybSpq0mg_0 bus +XJmn9i57K3g_0 bus +XLvSaN_M6lE_0 car +XL0B2niNRCw_2 bus +XMlEA_yRojM_0 knife +XMyio1ZckJc_0 bus +XQBtgwUzEL0_0 car +XQX5y5BQykU_0 bus +XQ6u2yTbu_0_0 car +XQ7UbbPjnDo_1 knife +XRenv5AHI_8_0 boat +XRpgkCuziGY_0 umbrella +XSI7M8s2Tc0_0 bus +XS4ow1Wcaro_0 car +XTm-jN1RVHA_0 umbrella +u_YKLGqrMKQ_1 knife +u_gN-dXNRHI_0 knife +vARZcTna8NU_0 boat +vBEaeqdPsho_4 car +vBEaeqdPsho_3 car +vDT-DShjnjU_0 umbrella +vEMHY2cT6kA_0 bear +vEi5gkcTDGY_0 bus +vE9zapt1WdI_3 car +vFSRrtT5AL8_0 bus +vGbt_XsSaVk_0 knife +vGi-DjriLLs_0 umbrella +vHAlsHYE3mo_3 car +vHAlsHYE3mo_0 car +vHXM9IJdVcM_0 umbrella +vIQAK-4lMOc_0 umbrella +vIgmRBC2ayQ_0 umbrella +vJl9QkAbpc8_0 car +vKxCl7DzJjI_0 knife +vK8dgvZ5B6A_0 umbrella +vLA-mHM7MAQ_0 knife +vL-6uNdrCV4_2 knife +vN54ADSnJmE_0 bus +vOKH_DIjvAU_3 knife +XUkTknKOdrs_4 knife +XVa23hmwe-E_0 umbrella +XVrNN52RTEs_2 car +XVrNN52RTEs_3 car +XV694aCXY8Q_0 boat +XW6BQWpl3bI_1 boat +XZl5Luzj6v0_6 bear +XaSsc3noeLs_0 boat +XbHWOyNM3Bw_0 bear +XbHeGzyGejE_0 bear +XbWrCVe09YA_0 boat +XcLl0qSs9bU_1 knife +XcifNE0anDo_0 knife +XcifNE0anDo_1 knife +Xc1jzGFyrnE_0 car +Xc5LW1FIVE0_2 knife +Xc5LW1FIVE0_3 knife +Xdu-98BUgmA_0 knife +Xd7VbtoAdb0_0 car +XeOwt5KeVfA_2 car +XeR1DgyOa9o_0 knife +XekvrqFtazY_0 bus +XeplLROyXyA_5 umbrella +XgBTEQN_ZxA_2 bus +XgBTEQN_ZxA_4 bus +XgBTEQN_ZxA_7 bus +XhSmPb3cA_A_1 knife +XhSmPb3cA_A_3 knife +XiEeY5R56EQ_0 knife +vOy0N09kGEE_0 umbrella +vO56uCHmSjg_0 umbrella +vPVpX6GPY5Q_0 bus +vPVpX6GPY5Q_1 bus +vQ_8ry_dx68_3 boat +vRhGvmXk2js_1 boat +vRzpk-thwA0_0 bus +vTvjeXsP7TM_1 car +vTwSeYRU_WQ_0 car +vTwSeYRU_WQ_2 car +vUKk9LqKVpA_0 boat +vUKk9LqKVpA_1 boat +vUg2Sr7Jl-Y_0 umbrella +vVKZzTBvsF4_1 bear +vVNCUA8hss0_0 boat +vVUbZCrCqEU_1 boat +vV72xGim-is_5 knife +vWMiT73g5-k_0 boat +vWO0tyaGuaM_0 umbrella +vWUAzQ_EEJ4_0 knife +vW_aJr-PSvA_0 bus +vW_o48lG_0I_0 bus +vXX9FmlwVlk_1 bus +vXX9FmlwVlk_6 bus +vXX9FmlwVlk_0 bus +vXX9FmlwVlk_2 bus +vXX9FmlwVlk_4 bus +vXaLFnwvrX4_0 bear +vXvR0RiGzj4_1 car +vYROjLzMqvY_1 bus +vYROjLzMqvY_2 bus +vYROjLzMqvY_3 bus +vYwdLoOa0Rc_0 umbrella +vYwdLoOa0Rc_1 umbrella +vY1sAfu99Es_2 bear +vZznldYVwGA_0 boat +vbfWHUjHR2k_0 bus +vcdEtOGEEcU_1 bear +vcdEtOGEEcU_0 bear +vcdEtOGEEcU_2 bear +vch6R3EO9Ec_0 knife +XjHJiHO6onE_5 bear +XmVv2wQSvjs_1 car +XoJahpK73EM_0 boat +XoqPCnlpymI_2 knife +XpDVw5mS058_0 boat +Xp591jCTBOA_0 bear +XqfkP1lAkyE_4 bus +XqfkP1lAkyE_5 bus +XqfkP1lAkyE_2 bus +Xq-5DHWJ1pk_1 bear +Xrh68BP53Gw_0 car +XriRhjtrlLE_0 car +Xu-ZZl_L38Q_2 boat +Xv9eEVcD2P0_0 bus +XwvKtur_QEk_0 knife +XxHnDkI1NdQ_0 bus +XxHnDkI1NdQ_1 bus +vfzGrdk_Mxo_0 bear +vhrRnvGSMMY_2 boat +vhrRnvGSMMY_5 boat +vhrRnvGSMMY_6 boat +vhrRnvGSMMY_8 boat +vh4BHzMwVT8_2 boat +vh4BHzMwVT8_3 boat +vi4ktD0dAD4_0 car +vkfdn7gkQh8_1 umbrella +vknUR0K4MqM_0 bus +vlNLyHxz1TY_0 boat +vlaeAly1nZc_0 boat +vmr5UiZekic_1 bear +vo0WWdM7UCs_0 bus +vo6Uzhx2fcw_0 boat +vpItyB8epmQ_4 boat +vp8NiaEmk2M_0 bus +vqeybXtIwxE_3 umbrella +vrK5lDQJnmc_0 car +Xy1w-6sjVS0_0 bus +Xzj_w2QkjRg_0 umbrella +X0iu2HmUYfY_0 umbrella +X0nevXM5278_0 car +X1drOgA68EU_0 bear +X2zWe7ayseQ_1 bear +X3ST-FA3VS0_4 bear +X4YaqObAEns_1 bus +X4kxk4G-BOs_0 bear +X4kxk4G-BOs_1 bear +X6Y6e6qsVOc_1 bear +X6tuO-hL1cg_0 boat +X6z7yGyP3UY_0 boat +X7AJSe6kUz4_0 boat +X7PChwjgRog_0 boat +X7mkuAPcpg0_0 bus +X8Wc00FiJn8_1 bear +X8lHVX9uGm4_0 car +X9dNz1MhFTM_0 car +vtOaPYxGauU_0 boat +vwp5f1sTcOM_2 boat +vxEizaWVZ2E_0 car +vx7S4ISNz90_0 bear +vzKEVGD3E3w_0 boat +vzKEVGD3E3w_1 boat +vzmWbtFBxb0_0 bus +v0DjGmLiuao_0 car +v0P7DOSAooM_0 boat +v0Uh3fazz7A_4 bear +v4CWziKFAvg_0 boat +v4CWziKFAvg_1 boat +v4TWD1hSObU_0 umbrella +v4TWZQM-t_M_0 boat +v4wheqJ7qmw_0 car +v4-PEShPpKo_1 car +v4-PEShPpKo_0 car +X_1xeuzdJII_3 bus +YAI5kxAVlag_0 bus +YAS9QgwaKuA_3 bear +YAacEL8GB8Y_0 bus +YCTBEauAnvs_0 boat +YCT0ue2AdNE_0 umbrella +YC0SWC1thDM_2 car +YDxjfXnUsjA_0 bus +YFb4IgdgsQI_1 boat +YGm0A03QK-0_0 bus +YJklsCjPlRE_0 car +YJrYjEZ4Hfo_1 bear +YLNAOu0nAaM_1 bus +YMWEbvBeA2k_0 car +YNOl5XssrmA_0 car +v6RTPFSqVAo_0 bear +v6d52nxP9CI_0 boat +v6d52nxP9CI_6 boat +v6d52nxP9CI_2 boat +v7R5EfiWsMU_0 boat +v7mxF1u1eJA_0 boat +v74SVFcInoY_0 bus +v77um2oiCmw_1 bear +v8vdjpigkqA_3 bear +v9EO_34zhPY_0 bus +v9dJjyyqJ14_0 bear +v-_nfHjdDrM_0 car +wAJI2wAjCLA_0 car +wAktmcUSj0Q_0 bear +wAsEbrNlx-Q_0 car +wBEyQdKDniA_0 bus +wDOuWmULTDo_0 bus +wDwRfk2Ka7A_2 umbrella +wFuYr5TAoA4_0 car +wFuYr5TAoA4_2 car +wGqMuP3z6nY_2 bear +wHdnCnPBax4_0 umbrella +wHrdTEho0Do_2 bus +wItLJ3GVPHo_0 umbrella +wIzhSLqL-4M_0 boat +YPR6uiSn_PI_0 bus +YPR6uiSn_PI_2 bus +YPWoY6sseHw_2 bus +YP9HVTyFrM0_0 umbrella +YQRaUcLNZjw_1 car +YRmCe16K5EI_0 umbrella +YRxTciapqLc_0 bear +YSFyOBQNQzc_1 umbrella +YSOeyn1SUIc_0 bear +YSx79S6HsRE_0 boat +YSx79S6HsRE_1 boat +YVueKFH38pQ_0 umbrella +YWAY2hVlXwU_1 boat +YXC4y1_fd5M_1 boat +YYjM_RIWUWk_0 bus +YY-G2b46dbU_0 bus +YalvFPYggIo_0 bus +YbsAJsBizWo_0 car +wJbu3nAVmh8_0 car +wJ-qeIIyve0_1 bear +wKlqztWBWCE_0 bus +wLXsUww1z0Y_1 bus +wLXsUww1z0Y_2 bus +wMW3eYDAmiM_0 car +wN6DTQLhQo0_0 boat +wOAtMDJ1DIU_1 bus +wOqLqQhPKNs_2 bus +wPCVya7FjXI_0 bear +wPcWihBU6Fc_0 boat +wPjzhuBuZ_E_0 car +wPrTnHfCQy0_0 bear +wP83jrOriho_5 boat +wP83jrOriho_1 boat +wP83jrOriho_3 boat +wQY4K0ZN5RY_0 bus +wQY4K0ZN5RY_1 bus +wQY4K0ZN5RY_3 bus +wRJ_foSdk2g_0 umbrella +wRs7_Un28R0_0 bus +wSaf-OQyJzM_0 boat +wSkaSUiYB60_0 boat +wUG-UKf5xOM_2 bear +wUtwwmbus0k_0 bear +wVI9BeWuM68_0 bear +wVX6wPj2U5M_0 bus +YcrP36sQwVc_5 bear +YepGVMeHePw_1 boat +Ye3mi53K_Oo_2 boat +YgouPUMM7w8_0 bus +YhZT5GU-dEY_0 bear +YiDVwrN1Djs_3 bus +Yi8XHxZACGY_0 bus +YlGg5v-AWZc_2 umbrella +YlnMI5yk7FU_0 boat +YmRfW-9QwH0_0 car +YodCYpx5p8o_2 bear +YogxE9OtHGE_0 car +YogxE9OtHGE_2 car +YozOMrrhBWk_0 umbrella +YozOMrrhBWk_5 umbrella +Yo8IaFdsDHQ_0 umbrella +Yo8IaFdsDHQ_1 umbrella +YpGGnhGqqkc_0 car +Ypv2bwSbJbg_0 bus +YpyrD-P9emk_1 bus +Yq3H6FwjqwQ_2 bear +wXg6MT7--Ms_1 bus +wYO_Z3tO-P0_0 car +wYO_Z3tO-P0_1 car +wYO_Z3tO-P0_2 car +waGAoKeMDbo_2 bus +waZHoBhYNXM_2 car +wan2A1Zp9pg_0 umbrella +wa4LKNmoGCI_0 bus +wbBafnofeHM_1 bus +wcLRQ5lDklc_2 bus +wcRJMRP7TtY_0 car +wcUHhJA9ynY_0 umbrella +wcUHhJA9ynY_1 umbrella +wc6z479m8VU_0 knife +wePYCAT9VWI_0 boat +weUGYN9mO8M_0 car +we9P1H3yM9s_0 umbrella +wgn5GA4Kt_w_0 bus +wioe2rgDFxQ_0 bus +wi_60seXhMg_0 umbrella +wkCC1-6dZZc_0 bear +wkRF61CxvWQ_1 boat +YsJGlSMV6fc_0 bear +YsKpyV6dNVU_0 umbrella +YsKpyV6dNVU_6 umbrella +Yukb6C-FiPs_0 bus +YyqN8OKq7-k_0 car +Yy9Cj5ayVow_4 car +Y2esC00COVs_0 umbrella +wkhiKomfWwo_0 boat +wku7FWw9zok_6 bear +wmN3gF7czBE_0 boat +woB4lneU8v4_2 boat +woB4lneU8v4_5 boat +woB4lneU8v4_3 boat +wonqKYd_Hkc_0 boat +wulomSbG8Ww_0 boat +wwHyMOLjtHw_0 car +Y8gjbHlOSpg_1 car +wz-CYTAvpJA_0 car +wz-CYTAvpJA_1 car +w1xC4CowaVk_2 bear +w2d7ZPHVRsQ_0 car +w4QoeqK4vN4_0 boat +w5KKrxi32ZU_0 boat +w5RAGrRh6N0_0 boat +w85PvG-O3JQ_3 bear +w-RoxIo67S8_0 bear +w_dzHMbP1wk_0 car +xAdflusGMAM_2 bear +xAdflusGMAM_1 bear +xBQVhJr5tn4_0 car +xBQVhJr5tn4_1 car +xBW2dB1aHqE_1 bear +xE-fIbBizEc_0 boat +xIjuSe8NERE_0 boat +xIr-46lqsbs_4 boat +xI3wdcR9GOU_0 bear +xJaqlEqJIsg_0 car +xKUjAAXXark_1 car +xKjnn1lJsUE_0 boat +xLl8JlHPals_0 bear +xL0aucx8LjA_0 car +xM1N_JeMAns_0 car +xNfYVO0HOWA_0 bear +xNfYVO0HOWA_1 bear +xNqzZtEMt6A_1 car +xOQ_zqhFFoQ_0 car +xOQ_zqhFFoQ_1 car +xOQ_zqhFFoQ_2 car +xPgexGqlrpM_0 boat +xQ2ursLiV78_0 boat +xVl7ISxNOBo_1 boat +xWfIV6ykSZU_0 umbrella +xYRbcgZcjTo_0 boat +xZdiy-peZpE_0 bear +xcC48didfYg_0 car +xds7aav_WA0_0 umbrella +xeEFpaZutxQ_2 car +xeEFpaZutxQ_0 car +xemv_TG3nHo_2 boat +xf7e7HpnDAI_2 umbrella +xhLH-f-e2Ds_0 bear +xhLH-f-e2Ds_5 bear +xhLH-f-e2Ds_1 bear +xhLH-f-e2Ds_3 bear +xhLH-f-e2Ds_4 bear +xhYRRVSUjcI_0 bear +xh6_xD0_FUY_0 umbrella +xi1l0PNYmVU_0 car +xi1l0PNYmVU_1 car +xk-PCxxgLyQ_0 car +xlSq_r-1VZI_0 car +xlTBS98u4Xk_1 boat +xl03KNG3qcY_2 bear +xl03KNG3qcY_3 bear +xmXEOSj-QR8_0 umbrella +xm61skXJVHY_0 bear +xm7yMjZR_HM_0 car +xniXqwdU3rM_1 car +xn_6GQGdyww_0 bear +xoL1TWqV2UY_8 car +xoL1TWqV2UY_3 car +xoL1TWqV2UY_4 car +xoL1TWqV2UY_6 car +xo93ACxVFCE_0 car +xu3hCCY1M98_0 car +xvJ-vgSlRFQ_1 bear +xyUFBTV5sfA_1 boat +xyUFBTV5sfA_5 boat +xzFwd6rktG8_1 bear +x1PZyiPtcD0_2 bear +x1PZyiPtcD0_0 bear +x2MUZI0ckUs_0 boat +x51qh-jbh2w_0 car +x8bgasvRg_0_0 car +x_PtUMz2m3g_0 umbrella +x_yZa__92dU_0 bear +yE9ySV90e2U_2 bear +yFdbcjv2scY_0 bear +yFwt2mHmJQw_2 umbrella +yFyTQPoWKrg_0 car +yGYLwBmuRVI_0 bear +yGYLwBmuRVI_1 bear +yGq_wX2hSms_0 car +yHFbPuIOGec_0 boat +yMVPEp44IcU_1 car +yNYzTl3zuSA_0 car +yOeQRz1L-6w_0 boat +yPx8JYuB8jo_5 bear +yTEPer0Bvnk_0 boat +yTr7cqNxVw8_0 boat +yVwePYmRfaA_2 boat +yVwePYmRfaA_0 boat +yV3gYczZGSU_0 boat +yWKpg3C3HRA_0 umbrella +yWQT0KUXmZs_0 car +yXA2s-Ylkx4_0 umbrella +yYt1-j5ltQg_0 bear +yZOWsBbP8Dw_1 boat +yafgzvvEBsk_0 car +ygqn0Cw0cJg_0 boat +ykAF4z2vPRI_1 car +ynSIMn0mh5Q_0 car +ynuXudWT-jg_1 boat +yqDO3G8QSxs_2 boat +ysudb_DYv1E_0 bear +ytzy45KRs4k_0 umbrella +yy-1Eaz2SGI_4 boat +yy-1Eaz2SGI_5 boat +yy-1Eaz2SGI_6 boat +y26dbfVQaAI_0 car +y3HDa7ZvWW4_0 umbrella +y5rlUzgK0z4_0 umbrella +y6l_Xj3A7dU_0 bear +y6nMm6sNieE_0 bear +y6oa4gTfIaw_0 boat +y7_Teuq-Jd4_0 umbrella +y-J-zu3KYKk_0 boat +y-lv7_3azcQ_3 bear +y-lv7_3azcQ_1 bear +y-lv7_3azcQ_2 bear +y_Kbef75lDk_0 umbrella +y_OvZEh5PxQ_1 umbrella +zA7rl-0pCw4_1 bear +zBCRUfv1YVo_0 car +zBomR9gjgg4_1 car +zCnqglOaM40_0 boat +zC1J8hrm_FI_0 boat +zGOI3Uds1-A_0 car +zGvuvfZeouY_0 car +zHwK-Ov5Dn8_1 bear +zIGdWP0BOPc_0 car +zIoLntgax_4_0 car +zIrTQvy-DtU_0 umbrella +zKN-t-wHfVw_0 car +zOxKFs0x_-M_0 car +zPUoexM4GJg_1 bear +zS4G-dKS3dg_0 car +zUYNrm52mG8_0 car +zU9O4EpnP8g_0 boat +zW4j5HFdFCE_1 bear +zW9G9_luulU_6 boat +zW9G9_luulU_8 boat +zX70EOhK1IA_4 boat +zX70EOhK1IA_0 boat +zX70EOhK1IA_2 boat +zX70EOhK1IA_3 boat +zYNSRTs7wcI_0 boat +zZMZCzV930Y_0 boat +zaXvp0LSorI_0 umbrella +zcIJlqUAlyQ_0 boat +zcdpKM2gDkA_3 bear +zdWOfDZyRWg_0 car +zdp6LbsF3Fo_0 car +zdp6LbsF3Fo_1 car +zglydzoqdNw_1 car +zhSMuVKY4jM_1 boat +zhgbbZA2jZo_0 car +zj0QGbLx2Ek_0 umbrella +zkC1ygaZUL4_0 car +zkFlovQ2F80_2 umbrella +zkFlovQ2F80_4 umbrella +zkFlovQ2F80_0 umbrella +zkYqOEAbTTE_0 car +zk5BFmxsRfQ_1 car +zmXJ3VmO_yQ_0 bear +zmXJ3VmO_yQ_1 bear +zn_LOCSgnBI_0 car +zobMJDgPWmM_0 boat +zpW9Kjtbu7g_1 boat +zp4-YNYr-l8_0 car +zqDdt_wpfcM_0 bear +zqyhnAN5qnA_0 car +zq-AjPBQb3w_0 umbrella +zsszkZnE24M_0 car +zsszkZnE24M_1 car +zwKNqBmI95k_0 umbrella +zxfyvjQQ0QY_0 car +zxuleRJc5Pw_1 boat +zySbpWHTUUI_2 umbrella +zzDlzbpuFUg_1 car +zzOYV3PIwDo_1 car +zzljeIZDjM8_0 car +z1CT7NYPStE_0 boat +z1CT7NYPStE_2 boat +z1DFtYFOfsQ_0 boat +z1GcDqMXI5U_0 bear +z1WPNBklZbo_0 bear +z3V1O449zY8_0 car +z3V1O449zY8_1 car +z3V1O449zY8_2 car +z32BNdijIPo_0 car +z4C0C5AtXd8_1 bear +z4Nk6je-k5E_5 bear +z4Nk6je-k5E_6 bear +z4Nk6je-k5E_2 bear +z4Nk6je-k5E_4 bear +z4YdhKjeNQk_0 car +z5PqRVPhGGo_0 bear +z56C-TtwATI_0 car +z6Bzk_B2FVo_1 umbrella +z6gL7THeOz4_0 car +z8GzZUKj04k_0 car +z8QYapjsTBo_0 bear +z8WzXJMRLkg_1 bear +z9CJpzFuqHU_0 boat +z-gqhqI7U10_0 umbrella +z-n_qZEuRko_0 umbrella +z_CWMOiNpzY_1 boat +0Ah0DHbJ6Uw_0 bear +0B-l9QmJK3I_0 car +0DHXMcNUn60_1 umbrella +0EEILwHA4Dg_0 umbrella +0FRiwnN3Wv8_0 bear +0FUPhsPv9vs_0 boat +0FUPhsPv9vs_1 boat +0GR555fb7uE_1 boat +0GR555fb7uE_3 boat +0Gal36CHm94_0 car +0Hf-spRN8iA_0 bear +0H81H-1s398_0 car +0JkwSF_s82I_0 umbrella +0JxUW6X6VTA_1 car +0JxUW6X6VTA_2 car +0LY3jcKxA2E_0 boat +0NN0x0UcFVI_0 car +0NgLxOGQPPM_1 car +0Nh6NERAbQM_0 umbrella +0NyneL4SB78_0 umbrella +0O2cDoxCAhA_0 car +0PqvPOqRHik_0 bear +0ROl0QaHTgU_0 boat +0ThOYMXH3Mw_0 umbrella +0TyHCEslM-4_0 boat +0UGD0u7LEPY_0 car +0UVJn4oJR3I_0 car +0Vu78K6ZsOk_2 bear +0XETGtPrUR0_1 boat +0XrWsyRsBYs_1 bear +0YWXAZlIFZE_0 car +0YWXAZlIFZE_1 car +0YaZ8lrPQJc_0 boat +0YaZ8lrPQJc_2 boat +0YaZ8lrPQJc_5 boat +0ZJeQYZxfGQ_7 bear +0ZJeQYZxfGQ_6 bear +0agrBEPe_w4_2 bear +0bx9mbPU7zo_0 umbrella +0c5dV9e0rL0_1 car +0hafN9Sygek_1 bear +0jL3xw-Gfq8_2 boat +0kyg-HgBo7o_0 boat +0lXT8w6Nvz4_1 car +0loh5Nhb32w_0 bear +0lyjvzKFjn0_1 bear +0lyjvzKFjn0_2 bear +0mIwwe5irHk_0 car +0mSZED2I97w_0 car +0mSZED2I97w_2 car +0mSZED2I97w_1 car +0oHtf7nx8m0_0 car +0oHtf7nx8m0_1 car +0peaciSDgqg_0 boat +0rIli5nmkus_0 car +0sAim6AJwgY_0 car +0sAukk-qZs8_1 car +0sWjMW4aW_Y_0 bear +0sbXLfSaBvk_0 umbrella +0tapt-cyoSY_12 bear +0vC1j_r-gPc_1 boat +0vun54M7U5c_0 umbrella +0wXgXCqnblk_0 umbrella +0wzUHyuc5JE_0 boat +0zKI3bZagm4_2 boat +01aEu9jy-zA_0 car +02AiKGZAu3k_2 bear +02bMGGTZE_M_0 boat +04FPpXq4qHc_0 umbrella +04FPpXq4qHc_5 umbrella +04jEe0lfdos_0 car +04p58ydbAvM_0 car +05VoMpLo7Cc_2 boat +05rSMaVX3yA_1 boat +06kAyBeWx5c_1 umbrella +08Fj_YF5X8Q_2 bear +0-Jhv9dONP4_0 bear +0-zDto8pBU4_0 bear +0_ByJ0bAD70_1 bear +0_P-fui2MeI_0 boat +0_soacANAc8_0 umbrella +0_2dsK8nudw_0 boat +0_2dsK8nudw_1 boat +0_2dsK8nudw_2 boat +1EIBn1zqhJA_0 boat +1Fv0cFr9B_Y_0 bear +1Gd-hUsNAsQ_0 bear +1Gd-hUsNAsQ_5 bear +1HhUsmUQmRY_0 boat +1KnTTBiP4ig_0 umbrella +1LKTvGMlL60_0 bear +1MVBovgEi4s_0 bear +1OvseXyo27E_0 umbrella +1PYMTwN-dl4_0 boat +1REcM5EtrZg_0 boat +1REcM5EtrZg_1 boat +1SQF7Tb6pUA_2 bear +1T4c050qGWo_0 boat +1UGqDCwd0TU_2 bear +1VziogDsYAs_1 bear +1WOfnEUurGM_0 boat +1YelAl0OQQg_0 bear +1anH_WthXTc_0 umbrella +1anH_WthXTc_1 umbrella +1avrrmB_Q5s_3 bear +1cbY1pGpdhM_0 umbrella +1cy1p57Z49c_0 boat +1dmbrwAgFuc_0 bear +1fPDeE9SwYI_6 bear +1gbd0C2wJrI_2 bear +1huEYUsV2ng_0 boat +1iD7yA3Elk4_0 umbrella +1iLq0PGfeCs_1 boat +1irtTU-RM8g_0 boat +1lCEFERcEKg_1 boat +1lSGhF2K_lM_3 bear +1l-NcYZKF8w_0 umbrella +1miy1sfneCI_0 bear +1qIgbCRt2C4_0 bear +1qknV5a5WQA_5 bear +1rt4XRA4RHE_0 bear +1rt4XRA4RHE_3 bear +1v8UDwaLZOk_1 boat +1yym4MiYTrs_0 boat +1yym4MiYTrs_1 boat +1zGry9uSuEs_0 boat +10oedSsXbw0_0 bear +14R96gxvKtU_1 boat +15ImffljXUs_1 umbrella +16BnXZheZE8_0 boat +18XvETJJDqA_0 bear +19ID_DbSclo_1 bear +19vhT11oPv4_0 umbrella +1__PWUxtAJI_0 boat +2Da3689mFHo_0 boat +2DimBSzdfPw_0 boat +2Fo-71zWO5Q_0 bear +2F9aM3isFOg_0 boat +2HDMk0mGW_w_0 umbrella +2IWPUKQEQc0_0 boat +2Irm_qCNQ_g_10 bear +2Irm_qCNQ_g_2 bear +2Irm_qCNQ_g_4 bear +2IyAOD0OkOg_0 bear +2I_k7e8QpWI_1 umbrella +2LWxx48-zmY_0 boat +2OYJuEnLK_w_0 umbrella +2O-9dVZBFm4_0 umbrella +2PL1rgU3jQ4_3 bear +2Pxvoh1PnpM_0 umbrella +2QOthN0H0jo_0 boat +2UBlre798kQ_0 boat +2U7mw3Z_nrI_1 bear +2ZeSJRQEIDg_0 umbrella +2huYkh1UAa8_0 boat +2j5p2kIFnF8_0 boat +2kAmyrOg2is_0 umbrella +2l4-4yNg4uM_0 bear +2l4-4yNg4uM_1 bear +2nWt5S5AcdM_0 bear +2oAbMVTBupI_2 boat +2olUVemt4wc_0 umbrella +2rbAoA6KuZ4_0 boat +2rzjzIvxob0_0 umbrella +2sDjXjM3vuk_4 bear +2sgrwTqPz-Q_1 umbrella +2vC56ILIWK0_1 bear +2w5-fxqKaR0_0 boat +2xzgP87zGDM_0 boat +20nMgEiCqVs_0 bear +223bkVsFvUg_0 umbrella +23-uEh5ygBE_0 boat +24kbYgf2_xM_0 boat +27Yd0qtplBs_0 boat +2_VfwSLic7o_0 boat +3EBKN0vh_8Y_0 umbrella +3EQ8WatEGfM_1 bear +3FBfwZ1vctY_0 boat +3GXWmiQHAA4_0 boat +3Hc48OCKEaQ_0 bear +3ICqGhWY-HU_0 bear +3IOrKwocmOM_0 bear +3KUAz0bb87g_0 umbrella +3KqDceVP3xg_4 boat +3MqGpNqj-fo_2 bear +3M5VwMaIzvc_0 bear +3PN8pPy1PLc_1 bear +3PN8pPy1PLc_4 bear +3PuByhkRjdA_0 bear +3P8-bKeMTDU_0 bear +3P8-bKeMTDU_1 bear +3QQYEFonITE_0 umbrella +3SJI7j-hBwU_0 umbrella +3SbQY-gSjTI_1 bear +3SofVK5wM1k_0 bear +3T5iqGlQLn8_0 bear +3T5iqGlQLn8_4 bear +3UJ24QWw0js_0 bear +3UUo8exclHk_0 umbrella +3VZuzA8i9tI_0 boat +3ZWFSRxFKp8_4 umbrella +3ZwOfZ6mdTE_0 umbrella +3cBiXmqHBLE_0 umbrella +3eH1SNLDT7U_1 boat +3fiWerkBy1s_0 boat +3fm54fM2fh0_1 boat +3kOuqiigfhM_0 umbrella +3khbnSUKCjw_0 umbrella +3khbnSUKCjw_3 umbrella +3khbnSUKCjw_5 umbrella +3khbnSUKCjw_1 umbrella +3leEAIEn6wg_1 bear +3oFuTv4g5QE_0 umbrella +3oFuTv4g5QE_2 umbrella +3ohEBnBnt7o_2 umbrella +3pli8lLuPF0_1 bear +3qGBc-85DMI_1 bear +3q0pJjI8W5o_0 bear +3v6DRHFQTz0_1 umbrella +3yct6bNJF9c_1 boat +3zhjI0Cn1AM_1 bear +3z0lIa162ps_0 bear +31PMTcBL5-o_1 umbrella +31PMTcBL5-o_0 umbrella +32GDx70-6cQ_2 boat +351brnq0Ryk_1 boat +38Tbojzrw80_3 bear +3__l885Wkz4_0 bear +4A-5QKpDBFE_0 bear +4A-5QKpDBFE_1 bear +4BbVz6UbHFY_1 bear +4GTfq2m-SnY_0 bear +4K0agSc78Js_0 umbrella +4K0agSc78Js_1 umbrella +4MUu-MomyB0_1 bear +4N85gqVvlWU_1 boat +4OQGDsYtfSg_0 boat +4QdM0aAdf4g_3 bear +4Qf9iJ-IMDg_0 bear +4R5HjEAW6Y4_0 boat +4ViaowUogyA_1 bear +4ViaowUogyA_3 bear +4VxP7VQ-WtQ_0 bear +4XCmBo2k6Hc_1 boat +4h2kJG8rDAk_1 boat +4h8E8d4P5ms_0 umbrella +4iktvQjNLS8_6 boat +4lyoTIuPa9s_0 umbrella +4rxmIDjvHvo_0 umbrella +4td5npVxACw_0 boat +4td5npVxACw_2 boat +4td5npVxACw_3 boat +4td5npVxACw_1 boat +4u8RQi7_xUQ_1 boat +4zYtj8BG_ZA_0 boat +4z3XNRP4Qvk_0 boat +40Ogw6O8g2M_0 umbrella +42-2FjqvBRw_0 boat +44nxZjEYqLI_0 boat +45HOGdlAVq0_2 umbrella +45HOGdlAVq0_3 umbrella +45HOGdlAVq0_6 umbrella +46Sp7L3iKK4_1 boat +47mMBnGHuOE_7 boat +48IdCSlEHlM_0 umbrella +48pGfV-z-x0_0 boat +5AhKWEjMmUw_0 umbrella +5AzSuHB6_jc_0 umbrella +5Ce6X4i25i4_4 umbrella +5Ce6X4i25i4_0 umbrella +5EaEfiCIEcA_4 umbrella +5EaEfiCIEcA_3 umbrella +5FZykf07mxY_0 umbrella +5FZykf07mxY_1 umbrella +5FviZXBOPWk_0 umbrella +5H6nBOIIziQ_0 umbrella +5IdOF-nnOkU_6 boat +5I2hW9gRRwU_1 boat +5JubFWZKmZc_1 umbrella +5Kf5KxsLCmI_0 boat +5PxBf16_oMg_0 umbrella +5WUSwyO4k7A_0 umbrella +5XWfGTUYLbQ_6 umbrella +5Y3Lrgpl6s8_0 umbrella +5dL3vGF_-ug_0 boat +5e9luwmv6mU_0 umbrella +5g_ugz2HmKM_2 boat +5iYpaHYUElI_0 boat +5iYpaHYUElI_3 boat +5iYpaHYUElI_5 boat +5nMhK15X4R8_2 boat +5rT33oH7aV4_0 boat +5srF-BzF_go_0 umbrella +5suoa4TFYd4_0 umbrella +5vMpwDm27VM_0 boat +5vyqdnOWivc_3 umbrella +52m9SGVaiW8_0 boat +521jpaMoQ58_2 boat +537tF6-uRB4_0 umbrella +561s-m-0mqU_0 umbrella +561s-m-0mqU_2 umbrella +561s-m-0mqU_3 umbrella +582V5-HF4yg_0 boat +582V5-HF4yg_1 boat +597l2xVl9Tc_0 umbrella +6C42Di7bIpE_1 boat +6FG49plD8TQ_0 boat +6FQz5w7HaKg_0 boat +6JGioFiqwww_0 umbrella +6JLdACYt7D4_1 umbrella +6MVLpYA1t8E_1 boat +6MVLpYA1t8E_3 boat +6OEFFwKhAFw_0 boat +6PVjXDW7JlY_1 boat +6Sxb0d7xIys_0 boat +6Ug54vSsrio_0 umbrella +6WP3KFUYTrM_0 boat +6XrW8Yjd16I_0 umbrella +6c0RAJO-AGg_0 umbrella +6inTfRLx_58_0 umbrella +6it-xMMovj4_2 umbrella +6khDUjxTmdo_0 boat +6mvP_NKlIHg_1 umbrella +6qpeBvh9pqs_0 boat +6rowMK5ERz8_2 umbrella +6sN56W9U7tY_2 boat +6tLtEuKyj1E_1 boat +6tQrO26kwOY_0 umbrella +6t0mbpnPPdg_0 umbrella +6t55VfdtMWE_4 boat +6t55VfdtMWE_7 boat +6t55VfdtMWE_8 boat +6t55VfdtMWE_0 boat +6uM7MFSH15g_0 umbrella +6uvJft-l1R0_3 boat +6yCsWwj87QI_0 boat +6zxrdodJut0_0 umbrella +61RreGvIPOk_1 boat +66WmMvvZOxI_0 umbrella +68C7HGRrJ8o_0 umbrella +68kx9VUVhzE_1 umbrella +6-Nh0bY1nUk_0 umbrella +7HD-o1yj47U_0 umbrella +7NXmDbHoJn0_3 umbrella +7NXmDbHoJn0_5 umbrella +7NXmDbHoJn0_6 umbrella +7RcyfoxqADA_0 umbrella +7WKzOMuf3Cg_1 umbrella +7a_nsGmUZNU_0 umbrella +7kSyhlnimb8_0 umbrella +7kaTL52xbiY_0 umbrella +7tlbytb63z4_0 umbrella +7uR1cEVdMDo_0 umbrella +7ydX3wCeOgk_0 umbrella +71k1TftUiYE_0 umbrella +76ljAryU9Bw_0 umbrella +78lA-eJGUn8_0 umbrella +7-ugeb_4vqE_0 umbrella +7_k6DM-PlXg_0 umbrella +8AZtNaOO_8A_1 umbrella +8FhIv4h9D3E_0 umbrella +8FhIv4h9D3E_1 umbrella +8H88MFohrUM_0 umbrella +8SuTrZ6xu2E_0 umbrella +8d_Vt2SWIvg_0 umbrella +8fsRltS2ul4_0 umbrella +8nReKSsSgGE_0 umbrella +8oOer9PS53g_3 umbrella +801xOkfqjkM_0 umbrella +84Ber6V3IrA_0 umbrella +84zKfCKtsDo_0 umbrella +9CGTYEUn-mo_2 umbrella +9JFicuESmEA_0 umbrella +9JiMiflDI68_0 umbrella +9J4O20b9qnY_0 umbrella +9S2mGfudahk_0 umbrella +9UVLb_-RbfA_0 umbrella +9bFrwgSSAkQ_2 umbrella +9bFrwgSSAkQ_4 umbrella +9bFrwgSSAkQ_0 umbrella +98OOq0Wh904_0 umbrella +99uO6qHrhsU_0 umbrella +-PaNPkpeFdI_0 umbrella +-PaNPkpeFdI_4 umbrella +-Z3_Ixwl1YY_0 umbrella +-bA7JdKB0LA_0 umbrella +-d9Vg5j5vZU_1 umbrella +-eJmt-GItyI_0 umbrella +-k8FuC01N5E_0 umbrella +-0y7A0GDVY8_3 umbrella +-0y7A0GDVY8_5 umbrella +-0y7A0GDVY8_7 umbrella +-3TIfnTSM6c_1 umbrella +-3TIfnTSM6c_2 umbrella +-98I0B3kkqw_0 umbrella +AAVVg5xx0p8_0 person +ACB01WGxOSM_0 skateboard +ACDc6tGnXXQ_0 elephant +ADWNgv6trag_0 person +ADznOfGgfj8_0 person +AEEVGgiuS5c_0 person +AEHbOzlbmOQ_0 dog +AEJTsQNMkME_0 bus +AFlkSTJ-mF0_0 dog +AGRV17_1OS0_1 bus +AHsZ4FTQ8Ew_0 truck +AIViQtfacts_2 horse +AJBtOVA1KSw_0 person +AJbQP-rIwCY_0 person +AJ9ODXcnhVo_0 person +AJ9ODXcnhVo_1 person +AKBq0oH8IOM_1 train +AKBq0oH8IOM_3 train +AL9dFpjFlLM_0 horse +AM-TjLTvBSU_5 bear +ANA-pgSAzGI_0 horse +ANVnK2HmZno_1 airplane +ANVnK2HmZno_7 airplane +ANeOKwjvX7w_0 dog +APP17gURiBU_0 bear +APP17gURiBU_1 bear +APTYyEYJfOY_0 bird +AQD8YBCTSPs_0 umbrella +ARaILMtc8fs_1 person +ARsokXpl07Y_1 boat +ARsokXpl07Y_2 boat +ASPK-ZSB9Ts_0 person +ASfv8cmreoA_0 person +ASfwyHCtnIU_0 person +AS5LvQT9rrQ_0 person +ATy91FTiYvU_0 person +AVF8lCKe6os_2 umbrella +AWRcJpWTPwQ_0 person +AWtY9Y2mPso_0 motorcycle +AWwDsm1WnKE_1 knife +AXjDlIFY7ww_0 boat +AYAkMpj_MHA_2 bicycle +AYAkMpj_MHA_5 bicycle +AYAkMpj_MHA_6 bicycle +Aax6L0Qqgio_0 bird +AcYd7y_-V74_0 person +AdY55Q3qVK0_2 elephant +AgbIDWiOXQ8_0 person +AgsYgmA19z4_0 person +AhWU-QUzOOA_0 person +AiqGEAjF6QI_0 train +Aiu6EH4a8v8_0 train +Aiu6EH4a8v8_1 train +Aiu6EH4a8v8_6 train +AixV6QSGqto_5 bird +AixV6QSGqto_6 bird +Ajj7WZLukdw_0 motorcycle +AjpbAriY8rU_0 person +Alab3dEYXM0_0 person +AoAoH9yb6zY_11 bear +AoAoH9yb6zY_6 bear +Ao7Sa2afCb4_0 person +ApDgLQUsEqc_0 bicycle +ApakHefqWv0_2 airplane +AqIG0zk2bpg_0 person +AqTXLh7DtcM_0 person +AqTXLh7DtcM_1 person +AqdoD9jkBFc_0 horse +Aqj7VnXQt4s_0 cow +Aq4dBqb2SbQ_0 person +ArgYRdhvlc0_0 skateboard +AsPXe7qUyuI_0 person +AuLrPQqrKV4_0 motorcycle +AuY8vITQrsE_0 cow +AvBm7iHiDdI_2 boat +AvSgTHXgSXQ_0 cow +AwVdVzh1Eh0_0 person +AwvDMOeS7no_0 person +Awzt30r0OLQ_1 bus +Aw2t3AalW4s_4 elephant +Ayh_2ithjCE_0 cow +Ayh_2ithjCE_1 cow +Ayh_2ithjCE_2 cow +AylQiap7dj4_2 bear +AylQiap7dj4_3 bear +Ay9QToaaTGc_1 truck +Ay_a2OkcdEk_0 person +AzVvPUazPYk_0 motorcycle +AzzlFx32dQs_1 boat +A1RSx6j_ra0_9 elephant +A1RSx6j_ra0_4 elephant +A1RSx6j_ra0_6 elephant +A27YZAfJmrc_0 knife +A27YZAfJmrc_1 knife +A3E72P24pf8_0 person +A3cgW1rDOcI_0 person +A32Fi06yKpU_0 horse +A5U6AHe9_4A_0 train +A5pUgLCQq9k_0 elephant +A5pUgLCQq9k_2 elephant +A5pUgLCQq9k_3 elephant +A63BoLTUNAM_0 horse +ZBzVnA8zj6Y_0 person +ZB45YyN1WUM_0 bus +ZFYGhJKiw5w_1 giraffe +ZGfOCwbu-PY_0 person +ZHTMfW1eaW0_0 cat +ZHURcze8rOI_0 person +ZIJUWQKzzsQ_0 person +ZJgwacILoAw_0 person +ZMgP2kxv5E8_1 person +ZM3wX5zgKOA_0 person +ZNXnJahaXIY_0 person +ZOc4wfLX2Jo_0 cow +ZOnuSLp6asQ_0 train +ZPQNucbAjBM_0 cow +ZQITHWk17a0_0 bicycle +ZQxmb_nVoH4_1 cow +ZRUXj8o10Po_0 person +ZSnP5B6NiI8_0 train +ZTqDuCZVTmM_1 airplane +ZTqDuCZVTmM_5 airplane +ZU3AYv2eU74_0 motorcycle +ZU4XQbNaYQc_0 knife +ZVZWEWzZg50_1 bird +ZVjep3tDJjU_0 person +ZWL6CshdsuY_1 cow +ZWogXn8xs7E_0 motorcycle +ZXU4Uua3l0E_0 car +ZYOUZjfZMhk_0 cow +ZYS0h2pAK6M_0 horse +ZYm5iVw0YdE_0 truck +ZY8pG-I5Ax8_1 bicycle +ZZBBcTBPmis_0 person +ZZpckGIvGTI_1 boat +Zana4yKDGxY_3 skateboard +Zana4yKDGxY_1 skateboard +ZbnxzLt8FJk_1 dog +ZbnxzLt8FJk_0 dog +ZcXtrHkjobw_0 person +ZelRUJyMMkw_0 person +ZeqhN6ndscE_0 person +Ze8cOn59rW4_0 person +Ze8cOn59rW4_1 person +Zj1TAkYHlQo_0 person +Zj7GzCIi_9c_0 person +ZlEiOICCDdc_0 person +ZlH8Hd961FM_1 knife +Zl30Oy50PfQ_0 person +ZmXKvpkfHZA_0 train +ZmdvunyqJB8_0 bus +ZqTkqkEbXEk_0 cow +ZrPn3BODZJM_1 person +ZrPn3BODZJM_0 person +ZuBD3A8Vecs_0 bird +ZuEbZKmjxaA_0 train +ZuEbZKmjxaA_1 train +Zu7udgxuUkk_5 airplane +Zu7udgxuUkk_6 airplane +Zu7udgxuUkk_1 airplane +Zu7udgxuUkk_2 airplane +Zu7udgxuUkk_3 airplane +ZvadVS1LnQU_0 bus +ZvadVS1LnQU_1 bus +ZvadVS1LnQU_2 bus +ZwLvs9JUsFY_0 person +Zw4-vF-vOMk_0 person +ZxO4Gd5fhOg_1 train +ZxO4Gd5fhOg_2 train +ZxX6DBopv30_0 skateboard +ZyEA24Ud3EM_0 person +ZyM24-ekpz8_0 person +ZzBvzlzuw4M_0 person +Z03ZC9qmwDc_0 zebra +Z1N0xBj_H3E_0 bird +Z1ns6XidhT8_0 elephant +Z2S6XnfE5vI_0 person +Z2kb4LiQJUU_0 train +Z2zB-gtDgOM_1 elephant +Z22DSYtblFo_0 bicycle +Z5rHikLjARg_0 person +Z6XKceRI1bE_0 bus +Z6XKceRI1bE_3 bus +Z6XKceRI1bE_6 bus +Z6XKceRI1bE_10 bus +Z6qQE2_jsIM_0 skateboard +Z68yTt3upjk_0 motorcycle +Z8SxFPbnptI_0 person +Z8pujku9bPw_0 person +Z9vZk0io0fw_0 truck +Z9vZk0io0fw_1 truck +Z-R7-Ww03t8_0 knife +Z_kKBbIzdXM_0 person +Z_pwMCnOdk4_0 knife +Z_pwMCnOdk4_3 knife +Z_0227AsAvk_0 bus +A_a1H0EO64s_0 person +A_a1H0EO64s_1 person +A_pc9ov1cT4_0 person +A_weMKVolQM_3 bear +BBC4Jmlky4Y_0 horse +BBHBoewIXhw_1 umbrella +BBHBoewIXhw_3 umbrella +BBHBoewIXhw_4 umbrella +BCKR989ZYyM_0 car +BCKR989ZYyM_2 car +BCpaJ-tEv-0_0 car +BFP7MT8RM8U_0 elephant +BF7cTjrTSwY_0 cow +BF8d91cJS3o_0 person +BGcAVF0Zi_o_0 person +BGzetX8Dz-M_0 cow +BHurVVjld8Y_0 person +BIUeggZa3SU_2 person +BIUeggZa3SU_0 person +BIUeggZa3SU_1 person +BIfedkd3HEg_0 boat +BJaAlMv6b_U_1 motorcycle +BKKSiAed9CI_0 horse +BKtAnbXVk1E_0 person +BLCEb_seyUs_0 airplane +BLCEb_seyUs_1 airplane +BL8o-tdhlxs_2 train +BL8o-tdhlxs_3 train +BMhmY9_ltFc_0 person +BO7KZKb9bkQ_0 cow +BQRwIXopDJw_0 person +BQRwIXopDJw_1 person +BQswg--xiy8_1 horse +BRd8dUMN0a4_0 knife +BRmtavy2ZEo_0 person +BR0NNg6gLLo_0 person +BSo8wjoZ7zc_0 skateboard +BTSUQrxC6l4_1 bus +BUHULgt_7DA_2 elephant +BU3iU3zJnDI_0 person +BU8sEPifL08_0 person +BVTVHHm7vkA_0 boat +BWNTXqGixw8_0 bird +BZUE0vDhMvk_1 knife +Bb2fkGYxp2E_0 person +BckXjb2o93U_0 person +BdHNtn10UKE_1 horse +BeXziIDAJDc_0 person +BgHV_87CxNI_0 umbrella +BgXr-bSqMIo_0 train +BhO0SwB8Ee4_0 person +Bh4m74dLZaM_0 person +BlYWgnhwvkM_0 elephant +BlYWgnhwvkM_2 elephant +BmZNFBFj-ws_0 person +Bm2yaWXwgjY_0 knife +BpXhq5Awd3U_0 dog +BrC6VbCzRGc_1 knife +BrHslMc3UMQ_0 truck +BscLJpi3AJc_0 person +Bv8WeZ_zrJc_2 bear +BzEC1EEC2ts_0 person +BzXWK-LODVo_0 person +BzbzymdK_TM_0 person +Bz6Od4GfW6A_0 truck +B0DRHTdmeK4_0 knife +B31JkzyQDkg_0 bear +B5GVudI81dM_0 dog +B6nArbkcRek_0 motorcycle +B6sR2aqScR4_1 bus +B7IP-2uNuWs_0 skateboard +B7yxjI6dz4s_0 motorcycle +B8iZGZlQcsg_0 person +B8opNd6uzmY_1 person +B9GQwzI2Eqk_0 dog +B92X9Xn1P2s_0 person +B-CJ8miJKPs_2 cow +B-n15EytPtQ_0 person +B_WnXKd-oZk_0 person +CADW3z8x4AU_0 skateboard +CADyh6laNA0_0 motorcycle +CA3wWkrNnRs_0 person +CBSNFKeTnpA_0 bird +CCyZAt2Js0U_0 car +CE-LfFDfGKQ_0 person +CE-LfFDfGKQ_1 person +CFN40hxKxM8_1 airplane +CFPhXPCobFg_0 person +CGg2FXjvvOA_0 person +CH3phgDW5Fc_0 person +CINfsd8LiOU_3 horse +CINfsd8LiOU_0 horse +CINfsd8LiOU_2 horse +CIqkbJoJhBI_0 train +CKmnpW6gboU_1 boat +CKmnpW6gboU_0 boat +CLtQxCqTzcY_1 knife +CMgYFnnxQUU_0 horse +COcbSVCp4ig_0 bicycle +COcbSVCp4ig_3 bicycle +COcbSVCp4ig_4 bicycle +COcbSVCp4ig_5 bicycle +CRF7PcgB2yQ_2 bus +CSnhpel7FTA_0 person +CSriNtLepLs_1 skateboard +CVmBocpXeTc_0 bus +CWCfCeYh2bA_1 train +CWvjAYt5eR4_0 bus +CW9n8Gahfgg_0 cow +CXT98GHNtRU_0 person +CZ-Sh-SXaRQ_0 person +Can5eao1S3Y_0 bus +CbB-71R_n9M_1 motorcycle +CbpAv8c2Vsg_2 car +CbpAv8c2Vsg_3 car +Cb3iufTFMEU_0 person +Cc2vs8vuPmU_1 bird +Cc8E7aTdEVM_0 person +Cdain96L-q0_0 bus +Cd7g3ZoA5tQ_0 bus +CeN22koBQRM_0 person +Ce2jOHHBDLk_0 motorcycle +Ce7IPtXkNcs_0 person +CfqkbrB0Yy8_0 person +Cf2jOSj7eRg_2 train +CjbhKc3Vjpo_0 person +CkEVvGqgVkQ_1 knife +Cl13SbLP0hE_2 horse +Cl13SbLP0hE_3 horse +Cl13SbLP0hE_0 horse +Cl13SbLP0hE_1 horse +Cl-lB_jS8Wg_1 bear +CnMMdc6syXM_2 umbrella +Coxzc_S3ID0_1 knife +CpLMLRdeJJ0_0 train +CpN-qOO6Qm4_2 airplane +CpyK9j001RY_0 person +CqNEwP8PwS4_0 bear +CqNEwP8PwS4_1 bear +CqYiAanNpo4_0 person +Cqbu8vOsszI_0 cat +Cr5p4NYIR44_0 person +CttKQip6B2E_0 person +CuGu45Z4lt8_0 knife +CvszgVrLsgA_0 person +CwYG2Hf6-NY_1 cow +CwvR1fjMeSU_1 horse +CyuollntwZ8_0 dog +C1dCZ9W6WIM_0 person +C2x3rdWMAyg_0 dog +C3lwMd_rlG0_0 person +C5MrhYouFTc_0 cow +C5SKibJTnR4_0 cat +C6dANICzCcg_0 person +C6xJeHO8XSE_0 person +C7NXymSnEFw_0 bird +C8ExRKjU1vY_0 truck +C8V2-wEjv5A_1 cow +C8sUABBP0Jc_1 bicycle +C8sUABBP0Jc_2 bicycle +C80bmA0XrjM_0 person +C886JwUWvxw_0 skateboard +C-Tal1XUc8o_2 person +C-zp91eJqtk_3 bird +DApDao4fUqQ_3 horse +DApDao4fUqQ_1 horse +DApauH43Ivo_0 bicycle +DBArY7gHuoY_0 cow +DBsBTVJNxS8_0 dog +DBsBTVJNxS8_1 dog +aCNvyXSuG6w_0 person +aCVmJCtuPeg_0 bird +aCVmJCtuPeg_1 bird +aDMk7CwLIxM_0 train +aERiDkn_gkY_1 elephant +aEwD6TC8S4w_1 bicycle +aFEOvm-1KvA_0 horse +aHM4Dj-2y8o_0 airplane +aI0y0wY4LQw_1 person +aI0y0wY4LQw_2 person +aJAd-MiEsfk_1 person +aJWETVChAE8_0 person +aJoKSWtqs0g_0 truck +aLYtaO_J2_U_0 person +aLbjxTwAV7o_0 person +aMDD0PenhaM_0 cow +aMgj1BUBexw_0 person +aNgAUBTbUUM_0 person +aNmgrcJxdw8_0 motorcycle +aN2a-rDAYDQ_0 dog +aN2a-rDAYDQ_1 dog +aOhumbyx05c_0 cat +aQcTwMVs1Zk_0 skateboard +aQcTwMVs1Zk_1 skateboard +aQx68fklEXA_1 dog +aSGod2MJ5ww_1 horse +aSq5ZqH_K7E_0 truck +aTAXvSNkuvc_0 bus +aUFxg301s68_1 skateboard +aUsTtvWAzAc_0 person +aV8S5HLSI_o_0 person +aWHaR4ExDpk_0 truck +aWIZBHwtII8_0 motorcycle +aWgH9T2sGkE_0 boat +aWmC8Tbgy9A_0 train +aXa5YE_AmKg_0 person +aYAuay_bTaw_0 cat +aYVEZrX4mE0_2 bear +aZRYQJd-5CQ_0 train +aZRYQJd-5CQ_4 train +aZRYQJd-5CQ_3 train +aZRYQJd-5CQ_6 train +aaZxOcHxPec_0 person +ab_RTkwBG_4_0 person +acy4aJnh9SU_0 person +ac68trlkEnw_1 horse +adsmRxlAJo4_0 dog +afE4YqgaPlw_0 skateboard +afU2vHgUvaw_7 train +afU2vHgUvaw_2 train +afU2vHgUvaw_3 train +afkiqhwTeRQ_0 person +aiOHs3hApm0_0 skateboard +aiOHs3hApm0_1 skateboard +aij190b9wtM_4 bear +akWe9oXeKzA_0 person +ak1XT_Nl7VU_0 airplane +ak4CfFF9Bpk_0 person +albeyJBtKD8_0 person +alp0ImrbacI_0 dog +al12VKid_P8_0 person +amyr6d2Ns6M_0 horse +amyr6d2Ns6M_4 horse +amyr6d2Ns6M_6 horse +ao9LHpxNCqY_0 horse +apLT3-LKJgE_1 truck +apXNcHROKyY_0 horse +aqp_quyEngw_0 airplane +aspR9ca28CY_0 person +as3DGRDezaA_0 person +atElNgnFvlk_0 person +at-Ex-CnRX4_0 airplane +at-Ex-CnRX4_1 airplane +au_kgqsZlMU_0 truck +avRC7M3_kuA_0 bird +awnORAEMUIg_0 person +aytqFnOdBLA_0 person +azLbVm88Dzc_3 airplane +azLbVm88Dzc_2 airplane +azXlb1cxVGQ_1 elephant +a1qoB1eERn0_0 person +a2-lZhKXx9E_0 truck +a3In51YCqMg_0 dog +a3T8T1R2wAc_0 bear +a45XOJQaDQI_0 person +a5dffDLeZsI_0 airplane +a7hjIfPGJqI_0 cat +a74_tj_B-YA_2 knife +a74_tj_B-YA_1 knife +a8v0k4Bz_QA_0 person +a9jgDU5THOU_0 person +a97S4U5ezQw_0 truck +a97S4U5ezQw_1 truck +a-M2_3j67qI_4 knife +a-M2_3j67qI_5 knife +a-M2_3j67qI_6 knife +a-NeSgN26Zo_0 bicycle +bAKQZ0F7LFw_0 person +bA10PjxgV3w_1 elephant +bBPKh_BPJ50_4 bear +bBPKh_BPJ50_1 bear +bBW4swLrEHE_0 person +bB6tIraYEaI_0 skateboard +bCDw1dn7M1Y_0 car +bCDw1dn7M1Y_1 car +bCWM39xLsYs_0 skateboard +bDFkztSgMko_0 skateboard +bD6xZhJfhMU_0 truck +bFnzGS_doNQ_0 person +bGFRHhc7zUI_1 person +bGZtGWULlF0_0 skateboard +bGZtGWULlF0_1 skateboard +bIOpYFVLesY_0 person +bJviDDrUSwA_0 motorcycle +bKB6ESqkOic_1 truck +bKRAinEnagU_1 motorcycle +bKRAinEnagU_0 motorcycle +bNXcPzWMXsw_0 car +bN43crdYDJE_2 bus +bOL9YHt5u-o_0 skateboard +bOL9YHt5u-o_1 skateboard +bOofbwD246U_0 person +bPKew4jsGkE_0 truck +bPRVRL4x5T0_0 truck +bQkneVc9gaA_0 airplane +bQ64JFsWSf0_0 bicycle +bRWbXGRwlVY_0 person +bS1Z1k6laqY_0 person +bUqFsPoDKBE_0 train +bVP58EONEm4_0 cow +bW4nHswGFPo_0 motorcycle +bW5IvSesbV0_0 elephant +bXR-iz0NfrA_0 cat +bZDsNeqNn9I_0 car +bZDsNeqNn9I_2 car +bZDsNeqNn9I_3 car +bZDsNeqNn9I_5 car +bZIU-ajwk6Q_0 bicycle +bZIU-ajwk6Q_1 bicycle +bZ6Tq0KWSsU_0 truck +bZ6Tq0KWSsU_2 truck +banaB07Fu9c_0 bear +bcKUeyEaRPw_6 bicycle +bdhq0SKEqe4_0 person +bd3b9R30l-E_0 person +beDuTpy1tg4_2 horse +beDuTpy1tg4_0 horse +beLkXAaP78Y_0 train +be30TAE-gq4_0 person +bfQSyBsTmE4_0 umbrella +bgSSzKax51E_1 motorcycle +bgSSzKax51E_0 motorcycle +bhoUxK8FSqc_0 person +bhuPA9toCGY_0 person +biIFNnX2Nl4_0 skateboard +biu2ssO3dRg_0 bus +bjRPge2oFgU_0 knife +bjV04dzuqhk_1 elephant +bjdIG6B5zn0_0 person +bjdIG6B5zn0_1 person +blPLp16K1XY_2 bicycle +bmJ_QDIRS2U_1 train +bmJ_QDIRS2U_2 train +bmJ_QDIRS2U_3 train +bmLsrJHQQ14_4 knife +bnBORorLvmk_0 person +bnBORorLvmk_1 person +bnVGsydNrg8_0 airplane +bnVGsydNrg8_1 airplane +bnZbj1dD0qs_0 umbrella +bn0I2aJB5Ps_0 horse +boMU1mjUSDw_0 skateboard +bo8M-OTk4J0_0 person +bpw3BCxYYU4_0 horse +bqoDChNwIYY_0 umbrella +brJqQ_iH2VE_0 person +brMVhyEZLfo_0 person +bs5AY2jipno_0 train +btL-vruELoA_0 person +btq7gMuqMuo_1 person +btq7gMuqMuo_0 person +bvEJDHpRNoI_0 elephant +bvVfFv57gN4_0 bus +bvVfFv57gN4_4 bus +bwhPTEvGmIo_0 person +bydgNyGwoys_0 person +bziUK-7O0lY_0 dog +b0Z6qKhuldo_0 skateboard +b0sKQDUFTos_0 person +b1s-jYD36GQ_0 person +b4Wua_98Y9U_0 person +b4d_9Yc0MwY_0 bicycle +b4qC2fctnLU_0 horse +b4zSrjPtOfs_0 bicycle +b5CJtpeG1Lc_0 train +b5CJtpeG1Lc_2 train +b5CJtpeG1Lc_1 train +b5mOcLykYeQ_0 cow +b9VOmo_86Ds_1 person +b_W4BWH1i_A_1 person +b_W4BWH1i_A_0 person +cBxo9bPINJc_0 skateboard +cCEImigNo38_1 train +cDHZtfsI_gM_0 train +cDHZtfsI_gM_1 train +cDmkhESohro_0 boat +cEcTernKOqU_0 person +cEcTernKOqU_1 person +cGJLuwZIG5s_0 giraffe +cGJLuwZIG5s_1 giraffe +cGJLuwZIG5s_2 giraffe +cGwjfCPO-7k_0 car +cH0sXpOxvy0_2 bird +cH9u1pCWp2U_0 person +cH_SL9CR8y4_3 dog +cIxdxFkZ7y8_0 dog +cIxdxFkZ7y8_1 dog +cJvh4GqZn-s_0 person +cKQQVTnOzBk_0 horse +cLULEYFoBPc_2 cow +cMdjRuUhBIs_0 motorcycle +cMdjRuUhBIs_1 motorcycle +cMwa9cC304w_0 cow +cMwa9cC304w_1 cow +cNDYJRBsIOY_0 dog +cPlqWSd2TUc_0 person +cP-p4R-JZxY_1 bird +cRBw9lx-EKA_1 bus +cR2-4m174EM_0 bird +cR-AWpc5zTs_0 person +cTujx-TutbA_1 horse +cUrajeQPzpQ_0 umbrella +cUrf-ZwPzxI_0 person +cUwPVOboe0k_0 person +cVng1vleWNY_0 person +cVrxfV0w29w_0 person +cXZ7JY7YQmE_3 bird +cYdqN1oPRdY_0 person +cagT3K3Ep3s_0 skateboard +cagT3K3Ep3s_1 skateboard +ca8rEbHYMXg_0 cow +ca-ko46j2fQ_6 airplane +cbL66gVAa5Y_0 cow +cctYyTO8OtU_0 person +cc3mBIHi-GU_0 elephant +cdNz1OLa1tU_0 car +cf_U0G5W8BI_0 person +cggX7PRYUh0_0 person +cg_5uaJjLHk_0 person +ch_23jXJ_vA_2 dog +ciCfkv5831Y_0 airplane +cih9W0SPGYA_0 bird +ciwNB-l9a88_0 person +cjHlHkhg0z0_0 person +ckFwzL1Ot94_0 truck +ckV9ay1lm7A_0 airplane +clZo-o5v1EA_0 elephant +clvCQPta7y0_2 bird +clvCQPta7y0_0 bird +clvCQPta7y0_1 bird +cmTPsZ9x3PE_0 cat +cmW0Y4KGI7g_0 giraffe +cnhhgh_z5NU_0 cow +cnqT4u0k3sM_0 umbrella +cpK8K6JD_GM_0 airplane +cpK8K6JD_GM_2 airplane +cprvb4cW5x4_0 motorcycle +cqd8PRxMakA_0 truck +cqvjKRFEi8M_1 car +crys7VEeUgU_0 person +cskBHjsDXEs_0 cow +cso6B_84BFA_0 horse +ctm9x2MaZuk_0 cat +cxu1qpzXobY_1 bird +cxu1qpzXobY_12 bird +cxu1qpzXobY_0 bird +cxu1qpzXobY_2 bird +cxu1qpzXobY_4 bird +cxu1qpzXobY_5 bird +cxu1qpzXobY_6 bird +cxu1qpzXobY_7 bird +cxu1qpzXobY_8 bird +cxu1qpzXobY_9 bird +cxu1qpzXobY_10 bird +cxu1qpzXobY_11 bird +czO8IPcAO1A_0 person +c1FBptbYp3I_0 person +c1FBptbYp3I_1 horse +c2T3VDriTaY_0 knife +c39xfJcSlxk_0 dog +c4kbPHdCIE8_1 elephant +c43mnrjx2MU_0 bus +c5fPKbV5cAM_0 person +c53j9l_w3Cg_3 dog +c7gnf6G7Jpw_0 skateboard +c7oqQy2Fvlw_0 truck +c8JhzKh1i7s_0 person +c8JhzKh1i7s_1 person +c8gBv0b5g9w_1 elephant +c8iU4McayiU_0 person +c8iU4McayiU_1 horse +c8u5Y95o7jE_0 skateboard +c84BjBiic4s_0 motorcycle +c93WuBjZeRk_0 person +c-nMPinePds_0 cat +c_aupqZy-14_0 airplane +c_o91IPAB-c_0 umbrella +dAHCPltzogA_0 bird +dAP6fuArseQ_5 elephant +dAtQR4dHPgE_0 person +dA0WQ_RubaI_0 truck +dBzXNQJRzls_0 cat +dCJFMDQBPb4_0 boat +dEIuy8LjAxc_0 car +dElaQ10vYqg_1 motorcycle +dHMFcv4UnmU_1 bus +dIP3FoGUXDQ_0 person +dJYqTnxujb0_0 person +dJnLznNE29w_0 train +dJnLznNE29w_1 train +dJ9qJezt6do_0 car +dJ9qJezt6do_1 car +dKmrUcJ9rJY_0 person +dKmrUcJ9rJY_1 person +dK3_HiQMH4o_0 dog +dMFsGGvkSVU_7 airplane +dMFsGGvkSVU_0 airplane +dMFsGGvkSVU_3 airplane +dMFsGGvkSVU_5 airplane +dMFsGGvkSVU_6 airplane +dNByeKh4gnA_0 person +dNJ0q9QKzmY_0 boat +dNQYo7REyBU_0 person +dOkb5WhLZGU_0 person +dO0uu_fVUVI_0 car +dO0uu_fVUVI_1 car +dO4Jxsf987s_0 bus +dO-OrWse3dA_0 car +dPCSntP-29E_0 person +dPCSntP-29E_1 person +dP7je2qU_QA_0 dog +dQIlnQxMIKo_0 train +dQIlnQxMIKo_4 train +dQIlnQxMIKo_5 train +dSAlTJeDlfQ_0 person +dTvJyUKKshw_1 person +dTzaYePj1gY_1 cow +dT5gXQAE-Qk_0 train +dT5gXQAE-Qk_2 train +dT5gXQAE-Qk_3 train +dUpoYuxpKPM_0 person +dVTCCi__Z4Y_1 person +dVte44AGoEE_0 knife +dW4RjdpTaJo_0 person +dXYYgzjwm8w_0 person +dXf-d5rkqdA_0 horse +dZv4xXpV6js_0 boat +daeBFAZFQhU_0 person +dbXKW9_L9sE_0 bird +dbwBzQuj1uA_0 person +dc5oaWIkfwg_0 cat +dc-iaCwezlU_0 train +deO0aj59T8o_0 person +dfU8DcWDX8U_0 horse +dfU8DcWDX8U_4 horse +dgcW3TkPLmk_0 boat +dilCe3bivVk_0 bus +di59PG3l25w_0 bicycle +di59PG3l25w_1 bicycle +djsh1r_W6ko_0 person +djt1lzJn7ak_2 bird +dlYwqfTRqoo_0 person +dl-bg8WPGZs_0 person +dmk3Cedj6g0_0 person +dn006hdarCg_5 elephant +dn006hdarCg_4 elephant +dn006hdarCg_6 elephant +dn006hdarCg_7 elephant +dn006hdarCg_10 elephant +dn7iBi1t7UI_0 cow +dn83BrM71W4_1 boat +doOsOyiHItw_0 person +dpqVH2tgA3E_0 person +dqlk6F07Cxw_0 motorcycle +drohCN_vwC8_0 motorcycle +ds7JGeImFXo_0 horse +dtsLwaO2des_0 train +dt5TzAZByk0_0 person +duROYI-AZlk_0 person +duROYI-AZlk_1 person +dutryxrzRjE_0 umbrella +dvDxOc2VWhc_0 person +dvP5Dsp8EZA_2 dog +dvTIkEA7rOc_0 person +dvvoKcQ5OOQ_3 bear +dvx9-0cVEYc_0 person +dwQuyR9XFVM_0 skateboard +dxcnKYynkEY_1 cow +dxmxpyj3WVk_0 knife +dxmxpyj3WVk_3 knife +dyUVa3ZQVFg_0 horse +dzitRPrX410_0 cow +dzpcdtcQLfY_0 motorcycle +DEnqBEwPykc_0 person +DFCqlvY5OFY_1 bus +DFXptvzN9V8_3 umbrella +DFqSvoSh-qA_0 cat +DHEtea1hPBc_0 person +DHwUCu0rrvc_0 boat +DJ_neeMWAuw_2 dog +DLsYDXqthiY_0 skateboard +DMBbH5HyOME_0 person +DMn3ruRAObI_0 person +DMyjVWCLbes_0 person +DM6e1vEjYeM_0 bicycle +DM6e1vEjYeM_6 bicycle +DND0C3XD7mQ_0 horse +DOQilAKERwk_0 umbrella +DOmE1dA6CoQ_0 person +DQJ4cPhVhFg_0 airplane +DT895n1nqqY_5 bicycle +DT895n1nqqY_4 bicycle +DUO7S4ma320_1 cow +DUO7S4ma320_0 cow +DU9GDCN25lI_0 person +DV4bDUzPAIU_0 train +DWxidp6TWlg_0 airplane +DXhV8uXKo7w_0 cow +DXxF81ZJ_Jo_0 cow +DX1_rKFVugE_0 dog +DYBLqnRCo7g_0 cat +DZ2-5rYAUVk_0 train +DasqUqgdRv0_0 dog +DbNVb8C-Au8_0 person +DbcdvAsVI48_0 person +DcZSisTgSJs_0 airplane +Dc9pWTcUNXY_5 bear +DeVQ3mr19Sw_2 skateboard +DeYmal3wAoE_2 dog +DeYmal3wAoE_0 dog +DfOuxNA9lro_1 giraffe +DfXOTMc9IyM_1 dog +DfbPDcLTZEo_0 airplane +Df89T9IxDvc_0 person +Df93ocrYlyY_0 person +DgBuwqAbIkI_0 skateboard +DgBuwqAbIkI_1 skateboard +DhA0S7lPFVw_9 elephant +DhA0S7lPFVw_0 elephant +DhA0S7lPFVw_1 elephant +DhA0S7lPFVw_2 elephant +DhA0S7lPFVw_4 elephant +DhA0S7lPFVw_5 elephant +DhA0S7lPFVw_6 elephant +DhA0S7lPFVw_7 elephant +DhA0S7lPFVw_8 elephant +DhEO4MuDBOc_0 dog +DhJAQCycHJs_0 elephant +DhU-e-L13WM_0 person +DhU-e-L13WM_1 person +DhU-e-L13WM_2 person +DiLGyNCykDE_0 skateboard +DjQx_qEnXko_0 airplane +DkMltyvC5l4_0 person +DmPTbBo32qI_0 bear +DmzlB4KBLN4_0 bird +Dm-XQKFA-BQ_0 truck +Dni4lPw5oH0_0 person +DnzZd_9JlAA_0 cat +DoB18AvtSxQ_0 train +DofzMEokur0_0 person +DonLBf92rMc_0 dog +Dpp4k_BzZY8_1 airplane +DqcEAexhJ10_0 car +Dr6LfvQ_qKo_0 car +Ds_4eRyQDPo_2 boat +DuLk58XzeyA_0 train +Duv1XrdytdE_0 cow +Du4jlCLKZds_0 person +DvjMMfcCq3U_0 person +DvuTkGshMjA_2 cow +Dvx0WVMuXVw_3 boat +Dw4--8weqIA_0 person +Dx0LbiFgvPI_0 truck +DyY1MPuGf5w_3 dog +DzUJVl_Pej0_0 person +DzV-LWU5GoY_0 person +D0b7xYmwl-M_0 skateboard +D0fhKhpAhJM_0 zebra +D0jRA5TKT-o_0 person +D1vTDW7YDTk_0 person +D2hRnCm0JtM_0 person +D2oV8BC0iq8_0 person +D21mLV716vI_0 person +D32GncZb51Y_3 truck +D4Jcg1u1Z-o_0 person +D5maMxzZBe0_0 person +D5m40zCfU8E_0 person +D6E0xgBBquU_0 person +D68oMT6tpc4_0 person +D7H1UQbgDOw_0 cow +D9RGgV3fKds_0 bird +D_a5TQmLY-Y_1 person +EBJ5jExrVqY_0 cow +EBLJ9v0QSrU_0 car +EBUmagxsoV8_0 person +EC8ftAGy2qA_2 skateboard +EDBDHaRqToc_0 dog +EEZKnzcn-v0_0 cat +EEfiTwozdM0_0 cow +EExHYyuWa-o_6 bird +EExHYyuWa-o_2 bird +EExHYyuWa-o_5 bird +EFRywDKULxc_1 train +EIl3WAxkNwc_0 train +EJJXpIiBEuw_0 cow +EJrj49l1N8k_0 airplane +ELPjTNVxWfM_0 person +EL-2TiSSQJg_0 bear +ENPh0zyq2wo_0 motorcycle +EOAADsR4IpM_0 cow +EP3xfG5_2i8_0 cow +EQN5hODdb6o_0 skateboard +EQ09ewMQn8Q_2 bird +EQ09ewMQn8Q_0 bird +EQ09ewMQn8Q_1 bird +EQ9vXT_IFYQ_7 bird +EQ9vXT_IFYQ_3 bird +ESxRPsxVX-U_0 car +ETxRky6I39w_0 person +EVD8F2ZOBbI_0 elephant +EVYb5simSY0_0 umbrella +EWOehvvAvqU_0 person +EXK2mcPIoBI_3 skateboard +EXK2mcPIoBI_0 skateboard +EXK2mcPIoBI_1 skateboard +EXK2mcPIoBI_2 skateboard +EXeKX_vOTvc_1 car +Ed-cfsA3BsU_0 horse +EeQOKiPASgY_0 person +EfAYg1FMY-4_0 bear +EfAYg1FMY-4_5 bear +EfAYg1FMY-4_4 bear +EfSd4ucOXKs_0 truck +EfbKwoMA6Kk_3 horse +EgpujPNldhs_0 train +EhQXwVQsngU_0 boat +Ej0A86Eu1p8_0 person +ElHgkP_L8Eg_0 airplane +ElTbW5itOAs_0 car +ElTbW5itOAs_3 car +ElTbW5itOAs_4 car +ElTbW5itOAs_7 car +EmvEUer4CVc_0 umbrella +EnIkH0jrzaI_0 skateboard +En6a3Ed7fvk_0 person +Eo5s8ykuzbU_0 person +EpBZ77zmngM_0 horse +EpPw2JoHiTQ_0 person +EqPK8xdf8hQ_0 person +EqdBE21XAks_2 umbrella +EqdBE21XAks_3 umbrella +EqdBE21XAks_4 umbrella +Eqz3xG4mWTs_0 person +ErN8-oTPkq0_1 person +Er-RnWQrUac_0 cat +EsvPqOf-zEA_0 person +EtIj5IUtn-g_0 airplane +EtIj5IUtn-g_1 airplane +EtIj5IUtn-g_2 airplane +EtMlgBveP58_0 dog +EtMlgBveP58_1 dog +EtkDITl8mEM_0 person +EwlCKB77dYo_4 elephant +EwlCKB77dYo_2 elephant +EwlCKB77dYo_3 elephant +EwqkMKutzBE_1 knife +Ew-67eGgZAI_1 motorcycle +ExRpjMcFoBY_0 dog +EzRrohN-4ss_0 skateboard +EzZW0lM284U_0 skateboard +E2DbbyoqLg0_0 person +E2DxfZPPu5Y_0 horse +E2DxfZPPu5Y_1 horse +E2DxfZPPu5Y_2 horse +E5erp1mhTzk_2 bear +E7CsRpWElOo_0 horse +E76rAl8oksk_0 dog +E9ARkaJcz2M_0 person +E9J03vUxTZQ_0 truck +E9w2-Y4d3MM_2 truck +E9w2-Y4d3MM_0 truck +E-ea5keAG3Y_0 person +E-jpkZw_MdU_0 motorcycle +E_cxlc0vrMg_0 horse +FBA18EyY2eI_2 boat +FBQpWJPC5pQ_0 person +FBQpWJPC5pQ_1 person +FBo954IqOlo_1 bicycle +FBo954IqOlo_5 bicycle +FBo954IqOlo_0 bicycle +FBo954IqOlo_2 bicycle +FBo954IqOlo_3 bicycle +FCICeCD4dKc_0 person +FCypWBdHWb8_0 elephant +FDKvBZH5LZE_0 horse +FD89Oq7BclA_0 skateboard +FETKMmV7P70_0 motorcycle +FETKMmV7P70_1 motorcycle +FEbVjS5-4ps_0 person +FEsMY2y49d0_0 person +FFuW_UWBVpU_0 train +FHRrYqTZExQ_0 person +FID77dKUAU8_0 cat +FITKtv4tf7w_0 cow +FIi2mEV5dfQ_0 skateboard +FIi2mEV5dfQ_1 skateboard +FIvujc5oqIY_0 train +FJDKoEDLbNc_0 airplane +FLsLXPchOx0_0 knife +FMV_-mdKV8U_0 horse +FNNrfAuIQmo_1 horse +FNpd4DJ9LBA_0 horse +FPrcQJh9INg_0 person +FQMXzPIoL14_2 bird +FQ-_p0lM-FM_1 elephant +FRxSISi7wV4_0 bicycle +FSFW4QxV8-0_1 truck +FUlVrltDAOk_0 bird +FWNxjmydNdU_0 person +FYVNE1zYmyA_0 person +FZrXRU5CxC8_0 boat +FaG9RreeG6M_6 bicycle +FaG9RreeG6M_2 bicycle +FbF-nKQx0WI_0 person +FcP50mFdaYM_0 train +FdPApnQkBVQ_0 bird +FdPApnQkBVQ_1 bird +FdlDAmvsrR0_0 horse +Fd1uYmMhzPE_0 horse +FedOlGadIYU_0 bird +Fgd7fHxPhBs_0 truck +FhQLl40AANQ_0 bicycle +FhvdS8wJkrI_5 bicycle +FhvdS8wJkrI_1 bicycle +FhvdS8wJkrI_2 bicycle +FhvdS8wJkrI_3 bicycle +FiCIZpT08B0_0 cow +FiD6UZuDr1M_0 person +FjFwrTEJK1U_0 person +FjmcQfLBpvQ_0 person +FkSfwpb1Gss_0 person +Fkhru_XyPSU_4 bicycle +Fkhru_XyPSU_1 bicycle +FlOaA91Qa2M_0 cow +Fm7Z44jVp_A_1 person +Fm7Z44jVp_A_0 person +FnIpAhpGTps_0 person +Fn0IWwSVPlk_0 person +Fotm2Ewrdr8_0 dog +Fphk_JpP4JY_2 bus +Fp2WKSG1qGw_0 person +FrFv1rYtAws_0 train +Fr298zXE9O8_0 umbrella +FshCFVUSBXY_0 person +FsiLiUl9I10_1 dog +Fs0LVU4qKSs_0 skateboard +FtEi5TPqRiA_0 dog +FuWY9thbtxw_0 airplane +Fu9EsTmh8z0_0 person +FvCCkxW3sv8_0 person +FvDNYPmcXjQ_0 bear +FvDNYPmcXjQ_5 bear +FvDNYPmcXjQ_1 bear +FvDNYPmcXjQ_3 bear +FvHW0PyfZ_Q_1 skateboard +FvHW0PyfZ_Q_4 skateboard +FvHW0PyfZ_Q_5 skateboard +Fv542o8y6aE_0 person +FyEliJtlQIY_0 person +F0PPPvVTNnE_3 bear +F3iJ9TqS-lE_1 bear +F3iJ9TqS-lE_0 bear +F39H1yTLerI_1 train +F4xCJHUMGsE_1 elephant +F47hXNWC3K8_0 cat +F48wdm2YukQ_0 bicycle +F48wdm2YukQ_5 bicycle +F5Cc5wQJvhI_0 person +F5Tm5BM0oaM_0 train +F5unbOiULNM_0 motorcycle +F5unbOiULNM_1 motorcycle +F9B5cLZb3T4_4 bicycle +F-OWsiGzRg0_0 person +F_bZObIr47Y_0 bicycle +F_bZObIr47Y_1 bicycle +F_dg4Hi5ZU0_0 car +F_xLwEhMPdY_0 person +F_8rnxkAIgQ_0 person +F_88eTR1pKU_0 train +GAMoEnodBZ8_1 bicycle +GAZx8145Hkk_1 person +GAZx8145Hkk_0 person +GCW28zxN9vk_0 person +GDM2ctXPkmg_0 person +GD5lsE86vOA_0 car +GE2nS7Zbkrc_0 airplane +GE6JO6nrE2A_0 person +GF9unI6hEMI_0 airplane +GGULYyv3_eY_0 elephant +GGULYyv3_eY_1 elephant +GGVYYc0KNWc_0 truck +GHTZcjImEqk_0 person +GIJMEjX04dI_0 person +GIM6FHDMp0A_0 person +GJTjlO1FJpo_3 bear +GJTjlO1FJpo_5 bear +GKyxtLTjXUU_1 motorcycle +GLG6II1JYko_0 bird +GLpNrOwqNXc_0 person +GLvmwdOjsHE_0 cow +GOEqT5_bhls_1 elephant +GOVFUFYsINQ_2 elephant +GOfP3fxCTvw_0 person +GPPKPFCI-Kc_0 person +GPSXltbv0f4_0 motorcycle +GP5anr-xMfw_0 person +GRluMAZzu8c_0 airplane +GSlWcX28sLk_0 person +GUMAgiab8bg_0 person +GUQmoD1aWhw_0 truck +GUS7BLoHHPk_0 airplane +GVNmuLeQ6pA_1 airplane +GVNmuLeQ6pA_2 airplane +GWBEjzdOLjI_0 giraffe +GWBEjzdOLjI_1 giraffe +GWBEjzdOLjI_4 giraffe +GXMBH6OujvQ_0 person +GYM460lVV-k_0 horse +GYQO-VevHpI_0 person +GYYxgR_VGFQ_0 dog +GZSlxtl9bj4_0 horse +GZSnngz0VX4_4 dog +GZhWdIsibfs_2 bear +GaierMnR4Xk_1 elephant +Gbe74-OWIo4_0 person +GbwJhzDrFtI_0 airplane +GceLsS4AwH8_1 horse +GcjSF4Uyl74_0 person +GdoD65Qn6kE_0 cat +GeOos0BFCSY_0 bus +Gf_4plKc8tw_7 horse +Gk8oy0G3dRU_0 person +GlAH7-Rf8gc_1 truck +Gm9yMiay9Is_2 skateboard +Gm9yMiay9Is_3 skateboard +GnTFmN4UNrI_0 motorcycle +Gn6ltyIKgcs_0 person +GoXxeDaopwo_1 person +Gokzf7T4oVU_0 cat +GpE5cmO_2kQ_0 skateboard +GpE5cmO_2kQ_1 skateboard +Gq7NQWGviWU_0 train +GsLJXtf6RC0_0 person +GuMiw_OwxlM_0 knife +GubE6GTKTVc_0 person +GubjV1tFrVA_1 umbrella +GvRQ4QZHPGc_8 bicycle +Gvjv4DJftts_1 cat +Gv5P6ORl-1M_0 person +GwAGS0xPZDQ_0 person +GwY5WqLjTcM_1 cow +GwY5WqLjTcM_0 cow +G0C4XEsjKGU_1 bird +G0i_9qeBwm8_0 airplane +G0sAxRZi6m4_0 car +G1doEZFbv70_0 airplane +G1gPj-UK_gw_0 cow +G107tKapVcQ_0 giraffe +G16fmAfdp9A_1 zebra +G16fmAfdp9A_2 zebra +G2gyuboBt-E_0 elephant +G2gyuboBt-E_1 elephant +G3jqix8WiYE_0 person +G5jg_wMMXmU_0 person +G6iN1OKj_eE_0 elephant +d0G8DzwenzU_0 person +d2ugQO5Z8M8_0 airplane +d3_3kfZ7rkc_0 boat +d3_3kfZ7rkc_2 boat +d4cTjVsUbIA_0 person +d44bp_UDYOQ_0 cow +d6vOtyrW2eQ_0 motorcycle +d6vOtyrW2eQ_1 motorcycle +d6vTXY--7zw_6 truck +d6xRfIz84Og_1 cat +d8GWgCsv0fo_0 person +d8kSiPkTvek_1 bus +d9IW6kCjfmA_0 knife +d9IW6kCjfmA_1 knife +d9YRdtwcTOo_0 motorcycle +d-CkujEJl24_0 zebra +d-6-T4gkBTk_1 cow +d_eu3LZxECY_0 motorcycle +d_eu3LZxECY_1 motorcycle +eBIZSQg7pV8_0 airplane +eBSijengaq4_0 person +eBVE2h6i3Do_0 person +eByIZzEh-DA_1 dog +eByIZzEh-DA_2 dog +eCzDpCe6xvc_0 horse +eDUR6UTxYhk_0 person +eFXZRDC38No_0 bird +eGVUtZXFcmY_1 cat +eJn0yGDjytc_0 cat +eKcJ2alScW8_0 cow +eL4uMBEG4gE_0 bus +eMsvM8G2Z0s_0 truck +eM0KTbh6EZE_0 person +eN0JRkzxVPw_0 elephant +eOeuY4ZbTt8_0 bird +ePiG-qPeJ6c_1 elephant +ePiG-qPeJ6c_3 elephant +eQEBmp37ZMQ_0 person +eQ6zyKVuU2s_0 person +eROdacH1GEk_1 horse +eRsf1_omRf4_2 elephant +eRsf1_omRf4_5 elephant +eRsf1_omRf4_6 elephant +eRsf1_omRf4_9 elephant +eRsf1_omRf4_12 elephant +eRsf1_omRf4_13 elephant +eRsf1_omRf4_14 elephant +eRsf1_omRf4_15 elephant +eTfXd1DQ6mc_0 dog +eU_B2dXyBkI_0 elephant +eVAEQdogSqk_1 person +eVLFX7RZOJM_0 person +eVnnuxmvpM8_0 person +eVnnuxmvpM8_1 person +eVnnuxmvpM8_2 person +eWU6Kk9K6lI_0 airplane +eWZHute7e6Q_0 person +eXAJwsjltWs_1 airplane +eXAJwsjltWs_7 airplane +eXvofXrEuU8_0 person +eZFqrD8MAKk_0 horse +eZFqrD8MAKk_1 horse +eZc2BPYt4rU_0 person +eZ9Qy0zfLb8_1 dog +eaoH4_TdTt8_0 person +ea2xP5nm53M_2 knife +ea_yr_40TRY_0 airplane +ebc-oEY_eDM_0 cow +ecksf6PLvhw_1 dog +edx1TW6jRFg_0 person +ee6Zcz8Pyfk_1 cow +ee6Zcz8Pyfk_2 cow +efczZtAK28w_1 dog +egbQbEuLDlE_0 cat +egfoTu4gtZo_0 bicycle +egg1WCEyuTw_0 person +egmCEe7OgiE_0 person +ehxHGWKtaAg_0 person +eh9YpbAcMZE_0 person +ejRwmx3kUI8_0 person +ej0xIcEXWiU_0 horse +ekfKlK5w3Lg_0 person +ekwoV0dpRwI_0 person +ekwoV0dpRwI_1 person +ek7bnCHGZq0_0 skateboard +elB6RfDJA6M_1 dog +eljiGrMEYiQ_0 person +eljiGrMEYiQ_1 person +emISA6YzHZ4_0 bus +emISA6YzHZ4_2 bus +eoIk6xjgQ-4_3 bicycle +eomNxgG_ivE_1 umbrella +eomNxgG_ivE_2 umbrella +eomNxgG_ivE_3 umbrella +er7oQRfciJ8_1 person +euESct6MMNg_0 person +euU-dtl6yyA_0 person +evyGgkwoEpU_1 horse +ex_t3nR28rg_0 bird +ex_t3nR28rg_1 bird +ex_t3nR28rg_2 bird +ezrZuVfbOPs_0 person +ezyFfdIkCCQ_0 cow +ez5RcUDpMoI_0 bear +ez5RcUDpMoI_4 bear +e0cc8KmRgDE_0 person +e0cc8KmRgDE_1 person +e1VJlGQGYTA_0 umbrella +e37RxtyP9nk_2 person +e37RxtyP9nk_1 person +e5Q4wIVJR40_0 person +e5a3Z_wlpUU_0 person +e6FwS_DOE-U_1 horse +e6FwS_DOE-U_0 horse +e6xVrcpMa9Y_0 cat +e8Bc9zwTFnE_0 person +e9G1bOd8GlA_0 car +e9QeTOo4XBE_0 person +fBYtizIh0wc_0 cow +fCVsRanBID8_0 person +fDWKYttA3fM_1 umbrella +fEA-xCaKqfI_0 train +fEWxV64teMY_0 dog +fEpH1AFdSqs_0 person +fFGF5gVW6UU_2 bicycle +fFGF5gVW6UU_0 bicycle +fFGF5gVW6UU_1 bicycle +fFIVNddMFuc_0 person +fFT1LpdsEhQ_1 cow +fFmghP5NQVA_1 horse +fFw23dFiBDs_0 person +fGJKT5ttUQw_0 person +fHFCYOUh3vU_0 truck +fJJuwfeoaWI_0 cat +fJnC2nKYQVQ_0 motorcycle +fMl60_fkMfc_0 knife +fMu0OmctSTI_1 airplane +fNTptXtpsoo_0 cow +fOyaDea7Al4_0 person +fPA_KgXi5v8_0 bird +fPA_KgXi5v8_2 bird +fP7EpJzJt0A_0 horse +fQRAi5pN1Fg_0 bicycle +fQRAi5pN1Fg_1 bicycle +fRB4jD1Uecw_0 person +fRSu9-lyuaU_0 truck +fRoEX_9tHtM_0 person +fSB_aY8HhJI_0 person +fSFjxB1XU2E_0 person +fTd-8VbsXus_1 airplane +fUNAhHKf_OA_0 cow +fUva5AKNiPE_0 person +fUva5AKNiPE_1 person +fU8NxbaMKu0_0 bus +fWD8TEXWtek_0 bear +fYBeigFqN7Q_0 train +fYBeigFqN7Q_1 train +fYWFh5BSEyg_1 cow +fYup3iPmtHc_0 person +fbAOGfYPur0_0 person +fcFwbcMNdUo_0 bird +fcFwbcMNdUo_1 bird +fdMa18fwj14_0 person +fdQFJz9IOso_0 umbrella +fd73v3-Qjqk_0 knife +feMxoQY38A8_0 person +feMxoQY38A8_1 person +feNEI7bD5HI_0 bus +feO8Ip4MOn4_0 cat +ffQKiGKTDaA_0 bird +ffr6_q8liAc_0 person +ffr6_q8liAc_1 horse +fhVVVY5XhDI_1 knife +fhWE0XDoxjM_0 airplane +fh9tibERtYI_0 person +fiKs6mdtsmM_0 cow +fiVKh-Q-iY0_0 motorcycle +fkGWb9_HVsA_0 elephant +fk85Ace_-LM_0 dog +fmE9seWSDfs_0 umbrella +fmosIu7__Wc_1 person +fmrqs2YvNCQ_0 person +fm4syrPib5M_0 person +fnKNDlQq-JY_0 person +foWPkPNDqyU_0 bird +foWPkPNDqyU_1 bird +fojim3ViD7Y_0 person +fpI0N9Lv5V8_0 horse +fpv4fALQXpQ_0 person +fqWa-DUPAGw_0 person +G8IUU0gjlEI_3 boat +G88QbXTQ6LI_0 skateboard +G9Sdd3czaTk_0 dog +G-kF2D98oms_1 elephant +G-2yXvawYec_0 person +G-5iXA4ERtM_0 train +G__uy4I0Kzw_0 person +HAOmPeNNjNc_0 bus +HBUeO1WOFFk_0 motorcycle +HBbWtsju37w_0 boat +HBw-J_3WlCY_0 cat +HF8ZrMgnyo8_0 dog +HJYmTdBHVvU_1 elephant +HJYmTdBHVvU_2 elephant +HJ08tJU-IIA_0 dog +HKNkm0t39B4_0 cow +HKRKZksEGro_0 person +HMfFCe-og9A_1 bus +HMt7kgP0MC0_0 person +HM8XKdebDvI_0 boat +HNBF7AppAQQ_0 dog +HNheLARZ64w_0 bicycle +HNheLARZ64w_2 bicycle +HN-3LaZVuCs_0 car +HONOO3gmDec_1 person +HP6UlpPulc8_0 bicycle +HQ3nHqG24O0_1 cow +HRF40e3Tbvw_0 bicycle +HRF40e3Tbvw_2 bicycle +HRRhkyr7U5E_2 train +HRcVM9md3Xg_0 cow +HTrUPWOXlvI_1 person +HTrUPWOXlvI_0 person +HULLjmpSRUI_0 cow +HUssZ9c2Qvs_0 truck +HW8Z7IdfuIg_0 person +HYCFQjnuXBI_0 truck +HY4XBjJWJYg_0 truck +HY9NQ2zNtGc_0 cat +HZVvEd_Tg_g_0 person +HZngEEoQWDA_0 person +HaMmo5SdpUo_0 person +HaVnQ_P5HdQ_0 train +HacYwonTy6w_1 skateboard +HbWinZWeK2U_1 dog +HbhmAMorGaw_0 person +HeOWa0NNB0g_0 person +Hg0fRYqZQ3U_0 person +Hi384VDSwXw_1 bird +Hjo95Vo38qU_0 person +Hksncw-BlKU_0 giraffe +HlWb7xQHFKI_0 dog +HmH4hitBoc4_0 person +HoSTe-9VUJA_0 cow +HpdyNV4GqbM_0 person +HpdyNV4GqbM_1 person +HsGPGwN7vSk_0 person +Hugie4Q6leo_0 bicycle +HvKC4fLwUYw_1 person +HvKC4fLwUYw_0 person +HvOisoEmjKg_1 airplane +HvU4Jz4Gd1k_0 cow +Hv_d6KPoSgA_0 skateboard +HwZUDp7yxxk_0 person +HxPskaUPSXg_0 cow +HyHQRrpWhpk_0 boat +HylH7-rD0wA_0 bird +HzEm2GlGzhc_1 truck +HzTD_opfrqI_0 car +H0QTCKxJmLY_1 train +H1Oxjm0NqCg_0 person +H2GwgpAKbzY_0 dog +H3HrWs1HITE_0 cow +H3S_DkPBWtw_0 elephant +H3S_DkPBWtw_7 elephant +H3S_DkPBWtw_1 elephant +H3S_DkPBWtw_2 elephant +H3S_DkPBWtw_3 elephant +H3S_DkPBWtw_4 elephant +H3S_DkPBWtw_5 elephant +H3S_DkPBWtw_6 elephant +H3XF5rAtuJA_2 person +H3XF5rAtuJA_0 person +H3a-C6RRYyo_0 person +H5mmSHRHeOA_0 person +H6TuJxifX64_0 train +H6w4nf5H4U4_0 bird +H6y9C6Ndy2A_0 bird +H6y9C6Ndy2A_1 bird +H7XZ5716KnI_0 person +H7z05uOIPRM_1 train +H92s5sHsotk_0 airplane +H-4EZAh3ZiE_0 bus +IA1FFP5WN-4_0 bear +IA1FFP5WN-4_2 bear +ICj693xC5DY_2 airplane +ICj693xC5DY_0 airplane +ICj693xC5DY_1 airplane +ICxHfkE0XCo_0 person +IDx8_34ETTQ_0 person +IEyymbAxp24_0 dog +IFS0QSfnbaM_4 knife +IFS3ILjlHkY_2 truck +IF_auR-0fxM_0 knife +IGv9j-RQi0k_0 dog +IG0UmL5bvEo_0 cat +IHFF7DOpF4Q_0 motorcycle +IHmYV5ymU08_0 cow +IKEUMXjIyTQ_0 car +ILZvGBKYYrE_4 bus +ILZvGBKYYrE_0 bus +ILZvGBKYYrE_1 bus +ILZvGBKYYrE_3 bus +IMTbwAOJNIc_1 train +IMh4AHUZ2HQ_0 person +IM4EBlgTTOg_0 bus +INlrdk7hgl4_0 knife +IOQt3fFTSVc_0 horse +IO7-lFsWvl0_0 bicycle +IO7-lFsWvl0_2 bicycle +IPEJs-vLCV4_0 truck +IPEJs-vLCV4_1 truck +IRpgjSP4pLI_0 person +IUJGm3Iu0Bs_1 bicycle +IUgsoj74aWQ_0 person +IVlnjlVA5rc_1 bicycle +IXP1ML1tdZQ_0 bus +IXRxjnkOJeo_1 motorcycle +IXenlPUsqrc_0 person +IZvOv7tCr00_1 train +IcRjjKSX5uc_1 person +IcRjjKSX5uc_0 person +Icnle27cmMM_0 bicycle +IdVZJW1HC9E_0 airplane +IdVkEz2IF7w_0 car +Ieb9oZ9eB8I_0 dog +IfWSlkR8DbU_0 horse +If1zPOV0idg_0 horse +If1zPOV0idg_1 horse +Ih2gG0269H8_0 bus +IjQXXK4uYVY_0 dog +IlMHPX2VcGw_0 elephant +IluTkrIqsVg_1 elephant +IluTkrIqsVg_3 elephant +IluTkrIqsVg_6 elephant +Io7bj1jNpPU_0 car +IpjQJZ42zyQ_0 elephant +IpjQJZ42zyQ_1 elephant +IpjQJZ42zyQ_2 elephant +IpjQJZ42zyQ_3 elephant +IpwI5VTWHLc_0 horse +IpwI5VTWHLc_2 horse +Iqy4PPX-Tlc_0 person +IsHTpd2cnvI_0 train +Ithz7KSWCxU_0 bus +IudK7ch_IIg_1 airplane +IvRDw_IA0_s_0 cow +Iwve-3lTmMk_0 person +IyLshk4jlyo_0 cat +IygCvE4_amo_2 bird +IygCvE4_amo_3 bird +IyjFl1Hhk3Q_0 person +Iz4XK2zNDUU_0 person +I1wuUCQbXLc_0 umbrella +I2DkTg8wPnI_0 person +I2WoCDTXONA_0 person +I2WoCDTXONA_1 person +I2lh579NY2s_0 bird +I45pfwCBczo_0 person +I6ESaCg4z_8_0 person +I6TvXxQTtZQ_1 horse +I6TvXxQTtZQ_0 horse +I6TvXxQTtZQ_2 horse +I8OfOokt6YU_0 person +I8XhyDacLtU_1 bird +I8m0QjcQlSo_3 bicycle +I8m0QjcQlSo_4 bicycle +I9ivT_P5G18_0 person +I_k5qXHxb0Y_2 knife +I_k5qXHxb0Y_0 knife +JBkwLPruJe0_0 person +JBlDwXJFbQc_1 umbrella +JDZiLsus2es_1 skateboard +JDvfPX9cFDg_0 dog +JEpTSJRO3co_0 person +JG2tVzjxhao_0 bird +fsAEg5w8xTg_0 person +fsCwAYYI4js_0 person +fsKTO8ksQ90_0 person +ftMQOwvHDF8_1 car +ftns38_MSTM_0 cow +fvxc7ruCiYk_0 cow +fvxc7ruCiYk_3 cow +fv8aFklHmko_0 skateboard +fwEvL-luHlw_0 airplane +fwEvL-luHlw_1 airplane +fwt8LzF8Mic_0 person +fyZImQFj_Y8_0 cow +fycK7kJWV1I_0 umbrella +fzr3kw3BDDo_1 airplane +fz6ONSUlvNY_0 person +f0i5E4DOFc8_0 bus +f2SctRCBZQc_0 car +f3Z5d9I7rIw_0 knife +f4fxmsxPzrg_2 elephant +f5LEkr56Efg_0 person +f5Uz-TuMQ0Y_0 horse +f5ZpGBYuJ7o_0 boat +f5kAHBPObsw_1 cow +f6fZjMRJgoM_0 horse +f63aow5BRAI_5 bus +f65rTlprptk_0 horse +f7yNS6ltUFk_0 person +f8H7Ns8cw-c_1 train +f8rXEKktSCg_0 elephant +f_VqZJyJ4GM_0 motorcycle +gAHcWn06srk_0 person +gB0-eGpMj50_0 person +gB2asNpe3zY_0 person +gB7jSQgkcMM_1 horse +gCDC8R7IB7k_0 person +gCwe-o1nqBc_0 motorcycle +gCwe-o1nqBc_1 motorcycle +gC9z8IzG83s_2 bicycle +gDEk1TWuZug_2 person +gDG5Xr2p2y8_0 elephant +gDHnBnqogX0_1 airplane +gDHnBnqogX0_0 airplane +gDbZj1O36VU_0 airplane +gDihz5aZLyA_0 bus +gDihz5aZLyA_2 bus +gEkiX2yFQm0_0 cat +gEnLlmMhxfE_0 person +gGNmKI2M8i4_0 person +gGd6hYCKdEs_0 bird +gHMCfvdZzMM_1 person +gHYzGPx8f_4_0 zebra +gHYzGPx8f_4_1 zebra +gIx12Q8A3p8_1 person +gJwtAwSqEow_0 train +gKAPbj9esXI_0 skateboard +gLqb3YuVttM_0 umbrella +gMRigFNGMeY_0 person +gNfQargrILo_1 car +gOFgWsujZaI_0 cat +gOWc7VBEwMo_0 car +gPEMf91dil8_1 horse +gPSB23kv5Uc_0 person +gPhL52Mj1_A_1 motorcycle +gQ1qmNZzaTo_0 boat +gRDFlfzM_iI_4 elephant +gRDFlfzM_iI_6 elephant +gRDFlfzM_iI_1 elephant +gRDFlfzM_iI_3 elephant +gRMJhsEuiAc_0 motorcycle +gRMJhsEuiAc_1 motorcycle +gRMJhsEuiAc_6 motorcycle +gR29_U82QeE_1 horse +gSJbrV0vy8M_0 person +gSz16yrF9yA_0 person +gT0yjYUmf90_0 cow +gUGlSiBvfOs_1 motorcycle +gU8s5nxyBDk_0 airplane +gU8s5nxyBDk_1 airplane +gV3CcNeVZcY_0 elephant +gV3CcNeVZcY_1 elephant +gWkTSRUqxoo_0 person +gW6HdCsty0U_0 knife +gYLohMps12s_0 elephant +gYLohMps12s_3 elephant +gYLohMps12s_4 elephant +gYLohMps12s_1 elephant +gYLohMps12s_2 elephant +gaKGYmLxJVU_3 bicycle +gagJEV--3Pw_0 person +gdAVi92ZfSc_0 horse +gdx96NpU6BY_6 train +gd4UfPes3YI_0 cow +geEXytMwfq0_0 person +gePAI8wYSdw_0 person +gfTVuceAzNs_0 elephant +gg8YzsSulrQ_0 truck +ghciPMerSc0_0 truck +giWDg00GIDw_1 skateboard +gig9B4ecK3w_0 person +giy_SOmkBY8_0 umbrella +gjnyg97XwnA_0 person +gk-cycr3xjo_0 person +gmVDmxVI7n0_0 elephant +gpV4Qlx6YrA_6 bus +gqLSqmK3m74_0 motorcycle +gqZYY0m_TuM_0 motorcycle +gsrvWcnpNP4_1 motorcycle +gsrvWcnpNP4_0 motorcycle +gtVr7urU8c8_0 person +guDQk0hVgU0_0 bird +guFTeFvjr9Y_0 bird +gu3DTnVjNQM_0 knife +gwXwH2Cs3BY_0 knife +gxHGnBrpPZs_1 airplane +gxHGnBrpPZs_2 airplane +gxKuLTUNhp4_0 horse +gx7PFNpHd_A_0 person +gyaP7qiRxfY_0 cow +g1OZWFLSspQ_0 motorcycle +g1rQZNA6yyo_6 cow +g1rQZNA6yyo_0 cow +g1rQZNA6yyo_1 cow +g1rQZNA6yyo_2 cow +g1rQZNA6yyo_3 cow +g1rQZNA6yyo_4 cow +g1rQZNA6yyo_5 cow +g3HXJNMlAsM_0 airplane +g3oqxu4AhBw_0 person +g3swsx-acTI_1 dog +g3swsx-acTI_0 dog +g3vbaqnLXn8_0 cow +g4bayrAEhIU_0 umbrella +g5rUJOptHXQ_0 horse +g5ty_7So5Dw_0 cow +g51pzrSssl4_0 person +g8M5d--ghFM_0 person +g8vKB3IU1JY_0 horse +g8wHQVpij-I_0 person +g9eN0FHn4-E_0 dog +g-EAZ6gVcic_0 motorcycle +g-pVcRyPQG8_0 cow +g-yHAyCA2KI_1 horse +g_C47ek7TmI_1 knife +g_C47ek7TmI_4 knife +g_C47ek7TmI_5 knife +g_QHWoQgmFQ_0 person +g_QHWoQgmFQ_1 person +g_Tk-SESaYI_0 person +hBHt6mnfUeo_0 bus +hBMZHx3_cTs_0 train +hC69bGTvLBo_0 skateboard +hD3Bn03GXNQ_1 dog +hFNAxcRpGBM_0 skateboard +hFSygfNIY_Y_0 skateboard +hFex_TS-aUo_0 person +hGnscWmehTI_0 car +hG9efPyerw4_1 horse +hHdBCtElIQg_0 boat +hHlqyr11RiI_0 person +hIWM6v4zcSM_0 elephant +hKoGkl1wyCU_0 person +hON0t9Dzay4_0 motorcycle +hP1ViN_WadY_0 cow +hR-utsUhYSg_0 person +hSAUbt6-Yjc_0 knife +hSAUbt6-Yjc_1 knife +hSeHymINF98_1 bus +hTaEY4YCVqM_0 airplane +hUjzfhyM30Q_0 airplane +hUjzfhyM30Q_4 airplane +hUxguQsLvcs_4 knife +hUxguQsLvcs_5 knife +hUyAVmRxAzM_0 person +hU_dAA1A0X0_0 person +hU_9cs_qw1w_0 person +hVjyHhYH6Ss_1 airplane +hVjyHhYH6Ss_2 airplane +hVowH5-Ss4I_0 train +hV4tEsm-F5s_0 airplane +hZdxBk4cjmg_0 bus +haiW7jpl3wY_0 person +hcJBaxNIvE4_1 person +hcJBaxNIvE4_0 person +hcV4RZPeRbo_0 airplane +hcuLD1cn9GA_0 person +hdUc4uUYh0E_0 boat +hfWfYFG2O94_0 person +hgagtwzScGQ_0 person +hhFOwnYOLl0_0 giraffe +hhLyE41H8nE_0 motorcycle +hhNlg3Ws9Dc_0 person +hhyVc2wsXVk_0 horse +hhyVc2wsXVk_1 horse +hh432zDMgPo_0 train +hiKbm0rqEb4_3 skateboard +hiN_kULL84o_5 umbrella +hiN_kULL84o_4 umbrella +hkEV_E85Jzw_0 car +hkSv_YxmN7w_0 person +hlZDJrpJzPU_0 person +hljwk2WbXGY_0 person +hmSeUlyLLak_0 train +hnZvUHrA3CY_0 person +ho6sg-47RD0_0 airplane +hqNhKf3a69Q_2 truck +hqYyvTeOvas_0 bear +hqaNlwG0DNU_1 person +hqrmbVw_EwQ_0 cat +JIuyqZCU5zY_0 cow +JKiG_pk4lSE_0 person +JKmvEldBeEQ_0 cow +JKsodtdUW-o_0 boat +JMLFZcONQAs_2 skateboard +JMLFZcONQAs_5 skateboard +JMMci7hryUQ_0 motorcycle +JMMci7hryUQ_1 motorcycle +JMMci7hryUQ_2 motorcycle +JNUhCGqPlFg_0 bicycle +JPHPd13gaL8_0 car +JQrDalAaP4w_0 person +JQrDalAaP4w_1 person +JQz6IarIr4E_1 person +JRAVv2LgiGo_0 skateboard +JRUvqZtBMrM_1 knife +JR0QfXOOmaA_0 person +JSml3dguiUk_0 motorcycle +JTFT_iJGFUE_0 person +JUdUxjC2LRE_0 bus +JWU6vdEt_OU_0 person +JWgjcmMh62o_0 train +JWgjcmMh62o_3 train +JW0-hEA4v9A_0 person +JXIh3fJ4Jv0_0 person +JX8ODdMUi7g_0 bird +JZC15tOV-eg_0 horse +JZMOzYwcTA0_0 person +JasH0KtinHY_0 airplane +JasH0KtinHY_3 airplane +Ja5jdE_8qio_0 person +JbyTZ-esDXM_0 truck +JbyTZ-esDXM_1 truck +Jb93SMKg5-k_0 person +JcVOyLTTvKA_0 person +Jc18AfXzLZU_0 person +Jc18AfXzLZU_1 person +Jd7uOTcPvY8_1 car +JeWRfjjRMQk_0 person +JerVzlWZwac_0 bus +Je-lnjK_8fk_0 person +JfjkltN0lZc_2 horse +JfobA6aKaas_0 dog +JftQEHHdO5w_0 truck +JgaE8KDwg7k_1 bird +JgaE8KDwg7k_2 bird +Jgc2PQ8Swbo_0 cow +Jgkj9pj3-tc_1 horse +JhdyYrqxn_g_0 motorcycle +Jh7o2iR-lRg_0 person +JijsSnHthXE_0 train +Jio_xBodQxY_0 person +JjQ8bdq_eXk_0 person +JjtkwX4npyw_0 person +JlG7Wzz4uU8_0 car +JlG7Wzz4uU8_2 car +JmkUuTj-Nks_0 umbrella +JmtuhGXlqmY_1 airplane +JnNJksYeB18_0 car +JoKod4XDE6o_3 bird +JoKod4XDE6o_0 bird +JoKod4XDE6o_2 bird +Jp6_g7oF2lQ_0 cow +JqEprl56N4I_0 skateboard +JrIoaRmcs6o_0 cow +JrNq6Z5YSoc_0 person +JrUHo8zVwpo_0 bus +Jsjz8hiE_iU_0 person +Jt7Ojtx0TMs_1 car +Jt7Ojtx0TMs_3 car +JwBYrXUHdZ8_1 horse +JxTKws5Dx_8_0 cat +JxjXZYfiem4_0 dog +Jx9mLWFxpnc_0 dog +JyYBZBogBvs_1 boat +JyduNnkZOiY_0 person +JyrP5u2MuSo_0 motorcycle +Jzcc0pjgA5c_0 person +JzjRC1xYwy8_0 dog +J02u46SlewE_0 person +J1GtEDNcsHQ_1 horse +J2JOoOxaJdw_0 person +J2bB5BgR-5Q_0 bus +J2hdK_vuyyw_0 motorcycle +J2ycUTr0lJQ_0 cat +J4T_QA6J7kw_0 boat +J4T_QA6J7kw_1 boat +J4T_QA6J7kw_2 boat +J40neYxbEYA_0 skateboard +J5-Z9tNISPw_0 car +J6klPNMhLKc_0 cow +J7I-QXddTIk_0 person +J7hnNI0jtws_0 person +J8ITxacusCI_1 person +J8ITxacusCI_0 person +J9-8Qe3BWoI_0 bicycle +KARqX_agLpU_0 knife +KAgU6SrQTlQ_0 umbrella +KAgU6SrQTlQ_1 umbrella +KArVkjxSGpM_0 person +KBCIbwknDew_1 bicycle +KCeuwWEv3ZU_0 person +KCi4f4Hp6oA_0 airplane +KC5ECqMiTLU_0 skateboard +KD84e88aqHU_0 person +KD84e88aqHU_1 person +KEpHRYH8r28_0 giraffe +KGdIJzBVugY_0 truck +KHqFOBeHCwU_0 boat +KIOilXstQLY_0 person +KIOilXstQLY_1 person +KJ2kEj3C5HU_0 airplane +KKWUDcCI6yU_0 cat +KML2msVr5mE_2 elephant +KMNAnjpGqv4_2 truck +KNIVWRv3awA_0 truck +KOmUta2sIgk_0 person +KOsm1GUs46s_0 motorcycle +KOza4PGcE0M_1 bear +KPLDdfk8hIg_0 train +KPLDdfk8hIg_1 train +KP7RzxyTTAU_1 airplane +KRKxqkfpetI_0 person +KRNWPLnvZz4_0 person +KR7Ah1hw5gA_0 person +KS8S3STq2W4_0 bird +KS8S3STq2W4_1 bird +KTkhMglNlCE_0 person +KTpwnsz498Q_4 horse +KTpwnsz498Q_6 horse +KWYD2iyUmgk_0 horse +KXIJLUzQi5Q_0 person +KXMlBQiVeEg_0 train +KXPGShfFlU8_0 person +KX9MjIikBU8_3 bicycle +KYc-vKtN0DI_0 person +KY4mXNDM8I0_6 elephant +KZdOpoUJ3Nk_0 person +Kcg7gY3WD7M_0 person +Kcg7gY3WD7M_1 person +KeJWqAV0EgA_4 umbrella +KeJWqAV0EgA_6 umbrella +KedkADy9tBc_2 knife +KedkADy9tBc_4 knife +KgDguip9mZM_1 horse +KgDguip9mZM_2 horse +Kg0XH4mez1A_0 cow +Kho8jpdZzTs_0 skateboard +Kjd7D98QULc_0 airplane +KkdLE8EkzQ8_0 cat +Kkw7ZPCEz5w_0 person +Kk-2ajLfeh8_0 cat +Kk_LtYOgQXA_0 boat +KmLYFD7xykY_1 car +Kmwqg1uRPRE_0 person +KnQuff1ffzM_0 skateboard +KoRqIzHBQks_0 train +Koq5YYiN1tc_0 train +KpHpGcL_jEc_4 bird +KpHpGcL_jEc_3 bird +KpfTioA2qKw_4 elephant +KpfTioA2qKw_5 elephant +KpfTioA2qKw_0 elephant +KpfTioA2qKw_1 elephant +KpfTioA2qKw_2 elephant +KpfTioA2qKw_3 elephant +KppX5i4QRZ0_0 umbrella +KqsBJAhU_Dc_0 cat +KrRVwTPG26w_3 dog +KsE43Lli_3U_2 horse +KsE43Lli_3U_3 horse +KskL-dN784o_0 airplane +KtfQRtfJQ8s_2 skateboard +KxDh7a8_AmU_0 person +Ky4ahEexJUc_0 airplane +KzDLvBPcQew_2 knife +KzMFSHS4xVs_0 bird +KzOxVUsduDY_3 knife +Kzt2eSUr1rY_0 dog +K0IvSLIQbgQ_0 bird +K0SktTNMXQU_0 motorcycle +K2WsSTHs45g_1 elephant +K2WsSTHs45g_3 elephant +K2oIvJd-d-A_0 person +K4IN8pNA--U_1 person +K5C2Y3JvXCU_0 skateboard +K7TOmJ6RB_8_0 skateboard +K89ScUqJx5E_0 person +K8_u8_NkoAk_1 train +K9L-BYQcepo_0 bear +K9pgB6KH-EY_0 cow +K-laAofNBgs_0 horse +K-xigT3f2VA_0 horse +K-0pug6xNEI_3 train +huFyV9NBOBY_0 person +hua1XfGRDoc_0 horse +hulGMGXPaBE_1 elephant +hvXgMKsetW8_0 elephant +hxBjbg6s174_0 person +hyNwXcKelY0_1 train +hyNwXcKelY0_0 train +hzUpr73wZz0_0 airplane +h0jkFTI3qmI_1 horse +h1Hv9HnMe70_0 car +h1zuISckIeI_0 bus +h10iwpJO4pQ_0 train +h2vHhQ7_MT4_0 skateboard +h3Fo82UBMRY_0 dog +h3IHNdoTXT0_0 person +h3PBWibdVUc_0 train +h3RgUc0oY-c_1 knife +h3RgUc0oY-c_2 knife +h3t75PNg778_0 person +h3uSlke3koc_0 motorcycle +h4qpt2FEbC0_1 elephant +h5JnAInpuSo_0 motorcycle +h5JnAInpuSo_1 motorcycle +h7_4qHh7Vas_1 truck +h8TnGCoSVeQ_0 airplane +h8fKxUGKz8k_0 motorcycle +h8fKxUGKz8k_1 motorcycle +h-pm7wD31Ss_3 train +h-pm7wD31Ss_0 train +h-pm7wD31Ss_1 train +h-pm7wD31Ss_2 train +h_VG9OpleKc_0 motorcycle +h_VG9OpleKc_1 motorcycle +iAZV9nCf3RE_0 motorcycle +iA7evYzMygE_2 knife +iDBpYSvahjE_0 person +iDHjOnhAKA8_1 skateboard +iE75sptNwbs_1 truck +iE75sptNwbs_2 truck +iFVwtlc6IYE_0 horse +iFdOAHM4xDg_0 person +iFwPDZE4778_0 skateboard +iG4PvtWoxG8_3 cow +iH6Vlg0k330_3 dog +iH6Vlg0k330_5 dog +iH6Vlg0k330_6 dog +iIWFuFa7Z4M_2 person +iIWFuFa7Z4M_0 person +iIWFuFa7Z4M_1 person +iIzXR3qRt48_0 person +iI08dGJAOMs_4 elephant +iI08dGJAOMs_3 elephant +iJcf4PhS_SQ_0 person +iKzpo0D7b_8_0 cat +iK-7fByPADo_0 person +iMdJ5Xlz0hU_0 knife +iMeNXU67sVg_1 skateboard +iNiiX6P-kqA_1 dog +iOxVi3Tq4ts_0 train +iPlXCYJ6F7w_0 skateboard +iQ-tckw9_uk_0 truck +iRzm-CyyW-E_0 person +iSNNmpWe3LA_0 person +iS7wej_vrvM_0 person +iVBDQ5wm-0w_4 airplane +iVTAxc633DE_0 person +iXrLhQgf8HM_0 elephant +iXrLhQgf8HM_1 elephant +iX4gVag7ShI_0 person +iYL_l0MxgMY_0 bird +iYlgi1z6nYI_0 truck +iavLgJ3_05c_3 horse +icVQnqL0xPI_2 boat +idkGZQeYvJ0_0 skateboard +igbftnGj4-o_0 bicycle +igg-y1toBvA_0 truck +ihkqhIpO_hw_0 person +ijbDg16cIC8_1 bus +ik4t0sIEmTI_0 person +iltKgr5JKI0_0 person +il5UMLzlQts_0 bus +imDfH3So8XU_0 car +imDfH3So8XU_1 car +im4bCIqpJns_1 bicycle +im4bCIqpJns_2 bicycle +im4bCIqpJns_0 bicycle +ip1Y5qjDYfQ_0 airplane +ip_oGEZ6zMw_1 person +irvGAW8bqAw_2 bus +isbtQ06yVM8_0 truck +itNqceL9dLM_0 cow +iuii5XHcAYA_1 dog +iulQVUJanzg_0 skateboard +ivGBks6evlo_2 dog +ivSQWqs_u1I_0 bear +ivpPLs-cqxA_0 car +iwHJDgGVuCA_0 airplane +iwHJDgGVuCA_1 airplane +iw7zrlRPMo4_2 horse +ixgGTHdobNI_0 person +iyDedQNhiYI_0 cat +iyaI71EqLsg_0 person +izHN9JUwtJ8_0 boat +izQ74nq9zh4_0 cow +i0QLe6YR7yo_0 person +i1OlP2Sq0a0_2 truck +i1xqjStfSsc_0 person +i2SgjtgmsE0_0 person +i5DfO7_n0q8_0 cow +i5GkqX44npg_0 car +i5JWZKdNOac_0 motorcycle +i5JWZKdNOac_1 motorcycle +i6mzD2HGWOA_0 airplane +i6sR2IY4-Ck_0 cow +i8JA178zd0s_0 cow +i8Z9-KSMCTA_0 bicycle +i8syjc7Erco_0 motorcycle +i-EijejS9Oc_0 person +i-eCNLw3hVU_0 bird +i_l48nIXjxw_0 horse +jBYa-gqwSeY_1 cow +jCiTA9oIryk_0 elephant +jCuDdMn9sYA_0 person +jDGrgBt83DU_7 car +jD33e45nuRw_0 bear +jD5K1zGLtvc_0 skateboard +jEE_ZlDJ4cc_0 cow +jEzxW8ylxK8_5 airplane +jEzxW8ylxK8_1 airplane +jEz3EToUAg8_0 person +jGCLsWhdTds_0 umbrella +jHhJLxyr960_0 bicycle +jIqTFAgBLpc_0 dog +jJkZrKOehcQ_0 person +jKD0oOyMl2g_0 person +jLO5kFd36OY_0 bird +jMLgjCQWQY0_0 person +jMmH8xfY1kw_0 cow +jMyxNu6YkEQ_4 boat +jN5jdXmBv2Y_0 bird +jN5jdXmBv2Y_1 bird +jN5jdXmBv2Y_2 bird +jN5jdXmBv2Y_4 bird +jN5jdXmBv2Y_6 bird +jPouarzO-e4_0 cat +jQPz-9OfXRM_0 zebra +jRQuCIsXz1c_0 airplane +jRUeQo3V1bk_0 person +jR366TYYsuo_0 person +jSkwPkAAiFM_0 person +jTNzSUl_zOQ_2 elephant +jUzhGHE_jgE_0 person +jVYzDs5YRM4_0 cat +jVoxxEKEOFo_0 motorcycle +jX_taNw8FFg_0 skateboard +jY4Dh-UAAaY_8 skateboard +jZBMDKFS5D0_0 person +jbp8mHJfHGI_0 person +jcYNP_FWkA0_0 person +jcne18p2r2c_0 cat +jdttJqwg_3o_0 motorcycle +jfSY_UCtq-w_0 motorcycle +jfTXT98Naic_0 cow +jgQiUggCu7A_0 cow +jjTgUBAd4D0_0 cow +jjq2PAHcLiA_1 person +jjq2PAHcLiA_0 person +jlBGbg_CJz0_5 train +jlBGbg_CJz0_6 train +jlOOUqYlNNY_0 motorcycle +jlgECDznb0g_0 bear +jl7oYVm0X34_0 bird +jnU2n55I_LU_0 dog +jouq30Wmqxg_0 motorcycle +jouq30Wmqxg_2 motorcycle +jo6o9BwKsUQ_1 elephant +jqPPsrUULY8_0 horse +jtWUSSp-JiY_0 truck +juS7DvjMPoo_0 person +LCzQs5ybibU_0 horse +LDwE_VIc9Zc_0 cow +LEL3OcoqV8k_1 knife +LEPsxGhXYxY_2 truck +LEPsxGhXYxY_3 truck +LEXpJRLTRak_1 bear +LFWlRG2B-w0_0 bus +LFWlRG2B-w0_2 bus +LFWlRG2B-w0_3 bus +LGvjU4PVcC0_0 boat +LGvjU4PVcC0_1 boat +LGvjU4PVcC0_2 boat +LIC3D63R3HU_0 person +LIhhU9j6MI4_1 cow +LLD46pbwbiU_0 person +LLiy-k-4-OM_0 train +LLvpoIlozKU_0 horse +LLvpoIlozKU_1 horse +LO0IsJZeXhU_0 elephant +LO0IsJZeXhU_1 elephant +LPzXMvYB97A_0 person +LTh-XAE8m3M_2 train +LURSawdSS9k_0 dog +LUsb9vk1q6U_0 knife +LU539OYJ_z8_0 person +LXHO99b-uAQ_0 horse +LXHO99b-uAQ_5 horse +LX0HL9qztic_1 umbrella +LYPeAbFVTQw_0 person +LZCq31MG3yY_0 person +LZEMKs6H53w_0 person +LZNlxXE0_2s_1 skateboard +LZNlxXE0_2s_2 skateboard +LZNlxXE0_2s_3 skateboard +LZ3S39QfkKA_3 bicycle +LbHrVQR9f24_0 cow +LcvMMvrPIug_1 cow +LdNi4yjT3yE_0 person +LdusiqJFR6I_0 person +LesCJsHdAU0_0 cat +Le2725PKYQk_0 dog +LfUSKsg8JoQ_0 cat +LfhPiqIDAcI_0 person +LgbwFATbwhs_0 cat +LhF7TJOwt8o_0 motorcycle +LhOMGvkzP28_0 person +LhOMGvkzP28_1 person +LhkFN7f676g_0 airplane +Lh1QrEwtBxU_0 skateboard +LiS31CevvvA_0 person +LiS31CevvvA_1 person +LjRWmJThZrA_0 person +LjyZ7Djyq1U_0 person +LkP8lgpmCJc_0 airplane +LkfML7bjGg8_0 person +LmCzQ6WrePM_0 bus +LnYz8cQsrWk_0 cow +LpTBcxby8_U_0 cat +LpT4VBLapqM_0 car +LpjbdSyW__A_1 truck +Lqm0JTDlIaU_0 truck +LtIW9sP55N4_0 person +LuC8ON_75l4_0 person +LuRLF2TroVk_1 airplane +LunFMJp3_Uc_0 cat +Lup2fypzuD4_0 person +LurlbycI8WQ_0 person +Lvd7WBHnDpk_0 truck +Lwxi57QRroE_0 person +LyPkKroSsaU_0 bird +LyPkKroSsaU_2 bird +LyPkKroSsaU_7 bird +Lz7uf7cmfAU_0 horse +L0Y9j9DtU1o_0 dog +L0mqjqU7pmw_0 person +L1C1GJZuI6U_0 horse +L1TihVYcfII_0 bear +L1xr5gaSzeQ_0 bicycle +L2lJenTKrLU_0 truck +L2lJenTKrLU_3 truck +L2lJenTKrLU_5 truck +L22pyXEUjv8_0 bird +L22pyXEUjv8_1 bird +L5px8rMqxRY_0 motorcycle +L8Q0lJgaUi4_0 zebra +L-3-1978GvI_0 knife +L-6R2vuKWhc_1 truck +L--TMS61Zvw_1 boat +L--TMS61Zvw_5 boat +L_dOv3wd1ZM_0 person +L_nI4_2RbTU_0 knife +MAmHLoJdmc8_0 cow +MENNFokPNbU_0 airplane +MG8-IGrKVxc_0 truck +MG8-IGrKVxc_2 truck +MG8-IGrKVxc_3 truck +MG8-IGrKVxc_5 truck +MH1GdFqE_lo_0 horse +MH1GdFqE_lo_2 horse +MH1Kct5RCRg_6 airplane +MH1Kct5RCRg_10 airplane +MIkxezmilfY_0 person +MI6x6FrXJqs_0 knife +MI9BIgkOBjI_0 horse +MJ9vJFTTV5c_0 person +MKiCrBXtflw_0 cat +MK8Jm3I4In4_0 dog +MK8Jm3I4In4_4 dog +MMiSt9MNne8_0 train +MNve0XPgcGA_1 bird +MN1A5E3jNSE_0 horse +MPJu68gBGfI_0 person +MPMudxdiIds_0 train +MPfgu6-snaM_0 bird +MQ1o_7gpp5E_0 person +MQ1u8IEmFSA_0 person +MQ3HhLmsCik_0 person +MRNJmLLkjPc_1 motorcycle +MRNJmLLkjPc_2 motorcycle +MRqfEOhWW48_0 person +MSItPvVCUN8_0 cow +MSd5Ecl5-W0_0 person +MSnEnQ0psW8_0 car +MV6MGXhQwFQ_0 cat +MWbnSN-7WG0_0 cow +MWt4P6HWxMM_0 horse +MXEcQSFwng0_0 cat +MXTzea4MeHc_1 car +MXoVDyewPBE_0 person +MYFPnJIKK5k_0 person +MYpdq9KvK8o_1 umbrella +MasaNQLCMGE_0 person +MbRvEKuvR04_0 skateboard +Mb6r1es0AbU_0 cat +Mcdl3s6oQrc_3 bear +Mcdl3s6oQrc_1 bear +Me-clc6PGkA_2 horse +Me-clc6PGkA_3 horse +MfYpMzLWST8_0 cat +MgFhoihDD1U_0 person +Mkmpoid1BvA_1 train +MokOHR3wImM_0 cat +MqBTk3ITQ8c_5 elephant +MqBTk3ITQ8c_3 elephant +MrWZEUtDBq8_0 dog +MuyIuhdszH0_0 person +MuyIuhdszH0_2 motorcycle +MvKMtFVP5NU_0 person +MvbZEiffy8s_0 person +MvuGj1qR4Ic_0 motorcycle +MvxUj_Du2IY_0 horse +Mw6Cu1mPanU_1 cow +MxtJwd0GBkA_0 airplane +MzTsjMauBH8_0 truck +Mzrv2OCC2GE_1 person +M0TTCr9jjgc_0 horse +M12KvkF1Nec_0 person +M40gbbuNuL4_0 truck +M5p7jyvEgPk_1 knife +M52oDxJEXk4_2 horse +M52oDxJEXk4_0 horse +M7Kcv9fUrhA_0 cow +M9CCnnc8m8k_0 giraffe +NAInb4dMC_E_0 airplane +NAInb4dMC_E_3 airplane +NAsDBYDNhwY_0 cat +NDxs_vxhhME_1 person +ND-VrJY7mU0_0 person +NEsCBcZFajg_2 airplane +NEsCBcZFajg_5 airplane +jvlyXCBSuCk_0 person +jwYviTYbJYs_0 cow +jxL3F-iB2S8_0 bus +jxmsNv20V50_0 train +jyrY4oyyA7M_0 person +jzNOBsi5TtQ_0 cow +jzeFDGEt_iQ_0 person +j4UJ80q_s3c_4 skateboard +j4UJ80q_s3c_5 skateboard +j4t-Otp9ES8_0 person +j6XmNyG8nYE_0 bear +j8SM6uLadmU_0 motorcycle +j8aX3NuEnxc_1 airplane +j8aX3NuEnxc_0 airplane +j93wwDC_a2I_0 skateboard +j_tT90ISNnc_0 skateboard +j_6ZWhyOOcA_0 person +kBKG0SaNbdw_2 cow +kBYFlPJJx-s_0 person +kCHOoDF-pXo_0 cat +kCQIRLEi88s_0 person +kCefZaEK9M4_0 person +kCt3G72NjyY_0 motorcycle +kEx2sgiyKpY_0 dog +kG5vclMyg7w_0 skateboard +kHIZAi1E9gU_0 cow +kH3Hwla_MUM_0 person +kI7523l1Tu4_0 horse +kI7523l1Tu4_1 horse +kLwsGbEsMjs_5 elephant +kLwsGbEsMjs_1 elephant +kL52zPMgsXM_0 truck +kMIRREOoSt0_0 elephant +kOqKBgGRd_c_0 boat +kQu7xcJmp6w_0 airplane +kRLl2HLijWc_0 elephant +kRqsESioKVM_0 person +kSWUU8Ef-Rg_0 cow +kSXkd4PYX9M_0 bear +kSm9E8WwGYY_0 person +kTT6onfYUug_0 bicycle +kZcfsku1oJ4_1 bicycle +karZg0Iifks_0 skateboard +kavU8zKXrEY_0 elephant +kbD6iXQ3P6M_0 cow +kb4GuHpwuSw_1 cow +kdPgKSrjVYQ_0 train +kd9Tn_hyeb4_0 dog +keka7aToy_E_0 person +ke2Ap6Zvq64_0 cow +ke2uXJrB9WQ_1 bird +kfL1KEY53AM_0 person +kfMMMSNZWeM_0 giraffe +kgcb2y-aw8s_1 truck +khicinfB1nY_0 person +khr1-lWZOOw_0 bicycle +kixX1ga8yrw_0 person +ki51QTz_6iw_0 bus +kjhcR5ljaDU_0 car +kksfStf04pc_0 person +kk41Jjw-BpQ_0 horse +klxQpVdft5E_1 bicycle +kmIUPZSNl5A_0 airplane +knFBzlhmDMk_2 skateboard +knFBzlhmDMk_3 skateboard +koomOoaIF0Q_0 motorcycle +ko4el3e0QFI_0 bird +kqE2rNzUnvU_0 cow +kqJJ6_2vGtU_0 motorcycle +kqiHy-EzdcQ_0 airplane +kqiHy-EzdcQ_1 airplane +kqiHy-EzdcQ_2 airplane +krD5WtdljCc_0 bird +krR-lFUTXHo_0 cow +ksbdMzGs-gs_0 person +ksbdMzGs-gs_1 person +ktCRlGt6408_0 train +ktcXRj-Vz6c_0 bus +ktcXRj-Vz6c_1 bus +ktvaX1ALzwE_0 motorcycle +kwMNSTE0h8U_0 bus +kwMNSTE0h8U_1 bus +kwyn-eed9l4_1 bird +kx2jH9V7vYM_0 train +kz0gVW9uWkc_0 skateboard +k1C25MTUso4_0 person +k1Y6Y1yocF0_1 knife +k1qT5GtPmQo_0 bear +k2fCUP9H4cw_0 skateboard +k24lvYKkK5g_0 boat +k3hYFu55iGE_0 person +k3hYFu55iGE_1 person +k3pTU4KNdvE_0 train +k4tqy4pdlNs_0 horse +k5MmpG9afSM_2 bear +k5UoGZZb_RY_0 cat +k5oey7bw5kA_0 person +k5-IPGgeCPc_0 person +k5-IPGgeCPc_1 person +k8OboASs470_0 skateboard +k8OboASs470_1 skateboard +k9COlD7u1tI_0 knife +k-tdE0VAFkc_1 person +k-tdE0VAFkc_0 person +k_E-cIymiis_0 train +lAZQZSK_9bk_0 cat +lCc5-WmCZJk_3 dog +lCc5-WmCZJk_5 dog +lDWAsuKkv5Y_1 bird +lFObiVRO-BQ_3 airplane +lGAGodreVjQ_0 train +lGJB2hhw5pI_0 cat +lIbOGzXhSW8_2 horse +lI-A6pFtkLQ_0 train +lI_jxWxWivM_0 dog +lJXfbIuwTIQ_1 cow +lJccP5OJjZ8_0 train +lKBO-dakd8w_0 train +lLyfm0vbHrw_0 train +lL_4QscWdx4_0 person +lM0yKqnWblw_0 person +lNJbOSFK9N4_1 skateboard +lOFTlhNmKD8_0 bus +lOQf3A_3lPI_0 horse +lOWmL3mpSeA_0 train +lOvB2zlHw8w_0 dog +lO-XTKPQb5I_0 train +lPapZHOAdzk_0 bicycle +lP5lgBlsH0U_4 airplane +lP5lgBlsH0U_1 airplane +lP5lgBlsH0U_2 airplane +lQDy9Mri-18_0 person +lQsTpo0uOIw_1 boat +lQuFC-E7VUM_0 person +lQuzpkDKFQ8_0 person +lRuif4Zc7CI_0 boat +lSZa4pAHgV8_0 horse +lS-5gEkB0_o_0 motorcycle +lTTquh-jLwM_0 car +lThBPb6HI1U_0 cat +lVeIr8AFTjY_0 person +lWT2t48q164_0 motorcycle +lYSpeuL7-oo_0 umbrella +lZOTAg9Fofw_3 bird +lZVwQoLPjBU_0 giraffe +lZVwQoLPjBU_1 giraffe +lahDGDRe7X8_0 horse +lcKDCt1eWqg_1 knife +ldQGB8gzRjA_1 cow +ldhdyBduVoU_1 cow +lf_tYVzrap0_0 person +lge9f_bgAOk_0 person +lgzIpgcvPvU_0 person +lhNv9zDa1ug_0 car +lhadIxHkaVg_1 person +lhadIxHkaVg_0 person +lhnQuOIF-2c_1 person +ljLO1myCfoA_1 knife +ljayNZQpp-I_1 horse +ljayNZQpp-I_5 horse +ljeTwRM6DWE_0 person +lkvdy3Hejpw_0 person +ll6gTyUguMY_0 horse +ll6m5MTpf4o_0 person +lmpKSF0cXSc_0 train +lnfEV2dRfm4_0 motorcycle +ln0_FGR8B08_0 person +loVlMj9Dhkk_0 truck +lotZh71qMks_0 person +lpcqEaZD_Xk_5 bicycle +lpcqEaZD_Xk_0 bicycle +lpcqEaZD_Xk_1 bicycle +lpcqEaZD_Xk_2 bicycle +lpcqEaZD_Xk_3 bicycle +lpcqEaZD_Xk_4 bicycle +lqu4tjd3Zg4_12 bear +NE9AhZPTVFY_0 motorcycle +NFF4UemeH8g_0 truck +NFSj66emNbM_0 cat +NGS9BrtLJ0I_1 boat +NGvpnRrWSKc_1 bear +NHLBjlX2jeg_0 person +NHgh88y4e80_1 car +NHpM-oBMIRk_0 dog +NHrjnZsJWOw_0 person +NID_0E0tn_g_0 cow +NJQNZ36lsvw_2 truck +NJm81cIGO98_0 skateboard +NJ22Hynv9s4_0 umbrella +NJ22Hynv9s4_1 umbrella +NJ7MXR2AaoY_0 cow +NKQfFcfr6Ko_0 person +NL1iy1TKtRI_5 car +NL1iy1TKtRI_1 car +NL1iy1TKtRI_2 car +NL1iy1TKtRI_3 car +NL1iy1TKtRI_4 car +NMCijcIa_XU_2 knife +NMhR_Z4Rq7g_0 person +NNbRF02KnGM_1 skateboard +NQiMeD83sMw_0 truck +NQiMeD83sMw_1 truck +NQsnyZmQoPw_0 elephant +NQsnyZmQoPw_2 elephant +NQve9Yujb14_0 person +NRaAEznVIxQ_0 person +NTGqC7kOGAw_1 bird +NTRX6gLV_04_0 bus +NUSnWbhvmQs_0 cow +NVzCor2-ZpI_1 zebra +NV-p8Vp-bdA_0 horse +NWAQ1is2w98_0 airplane +NYIqB-l8eKk_0 train +NZ5OIYTIoYQ_0 person +NaCksn1bbv4_0 airplane +NaCksn1bbv4_2 airplane +NaEokN7Nh-U_2 knife +NadzcUmXDTk_0 person +NbJ2gM5KJTM_0 cat +NbJ2gM5KJTM_1 cat +NdXmkm9jcPA_1 airplane +Nd6ceCmRYBI_0 bird +NeXVfNsggZw_0 cow +NfEzlo6-i_4_0 train +NfEzlo6-i_4_2 train +NfEzlo6-i_4_3 train +Nhi9730yIzM_0 dog +NhskHQ9bqlo_0 cat +Nhvr0y1tqjk_0 person +NiP4AEjiwxs_1 boat +Nio43-cQPh0_0 train +Ni_TSyCk1Ak_0 cat +NjknyzAAQpM_0 person +NlOjGoYPj9Y_0 truck +NlTLvOcpoEA_0 elephant +NlVEu_8kdoI_0 horse +NlVEu_8kdoI_1 horse +NljV4UjnFJc_0 motorcycle +NnRWY12wxUk_0 person +NnVFfTO9-q8_0 person +No84NOV3Pwk_1 skateboard +NpZj-n9_STU_1 bird +NqwxEAASrCo_1 airplane +Nr9t7GeBwQY_2 skateboard +NsbG9FcyTFk_1 elephant +NsbG9FcyTFk_4 elephant +NsbG9FcyTFk_2 elephant +NsbG9FcyTFk_3 elephant +NuKyL_c3YcQ_0 cow +NulXMVhoGhU_0 knife +NuutxSJHULc_1 cow +NvkF9R1HsJc_0 car +NxTnPIBFKdE_0 airplane +Nxjnp7dqCdc_0 cow +NxqGplqsmNk_0 person +NyKq-nq-KlQ_0 person +NzAEnNO5-fo_0 bicycle +NzAEnNO5-fo_3 bicycle +NzAEnNO5-fo_4 bicycle +NzAEnNO5-fo_5 bicycle +N0LEywKxW9o_0 cat +N0e8A9q9tyU_0 train +N1OYtZSKdKQ_0 train +N1OYtZSKdKQ_3 train +N1pTdHcekjU_0 car +N28sspen6dM_3 bird +N28sspen6dM_1 bird +N3ffRSq8s7M_2 cow +N6nP6NLTaG0_0 motorcycle +N7Bv6ZMyBrU_0 skateboard +N9vkS7ish9k_0 cow +N_5Xf4hpanE_1 dog +N_5Xf4hpanE_0 dog +OBQQMo8mWLE_0 person +OCA5rhgrl48_0 person +OCLVaKMFCZg_1 bicycle +ODI8kcB_dSs_0 truck +ODJSlRRM1Uo_0 cat +OD4XsgCwIKk_0 person +OD9vhbbeBAE_0 horse +OEhrO1p2agU_0 person +OGOf9vbNJB8_0 person +OG8Nfns4uh0_0 cat +OHEyq1pCfZ8_0 truck +OIV8ASYsqZc_0 skateboard +OIV8ASYsqZc_1 skateboard +OImLl2ufWqI_0 cow +OJktr2-sJmY_0 motorcycle +OJktr2-sJmY_2 motorcycle +OKbNtRotT5w_2 horse +OKbNtRotT5w_5 horse +OKbNtRotT5w_7 horse +OK-2ALhNWts_0 bird +OLpvIpNUgY4_0 person +OLyGncmosSs_1 horse +OL_lZw3lqE4_0 person +OMm3ReCUyGA_0 person +ONlvohUS-io_0 cow +OOC45SMJl6M_0 bus +OPIxLQwJLaM_1 cow +OPbyoGG-M_E_0 horse +OPm_iAWIO2o_1 knife +OR4OEYlOndk_0 motorcycle +OSRtFznjiro_0 motorcycle +OSUOKZdfiXQ_0 person +OS6SXRjK0rU_0 horse +OUeSqgMRLUg_0 bird +OUrVDMMYK-4_0 person +OWBXMvAtmcA_0 cow +OWqaj3O-u6E_0 train +OWqaj3O-u6E_1 train +OWqaj3O-u6E_3 train +OWvRHFQJ-5g_1 train +OXjc7JlWYwk_1 bird +OXpPVrdEoko_0 elephant +OXpPVrdEoko_1 elephant +OYCDyQPt5rU_0 truck +OYRmTydmqZo_0 cow +OYugCmogPD8_0 bear +OZver3igS6U_1 zebra +OZy-0MSWC7o_0 person +OZ5z2K-vIYg_0 motorcycle +Ob4ur_FS9xM_0 dog +OdLj2La07lM_0 boat +OdnylLd12pU_0 skateboard +OdsXUxBBISo_0 airplane +OePFLxtDg7k_0 horse +OflyVi689KA_0 skateboard +Og9LiinXMtw_0 bus +Ojx6OtSIA3k_0 person +Omdbd0YsB2o_0 airplane +Omdbd0YsB2o_1 airplane +OnRL69PzM4I_0 bicycle +Oo3Uhz6L-cs_0 person +OpEMSVRTyxk_0 dog +OpJl0GUiLQI_0 person +OptQqflXY_g_9 elephant +OptQqflXY_g_0 elephant +OptQqflXY_g_4 elephant +OptQqflXY_g_5 elephant +OptQqflXY_g_8 elephant +OqmbWcekMxo_0 person +OrPfakDZX64_0 person +Orwr1k0mKho_0 person +Orwr1k0mKho_1 person +OtHHLfag4xg_2 knife +OumTAMPogf4_0 person +OvQFDkMjctE_0 person +OyDNx0iCGUM_0 truck +OyKi2PGJERI_0 person +OyKi2PGJERI_1 person +OyhAS52bQMA_1 person +OyhAS52bQMA_0 person +OzORAIgrZOg_1 knife +OzQFkM92we8_1 dog +O0o_u_t5Y6w_0 bus +O2TgLtQU7PI_0 knife +O3GPSL92hYw_0 elephant +O4UhXpMuxJI_0 person +O5PlzlxQuPc_0 dog +O5796OHwBy8_0 bear +O6cWlrockUQ_2 horse +O8s1bsDJrwc_0 person +O9dxeSLiF9A_0 skateboard +O9dxeSLiF9A_1 skateboard +O90WVIgQwww_0 person +O9_riOoIpKo_4 train +O9_riOoIpKo_6 train +O9_riOoIpKo_10 train +O_hypcyZCFo_0 airplane +lryNU4SKncc_0 cow +lrzxlHguluE_0 bird +lr7T4YcCWSU_0 elephant +lr7T9GuNUMY_0 cat +lskWmTPa9Gk_0 person +ls34lS6fGzw_0 person +lt7kXXW5D-c_0 bus +lvdU2uEdpnA_0 boat +lv6aYZguv6k_0 person +lxXwMvanqo4_1 boat +lznoTW8tuLI_0 bus +lznoTW8tuLI_1 bus +lznoTW8tuLI_2 bus +l0J9Km2lk2I_0 person +l0TirY4L7Es_1 horse +l0TirY4L7Es_3 horse +l3yFwpak_LA_1 horse +l38pNVKwDeo_0 bird +l4sdxYUAiJQ_0 person +l4_P74HRriU_0 person +l5GlzRyX39s_0 person +l5GlzRyX39s_1 person +l5WawiGWVxg_0 person +l6cEGnOtFZg_0 airplane +l682n6ZmpNk_0 person +l7Mmo3ow8qo_0 person +l7kq2yqxPQc_4 horse +l7kq2yqxPQc_2 horse +l8r-mOc3-3U_1 person +l9QgZQGtQWI_0 motorcycle +l-4jrxgMGTQ_0 skateboard +mAEnlKe67pQ_0 bicycle +mAhzB1TH8mU_0 truck +mAj62XUNkIM_0 horse +mBgSYaKydZY_0 person +mC5X6MO2y9A_0 person +mDf5zsFFweg_2 knife +mDf5zsFFweg_1 knife +mFbUnWMAreQ_0 person +mGDfepYDRRE_0 person +mHFxPudSk8c_0 motorcycle +mIFnGYdf0po_0 person +mJm2UYBiD8w_0 cat +mJo7aqOfRww_0 airplane +mJ6qCcS_-AQ_0 person +mJ-DsFbUPUg_0 motorcycle +mKBs2L-xwdU_0 person +mLVHfKExUNU_0 boat +mMdGNbPpLKQ_0 truck +mMy70TxInmA_0 person +mNpEoUW_OPI_0 knife +mOFqvrGzJiE_1 elephant +mOFqvrGzJiE_2 elephant +mOkmKyBZoXI_0 person +mP6-RR-Vuv0_3 truck +mR1y0XlZhQ4_0 person +mTeNKWTwFcs_0 person +mU7E6pi9PFU_0 bear +mU7E6pi9PFU_2 bear +mWeNwTJwEmo_0 person +mWhw719wEH4_0 person +mXBKJjrxqmc_0 knife +mXekeIascCc_0 person +mX_4T1I2ux4_0 dog +mYwEvpKN2-Q_0 train +mZ0VxiELg9A_2 motorcycle +mZ0VxiELg9A_0 motorcycle +maiqraHgwgg_0 skateboard +mbZZ48h5pnY_0 person +mboIIChd8tY_0 bicycle +mcR2Fi6wQj8_1 train +mcR2Fi6wQj8_0 train +mciQ3fR1QTE_0 truck +meAfvCGeyyU_0 person +me-WjezBU4U_0 motorcycle +mflX-nwtpzs_0 skateboard +mgSJL9uL49w_0 bus +mgSJL9uL49w_1 bus +mhDnVhRMCHc_5 cow +mhDnVhRMCHc_0 cow +mhDnVhRMCHc_1 cow +mhDnVhRMCHc_2 cow +mhDnVhRMCHc_3 cow +mhDnVhRMCHc_4 cow +mhIULm3ssFk_2 airplane +miJ1b0bNn9M_0 person +miLapj3u_5g_0 cat +miR8Xeb7SM0_0 umbrella +mi4j0PrR-Gs_0 truck +mi4j0PrR-Gs_1 truck +mjSUb46nTjs_0 horse +mj2ClgQE_Q0_3 skateboard +mj2ClgQE_Q0_2 skateboard +mj_R3ENyiKM_0 person +mnOoqy7I3L8_0 skateboard +mns4vFzs4_8_1 skateboard +mns4vFzs4_8_0 skateboard +mnwyrMq92so_0 person +moBNY2JjuEQ_0 cow +moc2yPvW_JU_1 person +mpA3PWbdVWc_1 bus +mp-cHp44pXo_0 bird +mp-cHp44pXo_1 bird +mqI9CDpsCDE_0 cat +mqYD18pFqm8_0 person +mrnDERbyZcM_0 skateboard +mtO9ioY8AHY_0 person +muk5R25UV1A_0 person +mungFWJMSsg_0 dog +mwRNyFvem8g_3 truck +myYMS85ltwo_0 skateboard +myiCWmM3XN4_1 dog +mziKTFuKVco_0 person +mznC1uLm_j8_0 skateboard +m0z25TJV2vU_0 person +m1VAqMAJ-Lw_0 elephant +m2DUDsR4tWA_1 bus +m2Sr_Q8JpcI_0 horse +m2Sr_Q8JpcI_2 horse +m2Sr_Q8JpcI_3 horse +m2-nK6oZ08E_0 horse +m2-nK6oZ08E_1 horse +m3u_pETGaMw_0 train +m4Ozpr8E1EE_1 train +m5mSFt43spE_4 motorcycle +m7VhCUoV_Dw_0 person +m77tPf0Ulb0_0 person +m8THukZrE7w_0 person +m86BSOvJvS8_0 person +m9hdxJE9HQE_2 train +m95nb4Vl_R0_0 elephant +m-Ry10-IgWg_0 horse +m-sLdoVujlI_1 bird +m_25GAJYGHE_1 car +nAO2Y4kF7b8_0 bicycle +nBllCINiO-4_0 train +nF_NlCSUpFo_0 cat +nIO0ZNZi6n0_0 person +nIiXsRSLxZI_0 person +nIiXsRSLxZI_1 person +nJO5eQXPS0M_1 horse +nKfhxWUyc4I_0 elephant +nKfhxWUyc4I_2 elephant +nLUyCQwkCds_1 motorcycle +nMW7WsVKd_E_0 truck +nO14Z3ggnZs_0 truck +nO16C5NBMQQ_0 person +nO16C5NBMQQ_1 person +nPJJOI4j3UQ_0 person +nQAqVHkffhY_6 train +nQAqVHkffhY_7 train +nQAqVHkffhY_1 train +nQAqVHkffhY_5 train +nQrJJZvmF74_0 cat +nRu8IVZXzCU_0 airplane +nR1Ng3PnYoU_0 cow +nSUBF0RYH1o_1 bicycle +nTfgyYqyO_Y_0 person +nTtqkLze7eY_0 horse +nTtqkLze7eY_3 horse +nTtqkLze7eY_4 horse +nW4sAWZ6dHQ_0 bicycle +nXYeq3IDOFo_0 truck +nXgq-W7J6ho_0 person +nYGQy8peDYk_0 person +nYHjMb7HoK8_3 bird +nYIUSRVmY30_0 person +naMdRxX0924_0 train +na6hNW8gSx8_0 bus +nbojUStyLvY_1 person +nbojUStyLvY_0 person +ncZiTQHehfk_0 person +nefS_k9oFMI_0 person +ngE_mlmsaqY_0 person +nh4AR9Mjwmo_0 bicycle +niQ2DNNlBSM_0 person +niUnVyYTszc_0 person +njOQqZ1pBGM_2 boat +njP6uuU-G6o_6 bear +njcuqdNTGfM_0 person +nj8ALe3wC9c_0 horse +nki1SdWtdCI_0 cow +nk6FezKWYSY_0 bird +nmNSM48p094_0 knife +nmRZQdp3xRk_0 person +nn8WcALmZ7c_3 bear +noTnh5A2OHo_4 boat +noTnh5A2OHo_1 boat +noWsAcioI8g_0 train +noe-qNQfJBo_0 bird +no-b9_3kXiQ_1 dog +npAPemisdEI_3 boat +npGL0Kl16f0_0 person +npGL0Kl16f0_1 person +nqZya6Vk3iY_0 cat +PAdHnsQ5png_0 cat +PAi_eJ_z59w_0 skateboard +PBPViL9vBZQ_0 motorcycle +PBS3-SzLV2A_1 horse +PBwR_Jdod_g_0 knife +PCJWOz32Js8_0 person +PDmAbS9Afkc_0 truck +PE8yxnkayr0_0 person +PE8yxnkayr0_1 person +PFKrDvQuKII_1 car +PFb83m0smRg_0 person +PHunbTKqKwk_0 train +PH5VqmGrnXs_0 cat +PIG9w10uliw_0 bus +PIo5FlB1sf4_3 bear +PIzyVPr2kvQ_0 person +PI_spS2t57M_1 horse +PI_spS2t57M_0 horse +PJK-c0HQksg_0 bear +PJUvXC0Eumw_0 airplane +PJsCV-lA78A_0 elephant +PJ0Y1xQ7ZJo_0 horse +PJ2kZmkL25Y_0 person +PKGRn71TQGQ_6 airplane +PKGRn71TQGQ_1 airplane +PKtLlpi00cM_1 skateboard +PK_UdRSa36U_0 motorcycle +PMDSUC0_Ytg_0 bus +PNxobv7rkRU_0 person +POWngj1oBhQ_1 train +POpePYwyHWY_0 bus +POu1oPwNd4g_0 umbrella +PPeaYnqzi9g_0 person +PPjAhD3i-v4_0 bus +PPqkkhaUIdE_3 bus +PPqkkhaUIdE_0 bus +PPqkkhaUIdE_1 bus +PRaq5kZmO2A_0 bus +PRyc4Vp0s00_0 bird +PSyuR_D5C2c_0 cat +PTLtv0VJ0_s_0 person +PTM6VrBcP80_0 dog +PTewrgfas9o_1 train +PT6u63wHOhs_0 dog +PT_tMCTzlSc_0 person +PV_FZhj_0hI_0 car +PWZIO2hdNRU_0 person +PWiyz8b24es_0 airplane +PXxs6Hzx7Pk_1 zebra +PZ3X20r0oVc_1 bird +PZ3X20r0oVc_0 bird +PdPZkfHUOq0_0 person +Pd9bh2hiWAk_0 person +PeA8729U1jg_0 boat +PeJxY7YFBTA_0 knife +PgFIqGCjnc0_0 horse +PgNvdw3Zges_0 umbrella +PgjeF-iHzLk_0 person +PgyVMv-RRL8_0 truck +PiI1e3aKeos_0 person +Pkju9RRBRAU_0 person +Pn01hUEOICo_0 bicycle +PoI-RFl6jqU_0 bird +PoI-RFl6jqU_2 bird +PpX6lJOP6ng_0 person +Pq1kVNudVJo_0 boat +PsPMm45bDZA_0 bird +PskTcGACgjw_0 person +PsrCCNATJd0_1 elephant +Ps9peKxde4U_0 dog +PvCZZzw4FKw_0 person +PvQVqhtqTVk_1 person +PvQVqhtqTVk_0 person +Pv3IqqHid-w_0 airplane +Pv3IqqHid-w_1 airplane +Pw7zlPV9yh4_0 motorcycle +PytUHdEhipQ_0 airplane +P0FylASL6h4_0 person +P06NLpHGLb8_0 truck +P06NLpHGLb8_1 truck +P1FTUN2gJkY_0 person +P3JAtlf2-VA_0 cat +P3MhJa_p-dU_1 truck +P5MpdcJgQrI_0 skateboard +P5NEco_Rqas_0 motorcycle +P5NEco_Rqas_1 motorcycle +P5v3n_5s-F8_0 horse +P7i0pgLo9kg_1 car +P8E7gprJa1s_1 skateboard +P8_7-uFl2Go_0 bicycle +P9dDbodBY8s_2 motorcycle +P9dDbodBY8s_0 motorcycle +P9dDbodBY8s_1 motorcycle +P91LJh-_E0Y_0 cow +P-FrYGR7Bf0_0 person +P-phCIDPeWw_0 horse +P-27cmR3CZE_0 knife +P-_MzAIxz2E_1 knife +QBAxag8dq6Q_0 cow +QBfotDmdDkk_1 skateboard +QBrAST1Q2iE_0 person +QCCt8ooY4qg_0 person +QCjqG8908mY_0 cow +QEDWauqnaSk_0 skateboard +QEGY7Dq2x9s_0 horse +QE0MjXjSFjU_0 boat +QFS35qERdLE_0 person +QFeMKKxurVg_2 horse +QFxep-yih-s_0 truck +QFxep-yih-s_1 truck +QGN2-Iqa4QQ_0 person +QHPYpnJSf2s_0 cat +QHhkx3CSiWk_0 person +QJ1W4Pajbv0_0 person +QLmFsJCZy_o_3 knife +QMRFisCEGQc_0 person +QM9Kddu2XcQ_0 train +QObG-uf4v68_0 motorcycle +QOjAwmQ_7vA_0 person +QPtMbvxzFuE_2 bear +QQC7AIIJg2Y_0 elephant +QQLrVBS8VSo_0 person +QQLrVBS8VSo_1 person +QSTf92HwJS0_1 dog +QSTf92HwJS0_0 dog +QTjiYkMuDGI_0 knife +QTqvJZS8ZNo_0 elephant +QUIxOZH8N8c_0 person +QUUgu5YvS1c_0 person +QU7X6RkjKPE_1 boat +QVUI5ZkkDsA_0 person +QVnam2Ma6mY_0 person +QY1rz6k86s0_1 person +QZS3V-7xnAA_0 person +QZWqiN4OA_A_0 person +QZk1HSA90KA_0 knife +QaUHYb5os4U_0 person +QahBgQXhNfo_0 cat +QbOvfWFyPzg_0 dog +QbOvfWFyPzg_1 dog +QbPvdKEmnrI_0 person +Qb4RNeQYfPc_0 boat +QcLa-GP2ITc_0 person +QcLa-GP2ITc_1 person +QdeUvHCiXwc_1 horse +Qd0chk9vUQ0_0 bear +QeISQLJERxg_0 person +QfJeJLieLew_0 cow +QfJk-eDxmKE_0 person +Qfkb-gc72qg_0 cow +QgPao5AkXFU_0 skateboard +QgiX6-1aN-4_0 bus +QhGx_MwYnWs_0 person +QhIp71nr7Vk_0 dog +Qk_VhG5lt1Q_0 cat +QmRFPW81gZc_1 truck +QmfJmQuF1-I_0 bus +QmuLT1MpdP8_0 person +Qm2yaeiexlI_2 motorcycle +Qrd-Q3XrT3A_0 train +QszBg-eN7F8_0 cat +QtBYK8AxWCw_1 person +QtpKcTyf4n4_0 knife +Qtq2m-MV2q4_0 cow +QvY9ysq30EI_3 elephant +QvY9ysq30EI_5 elephant +QvY9ysq30EI_0 elephant +QvY9ysq30EI_2 elephant +QwJNOYFZ3W8_1 elephant +QwTIODgGfOM_0 person +QxLFtmn_Igw_2 bear +QyyPl-aCFUs_0 cat +QzETtzOBUaY_0 person +Q0HpPvC0bKA_0 person +Q0M_Fog02Yw_1 horse +Q0UrlXLNioY_1 umbrella +Q0tQtb1npx4_0 car +Q0x55aCCNxA_0 person +Q31q8b3CSN8_1 skateboard +Q4rAM1058Z4_0 horse +Q4rAM1058Z4_1 horse +Q5G2n-3zXX8_1 person +Q5G2n-3zXX8_0 person +Q5X1kisU8Qo_0 person +Q6hwtMw2jkU_4 skateboard +Q6hwtMw2jkU_3 skateboard +Q7SViqj0bEg_0 dog +Q83xNK10WK0_0 bear +Q-lTGQgTOEg_0 person +Q_rsZh5VqdY_0 person +RANBJV7BN3k_0 person +RAmxGTzr25A_0 person +RBccU2wq7Qs_0 knife +RBclSX-7rYQ_0 person +RDiehz1pFVA_0 knife +RD7nVPZTGEw_0 skateboard +REBfrgEC_3U_0 knife +REh7f-__WqU_0 cat +RE40E9-qdHE_0 horse +RFO8tA6rfbo_0 truck +RFbhEQ4qN-A_0 person +RIfxXKT-_88_1 skateboard +RJZgo3_JEPs_0 person +RJi5ZRGQb-A_0 person +RJxPTuKUKjk_0 horse +RKFpQfRSYIc_2 motorcycle +RKFpQfRSYIc_3 motorcycle +RKFpQfRSYIc_4 motorcycle +RKFpQfRSYIc_6 motorcycle +RKFpQfRSYIc_7 motorcycle +RKFpQfRSYIc_8 motorcycle +RKFpQfRSYIc_9 motorcycle +RKFpQfRSYIc_10 motorcycle +RKFpQfRSYIc_11 motorcycle +RKFpQfRSYIc_0 motorcycle +RKFpQfRSYIc_1 motorcycle +RLcZcFP03fA_0 person +RN6TzMbUlyg_0 airplane +ROdg8e5a0Fk_1 cow +RPwZjkygYo4_1 elephant +RR-fksDmQTU_0 dog +RSLwmLbf3No_0 horse +RSO2IDZGDus_0 person +RSQ7pHT5sU4_1 cow +RSWyviTCTqk_0 cat +RTAQO62dbRo_0 horse +RTONY5PqRUo_0 skateboard +RT0mh9U0YDc_0 person +RUAbb66fW18_0 bicycle +RUW8xYh84q4_0 dog +RU0u42rf0Hw_2 truck +RU0u42rf0Hw_3 truck +RU_8ryQNxC0_1 bird +RWJfJx1nXNQ_0 bicycle +RWo2zaceWcc_0 bird +RahqzUIhIkc_0 cow +RawtpxzAbmM_0 person +RdZGVs8pH40_2 skateboard +RdZGVs8pH40_1 skateboard +Rdge7lmfdc8_0 person +RfVv6ECZ78Y_3 bear +Rfa2If7RJTY_0 knife +Rfa2If7RJTY_1 knife +RfvNPPjs-bw_0 boat +Ri3O4rz5S2o_0 boat +RoMemRfbKkc_0 person +RoNJ0fP0VUU_0 person +RqAANAYxYz0_0 person +RqqaUsDM-aI_0 person +RrnixlsQyn8_0 person +Rr6AsTlUNKQ_0 person +RspILw0UAM8_0 person +RsyjwcMkRrY_1 knife +RsyjwcMkRrY_2 knife +Rt1reRy5GVY_0 person +RuFIanBmYzM_0 bicycle +Ru9ksAvNYc0_2 cow +RwVTAYsyWMo_0 person +RxWOvD9i9Ig_0 car +RxtS3kGOYoc_0 bicycle +RxtS3kGOYoc_2 bicycle +RxtS3kGOYoc_4 bicycle +RxtS3kGOYoc_6 bicycle +RxtS3kGOYoc_9 bicycle +RxtS3kGOYoc_12 bicycle +Rx9YjtdgOEI_0 person +RyVdNK-PCyg_0 person +RylJTxUTfF0_0 skateboard +RzdsXt87bVE_0 dog +R0biK134LTQ_0 person +R0n9cqLQE4E_0 skateboard +R3rDAaPE_s4_3 truck +R45uCINxuVY_0 person +R7IE_IohaIk_1 airplane +R7IE_IohaIk_6 airplane +R7IE_IohaIk_0 airplane +R8Zg4uo1QpM_0 person +R9d1vlii7cs_8 truck +R9hRCG8pAHM_0 horse +R9hRCG8pAHM_1 horse +R_xLhXpHgp0_4 skateboard +SAeiSpeFynU_1 bus +SBmb0VU07rs_0 boat +SCLi5OFtzQk_0 skateboard +SCaWHsWzxqY_0 person +SC18zgZ9Diw_0 bus +SDCTiDVOdW0_0 bear +SFA4mVjImxk_0 person +SFoil_6CvbI_0 bird +SGsRwH8YxQg_1 airplane +SGsRwH8YxQg_11 airplane +SHSsDGmwywY_0 cow +SIZ3AYCr7PQ_0 person +SIv3Hcq1ge8_0 elephant +SIv3Hcq1ge8_1 elephant +SJkZwyPxUTg_0 cow +SJqduSR9h4g_0 elephant +SJwgIeOkfTM_1 horse +SKoDZimqLV0_4 bus +SMF8aDGwELI_0 giraffe +SNbBUZtngzM_0 person +SNnofRkUk8w_2 boat +SNqtno2pOzc_1 dog +SNqtno2pOzc_2 dog +SQn8ueHVBWc_4 elephant +SQn8ueHVBWc_6 elephant +SQn8ueHVBWc_1 elephant +SQn8ueHVBWc_3 elephant +SQ4tDbbdzr8_0 train +SQ4tDbbdzr8_2 train +SSjgAjilS8g_0 person +SSwA_nC9rr0_0 person +SThjw6JeBnQ_0 person +STuEo8vap08_0 person +SUHEgX-8bo0_0 person +SUwLfCebumU_1 bear +SUwLfCebumU_2 bear +SVUAFI7bHqQ_0 person +SWedQv5UnQo_0 person +SXWo-zKZICs_0 person +SYT4odK3Dwo_1 bird +Sc_CAareVEI_1 elephant +Sc_CAareVEI_6 elephant +Sc_CAareVEI_7 elephant +Sc_CAareVEI_2 elephant +Sc_CAareVEI_3 elephant +SdzIWTR-rkc_0 person +SeBOeRzwqrQ_0 skateboard +SeU_71ydaeA_0 elephant +SehCD9wP-Pk_0 person +Sf9OdV3i3I4_0 person +SgglaVke5lo_3 boat +SgySshdgJrQ_0 motorcycle +Shves64RCp4_0 cat +SiotcXGUwAs_0 person +Sj56u4dFe4k_2 person +SlR9qCk_m9k_0 motorcycle +SlR9qCk_m9k_1 motorcycle +SlZZmtOGyeE_0 airplane +SlZZmtOGyeE_1 airplane +SndDcPzB8Hc_0 cat +Sn2SGmheI-Q_0 person +Sn9gOBw9bf4_0 person +SoiA6jtejG4_0 dog +SpbyBYH0OjI_0 person +Sph2g6B-X2M_0 cat +SpjssmEyc_o_0 airplane +SqHtdCP5Oao_1 horse +SqHtdCP5Oao_2 horse +SqLiHZHzp9w_0 person +SqoR7vKYzCY_0 horse +Sq-Xok-ea7U_0 person +SreiPFJ6vBw_1 boat +SsMS0eIy2Ws_0 person +Sse7vXMMO6E_0 person +Suaush4Da4s_0 person +SvPL8gOREaU_0 knife +SwaILKCtBVA_0 truck +Sw4B_VFic3M_0 skateboard +Sw7L3wImbSA_0 person +SyldRIQbAGU_0 person +SzVyFmQ28Xo_0 car +SzkobSwGTMk_1 bird +Sz2bTIe9kTo_0 airplane +nrEv-Plh45s_0 bear +nt_BXwq_xhA_0 giraffe +nuCdww9iIOs_0 horse +nuMeNIi1MPY_0 person +nuMeNIi1MPY_1 person +nui8beXjUlU_0 elephant +nui8beXjUlU_1 elephant +nvMXQKwroRY_0 person +nvaO13WFhos_0 person +nxBkP48NgKY_0 motorcycle +nxclZ6iCf7o_0 cow +nyogtZp3kIk_1 airplane +nzf12QyuD4E_0 truck +n0tx4V2rF3I_1 giraffe +n09NxJcTEYQ_0 person +n12ITkwyzvM_0 cow +n15n46culQU_0 person +n19nqH4078Y_0 bear +n2F8uNrgh1U_1 elephant +n2daSQR_dTI_0 motorcycle +n3Eb6Cf77Vg_0 airplane +n3aHtfCo_aw_0 person +n3fhSGUvtH8_2 knife +n5alwWwFPb0_0 motorcycle +n5osSY0_BSo_0 person +n5-RrJI-Lxw_0 person +n6I0k52pV18_0 bear +n8xNf-PRHnc_0 truck +n9AUV2KuhLo_0 cow +n9zSAZMj2Mk_0 knife +n-I-WnLfnqE_0 horse +n-QBM6yD7RI_0 bird +n-eDiuWYJUc_0 person +n-1FhryZboM_0 person +n_Cv1LzGol0_0 person +oBixVhXVcmY_0 person +oBjIRWu_BWA_0 truck +oCCV0-mP2R4_0 bus +oDlSzIkDJGM_1 car +oDnobYn8maE_0 person +oDrYXyIN9xs_2 dog +oEcyeE0kNFc_0 horse +oElAgrukyOk_0 person +oE0bjG0z-nk_0 person +oGDp2b_LvDA_0 bicycle +oHu9fCIhAjs_0 person +oIQuiXJzEUI_0 person +oIYCDBqfT6I_1 elephant +oIZHf-r5C3w_2 bird +oI3ETWYxCi8_2 person +oI3ETWYxCi8_1 person +oJAivZwYxDE_0 person +oLTHGMleOxk_0 car +oLTHGMleOxk_1 car +oMZczwLgR1Q_0 boat +oMZczwLgR1Q_3 boat +oMZczwLgR1Q_1 boat +oMZczwLgR1Q_2 boat +oNMf32fzYvo_0 person +oOi9E4se4ww_0 person +oOp7fTxc8qY_0 person +oOp7fTxc8qY_1 person +oQcVQukPVdA_0 horse +oRacxmfNaSM_0 cat +oSwwku39aC0_0 skateboard +oXHr2yBfL3Y_0 cat +oXfOERZ2kMs_0 cow +oXlK1t1qisA_0 person +oYw8UE0VSFk_10 elephant +oYw8UE0VSFk_1 elephant +oYw8UE0VSFk_5 elephant +oYw8UE0VSFk_8 elephant +oY5CyHk-QEo_0 person +oaHCd7KI_Fc_0 airplane +oaK_EfFOb7o_2 skateboard +oaK_EfFOb7o_0 skateboard +oa5NT5mX--c_0 person +oa838tg7QCk_2 elephant +oa838tg7QCk_3 elephant +ocJUmpBIBOo_0 person +oc7XeYj7dOE_0 skateboard +odjK5W70JaE_0 person +oeYHzAMgoQ4_0 skateboard +ofynEJHRTz4_1 person +of1ISNDelz4_0 cat +ogJGxnVqTWY_0 cow +ogNqc-uHzQ4_0 umbrella +ohkrDDXUwjY_0 person +ohrYGLaImow_0 cow +ohxeFH800SE_0 skateboard +oiftoNj28hs_0 elephant +oiwU7UpO9S4_0 person +oi4GfdQBxyc_0 person +ojiIyU5ibT0_0 person +okPcGR4BRQM_0 person +omsmPSC4u3A_0 airplane +onH8ELLteHg_0 motorcycle +oo3eTJKpErU_1 elephant +oo3eTJKpErU_2 elephant +opWm4bW5B9k_2 truck +opYiNVXmySg_0 skateboard +opkxXg1s8ZQ_0 horse +opkxXg1s8ZQ_2 horse +opkxXg1s8ZQ_3 horse +opkxXg1s8ZQ_4 horse +osYXdQYkiPQ_0 person +otKNUa-KgUg_0 car +otKNUa-KgUg_1 car +otOxAXKskbI_0 boat +otU4Zd1n65g_0 bear +otqOLpbz4LQ_0 airplane +ouK26Crplso_1 car +ouSUKHZs1Dc_0 person +ousG5WHZq8I_0 elephant +ouwAzKpUG7k_0 train +ovQiwCBG8Eg_4 elephant +ovZ4In0kLUg_7 bear +ovZ4In0kLUg_2 bear +ovZ4In0kLUg_6 bear +owW-da7Tdls_0 person +owtKQFT_gNk_0 person +ox0mlEooWI0_0 skateboard +oyuMudJ9EM8_0 person +ozRJI9h3tks_0 horse +ozRJI9h3tks_1 horse +ozvxKPrfdo8_0 dog +oz11xvTIbvM_0 person +o0QRA7gPhBI_0 giraffe +o02m7tfad28_0 person +o02m7tfad28_1 person +o09Ks_UmmkY_1 train +o3eHOnTMxnU_0 airplane +o4PVsZPaxOM_0 train +o4PVsZPaxOM_1 train +o4VOx1SeRKY_0 bicycle +o4VOx1SeRKY_2 bicycle +o4VOx1SeRKY_4 bicycle +o4VOx1SeRKY_5 bicycle +o4VOx1SeRKY_1 bicycle +o4VOx1SeRKY_3 bicycle +o7wb_t8x0D8_0 person +o8KS5SYj0GE_6 bird +o8YfQD0GA00_0 person +o9gD7-MVkJ4_1 bus +o-IwJTgdr_A_4 bird +o_sONKO9OMk_0 person +o_7RumsdAcE_0 motorcycle +pAVwx70oxIc_0 person +pAthLZfnXaM_0 person +pAthLZfnXaM_1 person +pBWgDW8f6II_0 person +pB5-haagdS8_2 bird +pEUCkpfCcaw_0 boat +pEtOW-iQZCA_0 person +pE-OFVB2lzo_0 train +pHsAHiqdb-c_0 bird +pIHbW9IMV2E_1 airplane +pIHbW9IMV2E_0 airplane +pINK56mkS-E_0 cat +pJBMnX2HBFo_0 train +pJ6wkaE8-iY_3 elephant +pKFd8IXz4K4_0 boat +pKnRcv--qEI_0 cat +pLvGIJc0ETk_1 cat +pMKMeBQzCC8_0 dog +pMKMeBQzCC8_1 dog +pMgX9KscZSg_1 train +pNG0qeNr-Vo_0 person +pNWXXO380uQ_4 dog +pNWXXO380uQ_10 dog +pNWXXO380uQ_1 dog +pNWXXO380uQ_2 dog +pNWXXO380uQ_6 dog +pP84ZurhiFY_0 umbrella +pQAJTPvkPj4_0 bird +pRArAdUzaKg_0 person +pRVlgxVhtuA_0 cat +pRy6kU2p41E_0 cat +pS5AzmSvRPY_0 horse +pU9s744_T6o_0 truck +pVR9b-qG1Ig_0 giraffe +pVR9b-qG1Ig_6 giraffe +pVR9b-qG1Ig_7 giraffe +pVR9b-qG1Ig_1 giraffe +pXLbIBluyAQ_0 bus +pXfO7xO-99w_0 cat +pYXDml6lcAY_0 motorcycle +pZCCPMu42GA_0 person +pbFuk0oX6a8_0 bicycle +pbFuk0oX6a8_1 bicycle +pbFuk0oX6a8_2 bicycle +pb3p83fw9bg_0 person +pcUV4ja1VRc_0 truck +pceUU6aj_ao_0 cat +pdyhFh6-rCo_0 bear +peBxgn7gXlw_1 motorcycle +peHZd4qdOMI_3 boat +pe00hbvqjDI_0 person +pe_73GR1-NI_1 airplane +pfED6WafVwQ_0 bear +pfpKoO-GjGI_3 truck +pfpKoO-GjGI_1 truck +phXjZ1yxWD0_0 bus +phec6_yC2HY_0 person +phjJhuKxT5Y_0 train +piGT-hRYHHQ_0 horse +piN1RiueJhY_0 horse +pjLei6UAHsE_0 airplane +pjLei6UAHsE_1 airplane +pjZqJuEX1ow_0 airplane +S2FTgueR-80_0 person +S2FTgueR-80_1 person +S3U383sqlRs_0 bicycle +S4UDIyyqmlY_2 motorcycle +S6h6E0IKO6Y_0 dog +S73sRU7b2dk_0 person +S9QmlxGGxGM_4 knife +S9goDsKFXAg_0 person +S-qgaqzenIE_0 person +TBpnes8Z-3s_0 person +TCtRzPGrwls_0 horse +TCycfRWpg0s_0 elephant +TDKDtLliMhg_0 person +TDlLgW8Fjes_0 person +TFcak4kNd2c_0 person +TGFSBSitWNw_0 cow +TISjnLr1r-k_4 giraffe +TISjnLr1r-k_5 giraffe +TISjnLr1r-k_3 giraffe +TJsLSuQcb7E_0 horse +TKadOIk-uPI_5 truck +TK61mJMHqTE_0 train +TK61mJMHqTE_1 train +TLxcXucOpWw_0 skateboard +TMaLrtjFU34_3 cow +TNNXwm3Bt5I_0 bicycle +TOLyNcTSGPA_0 person +TPglVxQN85I_0 dog +TRH4PZkAkiE_0 person +TSl3wSreplo_2 bird +TSl3wSreplo_0 bird +TVuX76wWzwY_0 person +TW9LBSqxNWo_0 bicycle +TW9LBSqxNWo_2 bicycle +TW9LBSqxNWo_6 bicycle +TXD-idarfhU_0 person +TYsJu2G5WVY_2 knife +TZdDUMDyozA_0 dog +TZfFEYUY5_0_0 boat +TZsigdW7Qfs_0 airplane +TaL6ssJD8z4_0 airplane +TalhQQ9B7vc_0 zebra +Ta-JBO0InZk_0 horse +Ta-JBO0InZk_1 horse +Ta-JBO0InZk_2 horse +Tbm_BFLOPic_0 train +TcRl6wotFw4_0 horse +TcR9fR_SWLg_0 bicycle +TeiC-tObc4o_0 bicycle +TgRRY3Mn0Ro_0 person +Ti411VXWtAc_0 dog +TjCiDUNoDi0_0 skateboard +TkktEeCiSAo_4 knife +TkktEeCiSAo_5 knife +TlXSJmmN3dc_0 motorcycle +TnB8G7eZm24_0 person +TnY1qP0YQQ8_0 person +Tnc7CCuk78Y_0 person +Tn4trDBJAqE_0 person +To8VzjtX70s_1 person +To-lnvpzIKY_0 person +TqKcS4Cx7wc_0 bird +TqvuyyM_x4E_0 bird +TqvuyyM_x4E_1 bird +TsM45PkaTj0_1 bird +Ts4iqmKVRy4_0 knife +TtI1W2xFQ5k_0 person +TtI1W2xFQ5k_1 person +TtnuIzV01ek_2 train +TtyfhN-jWcc_0 person +TuEArk4EFWg_0 person +TuEwZSEUe5A_0 person +TuOnAlE6TRs_0 airplane +TubHgt_FxYo_0 person +TufSi0uSU8M_0 person +TvUmQi32j08_0 person +TvUmQi32j08_1 person +TvuhORVyaL4_0 person +TvuhORVyaL4_1 person +TwH6hv5zVIU_0 airplane +TwSnlq5Kma0_0 skateboard +TxV4qpdgJ3Y_0 airplane +TxV4qpdgJ3Y_1 airplane +TyIzjLHGvjo_0 person +TzUMxAOWWcc_0 bicycle +TzVawH7veiM_0 bicycle +T0WCoXgklkw_0 person +T0r5yfzMs4g_1 bicycle +T24d3EHv2GE_0 bird +T406qi8vIlk_5 airplane +T406qi8vIlk_2 airplane +T6XxSbeAl6Q_0 motorcycle +T8e9Qi4dcNY_1 bear +T95G52MuPFU_0 horse +T-PL14w9TV4_0 cat +T-cOBQACeAw_1 bird +T_2A3L49ah4_0 dog +T_2A3L49ah4_2 dog +T_2A3L49ah4_3 dog +T_2A3L49ah4_5 dog +UANkhHNWM-M_0 person +UAnl6TGZhxs_0 cow +UA5VCImEZ2Y_0 dog +UBdNIuCPaZ4_0 car +UBdNIuCPaZ4_2 car +UBsG3-ocU64_1 boat +UE40h6VhUaU_1 bicycle +UF8l_MU2rj8_0 person +UGCPxfU7FKM_0 person +UG5FFY29OV0_0 cat +UHO129a_p0U_0 airplane +UHYwdGF9W-0_1 horse +UHYwdGF9W-0_0 horse +UIvJPTYu6Hc_0 train +UI4IvmmFIPQ_0 person +UKExOybWiRM_0 motorcycle +UKExOybWiRM_1 motorcycle +UKkr05PKrb0_0 bicycle +UKlB9mDIXss_0 person +ULdZGJs5ta8_0 motorcycle +UMsR07JXCYs_0 cow +UM446G0Lud4_0 knife +UOUaveJ_TWA_0 person +UO_zNFtEt3Q_0 person +UPkEE2dnlkU_0 elephant +UPkEE2dnlkU_1 elephant +UQAJPD_gH7g_0 cat +UQDXdgIlpDg_0 knife +UQibn_ZNp9Y_0 skateboard +UQibn_ZNp9Y_1 skateboard +USAjeRaDlJ0_0 person +UTqlz0i9KIo_0 person +UVTPHohbCV0_0 person +UX4dpwv6qWE_0 dog +UYAtAlnvVy4_0 skateboard +UYc0lVVxayQ_0 dog +UcCtmXy5F4g_0 dog +UcbWaG8GwRs_3 airplane +UcbWaG8GwRs_2 airplane +UceYFW8-zZM_0 train +Ucse975FqUA_0 elephant +Uc5PAhXhIzk_0 umbrella +UgsSu7wC28w_0 bird +Uhj0HRMHPXY_0 person +Uhsh3JUb_aI_0 bicycle +UisVwousE8g_0 cat +Ui8yPflhqHs_0 person +UjMTd3LCxyQ_0 person +UjMTd3LCxyQ_1 person +UlFA0xDQcS4_0 skateboard +UlhZSONgFCI_1 cow +UlhZSONgFCI_2 cow +Umvp1XgX6Qc_0 person +Um-FzEOyncc_0 person +UnUlhJaHWlA_0 bear +UnyyMjT0BCc_0 horse +UsCJdEa7tq4_0 dog +UsCJdEa7tq4_1 dog +Usrv7_ONvi0_0 horse +Us6dL_WD7xg_0 truck +UtyaA_QRIrQ_0 truck +Uu9k1VohpvA_0 horse +UvptsJcl_ms_0 person +UwtHiozuyRs_0 person +UxPh-hnwal4_0 truck +U2LvNquzuZ0_0 bicycle +U2LvNquzuZ0_2 bicycle +U4LhReaGH70_0 person +U64eMon0R9w_1 person +U74o2HGsFeI_0 dog +U853uMV0qAY_0 person +U86p5VtUC6c_0 knife +U9YbGyTBb5k_0 person +U99ENpOmVGI_0 airplane +pmrTy1xQ5kI_0 person +prJIAYsv8bQ_0 truck +pramqy_Y1gA_0 boat +prlcpxzCoyc_0 bus +ps-nNC6Equg_0 cat +ptF2Hqj7DGk_1 motorcycle +ptF2Hqj7DGk_0 motorcycle +ptPi712LDq0_3 bear +ptU4EDudgg8_1 bus +pt6v3JZFi4c_0 bird +puifEp7W50E_0 motorcycle +puifEp7W50E_1 motorcycle +pu0G99aVryc_2 car +pu0G99aVryc_0 car +pwFqv42foTM_0 person +pye4y8sPr9I_0 person +py0U90-ZTkI_0 cat +py2dhJjpOaI_0 bear +p19EU6tw9oM_0 person +p2DntTqvGT4_3 car +p2DntTqvGT4_1 car +p2QsmFuYxdI_0 train +p2TTKNDiGv0_1 bicycle +p4pf9W4qt8s_0 person +p40Oqh_akS4_3 bird +p43GludvR_g_0 bicycle +p5F9hHDkbKc_0 train +p7UAl7_bv4s_0 bus +p8KQvF1DyLg_0 person +p8YhfWsz1JY_1 person +p8YhfWsz1JY_0 person +p8gE3VpTAR4_0 person +p84Z-poVaAw_0 motorcycle +p9ixpjYEEag_0 motorcycle +p-J_LbVq7CU_0 person +p-SJ_Ym5pTA_0 cow +p-XasPaki0k_0 cow +p-cJamorAiY_0 person +p-2rgSte1DI_1 bus +p-2rgSte1DI_2 bus +p-6u3d8YV70_0 person +p_YVPahadQ4_0 elephant +p_YVPahadQ4_1 elephant +qDP6_m4bDRA_0 horse +qD8NS4r2Gd8_1 train +qEjyhyeCIR8_0 cow +qEjyhyeCIR8_3 cow +qEjyhyeCIR8_1 cow +qEjyhyeCIR8_2 cow +qGiLjP8-EVQ_0 person +qHYuGyp8_HU_0 bear +qHZsnSLmqEY_0 person +qIJo1R3rHmQ_0 person +qJI7mnjOp0A_1 umbrella +qJOaXM8s-Yo_0 knife +qJOaXM8s-Yo_1 knife +qJugj62heF8_0 airplane +qKqEqxMZHVg_0 person +qM566R4U4Ug_0 bird +qQbEwbtvdRg_0 person +qSR2E4eqjqI_0 skateboard +qSiMwC5e5_I_0 person +qUGXSXCXUbw_1 person +qVCH1ozivyk_0 person +qV9Ll-N_rpc_0 dog +qWpIdTdBIQU_0 boat +qWpIdTdBIQU_2 boat +qWpIdTdBIQU_3 boat +qXaS7daelL4_0 person +qXfnmaLtO-M_0 airplane +qXwXdnrUo5w_0 train +qXx4Vj-HwkU_2 bus +qYf_XBAUa_o_2 elephant +qZFwurCX4DM_0 train +qZH-IY7bBzg_0 person +qZQcY5PTh10_0 cat +qZVUho1xBlo_1 truck +qZVUho1xBlo_2 truck +qZVUho1xBlo_0 truck +qbYjOWN6n70_0 horse +qceiUxIt1VE_0 car +qcjVVDAbHUI_0 person +qcmbCgcy3co_0 person +qdNXPwWD9_Q_1 person +qdzu1EFDYUE_0 cow +qel4U0nmQOI_1 person +qfp7BvAtQa8_0 person +qgKnno5T6f0_0 motorcycle +qguyMwcAj4M_0 person +qhb1bts1fSM_0 bear +qheo-lRVpfk_4 knife +qheo-lRVpfk_0 knife +qheo-lRVpfk_1 knife +qheo-lRVpfk_2 knife +qheo-lRVpfk_3 knife +qhmscyJC8dM_0 elephant +qh8xnvGfllE_1 bird +qh8xnvGfllE_2 bird +qipZi2kaQyA_3 person +qi3hoxEao_g_1 person +qi3hoxEao_g_2 person +qptB3_MZagA_1 horse +qp5tJGAi9h0_0 airplane +qqL9gnwx87g_0 cow +qqL9gnwx87g_1 cow +qq4_m1S3AOI_0 person +qt6FFVa8DGM_0 person +quoX4193twY_0 dog +qvMRVm660LM_0 person +qvZGFb3CbxA_0 bird +qvcNxorHqCc_0 person +qx647iZCsoE_5 umbrella +qyQFBM_7mBw_0 bird +qywYqT8IzaQ_0 skateboard +qz4S2Tn1Jkk_0 person +q2qEXqY43ws_0 cow +q2v3AmGBH-M_4 train +q2v3AmGBH-M_1 train +q2v3AmGBH-M_5 train +q2v3AmGBH-M_6 train +q3TB2Rnymkg_1 truck +q3pYgC4-lrs_0 elephant +q35X7FnaiGw_2 bear +q5BC4AVKV4c_0 person +q6nXZqEmQGQ_0 person +q9MXoyUF-BU_0 person +q9d2hPrip6k_0 dog +q_dqx0-AtKk_0 person +rA595TIyUgY_0 bird +rBko9NgVOX4_0 person +rB2323YW1iA_0 cow +rDQ2hcIWoBY_1 train +rEXtAqxJj8c_0 person +rGVf1BsLfng_0 cow +rHvp_Dghuho_0 person +rH33U6qgd9M_1 umbrella +rIqhuv94Zuc_0 person +rKN5E25jozk_1 person +rKN5E25jozk_0 person +rLbBCTSGdzc_0 person +rOoxhMEKcgc_0 bear +rPEIT9eAAMY_2 bicycle +rPEIT9eAAMY_3 bicycle +rPUzTjaLdkk_0 cat +rPuPm0ctC3s_11 train +rQHtu5_Piv4_1 cat +rQKV6GBQuag_0 airplane +rRH0VLQDJZQ_0 person +rSF1UQ01lZc_0 person +rSSbdX8817Q_3 dog +rSu82skaMJQ_2 skateboard +rSu82skaMJQ_5 skateboard +rTIN784f0CM_0 train +rTIN784f0CM_1 train +rTIN784f0CM_3 train +rTV3ev-xyuk_0 train +rTYmEM2Lhew_0 bus +rT4P9ZJeBG8_0 train +rT4P9ZJeBG8_1 train +rT4crgFLycE_5 bicycle +rUJ7zeax1zY_0 person +rV1Baq6-C6Q_0 elephant +rWyf2iqpfng_0 horse +rXf2T3VO-kI_1 cow +rYkLuW5NLic_0 train +rZi9k9F8S1w_1 person +rZi9k9F8S1w_0 person +rbIYpEELMQc_3 horse +rbIYpEELMQc_2 horse +rbMVAO2mJiY_0 person +rbn7_DeuItc_0 elephant +rcF4-O7o_Qk_0 person +rcF4-O7o_Qk_1 person +rc96rbja6VI_5 skateboard +rc-e_NDrZDM_0 person +rdBSfuG2KBA_2 boat +rdBSfuG2KBA_0 boat +rdQvGZDUDJA_1 person +rdhiEKvYF0w_0 car +rdnDsUHCZSY_1 cat +rePM3_x9tqw_7 person +rePM3_x9tqw_4 person +rePM3_x9tqw_5 person +rfL51BZGldc_6 truck +VCkpd_d1z4U_0 airplane +VE-3PfVw5-Y_1 airplane +VG2QbeXEwec_0 elephant +VIQGgTWrg00_0 person +VIr_rdbfvQQ_0 horse +VJVWk9wyMjI_0 cow +VJmgPBopcB4_0 horse +VJ0by87MRoI_4 bicycle +VJ0by87MRoI_7 bicycle +VLSeTnShp54_0 motorcycle +VLSeTnShp54_1 motorcycle +VLSol2tA9WY_0 elephant +VLcSoFR7qBw_0 car +VMDBBz7G-Pg_0 motorcycle +VMmtrv5OtMQ_0 boat +VMxS4op_OBg_0 person +VNCLtdahLmI_0 bear +VNCLtdahLmI_3 bear +VNHGw5Sj0Qc_0 person +VN8_N7Ceofk_0 cow +VP0WD1miM00_0 horse +VP20LIiI9S4_3 horse +VP20LIiI9S4_7 horse +VP20LIiI9S4_1 horse +VP20LIiI9S4_2 horse +VP20LIiI9S4_5 horse +VQWxUc9QOjU_4 bear +VRtl4gAWELM_0 skateboard +VRt9s3OQPzo_0 person +VSLdNogDia0_0 bird +VSrmwgo-veI_1 boat +VTqoizpYNeI_0 car +VTqoizpYNeI_1 car +VTqoizpYNeI_2 car +VTqoizpYNeI_3 car +VT11p8szxZY_0 cow +VUVAbtGJbuE_0 person +VUh5jCDWj08_0 cat +VUl6vkX7PRU_0 airplane +VVn3XeSqijk_2 motorcycle +VWTes_MfrOc_0 knife +VXNEqQb5C4Y_0 motorcycle +VXT0TH9jfZo_0 elephant +VXZscyYzxqw_1 person +VYYS45KWEgo_1 dog +VYr49ml0uaE_0 person +VZj4RHsnOWU_0 person +VZqdzb_qI2g_0 person +Va81siK4zeI_0 umbrella +VdLqI43E7eY_0 cow +Vd5pCJuOoDM_0 car +VfBrelUfLFg_0 cow +Vgpm6fwLIns_0 motorcycle +Vhc7DKkRHOo_0 dog +ViQIgBdCkh8_0 car +VlBlBgxUa-U_0 horse +Vlq4fYmrr6g_0 car +VmVN4E_qtfM_0 person +Vm9-f0pXycc_2 bicycle +VngapMBo560_0 cow +Vou-Sfzlpu8_2 train +VqdeO4pa_rc_0 elephant +Vqj-Qv5bVyE_0 person +Vr1Wqz5_UA0_1 cow +Vr1Wqz5_UA0_2 cow +Vr1Wqz5_UA0_0 cow +VsAo8VBzDTM_0 person +VsOw_U6hYRY_0 motorcycle +VsOw_U6hYRY_1 motorcycle +Vsyd7-_CUA0_0 person +Vs2JphYinjk_0 giraffe +VtdrYDJFw-Y_0 person +VtkV11WZWEc_0 cow +VuDA6sPAa9U_0 person +VuLf3ZTqniM_0 dog +VuW2wDK-uZI_0 motorcycle +Vv-z9_l8_ms_0 bird +VwdZHZPjlT0_0 cat +Vwkf0U9PZvI_0 airplane +VwppYMiCI1g_0 umbrella +VwvER7iR2YI_0 person +VxG5gvk1mfo_2 elephant +VxH52JoUd0I_0 person +Vxyq13mC_uk_0 person +Vxyq13mC_uk_1 person +Vyf_VJEQ1jE_0 airplane +V0CjVa5_1P0_0 horse +V0sliERbCxI_0 person +V0sliERbCxI_1 motorcycle +V0w_hBBqe-g_0 person +V1ufPW4ictQ_0 skateboard +V25H8smvzbM_0 dog +V56RVnEPG54_0 motorcycle +V6rg5et7Q14_0 cat +V6rg5et7Q14_1 cat +V6_XA2w3sTs_0 boat +V7CVQjk9-Xc_0 skateboard +V8Pv-I4ovPs_0 person +V9m1dMbXxug_0 truck +V9qvycn1a3E_0 train +V-ZKLxW5cuM_5 horse +V-ZKLxW5cuM_2 horse +V-ZKLxW5cuM_4 horse +V-iFCgvAuCg_0 person +WBcYTIQ65Ow_0 person +WB6uQ708AxE_0 bird +WCNpGdfG8nk_0 person +WCZ4ZQ5ohf4_0 motorcycle +WGw94BtHxYE_0 bird +WGw94BtHxYE_1 bird +WG1DuTb70bQ_0 cat +WItuBm7azO0_0 cat +WKpjUNNgKG0_1 person +WLZkZ-4Y9fY_0 cow +WN5u1Y1yGkA_0 airplane +WP5JXCVRe9g_0 person +WP5JXCVRe9g_1 person +WQ603pEp_1k_5 airplane +WTEO_Ywn9AI_0 umbrella +WTw46mBWjOw_1 airplane +WUvTKLEimNw_2 truck +WWcVr4lbq3E_0 person +WXETP4eMyD0_0 cow +WZWh1M3qGAc_0 truck +WbXmf511q4E_0 horse +Wb9i7jssQsY_0 motorcycle +WcUFxXISmb0_1 motorcycle +WcUFxXISmb0_2 motorcycle +WcgQXl6I-Ks_0 car +Wc6RwJ_8yts_0 person +Wc_-Q9ba0zs_0 airplane +Wdh2SMcRQ2M_0 horse +Wdh2SMcRQ2M_1 horse +WfZR-VRmSB0_3 boat +Wfl0LOShC_I_0 bus +Wh9avYClECA_0 person +WixZlWbnBdM_0 person +WkvpcaxQTSg_0 dog +WlFD1z5akJc_0 person +WlK6sU21od0_1 dog +WlP5_pcua1U_1 truck +Wl1vbjfAxeA_0 dog +Wl1vbjfAxeA_1 dog +WmNKtcf5iLM_0 person +WpxEmYBfqSU_0 elephant +Wqb84sv1P68_0 cat +WrClMyPxaDk_0 person +WrSS3nc07hE_0 cat +WsFZj4Bgtwc_0 bicycle +WvGCvwHutAc_1 airplane +WvUiJ8ZRRfc_0 bird +WvUziN47FfY_4 horse +Wwx2Vce-1oM_0 car +Wx0zNFqSUZo_0 horse +Wx1qid26zsw_0 dog +WzCI6AqY7cg_0 bus +WzrI82-Ak4I_1 motorcycle +W1juH0nZ8v0_0 airplane +W1yEDHYLG1Y_0 truck +W14Nt0_EGQg_0 person +W17CFtB5Oy4_0 truck +W1-9iBLd1lg_0 person +W23FACVBLgI_0 person +W3Bv11o03TQ_0 cat +W4cKlmHvXZ4_0 knife +W4gR7_z77A0_0 person +W4iSCn6ILJs_0 motorcycle +W7xlWK7cuEI_1 skateboard +W8U3FkkaVbc_0 person +W8d2hNOMHpQ_1 horse +W8yL4Qnuo4k_0 elephant +W86rN6nrllQ_0 person +W9lLrNUFQ9M_0 person +W975mcNRX7c_0 boat +W-sCMBY47ck_0 horse +W_QxijO2VBw_0 zebra +rftE7M9tNqI_0 person +rftE7M9tNqI_1 person +rhWLgPl3lt8_0 person +rhjcRHB4crY_1 bicycle +riNqBOlFCuw_3 dog +riVZCbT4LDE_2 person +rih7ECmHfRs_1 cat +rkIzABhjHkA_0 person +rk1ByqQSwtI_1 elephant +rlWlgyP-3-s_1 umbrella +rlWlgyP-3-s_2 umbrella +rlWlgyP-3-s_4 umbrella +rlqtE0bF9nk_0 bicycle +rmVxFro55IQ_0 skateboard +rmxx9X1ytcA_0 airplane +rm4XeENehOU_0 skateboard +rn9-fIMYEkA_2 motorcycle +rn9-fIMYEkA_0 motorcycle +roUwF9YU21U_0 person +rsne3z-CaDw_1 train +rtjlk_iOmdE_2 train +rtjlk_iOmdE_0 train +rt4Qm6HPVTY_1 boat +rvBm-SnbjVI_0 cow +rwQl_jKPcyM_0 person +rww5DvtCsG4_0 horse +rwzjQSTLmhk_0 person +ryUMZWWwJUk_0 person +r0P-2rp1Hpk_1 bus +r0vIwhp5RLo_0 knife +r03Za0dP0d8_0 person +r09YKBrwa8M_0 horse +r3PUq_cy6Mc_0 truck +r3cOrAN6BI8_0 train +r3cOrAN6BI8_1 train +r7WW1Fl-s6s_5 bus +r7WW1Fl-s6s_4 bus +r7WW1Fl-s6s_6 bus +r7WW1Fl-s6s_7 bus +r7WW1Fl-s6s_1 bus +r7xw4qHLKIY_2 horse +r7xw4qHLKIY_1 horse +r7yOsosLuHI_0 cow +r8NwODfEuhI_0 dog +r8NwODfEuhI_2 dog +r9LAMeOEcsI_0 person +r9jyOtbfWs8_0 person +r9osF8drSbo_0 person +r-Dva6GT-a0_1 dog +r-tFy30HVCw_0 person +r-0UD9KQhvY_0 car +r_sRdP_5WaM_0 skateboard +sByCUshWhWs_0 dog +sB613NHl89g_0 elephant +sB8zpg-GrRo_0 person +sD_9McrL3UQ_0 skateboard +sD_9McrL3UQ_1 skateboard +sEzZ3JnSzaM_0 bird +sFxTS449nUg_0 person +sG0q9rphsoY_0 cat +sIIFHk89TT0_0 person +sI17jkxX6tE_3 skateboard +sJyknuUaIOg_0 skateboard +sKCW1p03okE_0 person +sKD6TBNqy6s_0 person +sKD6TBNqy6s_1 person +sKJ0JtWZeWw_1 cow +sKJ0JtWZeWw_3 cow +sLZh8XaxoYw_0 person +sLfyo1VrX3g_3 knife +sLfyo1VrX3g_2 knife +sLnYAS4LAY8_1 person +sLnYAS4LAY8_2 person +sMVMaH9aWHw_0 horse +sNV29dtSqYs_1 umbrella +sOfNz788QiQ_2 horse +sP4jeoUjHZM_1 motorcycle +sRb7OHsI6s4_0 bird +sV9L8gpGDmA_0 motorcycle +sWbk2Sw9Rew_0 person +sWfMpwviOCA_0 car +sXSjs2EV61Y_2 knife +sXw73oA1Tq0_0 horse +sX5GCwZG8d8_1 bus +sbkHA-DWPSI_0 person +scyRfbyCzJU_0 cat +sc15m4_lcvw_0 person +sdAAObJErSA_0 motorcycle +sezamC2zGqg_0 bird +sf76JIFYKB0_1 cat +sgHdQYSWPXg_0 car +sgU4wTZ6k5s_1 person +shXeONsfVmU_0 person +shiIdcOonRs_0 person +siFucH6jjIs_0 boat +siFucH6jjIs_1 boat +sj7NOYq8KBA_0 person +skEWWsL6k9g_0 horse +skl1lsZUG4k_0 person +sm346w9J4zA_0 knife +snZjH03fjVk_1 person +soNDR07vxhQ_1 person +soNDR07vxhQ_0 person +sofKbpbuX84_0 person +sofKbpbuX84_1 person +spVw0PNXErs_0 dog +sqLiQtbkEO4_0 cow +sqv-uPhtxwk_0 airplane +sq-wqsIw5hw_0 train +ssspgc75B08_0 giraffe +steKGH-8MZw_0 horse +steKGH-8MZw_2 horse +sts2vAv4BQo_0 person +suERIXWx_z0_1 person +svCBYM2zl80_0 horse +swuFjNkTmQY_0 dog +syZTh043BkQ_0 horse +s0YqBVjRDyU_0 person +s1Pd7evRn0U_2 dog +s2PyqAoOqrY_0 cow +s2x8llFphNY_0 elephant +s3WiR_wFUBE_0 cat +s3ijyNmvxpE_0 person +s4rr5OrSI4k_0 skateboard +s5I219neN7c_0 person +s5jmkD6lkbU_0 dog +s5n7L55KpWE_1 skateboard +s7or9ZhEyXE_0 person +s74eu-v6aqA_0 person +s8W4NK7dWe0_0 person +s83wzR7ySyM_0 skateboard +s9G4llLAJiU_0 skateboard +s9OmvmQH9hA_0 elephant +s94ng_sG6Dg_0 boat +s-Jnbfjkmak_0 skateboard +s-Jnbfjkmak_1 skateboard +s-guJTrtfSU_0 skateboard +s-yjgHx_YWg_0 train +tAGvlfgdOsI_0 skateboard +tAGvlfgdOsI_2 skateboard +tBlPdyu-syw_0 bird +tBlPdyu-syw_2 bird +tBryhvKADFQ_0 dog +tGyP_SbWsVA_0 person +tHA_VdGe90Y_0 airplane +tHA_VdGe90Y_1 airplane +tHcqw8Cejs8_0 person +tHfOMcj62SY_0 zebra +tI2i9_rBdwo_1 bird +tI2i9_rBdwo_3 bird +tKpbcnqu6bY_0 bird +tK0pl2_wbWU_2 elephant +tLJpuELQgxY_0 person +tLa4F5ekKW0_0 cat +tLzUBeOwhyM_1 bicycle +tMojfxB-9zA_0 person +tMp5Y1zucfI_1 train +tMp5Y1zucfI_0 train +tM3FYC5IVPo_0 motorcycle +tNiu2o7-KPY_1 car +tOK5TnF8eHQ_2 bird +tOL0kPV03Uw_0 train +tOlXErF8Z4o_0 horse +tPCRXfE_aGo_0 bus +tQj85vHtmeE_0 bus +tQnUccPTkck_1 truck +tQ_Vy-9pvoQ_0 skateboard +tSlXTInFXss_0 person +tTSVU8IU10c_0 motorcycle +tUdWqmNDeY8_0 person +tUm_oehvEpM_1 person +tVOS6wht6oQ_1 horse +tV17SBx-oqE_0 person +tXBDRj1c-Uc_0 person +tXf9xVs5ZGk_0 train +tYKrjpIMYb0_1 skateboard +tYciFvRQuec_1 truck +tYciFvRQuec_0 truck +tY-4fAv_YRU_0 horse +tY-4fAv_YRU_1 horse +XA65Kh83GmE_0 cow +XA65Kh83GmE_1 cow +XBNPaOqVqds_0 bird +XBUvxtvKWM0_0 cat +XByg_hQRQDM_2 bird +XDNVcbDkafM_2 airplane +XDNVcbDkafM_3 airplane +XDNVcbDkafM_4 airplane +XD0ydIAwgGM_0 cow +XD_iMe4m2vQ_1 person +XGX6SRd3ZkE_0 bird +XHu9PxuBpXg_0 airplane +XIzQLXQTsRo_0 cow +XI3_0lXrnfY_0 cow +XJq9qp3jhq0_0 motorcycle +XJq9qp3jhq0_2 motorcycle +XJq9qp3jhq0_1 motorcycle +XLgI0VgtzEw_0 cow +XL50qkg4qdA_2 elephant +XL50qkg4qdA_0 elephant +XMIsf8xuMh4_0 train +XPi83QmsR90_0 cat +XQliC40rP9M_0 person +XRKZRwdqhNo_0 bird +XSMGAlakHWY_0 person +XS5wfvz6XZI_0 bird +XTWeBFPqdh0_0 person +XT0t6ims_FI_2 skateboard +XVabRVMuX4Q_0 motorcycle +XVabRVMuX4Q_1 motorcycle +XVabRVMuX4Q_2 motorcycle +XVabRVMuX4Q_3 motorcycle +XVabRVMuX4Q_4 motorcycle +XYA6HKrVVQQ_0 cow +XZBFfRl6DkA_0 person +XaVZr4HPh2M_0 cat +XalkAzccT5I_0 person +Xa6tjMVGH2I_0 motorcycle +Xa6tjMVGH2I_2 motorcycle +Xd9tLIFo_7E_0 cow +XeIssB-JkcU_1 bicycle +XeIssB-JkcU_2 bicycle +Xevq2dskQWo_0 truck +XfUIrHPVj-s_0 cat +Xf09qM8SYBc_0 truck +XgDJ16iRhxs_0 elephant +XgDJ16iRhxs_1 elephant +XgDJ16iRhxs_2 elephant +XgFaXb7Vb58_0 elephant +XgxYznR79R0_0 dog +XhOx4rgdI-8_0 bird +XhTWW9CwFzM_0 motorcycle +XiSjHcHG5IU_1 bird +XjXFktrwSOk_0 bear +XkpxlUwx4oc_5 truck +XkpxlUwx4oc_1 truck +XkpxlUwx4oc_2 truck +Xkr3OHSz_CA_1 person +Xkr3OHSz_CA_0 person +XlIxLJTiphI_1 airplane +XlSvIczm3JA_0 person +XlcJsAWbsyA_0 dog +Xmwv-NZZat8_0 person +Xm_CKSNQE3E_0 bird +XnfAvhHnH6M_0 train +XnfAvhHnH6M_1 train +XoWHAeOAXg0_0 motorcycle +XoXMpm6Yxfs_0 person +Xoa_dCJDiTE_0 motorcycle +XocaP_gyqJU_0 person +XopbyM2SJbc_0 bicycle +XopbyM2SJbc_1 bicycle +Xr_3UPISgT0_0 skateboard +XsK5KxttYBA_0 person +XtTLGRBrm3I_0 skateboard +XtVTdegdzvI_0 motorcycle +Xu6xzBcJySk_0 person +Xu6xzBcJySk_1 person +XvvA9Zc1TMA_0 person +XvwOXlVdehA_1 person +Xwqm_wzZDQI_0 cow +XxkkXeLqqu8_2 airplane +XxkkXeLqqu8_0 airplane +XxmNQjB1D_Y_0 cat +XyldpxZmUN8_0 dog +X0CZDjRqcKg_0 horse +X02e7Fj9BLM_0 umbrella +X0-n3maCrZU_1 dog +X2uXOY9J_UU_0 person +X3HCAEcRaW8_0 bicycle +X3qbUW_qT7k_2 airplane +X4SbOXRpo0A_1 dog +X7xm2nZL7jc_0 bear +X79vSvy6SOQ_0 skateboard +X9L-jwA6Ozg_1 train +X9L-jwA6Ozg_0 train +X9a5wEDFXc8_0 boat +X_TnIuY27eM_8 bird +YA4-rm-dcsw_0 person +YA-N841dD-0_0 person +YB1trUAUzhg_0 person +YB2wzBLh7MU_0 zebra +YCU3daBCWsU_0 umbrella +YCXHNoYaQRc_3 skateboard +YCXHNoYaQRc_4 skateboard +YDd_skWNTMs_0 skateboard +YDyc1Yv9j_s_0 person +YEPfw3k3vEw_0 person +YEvBzZ5KBYY_1 horse +YEz7v7toUwM_0 truck +YFQlAc3qTBQ_0 motorcycle +YIHcQxH9e1o_0 train +YIzqB2G1UvY_0 person +YI4lmC3imb4_0 horse +YJiqdRcs_gU_1 person +YKlWROFtcxc_1 skateboard +YKlWROFtcxc_0 skateboard +YKoT-GgRSw0_0 elephant +YKoT-GgRSw0_1 elephant +YKrdwZe1vq8_0 dog +YL97h6yps6w_1 knife +YMbqULxZJpg_1 horse +YMbqULxZJpg_2 horse +YMkOJNatD88_0 person +YNEDPsAWm5I_0 person +YQXwRsP0zvE_1 person +YQgUV8TrYcw_0 person +YRWC7Tdc5oI_0 person +YTD8j8z44qQ_0 person +YTd8Rxtpt1E_0 train +YTd8Rxtpt1E_3 train +YTd8Rxtpt1E_4 train +YTd8Rxtpt1E_6 train +YTd8Rxtpt1E_7 train +YTd8Rxtpt1E_8 train +YTd8Rxtpt1E_9 train +YTzuVYGpDhA_0 motorcycle +YUhgrCNuMGQ_3 bear +YVDCTyDcjjA_1 cow +YWRbi_v93Mo_0 person +YWhwljQ3efA_3 train +YWhwljQ3efA_4 train +YXeaiwTZ3ZE_0 cow +YXz7CDJ11jY_0 bird +YYUo7EkkJeg_0 bicycle +YYUo7EkkJeg_1 bicycle +YZmhYkqgBi0_0 skateboard +YZmhYkqgBi0_1 skateboard +YZmhYkqgBi0_2 skateboard +YZ3kcrHk4N8_1 horse +YZ3kcrHk4N8_0 bicycle +Yax1xdgRbt4_0 person +Ya2zfpe-_ro_0 bus +YcjMrWCSRSA_0 person +YdooYDhKq00_0 person +YeTYMiaLkWY_1 cow +YfvvO_T8j8k_0 skateboard +Yf9jBSXQTLo_0 car +Yf9jBSXQTLo_1 car +Yf9jBSXQTLo_2 car +Yf9jBSXQTLo_6 car +Yf-okdUBk9g_1 bird +YgM058nmMnQ_0 person +YjZoPTjqDGw_0 skateboard +Yj6XWsgomO0_0 cat +YluDona_474_2 bus +YmlQVVQx4SA_0 person +Ym3lE2u4vxE_3 skateboard +Ym3lE2u4vxE_1 skateboard +Ym37vW7b0U0_0 cow +YnZU-Qa6yeI_2 bus +Ynyd8SBB5Wg_0 knife +YoFfsRgrNeY_0 person +Yof6XFKNuNY_2 horse +YorREGtes1I_0 person +Yo9XVrgl_GM_0 cat +YpDsXa1kNZU_0 truck +Ypb0U6Ga5pk_3 train +Ypb0U6Ga5pk_1 train +Ypb0U6Ga5pk_2 train +Yp1kl6xU-Og_0 person +YqvGb_tDI38_1 bird +YrhvCSxifRc_0 car +YtrNZ4mlMw4_0 elephant +YvAlZo3quqE_0 person +YvwW9T4Qpek_0 motorcycle +Yv3YH0nImQI_3 truck +YxRG0JQrpwI_0 person +Yxia21K4O6I_3 truck +Yy0lIDbLxQ8_0 elephant +Yy0lIDbLxQ8_3 elephant +Yy0lIDbLxQ8_1 elephant +Yy0lIDbLxQ8_2 elephant +YzTl0Nf0Kpw_0 cow +YzT_UsE8Mhs_0 airplane +Y0Hz5Hw1AiM_0 person +Y1lKSppJhdI_0 cow +Y16c_yGYw1M_0 elephant +Y16c_yGYw1M_1 elephant +Y2jXJzRVhMI_0 person +Y2x6ow80IkQ_0 person +Y3TtBVfW6gs_0 person +Y3ZDfyDvFi4_0 elephant +Y3c_6Zv0dxg_1 knife +Y3mx4jYyagQ_0 train +Y5Atu2VWemQ_0 train +Y5BEvakwvuM_0 dog +Y64ky0LNHko_2 elephant +Y-YU80ccuXg_0 elephant +ZBJsNXYIQ4o_0 person +taPyucc_cOU_0 person +taPyucc_cOU_1 person +tafdN9GXP0g_2 skateboard +tbLnjlX1xF8_2 bird +tbuu2U3o02Y_0 person +tcOx8KjmHPo_0 person +tc98WTYT-VI_0 elephant +tdIWlg4_01E_1 bird +tgRYkhC-gJU_0 person +thZqLw7IxVw_0 knife +tj2-fSeuMRI_0 bird +tmch--OGZhY_0 giraffe +tmsInTqqzHI_0 zebra +tof4QiBHPQQ_0 person +towJyxwm3wE_0 bird +to8OyPMfkaI_0 person +tpQv6Sn5z3o_0 motorcycle +tpcuQY4eNaI_1 bus +tpeBIe69wr0_1 bus +tpeBIe69wr0_3 bus +tpwUnqxQYjo_0 train +tqy3XprB11s_1 horse +tqy3XprB11s_2 horse +tq9WP-2U1QM_0 person +tsMTiOeM52E_0 cat +tsg-S4Hk2go_0 person +ttzJbLLAR34_0 cat +tvSJKUR21UM_0 train +twewRZpG7Fs_0 cow +twxvNeK9FZo_1 bear +txDhTthoXSk_0 motorcycle +tx0mtmimu0k_1 person +tx2PSvwf7FU_1 cow +tyem40ZMKGE_0 person +tygG1C5DURU_0 person +ty3iURJku9k_0 person +tzH_tvBDeJA_0 skateboard +tzPForR9Ejs_1 train +tzvKjCoHBMI_0 bird +t0TW8zZxCWQ_0 person +t1N1ijCr5NE_0 bicycle +t1N1ijCr5NE_1 bicycle +t4FZmjCINtw_0 bus +t4naVz1a0sg_0 train +t4zuUZQozs8_0 horse +t5B7vIbyRNQ_0 person +t5kzdnId2sI_0 horse +t5s4Fs07WLM_0 dog +t50QLEhcZCE_0 person +t6C6ukC_zEA_1 bird +t6C6ukC_zEA_2 bird +t6C6ukC_zEA_0 bird +t7YFOxuWxtg_0 umbrella +t7YFOxuWxtg_3 umbrella +t7s424DNznk_0 cat +t8MqK7LWqs8_0 airplane +t8mVwobdP40_0 boat +t_qvtoXbLRI_0 person +uAWXGcWWgSU_0 person +uAZF38u6SOo_0 umbrella +uAzws057QjE_0 skateboard +uA1sb8QyXuU_0 skateboard +uCZi19CC7rk_1 train +uCZi19CC7rk_2 train +uCZi19CC7rk_3 train +uE5rIJoAafE_0 bird +uE5rIJoAafE_1 bird +uH0jKXHq7Lw_0 horse +uH35b2DEXFw_1 skateboard +uH9vcwYxL2s_1 person +uIu2jQswp94_0 person +uJcu-YlAtbc_0 bird +uKJqU3gtIWM_0 umbrella +uLPuf056wH4_0 horse +uMAkaCYTDuc_0 truck +uMYGWhLdrlc_0 boat +uMiNpG3NcEw_0 person +uMpufBdwRn8_0 giraffe +uNpHGE63PdQ_2 truck +uNpHGE63PdQ_8 truck +uOmCLzEMPGc_0 train +uRFXE4UfdTE_0 cow +uR8MqB3VgSI_0 truck +uS1QmKXc0uY_0 person +uTsfiR5FPdM_0 person +uT9uk3mtt98_0 bird +uUU-VpxxSiM_0 cow +uVrW8Mm2xGY_0 person +uWyTGtedEqU_1 person +uWyTGtedEqU_0 person +uarSTtaV_Ps_4 boat +ua6Xyj9aWT4_0 bear +ua6Xyj9aWT4_1 bear +ua6Xyj9aWT4_2 bear +ubHgpaAseuo_1 elephant +ubijaVodfKg_0 person +ubijaVodfKg_1 person +ubsr27_dQOk_0 elephant +ubsr27_dQOk_2 elephant +ubsr27_dQOk_3 elephant +ubsr27_dQOk_1 elephant +ucUearjcPHk_1 airplane +ucfXE6fw3go_0 cow +udlyGSCujUU_0 truck +ufB4EORClps_1 knife +ufMXT_CmtK4_0 airplane +uhm0JnSA-kQ_0 person +uiLBqX72k4k_7 boat +uiM-lDuYaeY_0 person +ujoJwRvjEdI_0 person +ujz4u55Tp1U_0 cat +ul47aFS8dQE_1 motorcycle +ul47aFS8dQE_2 motorcycle +ul47aFS8dQE_3 motorcycle +umkNI2_0Lqc_0 person +umxZfostBlE_0 train +um22CD4bkqo_0 cow +un6QDPagbfo_1 cow +un6QDPagbfo_0 cow +up6VT6l38-A_1 skateboard +uqn85v1WM7A_0 motorcycle +urAYVS5Lz7k_0 person +usAsP-m-qs4_0 dog +uuhWeHmlvt4_0 person +uu3KluYuhc0_0 person +uu3pH95cmtk_0 person +uwXhzSsAIJw_0 person +uw9TxuXeiP0_0 train +uxgUbys1eD8_1 bus +uzMFzDPfsws_0 knife +uzsdMqrgiL8_0 person +u14Sp3wCQew_0 car +u2BHvsjQGjw_0 person +u25Jazd2yJM_0 person +u4KPFsw5W5c_0 motorcycle +u4oma0FVycA_8 knife +u69KRu61wXM_0 person +u7xTeWelI-U_3 knife +u8mmwwrdNb0_4 airplane +u8mmwwrdNb0_5 airplane +u8mmwwrdNb0_9 airplane +u80Y4lA5xT0_0 dog +u85tUrDgmOQ_0 bus +u9HkSfjYpnA_0 motorcycle +u9rfXD33UIM_0 person +u9_P9HFh_NY_0 dog +u-_A36Ha04o_0 cow +u_D1eyd8AOM_0 car +vAUSfFO5UI4_1 dog +vFMzMNDlnBs_0 person +vGIYDcnNTvA_0 knife +vHQkxg7kPUk_0 dog +vH0ZiiuSQzU_2 person +vH7sKynwjD4_0 person +vJypzwSdyN4_0 train +vMt5AD41SKM_0 person +vMt5AD41SKM_1 person +vOY2IRNsjYg_1 person +vOY2IRNsjYg_0 person +vQ6eOB8rxUE_0 person +vRjErSbQNNY_0 person +vTa2zdbIyUw_0 person +vT2JpCnT6rg_0 boat +vWqexY1OdWg_1 skateboard +vXbTARLug3M_0 person +vYN_Gy6fUbI_0 bus +vYhPihwivZs_0 person +vaaqJVWoSf0_0 person +vadASNfLl9I_0 dog +vas3iNRcsK8_0 elephant +vas3iNRcsK8_1 elephant +vbLhfzHqEKc_2 horse +vbSnjtc3vIs_0 cat +vcALsxetYU4_0 airplane +vc-_aAQAXs0_0 knife +vdXD-HTzyFM_0 cat +vfeKOPKE6l8_0 person +vf7NtV1T5Jc_0 train +vf7NtV1T5Jc_1 train +vjb_l1_hEXk_0 person +vjojFy4rPeo_3 car +vjojFy4rPeo_1 car +vj_BAwFKqtQ_0 umbrella +vklwqjQis8Y_1 cat +vlPgSny76H8_0 person +vlflI5iuszQ_0 person +vnD3gELVAq8_0 person +vnyBVn70QLY_0 cat +vnzsKpfAS_M_1 horse +vpBxBDjiJxw_1 dog +vvamB_-Z0so_0 horse +vv3gfxFz2zw_0 person +vwe8ZaV-4z8_0 bicycle +vwtokH03eW0_0 skateboard +vwxzh1lJ7iw_5 motorcycle +vxmdsyEpU6A_2 bus +vx0oKJcOQb0_0 train +vx0oKJcOQb0_3 train +vx0oKJcOQb0_4 train +vyLqolkoVIM_0 person +vzBbUEwED60_0 person +vzBbUEwED60_1 person +vzU0GH4cZM4_0 cow +v0tUEeE4RGc_1 truck +v0xTNbrYZY0_0 giraffe +v01IvIxWXTo_0 person +v1iIhTWRjg8_0 boat +v1-PGfS1YCY_0 boat +v3LIQHdveBA_0 person +v4H5VwQyKEU_0 train +v4H5VwQyKEU_1 train +v4QYOX-FHhY_1 motorcycle +v40pc8KBg0I_2 horse +v5YzVj25_hs_0 truck +v5lUHsxx0mc_1 skateboard +v50Qa_KMCzQ_0 truck +v51CdpETaug_0 bird +v6UDfM50GIM_1 truck +v7XVyg16ens_0 cat +v8Kp0jhKsKk_0 person +v8ceKkKdqrE_1 knife +v8hOOgLXRjg_0 person +v8kyeMoFLqk_0 horse +v8rj3jIndSE_0 dog +v8tktR3aE38_0 airplane +v_yEG5_Qm8Y_0 person +wCu6xsT18qo_0 person +wDHRro9mXuM_0 horse +wDcnUJFHguE_0 horse +wE8LYkzcq0o_1 horse +wE8LYkzcq0o_0 horse +wGPW8I8nGmc_0 train +wGWIrs5ja0Y_0 bicycle +wGyJeWBe8VA_0 umbrella +wIapUcRvgTM_0 bear +wIapUcRvgTM_5 bear +wI0a0fzgy3w_0 horse +wJdfgWlSY5M_0 person +wJdfgWlSY5M_1 person +wK7yIg1qfZ4_0 person +wLA244rmq6g_0 cat +wLHLSvMwmjM_0 skateboard +wL0z6-jkCcc_0 dog +wL0z6-jkCcc_3 dog +wL0z6-jkCcc_1 dog +wL9iOnWhckI_1 skateboard +wL9iOnWhckI_3 skateboard +wMShicf3N_E_0 person +wMyAEfVE_u4_1 elephant +wNKWZ43SioQ_0 airplane +wNKWZ43SioQ_2 airplane +wNWW59wDinQ_1 train +wNcjU9-ck10_0 person +wODzPBxcT0A_0 motorcycle +wODzPBxcT0A_2 motorcycle +wOLrGAo0vFo_0 horse +wOSL7OPRBXM_1 dog +wPRCf3v0EfI_0 motorcycle +wQtHgysmmFg_1 boat +wQvPlByUvB0_1 knife +wSSTL6uuM9Y_0 train +wSmVgAahSUw_0 skateboard +wSmVgAahSUw_1 skateboard +wSmVgAahSUw_2 skateboard +wTMj2Gp8wz4_1 bird +wTMj2Gp8wz4_0 bird +wTtXB0Z2eMk_0 car +wV1VMLQfTYo_0 skateboard +wWpNKbsF6q8_0 bear +wa1KdARQXXg_0 truck +wa3jVRzsWGo_2 truck +wbmT4LB3lVQ_2 knife +wb9x3QDpcYA_0 person +wb9x3QDpcYA_1 person +wcOuc6Y3Gek_0 train +wcjnFIBHoc8_0 bear +wdb2-oX7HqU_0 boat +wdhqMpQcsjc_0 dog +wdhqMpQcsjc_2 dog +weH4PvRo2GU_1 bear +wgZbNzu2Mdw_0 person +wguspvl5Ioo_0 person +wg1ZFP15W8U_0 horse +wg6XS3q4Vg8_0 train +wifl75i2zGw_0 person +wiiV9QdYsYM_3 bus +wjfHYr4lXU0_0 cow +wmfJAE6gu7w_0 person +wmjfHsCs1CE_0 person +wmn4YG9rirU_1 bird +wmn4YG9rirU_0 bird +wmx0UeWsPyU_0 person +woEUh2mzEkE_0 horse +wqD1WkfidVw_1 bear +wr5b8Op3LUM_2 bear +wuAwZ_wX7jk_0 knife +wuFVuJjgpLk_0 airplane +wvadJ-1Ls80_0 person +wymDvXB08SM_0 person +wzBmon2jJxI_2 bird +wzlA0qMLDV8_1 cow +wzlA0qMLDV8_2 cow +wzlA0qMLDV8_3 cow +wzuQhwWLllk_2 bird +w0JzCkELpj8_0 cat +w0bfVrI7CPQ_0 bear +w1j-YVcZpfc_0 person +w2WW3bYmA7s_0 truck +w247rqoLoGg_0 bear +w3F_8A8kY7o_3 elephant +w3F_8A8kY7o_5 elephant +w3F_8A8kY7o_6 elephant +w3adXMIxupk_0 cat +w35-xR0Vn_0_0 zebra +w5Pb_ORVLKI_0 airplane +w6A2W9VQeZk_0 car +w6JEUZI5Vh8_2 skateboard +w6JEUZI5Vh8_0 skateboard +w6JEUZI5Vh8_3 skateboard +w7IKxGLuaQA_0 horse +w7g5pDCGteg_0 person +w8zrFmMpPmc_0 motorcycle +w8-ovxjadNo_0 train +w93q7lv9In8_0 person +w-eAEp0TUi0_0 horse +w-eAEp0TUi0_1 horse +w_euwPW5ukA_0 bicycle +xAUupk4sGI0_0 person +xAedjC0r5KY_0 person +xAfxJQL2_aY_0 zebra +xDgoaE-g50s_2 bear +xFnFWM8KXcE_0 person +xFzsK94M68U_1 person +xGbFeCuGypE_0 person +xHOcerZTZxM_0 person +xIUJ8zlr0TU_0 bear +xIizuktSVrM_0 truck +xJ_xdRV9lzo_0 cat +xKd8dHsveKg_0 person +xMiQuC8eKGU_0 person +xMp4dCjzI08_0 cat +xMuQzm__4bo_1 person +xMuQzm__4bo_0 person +xNBT-PZEMH0_0 bicycle +xOLvPvBg-8U_1 horse +xOtxf0cmHyA_2 horse +xPDDIKF9T3A_0 person +xRJNEyms-F8_0 train +xSIjCyHBypw_0 umbrella +xSIjCyHBypw_1 umbrella +xSL4NZUmhW4_0 person +xUB3mR57tLE_0 bicycle +xUtGzUu5Ryc_0 umbrella +xU_2MZdWfxM_0 cow +xVuNCF2vbXs_0 person +xWWnn5OWp4I_0 airplane +xYVriT4YV0M_0 person +xZLHtt1yjYk_0 truck +xZZ_W6fRi8E_0 knife +xbL4hiu8qh0_0 horse +xbQZucd8eu0_0 bicycle +xbQZucd8eu0_3 bicycle +xbQZucd8eu0_2 bicycle +xcY11ewiUMM_1 horse +xd_raY9PCHM_0 bus +xd_raY9PCHM_1 bus +xeAkz6Kg108_0 bird +xeBhbPbmS8w_0 person +xfzxTuJ85A4_0 airplane +xfzxTuJ85A4_1 airplane +xitZyv8gMgQ_1 horse +xjdEiJ_z4T8_0 motorcycle +xj3FKNXP-cw_0 bird +xkKoATbAX0w_0 dog +xkeTuOlBIMM_0 cat +xlT93OXr3uc_0 person +xlT93OXr3uc_1 person +xlfOatU3OyY_0 boat +xljqBqpwIHo_0 person +xl110TqE0kQ_0 cat +xmWAmSXnWCY_0 car +xo54E-kQcoA_1 boat +xpGDfRYqtSE_0 cow +xpcNJG8acpU_0 dog +xp_ShmZCoDw_2 airplane +xqNQIYHzAGk_0 person +xrGm-1D2Zqk_1 train +xsrHSco3Zcs_0 person +xsrNtKa0oZg_1 person +xs1kBHxDpxU_0 train +xs1kBHxDpxU_1 train +xs1kBHxDpxU_2 train +xtHE1-GIP_w_0 person +xtXt8Vm3Qps_2 dog +xuAm_BWnXRc_1 motorcycle +xuAm_BWnXRc_0 motorcycle +xucBFquWbi8_1 bear +xv4fy9zyuNE_0 person +xv6NQvvvIhk_1 bicycle +xxEtEzi7YiY_0 bus +xxcJJA7hCQY_0 person +xxdOVyEU-c4_0 person +xyg1xFLohGI_0 cow +xyyz5QJ7wi8_0 dog +xzC5_r9raeY_0 person +xzFcPnglQf4_0 person +x0RxwpR4wIc_0 bird +x0RxwpR4wIc_1 bird +x0nlchdJVJw_0 bear +x0nlchdJVJw_1 bear +x0q0JMiiw1A_0 cat +x0xsHmQGaB8_0 dog +x1RBYEheBRQ_0 person +x2MJ_zDJY3k_0 person +x2Tfa1fMOyE_0 person +x29EcPsdK1Q_0 dog +x29EcPsdK1Q_1 dog +x4h9pGwdSMU_0 horse +x4r2tx9_9wQ_1 person +x4r2tx9_9wQ_0 person +x4uX_33GiJk_1 truck +x48Ogx7C31g_0 person +x4-I_EckNls_0 bus +x4-I_EckNls_1 bus +x4-I_EckNls_2 bus +x4-I_EckNls_3 bus +x5nImw1YH94_0 person +x6sZc4EoI8o_0 person +x6298plJ-7M_0 cow +x7jo9uCmWA0_0 bear +x8VC2CXIDBI_0 person +x96LXIEQ3SM_1 cow +x96LXIEQ3SM_0 cow +x-2AUxPCkVM_0 person +x-26Z1zy1-E_1 person +x-26Z1zy1-E_2 person +x-26Z1zy1-E_3 person +x-26Z1zy1-E_0 person +x_CImXdwsg4_0 truck +x_XV2Y3pwDA_1 bicycle +x_XV2Y3pwDA_0 bicycle +yCYtcDx1zzE_0 umbrella +yCaJQKIGAjg_0 motorcycle +yCz3VdCGZMA_0 person +yDw-9GLrYj0_0 person +yF0X9hui-Go_0 person +yGD_BY9mQlM_0 boat +yIkwS9Vkq-k_0 elephant +yJOGbyQ8qs8_0 person +yJZU3h3_06M_1 cat +yLFd8GdaqBg_0 person +yLL5Dv2F1rs_1 elephant +yLL5Dv2F1rs_5 elephant +yLL5Dv2F1rs_0 elephant +yLNuhB7I5iI_1 knife +yLNuhB7I5iI_2 knife +yLkMk9nMaos_0 train +yLkMk9nMaos_7 train +yLkMk9nMaos_1 train +yLkMk9nMaos_2 train +yM9_GnJpXsM_0 airplane +yNnOUMUIIno_0 bicycle +yOrqtKYEfNs_0 train +yOrqtKYEfNs_1 train +yOrqtKYEfNs_2 train +yPscRV8ebRg_0 person +yQLGypU_WiY_0 knife +yTZekxz2awI_4 airplane +yTZekxz2awI_1 airplane +yT-tBu_wqEo_0 cat +yVO-nlNYxrU_0 person +yV1EsNcE3kY_0 airplane +yYIY-K1Hk-0_0 cat +yYUnGStTnHE_0 train +yYUnGStTnHE_1 train +yYr5tuCEb3w_0 cat +yY6S-xTKWGc_1 person +yaNT5d8H3ho_0 person +yahVo8Nqxks_0 person +ybCbkJl7tog_0 person +ybt9EtMfrdI_0 person +ydxMYuiOJAI_0 person +ygK39Pz1tKw_1 motorcycle +yhp30idsPKU_0 boat +yiCMaealOnQ_0 cow +yiujj_fUOg8_0 person +yjOTRS1-3Is_0 cow +yjUDTPRe-tg_1 person +yjnR7dP-hxE_1 bird +ykQnvD35jxs_0 bus +ymoggco-rpw_1 elephant +ynHMWKjfsNk_0 car +ynYz6f5FCOk_0 motorcycle +yoTs9WxR0mI_0 person +yo3wwD8VMLA_0 person +yo9gwC7gpEk_0 boat +ypC9L5um-ic_0 person +yp9kACFk9KU_0 car +yqWKo_T-YsM_0 person +ysb6LLJ0t-c_0 person +yssYMx-tQs4_0 horse +yu2v206waMs_0 person +yvDdzmW5jGs_0 cat +yxURDHgvWrs_0 train +yxURDHgvWrs_7 train +yyMtxTJNnUM_0 skateboard +yzE2GgYffew_0 person +y0HZlHGSvHk_0 horse +y0ptIotKNVU_1 horse +y0qGszhFtUc_0 bird +y2BOVk7bg7k_0 cow +y2BOVk7bg7k_1 cow +y2xzls--cC4_0 person +y2_iaWWx-C0_1 zebra +y3VNGZBlDb0_0 cat +y3hSeUaVwAY_0 bus +y34cSfArQnM_0 cat +y6nBJ0OUtDs_0 person +y6nBJ0OUtDs_2 person +y67A9YHKh1U_0 person +y8ib31rVZA0_0 bicycle +y8ib31rVZA0_1 bicycle +y8r2SJltJ1M_0 dog +y9hu6CyRi5s_0 airplane +y_O1AiuRLGA_0 umbrella +y_5uacneFuc_0 horse +zAvoyJ0_PSA_0 cow +zBtuA6r8o0M_0 cat +zCG95maa310_0 person +zCnZg9VP1xw_0 truck +zDs4lXFLJuM_1 horse +zD59UHvdpmY_0 person +zESRFobSQMU_0 truck +zESRFobSQMU_1 truck +zHRsZ9HlcBk_0 person +zIDehNZ1yiM_0 person +zIvzY3cVVbM_0 person +zI5cBWlyAMo_0 dog +zI5cBWlyAMo_1 dog +zJdOWFEL_CQ_0 person +zLflV_7noSM_1 airplane +zMhr8GZ1QeY_1 airplane +zMjW-G29IRA_3 bear +zMjW-G29IRA_1 bear +zMjW-G29IRA_2 bear +zMjW-G29IRA_4 bear +zNFb--FJ2A4_0 person +zNF5YxfaNTk_0 cat +zNfVxQPGrvM_1 elephant +zN8rF-AchY0_1 motorcycle +zN9Tz6jp7AY_0 person +zOLTybhsJ5s_0 cat +zORNq_7nmVQ_1 giraffe +zORNq_7nmVQ_0 giraffe +zOoxYmqzDyc_1 dog +zPvrRc94j6s_0 person +zP2DkEcgJFo_0 person +zP8Recx-KgA_0 boat +zQbeiOf9ljM_0 person +zU0g6JCyxAs_2 elephant +zVVQ63dPpe4_2 bicycle +zWQQBElMPYI_0 person +zX9OX5I2574_0 person +zYvjN5ShZDI_0 person +zYzASiLjHgY_0 person +zZ8f7oFIg_c_0 person +zbtsVe8RQqI_0 person +zb8-yrB5SlI_1 bird +zcgArp_fmjc_5 skateboard +zcsREBhC1Rc_0 dog +zdWtCunlv1c_0 cow +zdqJTtHvwk4_0 person +zd3rNWQ-OUQ_0 person +zgJHKszSf2o_0 person +zgJHKszSf2o_1 person +zgRxry9FvEk_1 horse +zgSx8Y5FaPI_1 knife +zhDC_SqN7lQ_0 bear +zhNNahIXxC8_0 bear +zjQG5PadkFQ_0 person +zj4cs0_VpTk_0 truck +zkSIG3AE7tY_0 elephant +zmDkkM7Buuo_0 cow +zmEU5n2Dy8Y_0 dog +zmdKmfMPuvA_0 bird +znTYxWfU2XM_0 truck +zpEtPFxxD5M_0 horse +zqE3Jnn6_gw_0 person +zqYLN7vCqcw_0 train +zqq508NRpOY_0 person +ztMFfJj7jb0_0 knife +zt3ojCKnIYM_0 cat +zwSnaqQ-5UU_0 person +zxiZnbMo3io_0 motorcycle +zxiZnbMo3io_1 motorcycle +zxzApvuo8Lg_0 person +zx0RzA6ts8U_0 cow +zyXxWBoTuww_0 person +zyXxWBoTuww_1 person +zyftQz018g0_0 bus +zy0lNSoVB0A_0 cat +zzRnX2EiOYU_0 cat +z0Tl2FDG69g_0 elephant +z1kOi92oBDI_0 truck +z1kOi92oBDI_1 truck +z1qQ7Ma5C5U_1 truck +z1qQ7Ma5C5U_0 truck +z18s4h6yW2A_0 bird +z2M6XJGE1QM_0 dog +z2RqakqNnIM_1 skateboard +z29ijVd-dvc_0 airplane +z3rcLKwHCxM_1 truck +z5-nsuFvaR8_0 motorcycle +z7FTg1R3Hik_0 horse +z7mLqljZMP8_0 person +z709zOu3tM8_0 car +z9HO__A5ryw_0 dog +z9wpJN1R63w_0 person +z-iM0zVi7a4_0 bus +z_CQX_gwU_o_0 person +z_w1gsSfZhQ_0 person +0AroA_SBRtQ_0 person +0BUPQDR99KY_0 bear +0DDYOUzExSY_0 person +0DGPzzGhUgI_0 person +0DHLS1VDcnA_1 bear +0EeBXB53BQE_0 airplane +0EnI7ZqJvqI_1 car +0EnI7ZqJvqI_2 car +0GzrKbW6Reo_0 person +0G0mSrzOZ2M_8 bus +0G0mSrzOZ2M_9 bus +0G0mSrzOZ2M_10 bus +0IHYTCKh8HM_0 person +0KWfi9m1uZg_0 horse +0KWfi9m1uZg_2 horse +0KWfi9m1uZg_1 horse +0L0JFDbAEZg_0 knife +0Neg9vT08to_0 cow +0NtpuqPU3YI_0 airplane +0N7yCdf7DPs_0 truck +0ORpOxJZo-Y_1 bear +0OqnKMwSULM_0 skateboard +0OqnKMwSULM_1 skateboard +0Pk8OLmmqrM_0 motorcycle +0Pu-_5lNYZM_0 bird +0QKe3M6GiT4_0 person +0Tu3KWEm4SE_0 cow +0Tu3KWEm4SE_1 cow +0TwpPpqiVQ8_0 cow +0U6SmZC1j40_0 person +0VKozmEWjZ4_0 person +0VaX_g70BaY_0 motorcycle +0ZGdpgF-bGI_0 bus +0ZQ_-4ia7z0_0 person +0c-Cwr5rI_A_0 elephant +0c-Cwr5rI_A_1 elephant +0fyRjxenSfY_0 bear +0fyRjxenSfY_1 bear +0f4alYlvEQw_0 person +0gelRcDsNio_0 airplane +0ghRNQFgHow_0 bicycle +0gl1mPRzCqo_0 person +0h9x35zsnyo_0 bird +0iLR3BtDujk_0 train +0iYm4g4D2wY_0 person +0iv0Xw_u-sc_0 bicycle +0i-Nv28lRT0_0 bicycle +0kZSWqFOr0c_0 person +0kidYsWSVvc_0 person +0mbZJnNhckg_0 person +0omh-B4giqI_0 umbrella +0owf_YERias_0 skateboard +0pAMIiK_RDo_0 person +0pm7YRiUKTc_0 horse +0qVc1Whb3GA_0 person +0qwRoiWnwmQ_0 person +0rQzfr4WVKc_0 cat +0sA23Q_HQr8_2 zebra +0sA23Q_HQr8_1 giraffe +0sA23Q_HQr8_0 giraffe +0sfu67JuBFg_0 person +0ss0_Sgy72g_1 skateboard +0tNuUAe5sNE_1 person +0tNuUAe5sNE_0 person +0txAuEdZYTI_0 motorcycle +0uJKDzuaiys_0 train +0urYbdFc55k_0 train +0utGbb5enqA_2 dog +0utGbb5enqA_1 dog +0vQFT9tfq40_0 person +0viKlMZRKdk_0 person +0v7GMl2k-Sk_3 train +0yCCEL3tl24_0 elephant +0zmzEkQWyps_0 boat +0zraBBQY8ew_0 umbrella +0zyhohOeIM4_0 train +00xcm8_ZTBc_0 person +01CYScp2Yc0_1 horse +01mkUffAvo8_0 person +02zor_ScZfo_1 person +02zor_ScZfo_0 person +03p9Ao9JvpY_0 train +03p9Ao9JvpY_2 train +03u5BWTYiRg_0 train +04Sh9tJvOAc_0 airplane +04UO1jSx2p4_0 person +04gNIg-kFI8_0 person +057f0LfDVoA_1 train +08Nunz5Qngc_0 bus +09jyC-o18uU_3 elephant +09kq3b7cMwc_0 cat +1AcsNm2kiok_0 horse +1BfbSv9ZCu4_0 knife +1BfbSv9ZCu4_3 knife +1BiqFD2BD7Y_0 horse +1C3_qaiKlwo_0 truck +1DHXDdSkk0s_0 bicycle +1DeIbpIRrAc_0 knife +1Dfkbv8bi9k_0 person +1Dz4x50F-RQ_0 dog +1EYL4Mm3dfA_0 bear +1EiH3PTqhLE_0 person +1ExRnJBXYP4_0 knife +1FVN3QOPlR0_0 person +1FVN3QOPlR0_1 person +1GJ0iwyNHIc_0 airplane +1JWHb6FAbmI_0 person +1Knz9s55vjc_0 car +1Knz9s55vjc_1 car +1Knz9s55vjc_2 car +1Knz9s55vjc_3 car +1LmCkh8Dd-o_0 dog +1MmlnQKtd6g_0 umbrella +1M6GhIT94zE_0 cow +1M6GhIT94zE_2 cow +1NThnoBEkmc_0 person +1ONRbj8GKJ4_1 bear +1ONRbj8GKJ4_2 bear +1ONRbj8GKJ4_8 bear +1ONRbj8GKJ4_10 bear +1ONptqLyHxQ_0 dog +1OSa1ptYmzE_0 train +1OSa1ptYmzE_1 train +1Ob23hwFaDg_0 motorcycle +1PSIOY62FBg_1 bear +1Pe9JpKgjGY_0 car +1P8yUGru9R4_0 knife +1RCZCLIZzc4_0 boat +1RGxleB_Ezk_0 person +1RKOWfpa5Dc_0 knife +1RuPxpqNjBI_0 horse +1Tpmsev8onw_0 cat +1TsLUvJiluI_1 person +1TsLUvJiluI_0 person +1UhZKsDTuQs_2 boat +1V-7ErZ83ZY_0 bus +1ZN9xVmQojU_0 umbrella +1ZbSl9tPtbA_0 bird +1Z7CVnRjVT0_0 person +1as5iG4PPas_0 bus +1bFvYEA0U3U_1 elephant +1bveGPhOKuU_0 cow +1cKjzUG0YCQ_0 bicycle +1ceprZO-VEU_2 train +1ecpkwMLabI_0 person +1fOM-kkuRsw_0 car +1ggOn5NDRco_0 cat +1hUe5E9cjiU_0 motorcycle +1iQKKup2m3I_0 truck +1iQKKup2m3I_1 truck +1iSjb4IlqfU_0 person +1i7lugA55RU_0 bicycle +1i7lugA55RU_1 bicycle +1kZMlCvKoe8_0 skateboard +1kZMlCvKoe8_1 skateboard +1kZMlCvKoe8_2 skateboard +1ksBabVqkMY_0 car +1ltK_3kkqfg_4 elephant +1l7LOpfDmXY_0 person +1ohoCoKJLDU_0 motorcycle +1oyjAtaWDZA_0 truck +1sQ3EL13Vqo_0 person +1tK31PAVNJM_5 elephant +1tK31PAVNJM_0 elephant +1tK31PAVNJM_2 elephant +1tK31PAVNJM_3 elephant +1v2enBiUcqA_0 bus +1wIGd0H1CUo_0 person +1xSI36nguW0_0 bear +1xs-ibIaMMU_0 person +1xyKgJUu0lM_0 skateboard +1zVWBQWZxV0_0 person +1zVWBQWZxV0_1 person +1zqpqKWhr1Y_0 person +10la9pvd-pk_0 knife +11kfBYxzlFA_0 person +12f1R5wMVPs_0 person +12_S_8HkAvA_0 person +1462k8mwVB0_0 elephant +15Lx-nGngUo_0 skateboard +18WxVaz5Ue4_1 skateboard +19A2XM5NIWs_0 person +19UmUpkjRbs_0 person +19oZ30mOTkU_0 boat +1-p8vd0PFQ4_0 dog +1_6ymF7z_iM_0 truck +2ASHEEgYHcU_0 cat +2CF0oQ38cBQ_0 motorcycle +2DM1oM4HFjI_0 motorcycle +2FXE_xO8Mb4_0 bus +2FvnQne8he8_0 train +2GTexq12sBY_0 person +2GTtMvLQqio_4 truck +2GZphW1DkS4_0 person +2HvVFwq85n0_0 person +2Hwu-YpHKw0_0 elephant +2H8AZ00ONQE_0 elephant +2IJ4H46ZxEE_0 person +2INYBScuPM8_0 car +2IqEaQ0oyQg_0 airplane +2JN_uMTDa9I_0 skateboard +2KWlj_ZAw94_0 horse +2KWlj_ZAw94_1 horse +2KWlj_ZAw94_2 horse +2K2gLrhP9AU_1 airplane +2K2gLrhP9AU_2 airplane +2K6iDBPdcHk_0 motorcycle +2LBHZoJ5skk_0 person +2L3uwdhZtV0_0 car +2MJHsLxKUBg_0 person +2MiqTBWBlEc_0 umbrella +2NjC1r6v4IQ_0 person +2O-2zfQxbnA_0 person +2PaTs4s2Ybw_1 bear +2PaTs4s2Ybw_7 bear +2PaTs4s2Ybw_4 bear +2Pa1anwpeKE_0 person +2Q3_TaV8vcg_0 dog +2Rc-oAwMJBs_0 horse +2Tp0YJi7JwQ_0 giraffe +2UpHhiQWzD4_0 truck +2VZlkg5HjME_0 cow +2WTwzNufol8_0 dog +2WTwzNufol8_1 dog +2WtNxQ0RBfc_0 person +2ZXlS-GRWAw_0 knife +2Z6wSOr0jLI_1 person +2a5TUccpQ08_0 dog +2a_-AyOXTXg_0 skateboard +2cFRz-musVA_0 airplane +2cFRz-musVA_1 airplane +2cFRz-musVA_2 airplane +2cFRz-musVA_3 airplane +2dZFWL9XGmw_0 cow +2fCH7TpvtlM_0 train +2fCH7TpvtlM_1 train +2fJ1hPXpiQc_3 knife +2fJ1hPXpiQc_0 knife +2gGuKs-4t94_0 boat +2i45n6p8AT8_0 person +2i_wjgk6DiA_0 horse +2lK0mmHTvB8_3 train +2lK0mmHTvB8_1 train +2lqlNq6aII0_0 skateboard +2lxPwFW5YQo_0 umbrella +2l2gnrYWuWQ_0 truck +2l7MPXzF64M_0 cat +2l7TuAfDgO8_0 truck +2mO7-ybapaQ_1 umbrella +2nqGkC9ebf8_0 boat +2oA7J6HSmt8_6 bicycle +2oA7J6HSmt8_9 bicycle +2tSpb14o7SA_0 person +2vF8Va9DGSM_5 bicycle +2vF8Va9DGSM_4 bicycle +2vF8Va9DGSM_14 bicycle +2vF8Va9DGSM_15 bicycle +2vF8Va9DGSM_2 bicycle +2vrbssf2sDM_0 truck +2v808Hn8_do_0 person +2v808Hn8_do_1 person +2yEUVUqYMPc_0 giraffe +2ya3SN5pLyU_0 car +2065vf90oIM_0 person +2065vf90oIM_1 person +21GQbN_4k9M_0 cow +21Hp5g5RrOc_1 person +21Hp5g5RrOc_0 person +22iFltXYCcQ_0 cow +22ztStWwd8g_0 train +22ztStWwd8g_2 train +22ztStWwd8g_3 train +23qU2q5u0OE_6 bird +24Zxq5TuxzI_0 cow +26kWe8Ikgxk_0 bird +28AecePdVok_0 truck +281z-ZLrI3g_7 bicycle +281z-ZLrI3g_4 bicycle +29bWSLuiEl0_1 person +2_R2wz82ugQ_0 umbrella +3A4oCDgMkHw_0 cow +3A-dEIjnmyE_1 skateboard +3Bag9o-z-Ks_4 bear +3DN2iQJzM-k_0 train +3DaASBRARLQ_0 cow +3D8wwibqkYo_0 cow +3EtIKWgGaKY_0 person +3FJ4ZWRq_S0_0 person +3GLXlSuXWcs_1 cow +3GQxmRKhMMY_1 airplane +3GQxmRKhMMY_2 airplane +3GQxmRKhMMY_3 airplane +3GQxmRKhMMY_4 airplane +3GULyU-IOhA_0 person +3HFqP9a97kA_0 bird +3IgOwKkKALw_0 cat +3LruhG4SULI_1 truck +3LruhG4SULI_2 truck +3LruhG4SULI_7 truck +3LxUuC1C4y8_0 bird +3L7LWpMShiw_0 skateboard +3L759GhRx6M_0 person +3MiM8HSul5A_0 cow +3MiM8HSul5A_2 cow +3MiM8HSul5A_4 cow +3M9T5RFr_9s_0 person +3OmdALGspY8_0 person +3O4ynxtRIDk_5 train +3O4ynxtRIDk_2 train +3RLrjX-XB98_0 person +3RhgYReCxjo_0 bus +3S-lQgiUWVU_1 horse +3S-lQgiUWVU_0 horse +3UDEQElT2yQ_0 train +3WhmVhG1ZwU_0 boat +3WrB7zPpcHU_0 cow +3XDvXaNmGpM_0 dog +3XDvXaNmGpM_1 dog +3X29L9uQCqc_0 train +3X29L9uQCqc_1 train +3Y7-acGE4Wc_0 person +3ZBYYBUfT6E_0 train +3Zwa4XoeZcA_0 person +3bSWlbx1o3I_2 bear +3cOMDXFxcOQ_0 cat +3dvUlr2yxz4_0 train +3g4c88ocJ38_0 skateboard +3hMszgfh_qA_0 bicycle +3hR78-EVNEE_0 truck +3jdK8UPhpO8_1 skateboard +3jdK8UPhpO8_0 skateboard +3kdpeeQ1Jnc_0 car +3kd_QEZRUWc_1 truck +3kd_QEZRUWc_5 truck +3lHqsoi5cgo_0 person +3liK-2EflUk_0 car +3mIRDwcY1Lg_1 person +3m5eMVv4z6w_1 bear +3nD6nhJtxIU_1 skateboard +3nbim5nlANI_1 horse +3q6LFZBelUs_0 person +3rSUjqH5Wlw_0 truck +3sEpU7UoQP8_0 person +3sg9txiHCp0_0 bear +3szPqA1S6P0_0 person +3tv_dUR84cE_1 airplane +3tv_dUR84cE_0 airplane +3uG4S1gvMxs_0 bird +3uVS_DAYfvY_3 car +3vuykX663QA_0 person +3wI_ureHDBY_0 train +3xLvnY9w5y0_0 person +3xy8Fz8Nsgk_0 bear +3zV0wmpiS78_0 person +3zccg30U6vs_0 person +30AwDyYIr7o_0 skateboard +325FEWXtOYw_0 person +3293hM-lzx8_0 person +32_1y90B5eQ_0 person +34L4iiCFTXM_0 airplane +34Pma_R21A8_2 person +34jFMRay1zg_0 person +35-MplWeZYQ_0 motorcycle +36zopo-HS48_0 person +38fx_nvlYDE_0 truck +39yxd86tGLU_1 boat +3-ugxoEDuFY_0 person +3_DeqcBRuwE_1 elephant +3_DeqcBRuwE_3 elephant +3_w3NNPGotM_0 person +4ARhlapmEmI_0 dog +4Ac5edN3qIA_0 elephant +4Ac5edN3qIA_1 elephant +4BItGVIP3_w_0 cow +4BItGVIP3_w_1 cow +4BO3P7E3NDE_0 truck +4BO3P7E3NDE_1 truck +4BO3P7E3NDE_2 truck +4Bw4gKDBQCM_1 dog +4C8rmAORSg8_0 person +4Dcg1W7RRmQ_1 train +4ENxW7OPynQ_1 car +4ExA1FWRfMM_0 dog +4FVfzA07rVs_0 person +4FVfzA07rVs_1 person +4GgzQqhrTmA_0 train +4GrMZIyjUdo_0 person +4IUjw1DfTd4_0 cow +4ItJTYAUV3Q_0 cat +4IxmhmTsSRM_0 person +4I72WJJrc1o_0 person +4I72WJJrc1o_1 person +4KFEzxXCjmw_0 car +4KYtNfb0-64_0 person +4KqP6ylUZpI_0 umbrella +4LHOLAPnjV8_0 boat +4LXlXP1epJE_0 person +4MFPOb36tfo_2 bear +4MFPOb36tfo_1 bear +4MZrjdSF01s_1 boat +4Me3lyNuZ7k_0 person +4M9sKAzevzo_0 train +4NI5ycFo2TA_0 airplane +4NI5ycFo2TA_1 airplane +4NKnUR1OMGo_0 horse +4NKnUR1OMGo_1 horse +4Ng6OxFQ9RY_3 bear +4Nx45ho9gSg_0 person +4PNJ3ZV4f8E_0 airplane +4PNJ3ZV4f8E_1 airplane +4PNvdZPZIdM_0 train +4PhakAK74GE_1 motorcycle +4PxLGSy75rk_2 knife +4QOhfEMrhzU_0 airplane +4Q0M6mWNDiU_0 horse +4RhaYtFsnGY_0 person +4SrP2aSHoRk_0 person +4TyWpb19rk4_0 umbrella +4U9sm_eqKTM_1 car +4U9sm_eqKTM_2 car +4Xd_k2REw4I_3 bear +4YRd-9lHLko_0 truck +4ZIgGDQB_R0_0 airplane +4ZYWcd-Fdzg_0 person +4Zxsg6aJ9tA_0 person +4aOWHpM7rOM_0 skateboard +4avaoLry8L0_2 skateboard +4bHGieqZfUk_1 knife +4duFrAfYG8k_0 person +4d6P5umc9j0_0 bird +4fIznTWAFRw_0 horse +4fIznTWAFRw_1 horse +4fIznTWAFRw_2 horse +4f_X4WbQu4M_0 elephant +4hCLCX2lLGk_0 person +4iBMfS5mIt8_0 bird +4ibKNzoA1tQ_0 truck +4igLFns238c_0 motorcycle +4kGNxHIXcUA_0 person +4kLhVZ9UGDE_0 skateboard +4lC7BU1eHxc_0 bus +4l683stlRno_0 knife +4mv1Nx0j3k4_0 person +4nz8CN4XlBE_0 dog +4oWXZIsPnEg_4 elephant +4ofuHARhFlQ_0 person +4pYH5Cm7Vkg_1 boat +4p3JGxvfiNE_4 bicycle +4p3JGxvfiNE_8 bicycle +4p3JGxvfiNE_10 bicycle +4qBYTh0AcfM_0 train +4qIx-9Qs3Zs_0 airplane +4qIx-9Qs3Zs_2 airplane +4qRkIra0ARM_0 person +4rhkfDV0QC8_1 truck +4ry_MJjFDUA_0 cat +4skAfQd8nX8_0 person +4t79zNxVi0Y_0 elephant +4t79zNxVi0Y_1 elephant +4uFHcf-qpkU_0 horse +4uwly-P5oxg_0 person +4uwly-P5oxg_1 person +4u7pm-h8fiE_0 person +4wox28JkSKY_1 person +4w3ykGq-Q_E_0 bicycle +4w3ykGq-Q_E_2 bicycle +4w5q5RdJ5g4_0 horse +4w5q5RdJ5g4_2 horse +4w5q5RdJ5g4_4 horse +4x80RbpjCPM_0 bear +4x80RbpjCPM_4 bear +4yFIyyevEVY_1 airplane +4ycylGSteiU_0 truck +4yjvwunpMKI_0 car +4yjvwunpMKI_1 car +4yjvwunpMKI_2 car +4yw2hFyx47Q_0 person +4y3qJAq5ap0_0 car +40QgDL4dxrc_0 airplane +40deMboVqPI_1 bird +44FNsfkuWOI_0 elephant +44hlNbUHL2c_0 person +44672wUoOwM_0 person +46NXMVbpzZw_1 boat +468w3XkLHwc_1 boat +47Nn3ywWOlU_1 person +47cBD-Sq9mw_1 person +48ujtCaCdX0_0 person +49CwzbRIUpI_1 bird +49a6EgDu-ZU_0 truck +4-GpBan9Z8s_0 horse +4_A8f6NAa3w_0 person +5BHekdOG9JA_0 elephant +5Bw22C4nsb4_0 train +5CPZUe4hn0M_0 airplane +5DS23LkFit8_0 cow +5DVU9wTDzN8_0 skateboard +5DjSsYt5N4Q_0 skateboard +5FAbvaslTQE_0 motorcycle +5FXOzzaKrcw_0 airplane +5Fro7Bo628Y_0 boat +5FxLl3jd7I0_0 skateboard +5F5fgLUXow8_3 car +5F5fgLUXow8_7 car +5F5fgLUXow8_8 car +5F5fgLUXow8_0 car +5F5fgLUXow8_1 car +5F5fgLUXow8_2 car +5F5fgLUXow8_4 car +5GMISyAZA9o_0 horse +5GpziDmwRTc_0 cow +5JPqrGj3CgM_0 giraffe +5Ko6ZHOz4IY_0 person +5Lbguv7FGLM_1 bird +5M7Wx_HJ_XQ_0 person +5Nz4g-YykuI_0 person +5O41yfenxMM_1 cow +5PeDI6XI7is_3 horse +5Qd986abGHo_0 person +5Tza7UHp3xE_0 train +5WTw98UVUCo_1 horse +5WpjuP9uJrI_2 bird +5W8Hg8uhxgQ_0 car +5W8Hg8uhxgQ_1 car +5XEAIdyb_ng_0 person +5XcopMzRch4_0 skateboard +5YbA5Uw-5xQ_0 person +5YbA5Uw-5xQ_1 person +5bIO0Gl25u0_1 boat +5bIO0Gl25u0_0 boat +5dGbxAkTDPM_1 cow +5dRnssv_jug_0 cow +5eRQh3Rv1Lk_0 horse +5eak0nLYZC0_0 airplane +5enKNMe1Dpg_0 person +5eq6WBGMyME_0 giraffe +5eum6r7kxbw_1 giraffe +5eum6r7kxbw_4 giraffe +5e84K5OEIj4_0 person +5fXoyIBk_gI_0 person +5gNgZQ0nDW8_4 knife +5gNgZQ0nDW8_5 knife +5gNhZJMFmis_0 bear +5gNhZJMFmis_1 bear +5gbLo2hItTs_0 person +5geZjQ9qAJU_0 motorcycle +5iDhgUX1kdc_0 person +5iwoWJK4GGo_0 car +5ll8fjNhIzg_0 person +5lv2GCs3_E0_0 person +5l9rlcuS7pE_0 bus +5mocfP3c3JE_0 bear +5mqvNWXtMCU_0 cat +5nAuDbKmWLY_0 elephant +5nC2ZXfE-sg_0 train +5nkh3PK6lBs_0 cow +5of5t38DQL4_0 cow +5okxoIw3cJI_0 skateboard +5ovlgihl130_0 knife +5phhj08_8hI_0 dog +5psIBlFu-yQ_0 person +5rh7nf5z_O0_1 cow +5rkM4mLsQoU_0 knife +5sIj93XnVc0_1 motorcycle +5sjUnvABkko_0 airplane +5s4kqURLLo4_0 person +5toRpAYrY_4_0 person +5uYObEyAbCQ_0 horse +5ukcjpXOopg_0 person +5vPXxAEGTrw_0 airplane +5vUtusnPXXs_0 bird +5vaBUAh4HkU_0 airplane +5yMeqHPiJgY_1 horse +5yMeqHPiJgY_2 horse +5yMeqHPiJgY_3 horse +5yeSANffSRk_0 person +5yeSANffSRk_1 person +5zJuhMtO1F8_0 bird +5zKtWxffw-0_0 boat +51rDJW0FO8w_0 horse +51yQTVmaMXw_1 motorcycle +52UjkVxSSHg_0 person +52VFNDCXUHg_0 person +52pNzl4wrxs_0 person +52wdqvYrGv4_0 person +522wkm19sH0_0 bus +54icMYqqx_w_1 bus +55H1IVgQj3E_0 boat +56BI7lH0z1g_0 person +56bgv0J-cXw_1 knife +56bgv0J-cXw_4 knife +56r2wDCnuQQ_0 horse +57BY7QjcYbQ_0 person +574FA_5qp-s_0 bus +58K_ZPS7U8M_0 person +58gdyHWU6do_1 truck +5802XdQdAkU_0 cow +59JJGcB2jRE_0 horse +59JJGcB2jRE_4 horse +59JJGcB2jRE_2 horse +59cXOQc39JI_1 zebra +5928Zhy26yI_1 giraffe +5-Oeo8tmauc_0 bus +5-Oeo8tmauc_1 bus +5-Oeo8tmauc_2 bus +5-O2xma48Tw_0 bird +5-y_Rrr8shw_2 person +5_njhyGAXdE_0 truck +5_njhyGAXdE_1 truck +5_njhyGAXdE_2 truck +5_2sGSrZblY_0 person +6AD9GHHEVkE_1 boat +6AYkCla5Oak_0 car +6A2LC4_gts4_0 person +6A2LC4_gts4_1 person +6BB65BA-pS0_1 knife +6CKS3WJRpHI_0 person +6C1C-L7L6CE_0 person +6DQ-H73b62Y_0 person +6EHcwJiML3g_2 person +6GlBa-DUEqc_0 person +6HlTwF1ZDkc_0 person +6HrWOx9GfzI_0 person +6JrhpITR8po_1 cow +6JrhpITR8po_0 cow +6KpKxtwB1Ww_0 person +6LiW0KF3fME_0 person +6Meaw8zK8sU_0 person +6M3wDWZDZJ8_0 car +6M4oJG9NsRM_0 person +6Nc1z3BVzlI_0 bear +6OlxDr5vZuI_2 horse +6Ona04rOyZk_0 cat +6PBKPTCkWOo_0 person +6PH-mFChsi0_0 airplane +6PwE6q6pebc_1 person +6QFs4uNsSt4_0 person +6RIFox7kLqY_0 cat +6SBj14dkVPM_0 cow +6SdX0oE9Qm8_0 cat +6SizSdOT9_k_0 horse +6TEQ098RfzE_0 cow +6TQ8X9G4BAY_0 dog +6UQbOOWv_ws_0 cow +6UQbOOWv_ws_2 cow +6XUe2u2YWkQ_2 umbrella +6bJPo4tzJvQ_0 person +6bco275PcUs_0 truck +6bco275PcUs_1 truck +6gwBOlfJ34I_1 skateboard +6gww5ltOLQY_0 bird +6gww5ltOLQY_1 bird +6hAG7632JjA_0 cat +6htKDjHsXPQ_0 cow +6id5A0aiJbE_0 train +6jwTUZocHXY_0 horse +6j07-PcNv70_0 truck +6kjb3q8EygI_0 elephant +6lAxaY4AYB8_0 person +6lPPfWdeBvU_0 cat +6l3SpVgqJY0_0 person +6mYi-vXre4Q_0 truck +6med3JZ2k40_0 person +6miVJWDTBCY_1 train +6n6fVeWD_m0_0 knife +6o61j0KZ9cA_0 person +6pPjKIlVlfY_0 bicycle +6pnenPlFGIc_0 motorcycle +6pnenPlFGIc_1 motorcycle +6pny8Td3Lvs_0 horse +6qRIuIHqJco_0 train +6qSDUh2ES7Q_0 person +6qVpY1VC2hU_1 cat +6qhp1FiVbBQ_0 knife +6rlBtCRp25g_0 cat +6r0rYZCL4Qc_0 person +6r0rYZCL4Qc_1 person +6uMmknjq0mg_0 bicycle +6uSZqFsKMGI_0 cow +6um2PoiKfT4_0 motorcycle +6vAGEaKFuyY_1 bus +6vAGEaKFuyY_2 bus +6vafM_LKdhA_0 umbrella +6vc8u4MPWkY_0 bird +6v_NKAM10sA_5 bicycle +6v_NKAM10sA_9 bicycle +6v_NKAM10sA_10 bicycle +6v_NKAM10sA_11 bicycle +6v_NKAM10sA_12 bicycle +6v_NKAM10sA_0 bicycle +6v_NKAM10sA_1 bicycle +6w-nwNFVYm8_0 motorcycle +6y78kiGuIAk_0 person +6zPET0HFVaM_3 train +6zPgsocp4bY_1 bicycle +6zPgsocp4bY_2 bicycle +6zPgsocp4bY_3 bicycle +6zPgsocp4bY_7 bicycle +6zPgsocp4bY_9 bicycle +6zW1omjPFRs_0 elephant +6zW1omjPFRs_1 elephant +62MEsd3U1aQ_0 person +62PpG0cOcbU_0 person +63vKOQ-SCBw_0 airplane +63_kFJCm2pQ_0 person +64yGcACuF0g_0 cat +64yZxDGH92I_0 person +64-njkqyF7k_0 bus +65u4BXZ10RY_0 dog +65u4BXZ10RY_1 dog +654ylXfWndU_0 boat +66HPgc7Up3o_6 horse +66HPgc7Up3o_3 horse +66HPgc7Up3o_4 horse +66HPgc7Up3o_7 horse +66N_Ju8hg2U_0 knife +665JKK-JrTc_0 person +67kix34dj7A_0 truck +67wgEifQYpg_0 person +68KnEa1hVf8_0 bicycle +6-Z9S0qy8ys_1 dog +6-7x1BQGuQE_0 person +6_nq4o_21CY_0 elephant +7BBHz6wfABM_0 person +7CYm8WQftfw_0 bus +7DIXCjEBWLw_0 airplane +7D-ypPzaTDI_0 person +7GvsFRhnxWc_1 bird +7G2sXxpbA-0_0 motorcycle +7HXox1j1X2A_0 person +7Hthj7LhsoI_1 elephant +7H1AhHiyip0_0 person +7JXhfaNTsUQ_2 bird +7K61aiu3UsM_0 person +7K61aiu3UsM_1 person +7LKG4ReUlZA_0 person +7LTKFUY3Xo8_0 bird +7MQZWaHzUOo_0 cow +7Mb_dcvNENM_7 bicycle +7Mb_dcvNENM_3 bicycle +7Mb_dcvNENM_4 bicycle +7Mb_dcvNENM_5 bicycle +7Mb_dcvNENM_6 bicycle +7NDhXBp57BY_0 person +7NFMDZwqdw4_0 person +7Ng49Wed4Y4_0 cow +7Ng49Wed4Y4_2 cow +7NxvW5DSQrI_0 cat +7O8grUKQopY_0 person +7PeZgsBNi5g_0 car +7QauV6mvt98_0 car +7RxzfGFIxSg_0 cat +7Strg7qJtW0_0 elephant +7Strg7qJtW0_7 elephant +7Strg7qJtW0_1 elephant +7Strg7qJtW0_2 elephant +7Strg7qJtW0_3 elephant +7VQ8QZRnxD8_0 cow +7Vcfkjk--Fc_1 dog +7V5Q7Te4KNI_0 bus +7WZRhdW3Ysw_0 elephant +7XQ-ufhX7gc_0 cow +7XQ-ufhX7gc_1 cow +7YCox5adS-U_0 person +7YQM-nFSHW4_0 knife +7Ya_jh9VO9U_0 person +7aTla4KAK_U_1 knife +7bqlApH5GwI_1 bicycle +7dFEYp-1Hgo_0 person +7e8WNmzDHUQ_0 person +7fF7heSCMTw_0 motorcycle +7fRxyCT-Wao_0 giraffe +7fRxyCT-Wao_2 giraffe +7fSMUG5W8vk_2 bicycle +7g8SI9aAn70_1 umbrella +7hIJP5KExbE_1 elephant +7hjOcuaQm7I_0 elephant +7kPsaqRQBCk_0 knife +7kl1hNW3aVs_0 motorcycle +7k7H9RKhOF8_1 skateboard +7k7H9RKhOF8_3 skateboard +7ledBa3nuVs_0 train +7ledBa3nuVs_2 train +7m98zjjFHbU_0 person +7ntsSm-LFZA_0 person +7ntsSm-LFZA_1 person +7nzY38tPTM0_0 person +7nzY38tPTM0_1 person +7n8C_td0Th8_0 horse +7p4RxRFB_Eg_0 horse +7rE5dIroJwQ_0 person +7rifGM-TuPA_0 horse +7trl2U6nLPc_0 horse +7vyHv7_GxbQ_0 person +7wte1pPBwQ0_1 bear +7w616uMnI_8_0 elephant +7w616uMnI_8_1 elephant +7x8K4JervhE_0 bus +7y0joj813H0_3 bus +7zRaB-2B7B0_0 train +72RzEHZFYtM_2 airplane +72RzEHZFYtM_1 airplane +73Wonc3xnLI_0 person +73Z4KnnAMlU_0 person +74gRlu6vJLY_0 person +747bRdBUPSw_0 person +76LU6w1a7UA_1 airplane +76PIBEC3WVo_0 skateboard +77GychcVDRI_0 person +77dvi_3OU4M_0 person +79MY0qku9uc_1 horse +8AgZqrCi9no_0 horse +8BK44tI3ACo_0 person +8BQJVHpHFsU_1 dog +8BQJVHpHFsU_2 dog +8B3bbakza_Q_0 person +8CJRCoA1Rps_0 person +8ClOgfNAjXs_0 giraffe +8DlXcc1IXlw_0 car +8EwDzFi34nA_0 cow +8FEp5ORJ27g_0 truck +8FyuS809d24_0 dog +8FyuS809d24_1 dog +8GGi0BXLCaM_0 person +8G_vBzM-Ws4_1 umbrella +8HcyzPUv5ag_0 person +8JIpa6tfWzo_0 airplane +8JKJnuN_UTI_0 cow +8JhHIO_7m-0_0 cow +8LGnOH6nDbc_0 dog +8LGnOH6nDbc_1 dog +8Lx004yCltY_6 elephant +8Lx004yCltY_12 elephant +8Lx004yCltY_18 elephant +8MO_kng7L-s_0 person +8MO_kng7L-s_1 person +8NlznvdsNJQ_2 boat +8N8hB2Au4JE_0 person +8Pbd3dd3v5E_0 person +8Pz3xq3KFo0_6 elephant +8Pz3xq3KFo0_4 elephant +8Qr-5_567tI_1 truck +8Q8g9z-DNF8_0 motorcycle +8RZsKbffdqI_0 cat +8Sbz2MGzhp4_0 person +8UcqXCLmq-M_1 elephant +8UcqXCLmq-M_3 elephant +8UcqXCLmq-M_6 elephant +8UcqXCLmq-M_7 elephant +8Ul_lS0g_RU_0 skateboard +8UmKRVMR08g_2 bird +8U7BmrkcgcU_2 truck +8VkbfdMQrR8_0 person +8VzjERSpeS4_1 elephant +8VzjERSpeS4_0 elephant +8WcBoYh-IMg_0 bird +8X27eyH-tx0_0 car +8Zi2bsTpMeY_0 person +8ZmfZDMaVhg_0 cat +8Z1GvAHPEnU_0 cat +8a1bD-UgfKE_0 truck +8bD-aqWPxwM_0 motorcycle +8bE_FhrjBuM_2 skateboard +8bE_FhrjBuM_0 skateboard +8bE_FhrjBuM_1 skateboard +8bypIjdKgEI_0 person +8b5fedIr-WQ_0 person +8cNzCe26dSM_0 person +8cSOpd9gaPE_0 cow +8c8TJ_Jzngk_0 horse +8d6950aGpD8_0 dog +8eK3ktD9j5o_0 horse +8eK3ktD9j5o_1 horse +8ewNcrMhg-w_0 person +8gsiG2Wu3YM_0 giraffe +8hFEJz0GvfU_0 elephant +8hwa44VMdLs_0 person +8h8Cpkugo-Y_0 elephant +8h_eY7zEIqk_3 truck +8iBiHoA_OJk_0 person +8jRFQ8RKZ0s_1 car +8kTREwiI1-8_0 cow +8kn6PJbtsyA_0 bicycle +8kn6PJbtsyA_1 bicycle +8kn6PJbtsyA_2 bicycle +8kn6PJbtsyA_3 bicycle +8kn6PJbtsyA_4 bicycle +8lKXEr2W3yM_0 knife +8lMRKCKyBwk_0 person +8lonNtE99PI_1 person +8l7UmXXnAJs_0 truck +8mlHevSC8cc_0 car +8m-GtOBjbzY_1 bicycle +8nWSGwlJyPQ_0 cat +8nsl-r_i0AI_0 person +8n3A8io4GNU_0 person +8okfUuO0Pvc_1 bird +8poWB-6q4xk_1 bicycle +8p2saqn2kiQ_0 person +8qFJg_AoKeY_0 cow +8qulLm8MYrM_0 bus +8rBxRMDJEFY_0 person +8sOWPIfWpCM_0 horse +8tKto2zQWUg_0 elephant +8uoYlmdJlAo_1 knife +8wdvLn40CTk_5 bus +8wdvLn40CTk_0 bus +8wdvLn40CTk_1 bus +8wv3WJBJmog_1 dog +8yFZUTSjpos_0 motorcycle +8zBx-nHUqBY_0 person +8zUAF30Hu6c_1 train +8zUAF30Hu6c_2 train +8zftjn0I9TQ_0 truck +8zftjn0I9TQ_2 truck +8zjgYuK3nVY_0 person +8z-YLOzAxb4_2 bicycle +8z-YLOzAxb4_4 bicycle +8z-sTr28AWk_0 skateboard +80CcMFD-Rcw_1 person +80CcMFD-Rcw_0 person +81cNVk8boEM_0 person +82lK9rB-e08_1 motorcycle +84P6L_HrN48_0 bird +88N5__h7Zdo_0 bicycle +89a461_gh2o_0 bicycle +89mGhzBokZ8_1 bear +89qfsC77BYk_0 person +8_oUj2cuPdo_0 dog +9A-VO1zCZJ4_1 motorcycle +9BVgbNz-bi8_0 person +9BVgbNz-bi8_1 person +9BpvtvUGG5g_0 person +9DGpFjuUVBk_0 person +9DY0dTRH5xI_0 bird +9D5ORdC7BuQ_6 bus +9ELQq5BMR1U_0 person +9E8VBIYmTGY_1 cow +9E8VBIYmTGY_0 cow +9FAB9BrcQls_0 person +9FTOvdcnzDQ_0 airplane +9GdhKEBm0pA_6 bicycle +9GdhKEBm0pA_1 bicycle +9GdhKEBm0pA_3 bicycle +9HqapwdLVzk_4 knife +9KfdTsjy53o_0 truck +9LHbQA-pT0U_2 horse +9LJRUmW_AII_0 boat +9LOpNoTFWKg_0 truck +9LOpNoTFWKg_4 truck +9LOpNoTFWKg_1 truck +9LOpNoTFWKg_2 truck +9LqExSHe9y8_0 knife +9Ls7gSZQt1w_2 bear +9NsmnTdRiik_0 airplane +9PsezNNV0Jc_1 airplane +9PsezNNV0Jc_2 airplane +9PsezNNV0Jc_0 airplane +9Q3srzApSJU_0 person +9RGlWjTKvE0_0 bus +9RZCK24Shec_0 cat +9ScZtgWAJZA_1 person +9SgrA5Q1d94_0 person +9ShZpsmuvc4_2 skateboard +9ShZpsmuvc4_1 skateboard +9UU2h6M8DJk_2 truck +9UwLiWKOIGY_0 person +9U-tccGetsk_0 knife +9VwSYjCCRYk_1 truck +9VwSYjCCRYk_2 truck +9WDPvYpnrfU_1 truck +9WDt0JjOFIA_0 person +9YVkZ7QxD5E_0 person +9Y6XZFO31JU_0 cow +9ZpZZoTtySo_1 bear +9Z0Jz1tesQ4_4 cow +9Z0Jz1tesQ4_1 cow +9Z0Jz1tesQ4_2 cow +9Z0Jz1tesQ4_3 cow +9aQOAnspXGo_1 bird +9bYPYgMQVjU_0 person +9bzmQFGK8m8_0 person +9dOPPvgyMqk_0 person +9eI_0DoOE08_0 person +9eI_0DoOE08_1 person +9g8o260G10k_0 bird +9hAU80xKWy0_0 truck +9jS5MThAtmo_0 person +9kGuuCx39JA_0 motorcycle +9lsXenPJ-X8_1 bird +9ltdzlYXfp8_0 cow +9ltdzlYXfp8_3 cow +9muklrcigJY_0 dog +9nqU8e9IUPU_0 skateboard +9pEB8cjvPSQ_1 horse +9qamzN9bwxw_0 person +9rvVWyyuud0_0 person +9r1FvK19XV8_0 person +9uhZRDsQKnc_0 person +9yt1if13PHk_0 elephant +9y5txKR57mc_0 bird +9zBCjCtH3Eg_0 horse +9zqk5w8Qx1Q_1 bicycle +9zroWMwZHGI_1 person +907A5I4-LpA_0 motorcycle +91SWvU-5TcI_0 person +92MaWPuO8PI_0 boat +92560YiwSP0_0 person +93gyPa_dPGU_0 truck +946wiAK4Seg_1 person +95CV_olHtcI_0 person +96WWGXa4QrI_0 car +96akJFw5SPU_0 truck +96iqXHgOXKY_0 person +98XiF-Z__aI_0 cat +99Tb7HSFn3I_0 person +9_bFE0FUq_c_1 knife +-A-tBuMjU8s_0 cat +-B4YQQLrOfI_2 skateboard +-C0rYHhL_x4_0 motorcycle +-DYf49hlRSE_0 person +-Ebcfmg0-eE_0 person +-E05a-eQSwY_0 umbrella +-FMaVn21dYU_1 horse +-Fu9coX9J-A_0 person +-Fu9coX9J-A_1 person +-Gk4iMiEMCc_0 person +-LVtIbelA3M_0 horse +-LXr7LdXtrk_0 boat +-LjAFTF5WP4_0 bicycle +-LjAFTF5WP4_1 bicycle +-LjAFTF5WP4_3 bicycle +-MpLPuviQ00_0 person +-M_jT3EYgcc_0 person +-NWvB2g952Q_2 bird +-OZt785bbpY_0 airplane +-P37Y1G6oHk_2 airplane +-P37Y1G6oHk_3 airplane +-P37Y1G6oHk_0 airplane +-QBeUV_OkJg_1 dog +-QQCINzsXpw_0 person +-Q6g2xZ0PxY_1 airplane +-RjxMfaV-Vo_1 knife +-RjxMfaV-Vo_2 knife +-SPHavKGd3M_0 skateboard +-S8L2HACCPE_12 elephant +-S8L2HACCPE_1 elephant +-S8L2HACCPE_10 elephant +-TKKOo1FfAI_0 bird +-VgWHKeRRjs_0 airplane +-VgWHKeRRjs_1 airplane +-WyEyKxdZOQ_0 person +-XWeGpACKwc_0 skateboard +-Xj6MiGVWt0_0 person +-XwZnoNm0FU_0 dog +-ZDO95E0pl8_0 person +-anX-ad_gHQ_0 person +-avz2OsPIq4_2 bicycle +-bJkl4q5f-A_0 bird +-c1b7nHzGn4_0 airplane +-dQnNlBQp3o_0 person +-db_SToBhkg_2 motorcycle +-eZUdm8ERQQ_0 person +-e42Pb0YeOY_0 cat +-fnhznKC3CU_0 person +-f0JLwuyuTM_0 person +-jL0HOXwYls_0 person +-kLIF2a7yeU_0 person +-k1TxEpOgnA_0 person +-l9NS6DuRPI_0 person +-mgNwLW3ODc_0 person +-mwDgqLpu-k_0 skateboard +-nOfuA8B7As_1 bicycle +-nzXunuZac4_0 cat +-oG6YVPhC_I_0 horse +-o28rb1UnYA_0 car +-sJOJNjOCBI_0 motorcycle +-sJOJNjOCBI_1 motorcycle +-sWch1rnO10_0 person +-th9NS9hl6s_0 cow +-uP01llwXFY_5 boat +-uP01llwXFY_1 boat +-u5MNR-9ClU_0 person +-vkMKVuweFA_0 person +-v7FXEhgwtE_0 person +-y652b4w3Ss_0 bird +-zqHD6Jthqg_0 person +-0U1vm6LIi8_0 person +-1je1K1ihbk_2 skateboard +-2iw3MzUP2Y_0 motorcycle +-3OvKcu5P2U_0 car +-3fzr21Ov5w_0 person +-6vJDV8XnWE_0 boat +-7Im8MyvaXU_0 cat +--8shIp3t0I_0 knife +-_iBuJTwjw8_1 horse +-_xag4X_Do0_0 bird +_ATEx5gbBEQ_0 knife +_ATEx5gbBEQ_1 knife +_AcvI8VF5ig_0 cow +_Ae4vmwt8uA_0 person +_Auvs-o5Pck_0 truck +_A8nA25Tq8c_1 person +_C_yvxdjVGA_2 horse +_C_yvxdjVGA_0 horse +_DXAxnPIiBU_0 cow +_D-9w3aSX50_0 person +_GyE3cPQ6U8_0 car +_HN1_MjnjWo_2 elephant +_HYaLoOKE84_1 cow +_IhkqtAQHBw_0 train +_InrHPE8Umw_0 motorcycle +_IpUnYit3Pg_0 dog +_JNG6qK6INs_3 bear +_KzDIvt0cCk_0 person +_K6jYgDC1JU_0 airplane +_NZ4o-omJLE_0 umbrella +_NtOMcyVAp4_1 dog +_OmnjH4t-IY_0 person +_QF0A9B-xB8_0 person +_QRy9nd4kcg_0 airplane +_Q9M8QAjSMk_0 person +_Rd-wEO2r10_0 person +_R6nlDzh6Tc_0 person +_R6nlDzh6Tc_2 person +_T0O1BlYjaU_1 bear +_VegkTdhrQE_0 motorcycle +_WKJaPPBz8Q_0 umbrella +_WcqTpLKkww_1 truck +_Y6_E1l4blQ_1 knife +_ZDU4qi4lcI_2 cow +_ZDU4qi4lcI_0 cow +_ZDU4qi4lcI_1 cow +_ZHmkH59bCQ_0 person +_ZXqLyRe4n0_0 elephant +_ZsogS9uPJQ_0 person +_akq_DieEWE_0 person +_akq_DieEWE_1 person +_bO2sdIelLY_0 person +_dC_upYbxWI_0 knife +_eCb7mFYyIg_0 motorcycle +_egWujmdZtw_0 person +_epdfuB0qRM_0 car +_e5Vvy9DJ9E_4 bear +_e5Vvy9DJ9E_0 bear +_foK5Dvj1As_0 bird +_hryEVGKNuw_0 horse +_iY4AnGfq0Y_0 train +_jBzwdg0QRA_1 bus +_jci9tIBIB4_5 truck +_kdhlRke8uI_0 person +_kfdh_5bI-Q_0 person +_lmD-useijU_0 person +_mJBwuCegJ0_12 truck +_mJBwuCegJ0_1 truck +_mJBwuCegJ0_2 truck +_mJBwuCegJ0_8 truck +_mJBwuCegJ0_9 truck +_oRtPVRmtwo_0 dog +_pEHwWe2seA_5 elephant +_sV1Jd1uiYg_0 person +_tZU1XTOML4_0 boat +_usyDpllGBo_0 horse +_vBAv8cBoqE_0 skateboard +_vV0wdWq0cU_0 person +_xMVx44FbT4_0 horse +_xQn3TupjYs_0 cat +_xy58m6yCko_0 motorcycle +_yQQjARqD1s_0 boat +_yfoe4GCA0Q_4 airplane +_yfoe4GCA0Q_2 airplane +_yv5Cwbm9EA_0 person +_zIDofZkgS4_1 truck +_zQt1CSSKyA_1 bicycle +_0eR2vQAEqE_0 elephant +_0eR2vQAEqE_1 elephant +_17u-cPTYt0_0 car +_17u-cPTYt0_1 car +_2mIWIhbDPY_0 bus +_37U5Elgnck_0 person +_5fE6dP48FM_0 cow +_5sIT4l5izM_0 knife +_6qUuUUYvUQ_0 person +_7zbbqEa3nw_1 train +_7zbbqEa3nw_4 train +_8VTthFkvS0_0 bird +_8iyumFI4sQ_1 elephant +_8iyumFI4sQ_2 elephant +_8iyumFI4sQ_3 elephant +_81FImml2gk_0 dog +_9bypka_Q4c_0 bus +_-CvwC7H730_0 person +_-XcxnQLKPM_0 dog +__Q5A7gExpI_0 person diff --git a/ltr/data_specs/youtubevos_jjtrain.txt b/ltr/data_specs/youtubevos_jjtrain.txt new file mode 100755 index 0000000..df9c792 --- /dev/null +++ b/ltr/data_specs/youtubevos_jjtrain.txt @@ -0,0 +1,3171 @@ +d9db6f1983 +05aa652648 +8be56f165d +b941aef1a0 +ae2cecf5f6 +e97cfac475 +c36240d96f +30dbdb2cd6 +eebf45e5c5 +a8999af004 +a5c2b2c3e1 +c3509e728d +9e4c752cd0 +2142af8795 +70a6b875fa +bcd1d39afb +ff773b1a1e +ed72ae8825 +0866d4c5e3 +1b88ba1aa4 +ce25872021 +3543d8334c +b220939e93 +ee947ed771 +2457274dbc +1dfbe6f586 +36299c687c +8f1600f7f6 +5ee23ca60e +c1268d998c +606c86c455 +9cfee34031 +b44e32a42b +3a3bf84b13 +668364b372 +10eced835e +983e66cbfc +30c35c64a4 +6b1e04d00d +b1fc9c64e1 +8056117b89 +cfd9d4ae47 +392ecb43bd +3113140ee8 +ce9b015a5e +b7c2a469c4 +38924f4a7f +4b54d2587f +b6b4738b78 +079049275c +080196ef01 +4b97cc7b8d +8aa817e4ed +301f72ee11 +3c019c0a24 +f1d99239eb +0ee92053d6 +ecfedd4035 +298c844fc9 +f6c7906ca4 +142d2621f5 +e2b608d309 +75eaf5669d +d4dd1a7d00 +d6476cad55 +cff035928b +e7ea10db28 +2dc0838721 +566cef4959 +c15b922281 +67ea169a3b +1157472b95 +a6470dbbf5 +a965504e88 +6c4ce479a4 +4daa179861 +89379487e0 +e1ab7957f4 +7f1723f0d5 +282fcab00b +44f7422af2 +b2a9c51e1b +10b31f5431 +fa4370d74d +faf5222dc3 +c46deb2956 +bbd31510cf +08e1e4de15 +c3641dfc5a +ef96501dd0 +cb2e35d610 +d87160957b +3802d458c0 +3a4e32ed5e +80b790703b +41059fdd0b +dc504a4f79 +b8fb75864e +472da1c484 +9e4de40671 +7163b8085f +ae8545d581 +b68fc1b217 +b06ed37831 +306121e726 +81dffd30fb +f6708fa398 +9684ef9d64 +aaff16c2db +fdb8b04124 +ff15a5eff6 +b5aae1fe25 +f3fc0ea80b +9153762797 +6f96e91d81 +22b13084b2 +5ede4d2f7a +c053e35f97 +58c374917e +9c5180d23a +5914c30f05 +aaba004362 +25dc80db7c +01ed275c6e +94e76cbaf6 +b7a2c2c83c +5bab55cdbe +45d9fc1357 +9a39112493 +8ef595ce82 +fa88d48a92 +aef3e2cb0e +4634736113 +ba3a775d7b +17cb4afe89 +5d0e07d126 +2293c99f3f +ea286a581c +2d01eef98e +747f1b1f2f +b26b219919 +56fc0e8cf9 +5da6b2dc5d +a416b56b53 +c3be369fdb +898fa256c8 +2376440551 +1705796b02 +6a80d2e2e5 +b27b28d581 +c219d6f8dc +f8603c26b2 +ede3552eae +bd0d849da4 +ff2ada194f +17656bae77 +3dcbc0635b +57bfb7fa4c +a39c9bca52 +6061ddbb65 +01c3111683 +26b895d91e +3a33f4d225 +81aa1286fb +d3f5c309cc +5fd1c7a3df +f9bd1fabf5 +54e8867b83 +551acbffd5 +e5be628030 +13870016f9 +c2406ae462 +46565a75f8 +c37b17a4a9 +31539918c4 +3fea675fab +992bd0779a +0a7a2514aa +dbd66dc3ac +cce03c2a9b +9c29c047b0 +5316d11eb7 +29a0356a2b +7e2f212fd3 +bcc5d8095e +b96c57d2c7 +0fb173695b +a61d9bbd9b +f3b24a7d28 +c279e641ee +62ad6e121c +03a63e187f +fa8b904cc9 +097b471ed8 +f1ec5c08fa +685a1fa9cf +84be115c09 +6376d49f31 +e22ffc469b +a800d85e88 +f23e95dbe5 +c0f49c6579 +5eec4d9fe5 +6d7a3d0c21 +d7c7e064a6 +de5e480f05 +acf2c4b745 +9c293ef4d7 +3935e63b41 +8bfff50747 +d535bb1b97 +7f5faedf8b +69f0af42a6 +7b39fe7371 +d521aba02e +6406c72e4d +c70f9be8c5 +4c7710908f +59d53d1649 +6e2f834767 +f09d74856f +e7c8de1fce +67e717d6bd +b179c4a82d +3f4f3bc803 +545468262b +edd663afa3 +0f17fa6fcb +17418e81ea +dd0f4c9fb9 +986b5a5e18 +804382b1ad +5519b4ad13 +a3a945dc8c +b9d3b92169 +9fcb310255 +5f29ced797 +30fc77d72f +54a4260bb1 +28075f33c1 +b87d56925a +2f53822e88 +e44e0b4917 +3eb39d11ab +f0eb3179f7 +8a27e2407c +a4f05d681c +adfd15ceef +7cc9258dee +941c870569 +11a6ba8c94 +282b0d51f5 +cec3415361 +79d9e00c55 +219057c87b +b41e0f1f19 +b6d65a9eef +418bb97e10 +0dab85b6d3 +7d18074fef +52355da42f +4350f3ab60 +1250423f7c +b4eaea9e6b +8ec3065ec2 +7143fb084f +536b17bcea +2dcc417f82 +75d5c2f32a +82d15514d6 +8bd1b45776 +6d12e30c48 +3e1448b01c +df1b0e4620 +3b9ad0c5a9 +05a569d8aa +968492136a +a5eaeac80b +c31fa6c598 +1f1beb8daa +d0acde820f +1416925cf2 +3c700f073e +26f7784762 +28c972dacd +0c44a9d545 +5069c7c5b3 +cea7697b25 +fa08e00a56 +c9d1c60cd0 +f46fe141b0 +6c54265f16 +c49f07d46d +b37c01396e +8929c7d5d9 +7e9b6bef69 +5bddc3ba25 +76a75f4eee +977bff0d10 +efb24f950f +b6b4f847b7 +2c1e8c8e2f +994b9b47ba +a15ccc5658 +86d3755680 +c046fd0edb +2efb07554a +d7b34e5d73 +e19edcd34b +82b865c7dd +327dc4cabf +42da96b87c +39d584b09f +94db712ac8 +da6c68708f +a9804f2a08 +79921b21c2 +a3b40a0c1e +efce0c1868 +1187bbd0e3 +63281534dc +911ac9979b +96fc924050 +934bdc2893 +6316faaebc +d927fae122 +8ee198467a +83d40bcba5 +272f4163d0 +3a7bdde9b8 +695b61a2b0 +9893d9202d +3db907ac77 +8193671178 +9e16f115d8 +dd8636bd8b +0de4923598 +9f66640cda +c2baaff7bf +2c2c076c01 +d7fbf545b3 +145fdc3ac5 +6b1b6ef28b +365b0501ea +e00baaae9b +58adc6d8b6 +c7030b28bd +75cae39a8f +64f55f1478 +c2be6900f2 +e48e8b4263 +f891f8eaa1 +6c23d89189 +f2b83d5ce5 +7106b020ab +9a4e9fd399 +2cf114677e +b50f4b90d5 +ea16d3fd48 +c8c8b28781 +6d6d2b8843 +93e811e393 +c42917fe82 +65ff12bcb5 +42ffdcdee9 +7d11b4450f +adabbd1cc4 +755bd1fbeb +4d983cad9f +f51c5ac84b +a71e0481f5 +9ddefc6165 +4478f694bb +ed911a1f63 +fd31890379 +d600046f73 +ed3291c3d6 +1b43fa74b4 +7799df28e7 +92dabbe3a0 +47a05fbd1d +d5695544d8 +1e1e42529d +a1dfdd0cac +1c4090c75b +dbfc417d28 +3b9ba0894a +63d90c2bae +1981e763cc +bb89a6b18a +b96a95bc7a +7570ca7f3c +6cbfd32c5e +a7491f1578 +b72ac6e10b +106242403f +4dfaee19e5 +bc4ce49105 +c5fba7b341 +c55784c766 +c10d07c90d +3cd5e035ef +dac71659b8 +1c41934f84 +ced49d26df +d05279c0bd +03e2b57b0e +6aa8e50445 +4625f3f2d3 +a41ec95906 +534a560609 +c8a46ff0c8 +1032e80b37 +0a275e7f12 +18ac264b76 +d154e3388e +7a56e759c5 +d021d68bca +8c0a3251c3 +541c4da30f +7cec7296ae +0693719753 +42f5c61c49 +0a2f2bd294 +e402d1afa5 +115ee1072c +585dd0f208 +5cbf7dc388 +11ccf5e99d +96fbe5fc23 +49405b7900 +9108130458 +cb35a87504 +e348377191 +49e7326789 +c9de9c22c4 +8d87897d66 +f7a8521432 +79f014085e +4b556740ff +0b1627e896 +d26f6ed9b0 +8f918598b6 +4e82b1df57 +e3bf38265f +23b3beafcc +8f81c9405a +c20fd5e597 +ef44945428 +15097d5d4e +06ee361788 +9720eff40f +650b0165e4 +075c701292 +8b99a77ac5 +597ff7ef78 +39bc49a28c +91bb8df281 +8d81f6f899 +322da43910 +6abf0ba6b2 +5031d5a036 +e672ccd250 +d95707bca8 +b1d1cd2e6e +6846ac20df +db59282ace +cbb410da64 +d7797196b4 +2cdbf5f0a7 +962f045bf5 +2cd01cf915 +c0a1e06710 +c8557963f3 +d973b31c00 +7923bad550 +b0c7f11f9f +092e4ff450 +598935ef05 +003234408d +0b68535614 +de36b216da +92b5c1fc6d +04d62d9d98 +ead5d3835a +a21ffe4d81 +28449fa0dc +b70d231781 +5ede9767da +eda8ab984b +6a37a91708 +d3932ad4bd +574b682c19 +4d67c59727 +0274193026 +84752191a3 +97d9d008c7 +27a5f92a9c +01b80e8e1a +5352c4a70e +a29bfc29ec +b24af1c35c +1d6ff083aa +16af445362 +c61fe6ed7c +4fded94004 +3f0b0dfddd +948f3ae6fb +d280fcd1cb +46630b55ae +558aa072f0 +5497dc3712 +40709263a8 +abab2e6c20 +d38bc77e2c +b6b8d502d4 +65ab7e1d98 +b0df7c5c5c +3bd9a9b515 +832b5ef379 +40b8e50f82 +f1af214222 +a2c996e429 +882b9e4500 +f3a0ffc7d9 +e92e1b7623 +46bf4e8709 +1d746352a6 +59fe33e560 +6e4f460caf +7828af8bff +4918d10ff0 +511e8ecd7f +2c29fabcf1 +f6474735be +e25fa6cf39 +49ec3e406a +8bdb091ccf +df5e2152b3 +6ade215eb0 +de6a9382ca +a023141022 +7e6d1cc1f4 +652b67d960 +b37a1d69e3 +f2b7c9b1f3 +50243cffdc +95b58b8004 +3ae1a4016f +8cac6900fe +0f6b69b2f4 +e8f8341dec +5abe46ba6d +be116aab29 +75595b453d +f22648fe12 +5cb0cfb98f +e128124b9d +c438858117 +5a13a73fe5 +6538d00d73 +4b2974eff4 +d0a83bcd9f +cabba242c2 +bb87ff58bd +6cc791250b +645913b63a +6353f09384 +6acc6049d9 +e499228f26 +89b874547b +4cd9a4b1ef +5fb8aded6a +38c197c10e +a5ea2b93b6 +4db117e6c5 +e4af66e163 +69b8c17047 +b77e5eddef +99c4277aee +681249baa3 +04460a7a52 +a24f63e8a2 +8b91036e5c +aa51934e1b +01082ae388 +0c11c6bf7b +a0bc6c611d +b0de66ca08 +337975816b +56cc449917 +6b9c43c25a +dd601f9a3f +f2445b1572 +6fc6fce380 +e85c5118a7 +215dfc0f73 +c4f256f5d5 +93901858ee +3252398f09 +2489d78320 +2c54cfbb78 +17cd79a434 +180abc8378 +ce7d1c8117 +7de45f75e5 +27cf2af1f3 +f9daf64494 +7a13a5dfaa +d8e77a222d +b48efceb3e +686dafaac9 +346aacf439 +6979b4d83f +916942666f +6ba99cc41f +8aca214360 +952633c37f +9d12ceaddc +768671f652 +5bf23bc9d3 +aa1a338630 +98ac6f93d9 +ae499c7514 +7bb7dac673 +e625e1d27b +d9edc82650 +e0be1f6e17 +1cb44b920d +ebe56e5ef8 +222904eb5b +9a72318dbf +902bc16b37 +d295ea2dc7 +2db0576a5c +ddcd450d47 +18913cc690 +95bd88da55 +abe61a11bb +203594a418 +a73d3c3902 +e57f4f668b +8f5d3622d8 +9caa49d3ff +da01070697 +d6faaaf726 +82fec06574 +ba795f3089 +4083cfbe15 +923137bb7f +0444918a5f +e2167379b8 +82e117b900 +8f8c974d53 +da28d94ff4 +d45f62717e +dbba735a50 +9c3ce23bd1 +96825c4714 +cc892997b8 +17b0d94172 +07652ee4af +0358b938c1 +75fa586876 +0ca839ee9a +19696b67d3 +7b5cf7837f +9041a0f489 +a301869dea +80db581acd +f2ab2b84d6 +757a69746e +2a5c09acbd +614e7078db +529b12de78 +aedd71f125 +547b3fb23b +e11adcd05d +1dba687bce +6c9e3b7d1a +6ab9dce449 +117cc76bda +77920f1708 +6dd36705b9 +4de4ce4dea +b6ec609f7b +b241e95235 +25c750c6db +3bb4e10ed7 +b1d7c03927 +73eac9156b +c0e8d4635c +c69689f177 +ce49b1f474 +1ef8e17def +ef65268834 +c95cd17749 +29e630bdd0 +324e35111a +68f6e7fbf0 +d0696bd5fc +e93f83e512 +b493c25c7f +b08dcc490e +fbc645f602 +2589956baa +852a4d6067 +acbf581760 +a20fd34693 +c45411dacb +c30a7b62c9 +835e3b67d7 +d763bd6d96 +e653883384 +6363c87314 +4e824b9247 +285b69e223 +4bf5763d24 +722803f4f2 +967b90590e +c0e973ad85 +be2a367a7b +1b2d31306f +44f4f57099 +4cef87b649 +404d02e0c0 +7584129dc3 +540850e1c7 +fbfd25174f +fcd20a2509 +e39e3e0a06 +e7784ec8ad +e3e3245492 +fd6789b3fe +1fc9538993 +939378f6d6 +82c1517708 +058a7592c8 +614e571886 +5c42aba280 +ea3b94a591 +55eda6c77e +f4207ca554 +f659251be2 +3e3e4be915 +578f211b86 +7bb5bb25cd +2d03593bdc +0970d28339 +ee9a7840ae +8bd7a2dda6 +9a50af4bfb +0450095513 +fa67744af3 +a7203deb2d +2c11fedca8 +d6c02bfda5 +09a6841288 +df39a0d9df +a17c62e764 +e53e21aa02 +651066ed39 +4783d2ab87 +3a4565e5ec +a0b208fe2e +653821d680 +762e1b3487 +6ef0b44654 +01694ad9c8 +6c5123e4bc +85dc1041c6 +b2edc76bd2 +76962c7ed2 +b2a26bc912 +4cf208e9b3 +17d8ca1a37 +0fa7b59356 +79bf95e624 +383bb93111 +e78d450a9c +4b19c529fb +732df1eb05 +e71629e7b5 +db231a7100 +a06722ba82 +e676107765 +37d4ae24fc +a14f709908 +39f6f6ffb1 +4e4e06a749 +117757b4b8 +8515f6db22 +2e03b8127a +985c3be474 +4a3471bdf5 +09c9ce80c7 +94091a4873 +972c187c0d +c6e55c33f0 +5b1001cc4f +285580b7c4 +73f8441a88 +7eb2605d96 +ec1299aee4 +d704766646 +1fa350df76 +09c5bad17b +9445c3eca2 +8662d9441a +02d28375aa +1257a1bc67 +d699d3d798 +9fd2fd4d47 +2be06fb855 +ef0a8e8f35 +8f1ce0a411 +e8073a140b +eb6992fe02 +db7f267c3f +ff204daf4b +e950befd5f +1abf16d21d +5c52fa4662 +c2b974ec8c +0b5b5e8e5a +ab2e1b5577 +017ac35701 +17c7bcd146 +b63094ba0c +038b2cc71d +b9dd4b306c +334cb835ac +b247940d01 +ba5e1f4faa +19a6e62b9b +377db65f60 +93e6f1fdf9 +6fdf1ca888 +76b90809f7 +223a0e0657 +6c11a5f11f +fb92abdaeb +c60897f093 +01c76f0a82 +7b5388c9f1 +c3128733ee +5790ac295d +fbe53dc8e8 +08c8450db7 +d0483573dc +d5853d9b8b +579393912d +bbe0256a75 +6135e27185 +df8ad5deb9 +14c21cea0d +a37db3a2b3 +68fa8300b4 +7b733d31d8 +b82e5ad1c9 +84e0922cf7 +34370a710f +99c04108d3 +9869a12362 +baff40d29d +3aa7fce8b6 +c20a5ccc99 +711dce6fe2 +0a23765d15 +57c7fc2183 +4620e66b1e +1bd87fe9ab +0b9cea51ca +cd8f49734c +07353b2a89 +14a6b5a139 +3332334ac4 +f36483c824 +6afd692f1a +e828dd02db +c909ceea97 +4bffa92b67 +5a91c5ab6d +119cf20728 +bbaa9a036a +6eb30b3b5a +b1f540a4bd +f7f2a38ac6 +ad573f7d31 +ae9cd16dbf +446b8b5f7a +191e74c01d +c01878083f +f9c68eaa64 +d0fb600c73 +9437c715eb +85a4f4a639 +9955b76bf5 +e2fcc99117 +2431dec2fd +ad65ebaa07 +909dbd1b76 +75a058dbcd +e352cb59c8 +8ee2368f40 +9a7fc1548b +bd3ec46511 +66e98e78f5 +6c81b014e9 +63ebbcf874 +7c03a18ec1 +80f16b016d +85b1eda0d9 +3c8320669c +edd22c46a2 +01baa5a4e1 +7320b49b13 +f0483250c8 +8f3b4a84ad +02264db755 +84a4bf147d +ca3787d3d3 +c18e19d922 +7f3658460e +cc8728052e +f40a683fbe +c7cef4aee2 +1514e3563f +122896672d +603189a03c +864ffce4fe +e26e486026 +e8fa21eb13 +120cb9514d +644081b88d +b7d69da8f0 +bddcc15521 +5589637cc4 +55341f42da +b751e767f2 +cd47a23e31 +beb921a4c9 +24b0868d92 +b1d7fe2753 +75cee6caf0 +4ae13de1cd +78e29dd4c3 +bcc241b081 +b84b8ae665 +6a986084e2 +ce4f0a266f +e98d57d99c +e699da0cdf +8792c193a0 +d4f4f7c9c3 +21f1d089f5 +c89147e6e8 +edeab61ee0 +11c722a456 +513aada14e +c82235a49a +01c4cb5ffe +e33c18412a +a78758d4ce +d55cb7a205 +d5df027f0c +34fbee00a6 +b3eb7f05eb +a6d8a4228d +e42b6d3dbb +5bafef6e79 +2c44bb6d1c +418035eec9 +217bae91e5 +f52104164b +cad8a85930 +d177e9878a +997117a654 +3f3b15f083 +871015806c +dad980385d +328d918c7d +4f827b0751 +7d55f791f0 +837c618777 +c8b869a04a +77e7f38f4d +d991cb471d +df9705605c +89ebb27334 +485f3944cd +893f658345 +f7e6bd58be +98e909f9d1 +d6ac0e065c +806b6223ab +11feabe596 +ce7dbeaa88 +eaa99191cb +be9b29e08e +7082544248 +d847e24abd +559824b6f6 +bb1b0ee89f +4a8af115de +bf5374f122 +a66e0b7ad4 +c44beb7472 +ba1f03c811 +7e1e3bbcc1 +e4004ee048 +9418653742 +cfda2dcce5 +101caff7d4 +13325cfa14 +5ff8b85b53 +2039c3aecb +453b65daa4 +e436d0ff1e +59b175e138 +cf85ab28b5 +3fd96c5267 +c4ff9b4885 +4810c3fbca +b0f5295608 +ae0b50ff4f +88d3b80af6 +ef9a2e976b +17c220e4f6 +dc71bc6918 +bd321d2be6 +fbe541dd73 +6a96c8815d +94e4b66cff +ac31fcd6d0 +cd4dc03dc0 +903e87e0d6 +b678b7db00 +f7e5b84928 +4100b57a3a +258b3b33c6 +57bd3bcda4 +42264230ba +f7a71e7574 +3a0d3a81b7 +9773492949 +eb7921facd +5f808d0d2d +85ab85510c +b13abc0c69 +1022fe8417 +4d5c23c554 +1fe2f0ec59 +50efbe152f +240118e58a +acf44293a2 +50168342bf +9efb47b595 +7550949b1d +8b473f0f5d +a36bdc4cab +1a3e87c566 +0503bf89c9 +f9681d5103 +26de3d18ca +80e12193df +1a5fe06b00 +61d08ef5a1 +74ec2b3073 +0cd7ac0ac0 +f22d21f1f1 +16288ea47f +6da6adabc0 +ce6866aa19 +12bddb2bcb +f6f59d986f +c844f03dc7 +16c3fa4d5d +92e3159361 +29f2332d30 +9a767493b7 +b4d84bc371 +bdb74e333f +b1399fac64 +a0e6da5ba2 +145d5d7c03 +b4e5ad97aa +1239c87234 +87d1f7d741 +16fe9fb444 +444d4e0596 +0630391881 +4cad2e93bc +93f623d716 +8d4ab94e1c +9e29b1982c +84d95c4350 +84f0cfc665 +081207976e +e5ce96a55d +8bffc4374b +f9750192a4 +5f6ebe94a9 +c7a1a17308 +36d5b1493b +30318465dc +14fd28ae99 +4facd8f0e8 +08e48c1a48 +61344be2f6 +afe1a35c1e +5f51876986 +eeb90cb569 +37fa0001e8 +df05214b82 +4894b3b9ea +b15bf4453b +c73c8e747f +65866dce22 +ba3fcd417d +4f062fbc63 +f1489baff4 +d3f55f5ab8 +ab23b78715 +83daba503a +0e27472bea +77eea6845e +99c6b1acf2 +0700264286 +2f309c206b +6bdab62bcd +ca91e99105 +ef5dde449d +44b4dad8c9 +be3e3cffbd +ba3c7f2a31 +b7f675fb98 +4c397b6fd4 +8666521b13 +eeed0c7d73 +fc918e3a40 +19c00c11f9 +011ac0a06f +2c41fa0648 +4b02c272b3 +29d779f9e3 +6927723ba5 +952ec313fe +2120d9c3c3 +ae20d09dea +3ec273c8d5 +7f21063c3a +8e98ae3c84 +8ca3f6e6c1 +c7ebfc5d57 +5566ab97e1 +a39a0eb433 +a4757bd7af +d756f5a694 +a5122c6ec6 +bb337f9830 +b9b6bdde0c +4d26d41091 +43b5555faa +3cadbcc404 +f9f3852526 +193ffaa217 +ef0061a309 +15f67b0fab +c4272227b0 +d708e1350c +53e32d21ea +15d1fb3de5 +5c01f6171a +802b45c8c4 +89bdb021d5 +5de9b90f24 +d355e634ef +53bf5964ce +df3c430c24 +2a18873352 +0ce06e0121 +04f21da964 +ee07583fc0 +d48ebdcf74 +070c918ca7 +020cd28cd2 +5ac7c88d0c +bfe262322f +84696b5a5e +97ba838008 +d2ede5d862 +3b6e983b5b +30176e3615 +7f838baf2b +90bc4a319a +abbe2d15a0 +d343d4a77d +582d463e5c +2c1a94ebfb +72b01281f9 +f5bddf5598 +d73a60a244 +9057bfa502 +e0a938c6e7 +8f1204a732 +eaed1a87be +2c04b887b7 +7b918ccb8a +fe6c244f63 +c34d120a88 +6057307f6e +57243657cf +d65a7bae86 +256ad2e3fc +7094ac0f60 +45f8128b97 +3e2845307e +d5ee40e5d0 +5104aa1fea +4536c882e5 +504dd9c0fd +62ede7b2da +4e72856cc7 +f1dc710cf4 +feec95b386 +ff49d36d20 +61f5d1282c +8b3645d826 +a6a810a92c +e65f134e0b +981ff580cf +94a33abeab +07cc1c7d74 +32a7cd687b +e8ed1a3ccf +e88b6736e4 +03c95b4dae +ab90f0d24b +c34365e2d7 +ec579c2f96 +f9ea6b7f31 +d719cf9316 +bf28751739 +d247420c4c +22d9f5ab0c +e22de45950 +c3b0c6e180 +2e00393d96 +0974a213dc +33e29d7e91 +89c802ff9c +614afe7975 +4fa160f8a3 +71d67b9e19 +91b67d58d4 +3054ca937d +c92c8c3c75 +ec139ff675 +0155498c85 +5f1193e72b +bea1f6e62c +5c44bf8ab6 +c96465ee65 +1a8bdc5842 +df20a8650d +388843df90 +a412bb2fef +df2bc56d7c +d14d1e9289 +a235d01ec1 +4dfdd7fab0 +aa175e5ec7 +86a8ae4223 +1e4be70796 +06840b2bbe +827171a845 +ce712ed3c9 +dfc0d3d27a +2bffe4cf9a +5ef5860ac6 +2f724132b9 +2117fa0c14 +89363acf76 +9b473fc8fe +5aba1057fe +734ea0d7fb +f6d6f15ae7 +2f7e3517ae +a5b5b59139 +68cc4a1970 +420caf0859 +b3d9ca2aee +ba8a291e6a +e4ffb6d0dd +a4a506521f +d53b955f78 +f2dd6e3add +fa9b9d2426 +110d26fa3a +42f17cd14d +eac7a59bc1 +b4805ae9cd +f3704d5663 +e41ceb5d81 +c3bf1e40c2 +a64a40f3eb +224e7c833e +69491c0ebf +e3f4635e03 +58fc75fd42 +5ef6573a99 +6c56848429 +b70a2c0ab1 +e6261d2348 +0738493cbf +58b9bcf656 +1f1a2a9fc0 +52ee406d9e +ebbf5c9ee1 +e4ef0a3a34 +78aff3ebc0 +68807d8601 +dbf4a5b32b +3a7ad86ce0 +7c73340ab7 +c8f6cba9fd +11cbcb0b4d +9c166c86ff +838eb3bd89 +d689658f06 +b93963f214 +07913cdda7 +e9d3c78bf3 +05a0a513df +8899d8cbcd +6893778c77 +1a6c0fbd1e +ca91c69e3b +ca4b99cbac +3b3b0af2ee +1ecdc2941c +b8e16df00b +adfdd52eac +a522b1aa79 +a378053b20 +a4bac06849 +587250f3c3 +322505c47f +2d4d015c64 +da6003fc72 +5f32cf521e +2a8c5b1342 +df01f277f1 +6e618d26b6 +678a2357eb +eb8fce51a6 +b58d853734 +54657855cd +c6d9526e0d +28475208ca +463c0f4fdd +b61f998772 +bcaad44ad7 +f66981af4e +d6eed152c4 +7136a4453f +0e9f2785ec +d2484bff33 +9268e1f88a +fe985d510a +2c3ea7ee7d +134d06dbf9 +5a25c22770 +d454e8444f +7559b4b0ec +3db1ddb8cf +af5fd24a36 +9966f3adac +e27bbedbfe +3ef2fa99cb +702fd8b729 +efe828affa +c9862d82dc +b22099b419 +e95e5afe0f +909655b4a6 +9c7feca6e4 +7e24023274 +98a8b06e7f +847eeeb2e0 +ea065cc205 +598c2ad3b2 +78d3676361 +35d01a438a +dac361e828 +013099c098 +7053e4f41e +d200838929 +4a341402d0 +c9734b451f +307bbb7409 +594065ddd7 +7368d5c053 +edb8878849 +78c7c03716 +075926c651 +35573455c7 +81541b3725 +bc318160de +324c4c38f6 +ea5672ffa8 +fa04c615cf +53e274f1b5 +6848e012ef +e0b2ceee6f +fc33b1ffd6 +2263a8782b +9bccfd04de +3c2784fc0d +2df356de14 +728e81c319 +3efc6e9892 +733824d431 +da080507b9 +9a9c0e15b7 +4680236c9d +fc96cda9d8 +61da008958 +318dfe2ce2 +aebb242b5c +540cb31cfe +382caa3cb4 +b76df6e059 +df365282c6 +984f0f1c36 +d429c67630 +9f3734c3a4 +3f18728586 +7435690c8c +c8edab0415 +b05ad0d345 +dfdbf91a99 +59bf0a149f +189b44e92c +bfd91d0742 +fe6a5596b8 +adb0b5a270 +de46e4943b +6b3a24395c +05579ca250 +94031f12f2 +29de7b6579 +a50eb5a0ea +281629cb41 +caeb6b6cbb +319f725ad9 +bf2232b58d +a9e42e3c0c +6bf2e853b1 +0bcfc4177d +1ec8b2566b +c6a12c131f +c70682c7cc +0bd864064c +b4b565aba1 +484ab44de4 +692ca0e1a2 +aed4e0b4c4 +4fdfef4dea +b7f31b7c36 +c813dcf13c +47354fab09 +0e803c7d73 +d04258ca14 +5b07b4229d +3d8997aeb6 +c5e845c6b7 +1acd0f993b +a4ba7753d9 +0e621feb6c +c14826ad5e +1b7e8bb255 +fcf637e3ab +2680861931 +fb49738155 +aade4cf385 +5ff66140d6 +5ca36173e4 +869fa45998 +d49ab52a25 +c82ecb90cb +f7cf4b4a39 +2481ceafeb +e9ec1b7ea8 +83424c9fbf +bdccd69dde +b86c17caa6 +bb1c770fe7 +3454303a08 +6ead4670f7 +5cb49a19cf +c33f28249a +0e04f636c4 +6908ccf557 +643092bc41 +9467c8617c +161eb59aad +d3e6e05e16 +b0623a6232 +af8826d084 +839bc71489 +fb08c64e8c +01c783268c +af3de54c7a +6a5977be3a +3ea4c49bbe +8939db6354 +3d690473e1 +6b0b1044fe +a3f4d58010 +8647d06439 +ff692fdc56 +c6c18e860f +9fc5c3af78 +38eb2bf67f +9d2101e9bf +dc7771b3be +4a7191f08a +7ca6843a72 +8f0a653ad7 +e4d19c8283 +e0bdb5dfae +40f4026bf5 +93a22bee7e +b6d79a0845 +29dde5f12b +fb4cbc514b +02668dbffa +cdc6b1c032 +b6f92a308d +98043e2d14 +6d6eea5682 +ee9706ac7f +09ff54fef4 +50568fbcfb +79e20fc008 +6b79be238c +0355e92655 +67741db50a +e5d6b70a9f +4af8cb323f +7666351b84 +a50c10060f +26bc786d4f +804c558adb +83ca8bcad0 +17622326fd +2bf545c2f5 +517d276725 +98595f2bb4 +ad97cc064a +0d9cc80d7e +58163c37cd +f77ab47923 +cad5a656a9 +17f7a6d805 +8b523bdfd6 +1180cbf814 +07c62c3d11 +98fe7f0410 +3245e049fb +1233ac8596 +a066e739c1 +42eb5a5b0f +082900c5d4 +f2c276018f +9d407c3aeb +ecae59b782 +fb47fcea1e +f697fe8e8f +772a0fa402 +16d1d65c27 +76693db153 +6a078cdcc7 +1da256d146 +e36ac982f0 +4e70279712 +7367a42892 +2ac9ef904a +fbd77444cd +a1aaf63216 +bb334e5cdb +e668ef5664 +ab33a18ded +13960b3c84 +2261d421ea +2ce660f123 +683de643d9 +9a3254a76e +abbe73cd21 +398f5d5f19 +62a0840bb5 +3450382ef7 +92a28cd233 +1f2609ee13 +9a84ccf6a7 +61b481a78b +b40b25055c +f1ba9e1a3e +8b4f6d1186 +3c90d225ee +402316532d +0e05f0e232 +71e06dda39 +3a2c1f66e5 +43d63b752a +61fd977e49 +43a6c21f37 +2e0f886168 +24ddf05c03 +c9188f4980 +3935291688 +e6deab5e0b +f253b3486d +4e87a639bc +a2e6608bfa +e588433c1e +d90e3cf281 +a5f350a87e +b871db031a +51b37b6d97 +4cdfe3c2b2 +27f0d5f8a2 +f2e7653f16 +9151cad9b5 +fb4e6062f7 +bac9db04f5 +a77b7a91df +d5cae12834 +34b109755a +ed3e6fc1a5 +e415093d27 +9cb2f1b646 +add21ee467 +adc648f890 +25d2c3fe5d +c9c3cb3797 +e72f6104e1 +1f8014b7fd +8dcccd2bd2 +1d3087d5e5 +d632fd3510 +920c959958 +be15e18f1e +5b5babc719 +d6e12ef6cc +daebc12b77 +a973f239cd +eb383cb82e +2703e52a6a +09a348f4fa +479cad5da3 +01ff60d1fa +360e25da17 +aa45f1caaf +7bb0abc031 +af8ad72057 +456fb9362e +150ea711f2 +238b84e67f +3026bb2f61 +97476eb38d +45a89f35e1 +22472f7395 +be376082d0 +958073d2b0 +6377809ec2 +bb2d220506 +be8b72fe37 +18bad52083 +bf961167a6 +cb3f22b0cf +2383d8aafd +3ed3f91271 +f4dd51ac35 +4a885fa3ef +1c9f9eb792 +bd2c94730f +91634ee0c9 +6cb2ee722a +e597442c99 +b3779a1962 +4a50f3d2e9 +e9bc0760ba +b24f600420 +24440e0ac7 +909c2eca88 +13e3070469 +b54278cd43 +b3996e4ba5 +5eecf07824 +794e6fc49f +37ddce7f8b +98b6974d12 +a2c146ab0d +2bb00c2434 +fc28cb305e +3ae81609d6 +51eea1fdac +83ce590d7f +d292a50c7f +09338adea8 +a6027a53cf +d6c1b5749e +7d783f67a9 +9d15f8cb3c +19367bb94e +114e7676ec +63e544a5d6 +ad6255bc29 +0762ea9a30 +6f4789045c +4a6e3faaa1 +e9502628f6 +90118a42ee +41a34c20e7 +c8c7b306a6 +895c96d671 +04fe256562 +232c09b75b +39c3c7bf55 +369c9977e1 +3c5ff93faf +9893a3cf77 +b0cca8b830 +fe9db35d15 +b11099eb09 +d1802f69f8 +0065b171f9 +19ee80dac6 +7e7cdcb284 +07ac33b6df +b64fca8100 +c8ab107dd5 +288c117201 +767856368b +e8485a2615 +756f76f74d +dba35b87fd +637681cd6b +49b16e9377 +f46184f393 +de2ab79dfa +6899d2dabe +3a1d55d22b +9f97bc74c8 +04735c5030 +f14409b6a3 +47269e0499 +7d508fb027 +f94aafdeef +12eebedc35 +a0071ae316 +2b6c30bbbd +a3f2878017 +e221105579 +bf461df850 +5fd3da9f68 +2fc9520b53 +a919392446 +b5a09a83f3 +e0fb58395e +69c67f109f +3cb9be84a5 +defb71c741 +79bc006280 +b673e7dcfb +19e8bc6178 +5252195e8a +322b237865 +b19b3e22c0 +e2b37ff8af +d9e52be2d2 +9b997664ba +7bf3820566 +fffe5f8df6 +e674510b20 +9eadcea74f +e4922e3726 +e275760245 +f4daa3dbd5 +e8cee8bf0b +72690ef572 +fd542da05e +e78922e5e6 +792218456c +9bebf1b87f +b2456267df +df96aa609a +34046fe4f2 +3e3a819865 +f233257395 +774f6c2175 +2a6d9099d1 +770a441457 +6997636670 +f2f333ad06 +279214115d +12ec9b93ee +919ac864d6 +f8819b42ec +08d50b926c +ea138b6617 +ddb2da4c14 +72cadebbce +a2bcd10a33 +589f65f5d5 +16763cccbb +e6267d46bc +351cfd6bc5 +91be106477 +5bc77844da +4cff5c9e42 +db0968cdd3 +ed9ff4f649 +7aecf9f7ac +5f6f14977c +0d97fba242 +de4ddbccb1 +714d902095 +9584092d0b +bc6b8d6371 +a7392d4438 +9df0b1e298 +104f1ab997 +6b25d6528a +670f12e88f +9715cc83dc +a61cf4389d +e4e2983570 +77610860e0 +de827c510d +f89288d10c +486a8ac57e +4f37e86797 +16adde065e +268ac7d3fc +d7411662da +46f5093c59 +58a07c17d5 +7c88ce3c5b +08931bc458 +c937eb0b83 +202b767bbc +fe24b0677d +b6a1df3764 +4aa9d6527f +625817a927 +2ee2edba2a +b1457e3b5e +f99d535567 +2268cb1ffd +f635e9568b +9b4f081782 +f6283e8af5 +dde8e67fb4 +3193da4835 +2465bf515d +175169edbb +f4aa882cfd +4f470cc3ae +270ed80c12 +5247d4b160 +639bddef11 +d74875ea7c +04667fabaa +9bce4583a2 +0043f083b5 +44b5ece1b9 +466839cb37 +076f206928 +aa27d7b868 +d367fb5253 +a38950ebc2 +0f74ec5599 +caac5807f8 +e42d60f0d4 +e914b8cac8 +c4cc40c1fc +24866b4e6a +2b08f37364 +9877af5063 +5b27d19f0b +69a436750b +da0e944cc4 +8891aa6dfa +ad54468654 +f6fe8c90a5 +4932911f80 +78896c6baf +c44676563f +c94b31b5e5 +ecb33a0448 +7f559f9d4a +98911292da +14f9bd22b5 +9a02c70ba2 +9ce6f765c3 +44eaf8f51e +66852243cb +1a359a6c1a +fb5ba7ad6e +ecfff22fd6 +ddfc3f04d3 +499bf07002 +0b34ec1d55 +c7637cab0a +3c713cbf2f +ec387be051 +a653d5c23b +e63463d8c6 +91c33b4290 +946d71fb5d +54b98b8d5e +51eef778af +0044fa5fba +524b470fd0 +2bdd82fb86 +d195d31128 +5bd1f84545 +f3734c4913 +8eb0d315c1 +b5eb64d419 +1336440745 +a2a800ab63 +04990d1915 +3dd48ed55f +2f53998171 +57d5289a01 +46e18e42f1 +dd9fe6c6ac +0f1ac8e9a3 +08feb87790 +b0b0731606 +37e10d33af +708535b72a +9574b81269 +c3dd38bf98 +8873ab2806 +c9999b7c48 +86c85d27df +a0b61c959e +2d183ac8c4 +b0aece727f +d88a403092 +3cc6f90cb2 +8dea22c533 +045f00aed2 +ef07f1a655 +5b263013bf +28a8eb9623 +48375af288 +f7783ae5f2 +b94d34d14e +0e9ebe4e3c +d55f247a45 +f6cd0a8016 +37e45c6247 +3504df2fda +e1a1544285 +6eca26c202 +bb1fc34f99 +9ecec5f8ea +e92b6bfea4 +f9b6217959 +a2f2a55f01 +edbfdfe1b4 +90107941f3 +c71f30d7b6 +a48c53c454 +ac46bd8087 +e90c10fc4c +ffb904207d +9579b73761 +cdcfe008ad +bc17ab8a99 +5161e1fa57 +a36e8c79d8 +9a68631d24 +c3c760b015 +79e9db913e +e9460b55f9 +a96b84b8d2 +104e64565f +600803c0f6 +5fee2570ae +225aba51d9 +b938d79dff +9077e69b08 +58045fde85 +e43d7ae2c5 +4feb3ac01f +b190b1aa65 +693cbf0c9d +247d729e36 +94bf1af5e3 +c544da6854 +6a42176f2e +0368107cf1 +93e2feacce +dcf8c93617 +33098cedb4 +8cbbe62ccd +7b74fd7b98 +3ae2deaec2 +890976d6da +bf551a6f60 +49058178b8 +fdb28d0fbb +aa07b7c1c0 +b7bcbe6466 +da070ea4b7 +83d3130ba0 +1dec5446c8 +99fecd4efb +ce2776f78f +b1fcbb3ced +2350d71b4b +0b285c47f6 +863b4049d7 +afcb331e1f +3c47ab95f8 +52d225ed52 +67ea809e0e +bd7e02b139 +b19c561fab +c598faa682 +05774f3a2c +721bb6f2cb +7ff84d66dd +13adaad9d9 +5edda6ee5a +cb15312003 +65dcf115ab +a590915345 +5e4849935a +b53f675641 +be5d1d89a0 +90d300f09b +00ad5016a4 +7419e2ab3f +84a4b29286 +a34f440f33 +165c3c8cd4 +f6e501892c +f5966cadd2 +636e4872e0 +6944fc833b +17e33f4330 +1cd10e62be +1afd39a1fa +796e6762ce +77d8aa8691 +8ddd51ca94 +4c9b5017be +ef232a2aed +7eb26b8485 +f3085d6570 +2a3824ff31 +8be950d00f +b8c3210036 +9fbad86e20 +3db0d6b07e +362c5bc56e +3373891cdc +f0dfa18ba7 +6c623fac5f +b62c943664 +9e249b4982 +e8d97ebece +22f02efe3a +83ae88d217 +8c9ccfedc7 +824973babb +d8eb07c381 +61c7172650 +79fcbb433a +18b5cebc34 +f8af30d4b6 +ad397527b2 +1da4e956b1 +365f459863 +27303333e1 +fa9526bdf1 +c35e4fa6c4 +5b48ae16c5 +17d18604c3 +9582e0eb33 +64453cf61d +6fc9b44c00 +8749369ba0 +1b883843c0 +217c0d44e4 +4abb74bb52 +b5f1c0c96a +ded6069f7b +9f5b858101 +0536c9eed0 +ee40a1e491 +4f35be0e0b +f3e6c35ec3 +35637a827f +69340faa52 +d04a90aaff +b9004db86c +5c6ea7dac3 +12156b25b3 +96e1a5b4f8 +5eef7ed4f4 +197f3ab6f3 +6caeb928d6 +e424653b78 +98d044f206 +bb04e28695 +c27adaeac5 +1ad202e499 +4a088fe99a +5c83e96778 +c2b62567c1 +99fcba71e5 +b30bf47bcd +4867b84887 +75f7937438 +3a20a7583e +a402dc0dfe +50f290b95d +1145b49a5f +b382b09e25 +6e36e4929a +2c5537eddf +005a527edd +28bf9c3cf3 +90617b0954 +5c4c574894 +f15c607b92 +990f2742c7 +0a8c467cc3 +e0f7208874 +ed844e879f +2000c02f9d +11a0c3b724 +5c7668855e +5e35512dd7 +26011bc28b +27659fa7d6 +aaed233bf3 +fbaca0c9df +526df007a7 +7fa5f527e3 +1b96a498e5 +cfcd571fff +28f4a45190 +77ba4edc72 +e8962324e3 +a09c39472e +222597030f +caa8e97f81 +3e108fb65a +8bbeaad78b +8c09867481 +b70c052f2f +c479ee052e +728cda9b65 +cfc2e50b9d +d7697c8b13 +24b5207cd9 +a2bdaff3b0 +a18ad065fc +7a14bc9a36 +07177017e9 +91ca7dd9f3 +cae7ef3184 +39545e20b7 +5ab49d9de0 +f7782c430e +76379a3e69 +8a4a2fc105 +b01080b5d3 +64e05bf46e +b5ebb1d000 +1903f9ea15 +1a95752aca +d107a1457c +a83d06410d +fb63cd1236 +402680df52 +5e4ee19663 +fb23455a7f +94209c86f0 +64148128be +fd33551c28 +cff8191891 +b2f6b52100 +0990941758 +5a50640995 +de37403340 +e8da49ea6a +72cae058a5 +2d9a1a1d49 +e4428801bc +6c9d29d509 +857a387c86 +b9f43ef41e +79a5778027 +1bbc4c274f +4cd427b535 +cebbd826cf +d44a764409 +2a6a30a4ea +8200245704 +920329dd5e +53c30110b5 +45636d806a +b841cfb932 +6454f548fd +b064dbd4b7 +c1e8aeea45 +8883e991a9 +c64035b2e2 +b5f7fece90 +2b8b14954e +57c010175e +ee316eaed6 +aae78feda4 +c079a6482d +93da9aeddf +839381063f +ff97129478 +3c4db32d74 +c3edc48cbd +ebbb90e9f9 +1eb60959c8 +b60a76fe73 +69910460a4 +397abeae8f +9adf06d89b +4f424abded +b3dde1e1e9 +183ba3d652 +2b659a49d7 +c8f494f416 +a1bb65fb91 +ffc43fc345 +acf736a27b +358bf16f9e +f05b189097 +50c6f4fe3e +625b89d28a +35ab34cc34 +4a0255c865 +2d8f5e5025 +bd5b2e2848 +256dcc8ab8 +1daf812218 +3150b2ee57 +57c457cc75 +7d18c8c716 +85e081f3c7 +132852e094 +71d2665f35 +779e847a9a +625892cf0b +06fbb3fa2c +ea2545d64b +d3b088e593 +91f107082e +ae628f2cd4 +3d5aeac5ba +72edc08285 +a5cd17bb11 +077d32af19 +07238ffc58 +e0f217dd59 +595a0ceea6 +4fca07ad01 +d3eefae7c5 +21386f5978 +f5e2e7d6a0 +8dd3ab71b9 +f0a7607d63 +94cf3a8025 +f5f8a93a76 +3e91f10205 +3af847e62f +0860df21e2 +ad28f9b9d9 +23993ce90d +cd5ae611da +62f025e1bc +201a8d75e5 +3fff16d112 +6ca006e283 +be1a284edb +5c021681b7 +fea8ffcd36 +2cc5d9c5f6 +2f97d9fecb +bc4240b43c +859633d56a +f119bab27d +f54c67b9bb +78f1a1a54f +beeb8a3f92 +a31fccd2cc +f7961ac1f0 +e7c6354e77 +e6295f223f +95f74a9959 +3735480d18 +3609bc3f88 +0c817cc390 +16afd538ad +c82a7619a1 +bfcb05d88d +b86e50d82d +f470b9aeb0 +4dadd57153 +394638fc8b +81a58d2c6b +ea320da917 +cec41ad4f4 +97659ed431 +d4193011f3 +3b96d3492f +65f9afe51c +20e3e52e0a +e99706b555 +7dd409947e +5e1011df9a +735a7cf7b9 +390352cced +64750b825f +bb721eb9aa +a5f472caf4 +ee6f9b01f9 +4beaea4dbe +ff2ce142e8 +88ede83da2 +669b572898 +3fee8cbc9f +6adb31756c +63fff40b31 +ad4108ee8e +2f96f5fc6f +5b1df237d2 +fcb10d0f81 +7a802264c4 +1232b2f1d4 +a99738f24c +962781c601 +8799ab0118 +720b398b9c +86e61829a1 +1b3fa67f0e +e4b2095f58 +8604bb2b75 +0d3aad05d2 +b9166cbae9 +25ae395636 +49fbf0c98a +238d947c6b +7660005554 +964ad23b44 +54ebe34f6e +a66fc5053c +6c0949c51c +fe58b48235 +ef6cb5eae0 +8859dedf41 +59e3e6fae7 +a22349e647 +eaab4d746c +5e08de0ed7 +ef78972bc2 +d874654b52 +f305a56d9f +a832fa8790 +59623ec40b +3e680622d7 +375a49d38f +21d0edbf81 +5390a43a54 +697d4fdb02 +cef824a1e1 +ac2b431d5f +9bfc50d261 +c013f42ed7 +f1b77bd309 +6f67d7c4c4 +c32d4aa5d1 +e23cca5244 +6b928b7ba6 +a2052e4f6c +00917dcfc4 +50cce40173 +bfab1ad8f9 +ce1bc5743a +720e3fa04c +ef6359cea3 +854c48b02a +8def5bd3bf +05ffcfed85 +af0b54cee3 +5380eaabff +9fcc256871 +f34497c932 +08f561c65e +b34105a4e9 +392bc0f8a1 +5fba90767d +d8aee40f3f +2feb30f208 +c01faff1ed +8b0cfbab97 +ac3d3a126d +dc704dd647 +f7f6cb2d6d +c3e4274614 +432f9884f9 +1a8afbad92 +4399ffade3 +2a559dd27f +a2a80072d4 +f3400f1204 +1f64955634 +4523656564 +c26f7b5824 +f9823a32c2 +e6f065f2b9 +73e1852735 +b2b0baf470 +9a08e7a6f8 +e1194c2e9d +9d04c280b8 +abb50c8697 +feb1080388 +4fffec8479 +413bab0f0d +848e7835a0 +f895ae8cc1 +df9c91c4da +73329902ab +b920b256a6 +748b2d5c01 +7c78a2266d +521cfadcb4 +376bda9651 +8ecf51a971 +e158805399 +0379ddf557 +0f6072077b +d99d770820 +98c7c00a19 +89d6336c2b +2c6e63b7de +1aa3da3ee3 +7b49e03d4c +1ee0ac70ff +6df3637557 +09049f6fe3 +f7d49799ad +5c185cff1d +49c104258e +6b685eb75b +00a23ccf53 +466ba4ae0c +e252f46f0b +764271f0f3 +c0847b521a +0f5fbe16b0 +3a079fb484 +0ffcdb491c +ac2cb1b9eb +a61715bb1b +54e1054b0f +2abc8d66d2 +4f601d255a +fd7af75f4d +3290c0de97 +e2c87a6421 +3e38336da5 +567a2b4bd0 +49972c2d14 +e8b3018d36 +486e69c5bd +9498baa359 +7151c53b32 +885673ea17 +ed3cd5308d +65bd5eb4f5 +824ca5538f +52ff1ccd4a +f8db369b40 +7d74e3c2f6 +0e30020549 +e214b160f4 +8a5d6c619c +8273a03530 +65e9825801 +4ec9da329e +18b245ab49 +777e58ff3d +1178932d2f +c5b6da8602 +207bc6cf01 +93ff35e801 +8e3a83cf2d +9a3570a020 +d7572b7d8a +3988074b88 +d992c69d37 +eb6d7ab39e +0db5c427a5 +23b0c8a9ab +34a5ece7dd +5af15e4fc3 +19e061eb88 +94125907e3 +48bd66517d +3c090704aa +40a96c5cb1 +3e04a6be11 +2ebb017a26 +d9b63abc11 +18bb5144d5 +7a3c535f70 +d7157a9f44 +bec5e9edcd +764503c499 +0fc958cde2 +f714160545 +4aa2e0f865 +5e1ce354fd +df7626172f +f9d3e04c4f +a5da03aef1 +600be7f53e +74267f68b9 +68dcb40675 +96dfc49961 +0fe7b1a621 +9e6ddbb52d +0c3a04798c +f7b7cd5f44 +7c649c2aaf +fb2e19fa6e +a5ec5b0265 +30a20194ab +957f7bc48b +369dde050a +a977126596 +7d83a5d854 +15abbe0c52 +b5943b18ab +a046399a74 +cf13f5c95a +3d254b0bca +9e6319faeb +b4807569a5 +eb2f821c6f +ce5641b195 +e75a466eea +185bf64702 +834b50b31b +04fbad476e +5e8d00b974 +36c7dac02f +a3c502bec3 +374b479880 +c593a3f7ab +3064ad91e8 +75f99bd3b3 +3e7d8f363d +61cf7e40d2 +3de4ac4ec4 +96e6ff0917 +69aebf7669 +f5d85cfd17 +33639a2847 +e2bef4da9a +53253f2362 +1197e44b26 +78254660ea +1ca5673803 +b372a82edf +1f3876f8d0 +3b74a0fc20 +6ecad29e52 +6d7efa9b9e +c965afa713 +9b22b54ee4 +ee3f509537 +88b8274d67 +b8aaa59b75 +5255c9ca97 +4164faee0b +256bd83d5e +250116161c +51f384721c +48d83b48a4 +2038987336 +851f2f32c1 +2f2c65c2f3 +0b7dbfa3cb +ae01cdab63 +5e8d59dc31 +0e0930474b +fb34dfbb77 +2fbfa431ec +75b09ce005 +f0c7f86c29 +3f0c860359 +3aa876887d +a1bd8e5349 +f7afbf4947 +952058e2d0 +ff25f55852 +4f7386a1ab +3beef45388 +da690fee9f +0dbaf284f1 +83de906ec0 +126d203967 +93e85d8fd3 +ca346f17eb +f47eb7437f +556c79bbf2 +836ea92b15 +04194e1248 +2d4333577b +4182d51532 +b573c0677a +a6f4e0817f +f3986fba44 +bd96f9943a +efea4e0523 +c3b3d82e6c +4607f6c03c +fba22a6848 +1b73ea9fc2 +f95d217b70 +2f680909e6 +f8c3fb2b01 +fe7afec086 +7b0fd09c28 +12ad198c54 +6fce7f3226 +5e886ef78f +8b52fb5fba +fc9832eea4 +e391bc981e +f5f051e9b4 +49c879f82d +4b3154c159 +c7c2860db3 +524cee1534 +7a446a51e9 +b2432ae86d +f9e4cc5a0a +d9010348a1 +343bc6a65a +4f8db33a13 +22a1141970 +d724134cfd +797cd21f71 +bc3b9ee033 +9f30bfe61e +5458647306 +d4da13e9ba +6bf95df2b9 +e5fde1574c +a984e56893 +692eb57b63 +450787ac97 +72e8d1c1ff +772f2ffc3e +04474174a4 +e6be243065 +f4377499c2 +e21acb20ab +346e92ff37 +369893f3ad +06e224798e +9076f4b6db +f83f19e796 +b17ee70e8c +c16f09cb63 +8eddbab9f7 +72d8dba870 +c325c8201e +2a821394e3 +3e16c19634 +abeae8ce21 +684dc1c40c +474a796272 +79208585cd +8f3fdad3da +aa49e46432 +11e53de6f2 +e3d5b2cd21 +5afe381ae4 +950be91db1 +3649228783 +6eb2e1cd9e +351c822748 +20142b2f05 +de2f35b2fd +3aa3f1c9e8 +38fe9b3ed1 +0b6f9105fc +80ce2e351b +508189ac91 +fc6186f0bb +d42c0ff975 +1b8898785b +38b00f93d7 +68a2fad4ab +d182c4483a +f74c3888d7 +d2ebe0890f +8b518ee936 +86b2180703 +e22ddf8a1b +2fcd9f4c62 +64a43876b7 +d36d16358e +e4936852bb +8f2e05e814 +2f2d9b33be +25ad437e29 +1ab27ec7ea +faff0e15f1 +0bd37b23c1 +8953138465 +e803918710 +d86101499c +cae7b0a02b +f08928c6d3 +7ea5b49283 +4c51e75d66 +8cba221a1e +d69f757a3f +aa85278334 +baedae3442 +28c6b8f86a +2c05209105 +7551cbd537 +bbb4302dda +757cac96c6 +fdb3d1fb1e +525928f46f +8ff61619f6 +90cc785ddd +07b6e8fda8 +7c37d7991a +9047bf3222 +bda4a82837 +80e41b608f +45bf0e947d +7613df1f84 +c62188c536 +1669502269 +fdfce7e6fc +61ed178ecb +750be4c4d8 +bf8d0f5ada +da7a816676 +d79c834768 +7f02b3cfe2 +e76c55933f +054acb238f +768802b80d +720e7a5f1e +068f7dce6f +53143511e8 +cad673e375 +4e752f8075 +a7e6d6c29a +afb71e22c5 +71caded286 +390ca6f1d6 +bc141b9ad5 +9276f5ba47 +935feaba1b +e1e957085b +198afe39ae +cdd57027c2 +038c15a5dd +dbca076acd +6c99ea7c31 +2d33ad3935 +b85b78ac2b +2b69ee5c26 +8345358fb8 +5baaebdf00 +2e42410932 +d8596701b7 +0a7b27fde9 +939bdf742e +8643de22d0 +85f75187ad +3adac8d7da +4e49c2a9c7 +ca1828fa54 +2c0ad8cf39 +fcfd81727f +75cf58fb2c +401888b36c +674c12c92d +4416bdd6ac +92ebab216a +8ba782192f +569c282890 +2d3991d83e +bea83281b5 +7b18b3db87 +629995af95 +a5dd11de0d +3ee062a2fd +e845994987 +43326d9940 +74d4cee0a4 +ff66152b25 +715357be94 +675ed3e1ca +6dfe55e9e5 +f991ddb4c2 +b06f5888e6 +0df28a9101 +549c56f1d4 +d4034a7fdf +081d8250cb +8dda6bf10f +d87069ba86 +41124e36de +457e717a14 +b258fb0b7d +d01608c2a5 +83a8151377 +9a2f2c0f86 +92128fbf4b +f507a1b9dc +accafc3531 +05fdbbdd7a +07129e14a4 +ea345f3627 +caecf0a5db +eb6ac20a01 +967bffe201 +98ba3c9417 +659832db64 +ae1bcbd423 +b964c57da4 +63d37e9fd3 +4804ee2767 +69023db81f +675c27208a +4e7a28907f +ac783ef388 +28e392de91 +30085a2cc6 +a6bc36937f +69e0e7b868 +2125235a49 +3a98867cbe +a4065a7eda +1724db7671 +1de4a9e537 +a35e0206da +5d1e24b6e3 +9c3bc2e2a7 +ad1fe56886 +3eede9782c +871e409c5c +7c078f211b +165ec9e22b +1122c1d16a +c304dd44d5 +8175486e6a +6589565c8c +6afb7d50e4 +f788a98327 +50b6b3d4b7 +56e71f3e07 +df5536cfb9 +0eb403a222 +fbe8488798 +f2f55d6713 +8f62a2c633 +f48b535719 +a2554c9f6d +7d0ffa68a4 +375a5c0e09 +5d663000ff +24ab0b83e8 +9101ea9b1b +a65bd23cb5 +ef8cfcfc4f +2f17e4fc1e +1f7d31b5b2 +03a06cc98a +784398620a +5937b08d69 +3decd63d88 +5cb0cb1b2f +a07b47f694 +0ac8c560ae +68cb45fda3 +6b17c67633 +e1561d6d4b +ad2de9f80e +8f16366707 +5cac477371 +0c26bc77ac +02f3a5c4df +1a25a9170a +38c9c3d801 +8e478e73f3 +e16945b951 +b9bcb3e0f2 +9fc2bad316 +2a63eb1524 +9bc454e109 +ea4a01216b +260846ffbe +8744b861ce +0248626d9a +cf4376a52d +ad3d1cfbcb +ea444a37eb +ed7455da68 +c2a9903b8b +97756b264f +d4b063c7db +eaec65cfa7 +3b7a50b80d +589e4cc1de +acff336758 +28d9fa6016 +3b512dad74 +a6c3a374e9 +b70a5a0d50 +97eb642e56 +96fb88e9d7 +9359174efc +310021b58b +2cbcd5ccd1 +60e51ff1ae +b8c03d1091 +8088bda461 +d3ae1c3f4c +dc34b35e30 +dbdc3c292b +fb81157a07 +20c6d8b362 +9e493e4773 +1dce57d05d +a99bdd0079 +91d095f869 +f46c2d0a6d +1af8d2395d +a2dc51ebe8 +a177c2733c +0348a45bca +e4eaa63aab +8ae168c71b +4baa1ed4aa +5678a91bd8 +b7fb871660 +784d201b12 +ef5e770988 +21df87ad76 +357a710863 +056c200404 +119dd54871 +f2fdb6abec +804f6338a4 +ab56201494 +75172d4ac8 +a49dcf9ad5 +0f51a78756 +70405185d2 +093c335ccc +c4f5b1ddcc +c96379c03c +a174e8d989 +bf443804e8 +26ddd2ef12 +7d1333fcbe +b2b2756fe7 +e29e9868a8 +2d900bdb8e +a3b8588550 +7e1922575c +ed8f814b2b +5a841e59ad +164410ce62 +1a9c131cb7 +1a6f3b5a4b +3cdf828f59 +152aaa3a9e +0f202e9852 +3cdf03531b +05e0b0f28f +e2fb1d6497 +2023b3ee4f +a16062456f +8d167e7c08 +37c19d1087 +2cb10c6a7e +e5abc0e96b +ff5a1ec4f3 +df741313c9 +3605019d3b +0f9683715b +65b7dda462 +6419386729 +2ea78f46e4 +b4b715a15b +1f9c7d10f1 +ece6bc9e92 +23d80299fe +562d173565 +77c834dc43 +aa6287bb6c +b6070de1bb +8179095000 +ce1af99b4b +ef308ad2e9 +44d239b24e +823e7a86e8 +07a11a35e8 +fdc6e3d581 +e2ea25542c +3424f58959 +726243a205 +c8d79e3163 +2e2bf37e6d +a07a15dd64 +8ba04b1e7b +482fb439c2 +d45158c175 +8aad0591eb +0321b18c10 +6eaff19b9f +b6a4859528 +4c25dfa8ec +152b7d3bd7 +e9582bdd1b +5ed838bd5c +e495f32c60 +13f6a8c20d +860745b042 +3ab9b1a85a +59323787d5 +f2cfd94d64 +d0b4442c71 +34dd2c70a7 +b379ab4ff5 +238d4b86f6 +e98eda8978 +c99e92aaf0 +67b0f4d562 +935d97dd2f +aa6d999971 +1892651815 +73e4e5cc74 +4ca2ffc361 +541d7935d7 +5bdf7c20d2 +23f404a9fc +610e38b751 +21f4019116 +454f227427 +b0a68228dc +51a597ee04 +56f09b9d92 +64dd6c83e3 +f6adb12c42 +a5b77abe43 +425a0c96e0 +1171141012 +999d53d841 +868d6a0685 +96a856ef9a +d2857f0faa +1d3685150a +c41e6587f5 +ec28252938 +c307f33da2 +36f5cc68fd +246b142c4d +51794ddd58 +e3d60e82d5 +c5b9128d94 +f46f7a0b63 +3f45a470ad +34efa703df +716df1aa59 +fe0f76d41b +18c6f205c5 +c9bf64e965 +ab199e8dfb +3d69fed2fb +165c42b41b +aeba9ac967 +462b22f263 +1c87955a3a +72552a07c9 +dc1745e0a2 +51b5dc30a0 +e6387bd1e0 +d2a58b4fa6 +e9422ad240 +cd603bb9d1 +f0268aa627 +6bf584200f +307444a47f +8b3805dbd4 +d7135cf104 +2bab50f9a7 +a78195a5f5 +89986c60be +5c74315dc2 +9223dacb40 +d01a8f1f83 +dd77583736 +125d1b19dd +44b1da0d87 +500c835a86 +394454fa9c +c0f5b222d7 +208833d1d1 +4f824d3dcd +2268e93b0a +260dd9ad33 +19b60d5335 +3ab807ded6 +8ec10891f9 +732626383b +b26d9904de +e8f7904326 +4a86fcfc30 +895cbf96f9 +8ca6a4f60f +0d40b015f4 +4efb9a0720 +6942f684ad +5158d6e985 +c39559ddf6 +b6bb00e366 +ee4bf100f1 +b7302d8226 +7ba3ce3485 +d2b026739a +41ff6d5e2a +707bf4ce41 +6efcfe9275 +a907b18df1 +895e8b29a7 diff --git a/ltr/data_specs/youtubevos_jjvalid.txt b/ltr/data_specs/youtubevos_jjvalid.txt new file mode 100755 index 0000000..41807ae --- /dev/null +++ b/ltr/data_specs/youtubevos_jjvalid.txt @@ -0,0 +1,300 @@ +d82a0aa15b +691a111e7c +97ab569ff3 +d4a607ad81 +f46c364dca +4743bb84a7 +1295e19071 +267964ee57 +df59cfd91d +c557b69fbf +927647fe08 +88f345941b +8ea6687ab0 +444aa274e7 +ae93214fe6 +b6e9ec577f +de30990a51 +acb73e4297 +6cccc985e0 +ebc4ec32e6 +f34a56525e +2b351bfd7d +a43299e362 +733798921e +feda5ad1c2 +103f501680 +da5d78b9d1 +634058dda0 +34d1b37101 +73c6ae7711 +a8f78125b9 +e1495354e4 +4fa9c30a45 +c3457af795 +fe3c02699d +878a299541 +a1193d6490 +d69967143e +d6917db4be +bda224cb25 +621584cffe +7a5f46198d +35195a56a1 +204a90d81f +e0de82caa7 +8c3015cccb +4e3f346aa5 +5e418b25f9 +4444753edd +c7bf937af5 +4da0d00b55 +48812cf33e +35c6235b8d +60c61cc2e5 +9002761b41 +13ae097e20 +ec193e1a01 +d3987b2930 +72f04f1a38 +97e59f09fa +d0ab39112e +9533fc037c +2b88561cf2 +6c4387daf5 +e1d26d35be +0cfe974a89 +0eefca067f +887a93b198 +4bc8c676bb +6f49f522ef +a9c9c1517e +8dcfb878a8 +1471274fa7 +53cad8e44a +46146dfd39 +666b660284 +51e85b347b +ec3d4fac00 +1c72b04b56 +2ba621c750 +d123d674c1 +bd0e9ed437 +dd61d903df +80c4a94706 +b4d0c90bf4 +52c8ec0373 +7bc7761b8c +25f97e926f +e72a7d7b0b +9f913803e9 +8bf84e7d45 +a9cbf9c41b +7abdff3086 +ae13ee3d70 +a68259572b +081ae4fa44 +8d064b29e2 +41dab05200 +6024888af8 +5110dc72c0 +b0dd580a89 +2ff7f5744f +45c36a9eab +ec4186ce12 +72cac683e4 +c2a35c1cda +11485838c2 +5675d78833 +55c1764e90 +bfd8f6e6c9 +7ecd1f0c69 +90c7a87887 +4f414dd6e7 +211bc5d102 +3299ae3116 +827cf4f886 +5665c024cb +08aa2705d5 +8e1848197c +d7bb6b37a7 +9d01f08ec6 +fad633fbe1 +11ce6f452e +644bad9729 +ae3bc4a0ef +b2ce7699e3 +f7e0c9bb83 +52c7a3d653 +7806308f33 +fed208bfca +9198cfb4ea +8c469815cf +731b825695 +c52bce43db +0d2fcc0dcd +1917b209f2 +b274456ce1 +d44e6acd1d +7e0cd25696 +8909bde9ab +68ea4a8c3d +69ea9c09d1 +5a4a785006 +b73867d769 +f0c34e1213 +84044f37f3 +479f5d7ef6 +3cc37fd487 +f8fcb6a78c +f0ad38da27 +d0c65e9e95 +3b6c7988f6 +f9ae3d98b7 +e4d4872dab +14dae0dc93 +86a40b655d +4eb6fc23a2 +15617297cc +4b67aa9ef6 +3e7d2aeb07 +4ea77bfd15 +2719b742ab +f04cf99ee6 +75285a7eb1 +74ef677020 +c9b3a8fbda +62d6ece152 +536096501f +3355e056eb +6a48e4aea8 +04259896e2 +189ac8208a +ba98512f97 +223bd973ab +a3f51855c3 +8b4fb018b7 +0ea68d418b +6d4bf200ad +c130c3fc0c +8a31f7bca5 +f8b4ac12f1 +f85796a921 +ef45ce3035 +e4f8e5f46e +d5b6c6d94a +c760eeb8b3 +0b9d012be8 +1f4ec0563d +2df005b843 +dc32a44804 +1cada35274 +4cfdd73249 +b8f34cf72e +53af427bb2 +1329409f2a +1b8680f8cd +2bbde474ef +2f5b0c89b1 +6693a52081 +684bcd8812 +e1f14510fa +72a810a799 +70c3e97e41 +7c4ec17eff +8a75ad7924 +fd77828200 +53d9c45013 +968c41829e +d39934abe3 +6e1a21ba55 +bc4f71372d +57246af7d1 +f49e4866ac +1e1a18c45a +a14ef483ff +d92532c7b2 +aab33f0e2a +f3325c3338 +4cf5bc3e60 +c98b6fe013 +619812a1a7 +f8c8de2764 +6dd2827fbb +f277c7a6a4 +1ca240fede +16e8599e94 +b554843889 +df0638b0a0 +d664c89912 +c5ab1f09c8 +d38d1679e2 +31bbd0d793 +b24fe36b2a +c1c830a735 +75504539c3 +a74b9ca19c +c6bb6d2d5c +99dc8bb20b +92c46be756 +7a626ec98d +0891ac2eb6 +7f54132e48 +c47d551843 +4122aba5f9 +5aeb95cc7d +8ca1af9f3c +4019231330 +8f320d0e09 +5851739c15 +b69926d9fa +b132a53086 +135625b53d +05d7715782 +e3e4134877 +d3069da8bb +747c44785c +59a6459751 +5a75f7a1cf +63936d7de5 +d301ca58cc +9c404cac0c +78613981ed +d072fda75b +390c51b987 +571ca79c71 +67cfbff9b1 +7a8b5456ca +efe5ac6901 +c4571bedc8 +57a344ab1a +d205e3cff5 +39befd99fb +3b23792b84 +6a5de0535f +ced7705ab2 +06ce2b51fb +dd415df125 +2f710f66bd +0f6c2163de +e470345ede +6b2261888d +6671643f31 +de74a601d3 +f14c18cf6a +f38e5aa5b4 +57427393e9 +6da21f5c91 +738e5a0a14 +0f2ab8b1ff +4a4b50571c +a263ce8a87 +031ccc99b1 +ab45078265 +01e64dd36a +e0c478f775 +b5b9da5364 +72acb8cdf6 +c922365dd4 +df11931ffe +ad3fada9d9 diff --git a/ltr/dataset/__init__.py b/ltr/dataset/__init__.py new file mode 100755 index 0000000..17d547c --- /dev/null +++ b/ltr/dataset/__init__.py @@ -0,0 +1,15 @@ +from .lasot import Lasot +from .got10k import Got10k +from .tracking_net import TrackingNet +from .imagenetvid import ImagenetVID +from .coco import MSCOCO +from .coco_seq import MSCOCOSeq +from .youtubevos import YouTubeVOS +from .davis import Davis +from .lvis import LVIS +from .ecssd import ECSSD +from .msra10k import MSRA10k +from .hku_is import HKUIS +from .sbd import SBD +from .synthetic_video import SyntheticVideo +from .synthetic_video_blend import SyntheticVideoBlend diff --git a/ltr/dataset/base_image_dataset.py b/ltr/dataset/base_image_dataset.py new file mode 100755 index 0000000..814dd52 --- /dev/null +++ b/ltr/dataset/base_image_dataset.py @@ -0,0 +1,92 @@ +import torch.utils.data +from ltr.data.image_loader import jpeg4py_loader + + +class BaseImageDataset(torch.utils.data.Dataset): + """ Base class for image datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.image_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_images() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_images(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.image_list) + + def has_class_info(self): + return False + + def get_class_name(self, image_id): + return None + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_images_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_image_info(self, seq_id): + """ Returns information about a particular image, + + args: + seq_id - index of the image + + returns: + Dict + """ + raise NotImplementedError + + def get_image(self, image_id, anno=None): + """ Get a image + + args: + image_id - index of image + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + image - + anno - + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/ltr/dataset/base_video_dataset.py b/ltr/dataset/base_video_dataset.py new file mode 100755 index 0000000..e440195 --- /dev/null +++ b/ltr/dataset/base_video_dataset.py @@ -0,0 +1,109 @@ +import torch.utils.data +from ltr.data.image_loader import jpeg4py_loader + + +class BaseVideoDataset(torch.utils.data.Dataset): + """ Base class for video datasets """ + + def __init__(self, name, root, image_loader=jpeg4py_loader): + """ + args: + root - The root path to the dataset + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + self.name = name + self.root = root + self.image_loader = image_loader + + self.sequence_list = [] # Contains the list of sequences. + self.class_list = [] + + def __len__(self): + """ Returns size of the dataset + returns: + int - number of samples in the dataset + """ + return self.get_num_sequences() + + def __getitem__(self, index): + """ Not to be used! Check get_frames() instead. + """ + return None + + def is_video_sequence(self): + """ Returns whether the dataset is a video dataset or an image dataset + + returns: + bool - True if a video dataset + """ + return True + + def is_synthetic_video_dataset(self): + """ Returns whether the dataset contains real videos or synthetic + + returns: + bool - True if a video dataset + """ + return False + + def get_name(self): + """ Name of the dataset + + returns: + string - Name of the dataset + """ + raise NotImplementedError + + def get_num_sequences(self): + """ Number of sequences in a dataset + + returns: + int - number of sequences in the dataset.""" + return len(self.sequence_list) + + def has_class_info(self): + return False + + def has_occlusion_info(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_class_list(self): + return self.class_list + + def get_sequences_in_class(self, class_name): + raise NotImplementedError + + def has_segmentation_info(self): + return False + + def get_sequence_info(self, seq_id): + """ Returns information about a particular sequences, + + args: + seq_id - index of the sequence + + returns: + Dict + """ + raise NotImplementedError + + def get_frames(self, seq_id, frame_ids, anno=None): + """ Get a set of frames from a particular sequence + + args: + seq_id - index of sequence + frame_ids - a list of frame numbers + anno(None) - The annotation for the sequence (see get_sequence_info). If None, they will be loaded. + + returns: + list - List of frames corresponding to frame_ids + list - List of dicts for each frame + dict - A dict containing meta information about the sequence, e.g. class of the target object. + + """ + raise NotImplementedError + diff --git a/ltr/dataset/coco.py b/ltr/dataset/coco.py new file mode 100755 index 0000000..e8b008d --- /dev/null +++ b/ltr/dataset/coco.py @@ -0,0 +1,156 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader +import torch +from pycocotools.coco import COCO +import random +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class MSCOCO(BaseImageDataset): + """ The COCO object detection dataset. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None, + split="train", version="2014"): + """ + args: + root - path to coco root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() # the parent class thing would happen in the sampler + + self.image_list = self._get_image_list(min_area=min_area) + + if data_fraction is not None: + self.image_list = random.sample(self.image_list, int(len(self.image_list) * data_fraction)) + self.im_per_class = self._build_im_per_class() + + def _get_image_list(self, min_area=None): + ann_list = list(self.coco_set.anns.keys()) + image_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + if min_area is not None: + image_list = [a for a in image_list if self.coco_set.anns[a]['area'] > min_area] + + return image_list + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def has_segmentation_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def _build_im_per_class(self): + im_per_class = {} + for i, im in enumerate(self.image_list): + class_name = self.cats[self.coco_set.anns[im]['category_id']]['name'] + if class_name not in im_per_class: + im_per_class[class_name] = [i] + else: + im_per_class[class_name].append(i) + + return im_per_class + + def get_images_in_class(self, class_name): + return self.im_per_class[class_name] + + def get_image_info(self, im_id): + anno = self._get_anno(im_id) + + bbox = torch.Tensor(anno['bbox']).view(4,) + + mask = torch.Tensor(self.coco_set.annToMask(anno)) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, im_id): + anno = self.coco_set.anns[self.image_list[im_id]] + + return anno + + def _get_image(self, im_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.image_list[im_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, im_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_class_name(self, im_id): + cat_dict_current = self.cats[self.coco_set.anns[self.image_list[im_id]]['category_id']] + return cat_dict_current['name'] + + def get_image(self, image_id, anno=None): + frame = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/ltr/dataset/coco_seq.py b/ltr/dataset/coco_seq.py new file mode 100755 index 0000000..90a1e5b --- /dev/null +++ b/ltr/dataset/coco_seq.py @@ -0,0 +1,168 @@ +import os +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +import torch +import random +from pycocotools.coco import COCO +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class MSCOCOSeq(BaseVideoDataset): + """ The COCO dataset. COCO is an image dataset. Thus, we treat each image as a sequence of length 1. + + Publication: + Microsoft COCO: Common Objects in Context. + Tsung-Yi Lin, Michael Maire, Serge J. Belongie, Lubomir D. Bourdev, Ross B. Girshick, James Hays, Pietro Perona, + Deva Ramanan, Piotr Dollar and C. Lawrence Zitnick + ECCV, 2014 + https://arxiv.org/pdf/1405.0312.pdf + + Download the images along with annotations from http://cocodataset.org/#download. The root folder should be + organized as follows. + - coco_root + - annotations + - instances_train2014.json + - instances_train2017.json + - images + - train2014 + - train2017 + + Note: You also have to install the coco pythonAPI from https://github.com/cocodataset/cocoapi. + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, split="train", version="2014"): + """ + args: + root - path to the coco dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + data_fraction (None) - Fraction of images to be used. The images are selected randomly. If None, all the + images will be used + split - 'train' or 'val'. + version - version of coco dataset (2014 or 2017) + """ + root = env_settings().coco_dir if root is None else root + super().__init__('COCO', root, image_loader) + + self.img_pth = os.path.join(root, 'images/{}{}/'.format(split, version)) + self.anno_path = os.path.join(root, 'annotations/instances_{}{}.json'.format(split, version)) + + # Load the COCO set. + self.coco_set = COCO(self.anno_path) + + self.cats = self.coco_set.cats + + self.class_list = self.get_class_list() + + self.sequence_list = self._get_sequence_list() + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + self.seq_per_class = self._build_seq_per_class() + + def _get_sequence_list(self): + ann_list = list(self.coco_set.anns.keys()) + seq_list = [a for a in ann_list if self.coco_set.anns[a]['iscrowd'] == 0] + + return seq_list + + def is_video_sequence(self): + return False + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'coco' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def _build_seq_per_class(self): + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = self.cats[self.coco_set.anns[seq]['category_id']]['name'] + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def get_sequence_info(self, seq_id): + anno = self._get_anno(seq_id) + + bbox = torch.Tensor(anno['bbox']).view(1, 4) + + mask = torch.Tensor(self.coco_set.annToMask(anno)).unsqueeze(dim=0) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, seq_id): + anno = self.coco_set.anns[self.sequence_list[seq_id]] + + return anno + + def _get_frames(self, seq_id): + path = self.coco_set.loadImgs([self.coco_set.anns[self.sequence_list[seq_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, seq_id): + try: + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': cat_dict_current['supercategory'], + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + + def get_class_name(self, seq_id): + cat_dict_current = self.cats[self.coco_set.anns[self.sequence_list[seq_id]]['category_id']] + return cat_dict_current['name'] + + def get_frames(self, seq_id=None, frame_ids=None, anno=None): + # COCO is an image dataset. Thus we replicate the image denoted by seq_id len(frame_ids) times, and return a + # list containing these replicated images. + frame = self._get_frames(seq_id) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0, ...] for _ in frame_ids] + + object_meta = self.get_meta_info(seq_id) + + return frame_list, anno_frames, object_meta diff --git a/ltr/dataset/davis.py b/ltr/dataset/davis.py new file mode 100755 index 0000000..66ac216 --- /dev/null +++ b/ltr/dataset/davis.py @@ -0,0 +1,83 @@ +from pathlib import Path +from ltr.dataset.vos_base import VOSDatasetBase, VOSMeta +from pytracking.evaluation import Sequence +from ltr.admin.environment import env_settings +from ltr.data.image_loader import jpeg4py_loader + + +class Davis(VOSDatasetBase): + """ The Davis VOS dataset + + Publication: + A Benchmark Dataset and Evaluation Methodology for Video Object Segmentation + F. Perazzi, J. Pont-Tuset, B. McWilliams, L. Van Gool, M. Gross, and A. Sorkine-Hornung + CVPR, 2016 + http://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Perazzi_A_Benchmark_Dataset_CVPR_2016_paper.pdf + + Download the dataset from https://davischallenge.org/davis2017/code.html + """ + def __init__(self, root=None, sequences=None, version='2017', split='train', multiobj=True, + vis_threshold=10, image_loader=jpeg4py_loader): + """ + args: + root - Dataset root path. If unset, it uses the path in your local.py config. + sequences - List of sequence names. Limit to a subset of sequences if not None. + version - '2016' or '2017 + split - Any name in DAVIS/ImageSets/ + multiobj - Whether the dataset will return all objects in a sequence or multiple sequences with one object + in each. + vis_threshold - Minimum number of pixels required to consider a target object "visible". + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + """ + if version == '2017': + if split in ['train', 'val']: + root = env_settings().davis_dir if root is None else root + elif split in ['test-dev']: + root = env_settings().davis_testdev_dir if root is None else root + else: + raise Exception('Unknown split {}'.format(split)) + else: + root = env_settings().davis16_dir if root is None else root + + super().__init__(name='DAVIS', root=Path(root), version=version, split=split, multiobj=multiobj, + vis_threshold=vis_threshold, image_loader=image_loader) + + dset_path = self.root + self._jpeg_path = dset_path / 'JPEGImages' / '480p' + self._anno_path = dset_path / 'Annotations' / '480p' + + meta_path = dset_path / "generated_meta.json" + if meta_path.exists(): + self.gmeta = VOSMeta(filename=meta_path) + else: + self.gmeta = VOSMeta.generate('DAVIS', self._jpeg_path, self._anno_path) + self.gmeta.save(meta_path) + + if sequences is None: + if self.split != 'all': + fname = dset_path / 'ImageSets' / self.version / (self.split + '.txt') + sequences = open(fname).read().splitlines() + else: + sequences = [p for p in sorted(self._jpeg_path.glob("*")) if p.is_dir()] + + self.sequence_names = sequences + self._samples = [] + + for seq in sequences: + obj_ids = self.gmeta.get_obj_ids(seq) + if self.multiobj: # Multiple objects per sample + self._samples.append((seq, obj_ids)) + else: # One object per sample + self._samples.extend([(seq, [obj_id]) for obj_id in obj_ids]) + + print("%s loaded." % self.get_name()) + + def _construct_sequence(self, sequence_info): + + seq_name = sequence_info['sequence'] + images, gt_labels, gt_bboxes = self.get_paths_and_bboxes(sequence_info) + + return Sequence(name=seq_name, frames=images, dataset='DAVIS', ground_truth_rect=gt_bboxes, + ground_truth_seg=gt_labels, object_ids=sequence_info['object_ids'], + multiobj_mode=self.multiobj) diff --git a/ltr/dataset/ecssd.py b/ltr/dataset/ecssd.py new file mode 100755 index 0000000..8ac054f --- /dev/null +++ b/ltr/dataset/ecssd.py @@ -0,0 +1,84 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, opencv_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class ECSSD(BaseImageDataset): + """ + Extended Complex Scene Saliency Dataset (ECSSD) + + Publication: + Hierarchical Image Saliency Detection on Extended CSSD + Jianping Shi, Qiong Yan, Li Xu, Jiaya Jia + TPAMI, 2016 + https://arxiv.org/pdf/1408.5418.pdf + + Download the dataset from http://www.cse.cuhk.edu.hk/leojia/projects/hsaliency/dataset.html + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to ECSSD root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().ecssd_dir if root is None else root + super().__init__('ECSSD', root, image_loader) + + self.image_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + images = [] + + for i in range(1, 1001): + a = imread_indexed(os.path.join(self.root, 'ground_truth_mask', '{:04d}.png'.format(i))) + + if min_area is None or (a > 0).sum() > min_area: + images.append(i) + + return images + + def get_name(self): + return 'ecssd' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = imread_indexed(os.path.join(self.root, 'ground_truth_mask', '{:04d}.png'.format(self.image_list[im_id]))) + + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_loader(os.path.join(self.root, 'images', '{:04d}.jpg'.format(self.image_list[image_id]))) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/ltr/dataset/got10k.py b/ltr/dataset/got10k.py new file mode 100755 index 0000000..72013de --- /dev/null +++ b/ltr/dataset/got10k.py @@ -0,0 +1,183 @@ +import os +import os.path +import numpy as np +import torch +import csv +import pandas +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +from ltr.admin.environment import env_settings + + +class Got10k(BaseVideoDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, split=None, seq_ids=None, data_fraction=None): + """ + args: + root - path to the got-10k training data. Note: This should point to the 'train' folder inside GOT-10k + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + split - 'train' or 'val'. Note: The validation split here is a subset of the official got-10k train split, + not NOT the official got-10k validation split. To use the official validation split, provide that as + the root folder instead. + seq_ids - List containing the ids of the videos to be used for training. Note: Only one of 'split' or 'seq_ids' + options can be used at the same time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().got10k_dir if root is None else root + super().__init__('GOT10k', root, image_loader) + + # all folders inside the root + self.sequence_list = self._get_sequence_list() + + # seq_id is the index of the folder inside the got10k root path + if split is not None: + if seq_ids is not None: + raise ValueError('Cannot set both split_name and seq_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_train_split.txt') + elif split == 'val': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_val_split.txt') + elif split == 'vottrain': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_train_split.txt') + elif split == 'votval': + file_path = os.path.join(ltr_path, 'data_specs', 'got10k_vot_val_split.txt') + else: + raise ValueError('Unknown split name.') + seq_ids = pandas.read_csv(file_path, header=None, squeeze=True, dtype=np.int64).values.tolist() + elif seq_ids is None: + seq_ids = list(range(0, len(self.sequence_list))) + + self.sequence_list = [self.sequence_list[i] for i in seq_ids] + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.sequence_meta_info = self._load_meta_info() + self.seq_per_class = self._build_seq_per_class() + + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def get_name(self): + return 'got10k' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def _load_meta_info(self): + sequence_meta_info = {s: self._read_meta(os.path.join(self.root, s)) for s in self.sequence_list} + return sequence_meta_info + + def _read_meta(self, seq_path): + try: + with open(os.path.join(seq_path, 'meta_info.ini')) as f: + meta_info = f.readlines() + object_meta = OrderedDict({'object_class_name': meta_info[5].split(': ')[-1][:-1], + 'motion_class': meta_info[6].split(': ')[-1][:-1], + 'major_class': meta_info[7].split(': ')[-1][:-1], + 'root_class': meta_info[8].split(': ')[-1][:-1], + 'motion_adverb': meta_info[9].split(': ')[-1][:-1]}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def _build_seq_per_class(self): + seq_per_class = {} + + for i, s in enumerate(self.sequence_list): + object_class = self.sequence_meta_info[s]['object_class_name'] + if object_class in seq_per_class: + seq_per_class[object_class].append(i) + else: + seq_per_class[object_class] = [i] + + return seq_per_class + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _get_sequence_list(self): + with open(os.path.join(self.root, 'list.txt')) as f: + dir_list = list(csv.reader(f)) + dir_list = [dir_name[0] for dir_name in dir_list] + return dir_list + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "absence.label") + cover_file = os.path.join(seq_path, "cover.label") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + with open(cover_file, 'r', newline='') as f: + cover = torch.ByteTensor([int(v[0]) for v in csv.reader(f)]) + + target_visible = ~occlusion & (cover>0).byte() + + visible_ratio = cover.float() / 8 + return target_visible, visible_ratio + + def _get_sequence_path(self, seq_id): + return os.path.join(self.root, self.sequence_list[seq_id]) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible, visible_ratio = self._read_target_visible(seq_path) + visible = visible & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible, 'visible_ratio': visible_ratio} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def get_class_name(self, seq_id): + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + return obj_meta['object_class_name'] + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + obj_meta = self.sequence_meta_info[self.sequence_list[seq_id]] + + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return frame_list, anno_frames, obj_meta diff --git a/ltr/dataset/hku_is.py b/ltr/dataset/hku_is.py new file mode 100755 index 0000000..75c7871 --- /dev/null +++ b/ltr/dataset/hku_is.py @@ -0,0 +1,90 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, opencv_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class HKUIS(BaseImageDataset): + """ + HKU-IS salient object detection dataset + + Publication: + Visual saliency based on multiscale deep features + Guanbin Li and Yizhou Yu + CVPR, 2015 + https://arxiv.org/pdf/1503.08663.pdf + + Dowload dataset from https://sites.google.com/site/ligb86/hkuis + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to HKU-IS root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().hkuis_dir if root is None else root + super().__init__('HKUIS', root, image_loader) + + self.image_list, self.anno_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + files_list = os.listdir(os.path.join(self.root, 'imgs')) + image_list = [f[:-4] for f in files_list] + + images = [] + annos = [] + + for f in image_list: + a = imread_indexed(os.path.join(self.root, 'gt', '{}.png'.format(f))) + + if min_area is None or (a > 0).sum() > min_area: + im = opencv_loader(os.path.join(self.root, 'imgs', '{}.png'.format(f))) + images.append(im) + annos.append(a) + + return images, annos + + def get_name(self): + return 'hku-is' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = self.anno_list[im_id] + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_list[image_id] + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/ltr/dataset/imagenetvid.py b/ltr/dataset/imagenetvid.py new file mode 100755 index 0000000..74d0b23 --- /dev/null +++ b/ltr/dataset/imagenetvid.py @@ -0,0 +1,161 @@ +import os +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import default_image_loader +import xml.etree.ElementTree as ET +import json +import torch +import random +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +def get_target_to_image_ratio(seq): + anno = torch.Tensor(seq['anno']) + img_sz = torch.Tensor(seq['image_size']) + return (anno[0, 2:4].prod() / (img_sz.prod())).sqrt() + + +class ImagenetVID(BaseVideoDataset): + """ Imagenet VID dataset. + + Publication: + ImageNet Large Scale Visual Recognition Challenge + Olga Russakovsky, Jia Deng, Hao Su, Jonathan Krause, Sanjeev Satheesh, Sean Ma, Zhiheng Huang, Andrej Karpathy, + Aditya Khosla, Michael Bernstein, Alexander C. Berg and Li Fei-Fei + IJCV, 2015 + https://arxiv.org/pdf/1409.0575.pdf + + Download the dataset from http://image-net.org/ + """ + def __init__(self, root=None, image_loader=default_image_loader, min_length=0, max_target_area=1): + """ + args: + root - path to the imagenet vid dataset. + image_loader (default_image_loader) - The function to read the images. If installed, + jpeg4py (https://github.com/ajkxyz/jpeg4py) is used by default. Else, + opencv's imread is used. + min_length - Minimum allowed sequence length. + max_target_area - max allowed ratio between target area and image area. Can be used to filter out targets + which cover complete image. + """ + root = env_settings().imagenet_dir if root is None else root + super().__init__(root, image_loader) + + cache_file = os.path.join(root, 'cache.json') + if os.path.isfile(cache_file): + # If available, load the pre-processed cache file containing meta-info for each sequence + with open(cache_file, 'r') as f: + sequence_list_dict = json.load(f) + + self.sequence_list = sequence_list_dict + else: + # Else process the imagenet annotations and generate the cache file + self.sequence_list = self._process_anno(root) + + with open(cache_file, 'w') as f: + json.dump(self.sequence_list, f) + + # Filter the sequences based on min_length and max_target_area in the first frame + self.sequence_list = [x for x in self.sequence_list if len(x['anno']) >= min_length and + get_target_to_image_ratio(x) < max_target_area] + + def get_name(self): + return 'imagenetvid' + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_sequence_info(self, seq_id): + bb_anno = torch.Tensor(self.sequence_list[seq_id]['anno']) + valid = (bb_anno[:, 2] > 0) & (bb_anno[:, 3] > 0) + visible = torch.ByteTensor(self.sequence_list[seq_id]['target_visible']) & valid.byte() + return {'bbox': bb_anno, 'valid': valid, 'visible': visible} + + def _get_frame(self, sequence, frame_id): + set_name = 'ILSVRC2015_VID_train_{:04d}'.format(sequence['set_id']) + vid_name = 'ILSVRC2015_train_{:08d}'.format(sequence['vid_id']) + frame_number = frame_id + sequence['start_frame'] + + frame_path = os.path.join(self.root, 'Data', 'VID', 'train', set_name, vid_name, + '{:06d}.JPEG'.format(frame_number)) + return self.image_loader(frame_path) + + def get_frames(self, seq_id, frame_ids, anno=None): + sequence = self.sequence_list[seq_id] + + frame_list = [self._get_frame(sequence, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + # Create anno dict + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + # added the class info to the meta info + object_meta = OrderedDict({'object_class': sequence['class_name'], + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta + + def _process_anno(self, root): + # Builds individual tracklets + base_vid_anno_path = os.path.join(root, 'Annotations', 'VID', 'train') + + all_sequences = [] + for set in sorted(os.listdir(base_vid_anno_path)): + set_id = int(set.split('_')[-1]) + for vid in sorted(os.listdir(os.path.join(base_vid_anno_path, set))): + + vid_id = int(vid.split('_')[-1]) + anno_files = sorted(os.listdir(os.path.join(base_vid_anno_path, set, vid))) + + frame1_anno = ET.parse(os.path.join(base_vid_anno_path, set, vid, anno_files[0])) + image_size = [int(frame1_anno.find('size/width').text), int(frame1_anno.find('size/height').text)] + + objects = [ET.ElementTree(file=os.path.join(base_vid_anno_path, set, vid, f)).findall('object') + for f in anno_files] + + tracklets = {} + + # Find all tracklets along with start frame + for f_id, all_targets in enumerate(objects): + for target in all_targets: + tracklet_id = target.find('trackid').text + if tracklet_id not in tracklets: + tracklets[tracklet_id] = f_id + + for tracklet_id, tracklet_start in tracklets.items(): + tracklet_anno = [] + target_visible = [] + class_name_id = None + + for f_id in range(tracklet_start, len(objects)): + found = False + for target in objects[f_id]: + if target.find('trackid').text == tracklet_id: + if not class_name_id: + class_name_id = target.find('name').text + x1 = int(target.find('bndbox/xmin').text) + y1 = int(target.find('bndbox/ymin').text) + x2 = int(target.find('bndbox/xmax').text) + y2 = int(target.find('bndbox/ymax').text) + + tracklet_anno.append([x1, y1, x2 - x1, y2 - y1]) + target_visible.append(target.find('occluded').text == '0') + + found = True + break + if not found: + break + + new_sequence = {'set_id': set_id, 'vid_id': vid_id, 'class_name': class_name_id, + 'start_frame': tracklet_start, 'anno': tracklet_anno, + 'target_visible': target_visible, 'image_size': image_size} + all_sequences.append(new_sequence) + + return all_sequences diff --git a/ltr/dataset/lasot.py b/ltr/dataset/lasot.py new file mode 100755 index 0000000..7918220 --- /dev/null +++ b/ltr/dataset/lasot.py @@ -0,0 +1,168 @@ +import os +import os.path +import torch +import numpy as np +import pandas +import csv +import random +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader +from ltr.admin.environment import env_settings + + +class Lasot(BaseVideoDataset): + """ LaSOT dataset. + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, vid_ids=None, split=None, data_fraction=None): + """ + args: + root - path to the lasot dataset. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + vid_ids - List containing the ids of the videos (1 - 20) used for training. If vid_ids = [1, 3, 5], then the + videos with subscripts -1, -3, and -5 from each class will be used for training. + split - If split='train', the official train split (protocol-II) is used for training. Note: Only one of + vid_ids or split option can be used at a time. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().lasot_dir if root is None else root + super().__init__('LaSOT', root, image_loader) + + # Keep a list of all classes + self.class_list = [f for f in os.listdir(self.root)] + self.class_to_id = {cls_name: cls_id for cls_id, cls_name in enumerate(self.class_list)} + + self.sequence_list = self._build_sequence_list(vid_ids, split) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list)*data_fraction)) + + self.seq_per_class = self._build_class_list() + + def _build_sequence_list(self, vid_ids=None, split=None): + if split is not None: + if vid_ids is not None: + raise ValueError('Cannot set both split_name and vid_ids.') + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + if split == 'train': + file_path = os.path.join(ltr_path, 'data_specs', 'lasot_train_split.txt') + else: + raise ValueError('Unknown split name.') + sequence_list = pandas.read_csv(file_path, header=None, squeeze=True).values.tolist() + elif vid_ids is not None: + sequence_list = [c+'-'+str(v) for c in self.class_list for v in vid_ids] + else: + raise ValueError('Set either split_name or vid_ids.') + + return sequence_list + + def _build_class_list(self): + seq_per_class = {} + for seq_id, seq_name in enumerate(self.sequence_list): + class_name = seq_name.split('-')[0] + if class_name in seq_per_class: + seq_per_class[class_name].append(seq_id) + else: + seq_per_class[class_name] = [seq_id] + + return seq_per_class + + def get_name(self): + return 'lasot' + + def has_class_info(self): + return True + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return len(self.sequence_list) + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_path): + bb_anno_file = os.path.join(seq_path, "groundtruth.txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, low_memory=False).values + return torch.tensor(gt) + + def _read_target_visible(self, seq_path): + # Read full occlusion and out_of_view + occlusion_file = os.path.join(seq_path, "full_occlusion.txt") + out_of_view_file = os.path.join(seq_path, "out_of_view.txt") + + with open(occlusion_file, 'r', newline='') as f: + occlusion = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + with open(out_of_view_file, 'r') as f: + out_of_view = torch.ByteTensor([int(v) for v in list(csv.reader(f))[0]]) + + target_visible = ~occlusion & ~out_of_view + + return target_visible + + def _get_sequence_path(self, seq_id): + seq_name = self.sequence_list[seq_id] + class_name = seq_name.split('-')[0] + vid_id = seq_name.split('-')[1] + + return os.path.join(self.root, class_name, class_name + '-' + vid_id) + + def get_sequence_info(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + bbox = self._read_bb_anno(seq_path) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = self._read_target_visible(seq_path) & valid.byte() + + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame_path(self, seq_path, frame_id): + return os.path.join(seq_path, 'img', '{:08}.jpg'.format(frame_id+1)) # frames start from 1 + + def _get_frame(self, seq_path, frame_id): + return self.image_loader(self._get_frame_path(seq_path, frame_id)) + + def _get_class(self, seq_path): + raw_class = seq_path.split('/')[-2] + return raw_class + + def get_class_name(self, seq_id): + seq_path = self._get_sequence_path(seq_id) + obj_class = self._get_class(seq_path) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + seq_path = self._get_sequence_path(seq_id) + + obj_class = self._get_class(seq_path) + frame_list = [self._get_frame(seq_path, f_id) for f_id in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/ltr/dataset/lvis.py b/ltr/dataset/lvis.py new file mode 100755 index 0000000..276c02f --- /dev/null +++ b/ltr/dataset/lvis.py @@ -0,0 +1,152 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader_w_failsafe +import torch +import random +import lvis.lvis as lvis_pk +from collections import OrderedDict +from ltr.admin.environment import env_settings + + +class LVIS(BaseImageDataset): + """ The LVIS object detection dataset + + Publication: + LVIS: A Dataset for Large Vocabulary Instance Segmentation + Agrim Gupta, Piotr Dollár, and Ross Girshick + CVPR, 2019 + https://arxiv.org/pdf/1908.03195.pdf + + Download the images along with annotations from https://www.lvisdataset.org/dataset. The root folder should be + organized as follows. + - lvis_root + - annotations + - lvis_v0.5_train.json + - lvis_v0.5_val.json + - images + - val2017 + - train2017 + + Note: You also have to install the lvis Python API from https://github.com/lvis-dataset/lvis-api + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader_w_failsafe, data_fraction=None, min_area=None, split="train"): + """ + args: + root - path to lvis root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + split - 'train' or 'val'. + """ + root = env_settings().lvis_dir if root is None else root + super().__init__('LVIS', root, image_loader) + + self.img_pth = os.path.join(root, 'images', f'{split}2017/') + self.anno_path = os.path.join(root, 'annotations', f'lvis_v0.5_{split}.json') + + # Load the LVIS set. + self.lvis_set = lvis_pk.LVIS(self.anno_path) + + self.cats = self.lvis_set.cats + + self.class_list = self.get_class_list() # the parent class thing would happen in the sampler + + self.image_list = self._get_image_list(min_area=min_area) + + if data_fraction is not None: + self.image_list = random.sample(self.image_list, int(len(self.image_list) * data_fraction)) + self.im_per_class = self._build_im_per_class() + + def _get_image_list(self, min_area=None): + im_list = list(self.lvis_set.anns.keys()) # No 'iscrowd' information in LVIS + + if min_area is not None: + im_list = [s for s in im_list if self.lvis_set.anns[s]['area'] > min_area] + + return im_list + + def get_num_classes(self): + return len(self.class_list) + + def get_name(self): + return 'lvis' + + def has_class_info(self): + return True + + def get_class_list(self): + class_list = [] + for cat_id in self.cats.keys(): + class_list.append(self.cats[cat_id]['name']) + return class_list + + def has_segmentation_info(self): + return True + + def _build_im_per_class(self): + im_per_class = {} + for i, im in enumerate(self.image_list): + class_name = self.cats[self.lvis_set.anns[im]['category_id']]['name'] + if class_name not in im_per_class: + im_per_class[class_name] = [i] + else: + im_per_class[class_name].append(i) + + return im_per_class + + def get_images_in_class(self, class_name): + return self.im_per_class[class_name] + + def get_image_info(self, im_id): + anno = self._get_anno(im_id) + + bbox = torch.Tensor(anno['bbox']).view(4,) + + mask = torch.Tensor(self.lvis_set.ann_to_mask(anno)) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_anno(self, im_id): + anno = self.lvis_set.anns[self.image_list[im_id]] + + return anno + + def _get_image(self, im_id): + path = self.lvis_set.load_imgs([self.lvis_set.anns[self.image_list[im_id]]['image_id']])[0]['file_name'] + img = self.image_loader(os.path.join(self.img_pth, path)) + return img + + def get_meta_info(self, im_id): + try: + cat_dict_current = self.cats[self.lvis_set.anns[self.image_list[im_id]]['category_id']] + object_meta = OrderedDict({'object_class_name': cat_dict_current['name'], + 'motion_class': None, + 'major_class': None, # No 'supercategory' information available in LVIS + 'root_class': None, + 'motion_adverb': None}) + except: + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_class_name(self, im_id): + cat_dict_current = self.cats[self.lvis_set.anns[self.image_list[im_id]]['category_id']] + return cat_dict_current['name'] + + def get_image(self, image_id, anno=None): + frame = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/ltr/dataset/msra10k.py b/ltr/dataset/msra10k.py new file mode 100755 index 0000000..d1ab972 --- /dev/null +++ b/ltr/dataset/msra10k.py @@ -0,0 +1,87 @@ +import os +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader, imread_indexed +import torch +from collections import OrderedDict +from ltr.admin.environment import env_settings +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class MSRA10k(BaseImageDataset): + """ + MSRA10k salient object detection dataset + + Publication: + Global contrast based salient region detection + Ming-Ming Cheng, Niloy J. Mitra, Xiaolei Huang, Philip H. S. Torr, and Shi-Min Hu + TPAMI, 2015 + https://mmcheng.net/mftp/Papers/SaliencyTPAMI.pdf + + Download dataset from https://mmcheng.net/msra10k/ + """ + + def __init__(self, root=None, image_loader=jpeg4py_loader, data_fraction=None, min_area=None): + """ + args: + root - path to MSRA10k root folder + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + min_area - Objects with area less than min_area are filtered out. Default is 0.0 + """ + root = env_settings().msra10k_dir if root is None else root + super().__init__('MSRA10k', root, image_loader) + + self.image_list = self._load_dataset(min_area=min_area) + + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, min_area=None): + files_list = os.listdir(os.path.join(self.root, 'Imgs')) + image_list = [f[:-4] for f in files_list if f[-3:] == 'jpg'] + + images = [] + + for f in image_list: + a = imread_indexed(os.path.join(self.root, 'Imgs', '{}.png'.format(f))) + + if min_area is None or (a > 0).sum() > min_area: + images.append(f) + + return images + + def get_name(self): + return 'msra10k' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + mask = imread_indexed(os.path.join(self.root, 'Imgs', '{}.png'.format(self.image_list[im_id]))) + mask = torch.Tensor(mask == 255) + bbox = masks_to_bboxes(mask, fmt='t').view(4,) + + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return object_meta + + def get_image(self, image_id, anno=None): + frame = self.image_loader(os.path.join(self.root, 'Imgs', '{}.jpg'.format(self.image_list[image_id]))) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return frame, anno, object_meta diff --git a/ltr/dataset/sbd.py b/ltr/dataset/sbd.py new file mode 100755 index 0000000..6e98090 --- /dev/null +++ b/ltr/dataset/sbd.py @@ -0,0 +1,115 @@ +from .base_image_dataset import BaseImageDataset +from ltr.data.image_loader import jpeg4py_loader_w_failsafe +import torch +from collections import OrderedDict +import os +from scipy.io import loadmat +from ltr.data.bounding_box_utils import masks_to_bboxes + +from ltr.admin.environment import env_settings + + +class SBD(BaseImageDataset): + """ + Semantic Boundaries Dataset and Benchmark (SBD) + + Publication: + Semantic contours from inverse detectors + Bharath Hariharan, Pablo Arbelaez, Lubomir Bourdev, Subhransu Maji and Jitendra Malik + ICCV, 2011 + http://home.bharathh.info/pubs/pdfs/BharathICCV2011.pdf + + Download dataset from: http://home.bharathh.info/pubs/codes/SBD/download.html + """ + def __init__(self, root=None, image_loader=jpeg4py_loader_w_failsafe, data_fraction=None, split="train"): + """ + args: + root - path to SBD root folder + image_loader - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + split - dataset split ("train", "train_noval", "val") + """ + root = env_settings().sbd_dir if root is None else root + super().__init__('SBD', root, image_loader) + + assert split in ["train", "train_noval", "val"] + + self.root = root + + self.image_path_list, self.anno_file_list = self._load_dataset(split) + + # Load mat fine + anno_list = [loadmat(a) for a in self.anno_file_list] + + self.image_list = self._construct_image_list(anno_list) + if data_fraction is not None: + raise NotImplementedError + + def _load_dataset(self, split): + split_f = os.path.join(self.root, split.rstrip('\n') + '.txt') + + with open(os.path.join(split_f), "r") as f: + file_names = [x.strip() for x in f.readlines()] + + image_list = [os.path.join(self.root, 'img', x + ".jpg") for x in file_names] + anno_list = [os.path.join(self.root, 'inst', x + ".mat") for x in file_names] + + assert (len(image_list) == len(anno_list)) + + return image_list, anno_list + + def _get_mask_from_mat(self, mat): + return torch.tensor(mat['GTinst'][0]['Segmentation'][0]) + + def _construct_image_list(self, anno_list): + image_list = [] + + for im_id, a in enumerate(anno_list): + mask = self._get_mask_from_mat(a) + for instance_id in range(1, mask.max().item() + 1): + image_list.append((im_id, instance_id)) + + return image_list + + def get_name(self): + return 'sbd' + + def has_segmentation_info(self): + return True + + def get_image_info(self, im_id): + image_id, instance_id = self.image_list[im_id] + anno_mat = loadmat(self.anno_file_list[image_id]) + mask = self._get_mask_from_mat(anno_mat) + + mask = (mask == instance_id).float() + bbox = masks_to_bboxes(mask, fmt='t') + valid = (bbox[2] > 0) & (bbox[3] > 0) + visible = valid.clone().byte() + + return {'bbox': bbox, 'mask': mask, 'valid': valid, 'visible': visible} + + def _get_image(self, im_id): + image_id, _ = self.image_list[im_id] + + img = self.image_loader(self.image_path_list[image_id]) + return img + + def get_meta_info(self, im_id): + object_meta = OrderedDict({'object_class_name': None, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + return object_meta + + def get_image(self, image_id, anno=None): + image = self._get_image(image_id) + + if anno is None: + anno = self.get_image_info(image_id) + + object_meta = self.get_meta_info(image_id) + + return image, anno, object_meta diff --git a/ltr/dataset/synthetic_video.py b/ltr/dataset/synthetic_video.py new file mode 100755 index 0000000..8dbfa04 --- /dev/null +++ b/ltr/dataset/synthetic_video.py @@ -0,0 +1,82 @@ +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class SyntheticVideo(BaseVideoDataset): + """ + Create a synthetic video dataset from an image dataset by applying a random transformation to images. + """ + def __init__(self, base_image_dataset, transform=None): + """ + args: + base_image_dataset - Image dataset used for generating synthetic videos + transform - Set of transforms to be applied to the images to generate synthetic video. + """ + super().__init__(base_image_dataset.get_name() + '_syn_vid', base_image_dataset.root, + base_image_dataset.image_loader) + self.base_image_dataset = base_image_dataset + self.transform = transform + + def get_name(self): + return self.name + + def is_video_sequence(self): + return False + + def has_class_info(self): + return self.base_image_dataset.has_class_info() + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return self.base_image_dataset.get_num_images() + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.get_images_in_class[class_name] + + def get_sequence_info(self, seq_id): + image_info = self.base_image_dataset.get_image_info(seq_id) + + image_info = {k: v.unsqueeze(0) for k, v in image_info.items()} + return image_info + + def get_class_name(self, seq_id): + return self.base_image_dataset.get_class_name(seq_id) + + def get_frames(self, seq_id, frame_ids, anno=None): + frame, anno, object_meta = self.base_image_dataset.get_image(seq_id, anno=anno) + + frame_list = [frame.copy() for _ in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[0].clone() for f_id in frame_ids] + + if self.transform is not None: + if 'mask' in anno_frames.keys(): + frame_list, anno_frames['bbox'], anno_frames['mask'] = self.transform(image=frame_list, + bbox=anno_frames['bbox'], + mask=anno_frames['mask'], + joint=False) + + anno_frames['bbox'] = [masks_to_bboxes(m, fmt='t') for m in anno_frames['mask']] + else: + frame_list, anno_frames['bbox'] = self.transform(image=frame_list, + bbox=anno_frames['bbox'], + joint=False) + + object_meta = OrderedDict({'object_class_name': self.get_class_name(seq_id), + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/ltr/dataset/synthetic_video_blend.py b/ltr/dataset/synthetic_video_blend.py new file mode 100755 index 0000000..96404a2 --- /dev/null +++ b/ltr/dataset/synthetic_video_blend.py @@ -0,0 +1,162 @@ +from collections import OrderedDict +from .base_video_dataset import BaseVideoDataset +from ltr.data.bounding_box_utils import masks_to_bboxes +import random +import torch + + +class SyntheticVideoBlend(BaseVideoDataset): + """ + Create a synthetic video by applying random transformations to an object (foreground) and pasting it in a + background image. Currently, the foreground object is pasted at random locations in different frames. + """ + def __init__(self, foreground_image_dataset, background_image_dataset, foreground_transform=None, + background_transform=None): + """ + args: + foreground_image_dataset - A segmentation dataset from which foreground objects are cropped using the + segmentation mask + background_image_dataset - Dataset used to sample background image for the synthetic video + foreground_transform - Random transformations to be applied to the foreground object in every frame + background_transform - Random transformations to be applied to the background image in every frame + """ + assert foreground_image_dataset.has_segmentation_info() + + super().__init__(foreground_image_dataset.get_name() + '_syn_vid_blend', foreground_image_dataset.root, + foreground_image_dataset.image_loader) + self.foreground_image_dataset = foreground_image_dataset + self.background_image_dataset = background_image_dataset + + self.foreground_transform = foreground_transform + self.background_transform = background_transform + + def get_name(self): + return self.name + + def is_video_sequence(self): + return False + + def has_class_info(self): + return self.foreground_image_dataset.has_class_info() + + def has_occlusion_info(self): + return True + + def get_num_sequences(self): + return self.foreground_image_dataset.get_num_images() + + def get_num_classes(self): + return len(self.class_list) + + def get_sequences_in_class(self, class_name): + return self.get_images_in_class[class_name] + + def get_sequence_info(self, seq_id): + image_info = self.foreground_image_dataset.get_image_info(seq_id) + + image_info = {k: v.unsqueeze(0) for k, v in image_info.items()} + return image_info + + def get_class_name(self, seq_id): + return self.foreground_image_dataset.get_class_name(seq_id) + + def _paste_target(self, fg_image, fg_box, fg_mask, bg_image, paste_loc): + fg_mask = fg_mask.view(fg_mask.shape[0], fg_mask.shape[1], 1) + fg_box = fg_box.long().tolist() + + x1 = int(paste_loc[0] - 0.5 * fg_box[2]) + x2 = x1 + fg_box[2] + + y1 = int(paste_loc[1] - 0.5 * fg_box[3]) + y2 = y1 + fg_box[3] + + x1_pad = max(-x1, 0) + y1_pad = max(-y1, 0) + + x2_pad = max(x2 - bg_image.shape[1], 0) + y2_pad = max(y2 - bg_image.shape[0], 0) + + bg_mask = torch.zeros((bg_image.shape[0], bg_image.shape[1], 1), dtype=fg_mask.dtype, + device=fg_mask.device) + + if x1_pad >= fg_mask.shape[1] or x2_pad >= fg_mask.shape[1] or y1_pad >= fg_mask.shape[0] or y2_pad >= \ + fg_mask.shape[0]: + return bg_image, bg_mask.squeeze(-1) + + fg_mask_patch = fg_mask[fg_box[1] + y1_pad:fg_box[1] + fg_box[3] - y2_pad, + fg_box[0] + x1_pad:fg_box[0] + fg_box[2] - x2_pad, :] + + fg_image_patch = fg_image[fg_box[1] + y1_pad:fg_box[1] + fg_box[3] - y2_pad, + fg_box[0] + x1_pad:fg_box[0] + fg_box[2] - x2_pad, :] + + bg_image[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] = \ + bg_image[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] * (1 - fg_mask_patch.numpy()) \ + + fg_mask_patch.numpy() * fg_image_patch + + bg_mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :] = fg_mask_patch + + return bg_image, bg_mask.squeeze(-1) + + def get_frames(self, seq_id, frame_ids, anno=None): + # Handle foreground + fg_frame, fg_anno, fg_object_meta = self.foreground_image_dataset.get_image(seq_id, anno=anno) + + fg_frame_list = [fg_frame.copy() for _ in frame_ids] + + fg_anno_frames = {} + for key, value in fg_anno.items(): + fg_anno_frames[key] = [value[0].clone() for f_id in frame_ids] + + if self.foreground_transform is not None: + fg_frame_list, fg_anno_frames['bbox'], fg_anno_frames['mask'] = self.foreground_transform( + image=fg_frame_list, + bbox=fg_anno_frames['bbox'], + mask=fg_anno_frames['mask'], + joint=False) + + # Sample a random background + bg_seq_id = random.randint(0, self.background_image_dataset.get_num_images() - 1) + + bg_frame, bg_anno, _ = self.background_image_dataset.get_image(bg_seq_id) + + bg_frame_list = [bg_frame.copy() for _ in frame_ids] + + bg_anno_frames = {} + for key, value in bg_anno.items(): + # Note: Since we get bg anno from image dataset, it does not has frame dimension + bg_anno_frames[key] = [value.clone() for f_id in frame_ids] + + if self.background_transform is not None: + if 'mask' in bg_anno_frames.keys(): + bg_frame_list, bg_anno_frames['bbox'], bg_anno_frames['mask'] = self.background_transform( + image=bg_frame_list, + bbox=bg_anno_frames['bbox'], + mask=bg_anno_frames['mask'], + joint=False) + else: + bg_frame_list, bg_anno_frames['bbox'] = self.background_transform( + image=bg_frame_list, + bbox=bg_anno_frames['bbox'], + joint=False) + + for i in range(len(frame_ids)): + # To be safe, get target bb for the mask + bbox = masks_to_bboxes(fg_anno_frames['mask'][i], fmt='t') + + loc_y = random.randint(0, bg_frame_list[i].shape[0] - 1) + loc_x = random.randint(0, bg_frame_list[i].shape[1] - 1) + + paste_loc = (loc_x, loc_y) + fg_frame_list[i], fg_anno_frames['mask'][i] = self._paste_target(fg_frame_list[i], bbox, + fg_anno_frames['mask'][i], + bg_frame_list[i], paste_loc) + + fg_anno_frames['bbox'][i] = masks_to_bboxes(fg_anno_frames['mask'][i], fmt='t') + + object_meta = OrderedDict({'object_class_name': self.get_class_name(seq_id), + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return fg_frame_list, fg_anno_frames, object_meta diff --git a/ltr/dataset/tracking_net.py b/ltr/dataset/tracking_net.py new file mode 100755 index 0000000..bb72764 --- /dev/null +++ b/ltr/dataset/tracking_net.py @@ -0,0 +1,151 @@ +import torch +import os +import os.path +import numpy as np +import pandas +import random +from collections import OrderedDict + +from ltr.data.image_loader import jpeg4py_loader +from .base_video_dataset import BaseVideoDataset +from ltr.admin.environment import env_settings + + +def list_sequences(root, set_ids): + """ Lists all the videos in the input set_ids. Returns a list of tuples (set_id, video_name) + + args: + root: Root directory to TrackingNet + set_ids: Sets (0-11) which are to be used + + returns: + list - list of tuples (set_id, video_name) containing the set_id and video_name for each sequence + """ + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, "TRAIN_" + str(s), "anno") + + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + sequence_list += sequences_cur_set + + return sequence_list + + +class TrackingNet(BaseVideoDataset): + """ TrackingNet dataset. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self, root=None, image_loader=jpeg4py_loader, set_ids=None, data_fraction=None): + """ + args: + root - The path to the TrackingNet folder, containing the training sets. + image_loader (jpeg4py_loader) - The function to read the images. jpeg4py (https://github.com/ajkxyz/jpeg4py) + is used by default. + set_ids (None) - List containing the ids of the TrackingNet sets to be used for training. If None, all the + sets (0 - 11) will be used. + data_fraction - Fraction of dataset to be used. The complete dataset is used by default + """ + root = env_settings().trackingnet_dir if root is None else root + super().__init__('TrackingNet', root, image_loader) + + if set_ids is None: + set_ids = [i for i in range(12)] + + self.set_ids = set_ids + + # Keep a list of all videos. Sequence list is a list of tuples (set_id, video_name) containing the set_id and + # video_name for each sequence + self.sequence_list = list_sequences(self.root, self.set_ids) + + if data_fraction is not None: + self.sequence_list = random.sample(self.sequence_list, int(len(self.sequence_list) * data_fraction)) + + self.seq_to_class_map, self.seq_per_class = self._load_class_info() + + # we do not have the class_lists for the tracking net + self.class_list = list(self.seq_per_class.keys()) + self.class_list.sort() + + def _load_class_info(self): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + class_map_path = os.path.join(ltr_path, 'data_specs', 'trackingnet_classmap.txt') + + with open(class_map_path, 'r') as f: + seq_to_class_map = {seq_class.split('\t')[0]: seq_class.rstrip().split('\t')[1] for seq_class in f} + + seq_per_class = {} + for i, seq in enumerate(self.sequence_list): + class_name = seq_to_class_map.get(seq[1], 'Unknown') + if class_name not in seq_per_class: + seq_per_class[class_name] = [i] + else: + seq_per_class[class_name].append(i) + + return seq_to_class_map, seq_per_class + + def get_name(self): + return 'trackingnet' + + def has_class_info(self): + return True + + def get_sequences_in_class(self, class_name): + return self.seq_per_class[class_name] + + def _read_bb_anno(self, seq_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + bb_anno_file = os.path.join(self.root, "TRAIN_" + str(set_id), "anno", vid_name + ".txt") + gt = pandas.read_csv(bb_anno_file, delimiter=',', header=None, dtype=np.float32, na_filter=False, + low_memory=False).values + return torch.tensor(gt) + + def get_sequence_info(self, seq_id): + bbox = self._read_bb_anno(seq_id) + + valid = (bbox[:, 2] > 0) & (bbox[:, 3] > 0) + visible = valid.clone().byte() + return {'bbox': bbox, 'valid': valid, 'visible': visible} + + def _get_frame(self, seq_id, frame_id): + set_id = self.sequence_list[seq_id][0] + vid_name = self.sequence_list[seq_id][1] + frame_path = os.path.join(self.root, "TRAIN_" + str(set_id), "frames", vid_name, str(frame_id) + ".jpg") + return self.image_loader(frame_path) + + def _get_class(self, seq_id): + seq_name = self.sequence_list[seq_id][1] + return self.seq_to_class_map[seq_name] + + def get_class_name(self, seq_id): + obj_class = self._get_class(seq_id) + + return obj_class + + def get_frames(self, seq_id, frame_ids, anno=None): + frame_list = [self._get_frame(seq_id, f) for f in frame_ids] + + if anno is None: + anno = self.get_sequence_info(seq_id) + + anno_frames = {} + for key, value in anno.items(): + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + obj_class = self._get_class(seq_id) + + object_meta = OrderedDict({'object_class_name': obj_class, + 'motion_class': None, + 'major_class': None, + 'root_class': None, + 'motion_adverb': None}) + + return frame_list, anno_frames, object_meta diff --git a/ltr/dataset/vos_base.py b/ltr/dataset/vos_base.py new file mode 100755 index 0000000..50a4fbe --- /dev/null +++ b/ltr/dataset/vos_base.py @@ -0,0 +1,398 @@ +import torch +from pathlib import Path +from collections import OrderedDict, defaultdict +import json +import numpy as np +import os + +from .base_video_dataset import BaseVideoDataset +from ltr.data.image_loader import jpeg4py_loader, imread_indexed +from ltr.data.bounding_box_utils import masks_to_bboxes + + +class VOSMeta: + def __init__(self, data=None, filename=None): + if filename is not None: + self.load(filename) + elif data is not None: + self._data = data + else: + raise ValueError("Must set either data or filename parameter") + + def save(self, gen_meta: Path): + gen_meta.parent.mkdir(exist_ok=True, parents=True) + json.dump(self._data, open(gen_meta, "w")) + + def load(self, gen_meta: Path): + if not gen_meta.exists(): + print("Generated metadata file %s is not found." % gen_meta) + print("Find and run VOSMeta.generate() to create it.") + raise FileNotFoundError(gen_meta) + self._data = json.load(open(gen_meta), object_pairs_hook=OrderedDict) + + @classmethod + def generate(cls, dset_name: str, dset_images_path: Path, dset_annos_path: Path): + """ + Count the annotation mask pixels per object, per frame, in all sequences in a dataset + :param dset_name: Dataset name, for printing the progress bar. + :param dset_annos_path: Path to annotations directory, containing sequence directories, + with annotation frames in them. + + :return: Dataset meta dict: + + {'sequence0': + { + 'shape': (height, width) + + 'obj_sizes': # Object pixels per frame + {'frame0': {'object0': px_count, 'object1': px_count, ...}, + 'frame1': {'object0': px_count, 'object1': px_count, ...}, + ... }, + + 'bboxes': # Bounding boxes per frame + {'frame0': {'object0': bbox, 'object1': bbox, ...}, + 'frame1': {'object0': bbox, 'object1': bbox, ...}, + ... }, + ... + } + """ + assert(dset_annos_path.exists()) + + dset_meta = OrderedDict() + sequences = [p.stem for p in sorted(dset_annos_path.glob("*")) if p.is_dir()] + + try: + from tqdm import tqdm + except: + def tqdm(x, *args, **kwargs): + return x + + for seq in tqdm(sequences, desc=dset_name, unit="seq"): + + obj_sizes2 = defaultdict(OrderedDict) + bboxes = defaultdict(OrderedDict) + shape = None + frame_names = [file.stem for file in sorted((dset_images_path / seq).glob("*.jpg"))] + anno_paths = list(sorted((dset_annos_path / seq).glob("*.png"))) + + # Extract information from the given label frames + for path in anno_paths: + f_id = path.stem + + # Count label-pixels per frame + labels = imread_indexed(path) + # labels = np.array(Image.open(path)) + obj_ids, obj_sizes = np.unique(labels, return_counts=True) + obj_ids = [str(oid) for oid in obj_ids] + obj_sizes = obj_sizes.tolist() + + if '0' in obj_ids: # Remove background id + obj_ids = obj_ids[1:] + obj_sizes = obj_sizes[1:] + obj_sizes2[f_id] = OrderedDict(zip(obj_ids, obj_sizes)) + + # Generate per-label bounding boxes + for obj_id in obj_ids: + bboxes[f_id][obj_id] = cls._mask_to_bbox(labels == int(obj_id)) + + if shape is None: + shape = labels.shape[:2] + + # Format result + + dset_meta[seq] = dict(shape=shape, obj_sizes=obj_sizes2, bboxes=bboxes, frame_names=frame_names) + + return VOSMeta(dset_meta) + + @staticmethod + def _mask_to_bbox(mask: np.ndarray): + + mask = mask.astype(int) + xs = mask.sum(axis=-2).nonzero()[0].tolist() + ys = mask.sum(axis=-1).nonzero()[0].tolist() + + if len(ys) > 0 and len(xs) > 0: + x, y, w, h = xs[0], ys[0], xs[-1] - xs[0], ys[-1] - ys[0] + else: + x, y, w, h = 0, 0, 0, 0 + + return [x, y, w, h] + + @staticmethod + def _transpose_nested_dict(d): + """ Permute a 2-level nested dict such that the inner and outer keys swap places. """ + d2 = defaultdict(OrderedDict) + for key1, inner in d.items(): + for key2, value in inner.items(): + d2[key2][key1] = value + return d2 + + def select_split(self, dataset_name, split): + ltr_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') + sequences = set([s.strip() for s in open(os.path.join(ltr_path, 'data_specs', dataset_name + '_' + split + '.txt')).readlines()]) + all_sequences = set(self._data.keys()) + to_remove = all_sequences.difference(sequences) + for seq_name in to_remove: + self._data.pop(seq_name) + + def get_sequence_names(self): + return list(self._data.keys()) + + def get_shape(self, seq_name): + """ Sequence image shape (h,w) """ + h, w = self._data[seq_name]['shape'] + return h, w + + def get_obj_ids(self, seq_name): + """ All objects in the sequence """ + return list(self.get_obj_sizes_per_object(seq_name).keys()) + + def get_frame_names(self, seq_name): + """ All filename stems of the frames in the sequence """ + return self._data[seq_name]['frame_names'] + + def enable_all_frames(self, dset_images_path): + """ For YouTubeVOS: Update the frame names with (jpeg) files from the _all_frames set + :param dset_images_path: /path/to/train_all_frames/JPEGImages (or valid or test) + :param seq: Sequence name + :return: + """ + + # Try load the cached index + idx_file = dset_images_path.parent / "frame_names.json" + if idx_file.exists(): + print('Loading cached frame names from %s' % idx_file) + all_frame_names = json.load(open(idx_file)) + else: + # Cache the data to the user's home directory (guaranteed to be writable) + all_frame_names = dict() + user_idx_file = Path.home() / (dset_images_path.parent.stem + "_frame_names.json") + print('Indexing YouTubeVOS "all_frames" frame names to %s' % user_idx_file) + for seq in self._data: + all_frame_names[seq] = [file.stem for file in sorted((dset_images_path / seq).glob("*.jpg"))] + json.dump(all_frame_names, open(user_idx_file, "w")) + print('Done. Move %s to %s to load faster next time.' % (user_idx_file, idx_file)) + + for seq, frame_names in all_frame_names.items(): + self._data[seq]['frame_names'] = frame_names + + def get_aspect_ratio(self, seq_name): + """ Sequence aspect ratio """ + h, w = self._data[seq_name]['shape'] + return w / h + + def get_obj_sizes_per_frame(self, seq_name): + """ Get object pixel counts, grouped by frame names """ + return self._data[seq_name]['obj_sizes'] + + def get_bboxes_per_frame(self, seq_name): + """ Object bounding boxes, grouped by frame names """ + return self._data[seq_name]['bboxes'] + + def get_obj_sizes_per_object(self, seq_name): + """ Object pixel counts, grouped by object """ + return self._transpose_nested_dict(self.get_obj_sizes_per_frame(seq_name)) + + def get_bboxes_per_object(self, seq_name): + """ Object bounding boxes, grouped by object """ + return self._transpose_nested_dict(self.get_bboxes_per_frame(seq_name)) + + @staticmethod + def generate_datasets_meta(src, dst=Path("~/vosdataset_meta").expanduser()): + VOSMeta.generate("SyntheticCoco", src / "JPEGImages", src / "Annotations").save(src / "generated_meta.json") + + +class VOSDatasetBase(BaseVideoDataset): + + """ Generic VOS dataset reader base class, for both DAVIS and YouTubeVOS """ + + def __init__(self, name: str, root: Path, version=None, split='train', + multiobj=True, vis_threshold=10, image_loader=jpeg4py_loader): + """ + :param root: Dataset root path, eg /path/to/DAVIS or /path/to/YouTubeVOS/ + Note: YouTubeVOS 2018 and 2019 are expected to be in + /path/to/YouTubeVOS/2018 and /path/to/YouTubeVOS/2019, respectively + :param name: 'DAVIS' or 'YouTubeVOS' (case sensitive) + :param version: DAVIS: '2016', '2017, YouTubeVOS: '2018' or '2019' + :param split: DAVIS: Any name in DAVIS/ImageSets/, + YouTubeVOS: 'test', 'train', 'valid' or 'jjtrain', 'jjvalid' + :param multiobj: Whether the dataset will return all objects in a sequence or + multiple sequences with one object in each. + :param vis_threshold: Minimum number of pixels required to consider a target object "visible". + :param image_loader: Image loader. + """ + + assert root.exists() and root.is_dir() + + super().__init__(name, root, image_loader) + + self.version = version + self.split = split + self.vis_threshold = vis_threshold + self.multiobj = multiobj + + def _load_image(self, path): + im = self.image_loader(str(path)) + assert im is not None + im = np.atleast_3d(im) + return im + + @staticmethod + def _load_anno(path): + if not path.exists(): + return None + # im = np.atleast_3d(np.array(Image.open(path))) + im = imread_indexed(path) + return im + + def get_num_sequences(self): + return len(self._samples) + + def get_sequence_info(self, sample_id): + """ Get sample meta data. + :param sample_id: Sample to query. + :return: dict of metadata: + sequence: Sequence name + frame_shape: (height, width) of the images + frame_names: List of frame filename stems in the sequence + object_ids: Id numbers of all objects occurring in the sequence + obj_sizes: Matrix shape=(frames, object) of the number of pixels for each object in each frame + Coordinates in this matrix relate to the frame_names and object_ids + visible: Boolean matrix of the same shape as obj_sizes. Entries with more pixels + than self.visible_threshold are True. + """ + m = self.gmeta + seq_name, obj_ids = self._samples[sample_id] + f_names = m.get_frame_names(seq_name) # All frames + + f2i = {f: i for i, f in enumerate(f_names)} # Frame name to matrix index + o2i = {o: i for i, o in enumerate(obj_ids)} # Object id to matrix index + + # Get a matrix of object sizes: shape=(frames, objects) + obj_sizes = torch.zeros((len(f_names), len(obj_ids)), dtype=torch.int) + sizes_per_object = m.get_obj_sizes_per_object(seq_name) + + for obj_id in obj_ids: + frames = sizes_per_object[obj_id] + oid = o2i[obj_id] + for f, sz in frames.items(): + obj_sizes[f2i[f], oid] = sz + + visible = (obj_sizes > self.vis_threshold).byte() + + return dict(sequence=seq_name, frame_shape=m.get_shape(seq_name), frame_names=f_names, object_ids=obj_ids, + object_sizes=obj_sizes, visible=visible, valid=visible) + + def get_paths_and_bboxes(self, sequence_info): + + seq_name = sequence_info['sequence'] + annos_root = self._anno_path / seq_name + images_root = self._jpeg_path / seq_name + + frame_names = sequence_info['frame_names'] + f2i = {f: i for i, f in enumerate(frame_names)} + + images = [str(images_root / (f + ".jpg")) for f in frame_names] + + # Find the frames where ground truth is available and + # get the bounding boxes and segmentation labels of those frames + all_bboxes = self.gmeta.get_bboxes_per_frame(seq_name) + gt_labels = [str(annos_root / (f + ".png")) if f in all_bboxes.keys() else None for f in frame_names] + + gt_bboxes = OrderedDict() + for obj_id in sequence_info['object_ids']: + gt_bboxes[obj_id] = np.array([all_bboxes.get(frame, {}).get(obj_id, [-1, -1, -1, -1]) for frame in frame_names]) + + return images, gt_labels, gt_bboxes + + def _construct_sequence(self, sequence_info): + raise NotImplementedError + + def get_sequence_list(self): + if len(self.sequence_list) > 0: + return self.sequence_list + self.sequence_list = [self._construct_sequence(self.get_sequence_info(i)) for i in range(len(self._samples))] + return self.sequence_list + + def __len__(self): + return len(self._samples) + + def _get_image_path(self, meta, frame_id): + return self._jpeg_path / meta['sequence'] / (meta['frame_names'][frame_id] + ".jpg") + + def _get_anno_path(self, meta, frame_id): + return self._anno_path / meta['sequence'] / (meta['frame_names'][frame_id] + ".png") + + def get_frames(self, sample_id, frame_ids, anno=None): + """ Fetch frames with the given ids. + :param sample_id: Sample to get. + :param frame_ids: List of frame indices in the sequence belonging to the sample_id + :return: dict of metadata and data: + sequence: Sequence name + images: List of images. No entries may be None + labels: List of label/mask images. Entries may be None if the data is missing + bboxes: List of bounding boxes. Entries may be None if the data is missing + """ + seq_name, obj_ids = self._samples[sample_id] + + meta = self.get_sequence_info(sample_id) if anno is None else anno + frame_names = meta['frame_names'] + images = [self._load_image(self._jpeg_path / seq_name / (frame_names[f] + ".jpg")) for f in frame_ids] + labels = [self._load_anno(self._anno_path / seq_name / (frame_names[f] + ".png")) for f in frame_ids] + + # Generate bounding boxes for the requested objects + bboxes = [] + for lb in labels: + lb = torch.from_numpy(lb.squeeze()) + frame_bbs = {} + for obj_id in obj_ids: + bbox = masks_to_bboxes(lb == int(obj_id), fmt='t') + if bbox[3] == 0 or bbox[2] == 0: + print("!") + frame_bbs[obj_id] = bbox + bboxes.append(frame_bbs) + + # Insert empty bboxes for missing object ids + for bbox in bboxes: + for obj_id in obj_ids: + if obj_id not in bbox: + bbox[obj_id] = torch.zeros(4, dtype=torch.float32) + + # Remap to object id 1, if requested - for training + if not self.multiobj: + assert len(obj_ids) == 1 + obj_id = obj_ids[0] + labels = [torch.Tensor(lb == int(obj_id)) for lb in labels] + bboxes = [bbox[obj_id] for bbox in bboxes] + else: + labels = [torch.Tensor(lb) for lb in labels] + + object_meta = {key: meta[key] for key in ['sequence', 'frame_shape', 'frame_names', 'object_ids']} + + anno_frames = dict(bbox=bboxes, mask=labels) + for key in ['object_sizes', 'visible', 'valid']: + value = meta[key] + anno_frames[key] = [value[f_id, ...].clone() for f_id in frame_ids] + + return images, anno_frames, object_meta + + def get_name(self): + return "%s/%s/%s" % (self.name, self.version, self.split) + + def has_class_info(self): + return False + + def has_occlusion_info(self): + return True + + def get_num_classes(self): + return 0 + + def get_class_list(self): + return [] + + def get_sequences_in_class(self, class_name): + raise [] + + def has_segmentation_info(self): + return True diff --git a/ltr/dataset/youtubevos.py b/ltr/dataset/youtubevos.py new file mode 100755 index 0000000..dd3b3c4 --- /dev/null +++ b/ltr/dataset/youtubevos.py @@ -0,0 +1,192 @@ +from pathlib import Path +import os +from ltr.dataset.vos_base import VOSDatasetBase, VOSMeta +from pytracking.evaluation import Sequence +import json +from ltr.admin.environment import env_settings +from ltr.data.image_loader import jpeg4py_loader + + +class YouTubeVOSMeta: + """ Thin wrapper for YouTubeVOS meta data + meta.json + { + "videos": { + "": { + "objects": { + "": { + "category": "", + "frames": [ + "", + "", + ] + } + } + } + } + } + # is the same as the pixel values of object in annotated segmentation PNG files. + # is the 5-digit index of frame in video, and not necessary to start from 0. + """ + + def __init__(self, dset_split_path): + self._data = json.load(open(dset_split_path / 'meta.json'))['videos'] + + def sequences(self): + return list(self._data.keys()) + + def seq_frames(self, seq_name): + """ All filename stems of the frames in the sequence """ + frames = set() + for obj_id in self.object_ids(seq_name): + for f in self.object_frames(seq_name, obj_id): + frames.add(f) + return list(sorted(frames)) + + def object_ids(self, seq_name): + """ All objects in the sequence """ + return list(self._data[seq_name]['objects'].keys()) + + def object_category(self, seq_name, obj_id): + return self._data[seq_name]['objects'][str(obj_id)]['category'] + + def object_frames(self, seq_name, obj_id): + return self._data[seq_name]['objects'][str(obj_id)]['frames'] + + def object_first_frame(self, seq_name, obj_id): + return self.object_frames(seq_name, obj_id)[0] + + +class YouTubeVOS(VOSDatasetBase): + """ + YoutubeVOS video object segmentation dataset. + + Publication: + YouTube-VOS: A Large-Scale Video Object Segmentation Benchmark + Ning Xu, Linjie Yang, Yuchen Fan, Dingcheng Yue, Yuchen Liang, Jianchao Yang, and Thomas Huang + ECCV, 2018 + https://arxiv.org/pdf/1809.03327.pdf + + Download dataset from: https://youtube-vos.org/dataset/ + """ + def __init__(self, root=None, version='2019', split='train', cleanup=None, all_frames=False, sequences=None, + multiobj=True, vis_threshold=10, image_loader=jpeg4py_loader): + """ + args: + root - Dataset root path. If unset, it uses the path in your local.py config. + version - '2018' or '2019' + split - 'test', 'train', 'valid', or 'jjtrain', 'jjvalid'. 'jjvalid' corresponds to a custom validation + dataset consisting of 300 videos randomly sampled from the train set. 'jjtrain' contains the + remaining videos used for training. + cleanup - List of actions to take to to clean up known problems in the dataset. + 'aspects': remove frames with weird aspect ratios, + 'starts': fix up start frames from original meta data + all_frames - Whether to use an "all_frames" split. + sequences - List of sequence names. Limit to a subset of sequences if not None. + multiobj - Whether the dataset will return all objects in a sequence or multiple sequences with one + object in each. + vis_threshold - Minimum number of pixels required to consider a target object "visible". + image_loader - Image loader. + """ + root = env_settings().youtubevos_dir if root is None else root + super().__init__(name="YouTubeVOS", root=Path(root), version=version, split=split, multiobj=multiobj, + vis_threshold=vis_threshold, image_loader=image_loader) + + split_folder = self.split + if self.split.startswith("jj"): + split_folder = "train" + + dset_path = self.root / self.version / split_folder + + self._anno_path = dset_path / 'Annotations' + + if all_frames: + self._jpeg_path = self.root / self.version / (split_folder + "_all_frames") / 'JPEGImages' + else: + self._jpeg_path = dset_path / 'JPEGImages' + + self.meta = YouTubeVOSMeta(dset_path) + meta_path = dset_path / "generated_meta.json" + if meta_path.exists(): + self.gmeta = VOSMeta(filename=meta_path) + else: + self.gmeta = VOSMeta.generate('YouTubeVOS', self._jpeg_path, self._anno_path) + self.gmeta.save(meta_path) + + if all_frames: + self.gmeta.enable_all_frames(self._jpeg_path) + + if self.split not in ['train', 'valid', 'test']: + self.gmeta.select_split('youtubevos', self.split) + + if sequences is None: + sequences = self.gmeta.get_sequence_names() + + to_remove = set() + cleanup = {} if cleanup is None else set(cleanup) + + if 'aspect' in cleanup: + # Remove sequences with unusual aspect ratios + for seq_name in sequences: + a = self.gmeta.get_aspect_ratio(seq_name) + if a < 1.45 or a > 1.9: + to_remove.add(seq_name) + + if 'starts' in cleanup: + # Fix incorrect start frames for some objects found with ytvos_start_frames_test() + bad_start_frames = [("0e27472bea", '2', ['00055', '00060'], '00065'), + ("5937b08d69", '4', ['00000'], '00005'), + ("5e1ce354fd", '5', ['00010', '00015'], '00020'), + ("7053e4f41e", '2', ['00000', '00005', '00010', '00015'], '00020'), + ("720e3fa04c", '2', ['00050'], '00055'), + ("c73c8e747f", '2', ['00035'], '00040')] + for seq_name, obj_id, bad_frames, good_frame in bad_start_frames: + # bad_frames is from meta.json included with the dataset + # good_frame is from the generated meta - and the first actual frame where the object was seen. + if seq_name in self.meta._data: + frames = self.meta.object_frames(seq_name, obj_id) + for f in bad_frames: + frames.remove(f) + assert frames[0] == good_frame + + sequences = [seq for seq in sequences if seq not in to_remove] + + self.sequence_names = sequences + self._samples = [] + + for seq in sequences: + obj_ids = self.meta.object_ids(seq) + if self.multiobj: # Multiple objects per sample + self._samples.append((seq, obj_ids)) + else: # One object per sample + self._samples.extend([(seq, [obj_id]) for obj_id in obj_ids]) + + print("%s loaded." % self.get_name()) + if len(to_remove) > 0: + print(" %d sequences were removed, (%d remaining)." % (len(to_remove), len(sequences))) + + def _construct_sequence(self, sequence_info): + + seq_name = sequence_info['sequence'] + frame_names = sequence_info['frame_names'] + fname_to_fid = {f: i for i, f in enumerate(frame_names)} + images, gt_segs, gt_bboxes = self.get_paths_and_bboxes(sequence_info) + + init_data = dict() + for obj_id in sequence_info['object_ids']: + if obj_id == '0': + print("!") + f_name = self.meta.object_first_frame(seq_name, obj_id) + f_id = fname_to_fid[f_name] + if f_id not in init_data: + init_data[f_id] = {'object_ids': [obj_id], + 'bbox': {obj_id: gt_bboxes[obj_id][f_id,:]}, + 'mask': os.path.join(os.path.dirname(gt_segs[f_id]), (f_name + ".png"))} + assert init_data[f_id]['mask'] in gt_segs # If this fails, some file is missing + else: + init_data[f_id]['object_ids'].append(obj_id) + init_data[f_id]['bbox'][obj_id] = gt_bboxes[obj_id][f_id,:] + + return Sequence(name=seq_name, frames=images, dataset='YouTubeVOS', ground_truth_rect=gt_bboxes, + init_data=init_data, ground_truth_seg=gt_segs, object_ids=sequence_info['object_ids'], + multiobj_mode=self.multiobj) diff --git a/ltr/external/PreciseRoIPooling/.gitignore b/ltr/external/PreciseRoIPooling/.gitignore new file mode 100755 index 0000000..8d28381 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/.gitignore @@ -0,0 +1,106 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +.vim-template* + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/ltr/external/PreciseRoIPooling/LICENSE b/ltr/external/PreciseRoIPooling/LICENSE new file mode 100755 index 0000000..b1d20a6 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jiayuan Mao + +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. diff --git a/ltr/external/PreciseRoIPooling/README.md b/ltr/external/PreciseRoIPooling/README.md new file mode 100755 index 0000000..bb98946 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/README.md @@ -0,0 +1,66 @@ +# PreciseRoIPooling +This repo implements the **Precise RoI Pooling** (PrRoI Pooling), proposed in the paper **Acquisition of Localization Confidence for Accurate Object Detection** published at ECCV 2018 (Oral Presentation). + +**Acquisition of Localization Confidence for Accurate Object Detection** + +_Borui Jiang*, Ruixuan Luo*, Jiayuan Mao*, Tete Xiao, Yuning Jiang_ (* indicates equal contribution.) + +https://arxiv.org/abs/1807.11590 + +## Brief + +In short, Precise RoI Pooling is an integration-based (bilinear interpolation) average pooling method for RoI Pooling. It avoids any quantization and has a continuous gradient on bounding box coordinates. It is: + +- different from the original RoI Pooling proposed in [Fast R-CNN](https://arxiv.org/abs/1504.08083). PrRoI Pooling uses average pooling instead of max pooling for each bin and has a continuous gradient on bounding box coordinates. That is, one can take the derivatives of some loss function w.r.t the coordinates of each RoI and optimize the RoI coordinates. +- different from the RoI Align proposed in [Mask R-CNN](https://arxiv.org/abs/1703.06870). PrRoI Pooling uses a full integration-based average pooling instead of sampling a constant number of points. This makes the gradient w.r.t. the coordinates continuous. + +For a better illustration, we illustrate RoI Pooling, RoI Align and PrRoI Pooing in the following figure. More details including the gradient computation can be found in our paper. + +
+ +## Implementation + +PrRoI Pooling was originally implemented by [Tete Xiao](http://tetexiao.com/) based on MegBrain, an (internal) deep learning framework built by Megvii Inc. It was later adapted into open-source deep learning frameworks. Currently, we only support PyTorch. Unfortunately, we don't have any specific plan for the adaptation into other frameworks such as TensorFlow, but any contributions (pull requests) will be more than welcome. + +## Usage (PyTorch 1.0) + +In the directory `pytorch/`, we provide a PyTorch-based implementation of PrRoI Pooling. It requires PyTorch 1.0+ and only supports CUDA (CPU mode is not implemented). +Since we use PyTorch JIT for cxx/cuda code compilation, to use the module in your code, simply do: + +``` +from prroi_pool import PrRoIPool2D + +avg_pool = PrRoIPool2D(window_height, window_width, spatial_scale) +roi_features = avg_pool(features, rois) + +# for those who want to use the "functional" + +from prroi_pool.functional import prroi_pool2d +roi_features = prroi_pool2d(features, rois, window_height, window_width, spatial_scale) +``` + + +## Usage (PyTorch 0.4) + +**!!! Please first checkout to the branch pytorch0.4.** + +In the directory `pytorch/`, we provide a PyTorch-based implementation of PrRoI Pooling. It requires PyTorch 0.4 and only supports CUDA (CPU mode is not implemented). +To use the PrRoI Pooling module, first goto `pytorch/prroi_pool` and execute `./travis.sh` to compile the essential components (you may need `nvcc` for this step). To use the module in your code, simply do: + +``` +from prroi_pool import PrRoIPool2D + +avg_pool = PrRoIPool2D(window_height, window_width, spatial_scale) +roi_features = avg_pool(features, rois) + +# for those who want to use the "functional" + +from prroi_pool.functional import prroi_pool2d +roi_features = prroi_pool2d(features, rois, window_height, window_width, spatial_scale) +``` + +Here, + +- RoI is an `m * 5` float tensor of format `(batch_index, x0, y0, x1, y1)`, following the convention in the original Caffe implementation of RoI Pooling, although in some frameworks the batch indices are provided by an integer tensor. +- `spatial_scale` is multiplied to the RoIs. For example, if your feature maps are down-sampled by a factor of 16 (w.r.t. the input image), you should use a spatial scale of `1/16`. +- The coordinates for RoI follows the [L, R) convension. That is, `(0, 0, 4, 4)` denotes a box of size `4x4`. diff --git a/ltr/external/PreciseRoIPooling/_assets/prroi_visualization.png b/ltr/external/PreciseRoIPooling/_assets/prroi_visualization.png new file mode 100755 index 0000000..ea3a15f Binary files /dev/null and b/ltr/external/PreciseRoIPooling/_assets/prroi_visualization.png differ diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/.gitignore b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/.gitignore new file mode 100755 index 0000000..18495ea --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/.gitignore @@ -0,0 +1,2 @@ +*.o +/_prroi_pooling diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/__init__.py b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/__init__.py new file mode 100755 index 0000000..0c40b7a --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/__init__.py @@ -0,0 +1,13 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# File : __init__.py +# Author : Jiayuan Mao, Tete Xiao +# Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com +# Date : 07/13/2018 +# +# This file is part of PreciseRoIPooling. +# Distributed under terms of the MIT license. +# Copyright (c) 2017 Megvii Technology Limited. + +from .prroi_pool import * + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/build.py b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/build.py new file mode 100755 index 0000000..b198790 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/build.py @@ -0,0 +1,50 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# File : build.py +# Author : Jiayuan Mao, Tete Xiao +# Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com +# Date : 07/13/2018 +# +# This file is part of PreciseRoIPooling. +# Distributed under terms of the MIT license. +# Copyright (c) 2017 Megvii Technology Limited. + +import os +import torch + +from torch.utils.ffi import create_extension + +headers = [] +sources = [] +defines = [] +extra_objects = [] +with_cuda = False + +if torch.cuda.is_available(): + with_cuda = True + + headers+= ['src/prroi_pooling_gpu.h'] + sources += ['src/prroi_pooling_gpu.c'] + defines += [('WITH_CUDA', None)] + + this_file = os.path.dirname(os.path.realpath(__file__)) + extra_objects_cuda = ['src/prroi_pooling_gpu_impl.cu.o'] + extra_objects_cuda = [os.path.join(this_file, fname) for fname in extra_objects_cuda] + extra_objects.extend(extra_objects_cuda) +else: + # TODO(Jiayuan Mao @ 07/13): remove this restriction after we support the cpu implementation. + raise NotImplementedError('Precise RoI Pooling only supports GPU (cuda) implememtations.') + +ffi = create_extension( + '_prroi_pooling', + headers=headers, + sources=sources, + define_macros=defines, + relative_to=__file__, + with_cuda=with_cuda, + extra_objects=extra_objects +) + +if __name__ == '__main__': + ffi.build() + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/functional.py b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/functional.py new file mode 100755 index 0000000..98247e0 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/functional.py @@ -0,0 +1,85 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# File : functional.py +# Author : Jiayuan Mao, Tete Xiao +# Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com +# Date : 07/13/2018 +# +# This file is part of PreciseRoIPooling. +# Distributed under terms of the MIT license. +# Copyright (c) 2017 Megvii Technology Limited. + +import torch +import torch.autograd as ag + +__all__ = ['prroi_pool2d'] + + +_prroi_pooling = None + + +def _import_prroi_pooling(): + global _prroi_pooling + + if _prroi_pooling is None: + try: + from os.path import join as pjoin, dirname + from torch.utils.cpp_extension import load as load_extension + root_dir = pjoin(dirname(__file__), 'src') + + _prroi_pooling = load_extension( + '_prroi_pooling', + [pjoin(root_dir, 'prroi_pooling_gpu.c'), pjoin(root_dir, 'prroi_pooling_gpu_impl.cu')], + verbose=True + ) + except ImportError: + raise ImportError('Can not compile Precise RoI Pooling library.') + + return _prroi_pooling + + +class PrRoIPool2DFunction(ag.Function): + @staticmethod + def forward(ctx, features, rois, pooled_height, pooled_width, spatial_scale): + _prroi_pooling = _import_prroi_pooling() + + assert 'FloatTensor' in features.type() and 'FloatTensor' in rois.type(), \ + 'Precise RoI Pooling only takes float input, got {} for features and {} for rois.'.format(features.type(), rois.type()) + + pooled_height = int(pooled_height) + pooled_width = int(pooled_width) + spatial_scale = float(spatial_scale) + + features = features.contiguous() + rois = rois.contiguous() + params = (pooled_height, pooled_width, spatial_scale) + + if features.is_cuda: + output = _prroi_pooling.prroi_pooling_forward_cuda(features, rois, *params) + ctx.params = params + # everything here is contiguous. + ctx.save_for_backward(features, rois, output) + else: + raise NotImplementedError('Precise RoI Pooling only supports GPU (cuda) implememtations.') + + return output + + @staticmethod + def backward(ctx, grad_output): + _prroi_pooling = _import_prroi_pooling() + + features, rois, output = ctx.saved_tensors + grad_input = grad_coor = None + + if features.requires_grad: + grad_output = grad_output.contiguous() + grad_input = _prroi_pooling.prroi_pooling_backward_cuda(features, rois, output, grad_output, *ctx.params) + if rois.requires_grad: + grad_output = grad_output.contiguous() + grad_coor = _prroi_pooling.prroi_pooling_coor_backward_cuda(features, rois, output, grad_output, *ctx.params) + + return grad_input, grad_coor, None, None, None + + +prroi_pool2d = PrRoIPool2DFunction.apply + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/prroi_pool.py b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/prroi_pool.py new file mode 100755 index 0000000..d281e1d --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/prroi_pool.py @@ -0,0 +1,32 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# File : prroi_pool.py +# Author : Jiayuan Mao, Tete Xiao +# Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com +# Date : 07/13/2018 +# +# This file is part of PreciseRoIPooling. +# Distributed under terms of the MIT license. +# Copyright (c) 2017 Megvii Technology Limited. + +import torch.nn as nn + +from .functional import prroi_pool2d + +__all__ = ['PrRoIPool2D'] + + +class PrRoIPool2D(nn.Module): + def __init__(self, pooled_height, pooled_width, spatial_scale): + super().__init__() + + self.pooled_height = int(pooled_height) + self.pooled_width = int(pooled_width) + self.spatial_scale = float(spatial_scale) + + def forward(self, features, rois): + return prroi_pool2d(features, rois, self.pooled_height, self.pooled_width, self.spatial_scale) + + def extra_repr(self): + return 'kernel_size=({pooled_height}, {pooled_width}), spatial_scale={spatial_scale}'.format(**self.__dict__) + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.c b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.c new file mode 100755 index 0000000..1e65296 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.c @@ -0,0 +1,113 @@ +/* + * File : prroi_pooling_gpu.c + * Author : Jiayuan Mao, Tete Xiao + * Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com + * Date : 07/13/2018 + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +#include +#include + +#include +#include + +#include + +#include "prroi_pooling_gpu_impl.cuh" + + +at::Tensor prroi_pooling_forward_cuda(const at::Tensor &features, const at::Tensor &rois, int pooled_height, int pooled_width, float spatial_scale) { + int nr_rois = rois.size(0); + int nr_channels = features.size(1); + int height = features.size(2); + int width = features.size(3); + int top_count = nr_rois * nr_channels * pooled_height * pooled_width; + auto output = at::zeros({nr_rois, nr_channels, pooled_height, pooled_width}, features.options()); + + if (output.numel() == 0) { + THCudaCheck(cudaGetLastError()); + return output; + } + + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + PrRoIPoolingForwardGpu( + stream, features.data(), rois.data(), output.data(), + nr_channels, height, width, pooled_height, pooled_width, spatial_scale, + top_count + ); + + THCudaCheck(cudaGetLastError()); + return output; +} + +at::Tensor prroi_pooling_backward_cuda( + const at::Tensor &features, const at::Tensor &rois, const at::Tensor &output, const at::Tensor &output_diff, + int pooled_height, int pooled_width, float spatial_scale) { + + auto features_diff = at::zeros_like(features); + + int nr_rois = rois.size(0); + int batch_size = features.size(0); + int nr_channels = features.size(1); + int height = features.size(2); + int width = features.size(3); + int top_count = nr_rois * nr_channels * pooled_height * pooled_width; + int bottom_count = batch_size * nr_channels * height * width; + + if (output.numel() == 0) { + THCudaCheck(cudaGetLastError()); + return features_diff; + } + + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + PrRoIPoolingBackwardGpu( + stream, + features.data(), rois.data(), output.data(), output_diff.data(), + features_diff.data(), + nr_channels, height, width, pooled_height, pooled_width, spatial_scale, + top_count, bottom_count + ); + + THCudaCheck(cudaGetLastError()); + return features_diff; +} + +at::Tensor prroi_pooling_coor_backward_cuda( + const at::Tensor &features, const at::Tensor &rois, const at::Tensor &output, const at::Tensor &output_diff, + int pooled_height, int pooled_width, float spatial_scale) { + + auto coor_diff = at::zeros_like(rois); + + int nr_rois = rois.size(0); + int nr_channels = features.size(1); + int height = features.size(2); + int width = features.size(3); + int top_count = nr_rois * nr_channels * pooled_height * pooled_width; + int bottom_count = nr_rois * 5; + + if (output.numel() == 0) { + THCudaCheck(cudaGetLastError()); + return coor_diff; + } + + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + PrRoIPoolingCoorBackwardGpu( + stream, + features.data(), rois.data(), output.data(), output_diff.data(), + coor_diff.data(), + nr_channels, height, width, pooled_height, pooled_width, spatial_scale, + top_count, bottom_count + ); + + THCudaCheck(cudaGetLastError()); + return coor_diff; +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("prroi_pooling_forward_cuda", &prroi_pooling_forward_cuda, "PRRoIPooling_forward"); + m.def("prroi_pooling_backward_cuda", &prroi_pooling_backward_cuda, "PRRoIPooling_backward"); + m.def("prroi_pooling_coor_backward_cuda", &prroi_pooling_coor_backward_cuda, "PRRoIPooling_backward_coor"); +} diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.h b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.h new file mode 100755 index 0000000..bc9d351 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu.h @@ -0,0 +1,22 @@ +/* + * File : prroi_pooling_gpu.h + * Author : Jiayuan Mao, Tete Xiao + * Email : maojiayuan@gmail.com, jasonhsiao97@gmail.com + * Date : 07/13/2018 + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +int prroi_pooling_forward_cuda(THCudaTensor *features, THCudaTensor *rois, THCudaTensor *output, int pooled_height, int pooled_width, float spatial_scale); + +int prroi_pooling_backward_cuda( + THCudaTensor *features, THCudaTensor *rois, THCudaTensor *output, THCudaTensor *output_diff, THCudaTensor *features_diff, + int pooled_height, int pooled_width, float spatial_scale +); + +int prroi_pooling_coor_backward_cuda( + THCudaTensor *features, THCudaTensor *rois, THCudaTensor *output, THCudaTensor *output_diff, THCudaTensor *features_diff, + int pooled_height, int pooled_width, float spatial_scal +); + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cu b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cu new file mode 100755 index 0000000..452b020 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cu @@ -0,0 +1,443 @@ +/* + * File : prroi_pooling_gpu_impl.cu + * Author : Tete Xiao, Jiayuan Mao + * Email : jasonhsiao97@gmail.com + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +#include "prroi_pooling_gpu_impl.cuh" + +#include +#include + +#define CUDA_KERNEL_LOOP(i, n) \ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; \ + i < (n); \ + i += blockDim.x * gridDim.x) + +#define CUDA_POST_KERNEL_CHECK \ + do { \ + cudaError_t err = cudaGetLastError(); \ + if (cudaSuccess != err) { \ + fprintf(stderr, "cudaCheckError() failed : %s\n", cudaGetErrorString(err)); \ + exit(-1); \ + } \ + } while(0) + +#define CUDA_NUM_THREADS 512 + +namespace { + +static int CUDA_NUM_BLOCKS(const int N) { + return (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS; +} + +__device__ static float PrRoIPoolingGetData(F_DEVPTR_IN data, const int h, const int w, const int height, const int width) +{ + bool overflow = (h < 0) || (w < 0) || (h >= height) || (w >= width); + float retVal = overflow ? 0.0f : data[h * width + w]; + return retVal; +} + +__device__ static float PrRoIPoolingGetCoeff(float dh, float dw){ + dw = dw > 0 ? dw : -dw; + dh = dh > 0 ? dh : -dh; + return (1.0f - dh) * (1.0f - dw); +} + +__device__ static float PrRoIPoolingSingleCoorIntegral(float s, float t, float c1, float c2) { + return 0.5 * (t * t - s * s) * c2 + (t - 0.5 * t * t - s + 0.5 * s * s) * c1; +} + +__device__ static float PrRoIPoolingInterpolation(F_DEVPTR_IN data, const float h, const float w, const int height, const int width){ + float retVal = 0.0f; + int h1 = floorf(h); + int w1 = floorf(w); + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h)+1; + w1 = floorf(w); + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h); + w1 = floorf(w)+1; + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h)+1; + w1 = floorf(w)+1; + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + return retVal; +} + +__device__ static float PrRoIPoolingMatCalculation(F_DEVPTR_IN this_data, const int s_h, const int s_w, const int e_h, const int e_w, + const float y0, const float x0, const float y1, const float x1, const int h0, const int w0) +{ + float alpha, beta, lim_alpha, lim_beta, tmp; + float sum_out = 0; + + alpha = x0 - float(s_w); + beta = y0 - float(s_h); + lim_alpha = x1 - float(s_w); + lim_beta = y1 - float(s_h); + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, s_h, s_w, h0, w0) * tmp; + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, s_h, e_w, h0, w0) * tmp; + + alpha = x0 - float(s_w); + beta = float(e_h) - y1; + lim_alpha = x1 - float(s_w); + lim_beta = float(e_h) - y0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, e_h, s_w, h0, w0) * tmp; + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, e_h, e_w, h0, w0) * tmp; + + return sum_out; +} + +__device__ static void PrRoIPoolingDistributeDiff(F_DEVPTR_OUT diff, const float top_diff, const int h, const int w, const int height, const int width, const float coeff) +{ + bool overflow = (h < 0) || (w < 0) || (h >= height) || (w >= width); + if (!overflow) + atomicAdd(diff + h * width + w, top_diff * coeff); +} + +__device__ static void PrRoIPoolingMatDistributeDiff(F_DEVPTR_OUT diff, const float top_diff, const int s_h, const int s_w, const int e_h, const int e_w, + const float y0, const float x0, const float y1, const float x1, const int h0, const int w0) +{ + float alpha, beta, lim_alpha, lim_beta, tmp; + + alpha = x0 - float(s_w); + beta = y0 - float(s_h); + lim_alpha = x1 - float(s_w); + lim_beta = y1 - float(s_h); + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, s_h, s_w, h0, w0, tmp); + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, s_h, e_w, h0, w0, tmp); + + alpha = x0 - float(s_w); + beta = float(e_h) - y1; + lim_alpha = x1 - float(s_w); + lim_beta = float(e_h) - y0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, e_h, s_w, h0, w0, tmp); + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, e_h, e_w, h0, w0, tmp); +} + +__global__ void PrRoIPoolingForward( + const int nthreads, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + + bottom_rois += n * 5; + int roi_batch_ind = bottom_rois[0]; + + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, ((float)0.0)); + float roi_height = max(roi_end_h - roi_start_h, ((float)0.0)); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_data = bottom_data + (roi_batch_ind * channels + c) * height * width; + float *this_out = top_data + index; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + if (win_size == 0) { + *this_out = 0; + return; + } + + float sum_out = 0; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) + for (int h_iter = s_h; h_iter < e_h; ++h_iter) + sum_out += PrRoIPoolingMatCalculation(this_data, h_iter, w_iter, h_iter + 1, w_iter + 1, + max(win_start_h, float(h_iter)), max(win_start_w, float(w_iter)), + min(win_end_h, float(h_iter) + 1.0), min(win_end_w, float(w_iter + 1.0)), + height, width); + *this_out = sum_out / win_size; + } +} + +__global__ void PrRoIPoolingBackward( + const int nthreads, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + bottom_rois += n * 5; + + int roi_batch_ind = bottom_rois[0]; + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, (float)0); + float roi_height = max(roi_end_h - roi_start_h, (float)0); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_out_grad = top_diff + index; + float *this_data_grad = bottom_diff + (roi_batch_ind * channels + c) * height * width; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + + float sum_out = win_size == float(0) ? float(0) : *this_out_grad / win_size; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) + for (int h_iter = s_h; h_iter < e_h; ++h_iter) + PrRoIPoolingMatDistributeDiff(this_data_grad, sum_out, h_iter, w_iter, h_iter + 1, w_iter + 1, + max(win_start_h, float(h_iter)), max(win_start_w, float(w_iter)), + min(win_end_h, float(h_iter) + 1.0), min(win_end_w, float(w_iter + 1.0)), + height, width); + + } +} + +__global__ void PrRoIPoolingCoorBackward( + const int nthreads, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + bottom_rois += n * 5; + + int roi_batch_ind = bottom_rois[0]; + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, (float)0); + float roi_height = max(roi_end_h - roi_start_h, (float)0); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_out_grad = top_diff + index; + const float *this_bottom_data = bottom_data + (roi_batch_ind * channels + c) * height * width; + const float *this_top_data = top_data + index; + float *this_data_grad = bottom_diff + n * 5; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + + float sum_out = win_size == float(0) ? float(0) : *this_out_grad / win_size; + + // WARNING: to be discussed + if (sum_out == 0) + return; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + float g_x1_y = 0, g_x2_y = 0, g_x_y1 = 0, g_x_y2 = 0; + for (int h_iter = s_h; h_iter < e_h; ++h_iter) { + g_x1_y += PrRoIPoolingSingleCoorIntegral(max(win_start_h, float(h_iter)) - h_iter, + min(win_end_h, float(h_iter + 1)) - h_iter, + PrRoIPoolingInterpolation(this_bottom_data, h_iter, win_start_w, height, width), + PrRoIPoolingInterpolation(this_bottom_data, h_iter + 1, win_start_w, height, width)); + + g_x2_y += PrRoIPoolingSingleCoorIntegral(max(win_start_h, float(h_iter)) - h_iter, + min(win_end_h, float(h_iter + 1)) - h_iter, + PrRoIPoolingInterpolation(this_bottom_data, h_iter, win_end_w, height, width), + PrRoIPoolingInterpolation(this_bottom_data, h_iter + 1, win_end_w, height, width)); + } + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) { + g_x_y1 += PrRoIPoolingSingleCoorIntegral(max(win_start_w, float(w_iter)) - w_iter, + min(win_end_w, float(w_iter + 1)) - w_iter, + PrRoIPoolingInterpolation(this_bottom_data, win_start_h, w_iter, height, width), + PrRoIPoolingInterpolation(this_bottom_data, win_start_h, w_iter + 1, height, width)); + + g_x_y2 += PrRoIPoolingSingleCoorIntegral(max(win_start_w, float(w_iter)) - w_iter, + min(win_end_w, float(w_iter + 1)) - w_iter, + PrRoIPoolingInterpolation(this_bottom_data, win_end_h, w_iter, height, width), + PrRoIPoolingInterpolation(this_bottom_data, win_end_h, w_iter + 1, height, width)); + } + + float partial_x1 = -g_x1_y + (win_end_h - win_start_h) * (*this_top_data); + float partial_y1 = -g_x_y1 + (win_end_w - win_start_w) * (*this_top_data); + float partial_x2 = g_x2_y - (win_end_h - win_start_h) * (*this_top_data); + float partial_y2 = g_x_y2 - (win_end_w - win_start_w) * (*this_top_data); + + partial_x1 = partial_x1 / win_size * spatial_scale; + partial_x2 = partial_x2 / win_size * spatial_scale; + partial_y1 = partial_y1 / win_size * spatial_scale; + partial_y2 = partial_y2 / win_size * spatial_scale; + + // (b, x1, y1, x2, y2) + + this_data_grad[0] = 0; + atomicAdd(this_data_grad + 1, (partial_x1 * (1.0 - float(pw) / pooled_width) + partial_x2 * (1.0 - float(pw + 1) / pooled_width)) + * (*this_out_grad)); + atomicAdd(this_data_grad + 2, (partial_y1 * (1.0 - float(ph) / pooled_height) + partial_y2 * (1.0 - float(ph + 1) / pooled_height)) + * (*this_out_grad)); + atomicAdd(this_data_grad + 3, (partial_x2 * float(pw + 1) / pooled_width + partial_x1 * float(pw) / pooled_width) + * (*this_out_grad)); + atomicAdd(this_data_grad + 4, (partial_y2 * float(ph + 1) / pooled_height + partial_y1 * float(ph) / pooled_height) + * (*this_out_grad)); + } +} + +} /* !anonymous namespace */ + +#ifdef __cplusplus +extern "C" { +#endif + +void PrRoIPoolingForwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count) { + + PrRoIPoolingForward<<>>( + top_count, bottom_data, bottom_rois, top_data, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + + CUDA_POST_KERNEL_CHECK; +} + +void PrRoIPoolingBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count) { + + cudaMemsetAsync(bottom_diff, 0, sizeof(float) * bottom_count, stream); + PrRoIPoolingBackward<<>>( + top_count, bottom_rois, top_diff, bottom_diff, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + CUDA_POST_KERNEL_CHECK; +} + +void PrRoIPoolingCoorBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count) { + + cudaMemsetAsync(bottom_diff, 0, sizeof(float) * bottom_count, stream); + PrRoIPoolingCoorBackward<<>>( + top_count, bottom_data, bottom_rois, top_data, top_diff, bottom_diff, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + CUDA_POST_KERNEL_CHECK; +} + +} /* !extern "C" */ + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cuh b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cuh new file mode 100755 index 0000000..95ad567 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/src/prroi_pooling_gpu_impl.cuh @@ -0,0 +1,59 @@ +/* + * File : prroi_pooling_gpu_impl.cuh + * Author : Tete Xiao, Jiayuan Mao + * Email : jasonhsiao97@gmail.com + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +#ifndef PRROI_POOLING_GPU_IMPL_CUH +#define PRROI_POOLING_GPU_IMPL_CUH + +#ifdef __cplusplus +extern "C" { +#endif + +#define F_DEVPTR_IN const float * +#define F_DEVPTR_OUT float * + +void PrRoIPoolingForwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count); + +void PrRoIPoolingBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count); + +void PrRoIPoolingCoorBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count); + +#ifdef __cplusplus +} /* !extern "C" */ +#endif + +#endif /* !PRROI_POOLING_GPU_IMPL_CUH */ + diff --git a/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/travis.sh b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/travis.sh new file mode 100755 index 0000000..4d50d12 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/prroi_pool/travis.sh @@ -0,0 +1,18 @@ +#! /bin/bash -e +# File : travis.sh +# Author : Jiayuan Mao +# Email : maojiayuan@gmail.com +# +# Distributed under terms of the MIT license. +# Copyright (c) 2017 Megvii Technology Limited. + +cd src +echo "Working directory: " `pwd` +echo "Compiling prroi_pooling kernels by nvcc..." +nvcc -c -o prroi_pooling_gpu_impl.cu.o prroi_pooling_gpu_impl.cu -x cu -Xcompiler -fPIC -arch=sm_52 + +cd ../ +echo "Working directory: " `pwd` +echo "Building python libraries..." +python3 build.py + diff --git a/ltr/external/PreciseRoIPooling/pytorch/tests/test_prroi_pooling2d.py b/ltr/external/PreciseRoIPooling/pytorch/tests/test_prroi_pooling2d.py new file mode 100755 index 0000000..a29d92c --- /dev/null +++ b/ltr/external/PreciseRoIPooling/pytorch/tests/test_prroi_pooling2d.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# File : test_prroi_pooling2d.py +# Author : Jiayuan Mao +# Email : maojiayuan@gmail.com +# Date : 18/02/2018 +# +# This file is part of Jacinle. + +import unittest + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from jactorch.utils.unittest import TorchTestCase + +from prroi_pool import PrRoIPool2D + + +class TestPrRoIPool2D(TorchTestCase): + def test_forward(self): + pool = PrRoIPool2D(7, 7, spatial_scale=0.5) + features = torch.rand((4, 16, 24, 32)).cuda() + rois = torch.tensor([ + [0, 0, 0, 14, 14], + [1, 14, 14, 28, 28], + ]).float().cuda() + + out = pool(features, rois) + out_gold = F.avg_pool2d(features, kernel_size=2, stride=1) + + self.assertTensorClose(out, torch.stack(( + out_gold[0, :, :7, :7], + out_gold[1, :, 7:14, 7:14], + ), dim=0)) + + def test_backward_shapeonly(self): + pool = PrRoIPool2D(2, 2, spatial_scale=0.5) + + features = torch.rand((4, 2, 24, 32)).cuda() + rois = torch.tensor([ + [0, 0, 0, 4, 4], + [1, 14, 14, 18, 18], + ]).float().cuda() + features.requires_grad = rois.requires_grad = True + out = pool(features, rois) + + loss = out.sum() + loss.backward() + + self.assertTupleEqual(features.size(), features.grad.size()) + self.assertTupleEqual(rois.size(), rois.grad.size()) + + +if __name__ == '__main__': + unittest.main() diff --git a/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cu b/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cu new file mode 100755 index 0000000..452b020 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cu @@ -0,0 +1,443 @@ +/* + * File : prroi_pooling_gpu_impl.cu + * Author : Tete Xiao, Jiayuan Mao + * Email : jasonhsiao97@gmail.com + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +#include "prroi_pooling_gpu_impl.cuh" + +#include +#include + +#define CUDA_KERNEL_LOOP(i, n) \ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; \ + i < (n); \ + i += blockDim.x * gridDim.x) + +#define CUDA_POST_KERNEL_CHECK \ + do { \ + cudaError_t err = cudaGetLastError(); \ + if (cudaSuccess != err) { \ + fprintf(stderr, "cudaCheckError() failed : %s\n", cudaGetErrorString(err)); \ + exit(-1); \ + } \ + } while(0) + +#define CUDA_NUM_THREADS 512 + +namespace { + +static int CUDA_NUM_BLOCKS(const int N) { + return (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS; +} + +__device__ static float PrRoIPoolingGetData(F_DEVPTR_IN data, const int h, const int w, const int height, const int width) +{ + bool overflow = (h < 0) || (w < 0) || (h >= height) || (w >= width); + float retVal = overflow ? 0.0f : data[h * width + w]; + return retVal; +} + +__device__ static float PrRoIPoolingGetCoeff(float dh, float dw){ + dw = dw > 0 ? dw : -dw; + dh = dh > 0 ? dh : -dh; + return (1.0f - dh) * (1.0f - dw); +} + +__device__ static float PrRoIPoolingSingleCoorIntegral(float s, float t, float c1, float c2) { + return 0.5 * (t * t - s * s) * c2 + (t - 0.5 * t * t - s + 0.5 * s * s) * c1; +} + +__device__ static float PrRoIPoolingInterpolation(F_DEVPTR_IN data, const float h, const float w, const int height, const int width){ + float retVal = 0.0f; + int h1 = floorf(h); + int w1 = floorf(w); + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h)+1; + w1 = floorf(w); + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h); + w1 = floorf(w)+1; + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + h1 = floorf(h)+1; + w1 = floorf(w)+1; + retVal += PrRoIPoolingGetData(data, h1, w1, height, width) * PrRoIPoolingGetCoeff(h - float(h1), w - float(w1)); + return retVal; +} + +__device__ static float PrRoIPoolingMatCalculation(F_DEVPTR_IN this_data, const int s_h, const int s_w, const int e_h, const int e_w, + const float y0, const float x0, const float y1, const float x1, const int h0, const int w0) +{ + float alpha, beta, lim_alpha, lim_beta, tmp; + float sum_out = 0; + + alpha = x0 - float(s_w); + beta = y0 - float(s_h); + lim_alpha = x1 - float(s_w); + lim_beta = y1 - float(s_h); + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, s_h, s_w, h0, w0) * tmp; + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, s_h, e_w, h0, w0) * tmp; + + alpha = x0 - float(s_w); + beta = float(e_h) - y1; + lim_alpha = x1 - float(s_w); + lim_beta = float(e_h) - y0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, e_h, s_w, h0, w0) * tmp; + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + sum_out += PrRoIPoolingGetData(this_data, e_h, e_w, h0, w0) * tmp; + + return sum_out; +} + +__device__ static void PrRoIPoolingDistributeDiff(F_DEVPTR_OUT diff, const float top_diff, const int h, const int w, const int height, const int width, const float coeff) +{ + bool overflow = (h < 0) || (w < 0) || (h >= height) || (w >= width); + if (!overflow) + atomicAdd(diff + h * width + w, top_diff * coeff); +} + +__device__ static void PrRoIPoolingMatDistributeDiff(F_DEVPTR_OUT diff, const float top_diff, const int s_h, const int s_w, const int e_h, const int e_w, + const float y0, const float x0, const float y1, const float x1, const int h0, const int w0) +{ + float alpha, beta, lim_alpha, lim_beta, tmp; + + alpha = x0 - float(s_w); + beta = y0 - float(s_h); + lim_alpha = x1 - float(s_w); + lim_beta = y1 - float(s_h); + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, s_h, s_w, h0, w0, tmp); + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, s_h, e_w, h0, w0, tmp); + + alpha = x0 - float(s_w); + beta = float(e_h) - y1; + lim_alpha = x1 - float(s_w); + lim_beta = float(e_h) - y0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, e_h, s_w, h0, w0, tmp); + + alpha = float(e_w) - x1; + lim_alpha = float(e_w) - x0; + tmp = (lim_alpha - 0.5f * lim_alpha * lim_alpha - alpha + 0.5f * alpha * alpha) + * (lim_beta - 0.5f * lim_beta * lim_beta - beta + 0.5f * beta * beta); + PrRoIPoolingDistributeDiff(diff, top_diff, e_h, e_w, h0, w0, tmp); +} + +__global__ void PrRoIPoolingForward( + const int nthreads, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + + bottom_rois += n * 5; + int roi_batch_ind = bottom_rois[0]; + + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, ((float)0.0)); + float roi_height = max(roi_end_h - roi_start_h, ((float)0.0)); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_data = bottom_data + (roi_batch_ind * channels + c) * height * width; + float *this_out = top_data + index; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + if (win_size == 0) { + *this_out = 0; + return; + } + + float sum_out = 0; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) + for (int h_iter = s_h; h_iter < e_h; ++h_iter) + sum_out += PrRoIPoolingMatCalculation(this_data, h_iter, w_iter, h_iter + 1, w_iter + 1, + max(win_start_h, float(h_iter)), max(win_start_w, float(w_iter)), + min(win_end_h, float(h_iter) + 1.0), min(win_end_w, float(w_iter + 1.0)), + height, width); + *this_out = sum_out / win_size; + } +} + +__global__ void PrRoIPoolingBackward( + const int nthreads, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + bottom_rois += n * 5; + + int roi_batch_ind = bottom_rois[0]; + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, (float)0); + float roi_height = max(roi_end_h - roi_start_h, (float)0); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_out_grad = top_diff + index; + float *this_data_grad = bottom_diff + (roi_batch_ind * channels + c) * height * width; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + + float sum_out = win_size == float(0) ? float(0) : *this_out_grad / win_size; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) + for (int h_iter = s_h; h_iter < e_h; ++h_iter) + PrRoIPoolingMatDistributeDiff(this_data_grad, sum_out, h_iter, w_iter, h_iter + 1, w_iter + 1, + max(win_start_h, float(h_iter)), max(win_start_w, float(w_iter)), + min(win_end_h, float(h_iter) + 1.0), min(win_end_w, float(w_iter + 1.0)), + height, width); + + } +} + +__global__ void PrRoIPoolingCoorBackward( + const int nthreads, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels, + const int height, + const int width, + const int pooled_height, + const int pooled_width, + const float spatial_scale) { + + CUDA_KERNEL_LOOP(index, nthreads) { + // (n, c, ph, pw) is an element in the pooled output + int pw = index % pooled_width; + int ph = (index / pooled_width) % pooled_height; + int c = (index / pooled_width / pooled_height) % channels; + int n = index / pooled_width / pooled_height / channels; + bottom_rois += n * 5; + + int roi_batch_ind = bottom_rois[0]; + float roi_start_w = bottom_rois[1] * spatial_scale; + float roi_start_h = bottom_rois[2] * spatial_scale; + float roi_end_w = bottom_rois[3] * spatial_scale; + float roi_end_h = bottom_rois[4] * spatial_scale; + + float roi_width = max(roi_end_w - roi_start_w, (float)0); + float roi_height = max(roi_end_h - roi_start_h, (float)0); + float bin_size_h = roi_height / static_cast(pooled_height); + float bin_size_w = roi_width / static_cast(pooled_width); + + const float *this_out_grad = top_diff + index; + const float *this_bottom_data = bottom_data + (roi_batch_ind * channels + c) * height * width; + const float *this_top_data = top_data + index; + float *this_data_grad = bottom_diff + n * 5; + + float win_start_w = roi_start_w + bin_size_w * pw; + float win_start_h = roi_start_h + bin_size_h * ph; + float win_end_w = win_start_w + bin_size_w; + float win_end_h = win_start_h + bin_size_h; + + float win_size = max(float(0.0), bin_size_w * bin_size_h); + + float sum_out = win_size == float(0) ? float(0) : *this_out_grad / win_size; + + // WARNING: to be discussed + if (sum_out == 0) + return; + + int s_w, s_h, e_w, e_h; + + s_w = floorf(win_start_w); + e_w = ceilf(win_end_w); + s_h = floorf(win_start_h); + e_h = ceilf(win_end_h); + + float g_x1_y = 0, g_x2_y = 0, g_x_y1 = 0, g_x_y2 = 0; + for (int h_iter = s_h; h_iter < e_h; ++h_iter) { + g_x1_y += PrRoIPoolingSingleCoorIntegral(max(win_start_h, float(h_iter)) - h_iter, + min(win_end_h, float(h_iter + 1)) - h_iter, + PrRoIPoolingInterpolation(this_bottom_data, h_iter, win_start_w, height, width), + PrRoIPoolingInterpolation(this_bottom_data, h_iter + 1, win_start_w, height, width)); + + g_x2_y += PrRoIPoolingSingleCoorIntegral(max(win_start_h, float(h_iter)) - h_iter, + min(win_end_h, float(h_iter + 1)) - h_iter, + PrRoIPoolingInterpolation(this_bottom_data, h_iter, win_end_w, height, width), + PrRoIPoolingInterpolation(this_bottom_data, h_iter + 1, win_end_w, height, width)); + } + + for (int w_iter = s_w; w_iter < e_w; ++w_iter) { + g_x_y1 += PrRoIPoolingSingleCoorIntegral(max(win_start_w, float(w_iter)) - w_iter, + min(win_end_w, float(w_iter + 1)) - w_iter, + PrRoIPoolingInterpolation(this_bottom_data, win_start_h, w_iter, height, width), + PrRoIPoolingInterpolation(this_bottom_data, win_start_h, w_iter + 1, height, width)); + + g_x_y2 += PrRoIPoolingSingleCoorIntegral(max(win_start_w, float(w_iter)) - w_iter, + min(win_end_w, float(w_iter + 1)) - w_iter, + PrRoIPoolingInterpolation(this_bottom_data, win_end_h, w_iter, height, width), + PrRoIPoolingInterpolation(this_bottom_data, win_end_h, w_iter + 1, height, width)); + } + + float partial_x1 = -g_x1_y + (win_end_h - win_start_h) * (*this_top_data); + float partial_y1 = -g_x_y1 + (win_end_w - win_start_w) * (*this_top_data); + float partial_x2 = g_x2_y - (win_end_h - win_start_h) * (*this_top_data); + float partial_y2 = g_x_y2 - (win_end_w - win_start_w) * (*this_top_data); + + partial_x1 = partial_x1 / win_size * spatial_scale; + partial_x2 = partial_x2 / win_size * spatial_scale; + partial_y1 = partial_y1 / win_size * spatial_scale; + partial_y2 = partial_y2 / win_size * spatial_scale; + + // (b, x1, y1, x2, y2) + + this_data_grad[0] = 0; + atomicAdd(this_data_grad + 1, (partial_x1 * (1.0 - float(pw) / pooled_width) + partial_x2 * (1.0 - float(pw + 1) / pooled_width)) + * (*this_out_grad)); + atomicAdd(this_data_grad + 2, (partial_y1 * (1.0 - float(ph) / pooled_height) + partial_y2 * (1.0 - float(ph + 1) / pooled_height)) + * (*this_out_grad)); + atomicAdd(this_data_grad + 3, (partial_x2 * float(pw + 1) / pooled_width + partial_x1 * float(pw) / pooled_width) + * (*this_out_grad)); + atomicAdd(this_data_grad + 4, (partial_y2 * float(ph + 1) / pooled_height + partial_y1 * float(ph) / pooled_height) + * (*this_out_grad)); + } +} + +} /* !anonymous namespace */ + +#ifdef __cplusplus +extern "C" { +#endif + +void PrRoIPoolingForwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count) { + + PrRoIPoolingForward<<>>( + top_count, bottom_data, bottom_rois, top_data, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + + CUDA_POST_KERNEL_CHECK; +} + +void PrRoIPoolingBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count) { + + cudaMemsetAsync(bottom_diff, 0, sizeof(float) * bottom_count, stream); + PrRoIPoolingBackward<<>>( + top_count, bottom_rois, top_diff, bottom_diff, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + CUDA_POST_KERNEL_CHECK; +} + +void PrRoIPoolingCoorBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count) { + + cudaMemsetAsync(bottom_diff, 0, sizeof(float) * bottom_count, stream); + PrRoIPoolingCoorBackward<<>>( + top_count, bottom_data, bottom_rois, top_data, top_diff, bottom_diff, + channels_, height_, width_, pooled_height_, pooled_width_, spatial_scale_); + CUDA_POST_KERNEL_CHECK; +} + +} /* !extern "C" */ + diff --git a/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cuh b/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cuh new file mode 100755 index 0000000..95ad567 --- /dev/null +++ b/ltr/external/PreciseRoIPooling/src/prroi_pooling_gpu_impl.cuh @@ -0,0 +1,59 @@ +/* + * File : prroi_pooling_gpu_impl.cuh + * Author : Tete Xiao, Jiayuan Mao + * Email : jasonhsiao97@gmail.com + * + * Distributed under terms of the MIT license. + * Copyright (c) 2017 Megvii Technology Limited. + */ + +#ifndef PRROI_POOLING_GPU_IMPL_CUH +#define PRROI_POOLING_GPU_IMPL_CUH + +#ifdef __cplusplus +extern "C" { +#endif + +#define F_DEVPTR_IN const float * +#define F_DEVPTR_OUT float * + +void PrRoIPoolingForwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_OUT top_data, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count); + +void PrRoIPoolingBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count); + +void PrRoIPoolingCoorBackwardGpu( + cudaStream_t stream, + F_DEVPTR_IN bottom_data, + F_DEVPTR_IN bottom_rois, + F_DEVPTR_IN top_data, + F_DEVPTR_IN top_diff, + F_DEVPTR_OUT bottom_diff, + const int channels_, const int height_, const int width_, + const int pooled_height_, const int pooled_width_, + const float spatial_scale_, + const int top_count, const int bottom_count); + +#ifdef __cplusplus +} /* !extern "C" */ +#endif + +#endif /* !PRROI_POOLING_GPU_IMPL_CUH */ + diff --git a/ltr/models/__init__.py b/ltr/models/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/models/__pycache__/__init__.cpython-37.pyc b/ltr/models/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..9d560f5 Binary files /dev/null and b/ltr/models/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/backbone/__init__.py b/ltr/models/backbone/__init__.py new file mode 100755 index 0000000..11e398e --- /dev/null +++ b/ltr/models/backbone/__init__.py @@ -0,0 +1,2 @@ +from .resnet import resnet18, resnet50, resnet_baby +from .resnet18_vggm import resnet18_vggmconv1 diff --git a/ltr/models/backbone/__pycache__/__init__.cpython-37.pyc b/ltr/models/backbone/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..1efc80c Binary files /dev/null and b/ltr/models/backbone/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/backbone/__pycache__/base.cpython-37.pyc b/ltr/models/backbone/__pycache__/base.cpython-37.pyc new file mode 100755 index 0000000..1697ca4 Binary files /dev/null and b/ltr/models/backbone/__pycache__/base.cpython-37.pyc differ diff --git a/ltr/models/backbone/__pycache__/resnet.cpython-37.pyc b/ltr/models/backbone/__pycache__/resnet.cpython-37.pyc new file mode 100755 index 0000000..3135ac6 Binary files /dev/null and b/ltr/models/backbone/__pycache__/resnet.cpython-37.pyc differ diff --git a/ltr/models/backbone/__pycache__/resnet18_vggm.cpython-37.pyc b/ltr/models/backbone/__pycache__/resnet18_vggm.cpython-37.pyc new file mode 100755 index 0000000..d6c16b6 Binary files /dev/null and b/ltr/models/backbone/__pycache__/resnet18_vggm.cpython-37.pyc differ diff --git a/ltr/models/backbone/base.py b/ltr/models/backbone/base.py new file mode 100755 index 0000000..0964da8 --- /dev/null +++ b/ltr/models/backbone/base.py @@ -0,0 +1,47 @@ +import torch +import torch.nn as nn + + +class Backbone(nn.Module): + """Base class for backbone networks. Handles freezing layers etc. + args: + frozen_layers - Name of layers to freeze. Either list of strings, 'none' or 'all'. Default: 'none'. + """ + def __init__(self, frozen_layers=()): + super().__init__() + + if isinstance(frozen_layers, str): + if frozen_layers.lower() == 'none': + frozen_layers = () + elif frozen_layers.lower() != 'all': + raise ValueError('Unknown option for frozen layers: \"{}\". Should be \"all\", \"none\" or list of layer names.'.format(frozen_layers)) + + self.frozen_layers = frozen_layers + self._is_frozen_nograd = False + + + def train(self, mode=True): + super().train(mode) + if mode == True: + self._set_frozen_to_eval() + if not self._is_frozen_nograd: + self._set_frozen_to_nograd() + self._is_frozen_nograd = True + + + def _set_frozen_to_eval(self): + if isinstance(self.frozen_layers, str) and self.frozen_layers.lower() == 'all': + self.eval() + else: + for layer in self.frozen_layers: + getattr(self, layer).eval() + + + def _set_frozen_to_nograd(self): + if isinstance(self.frozen_layers, str) and self.frozen_layers.lower() == 'all': + for p in self.parameters(): + p.requires_grad_(False) + else: + for layer in self.frozen_layers: + for p in getattr(self, layer).parameters(): + p.requires_grad_(False) \ No newline at end of file diff --git a/ltr/models/backbone/mobilenetv3.py b/ltr/models/backbone/mobilenetv3.py new file mode 100755 index 0000000..faffdb6 --- /dev/null +++ b/ltr/models/backbone/mobilenetv3.py @@ -0,0 +1,322 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from collections import OrderedDict + + +def get_model_parameters(model): + total_parameters = 0 + for layer in list(model.parameters()): + layer_parameter = 1 + for l in list(layer.size()): + layer_parameter *= l + total_parameters += layer_parameter + return total_parameters + + +def _weights_init(m): + if isinstance(m, nn.Conv2d): + torch.nn.init.xavier_uniform_(m.weight) + if m.bias is not None: + torch.nn.init.zeros_(m.bias) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + elif isinstance(m, nn.Linear): + n = m.weight.size(1) + m.weight.data.normal_(0, 0.01) + m.bias.data.zero_() + + +class h_sigmoid(nn.Module): + def __init__(self, inplace=True): + super(h_sigmoid, self).__init__() + self.inplace = inplace + + def forward(self, x): + return F.relu6(x + 3., inplace=self.inplace) / 6. + + +class h_swish(nn.Module): + def __init__(self, inplace=True): + super(h_swish, self).__init__() + self.inplace = inplace + + def forward(self, x): + out = F.relu6(x + 3., self.inplace) / 6. + return out * x + + +def _make_divisible(v, divisor=8, min_value=None): + if min_value is None: + min_value = divisor + new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) + # Make sure that round down does not go down by more than 10%. + if new_v < 0.9 * v: + new_v += divisor + return new_v + + +class SqueezeBlock(nn.Module): + def __init__(self, exp_size, divide=4): + super(SqueezeBlock, self).__init__() + self.dense = nn.Sequential( + nn.Linear(exp_size, exp_size // divide), + nn.ReLU(inplace=True), + nn.Linear(exp_size // divide, exp_size), + h_sigmoid() + ) + + def forward(self, x): + batch, channels, height, width = x.size() + out = F.avg_pool2d(x, kernel_size=[height, width]).view(batch, -1) + out = self.dense(out) + out = out.view(batch, channels, 1, 1) + # out = hard_sigmoid(out) + + return out * x + + +class MobileBlock(nn.Module): + def __init__(self, in_channels, out_channels, kernal_size, stride, nonLinear, SE, exp_size): + super(MobileBlock, self).__init__() + self.out_channels = out_channels + self.nonLinear = nonLinear + self.SE = SE + padding = (kernal_size - 1) // 2 + + self.use_connect = stride == 1 and in_channels == out_channels + + if self.nonLinear == "RE": + activation = nn.ReLU + else: + activation = h_swish + + self.conv = nn.Sequential( + nn.Conv2d(in_channels, exp_size, kernel_size=1, stride=1, padding=0, bias=False), + nn.BatchNorm2d(exp_size), + activation(inplace=True) + ) + self.depth_conv = nn.Sequential( + nn.Conv2d(exp_size, exp_size, kernel_size=kernal_size, stride=stride, padding=padding, groups=exp_size), + nn.BatchNorm2d(exp_size), + ) + + if self.SE: + self.squeeze_block = SqueezeBlock(exp_size) + + self.point_conv = nn.Sequential( + nn.Conv2d(exp_size, out_channels, kernel_size=1, stride=1, padding=0), + nn.BatchNorm2d(out_channels), + activation(inplace=True) + ) + + def forward(self, x): + # MobileNetV2 + out = self.conv(x) + out = self.depth_conv(out) + + # Squeeze and Excite + if self.SE: + out = self.squeeze_block(out) + + # point-wise conv + out = self.point_conv(out) + + # connection + if self.use_connect: + return x + out + else: + return out + + +class MobileNetV3(nn.Module): + def __init__(self, model_mode="LARGE", num_classes=1000, multiplier=1.0, dropout_rate=0.0, output_layers=['default']): + super(MobileNetV3, self).__init__() + self.num_classes = num_classes + self.output_layers = output_layers + if model_mode == "LARGE": + layers = [ + [16, 16, 3, 1, "RE", False, 16], + [16, 24, 3, 2, "RE", False, 64], + [24, 24, 3, 1, "RE", False, 72], + [24, 40, 5, 2, "RE", True, 72], + [40, 40, 5, 1, "RE", True, 120], + + [40, 40, 5, 1, "RE", True, 120], + [40, 80, 3, 2, "HS", False, 240], + [80, 80, 3, 1, "HS", False, 200], + [80, 80, 3, 1, "HS", False, 184], + [80, 80, 3, 1, "HS", False, 184], + + [80, 112, 3, 1, "HS", True, 480], + [112, 112, 3, 1, "HS", True, 672], + [112, 160, 5, 1, "HS", True, 672], + [160, 160, 5, 2, "HS", True, 672], + [160, 160, 5, 1, "HS", True, 960], + ] + init_conv_out = _make_divisible(16 * multiplier) + self.init_conv = nn.Sequential( + nn.Conv2d(in_channels=3, out_channels=init_conv_out, kernel_size=3, stride=2, padding=1), + nn.BatchNorm2d(init_conv_out), + h_swish(inplace=True), + ) + self.layer1 = MobileBlock(16, 16, 3, 1, "RE", False, 16) + self.layer2 = nn.Sequential( + MobileBlock(16, 24, 3, 2, "RE", False, 64), + MobileBlock(24, 24, 3, 1, "RE", False, 72) + ) + self.layer3 = nn.Sequential( + MobileBlock(24, 40, 5, 2, "RE", True, 72), + MobileBlock(40, 40, 5, 1, "RE", True, 120), + MobileBlock(40, 40, 5, 1, "RE", True, 120) + ) + self.layer4 = nn.Sequential( + MobileBlock(40, 80, 3, 2, "HS", False, 240), + MobileBlock(80, 80, 3, 1, "HS", False, 200), + MobileBlock(80, 80, 3, 1, "HS", False, 184), + MobileBlock(80, 80, 3, 1, "HS", False, 184) + ) + self.layer5 = nn.Sequential( + MobileBlock(80, 112, 3, 1, "HS", True, 480), + MobileBlock(112, 112, 3, 1, "HS", True, 672) + ) + self.layer6 = nn.Sequential( + MobileBlock(112, 160, 5, 1, "HS", True, 672), + MobileBlock(160, 160, 5, 2, "HS", True, 672), + MobileBlock(160, 160, 5, 1, "HS", True, 960) + ) + + out_conv1_in = _make_divisible(160 * multiplier) + out_conv1_out = _make_divisible(960 * multiplier) + self.out_conv1 = nn.Sequential( + nn.Conv2d(out_conv1_in, out_conv1_out, kernel_size=1, stride=1), + nn.BatchNorm2d(out_conv1_out), + h_swish(inplace=True), + ) + + out_conv2_in = _make_divisible(960 * multiplier) + out_conv2_out = _make_divisible(1280 * multiplier) + self.out_conv2 = nn.Sequential( + nn.Conv2d(out_conv2_in, out_conv2_out, kernel_size=1, stride=1), + h_swish(inplace=True), + nn.Dropout(dropout_rate), + nn.Conv2d(out_conv2_out, self.num_classes, kernel_size=1, stride=1), + ) + + elif model_mode == "SMALL": + layers = [ + [16, 16, 3, 2, "RE", True, 16], + [16, 24, 3, 2, "RE", False, 72], + [24, 24, 3, 1, "RE", False, 88], + [24, 40, 5, 2, "RE", True, 96], + [40, 40, 5, 1, "RE", True, 240], + [40, 40, 5, 1, "RE", True, 240], + [40, 48, 5, 1, "HS", True, 120], + [48, 48, 5, 1, "HS", True, 144], + [48, 96, 5, 2, "HS", True, 288], + [96, 96, 5, 1, "HS", True, 576], + [96, 96, 5, 1, "HS", True, 576], + ] + + init_conv_out = _make_divisible(16 * multiplier) + self.init_conv = nn.Sequential( + nn.Conv2d(in_channels=3, out_channels=init_conv_out, kernel_size=3, stride=2, padding=1), + nn.BatchNorm2d(init_conv_out), + h_swish(inplace=True), + ) + + self.block = [] + for in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size in layers: + in_channels = _make_divisible(in_channels * multiplier) + out_channels = _make_divisible(out_channels * multiplier) + exp_size = _make_divisible(exp_size * multiplier) + self.block.append(MobileBlock(in_channels, out_channels, kernal_size, stride, nonlinear, se, exp_size)) + # self.block = nn.Sequential(*self.block) + + out_conv1_in = _make_divisible(96 * multiplier) + out_conv1_out = _make_divisible(576 * multiplier) + self.out_conv1 = nn.Sequential( + nn.Conv2d(out_conv1_in, out_conv1_out, kernel_size=1, stride=1), + SqueezeBlock(out_conv1_out), + nn.BatchNorm2d(out_conv1_out), + h_swish(inplace=True), + ) + + out_conv2_in = _make_divisible(576 * multiplier) + out_conv2_out = _make_divisible(1280 * multiplier) + self.out_conv2 = nn.Sequential( + nn.Conv2d(out_conv2_in, out_conv2_out, kernel_size=1, stride=1), + h_swish(inplace=True), + nn.Dropout(dropout_rate), + nn.Conv2d(out_conv2_out, self.num_classes, kernel_size=1, stride=1), + ) + + self.apply(_weights_init) + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + def forward(self, x, output_layers=None): + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + + out = self.init_conv(x) + if self._add_output_and_check('init_conv', out, outputs, output_layers): + return outputs + #out = self.block(out) + out = self.layer1(out) + if self._add_output_and_check('layer1', out, outputs, output_layers): + return outputs + out = self.layer2(out) + if self._add_output_and_check('layer2', out, outputs, output_layers): + return outputs + out = self.layer3(out) + if self._add_output_and_check('layer3', out, outputs, output_layers): + return outputs + out = self.layer4(out) + if self._add_output_and_check('layer4', out, outputs, output_layers): + return outputs + out = self.layer5(out) + if self._add_output_and_check('layer5', out, outputs, output_layers): + return outputs + out = self.layer6(out) + if self._add_output_and_check('layer6', out, outputs, output_layers): + return outputs + out = self.out_conv1(out) + if self._add_output_and_check('layer_out', out, outputs, output_layers): + return outputs + batch, channels, height, width = out.size() + out = F.avg_pool2d(out, kernel_size=[height, width]) + out = self.out_conv2(out).view(batch, -1) + if len(output_layers) == 1 and output_layers[0] == 'default': + return out + return outputs + +def mobilenet3(output_layers=None, path=None): + """Constructs a ResNet-18 model with first-layer VGGm features. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['init_conv','layer1', 'layer2', 'layer3', 'layer4', 'layer5','layer6','layer_out']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = MobileNetV3(model_mode="LARGE", num_classes=100, multiplier=1.0,output_layers=output_layers,dropout_rate = 0.8) + if path is not None: + print(path) + checkpoint = torch.load(path) + model.load_state_dict(checkpoint['model'], strict=False) + return model + +# temp = torch.zeros((1, 3, 224, 224)) +# model = MobileNetV3(model_mode="LARGE", num_classes=1000, multiplier=1.0) +# print(model(temp).shape) +# print(get_model_parameters(model)) \ No newline at end of file diff --git a/ltr/models/backbone/resnet.py b/ltr/models/backbone/resnet.py new file mode 100755 index 0000000..6a1dabc --- /dev/null +++ b/ltr/models/backbone/resnet.py @@ -0,0 +1,274 @@ +import math +import torch.nn as nn +from collections import OrderedDict +import torch.utils.model_zoo as model_zoo +from torchvision.models.resnet import model_urls +from .base import Backbone + + +def conv3x3(in_planes, out_planes, stride=1, dilation=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1, use_bn=True): + super(BasicBlock, self).__init__() + self.use_bn = use_bn + self.conv1 = conv3x3(inplanes, planes, stride, dilation=dilation) + + if use_bn: + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes, dilation=dilation) + + if use_bn: + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + + if self.use_bn: + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + + if self.use_bn: + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=dilation, bias=False, dilation=dilation) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(Backbone): + """ ResNet network module. Allows extracting specific feature blocks.""" + def __init__(self, block, layers, output_layers, num_classes=1000, inplanes=64, dilation_factor=1, frozen_layers=()): + self.inplanes = inplanes + super(ResNet, self).__init__(frozen_layers=frozen_layers) + self.output_layers = output_layers + self.conv1 = nn.Conv2d(3, inplanes, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(inplanes) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + stride = [1 + (dilation_factor < l) for l in (8, 4, 2)] + self.layer1 = self._make_layer(block, inplanes, layers[0], dilation=max(dilation_factor//8, 1)) + self.layer2 = self._make_layer(block, inplanes*2, layers[1], stride=stride[0], dilation=max(dilation_factor//4, 1)) + self.layer3 = self._make_layer(block, inplanes*4, layers[2], stride=stride[1], dilation=max(dilation_factor//2, 1)) + self.layer4 = self._make_layer(block, inplanes*8, layers[3], stride=stride[2], dilation=dilation_factor) + + out_feature_strides = {'conv1': 4, 'layer1': 4, 'layer2': 4*stride[0], 'layer3': 4*stride[0]*stride[1], + 'layer4': 4*stride[0]*stride[1]*stride[2]} + + # TODO better way? + if isinstance(self.layer1[0], BasicBlock): + out_feature_channels = {'conv1': inplanes, 'layer1': inplanes, 'layer2': inplanes*2, 'layer3': inplanes*4, + 'layer4': inplanes*8} + elif isinstance(self.layer1[0], Bottleneck): + base_num_channels = 4 * inplanes + out_feature_channels = {'conv1': inplanes, 'layer1': base_num_channels, 'layer2': base_num_channels * 2, + 'layer3': base_num_channels * 4, 'layer4': base_num_channels * 8} + else: + raise Exception('block not supported') + + self._out_feature_strides = out_feature_strides + self._out_feature_channels = out_feature_channels + + # self.avgpool = nn.AvgPool2d(7, stride=1) + self.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.fc = nn.Linear(inplanes*8 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def out_feature_strides(self, layer=None): + if layer is None: + return self._out_feature_strides + else: + return self._out_feature_strides[layer] + + def out_feature_channels(self, layer=None): + if layer is None: + return self._out_feature_channels + else: + return self._out_feature_channels[layer] + + def _make_layer(self, block, planes, blocks, stride=1, dilation=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample, dilation=dilation)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + def forward(self, x, output_layers=None): + """ Forward pass with input x. The output_layers specify the feature blocks which must be returned """ + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + if self._add_output_and_check('conv1', x, outputs, output_layers): + return outputs + + x = self.maxpool(x) + + x = self.layer1(x) + + if self._add_output_and_check('layer1', x, outputs, output_layers): + return outputs + + x = self.layer2(x) + + if self._add_output_and_check('layer2', x, outputs, output_layers): + return outputs + + x = self.layer3(x) + + if self._add_output_and_check('layer3', x, outputs, output_layers): + return outputs + + x = self.layer4(x) + + if self._add_output_and_check('layer4', x, outputs, output_layers): + return outputs + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + if self._add_output_and_check('fc', x, outputs, output_layers): + return outputs + + if len(output_layers) == 1 and output_layers[0] == 'default': + return x + + raise ValueError('output_layer is wrong.') + + +def resnet_baby(output_layers=None, pretrained=False, inplanes=16, **kwargs): + """Constructs a ResNet-18 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(BasicBlock, [2, 2, 2, 2], output_layers, inplanes=inplanes, **kwargs) + + if pretrained: + raise NotImplementedError + return model + + +def resnet18(output_layers=None, pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(BasicBlock, [2, 2, 2, 2], output_layers, **kwargs) + + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + return model + + +def resnet50(output_layers=None, pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNet(Bottleneck, [3, 4, 6, 3], output_layers, **kwargs) + if pretrained: + model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + return model \ No newline at end of file diff --git a/ltr/models/backbone/resnet18_vggm.py b/ltr/models/backbone/resnet18_vggm.py new file mode 100755 index 0000000..5333abf --- /dev/null +++ b/ltr/models/backbone/resnet18_vggm.py @@ -0,0 +1,159 @@ +import math +import torch +import torch.nn as nn +from collections import OrderedDict +from torchvision.models.resnet import BasicBlock +from .base import Backbone + + +class SpatialCrossMapLRN(nn.Module): + def __init__(self, local_size=1, alpha=1.0, beta=0.75, k=1, ACROSS_CHANNELS=True): + super(SpatialCrossMapLRN, self).__init__() + self.ACROSS_CHANNELS = ACROSS_CHANNELS + if ACROSS_CHANNELS: + self.average=nn.AvgPool3d(kernel_size=(local_size, 1, 1), + stride=1, + padding=(int((local_size-1.0)/2), 0, 0)) + else: + self.average=nn.AvgPool2d(kernel_size=local_size, + stride=1, + padding=int((local_size-1.0)/2)) + self.alpha = alpha + self.beta = beta + self.k = k + + def forward(self, x): + if self.ACROSS_CHANNELS: + div = x.pow(2).unsqueeze(1) + div = self.average(div).squeeze(1) + div = div.mul(self.alpha).add(self.k).pow(self.beta) + else: + div = x.pow(2) + div = self.average(div) + div = div.mul(self.alpha).add(self.k).pow(self.beta) + x = x.div(div) + return x + + +class ResNetVGGm1(Backbone): + + def __init__(self, block, layers, output_layers, num_classes=1000, frozen_layers=()): + self.inplanes = 64 + super(ResNetVGGm1, self).__init__(frozen_layers=frozen_layers) + self.output_layers = output_layers + self.vggmconv1 = nn.Conv2d(3,96,(7, 7),(2, 2), padding=3) + self.vgglrn = SpatialCrossMapLRN(5, 0.0005, 0.75, 2) + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + # self.avgpool = nn.AvgPool2d(7, stride=1) + self.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.fc = nn.Linear(512 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + + def _add_output_and_check(self, name, x, outputs, output_layers): + if name in output_layers: + outputs[name] = x + return len(output_layers) == len(outputs) + + + def forward(self, x, output_layers=None): + outputs = OrderedDict() + + if output_layers is None: + output_layers = self.output_layers + + if 'vggconv1' in output_layers: + c1 = self.vgglrn(self.relu(self.vggmconv1(x))) + if self._add_output_and_check('vggconv1', c1, outputs, output_layers): + return outputs + + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + + if self._add_output_and_check('conv1', x, outputs, output_layers): + return outputs + + x = self.maxpool(x) + + x = self.layer1(x) + + if self._add_output_and_check('layer1', x, outputs, output_layers): + return outputs + + x = self.layer2(x) + + if self._add_output_and_check('layer2', x, outputs, output_layers): + return outputs + + x = self.layer3(x) + + if self._add_output_and_check('layer3', x, outputs, output_layers): + return outputs + + x = self.layer4(x) + + if self._add_output_and_check('layer4', x, outputs, output_layers): + return outputs + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.fc(x) + + if self._add_output_and_check('fc', x, outputs, output_layers): + return outputs + + if len(output_layers) == 1 and output_layers[0] == 'default': + return x + + raise ValueError('output_layer is wrong.') + + +def resnet18_vggmconv1(output_layers=None, path=None, **kwargs): + """Constructs a ResNet-18 model with first-layer VGGm features. + """ + + if output_layers is None: + output_layers = ['default'] + else: + for l in output_layers: + if l not in ['vggconv1', 'conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer: {}'.format(l)) + + model = ResNetVGGm1(BasicBlock, [2, 2, 2, 2], output_layers, **kwargs) + + if path is not None: + model.load_state_dict(torch.load(path), strict=False) + return model \ No newline at end of file diff --git a/ltr/models/bbreg/__init__.py b/ltr/models/bbreg/__init__.py new file mode 100755 index 0000000..bb6162f --- /dev/null +++ b/ltr/models/bbreg/__init__.py @@ -0,0 +1 @@ +from .atom_iou_net import AtomIoUNet diff --git a/ltr/models/bbreg/__pycache__/__init__.cpython-37.pyc b/ltr/models/bbreg/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..c042f41 Binary files /dev/null and b/ltr/models/bbreg/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/bbreg/__pycache__/atom_iou_net.cpython-37.pyc b/ltr/models/bbreg/__pycache__/atom_iou_net.cpython-37.pyc new file mode 100755 index 0000000..4ef9777 Binary files /dev/null and b/ltr/models/bbreg/__pycache__/atom_iou_net.cpython-37.pyc differ diff --git a/ltr/models/bbreg/atom.py b/ltr/models/bbreg/atom.py new file mode 100755 index 0000000..203384c --- /dev/null +++ b/ltr/models/bbreg/atom.py @@ -0,0 +1,85 @@ +import torch.nn as nn +import ltr.models.backbone as backbones +import ltr.models.bbreg as bbmodels +from ltr import model_constructor + + +class ATOMnet(nn.Module): + """ ATOM network module""" + def __init__(self, feature_extractor, bb_regressor, bb_regressor_layer, extractor_grad=True): + """ + args: + feature_extractor - backbone feature extractor + bb_regressor - IoU prediction module + bb_regressor_layer - List containing the name of the layers from feature_extractor, which are input to + bb_regressor + extractor_grad - Bool indicating whether backbone feature extractor requires gradients + """ + super(ATOMnet, self).__init__() + + self.feature_extractor = feature_extractor + self.bb_regressor = bb_regressor + self.bb_regressor_layer = bb_regressor_layer + + if not extractor_grad: + for p in self.feature_extractor.parameters(): + p.requires_grad_(False) + + def forward(self, train_imgs, test_imgs, train_bb, test_proposals): + """ Forward pass + Note: If the training is done in sequence mode, that is, test_imgs.dim() == 5, then the batch dimension + corresponds to the first dimensions. test_imgs is thus of the form [sequence, batch, feature, row, col] + """ + num_sequences = train_imgs.shape[-4] + num_train_images = train_imgs.shape[0] if train_imgs.dim() == 5 else 1 + num_test_images = test_imgs.shape[0] if test_imgs.dim() == 5 else 1 + + # Extract backbone features + train_feat = self.extract_backbone_features(train_imgs.reshape(-1, *train_imgs.shape[-3:])) + test_feat = self.extract_backbone_features(test_imgs.reshape(-1, *test_imgs.shape[-3:])) + + train_feat_iou = [feat for feat in train_feat.values()] + test_feat_iou = [feat for feat in test_feat.values()] + + # Obtain iou prediction + iou_pred = self.bb_regressor(train_feat_iou, test_feat_iou, + train_bb.reshape(num_train_images, num_sequences, 4), + test_proposals.reshape(num_train_images, num_sequences, -1, 4)) + return iou_pred + + def extract_backbone_features(self, im, layers=None): + if layers is None: + layers = self.bb_regressor_layer + return self.feature_extractor(im, layers) + + def extract_features(self, im, layers): + return self.feature_extractor(im, layers) + + + +@model_constructor +def atom_resnet18(iou_input_dim=(256,256), iou_inter_dim=(256,256), backbone_pretrained=True): + # backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained) + + # Bounding box regressor + iou_predictor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + net = ATOMnet(feature_extractor=backbone_net, bb_regressor=iou_predictor, bb_regressor_layer=['layer2', 'layer3'], + extractor_grad=False) + + return net + + +@model_constructor +def atom_resnet50(iou_input_dim=(256,256), iou_inter_dim=(256,256), backbone_pretrained=True): + # backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained) + + # Bounding box regressor + iou_predictor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + net = ATOMnet(feature_extractor=backbone_net, bb_regressor=iou_predictor, bb_regressor_layer=['layer2', 'layer3'], + extractor_grad=False) + + return net diff --git a/ltr/models/bbreg/atom_iou_net.py b/ltr/models/bbreg/atom_iou_net.py new file mode 100755 index 0000000..15f0f73 --- /dev/null +++ b/ltr/models/bbreg/atom_iou_net.py @@ -0,0 +1,179 @@ +import torch.nn as nn +import torch +from ltr.models.layers.blocks import LinearBlock +from ltr.external.PreciseRoIPooling.pytorch.prroi_pool import PrRoIPool2D + + +def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1): + return nn.Sequential( + nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=True), + nn.BatchNorm2d(out_planes), + nn.ReLU(inplace=True)) + + +class AtomIoUNet(nn.Module): + """Network module for IoU prediction. Refer to the ATOM paper for an illustration of the architecture. + It uses two backbone feature layers as input. + args: + input_dim: Feature dimensionality of the two input backbone layers. + pred_input_dim: Dimensionality input the the prediction network. + pred_inter_dim: Intermediate dimensionality in the prediction network.""" + + def __init__(self, input_dim=(128,256), pred_input_dim=(256,256), pred_inter_dim=(256,256)): + super().__init__() + # _r for reference, _t for test + self.conv3_1r = conv(input_dim[0], 128, kernel_size=3, stride=1) + self.conv3_1t = conv(input_dim[0], 256, kernel_size=3, stride=1) + + self.conv3_2t = conv(256, pred_input_dim[0], kernel_size=3, stride=1) + + self.prroi_pool3r = PrRoIPool2D(3, 3, 1/8) + self.prroi_pool3t = PrRoIPool2D(5, 5, 1/8) + + self.fc3_1r = conv(128, 256, kernel_size=3, stride=1, padding=0) + + self.conv4_1r = conv(input_dim[1], 256, kernel_size=3, stride=1) + self.conv4_1t = conv(input_dim[1], 256, kernel_size=3, stride=1) + + self.conv4_2t = conv(256, pred_input_dim[1], kernel_size=3, stride=1) + + self.prroi_pool4r = PrRoIPool2D(1, 1, 1/16) + self.prroi_pool4t = PrRoIPool2D(3, 3, 1 / 16) + + self.fc34_3r = conv(256 + 256, pred_input_dim[0], kernel_size=1, stride=1, padding=0) + self.fc34_4r = conv(256 + 256, pred_input_dim[1], kernel_size=1, stride=1, padding=0) + + self.fc3_rt = LinearBlock(pred_input_dim[0], pred_inter_dim[0], 5) + self.fc4_rt = LinearBlock(pred_input_dim[1], pred_inter_dim[1], 3) + + self.iou_predictor = nn.Linear(pred_inter_dim[0]+pred_inter_dim[1], 1, bias=True) + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d) or isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight.data, mode='fan_in') + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + # In earlier versions batch norm parameters was initialized with default initialization, + # which changed in pytorch 1.2. In 1.1 and earlier the weight was set to U(0,1). + # So we use the same initialization here. + # m.weight.data.fill_(1) + m.weight.data.uniform_() + m.bias.data.zero_() + + def forward(self, feat1, feat2, bb1, proposals2): + """Runs the ATOM IoUNet during training operation. + This forward pass is mainly used for training. Call the individual functions during tracking instead. + args: + feat1: Features from the reference frames (4 or 5 dims). + feat2: Features from the test frames (4 or 5 dims). + bb1: Target boxes (x,y,w,h) in image coords in the reference samples. Dims (images, sequences, 4). + proposals2: Proposal boxes for which the IoU will be predicted (images, sequences, num_proposals, 4).""" + + assert bb1.dim() == 3 + assert proposals2.dim() == 4 + + num_images = proposals2.shape[0] + num_sequences = proposals2.shape[1] + + # Extract first train sample + feat1 = [f[0,...] if f.dim()==5 else f.reshape(-1, num_sequences, *f.shape[-3:])[0,...] for f in feat1] + bb1 = bb1[0,...] + + # Get modulation vector + modulation = self.get_modulation(feat1, bb1) + + iou_feat = self.get_iou_feat(feat2) + + modulation = [f.reshape(1, num_sequences, -1).repeat(num_images, 1, 1).reshape(num_sequences*num_images, -1) for f in modulation] + + proposals2 = proposals2.reshape(num_sequences*num_images, -1, 4) + pred_iou = self.predict_iou(modulation, iou_feat, proposals2) + return pred_iou.reshape(num_images, num_sequences, -1) + + def predict_iou(self, modulation, feat, proposals): + """Predicts IoU for the give proposals. + args: + modulation: Modulation vectors for the targets. Dims (batch, feature_dim). + feat: IoU features (from get_iou_feat) for test images. Dims (batch, feature_dim, H, W). + proposals: Proposal boxes for which the IoU will be predicted (batch, num_proposals, 4).""" + + fc34_3_r, fc34_4_r = modulation + c3_t, c4_t = feat + + batch_size = c3_t.size()[0] + + # Modulation + c3_t_att = c3_t * fc34_3_r.reshape(batch_size, -1, 1, 1) + c4_t_att = c4_t * fc34_4_r.reshape(batch_size, -1, 1, 1) + + # Add batch_index to rois + batch_index = torch.arange(batch_size, dtype=torch.float32).reshape(-1, 1).to(c3_t.device) + + # Push the different rois for the same image along the batch dimension + num_proposals_per_batch = proposals.shape[1] + + # input proposals2 is in format xywh, convert it to x0y0x1y1 format + proposals_xyxy = torch.cat((proposals[:, :, 0:2], proposals[:, :, 0:2] + proposals[:, :, 2:4]), dim=2) + + # Add batch index + roi2 = torch.cat((batch_index.reshape(batch_size, -1, 1).expand(-1, num_proposals_per_batch, -1), + proposals_xyxy), dim=2) + roi2 = roi2.reshape(-1, 5).to(proposals_xyxy.device) + + roi3t = self.prroi_pool3t(c3_t_att, roi2) + roi4t = self.prroi_pool4t(c4_t_att, roi2) + + fc3_rt = self.fc3_rt(roi3t) + fc4_rt = self.fc4_rt(roi4t) + + fc34_rt_cat = torch.cat((fc3_rt, fc4_rt), dim=1) + + iou_pred = self.iou_predictor(fc34_rt_cat).reshape(batch_size, num_proposals_per_batch) + + return iou_pred + + def get_modulation(self, feat, bb): + """Get modulation vectors for the targets. + args: + feat: Backbone features from reference images. Dims (batch, feature_dim, H, W). + bb: Target boxes (x,y,w,h) in image coords in the reference samples. Dims (batch, 4).""" + + feat3_r, feat4_r = feat + + c3_r = self.conv3_1r(feat3_r) + + # Add batch_index to rois + batch_size = bb.shape[0] + batch_index = torch.arange(batch_size, dtype=torch.float32).reshape(-1, 1).to(bb.device) + + # input bb is in format xywh, convert it to x0y0x1y1 format + bb = bb.clone() + bb[:, 2:4] = bb[:, 0:2] + bb[:, 2:4] + roi1 = torch.cat((batch_index, bb), dim=1) + + roi3r = self.prroi_pool3r(c3_r, roi1) + + c4_r = self.conv4_1r(feat4_r) + roi4r = self.prroi_pool4r(c4_r, roi1) + + fc3_r = self.fc3_1r(roi3r) + + # Concatenate from block 3 and 4 + fc34_r = torch.cat((fc3_r, roi4r), dim=1) + + fc34_3_r = self.fc34_3r(fc34_r) + fc34_4_r = self.fc34_4r(fc34_r) + + return fc34_3_r, fc34_4_r + + def get_iou_feat(self, feat2): + """Get IoU prediction features from a 4 or 5 dimensional backbone input.""" + feat2 = [f.reshape(-1, *f.shape[-3:]) if f.dim()==5 else f for f in feat2] + feat3_t, feat4_t = feat2 + c3_t = self.conv3_2t(self.conv3_1t(feat3_t)) + c4_t = self.conv4_2t(self.conv4_1t(feat4_t)) + + return c3_t, c4_t diff --git a/ltr/models/kys/__init__.py b/ltr/models/kys/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/models/kys/__pycache__/__init__.cpython-37.pyc b/ltr/models/kys/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..f719529 Binary files /dev/null and b/ltr/models/kys/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/kys/__pycache__/conv_gru.cpython-37.pyc b/ltr/models/kys/__pycache__/conv_gru.cpython-37.pyc new file mode 100755 index 0000000..15974e2 Binary files /dev/null and b/ltr/models/kys/__pycache__/conv_gru.cpython-37.pyc differ diff --git a/ltr/models/kys/__pycache__/cost_volume.cpython-37.pyc b/ltr/models/kys/__pycache__/cost_volume.cpython-37.pyc new file mode 100755 index 0000000..67f116c Binary files /dev/null and b/ltr/models/kys/__pycache__/cost_volume.cpython-37.pyc differ diff --git a/ltr/models/kys/__pycache__/predictor_wrapper.cpython-37.pyc b/ltr/models/kys/__pycache__/predictor_wrapper.cpython-37.pyc new file mode 100755 index 0000000..64ed9cb Binary files /dev/null and b/ltr/models/kys/__pycache__/predictor_wrapper.cpython-37.pyc differ diff --git a/ltr/models/kys/__pycache__/response_predictor.cpython-37.pyc b/ltr/models/kys/__pycache__/response_predictor.cpython-37.pyc new file mode 100755 index 0000000..efe2e7f Binary files /dev/null and b/ltr/models/kys/__pycache__/response_predictor.cpython-37.pyc differ diff --git a/ltr/models/kys/__pycache__/utils.cpython-37.pyc b/ltr/models/kys/__pycache__/utils.cpython-37.pyc new file mode 100755 index 0000000..dbff505 Binary files /dev/null and b/ltr/models/kys/__pycache__/utils.cpython-37.pyc differ diff --git a/ltr/models/kys/conv_gru.py b/ltr/models/kys/conv_gru.py new file mode 100755 index 0000000..0c090b4 --- /dev/null +++ b/ltr/models/kys/conv_gru.py @@ -0,0 +1,44 @@ +import torch +import torch.nn as nn +from ltr.models.layers.blocks import conv_block + + +class ConvGRUCell(nn.Module): + def __init__(self, input_dim, hidden_dim, kernel_size, padding_mode='zeros'): + " Referenced from https://github.com/happyjin/ConvGRU-pytorch" + super(ConvGRUCell, self).__init__() + self.hidden_dim = hidden_dim + + if padding_mode == 'zeros': + if not isinstance(kernel_size, (list, tuple)): + kernel_size = (kernel_size, kernel_size) + + padding = kernel_size[0] // 2, kernel_size[1] // 2 + self.conv_reset = nn.Conv2d(input_dim + hidden_dim, self.hidden_dim, kernel_size, padding=padding) + self.conv_update = nn.Conv2d(input_dim + hidden_dim, self.hidden_dim, kernel_size, padding=padding) + + self.conv_state_new = nn.Conv2d(input_dim+hidden_dim, self.hidden_dim, kernel_size, padding=padding) + else: + self.conv_reset = conv_block(input_dim + hidden_dim, hidden_dim, kernel_size=kernel_size, stride=1, + padding=int(kernel_size // 2), batch_norm=False, relu=False, + padding_mode=padding_mode) + + self.conv_update = conv_block(input_dim + hidden_dim, hidden_dim, kernel_size=kernel_size, stride=1, + padding=int(kernel_size // 2), batch_norm=False, relu=False, + padding_mode=padding_mode) + + self.conv_state_new = conv_block(input_dim + hidden_dim, hidden_dim, kernel_size=kernel_size, stride=1, + padding=int(kernel_size // 2), batch_norm=False, relu=False, + padding_mode=padding_mode) + + def forward(self, input, state_cur): + input_state_cur = torch.cat([input, state_cur], dim=1) + + reset_gate = torch.sigmoid(self.conv_reset(input_state_cur)) + update_gate = torch.sigmoid(self.conv_update(input_state_cur)) + + input_state_cur_reset = torch.cat([input, reset_gate*state_cur], dim=1) + state_new = torch.tanh(self.conv_state_new(input_state_cur_reset)) + + state_next = (1.0 - update_gate) * state_cur + update_gate * state_new + return state_next diff --git a/ltr/models/kys/cost_volume.py b/ltr/models/kys/cost_volume.py new file mode 100755 index 0000000..4cc971f --- /dev/null +++ b/ltr/models/kys/cost_volume.py @@ -0,0 +1,75 @@ +import torch +import torch.nn as nn +import numpy as np + +from spatial_correlation_sampler import SpatialCorrelationSampler + + +class CostVolume(nn.Module): + def __init__(self, kernel_size, max_displacement, stride=1, abs_coordinate_output=False): + super().__init__() + self.correlation_layer = SpatialCorrelationSampler(kernel_size, 2*max_displacement + 1, stride, + int((kernel_size-1)/2)) + self.abs_coordinate_output = abs_coordinate_output + + def forward(self, feat1, feat2): + assert feat1.dim() == 4 and feat2.dim() == 4, 'Expect 4 dimensional inputs' + + batch_size = feat1.shape[0] + + cost_volume = self.correlation_layer(feat1, feat2) + + if self.abs_coordinate_output: + cost_volume = cost_volume.view(batch_size, -1, cost_volume.shape[-2], cost_volume.shape[-1]) + cost_volume = remap_cost_volume(cost_volume) + + return cost_volume.view(batch_size, -1, cost_volume.shape[-2], cost_volume.shape[-1]) + + +def remap_cost_volume(cost_volume): + """ + + :param cost_volume: cost volume of shape (batch, (2*md-1)*(2*md-1), rows, cols), where md is the maximum displacement + allowed when computing the cost volume. + :return: cost_volume_remapped: The input cost volume is remapped to shape (batch, rows, cols, rows, cols) + """ + + if cost_volume.dim() != 4: + raise ValueError('input cost_volume should have 4 dimensions') + + [batch_size, d_, num_rows, num_cols] = cost_volume.size() + d_sqrt_ = np.sqrt(d_) + + if not d_sqrt_.is_integer(): + raise ValueError("Invalid cost volume") + + cost_volume = cost_volume.view(batch_size, int(d_sqrt_), int(d_sqrt_), num_rows, num_cols) + + cost_volume_remapped = torch.zeros((batch_size, num_rows, num_cols, + num_rows, num_cols), + dtype=cost_volume.dtype, + device=cost_volume.device) + + if cost_volume.size()[1] % 2 != 1: + raise ValueError + + md = int((cost_volume.size()[1]-1)/2) + + for r in range(num_rows): + for c in range(num_cols): + r1_ = r - md + r2_ = r1_ + 2*md + 1 + c1_ = c - md + c2_ = c1_ + 2*md + 1 + + r1_pad_ = max(-r1_, 0) + r2_pad_ = max(r2_ - cost_volume_remapped.shape[1], 0) + + c1_pad_ = max(-c1_, 0) + c2_pad_ = max(c2_ - cost_volume_remapped.shape[2], 0) + + d_ = cost_volume.size()[1] + cost_volume_remapped[:, r1_+r1_pad_:r2_-r2_pad_, c1_+c1_pad_:c2_-c2_pad_, r, c] = \ + cost_volume[:, r1_pad_:d_-r2_pad_, c1_pad_:d_-c2_pad_, r, c] + + return cost_volume_remapped diff --git a/ltr/models/kys/predictor_wrapper.py b/ltr/models/kys/predictor_wrapper.py new file mode 100755 index 0000000..814192f --- /dev/null +++ b/ltr/models/kys/predictor_wrapper.py @@ -0,0 +1,153 @@ +import torch +import torch.nn as nn +from ltr.models.kys.utils import shift_features + + +class PredictorWrapper(nn.Module): + def __init__(self, cost_volume, predictor): + super().__init__() + + self.cost_volume = cost_volume + self.predictor = predictor + self.fix_coordinate_shift = True + + def forward(self, data): + input1 = data['input1'] + input2 = data['input2'] + label_prev = data.get('label_prev', None) + + dimp_score_cur = data['dimp_score_cur'] + state_prev = data['state_prev'] + + score_shape = dimp_score_cur.shape + + if isinstance(input1, (tuple, list)): + feat1 = [self.extract_motion_feat(in1) for in1 in input1] + feat1 = [f1.view(-1, *f1.shape[-3:]) for f1 in feat1] + else: + feat1 = self.extract_motion_feat(input1) + feat1 = feat1.view(-1, *feat1.shape[-3:]) + + feat2 = self.extract_motion_feat(input2) + feat2 = feat2.view(-1, *feat2.shape[-3:]) + + dimp_score_cur = dimp_score_cur.view(-1, 1, *dimp_score_cur.shape[-2:]) + + if isinstance(input1, (tuple, list)): + cost_volume = [self.compute_cost_volume(f1, feat2, True) for f1 in feat1] + else: + cost_volume = self.compute_cost_volume(feat1, feat2, True) + + feat_map_size = torch.tensor([dimp_score_cur.shape[-1], dimp_score_cur.shape[-2]]).view(1, 2).float().to(dimp_score_cur.device) + if self.fix_coordinate_shift: + shift_value = - torch.ones(dimp_score_cur.shape[0], 2).to(dimp_score_cur.device) * 0.5 / feat_map_size + + if label_prev is not None: + label_prev_shape = label_prev.shape + label_prev = shift_features(label_prev.clone().view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view(label_prev_shape) + + dimp_score_cur = shift_features(dimp_score_cur.clone(), shift_value) + + pred_response, state_new, auxiliary_outputs = self.predictor(cost_volume, state_prev, dimp_score_cur, label_prev) + pred_response = pred_response.view(score_shape) + + # Shift back + if self.fix_coordinate_shift: + shift_value = torch.ones(dimp_score_cur.shape[0], 2).to(dimp_score_cur.device) * 0.5 / feat_map_size + + if 'is_target' in auxiliary_outputs: + auxiliary_outputs['is_target'] = shift_features( + auxiliary_outputs['is_target'].view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view(score_shape) + + if 'is_target_after_prop' in auxiliary_outputs: + auxiliary_outputs['is_target_after_prop'] = shift_features( + auxiliary_outputs['is_target_after_prop'].view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view(score_shape) + + if 'is_target_new' in auxiliary_outputs: + auxiliary_outputs['is_target_new'] = shift_features( + auxiliary_outputs['is_target_new'].view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view(score_shape) + + pred_response = shift_features(pred_response.view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view(score_shape) + + output = {'response': pred_response, 'state_cur': state_new, 'auxiliary_outputs': auxiliary_outputs} + return output + + def compute_cost_volume(self, feat_prev, feat_cur, use_current_frame_as_ref): + if use_current_frame_as_ref: + cost_volume = self.cost_volume(feat_cur, feat_prev) + else: + cost_volume = self.cost_volume(feat_prev, feat_cur) + return cost_volume + + def extract_motion_feat(self, backbone_feat): + backbone_feat = backbone_feat.view(-1, backbone_feat.shape[-3], backbone_feat.shape[-2], + backbone_feat.shape[-1]) + + return backbone_feat + + def predict_response(self, data, dimp_thresh=None, output_window=None): + feat1 = data['feat1'] + feat2 = data['feat2'] + label_prev = data.get('label_prev', None) + + dimp_score_cur = data['dimp_score_cur'] + state_prev = data['state_prev'] + + score_shape = dimp_score_cur.shape + + if isinstance(feat1, (tuple, list)): + feat1 = [f1.view(-1, *f1.shape[-3:]) for f1 in feat1] + else: + feat1 = feat1.view(-1, *feat1.shape[-3:]) + + feat2 = feat2.view(-1, *feat2.shape[-3:]) + dimp_score_cur = dimp_score_cur.view(-1, 1, *dimp_score_cur.shape[-2:]) + + if isinstance(feat1, (tuple, list)): + cost_volume = [self.compute_cost_volume(f1, feat2, True) for f1 in feat1] + else: + cost_volume = self.compute_cost_volume(feat1, feat2, True) + + feat_map_size = torch.tensor([dimp_score_cur.shape[-1], dimp_score_cur.shape[-2]]).view(1, 2).float().to( + dimp_score_cur.device) + if self.fix_coordinate_shift: + shift_value = - torch.ones(dimp_score_cur.shape[0], 2).to(dimp_score_cur.device) * 0.5 / feat_map_size + + if label_prev is not None: + label_prev_shape = label_prev.shape + label_prev = shift_features(label_prev.clone().view(-1, 1, *dimp_score_cur.shape[-2:]), + shift_value).view(label_prev_shape) + + dimp_score_cur = shift_features(dimp_score_cur.clone(), shift_value) + + pred_response, state_new, auxiliary_outputs = self.predictor(cost_volume, state_prev, dimp_score_cur, + label_prev, dimp_thresh, output_window) + + pred_response = pred_response.view(score_shape) + + # Shift back + if self.fix_coordinate_shift: + shift_value = torch.ones(dimp_score_cur.shape[0], 2).to(dimp_score_cur.device) * 0.5 / feat_map_size + + if 'is_target' in auxiliary_outputs: + auxiliary_outputs['is_target'] = shift_features( + auxiliary_outputs['is_target'].view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view( + score_shape) + + if 'is_target_after_prop' in auxiliary_outputs: + auxiliary_outputs['is_target_after_prop'] = shift_features( + auxiliary_outputs['is_target_after_prop'].view(-1, 1, *dimp_score_cur.shape[-2:]), + shift_value).view(score_shape) + + if 'is_target_new' in auxiliary_outputs: + auxiliary_outputs['is_target_new'] = shift_features( + auxiliary_outputs['is_target_new'].view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view( + score_shape) + + pred_response = shift_features(pred_response.view(-1, 1, *dimp_score_cur.shape[-2:]), shift_value).view( + score_shape) + + output = {'response': pred_response, 'state_cur': state_new, 'auxiliary_outputs': auxiliary_outputs, + 'cost_volume': cost_volume} + + return output \ No newline at end of file diff --git a/ltr/models/kys/response_predictor.py b/ltr/models/kys/response_predictor.py new file mode 100755 index 0000000..6262084 --- /dev/null +++ b/ltr/models/kys/response_predictor.py @@ -0,0 +1,160 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +from ltr.models.layers.blocks import conv_block +from .conv_gru import ConvGRUCell + + +class ResponsePredictor(nn.Module): + def __init__(self, state_dim=8, representation_predictor_dims=(64, 32), gru_ksz=3, + prev_max_pool_ksz=1, conf_measure='max', dimp_thresh=None): + super().__init__() + self.prev_max_pool_ksz = prev_max_pool_ksz + self.conf_measure = conf_measure + self.dimp_thresh = dimp_thresh + + cvproc_ksz = [3, 3] + use_bn = True + + padding_val = [int((s - 1) / 2) for s in cvproc_ksz] + + self.cost_volume_proc1 = nn.Sequential( + conv_block(1, 8, kernel_size=cvproc_ksz[0], stride=1, padding=padding_val[0], batch_norm=use_bn, relu=True), + conv_block(8, 1, kernel_size=cvproc_ksz[1], stride=1, padding=padding_val[1], batch_norm=use_bn, relu=False)) + + self.cost_volume_proc2 = nn.Sequential( + conv_block(1, 8, kernel_size=cvproc_ksz[0], stride=1, padding=padding_val[0], batch_norm=use_bn, relu=True), + conv_block(8, 1, kernel_size=cvproc_ksz[1], stride=1, padding=padding_val[1], batch_norm=use_bn, relu=False)) + + in_dim = state_dim + 1 + (conf_measure != 'none') + representation_predictor_list = [] + for out_dim in representation_predictor_dims: + representation_predictor_list.append(conv_block(in_dim, out_dim, kernel_size=3, stride=1, padding=1, + batch_norm=False, relu=True)) + in_dim = out_dim + + self.representation_predictor = nn.Sequential(*representation_predictor_list) + self.representation_dim = in_dim + + self.response_predictor = nn.Sequential( + conv_block(in_dim, 1, kernel_size=3, stride=1, padding=1, batch_norm=False, relu=False), + nn.Sigmoid()) + + self.state_predictor = ConvGRUCell(4, state_dim, gru_ksz) + + self.init_hidden_state_predictor = nn.Sequential( + conv_block(1, state_dim, kernel_size=3, stride=1, padding=1, batch_norm=False, relu=False, bias=False), + nn.Tanh()) + + self.is_target_predictor = nn.Sequential( + conv_block(state_dim, 4, kernel_size=gru_ksz, stride=1, padding=int(gru_ksz // 2), batch_norm=False, + relu=True), + conv_block(4, 1, kernel_size=gru_ksz, stride=1, padding=int(gru_ksz // 2), batch_norm=False, relu=False)) + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight.data, mode='fan_in') + if m.bias is not None: + m.bias.data.zero_() + + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, cost_volume, state_prev, dimp_score_cur, init_label=None, dimp_thresh=None, + output_window=None): + # Cost vol shape: n x h*w x h x w + # state_prev shape: n x d x h x w + # dimp_cur_shape: n x 1 x h x w + # init_label shape: n x 1 x h x w + if dimp_thresh is None: + dimp_thresh = self.dimp_thresh + auxiliary_outputs = {} + + num_sequences = cost_volume.shape[0] + feat_sz = cost_volume.shape[-2:] + + cost_volume = cost_volume.view(-1, 1, feat_sz[0], feat_sz[1]) + cost_volume_p1 = self.cost_volume_proc1(cost_volume).view(-1, feat_sz[0] * feat_sz[1]) + cost_volume_p1 = F.softmax(cost_volume_p1, dim=1) + + cost_volume_p2 = self.cost_volume_proc2(cost_volume_p1.view(-1, 1, feat_sz[0], feat_sz[1])) + cost_volume_p2 = cost_volume_p2.view(num_sequences, -1, feat_sz[0], feat_sz[1]) + cost_volume_p2 = F.softmax(cost_volume_p2, dim=1) + cost_volume_p2 = cost_volume_p2.view(num_sequences, -1, 1, feat_sz[0], feat_sz[1]) + + auxiliary_outputs['cost_volume_processed'] = cost_volume_p2 + + if state_prev is None: + init_hidden_state = self.init_hidden_state_predictor(init_label.view(num_sequences, 1, + feat_sz[0], feat_sz[1])) + state_prev_ndhw = init_hidden_state + else: + state_prev_ndhw = state_prev + + is_target = self.is_target_predictor(state_prev_ndhw) + auxiliary_outputs['is_target'] = is_target + + state_prev_ndhw = state_prev_ndhw.view(num_sequences, -1, feat_sz[0], feat_sz[1]) + + state_prev_nhwd = state_prev_ndhw.permute(0, 2, 3, 1).contiguous(). \ + view(num_sequences, feat_sz[0] * feat_sz[1], -1, 1, 1).expand(-1, -1, -1, feat_sz[0], feat_sz[1]) + + # Compute propagation weights + propagation_weight_norm = cost_volume_p2.view(num_sequences, feat_sz[0] * feat_sz[1], 1, feat_sz[0], feat_sz[1]) + + # Pool + if self.prev_max_pool_ksz > 1: + raise NotImplementedError + + # Max pool along prev frame ref + if self.conf_measure == 'max': + propagation_conf = propagation_weight_norm.view(num_sequences, -1, feat_sz[0], feat_sz[1]).max(dim=1)[0] + elif self.conf_measure == 'entropy': + propagation_conf = propagation_weight_norm.view(num_sequences, -1, feat_sz[0], feat_sz[1]) + propagation_conf = -(propagation_conf * (propagation_conf + 1e-4).log()).sum(dim=1) + + auxiliary_outputs['propagation_weights'] = propagation_weight_norm + + propagated_h = (propagation_weight_norm * state_prev_nhwd).sum(dim=1) + propagated_h = propagated_h.view(num_sequences, -1, feat_sz[0], feat_sz[1]) + + auxiliary_outputs['propagated_h'] = propagated_h.clone() + is_target_after_prop = self.is_target_predictor(propagated_h) + auxiliary_outputs['is_target_after_prop'] = is_target_after_prop + + if self.conf_measure != 'none': + propagation_conf = propagation_conf.view(num_sequences, 1, feat_sz[0], feat_sz[1]) + auxiliary_outputs['propagation_conf'] = propagation_conf + + predictor_input = torch.cat( + (propagated_h, dimp_score_cur.view(num_sequences, 1, *dimp_score_cur.shape[-2:]), + propagation_conf), dim=1) + else: + predictor_input = torch.cat( + (propagated_h, dimp_score_cur.view(num_sequences, 1, *dimp_score_cur.shape[-2:])), dim=1) + resp_representation = self.representation_predictor(predictor_input) + fused_prediction = self.response_predictor(resp_representation) + + auxiliary_outputs['fused_score_orig'] = fused_prediction.clone() + if dimp_thresh is not None: + fused_prediction = fused_prediction * (dimp_score_cur > dimp_thresh).float() + + if output_window is not None: + fused_prediction = fused_prediction * output_window + + scores_cat = torch.cat((dimp_score_cur, fused_prediction), dim=1) + + scores_cat_pool = F.adaptive_max_pool2d(scores_cat, 1).view(scores_cat.shape[0], scores_cat.shape[1], 1, 1). \ + expand(-1, -1, feat_sz[0], feat_sz[1]) + + state_gru_input = torch.cat((scores_cat, scores_cat_pool), dim=1) + + state_new = self.state_predictor(state_gru_input, propagated_h) + + is_target_new = self.is_target_predictor(state_new) + auxiliary_outputs['is_target_new'] = is_target_new + + return fused_prediction, state_new, auxiliary_outputs + diff --git a/ltr/models/kys/utils.py b/ltr/models/kys/utils.py new file mode 100755 index 0000000..9a9f3fa --- /dev/null +++ b/ltr/models/kys/utils.py @@ -0,0 +1,79 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def shift_features(feat, relative_translation_vector): + T_mat = torch.eye(2).repeat(feat.shape[0], 1, 1).to(feat.device) + T_mat = torch.cat((T_mat, relative_translation_vector.view(-1, 2, 1)), dim=2) + + grid = F.affine_grid(T_mat, feat.shape) + + feat_out = F.grid_sample(feat, grid) + return feat_out + + +class CenterShiftFeatures(nn.Module): + def __init__(self, feature_stride): + super().__init__() + self.feature_stride = feature_stride + + def forward(self, feat, anno): + anno = anno.view(-1, 4) + c_x = (anno[:, 0] + anno[:, 2] * 0.5) / self.feature_stride + c_y = (anno[:, 1] + anno[:, 3] * 0.5) / self.feature_stride + + t_x = 2 * (c_x - feat.shape[-1] * 0.5) / feat.shape[-1] + t_y = 2 * (c_y - feat.shape[-2] * 0.5) / feat.shape[-2] + + t = torch.cat((t_x.view(-1, 1), t_y.view(-1, 1)), dim=1) + + feat_out = shift_features(feat, t) + return feat_out + + +class DiMPScoreJittering(): + def __init__(self, p_zero=0.0, distractor_ratio=1.0, p_distractor=0, max_distractor_enhance_factor=1, + min_distractor_enhance_factor=0.75): + """ Jitters predicted score map by randomly enhancing distractor peaks and masking out target peaks""" + self.p_zero = p_zero + self.distractor_ratio = distractor_ratio + self.p_distractor = p_distractor + self.max_distractor_enhance_factor = max_distractor_enhance_factor + self.min_distractor_enhance_factor = min_distractor_enhance_factor + + def rand(self, sz, min_val, max_val): + return torch.rand(sz, device=min_val.device) * (max_val - min_val) + min_val + + def __call__(self, score, label): + score_shape = score.shape + + score = score.view(-1, score_shape[-2]*score_shape[-1]) + num_score_maps = score.shape[0] + + label = label.view(score.shape) + + dist_roll_value = torch.rand(num_score_maps).to(score.device) + + score_c = score.clone().detach() + score_neg = score_c * (label < 1e-4).float() + score_pos = score_c * (label > 0.2).float() + + target_max_val, _ = torch.max(score_pos, dim=1) + dist_max_val, dist_id = torch.max(score_neg, dim=1) + + jitter_score = (dist_roll_value < self.p_distractor) & ((dist_max_val / target_max_val) > self.distractor_ratio) + + for i in range(num_score_maps): + score_c[i, dist_id[i]] = self.rand(1, target_max_val[i]*self.min_distractor_enhance_factor, + target_max_val[i]*self.max_distractor_enhance_factor) + + zero_roll_value = torch.rand(num_score_maps).to(score.device) + zero_score = (zero_roll_value < self.p_zero) & ~jitter_score + + score_c[zero_score, :] = 0 + + score_jittered = score*(1.0 - (jitter_score | zero_score).float()).view(num_score_maps, 1).float() + \ + score_c*(jitter_score | zero_score).float().view(num_score_maps, 1).float() + + return score_jittered.view(score_shape) diff --git a/ltr/models/layers/__init__.py b/ltr/models/layers/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/models/layers/__pycache__/__init__.cpython-37.pyc b/ltr/models/layers/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..7a2c5f4 Binary files /dev/null and b/ltr/models/layers/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/activation.cpython-37.pyc b/ltr/models/layers/__pycache__/activation.cpython-37.pyc new file mode 100755 index 0000000..bb2f368 Binary files /dev/null and b/ltr/models/layers/__pycache__/activation.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/blocks.cpython-37.pyc b/ltr/models/layers/__pycache__/blocks.cpython-37.pyc new file mode 100755 index 0000000..8911ecb Binary files /dev/null and b/ltr/models/layers/__pycache__/blocks.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/distance.cpython-37.pyc b/ltr/models/layers/__pycache__/distance.cpython-37.pyc new file mode 100755 index 0000000..7fc4e6e Binary files /dev/null and b/ltr/models/layers/__pycache__/distance.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/filter.cpython-37.pyc b/ltr/models/layers/__pycache__/filter.cpython-37.pyc new file mode 100755 index 0000000..8f3d616 Binary files /dev/null and b/ltr/models/layers/__pycache__/filter.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/normalization.cpython-37.pyc b/ltr/models/layers/__pycache__/normalization.cpython-37.pyc new file mode 100755 index 0000000..de1dffe Binary files /dev/null and b/ltr/models/layers/__pycache__/normalization.cpython-37.pyc differ diff --git a/ltr/models/layers/__pycache__/transform.cpython-37.pyc b/ltr/models/layers/__pycache__/transform.cpython-37.pyc new file mode 100755 index 0000000..468bdb4 Binary files /dev/null and b/ltr/models/layers/__pycache__/transform.cpython-37.pyc differ diff --git a/ltr/models/layers/activation.py b/ltr/models/layers/activation.py new file mode 100755 index 0000000..403aedf --- /dev/null +++ b/ltr/models/layers/activation.py @@ -0,0 +1,67 @@ +import math +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def softmax_reg(x: torch.Tensor, dim, reg=None): + """Softmax with optinal denominator regularization.""" + if reg is None: + return torch.softmax(x, dim=dim) + dim %= x.dim() + if isinstance(reg, (float, int)): + reg = x.new_tensor([reg]) + reg = reg.expand([1 if d==dim else x.shape[d] for d in range(x.dim())]) + x = torch.cat((x, reg), dim=dim) + return torch.softmax(x, dim=dim)[[slice(-1) if d==dim else slice(None) for d in range(x.dim())]] + + + +class MLU(nn.Module): + r"""MLU activation + """ + def __init__(self, min_val, inplace=False): + super().__init__() + self.min_val = min_val + self.inplace = inplace + + def forward(self, input): + return F.elu(F.leaky_relu(input, 1/self.min_val, inplace=self.inplace), self.min_val, inplace=self.inplace) + + +class LeakyReluPar(nn.Module): + r"""LeakyRelu parametric activation + """ + + def forward(self, x, a): + return (1.0 - a)/2.0 * torch.abs(x) + (1.0 + a)/2.0 * x + +class LeakyReluParDeriv(nn.Module): + r"""Derivative of the LeakyRelu parametric activation, wrt x. + """ + + def forward(self, x, a): + return (1.0 - a)/2.0 * torch.sign(x.detach()) + (1.0 + a)/2.0 + + +class BentIdentPar(nn.Module): + r"""BentIdent parametric activation + """ + def __init__(self, b=1.0): + super().__init__() + self.b = b + + def forward(self, x, a): + return (1.0 - a)/2.0 * (torch.sqrt(x*x + 4.0*self.b*self.b) - 2.0*self.b) + (1.0 + a)/2.0 * x + + +class BentIdentParDeriv(nn.Module): + r"""BentIdent parametric activation deriv + """ + def __init__(self, b=1.0): + super().__init__() + self.b = b + + def forward(self, x, a): + return (1.0 - a)/2.0 * (x / torch.sqrt(x*x + 4.0*self.b*self.b)) + (1.0 + a)/2.0 + diff --git a/ltr/models/layers/blocks.py b/ltr/models/layers/blocks.py new file mode 100755 index 0000000..aef88c5 --- /dev/null +++ b/ltr/models/layers/blocks.py @@ -0,0 +1,36 @@ +from torch import nn + + +def conv_block(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1, bias=True, + batch_norm=True, relu=True, padding_mode='zeros'): + layers = [] + assert padding_mode == 'zeros' or padding_mode == 'replicate' + + if padding_mode == 'replicate' and padding > 0: + assert isinstance(padding, int) + layers.append(nn.ReflectionPad2d(padding)) + padding = 0 + + layers.append(nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, bias=bias)) + if batch_norm: + layers.append(nn.BatchNorm2d(out_planes)) + if relu: + layers.append(nn.ReLU(inplace=True)) + return nn.Sequential(*layers) + + +class LinearBlock(nn.Module): + def __init__(self, in_planes, out_planes, input_sz, bias=True, batch_norm=True, relu=True): + super().__init__() + self.linear = nn.Linear(in_planes*input_sz*input_sz, out_planes, bias=bias) + self.bn = nn.BatchNorm2d(out_planes) if batch_norm else None + self.relu = nn.ReLU(inplace=True) if relu else None + + def forward(self, x): + x = self.linear(x.reshape(x.shape[0], -1)) + if self.bn is not None: + x = self.bn(x.reshape(x.shape[0], x.shape[1], 1, 1)) + if self.relu is not None: + x = self.relu(x) + return x.reshape(x.shape[0], -1) \ No newline at end of file diff --git a/ltr/models/layers/distance.py b/ltr/models/layers/distance.py new file mode 100755 index 0000000..f0b7bc0 --- /dev/null +++ b/ltr/models/layers/distance.py @@ -0,0 +1,41 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class DistanceMap(nn.Module): + """Generate a distance map from a origin center location. + args: + num_bins: Number of bins in the map. + bin_displacement: Displacement of the bins. + """ + def __init__(self, num_bins, bin_displacement=1.0): + super().__init__() + self.num_bins = num_bins + self.bin_displacement = bin_displacement + + def forward(self, center, output_sz): + """Create the distance map. + args: + center: Torch tensor with (y,x) center position. Dims (batch, 2) + output_sz: Size of output distance map. 2-dimensional tuple.""" + + center = center.view(-1,2) + + bin_centers = torch.arange(self.num_bins, dtype=torch.float32, device=center.device).view(1, -1, 1, 1) + + k0 = torch.arange(output_sz[0], dtype=torch.float32, device=center.device).view(1,1,-1,1) + k1 = torch.arange(output_sz[1], dtype=torch.float32, device=center.device).view(1,1,1,-1) + + d0 = k0 - center[:,0].view(-1,1,1,1) + d1 = k1 - center[:,1].view(-1,1,1,1) + + dist = torch.sqrt(d0*d0 + d1*d1) + bin_diff = dist / self.bin_displacement - bin_centers + + bin_val = torch.cat((F.relu(1.0 - torch.abs(bin_diff[:,:-1,:,:]), inplace=True), + (1.0 + bin_diff[:,-1:,:,:]).clamp(0, 1)), dim=1) + + return bin_val + + diff --git a/ltr/models/layers/filter.py b/ltr/models/layers/filter.py new file mode 100755 index 0000000..1f38a20 --- /dev/null +++ b/ltr/models/layers/filter.py @@ -0,0 +1,183 @@ +import torch +import torch.nn.functional as F + + +def apply_filter(feat, filter, dilation_factors=None): + """Applies the filter on the input features (feat). The number of groups is automatically calculated. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + filter: The filter to apply. Must have dimensions (sequences, feat_dim, fH, fW) or (sequences, filters, feat_dim/groups, fH, fW) + output: + scores: Output of filtering. Dimensions (images_in_sequence, sequences, yH, yW) or (images_in_sequence, sequences, filters, yH, yW) + """ + + multiple_filters = (filter.dim() == 5) + + padding = (filter.shape[-2] // 2, filter.shape[-1] // 2) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = filter.shape[1] if multiple_filters else 1 + num_channels = feat.shape[-3] + groups = num_channels // filter.shape[-3] + + assert num_filters % groups == 0 and num_channels % groups == 0 + + if multiple_filters: + if dilation_factors is None: + scores = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), filter.view(-1, *filter.shape[-3:]), + padding=padding, groups=num_sequences*groups) + + return scores.view(num_images, num_sequences, -1, scores.shape[-2], scores.shape[-1]) + else: + scores_all = [] + start_id = 0 + + for d_factor, num_filters_with_d in dilation_factors.items(): + f_d = filter[:, start_id:start_id+num_filters_with_d, ...].contiguous() + + padding_d = [p+d_factor-1 for p in padding] + scores_d = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), + f_d.view(-1, *f_d.shape[-3:]), + padding=padding_d, groups=num_sequences * groups, + dilation=d_factor) + scores_d = scores_d.view(num_images, num_sequences, -1, scores_d.shape[-2], scores_d.shape[-1]) + scores_all.append(scores_d) + start_id += num_filters_with_d + + scores = torch.cat(scores_all, dim=2) + return scores + + scores = F.conv2d(feat.reshape(num_images, -1, feat.shape[-2], feat.shape[-1]), filter, + padding=padding, groups=num_sequences) + + return scores.view(num_images, num_sequences, scores.shape[-2], scores.shape[-1]) + + +def apply_feat_transpose(feat, input, filter_ksz, training=True, groups=1): + """Applies the transposed operation off apply_filter w.r.t. filter itself. Can be used to compute the filter gradient. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + input: Input activation (e.g. residuals). Must have dimensions (images_in_sequence, sequences, yH, yW) or + (images_in_sequence, sequences, filters, yH, yW) + training: Choose the faster implementation whether training or not. + output: + Output of transposed operation. Dimensions (sequences, feat_dim, fH, fW) + """ + + if groups != 1: + raise NotImplementedError('Not implemented other values of group.') + + if training or input.dim() == 5: + return _apply_feat_transpose_v3(feat, input, filter_ksz) + return _apply_feat_transpose_v2(feat, input, filter_ksz) + + +def _apply_feat_transpose_v1(feat, input, filter_ksz): + """This one is slow as hell!!!!""" + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + feat_sz = (feat.shape[-2], feat.shape[-1]) + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + # trans_pad = sz + padding - filter_ksz + trans_pad = [sz + ksz//2 - ksz for sz, ksz in zip(feat_sz, filter_ksz)] + + filter_grad = F.conv_transpose2d(input.flip((2, 3)).view(1, -1, input.shape[-2], input.shape[-1]), + feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + return filter_grad.view(num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=0) + + +def _apply_feat_transpose_v2(feat, input, filter_ksz): + """Fast forward and slow backward""" + + multiple_filters = (input.dim() == 5) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = input.shape[2] if multiple_filters else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [(ksz-1)//2 for ksz in filter_ksz] + + if multiple_filters: + filter_grad = F.conv2d(input.reshape(-1, num_filters, input.shape[-2], input.shape[-1]).permute(1,0,2,3), + feat.reshape(-1, 1, feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + if num_images == 1: + return filter_grad.view(num_filters, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).flip((3,4)).permute(1,0,2,3,4) + return filter_grad.view(num_filters, num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).flip((3,4)).permute(1,0,2,3,4) + + filter_grad = F.conv2d(input.reshape(1, -1, input.shape[-2], input.shape[-1]), + feat.reshape(-1, 1, feat.shape[-2], feat.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + return filter_grad.view(num_images, num_sequences, -1, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=0).flip((2,3)) + + +def _apply_feat_transpose_v3(feat, input, filter_ksz): + """Slow forward fast backward""" + + multiple_filters = (input.dim() == 5) + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + num_filters = input.shape[2] if multiple_filters else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [ksz//2 for ksz in filter_ksz] + + filter_grad = F.conv2d(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]).permute(1,0,2,3), + input.reshape(-1, 1, input.shape[-2], input.shape[-1]), + padding=trans_pad, groups=num_images * num_sequences) + + if multiple_filters: + if num_images == 1: + return filter_grad.view(-1, num_sequences, num_filters, filter_grad.shape[-2], filter_grad.shape[-1]).permute(1,2,0,3,4) + return filter_grad.view(-1, num_images, num_sequences, num_filters, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).permute(1,2,0,3,4) + + if num_images == 1: + return filter_grad.permute(1,0,2,3) + return filter_grad.view(-1, num_images, num_sequences, filter_grad.shape[-2], filter_grad.shape[-1]).sum(dim=1).permute(1,0,2,3) + + +def _apply_feat_transpose_v4(feat, input, filter_ksz): + """Slow forward fast backward""" + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + if isinstance(filter_ksz, int): + filter_ksz = (filter_ksz, filter_ksz) + + trans_pad = [ksz//2 for ksz in filter_ksz] + + filter_grad = F.conv2d(feat.permute(2,1,0,3,4).reshape(feat.shape[-3], -1, feat.shape[-2], feat.shape[-1]), + input.permute(1,0,2,3), + padding=trans_pad, groups=num_sequences) + + return filter_grad.permute(1,0,2,3) + + + +def filter_gradient(feat, filter, label=None, training=True): + """Computes gradient of the filter when applied on the input features and ground truth label. + args: + feat: These are the input features. Must have dimensions (images_in_sequence, sequences, feat_dim, H, W) + filter: The filter to apply. Must have dimensions (sequences, feat_dim, fH, fW) + label: Ground truth label in the L2 loss. Dimensions (images_in_sequence, sequences, yH, yW) + output: + filter_gradient: Dimensions same as input filter (sequences, feat_dim, fH, fW) + """ + + residuals = apply_filter(feat, filter) + if label is not None: + residuals = residuals - label + filter_ksz = (filter.shape[-2], filter.shape[-1]) + return apply_feat_transpose(feat, residuals, filter_ksz, training=training) diff --git a/ltr/models/layers/normalization.py b/ltr/models/layers/normalization.py new file mode 100755 index 0000000..9f14cbc --- /dev/null +++ b/ltr/models/layers/normalization.py @@ -0,0 +1,21 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class InstanceL2Norm(nn.Module): + """Instance L2 normalization. + """ + def __init__(self, size_average=True, eps=1e-5, scale=1.0): + super().__init__() + self.size_average = size_average + self.eps = eps + self.scale = scale + + def forward(self, input): + if self.size_average: + return input * (self.scale * ((input.shape[1] * input.shape[2] * input.shape[3]) / ( + torch.sum((input * input).view(input.shape[0], 1, 1, -1), dim=3, keepdim=True) + self.eps)).sqrt()) + else: + return input * (self.scale / (torch.sum((input * input).view(input.shape[0], 1, 1, -1), dim=3, keepdim=True) + self.eps).sqrt()) + diff --git a/ltr/models/layers/transform.py b/ltr/models/layers/transform.py new file mode 100755 index 0000000..5b55f9c --- /dev/null +++ b/ltr/models/layers/transform.py @@ -0,0 +1,25 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from collections import OrderedDict + + +def interpolate(x, sz): + """Interpolate 4D tensor x to size sz.""" + sz = sz.tolist() if torch.is_tensor(sz) else sz + return F.interpolate(x, sz, mode='bilinear', align_corners=False) if x.shape[-2:] != sz else x + + +class InterpCat(nn.Module): + """Interpolate and concatenate features of different resolutions.""" + + def forward(self, input): + if isinstance(input, (dict, OrderedDict)): + input = list(input.values()) + + output_shape = None + for x in input: + if output_shape is None or output_shape[0] > x.shape[-2]: + output_shape = x.shape[-2:] + + return torch.cat([interpolate(x, output_shape) for x in input], dim=-3) diff --git a/ltr/models/loss/__init__.py b/ltr/models/loss/__init__.py new file mode 100755 index 0000000..f815704 --- /dev/null +++ b/ltr/models/loss/__init__.py @@ -0,0 +1 @@ +from .target_classification import LBHinge diff --git a/ltr/models/loss/kl_regression.py b/ltr/models/loss/kl_regression.py new file mode 100755 index 0000000..c65d7c4 --- /dev/null +++ b/ltr/models/loss/kl_regression.py @@ -0,0 +1,70 @@ +import math +import torch +import torch.nn as nn +from torch.nn import functional as F + + +class KLRegression(nn.Module): + """KL-divergence loss for probabilistic regression. + It is computed using Monte Carlo (MC) samples from an arbitrary distribution.""" + + def __init__(self, eps=0.0): + super().__init__() + self.eps = eps + + def forward(self, scores, sample_density, gt_density, mc_dim=-1): + """Args: + scores: predicted score values + sample_density: probability density of the sample distribution + gt_density: probability density of the ground truth distribution + mc_dim: dimension of the MC samples""" + + exp_val = scores - torch.log(sample_density + self.eps) + + L = torch.logsumexp(exp_val, dim=mc_dim) - math.log(scores.shape[mc_dim]) - \ + torch.mean(scores * (gt_density / (sample_density + self.eps)), dim=mc_dim) + + return L.mean() + + +class MLRegression(nn.Module): + """Maximum likelihood loss for probabilistic regression. + It is computed using Monte Carlo (MC) samples from an arbitrary distribution.""" + + def __init__(self, eps=0.0): + super().__init__() + self.eps = eps + + def forward(self, scores, sample_density, gt_density=None, mc_dim=-1): + """Args: + scores: predicted score values. First sample must be ground-truth + sample_density: probability density of the sample distribution + gt_density: not used + mc_dim: dimension of the MC samples. Only mc_dim=1 supported""" + + assert mc_dim == 1 + assert (sample_density[:,0,...] == -1).all() + + exp_val = scores[:, 1:, ...] - torch.log(sample_density[:, 1:, ...] + self.eps) + + L = torch.logsumexp(exp_val, dim=mc_dim) - math.log(scores.shape[mc_dim] - 1) - scores[:, 0, ...] + loss = L.mean() + return loss + + +class KLRegressionGrid(nn.Module): + """KL-divergence loss for probabilistic regression. + It is computed using the grid integration strategy.""" + + def forward(self, scores, gt_density, grid_dim=-1, grid_scale=1.0): + """Args: + scores: predicted score values + gt_density: probability density of the ground truth distribution + grid_dim: dimension(s) of the grid + grid_scale: area of one grid cell""" + + score_corr = grid_scale * torch.sum(scores * gt_density, dim=grid_dim) + + L = torch.logsumexp(scores, dim=grid_dim) + math.log(grid_scale) - score_corr + + return L.mean() diff --git a/ltr/models/loss/target_classification.py b/ltr/models/loss/target_classification.py new file mode 100755 index 0000000..50eaaa4 --- /dev/null +++ b/ltr/models/loss/target_classification.py @@ -0,0 +1,31 @@ +import torch.nn as nn +import torch +from torch.nn import functional as F + + +class LBHinge(nn.Module): + """Loss that uses a 'hinge' on the lower bound. + This means that for samples with a label value smaller than the threshold, the loss is zero if the prediction is + also smaller than that threshold. + args: + error_matric: What base loss to use (MSE by default). + threshold: Threshold to use for the hinge. + clip: Clip the loss if it is above this value. + """ + def __init__(self, error_metric=nn.MSELoss(), threshold=None, clip=None): + super().__init__() + self.error_metric = error_metric + self.threshold = threshold if threshold is not None else -100 + self.clip = clip + + def forward(self, prediction, label, target_bb=None): + negative_mask = (label < self.threshold).float() + positive_mask = (1.0 - negative_mask) + + prediction = negative_mask * F.relu(prediction) + positive_mask * prediction + + loss = self.error_metric(prediction, positive_mask * label) + + if self.clip is not None: + loss = torch.min(loss, torch.tensor([self.clip], device=loss.device)) + return loss diff --git a/ltr/models/meta/__init__.py b/ltr/models/meta/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/models/meta/__pycache__/__init__.cpython-37.pyc b/ltr/models/meta/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..89f98c7 Binary files /dev/null and b/ltr/models/meta/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/meta/__pycache__/steepestdescent.cpython-37.pyc b/ltr/models/meta/__pycache__/steepestdescent.cpython-37.pyc new file mode 100755 index 0000000..76bb4e0 Binary files /dev/null and b/ltr/models/meta/__pycache__/steepestdescent.cpython-37.pyc differ diff --git a/ltr/models/meta/steepestdescent.py b/ltr/models/meta/steepestdescent.py new file mode 100755 index 0000000..a81af5b --- /dev/null +++ b/ltr/models/meta/steepestdescent.py @@ -0,0 +1,92 @@ +import math +import torch +import torch.nn as nn +from pytracking import TensorList +from ltr.models.layers import activation + + +class GNSteepestDescent(nn.Module): + """General module for steepest descent based meta learning.""" + def __init__(self, residual_module, num_iter=1, compute_losses=False, detach_length=float('Inf'), + parameter_batch_dim=0, residual_batch_dim=0, steplength_reg=0.0, + filter_dilation_factors=None): + super().__init__() + + self.residual_module = residual_module + self.num_iter = num_iter + self.compute_losses = compute_losses + self.detach_length = detach_length + self.steplength_reg = steplength_reg + self._parameter_batch_dim = parameter_batch_dim + self._residual_batch_dim = residual_batch_dim + self.filter_dilation_factors = filter_dilation_factors + + def _sqr_norm(self, x: TensorList, batch_dim=0): + sum_keep_batch_dim = lambda e: e.sum(dim=[d for d in range(e.dim()) if d != batch_dim]) + return sum((x * x).apply(sum_keep_batch_dim)) + + + def _compute_loss(self, res): + return sum((res * res).sum()) / sum(res.numel()) + + + def forward(self, meta_parameter: TensorList, num_iter=None, *args, **kwargs): + # Make sure grad is enabled + torch_grad_enabled = torch.is_grad_enabled() + torch.set_grad_enabled(True) + + num_iter = self.num_iter if num_iter is None else num_iter + + meta_parameter_iterates = [meta_parameter] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + meta_parameter = meta_parameter.detach() + + meta_parameter.requires_grad_(True) + + # Compute residual vector + r = self.residual_module(meta_parameter, filter_dilation_factors=self.filter_dilation_factors, **kwargs) + + if self.compute_losses: + losses.append(self._compute_loss(r)) + + # Compute gradient of loss + u = r.clone() + g = TensorList(torch.autograd.grad(r, meta_parameter, u, create_graph=True)) + + # Multiply gradient with Jacobian + h = TensorList(torch.autograd.grad(g, u, g, create_graph=True)) + + # Compute squared norms + ip_gg = self._sqr_norm(g, batch_dim=self._parameter_batch_dim) + ip_hh = self._sqr_norm(h, batch_dim=self._residual_batch_dim) + + # Compute step length + alpha = ip_gg / (ip_hh + self.steplength_reg * ip_gg).clamp(1e-8) + + # Compute optimization step + step = g.apply(lambda e: alpha.reshape([-1 if d==self._parameter_batch_dim else 1 for d in range(e.dim())]) * e) + + # Add step to parameter + meta_parameter = meta_parameter - step + + meta_parameter_iterates.append(meta_parameter) + + + if self.compute_losses: + losses.append(self._compute_loss(self.residual_module(meta_parameter, + filter_dilation_factors=self.filter_dilation_factors, + **kwargs))) + + # Reset the grad enabled flag + torch.set_grad_enabled(torch_grad_enabled) + if not torch_grad_enabled: + meta_parameter.detach_() + for w in meta_parameter_iterates: + w.detach_() + for l in losses: + l.detach_() + + return meta_parameter, meta_parameter_iterates, losses diff --git a/ltr/models/target_classifier/__init__.py b/ltr/models/target_classifier/__init__.py new file mode 100755 index 0000000..71f76c0 --- /dev/null +++ b/ltr/models/target_classifier/__init__.py @@ -0,0 +1 @@ +from .linear_filter import LinearFilter diff --git a/ltr/models/target_classifier/__pycache__/__init__.cpython-37.pyc b/ltr/models/target_classifier/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..0cc10f6 Binary files /dev/null and b/ltr/models/target_classifier/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/target_classifier/__pycache__/features.cpython-37.pyc b/ltr/models/target_classifier/__pycache__/features.cpython-37.pyc new file mode 100755 index 0000000..4e4068b Binary files /dev/null and b/ltr/models/target_classifier/__pycache__/features.cpython-37.pyc differ diff --git a/ltr/models/target_classifier/__pycache__/initializer.cpython-37.pyc b/ltr/models/target_classifier/__pycache__/initializer.cpython-37.pyc new file mode 100755 index 0000000..7bf634a Binary files /dev/null and b/ltr/models/target_classifier/__pycache__/initializer.cpython-37.pyc differ diff --git a/ltr/models/target_classifier/__pycache__/linear_filter.cpython-37.pyc b/ltr/models/target_classifier/__pycache__/linear_filter.cpython-37.pyc new file mode 100755 index 0000000..0859fe6 Binary files /dev/null and b/ltr/models/target_classifier/__pycache__/linear_filter.cpython-37.pyc differ diff --git a/ltr/models/target_classifier/__pycache__/optimizer.cpython-37.pyc b/ltr/models/target_classifier/__pycache__/optimizer.cpython-37.pyc new file mode 100755 index 0000000..4f65225 Binary files /dev/null and b/ltr/models/target_classifier/__pycache__/optimizer.cpython-37.pyc differ diff --git a/ltr/models/target_classifier/features.py b/ltr/models/target_classifier/features.py new file mode 100755 index 0000000..f4e74f0 --- /dev/null +++ b/ltr/models/target_classifier/features.py @@ -0,0 +1,69 @@ +import torch +from torch import nn +import torch.nn.functional as F +from torchvision.models.resnet import BasicBlock, Bottleneck +from ltr.models.layers.normalization import InstanceL2Norm +from ltr.models.layers.transform import InterpCat + + +def residual_basic_block(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + interp_cat=False, final_relu=False, init_pool=False): + """Construct a network block based on the BasicBlock used in ResNet 18 and 34.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + if interp_cat: + feat_layers.append(InterpCat()) + if init_pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + for i in range(num_blocks): + odim = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim + feat_layers.append(BasicBlock(feature_dim, odim)) + if final_conv: + feat_layers.append(nn.Conv2d(feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if final_relu: + feat_layers.append(nn.ReLU(inplace=True)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + return nn.Sequential(*feat_layers) + + +def residual_basic_block_pool(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + pool=True): + """Construct a network block based on the BasicBlock used in ResNet.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + for i in range(num_blocks): + odim = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim + feat_layers.append(BasicBlock(feature_dim, odim)) + if final_conv: + feat_layers.append(nn.Conv2d(feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + + return nn.Sequential(*feat_layers) + + +def residual_bottleneck(feature_dim=256, num_blocks=1, l2norm=True, final_conv=False, norm_scale=1.0, out_dim=None, + interp_cat=False, final_relu=False, final_pool=False): + """Construct a network block based on the Bottleneck block used in ResNet.""" + if out_dim is None: + out_dim = feature_dim + feat_layers = [] + if interp_cat: + feat_layers.append(InterpCat()) + for i in range(num_blocks): + planes = feature_dim if i < num_blocks - 1 + int(final_conv) else out_dim // 4 + feat_layers.append(Bottleneck(4*feature_dim, planes)) + if final_conv: + feat_layers.append(nn.Conv2d(4*feature_dim, out_dim, kernel_size=3, padding=1, bias=False)) + if final_relu: + feat_layers.append(nn.ReLU(inplace=True)) + if final_pool: + feat_layers.append(nn.MaxPool2d(kernel_size=3, stride=2, padding=1)) + if l2norm: + feat_layers.append(InstanceL2Norm(scale=norm_scale)) + return nn.Sequential(*feat_layers) \ No newline at end of file diff --git a/ltr/models/target_classifier/initializer.py b/ltr/models/target_classifier/initializer.py new file mode 100755 index 0000000..6458105 --- /dev/null +++ b/ltr/models/target_classifier/initializer.py @@ -0,0 +1,248 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +from ltr.external.PreciseRoIPooling.pytorch.prroi_pool import PrRoIPool2D +from ltr.models.layers.blocks import conv_block +import math + + +class FilterPool(nn.Module): + """Pool the target region in a feature map. + args: + filter_size: Size of the filter. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region.""" + + def __init__(self, filter_size=1, feature_stride=16, pool_square=False): + super().__init__() + self.prroi_pool = PrRoIPool2D(filter_size, filter_size, 1/feature_stride) + self.pool_square = pool_square + + def forward(self, feat, bb): + """Pool the regions in bb. + args: + feat: Input feature maps. Dims (num_samples, feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (num_samples, 4). + returns: + pooled_feat: Pooled features. Dims (num_samples, feat_dim, wH, wW).""" + + # Add batch_index to rois + bb = bb.reshape(-1,4) + num_images_total = bb.shape[0] + batch_index = torch.arange(num_images_total, dtype=torch.float32).reshape(-1, 1).to(bb.device) + + # input bb is in format xywh, convert it to x0y0x1y1 format + pool_bb = bb.clone() + + if self.pool_square: + bb_sz = pool_bb[:, 2:4].prod(dim=1, keepdim=True).sqrt() + pool_bb[:, :2] += pool_bb[:, 2:]/2 - bb_sz/2 + pool_bb[:, 2:] = bb_sz + + pool_bb[:, 2:4] = pool_bb[:, 0:2] + pool_bb[:, 2:4] + roi1 = torch.cat((batch_index, pool_bb), dim=1) + + return self.prroi_pool(feat, roi1) + + + +class FilterInitializer(nn.Module): + """Initializes a target classification filter by applying a number of conv layers before and after pooling the target region. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end. + num_filter_pre_convs: Conv layers before pooling. + num_filter_post_convs: Conv layers after pooling.""" + + def __init__(self, filter_size=1, feature_dim=256, feature_stride=16, pool_square=False, filter_norm=True, + num_filter_pre_convs=1, num_filter_post_convs=0): + super().__init__() + + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Make pre conv + pre_conv_layers = [] + for i in range(num_filter_pre_convs): + pre_conv_layers.append(conv_block(feature_dim, feature_dim, kernel_size=3, padding=1)) + self.filter_pre_layers = nn.Sequential(*pre_conv_layers) if pre_conv_layers else None + + # Make post conv + post_conv_layers = [] + for i in range(num_filter_post_convs): + post_conv_layers.append(conv_block(feature_dim, feature_dim, kernel_size=1, padding=0)) + post_conv_layers.append(nn.Conv2d(feature_dim, feature_dim, kernel_size=1, padding=0)) + self.filter_post_layers = nn.Sequential(*post_conv_layers) + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = bb.shape[0] if bb.dim() == 3 else 1 + + if self.filter_pre_layers is not None: + feat = self.filter_pre_layers(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1])) + + feat_post = self.filter_pool(feat, bb) + weights = self.filter_post_layers(feat_post) + + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights + + +class FilterInitializerLinear(nn.Module): + """Initializes a target classification filter by applying a linear conv layer and then pooling the target region. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end. + conv_ksz: Kernel size of the conv layer before pooling.""" + + def __init__(self, filter_size=1, feature_dim=256, feature_stride=16, pool_square=False, filter_norm=True, + conv_ksz=3, init_weights='default'): + super().__init__() + + self.filter_conv = nn.Conv2d(feature_dim, feature_dim, kernel_size=conv_ksz, padding=conv_ksz // 2) + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + if init_weights == 'default': + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif init_weights == 'zero': + m.weight.data.zero_() + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = feat.shape[0] + + feat = self.filter_conv(feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1])) + + weights = self.filter_pool(feat, bb) + + # If multiple input images, compute the initial filter as the average filter. + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights + + + +class FilterInitializerZero(nn.Module): + """Initializes a target classification filter with zeros. + args: + filter_size: Size of the filter. + feature_dim: Input feature dimentionality.""" + + def __init__(self, filter_size=1, feature_dim=256): + super().__init__() + + self.filter_size = (feature_dim, filter_size, filter_size) + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + + return feat.new_zeros(num_sequences, self.filter_size[0], self.filter_size[1], self.filter_size[2]) + + +class FilterInitializerSiamese(nn.Module): + """Initializes a target classification filter by only pooling the target region (similar to Siamese trackers). + args: + filter_size: Size of the filter. + feature_stride: Input feature stride. + pool_square: Do a square pooling instead of pooling the exact target region. + filter_norm: Normalize the output filter with its size in the end.""" + + def __init__(self, filter_size=1, feature_stride=16, pool_square=False, filter_norm=True): + super().__init__() + + self.filter_pool = FilterPool(filter_size=filter_size, feature_stride=feature_stride, pool_square=pool_square) + self.filter_norm = filter_norm + + # Init weights + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + + def forward(self, feat, bb): + """Runs the initializer module. + Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + returns: + weights: The output weights. Dims (sequences, feat_dim, wH, wW).""" + + num_images = feat.shape[0] + + feat = feat.reshape(-1, feat.shape[-3], feat.shape[-2], feat.shape[-1]) + weights = self.filter_pool(feat, bb) + + if num_images > 1: + weights = torch.mean(weights.reshape(num_images, -1, weights.shape[-3], weights.shape[-2], weights.shape[-1]), dim=0) + + if self.filter_norm: + weights = weights / (weights.shape[1] * weights.shape[2] * weights.shape[3]) + + return weights diff --git a/ltr/models/target_classifier/linear_filter.py b/ltr/models/target_classifier/linear_filter.py new file mode 100755 index 0000000..600cc50 --- /dev/null +++ b/ltr/models/target_classifier/linear_filter.py @@ -0,0 +1,131 @@ +import torch.nn as nn +import ltr.models.layers.filter as filter_layer +import math + + +class LinearFilter(nn.Module): + """Target classification filter module. + args: + filter_size: Size of filter (int). + filter_initialize: Filter initializer module. + filter_optimizer: Filter optimizer module. + feature_extractor: Feature extractor module applied to the input backbone features.""" + + def __init__(self, filter_size, filter_initializer, filter_optimizer=None, feature_extractor=None): + super().__init__() + + self.filter_size = filter_size + + # Modules + self.filter_initializer = filter_initializer + self.filter_optimizer = filter_optimizer + self.feature_extractor = feature_extractor + + # Init weights + for m in self.feature_extractor.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + if m.bias is not None: + m.bias.data.zero_() + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def forward(self, train_feat, test_feat, train_bb, *args, **kwargs): + """Learns a target classification filter based on the train samples and return the resulting classification + scores on the test samples. + The forward function is ONLY used for training. Call the individual functions during tracking. + args: + train_feat: Backbone features for the train samples (4 or 5 dims). + test_feat: Backbone features for the test samples (4 or 5 dims). + trian_bb: Target boxes (x,y,w,h) for the train samples in image coordinates. Dims (images, sequences, 4). + *args, **kwargs: These are passed to the optimizer module. + returns: + test_scores: Classification scores on the test samples.""" + + assert train_bb.dim() == 3 + + num_sequences = train_bb.shape[1] + + if train_feat.dim() == 5: + train_feat = train_feat.reshape(-1, *train_feat.shape[-3:]) + if test_feat.dim() == 5: + test_feat = test_feat.reshape(-1, *test_feat.shape[-3:]) + + # Extract features + train_feat = self.extract_classification_feat(train_feat, num_sequences) + test_feat = self.extract_classification_feat(test_feat, num_sequences) + + # Train filter + filter, filter_iter, losses = self.get_filter(train_feat, train_bb, *args, **kwargs) + + # Classify samples using all return filters + test_scores = [self.classify(f, test_feat) for f in filter_iter] + + return test_scores + + def extract_classification_feat(self, feat, num_sequences=None): + """Extract classification features based on the input backbone features.""" + if self.feature_extractor is None: + return feat + if num_sequences is None: + return self.feature_extractor(feat) + + output = self.feature_extractor(feat) + return output.reshape(-1, num_sequences, *output.shape[-3:]) + + def classify(self, weights, feat): + """Run classifier (filter) on the features (feat).""" + + scores = filter_layer.apply_filter(feat, weights) + + return scores + + def get_filter(self, feat, bb, *args, **kwargs): + """Outputs the learned filter based on the input features (feat) and target boxes (bb) by running the + filter initializer and optimizer. Note that [] denotes an optional dimension. + args: + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + *args, **kwargs: These are passed to the optimizer module. + returns: + weights: The final oprimized weights. Dims (sequences, feat_dim, wH, wW). + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + weights = self.filter_initializer(feat, bb) + + if self.filter_optimizer is not None: + weights, weights_iter, losses = self.filter_optimizer(weights, feat=feat, bb=bb, *args, **kwargs) + else: + weights_iter = [weights] + losses = None + + return weights, weights_iter, losses + + def train_classifier(self, backbone_feat, bb): + num_sequences = bb.shape[1] + + if backbone_feat.dim() == 5: + backbone_feat = backbone_feat.reshape(-1, *backbone_feat.shape[-3:]) + + # Extract features + train_feat = self.extract_classification_feat(backbone_feat, num_sequences) + + # Get filters from each iteration + final_filter, _, train_losses = self.get_filter(train_feat, bb) + return final_filter, train_losses + + def track_frame(self, filter_weights, backbone_feat): + if backbone_feat.dim() == 5: + num_sequences = backbone_feat.shape[1] + backbone_feat = backbone_feat.reshape(-1, *backbone_feat.shape[-3:]) + else: + num_sequences = None + + test_feat = self.extract_classification_feat(backbone_feat, num_sequences) + + scores = filter_layer.apply_filter(test_feat, filter_weights) + + return scores \ No newline at end of file diff --git a/ltr/models/target_classifier/optimizer.py b/ltr/models/target_classifier/optimizer.py new file mode 100755 index 0000000..c99c23f --- /dev/null +++ b/ltr/models/target_classifier/optimizer.py @@ -0,0 +1,439 @@ +import torch.nn as nn +import torch +import torch.nn.functional as F +import ltr.models.layers.filter as filter_layer +import ltr.models.layers.activation as activation +from ltr.models.layers.distance import DistanceMap +import math + + + +class DiMPSteepestDescentGN(nn.Module): + """Optimizer module for DiMP. + It unrolls the steepest descent with Gauss-Newton iterations to optimize the target filter. + Moreover it learns parameters in the loss itself, as described in the DiMP paper. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + init_filter_reg: Initial filter regularization weight (which is then learned). + init_gauss_sigma: The standard deviation to use for the initialization of the label function. + num_dist_bins: Number of distance bins used for learning the loss label, mask and weight. + bin_displacement: The displacement of the bins (level of discritization). + mask_init_factor: Parameter controlling the initialization of the target mask. + score_act: Type of score activation (target mask computation) to use. The default 'relu' is what is described in the paper. + act_param: Parameter for the score_act. + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + mask_act: What activation to do on the output of the mask computation ('sigmoid' or 'linear'). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, + init_filter_reg=1e-2, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, mask_init_factor=4.0, + score_act='relu', act_param=None, min_filter_reg=1e-3, mask_act='sigmoid', + detach_length=float('Inf'), alpha_eps=0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.distance_map = DistanceMap(num_dist_bins, bin_displacement) + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.alpha_eps = alpha_eps + + # Distance coordinates + d = torch.arange(num_dist_bins, dtype=torch.float32).reshape(1,-1,1,1) * bin_displacement + if init_gauss_sigma == 0: + init_gauss = torch.zeros_like(d) + init_gauss[0,0,0,0] = 1 + else: + init_gauss = torch.exp(-1/2 * (d / init_gauss_sigma)**2) + + # Module that predicts the target label function (y in the paper) + self.label_map_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.label_map_predictor.weight.data = init_gauss - init_gauss.min() + + # Module that predicts the target mask (m in the paper) + mask_layers = [nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False)] + if mask_act == 'sigmoid': + mask_layers.append(nn.Sigmoid()) + init_bias = 0.0 + elif mask_act == 'linear': + init_bias = 0.5 + else: + raise ValueError('Unknown activation') + self.target_mask_predictor = nn.Sequential(*mask_layers) + self.target_mask_predictor[0].weight.data = mask_init_factor * torch.tanh(2.0 - d) + init_bias + + # Module that predicts the residual weights (v in the paper) + self.spatial_weight_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.spatial_weight_predictor.weight.data.fill_(1.0) + + # The score actvation and its derivative + if score_act == 'bentpar': + self.score_activation = activation.BentIdentPar(act_param) + self.score_activation_deriv = activation.BentIdentParDeriv(act_param) + elif score_act == 'relu': + self.score_activation = activation.LeakyReluPar() + self.score_activation_deriv = activation.LeakyReluParDeriv() + else: + raise ValueError('Unknown score activation') + + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute distance map + dmap_offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).reshape(-1, 2).flip((1,)) - dmap_offset + dist_map = self.distance_map(center, output_sz) + + # Compute label map masks and weight + label_map = self.label_map_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + target_mask = self.target_mask_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + spatial_weight = self.spatial_weight_predictor(dist_map).reshape(num_images, num_sequences, *dist_map.shape[-2:]) + + # Get total sample weights + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) * spatial_weight + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(num_images, num_sequences, 1, 1) * spatial_weight + + backprop_through_learning = (self.detach_length > 0) + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if not backprop_through_learning or (i > 0 and i % self.detach_length == 0): + weights = weights.detach() + + # Compute residuals + scores = filter_layer.apply_filter(feat, weights) + scores_act = self.score_activation(scores, target_mask) + score_mask = self.score_activation_deriv(scores, target_mask) + residuals = sample_weight * (scores_act - label_map) + + if compute_losses: + losses.append(((residuals**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + # Compute gradient + residuals_mapped = score_mask * (sample_weight * residuals) + weights_grad = filter_layer.apply_feat_transpose(feat, residuals_mapped, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Jacobian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + scores_grad = sample_weight * (score_mask * scores_grad) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = ((scores_grad * scores_grad).reshape(num_images, num_sequences, -1).sum(dim=(0,2)) + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + scores = self.score_activation(scores, target_mask) + losses.append((((sample_weight * (scores - label_map))**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + return weights, weight_iterates, losses + + + +class DiMPL2SteepestDescentGN(nn.Module): + """A simpler optimizer module that uses L2 loss. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + gauss_sigma: The standard deviation of the label function. + hinge_threshold: Threshold for the hinge-based loss (see DiMP paper). + init_filter_reg: Initial filter regularization weight (which is then learned). + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, gauss_sigma=1.0, hinge_threshold=-999, + init_filter_reg=1e-2, min_filter_reg=1e-3, detach_length=float('Inf'), alpha_eps=0.0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.hinge_threshold = hinge_threshold + self.gauss_sigma = gauss_sigma + self.alpha_eps = alpha_eps + + def get_label(self, center, output_sz): + center = center.reshape(center.shape[0], -1, center.shape[-1]) + k0 = torch.arange(output_sz[0], dtype=torch.float32).reshape(1, 1, -1, 1).to(center.device) + k1 = torch.arange(output_sz[1], dtype=torch.float32).reshape(1, 1, 1, -1).to(center.device) + g0 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * (k0 - center[:,:,0].reshape(*center.shape[:2], 1, 1)) ** 2) + g1 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * (k1 - center[:,:,1].reshape(*center.shape[:2], 1, 1)) ** 2) + gauss = g0 * g1 + return gauss + + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute distance map + dmap_offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).flip((-1,)) - dmap_offset + label_map = self.get_label(center, output_sz) + target_mask = (label_map > self.hinge_threshold).float() + label_map *= target_mask + + # Get total sample weights + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(num_images, num_sequences, 1, 1) + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + weights = weights.detach() + + # Compute residuals + scores = filter_layer.apply_filter(feat, weights) + scores_act = target_mask * scores + (1.0 - target_mask) * F.relu(scores) + score_mask = target_mask + (1.0 - target_mask) * (scores.detach() > 0).float() + residuals = sample_weight * (scores_act - label_map) + + if compute_losses: + losses.append(((residuals**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + # Compute gradient + residuals_mapped = score_mask * (sample_weight * residuals) + weights_grad = filter_layer.apply_feat_transpose(feat, residuals_mapped, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Jacobian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + scores_grad = sample_weight * (score_mask * scores_grad) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = ((scores_grad * scores_grad).reshape(num_images, num_sequences, -1).sum(dim=(0,2)) + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + scores = target_mask * scores + (1.0 - target_mask) * F.relu(scores) + losses.append((((sample_weight * (scores - label_map))**2).sum() + reg_weight * (weights**2).sum())/num_sequences) + + return weights, weight_iterates, losses + + +class PrDiMPSteepestDescentNewton(nn.Module): + """Optimizer module for PrDiMP. + It unrolls the steepest descent with Newton iterations to optimize the target filter. See the PrDiMP paper. + args: + num_iter: Number of default optimization iterations. + feat_stride: The stride of the input feature. + init_step_length: Initial scaling of the step length (which is then learned). + init_filter_reg: Initial filter regularization weight (which is then learned). + gauss_sigma: The standard deviation to use for the label density function. + min_filter_reg: Enforce a minimum value on the regularization (helps stability sometimes). + detach_length: Detach the filter every n-th iteration. Default is to never detech, i.e. 'Inf'. + alpha_eps: Term in the denominator of the steepest descent that stabalizes learning. + init_uni_weight: Weight of uniform label distribution. + normalize_label: Wheter to normalize the label distribution. + label_shrink: How much to shrink to label distribution. + softmax_reg: Regularization in the denominator of the SoftMax. + label_threshold: Threshold probabilities smaller than this. + """ + def __init__(self, num_iter=1, feat_stride=16, init_step_length=1.0, + init_filter_reg=1e-2, gauss_sigma=1.0, min_filter_reg=1e-3, detach_length=float('Inf'), + alpha_eps=0.0, init_uni_weight=None, normalize_label=False, label_shrink=0, softmax_reg=None, label_threshold=0.0): + super().__init__() + + self.num_iter = num_iter + self.feat_stride = feat_stride + self.log_step_length = nn.Parameter(math.log(init_step_length) * torch.ones(1)) + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.gauss_sigma = gauss_sigma + self.min_filter_reg = min_filter_reg + self.detach_length = detach_length + self.alpha_eps = alpha_eps + self.uni_weight = 0 if init_uni_weight is None else init_uni_weight + self.normalize_label = normalize_label + self.label_shrink = label_shrink + self.softmax_reg = softmax_reg + self.label_threshold = label_threshold + + def get_label_density(self, center, output_sz): + center = center.reshape(center.shape[0], -1, center.shape[-1]) + k0 = torch.arange(output_sz[0], dtype=torch.float32).reshape(1, 1, -1, 1).to(center.device) + k1 = torch.arange(output_sz[1], dtype=torch.float32).reshape(1, 1, 1, -1).to(center.device) + dist0 = (k0 - center[:,:,0].reshape(*center.shape[:2], 1, 1)) ** 2 + dist1 = (k1 - center[:,:,1].reshape(*center.shape[:2], 1, 1)) ** 2 + if self.gauss_sigma == 0: + dist0_view = dist0.reshape(-1, dist0.shape[-2]) + dist1_view = dist1.reshape(-1, dist1.shape[-1]) + one_hot0 = torch.zeros_like(dist0_view) + one_hot1 = torch.zeros_like(dist1_view) + one_hot0[torch.arange(one_hot0.shape[0]), dist0_view.argmin(dim=-1)] = 1.0 + one_hot1[torch.arange(one_hot1.shape[0]), dist1_view.argmin(dim=-1)] = 1.0 + gauss = one_hot0.reshape(dist0.shape) * one_hot1.reshape(dist1.shape) + else: + g0 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * dist0) + g1 = torch.exp(-1.0 / (2 * self.gauss_sigma ** 2) * dist1) + gauss = (g0 / (2*math.pi*self.gauss_sigma**2)) * g1 + gauss = gauss * (gauss > self.label_threshold).float() + if self.normalize_label: + gauss /= (gauss.sum(dim=(-2,-1), keepdim=True) + 1e-8) + label_dens = (1.0 - self.label_shrink)*((1.0 - self.uni_weight) * gauss + self.uni_weight / (output_sz[0]*output_sz[1])) + return label_dens + + def forward(self, weights, feat, bb, sample_weight=None, num_iter=None, compute_losses=True): + """Runs the optimizer module. + Note that [] denotes an optional dimension. + args: + weights: Initial weights. Dims (sequences, feat_dim, wH, wW). + feat: Input feature maps. Dims (images_in_sequence, [sequences], feat_dim, H, W). + bb: Target bounding boxes (x, y, w, h) in the image coords. Dims (images_in_sequence, [sequences], 4). + sample_weight: Optional weight for each sample. Dims: (images_in_sequence, [sequences]). + num_iter: Number of iterations to run. + compute_losses: Whether to compute the (train) loss in each iteration. + returns: + weights: The final oprimized weights. + weight_iterates: The weights computed in each iteration (including initial input and final output). + losses: Train losses.""" + + # Sizes + num_iter = self.num_iter if num_iter is None else num_iter + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (weights.shape[-2], weights.shape[-1]) + output_sz = (feat.shape[-2] + (weights.shape[-2] + 1) % 2, feat.shape[-1] + (weights.shape[-1] + 1) % 2) + + # Get learnable scalars + step_length_factor = torch.exp(self.log_step_length) + reg_weight = (self.filter_reg*self.filter_reg).clamp(min=self.min_filter_reg**2) + + # Compute label density + offset = (torch.Tensor(filter_sz).to(bb.device) % 2) / 2.0 + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).flip((-1,)) - offset + label_density = self.get_label_density(center, output_sz) + + # Get total sample weights + if sample_weight is None: + sample_weight = torch.Tensor([1.0 / num_images]).to(feat.device) + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.reshape(num_images, num_sequences, 1, 1) + + exp_reg = 0 if self.softmax_reg is None else math.exp(self.softmax_reg) + def _compute_loss(scores, weights): + return torch.sum(sample_weight.reshape(sample_weight.shape[0], -1) * + (torch.log(scores.exp().sum(dim=(-2, -1)) + exp_reg) - (label_density * scores).sum(dim=(-2, -1)))) / num_sequences +\ + reg_weight * (weights ** 2).sum() / num_sequences + + weight_iterates = [weights] + losses = [] + + for i in range(num_iter): + if i > 0 and i % self.detach_length == 0: + weights = weights.detach() + + # Compute "residuals" + scores = filter_layer.apply_filter(feat, weights) + scores_softmax = activation.softmax_reg(scores.reshape(num_images, num_sequences, -1), dim=2, reg=self.softmax_reg).reshape(scores.shape) + res = sample_weight*(scores_softmax - label_density) + + if compute_losses: + losses.append(_compute_loss(scores, weights)) + + # Compute gradient + weights_grad = filter_layer.apply_feat_transpose(feat, res, filter_sz, training=self.training) + \ + reg_weight * weights + + # Map the gradient with the Hessian + scores_grad = filter_layer.apply_filter(feat, weights_grad) + sm_scores_grad = scores_softmax * scores_grad + hes_scores_grad = sm_scores_grad - scores_softmax * torch.sum(sm_scores_grad, dim=(-2,-1), keepdim=True) + grad_hes_grad = (scores_grad * hes_scores_grad).reshape(num_images, num_sequences, -1).sum(dim=2).clamp(min=0) + grad_hes_grad = (sample_weight.reshape(sample_weight.shape[0], -1) * grad_hes_grad).sum(dim=0) + + # Compute optimal step length + alpha_num = (weights_grad * weights_grad).sum(dim=(1,2,3)) + alpha_den = (grad_hes_grad + (reg_weight + self.alpha_eps) * alpha_num).clamp(1e-8) + alpha = alpha_num / alpha_den + + # Update filter + weights = weights - (step_length_factor * alpha.reshape(-1, 1, 1, 1)) * weights_grad + + # Add the weight iterate + weight_iterates.append(weights) + + if compute_losses: + scores = filter_layer.apply_filter(feat, weights) + losses.append(_compute_loss(scores, weights)) + + return weights, weight_iterates, losses diff --git a/ltr/models/target_classifier/residual_modules.py b/ltr/models/target_classifier/residual_modules.py new file mode 100755 index 0000000..fcc8772 --- /dev/null +++ b/ltr/models/target_classifier/residual_modules.py @@ -0,0 +1,85 @@ +import torch +import torch.nn as nn +import math +import ltr.models.layers.filter as filter_layer +import ltr.models.layers.activation as activation +from ltr.models.layers.distance import DistanceMap +from pytracking import TensorList + + +class LinearFilterLearnGen(nn.Module): + def __init__(self, feat_stride=16, init_filter_reg=1e-2, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, score_act='bentpar', act_param=None, mask_act='sigmoid'): + super().__init__() + + self.filter_reg = nn.Parameter(init_filter_reg * torch.ones(1)) + self.feat_stride = feat_stride + self.distance_map = DistanceMap(num_dist_bins, bin_displacement) + + # Distance coordinates + d = torch.arange(num_dist_bins, dtype=torch.float32).reshape(1,-1,1,1) * bin_displacement + if init_gauss_sigma == 0: + init_gauss = torch.zeros_like(d) + init_gauss[0,0,0,0] = 1 + else: + init_gauss = torch.exp(-1/2 * (d / init_gauss_sigma)**2) + + self.label_map_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.label_map_predictor.weight.data = init_gauss - init_gauss.min() + + mask_layers = [nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False)] + if mask_act == 'sigmoid': + mask_layers.append(nn.Sigmoid()) + init_bias = 0.0 + elif mask_act == 'linear': + init_bias = 0.5 + else: + raise ValueError('Unknown activation') + self.target_mask_predictor = nn.Sequential(*mask_layers) + self.target_mask_predictor[0].weight.data = mask_init_factor * torch.tanh(2.0 - d) + init_bias + + self.spatial_weight_predictor = nn.Conv2d(num_dist_bins, 1, kernel_size=1, bias=False) + self.spatial_weight_predictor.weight.data.fill_(1.0) + + if score_act == 'bentpar': + self.score_activation = activation.BentIdentPar(act_param) + elif score_act == 'relu': + self.score_activation = activation.LeakyReluPar() + else: + raise ValueError('Unknown activation') + + + def forward(self, meta_parameter: TensorList, feat, bb, sample_weight=None, is_distractor=None): + filter = meta_parameter[0] + + num_images = feat.shape[0] + num_sequences = feat.shape[1] if feat.dim() == 5 else 1 + filter_sz = (filter.shape[-2], filter.shape[-1]) + + # Compute scores + scores = filter_layer.apply_filter(feat, filter) + + # Compute distance map + center = ((bb[..., :2] + bb[..., 2:] / 2) / self.feat_stride).reshape(-1, 2).flip((1,)) + if is_distractor is not None: + center[is_distractor.reshape(-1), :] = 99999 + dist_map = self.distance_map(center, scores.shape[-2:]) + + # Compute label map masks and weight + label_map = self.label_map_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + target_mask = self.target_mask_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + spatial_weight = self.spatial_weight_predictor(dist_map).reshape(num_images, num_sequences, dist_map.shape[-2], dist_map.shape[-1]) + + if sample_weight is None: + sample_weight = math.sqrt(1.0 / num_images) * spatial_weight + elif isinstance(sample_weight, torch.Tensor): + sample_weight = sample_weight.sqrt().reshape(-1, 1, 1, 1) * spatial_weight + + # Compute data residual + scores_act = self.score_activation(scores, target_mask) + data_residual = sample_weight * (scores_act - label_map) + + # Compute regularization residual. Put batch in second dimension + reg_residual = self.filter_reg*filter.reshape(1, num_sequences, -1) + + return TensorList([data_residual, reg_residual]) diff --git a/ltr/models/tracking/__init__.py b/ltr/models/tracking/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/models/tracking/__pycache__/__init__.cpython-37.pyc b/ltr/models/tracking/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..0f530f8 Binary files /dev/null and b/ltr/models/tracking/__pycache__/__init__.cpython-37.pyc differ diff --git a/ltr/models/tracking/__pycache__/dimpnet.cpython-37.pyc b/ltr/models/tracking/__pycache__/dimpnet.cpython-37.pyc new file mode 100755 index 0000000..1a267e5 Binary files /dev/null and b/ltr/models/tracking/__pycache__/dimpnet.cpython-37.pyc differ diff --git a/ltr/models/tracking/__pycache__/kysnet.cpython-37.pyc b/ltr/models/tracking/__pycache__/kysnet.cpython-37.pyc new file mode 100755 index 0000000..3e399ea Binary files /dev/null and b/ltr/models/tracking/__pycache__/kysnet.cpython-37.pyc differ diff --git a/ltr/models/tracking/dimpnet.py b/ltr/models/tracking/dimpnet.py new file mode 100755 index 0000000..e4f8504 --- /dev/null +++ b/ltr/models/tracking/dimpnet.py @@ -0,0 +1,342 @@ +import math +import torch +import torch.nn as nn +from collections import OrderedDict +from ltr.models.meta import steepestdescent +import ltr.models.target_classifier.linear_filter as target_clf +import ltr.models.target_classifier.features as clf_features +import ltr.models.target_classifier.initializer as clf_initializer +import ltr.models.target_classifier.optimizer as clf_optimizer +import ltr.models.bbreg as bbmodels +import ltr.models.backbone as backbones +from ltr import model_constructor + + +class DiMPnet(nn.Module): + """The DiMP network. + args: + feature_extractor: Backbone feature extractor network. Must return a dict of feature maps + classifier: Target classification module. + bb_regressor: Bounding box regression module. + classification_layer: Name of the backbone feature layer to use for classification. + bb_regressor_layer: Names of the backbone layers to use for bounding box regression.""" + + def __init__(self, feature_extractor, classifier, bb_regressor, classification_layer, bb_regressor_layer): + super().__init__() + + self.feature_extractor = feature_extractor + self.classifier = classifier + self.bb_regressor = bb_regressor + self.classification_layer = [classification_layer] if isinstance(classification_layer, str) else classification_layer + self.bb_regressor_layer = bb_regressor_layer + self.output_layers = sorted(list(set(self.classification_layer + self.bb_regressor_layer))) + + + def forward(self, train_imgs, test_imgs, train_bb, test_proposals, *args, **kwargs): + """Runs the DiMP network the way it is applied during training. + The forward function is ONLY used for training. Call the individual functions during tracking. + args: + train_imgs: Train image samples (images, sequences, 3, H, W). + test_imgs: Test image samples (images, sequences, 3, H, W). + trian_bb: Target boxes (x,y,w,h) for the train images. Dims (images, sequences, 4). + test_proposals: Proposal boxes to use for the IoUNet (bb_regressor) module. + *args, **kwargs: These are passed to the classifier module. + returns: + test_scores: Classification scores on the test samples. + iou_pred: Predicted IoU scores for the test_proposals.""" + + assert train_imgs.dim() == 5 and test_imgs.dim() == 5, 'Expect 5 dimensional inputs' + + # Extract backbone features + train_feat = self.extract_backbone_features(train_imgs.reshape(-1, *train_imgs.shape[-3:])) + test_feat = self.extract_backbone_features(test_imgs.reshape(-1, *test_imgs.shape[-3:])) + + # Classification features + train_feat_clf = self.get_backbone_clf_feat(train_feat) + test_feat_clf = self.get_backbone_clf_feat(test_feat) + + # Run classifier module + target_scores = self.classifier(train_feat_clf, test_feat_clf, train_bb, *args, **kwargs) + + # Get bb_regressor features + train_feat_iou = self.get_backbone_bbreg_feat(train_feat) + test_feat_iou = self.get_backbone_bbreg_feat(test_feat) + + # Run the IoUNet module + iou_pred = self.bb_regressor(train_feat_iou, test_feat_iou, train_bb, test_proposals) + + return target_scores, iou_pred + + def get_backbone_clf_feat(self, backbone_feat): + feat = OrderedDict({l: backbone_feat[l] for l in self.classification_layer}) + if len(self.classification_layer) == 1: + return feat[self.classification_layer[0]] + return feat + + def get_backbone_bbreg_feat(self, backbone_feat): + return [backbone_feat[l] for l in self.bb_regressor_layer] + + def extract_classification_feat(self, backbone_feat): + return self.classifier.extract_classification_feat(self.get_backbone_clf_feat(backbone_feat)) + + def extract_backbone_features(self, im, layers=None): + if layers is None: + layers = self.output_layers + return self.feature_extractor(im, layers) + + def extract_features(self, im, layers=None): + if layers is None: + layers = self.bb_regressor_layer + ['classification'] + if 'classification' not in layers: + return self.feature_extractor(im, layers) + backbone_layers = sorted(list(set([l for l in layers + self.classification_layer if l != 'classification']))) + all_feat = self.feature_extractor(im, backbone_layers) + all_feat['classification'] = self.extract_classification_feat(all_feat) + return OrderedDict({l: all_feat[l] for l in layers}) + + + +@model_constructor +def dimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + score_act='relu', act_param=None, target_mask_act='sigmoid', + detach_length=float('Inf'), frozen_backbone_layers=()): + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPSteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, init_gauss_sigma=init_gauss_sigma, + num_dist_bins=num_dist_bins, + bin_displacement=bin_displacement, + mask_init_factor=mask_init_factor, + score_act=score_act, act_param=act_param, mask_act=target_mask_act, + detach_length=detach_length) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def dimpnet50(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=0, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=512, init_gauss_sigma=1.0, num_dist_bins=5, bin_displacement=1.0, + mask_init_factor=4.0, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + score_act='relu', act_param=None, target_mask_act='sigmoid', + detach_length=float('Inf'), frozen_backbone_layers=()): + + # Backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + if classification_layer == 'layer3': + feature_dim = 256 + elif classification_layer == 'layer4': + feature_dim = 512 + else: + raise Exception + + clf_feature_extractor = clf_features.residual_bottleneck(feature_dim=feature_dim, + num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPSteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, init_gauss_sigma=init_gauss_sigma, + num_dist_bins=num_dist_bins, + bin_displacement=bin_displacement, + mask_init_factor=mask_init_factor, + score_act=score_act, act_param=act_param, mask_act=target_mask_act, + detach_length=detach_length) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + + +@model_constructor +def L2dimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), hinge_threshold=-999, gauss_sigma=1.0, alpha_eps=0): + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPL2SteepestDescentGN(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, hinge_threshold=hinge_threshold, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def klcedimpnet18(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=1, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=256, gauss_sigma=1.0, + iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), alpha_eps=0.0, train_feature_extractor=True, + init_uni_weight=None, optim_min_reg=1e-3, init_initializer='default', normalize_label=False, + label_shrink=0, softmax_reg=None, label_threshold=0, final_relu=False, init_pool_square=False, + frozen_backbone_layers=()): + + if not train_feature_extractor: + frozen_backbone_layers = 'all' + + # Backbone + backbone_net = backbones.resnet18(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_basic_block(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim, final_relu=final_relu) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim, init_weights=init_initializer, + pool_square=init_pool_square) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.PrDiMPSteepestDescentNewton(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps, + init_uni_weight=init_uni_weight, + min_filter_reg=optim_min_reg, normalize_label=normalize_label, + label_shrink=label_shrink, softmax_reg=softmax_reg, + label_threshold=label_threshold) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net + + +@model_constructor +def klcedimpnet50(filter_size=1, optim_iter=5, optim_init_step=1.0, optim_init_reg=0.01, + classification_layer='layer3', feat_stride=16, backbone_pretrained=True, clf_feat_blocks=0, + clf_feat_norm=True, init_filter_norm=False, final_conv=True, + out_feature_dim=512, gauss_sigma=1.0, + iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + detach_length=float('Inf'), alpha_eps=0.0, train_feature_extractor=True, + init_uni_weight=None, optim_min_reg=1e-3, init_initializer='default', normalize_label=False, + label_shrink=0, softmax_reg=None, label_threshold=0, final_relu=False, frozen_backbone_layers=()): + + if not train_feature_extractor: + frozen_backbone_layers = 'all' + + # Backbone + backbone_net = backbones.resnet50(pretrained=backbone_pretrained, frozen_layers=frozen_backbone_layers) + + # Feature normalization + norm_scale = math.sqrt(1.0 / (out_feature_dim * filter_size * filter_size)) + + # Classifier features + clf_feature_extractor = clf_features.residual_bottleneck(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=out_feature_dim, final_relu=final_relu) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=out_feature_dim, init_weights=init_initializer) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.PrDiMPSteepestDescentNewton(num_iter=optim_iter, feat_stride=feat_stride, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, gauss_sigma=gauss_sigma, + detach_length=detach_length, alpha_eps=alpha_eps, + init_uni_weight=init_uni_weight, + min_filter_reg=optim_min_reg, normalize_label=normalize_label, + label_shrink=label_shrink, softmax_reg=softmax_reg, + label_threshold=label_threshold) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(input_dim=(4*128,4*256), pred_input_dim=iou_input_dim, pred_inter_dim=iou_inter_dim) + + # DiMP network + net = DiMPnet(feature_extractor=backbone_net, classifier=classifier, bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3']) + return net diff --git a/ltr/models/tracking/kysnet.py b/ltr/models/tracking/kysnet.py new file mode 100755 index 0000000..8f36b71 --- /dev/null +++ b/ltr/models/tracking/kysnet.py @@ -0,0 +1,174 @@ +import math +import torch +import torch.nn as nn +from collections import OrderedDict +import ltr.models.target_classifier as target_clf +import ltr.models.target_classifier.features as clf_features +import ltr.models.target_classifier.optimizer as clf_optimizer +import ltr.models.target_classifier.initializer as clf_initializer +import ltr.models.kys.predictor_wrapper as predictor_wrappers +import ltr.models.kys.response_predictor as resp_pred +import ltr.models.kys.cost_volume as cost_volume +import ltr.models.bbreg as bbmodels +import ltr.models.backbone as backbones +from ltr import model_constructor + + +class KYSNet(nn.Module): + def train(self, mode=True): + self.training = mode + + self.backbone_feature_extractor.train(False) + self.dimp_classifier.train(False) + self.predictor.train(mode) + self.bb_regressor.train(mode) + + if self.motion_feat_extractor is not None: + self.motion_feat_extractor.train(mode) + return self + + def __init__(self, backbone_feature_extractor, dimp_classifier, predictor, + bb_regressor, classification_layer, bb_regressor_layer, train_feature_extractor=True, + train_iounet=True, motion_feat_extractor=None, motion_layer=()): + super().__init__() + assert not train_feature_extractor + self.backbone_feature_extractor = backbone_feature_extractor + self.dimp_classifier = dimp_classifier + self.predictor = predictor + self.bb_regressor = bb_regressor + self.classification_layer = classification_layer + self.bb_regressor_layer = bb_regressor_layer + self.motion_layer = list(motion_layer) + self.output_layers = sorted(list(set([self.classification_layer] + self.bb_regressor_layer + self.motion_layer))) + self.train_iounet = train_iounet + self.motion_feat_extractor = motion_feat_extractor + + if not train_feature_extractor: + for p in self.backbone_feature_extractor.parameters(): + p.requires_grad_(False) + + def forward(self, test_image_cur, dimp_filters, test_label_cur, backbone_feat_prev, label_prev, + anno_prev, dimp_scores_prev, state_prev, dimp_jitter_fn): + raise NotImplementedError + + def train_classifier(self, train_imgs, train_bb): + assert train_imgs.dim() == 5, 'Expect 5 dimensions for train' + + num_sequences = train_imgs.shape[1] + num_train_images = train_imgs.shape[0] + + # Extract backbone features + train_feat = self.extract_backbone_features( + train_imgs.view(-1, train_imgs.shape[-3], train_imgs.shape[-2], train_imgs.shape[-1])) + + # Classification features + train_feat_clf = train_feat[self.classification_layer] + train_feat_clf = train_feat_clf.view(num_train_images, num_sequences, train_feat_clf.shape[-3], + train_feat_clf.shape[-2], train_feat_clf.shape[-1]) + + filter, train_losses = self.dimp_classifier.train_classifier(train_feat_clf, train_bb) + return filter + + def extract_backbone_features(self, im, layers=None): + im = im.view(-1, *im.shape[-3:]) + if layers is None: + layers = self.output_layers + + return self.backbone_feature_extractor(im, layers) + + def get_backbone_clf_feat(self, backbone_feat): + feat = backbone_feat[self.classification_layer] + + return feat + + def get_backbone_bbreg_feat(self, backbone_feat): + return [backbone_feat[l] for l in self.bb_regressor_layer] + + def extract_classification_feat(self, backbone_feat): + return self.dimp_classifier.extract_classification_feat(self.get_backbone_clf_feat(backbone_feat)) + + def get_motion_feat(self, backbone_feat): + if self.motion_feat_extractor is not None: + motion_feat = self.motion_feat_extractor(backbone_feat) + return motion_feat + else: + return self.predictor.extract_motion_feat(backbone_feat[self.classification_layer]) + + def extract_features(self, im, layers): + if 'classification' not in layers: + return self.backbone_feature_extractor(im, layers) + backbone_layers = sorted(list(set([l for l in layers + [self.classification_layer] if l != 'classification' and l != 'motion']))) + all_feat = self.backbone_feature_extractor(im, backbone_layers) + all_feat['classification'] = self.dimp_classifier.extract_classification_feat(all_feat[self.classification_layer]) + + if self.motion_feat_extractor is not None: + motion_feat = self.motion_feat_extractor(all_feat) + all_feat['motion'] = motion_feat + else: + all_feat['motion'] = self.predictor.extract_motion_feat(all_feat[self.classification_layer]) + + return OrderedDict({l: all_feat[l] for l in layers}) + + +@model_constructor +def kysnet_res50(filter_size=4, optim_iter=3, appearance_feature_dim=512, + optim_init_step=0.9, optim_init_reg=0.1, classification_layer='layer3', backbone_pretrained=True, + clf_feat_blocks=0, clf_feat_norm=True, final_conv=True, init_filter_norm=False, + mask_init_factor=3.0, score_act='relu', target_mask_act='sigmoid', num_dist_bins=100, + bin_displacement=0.1, detach_length=float('Inf'),train_feature_extractor=True, train_iounet=True, + iou_input_dim=(256, 256), iou_inter_dim=(256, 256), + cv_kernel_size=3, cv_max_displacement=9, cv_stride=1, + init_gauss_sigma=1.0, + state_dim=8, representation_predictor_dims=(64, 32), gru_ksz=3, + conf_measure='max', dimp_thresh=None): + + # ######################## backbone ######################## + backbone_net = backbones.resnet50(pretrained=backbone_pretrained) + + norm_scale = math.sqrt(1.0 / (appearance_feature_dim * filter_size * filter_size)) + + # ######################## classifier ######################## + clf_feature_extractor = clf_features.residual_bottleneck(num_blocks=clf_feat_blocks, l2norm=clf_feat_norm, + final_conv=final_conv, norm_scale=norm_scale, + out_dim=appearance_feature_dim) + + # Initializer for the DiMP classifier + initializer = clf_initializer.FilterInitializerLinear(filter_size=filter_size, filter_norm=init_filter_norm, + feature_dim=appearance_feature_dim) + + # Optimizer for the DiMP classifier + optimizer = clf_optimizer.DiMPSteepestDescentGN(num_iter=optim_iter, feat_stride=16, + init_step_length=optim_init_step, + init_filter_reg=optim_init_reg, init_gauss_sigma=init_gauss_sigma, + num_dist_bins=num_dist_bins, + bin_displacement=bin_displacement, + mask_init_factor=mask_init_factor, + score_act=score_act, act_param=None, mask_act=target_mask_act, + detach_length=detach_length) + + # The classifier module + classifier = target_clf.LinearFilter(filter_size=filter_size, filter_initializer=initializer, + filter_optimizer=optimizer, feature_extractor=clf_feature_extractor) + + # Bounding box regressor + bb_regressor = bbmodels.AtomIoUNet(input_dim=(4 * 128, 4 * 256), pred_input_dim=iou_input_dim, + pred_inter_dim=iou_inter_dim) + + cost_volume_layer = cost_volume.CostVolume(cv_kernel_size, cv_max_displacement, stride=cv_stride, + abs_coordinate_output=True) + + motion_response_predictor = resp_pred.ResponsePredictor(state_dim=state_dim, + representation_predictor_dims=representation_predictor_dims, + gru_ksz=gru_ksz, + conf_measure=conf_measure, + dimp_thresh=dimp_thresh) + + response_predictor = predictor_wrappers.PredictorWrapper(cost_volume_layer, motion_response_predictor) + + net = KYSNet(backbone_feature_extractor=backbone_net, dimp_classifier=classifier, + predictor=response_predictor, + bb_regressor=bb_regressor, + classification_layer=classification_layer, bb_regressor_layer=['layer2', 'layer3'], + train_feature_extractor=train_feature_extractor, + train_iounet=train_iounet) + return net diff --git a/ltr/run_training.py b/ltr/run_training.py new file mode 100755 index 0000000..f6faebd --- /dev/null +++ b/ltr/run_training.py @@ -0,0 +1,55 @@ +import os +import sys +import argparse +import importlib +import multiprocessing +import cv2 as cv +import torch.backends.cudnn + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +import ltr.admin.settings as ws_settings + + +def run_training(train_module, train_name, cudnn_benchmark=True): + """Run a train scripts in train_settings. + args: + train_module: Name of module in the "train_settings/" folder. + train_name: Name of the train settings file. + cudnn_benchmark: Use cudnn benchmark or not (default is True). + """ + + # This is needed to avoid strange crashes related to opencv + cv.setNumThreads(0) + + torch.backends.cudnn.benchmark = cudnn_benchmark + + print('Training: {} {}'.format(train_module, train_name)) + + settings = ws_settings.Settings() + settings.module_name = train_module + settings.script_name = train_name + settings.project_path = 'ltr/{}/{}'.format(train_module, train_name) + + expr_module = importlib.import_module('ltr.train_settings.{}.{}'.format(train_module, train_name)) + expr_func = getattr(expr_module, 'run') + + expr_func(settings) + + +def main(): + parser = argparse.ArgumentParser(description='Run a train scripts in train_settings.') + parser.add_argument('train_module', type=str, help='Name of module in the "train_settings/" folder.') + parser.add_argument('train_name', type=str, help='Name of the train settings file.') + parser.add_argument('--cudnn_benchmark', type=bool, default=True, help='Set cudnn benchmark on (1) or off (0) (default is on).') + + args = parser.parse_args() + + run_training(args.train_module, args.train_name, args.cudnn_benchmark) + + +if __name__ == '__main__': + multiprocessing.set_start_method('spawn', force=True) + main() diff --git a/ltr/train_settings/__init__.py b/ltr/train_settings/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/train_settings/bbreg/__init__.py b/ltr/train_settings/bbreg/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/train_settings/bbreg/atom.py b/ltr/train_settings/bbreg/atom.py new file mode 100755 index 0000000..c6f6b47 --- /dev/null +++ b/ltr/train_settings/bbreg/atom.py @@ -0,0 +1,95 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet with default settings, but additionally using GOT10k for training.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 16, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=50, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=50, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/bbreg/atom_gmm_sampl.py b/ltr/train_settings/bbreg/atom_gmm_sampl.py new file mode 100755 index 0000000..c91776b --- /dev/null +++ b/ltr/train_settings/bbreg/atom_gmm_sampl.py @@ -0,0 +1,96 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet using the baseline ATOM* settings in [https://arxiv.org/abs/1909.12297].' \ + 'Unlike standard ATOM, it employs the GMM-based proposal sampling and minor parameter changes.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'proposal_method': 'gmm', 'boxes_per_frame': 128, 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=200, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=200, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/bbreg/atom_paper.py b/ltr/train_settings/bbreg/atom_paper.py new file mode 100755 index 0000000..ce69596 --- /dev/null +++ b/ltr/train_settings/bbreg/atom_paper.py @@ -0,0 +1,94 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM IoUNet with default settings according to the paper.' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(11))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + trackingnet_val = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(11,12))) + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 16, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + data_processing_train = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.ATOMProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, trackingnet_train, coco_train], [1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=50, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([trackingnet_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=50, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = nn.MSELoss() + actor = actors.AtomActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/bbreg/atom_prob_ml.py b/ltr/train_settings/bbreg/atom_prob_ml.py new file mode 100755 index 0000000..3cd9284 --- /dev/null +++ b/ltr/train_settings/bbreg/atom_prob_ml.py @@ -0,0 +1,97 @@ +import torch.optim as optim +from ltr.dataset import Lasot, TrackingNet, MSCOCOSeq, Got10k +from ltr.data import processing, sampler, LTRLoader +import ltr.models.bbreg.atom as atom_models +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.bbreg as bbreg_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm + + +def run(settings): + # Most common settings are assigned in the settings struct + settings.description = 'ATOM using the probabilistic maximum likelihood trained regression model for bounding-box' \ + 'regression presented in [https://arxiv.org/abs/1909.12297].' + settings.batch_size = 64 + settings.num_workers = 8 + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 0, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0, 'test': 0.5} + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + # The joint augmentation transform, that is applied to the pairs jointly + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + # The augmentation transform applied to the training set (individually to each image in the pair) + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The augmentation transform applied to the validation set (individually to each image in the pair) + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # Data processing to do on the training pairs + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0, 0), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)], + 'add_mean_box': True} + data_processing_train = processing.KLBBregProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_train, + joint_transform=transform_joint) + + # Data processing to do on the validation pairs + data_processing_val = processing.KLBBregProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + transform=transform_val, + joint_transform=transform_joint) + + # The sampler for training + dataset_train = sampler.ATOMSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=1000*settings.batch_size, max_gap=200, processing=data_processing_train) + + # The loader for training + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # The sampler for validation + dataset_val = sampler.ATOMSampler([got10k_val], [1], samples_per_epoch=500*settings.batch_size, max_gap=200, + processing=data_processing_val) + + # The loader for validation + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = atom_models.atom_resnet18(backbone_pretrained=True) + objective = klreg_losses.MLRegression() + actor = bbreg_actors.AtomBBKLActor(net=net, objective=objective) + + # Optimizer + optimizer = optim.Adam(actor.net.bb_regressor.parameters(), lr=1e-3) + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + # Create trainer + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + # Run training (set fail_safe=False if you are debugging) + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/dimp/__init__.py b/ltr/train_settings/dimp/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/ltr/train_settings/dimp/dimp18.py b/ltr/train_settings/dimp/dimp18.py new file mode 100755 index 0000000..d138807 --- /dev/null +++ b/ltr/train_settings/dimp/dimp18.py @@ -0,0 +1,118 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for DiMP with ResNet18 as backbone.' + settings.batch_size = 26 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/init_loss', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 8, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + data_processing_train = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=30, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=30, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet18(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, final_conv=True, optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'iou': nn.MSELoss(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'iou': 1, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = actors.DiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters()}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/dimp/dimp50.py b/ltr/train_settings/dimp/dimp50.py new file mode 100755 index 0000000..043b91e --- /dev/null +++ b/ltr/train_settings/dimp/dimp50.py @@ -0,0 +1,119 @@ +import torch.nn as nn +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +from ltr import actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for DiMP with ResNet50 as backbone.' + settings.batch_size = 10 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/clf_ce', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'min_iou': 0.1, 'boxes_per_frame': 8, 'sigma_factor': [0.01, 0.05, 0.1, 0.2, 0.3]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + data_processing_train = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.DiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=30, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=30, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'iou': nn.MSELoss(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'iou': 1, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = actors.DiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters()}, + {'params': actor.net.feature_extractor.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/dimp/prdimp18.py b/ltr/train_settings/dimp/prdimp18.py new file mode 100755 index 0000000..ccf891d --- /dev/null +++ b/ltr/train_settings/dimp/prdimp18.py @@ -0,0 +1,119 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for PrDiMP with ResNet18 as backbone.' + settings.batch_size = 26 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + settings.print_stats = ['Loss/total', 'Loss/bb_ce', 'ClfTrain/clf_ce'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz, 'normalize': True} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.klcedimpnet18(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, final_conv=True, optim_init_step=1.0, optim_init_reg=0.05, optim_min_reg=0.05, + gauss_sigma=output_sigma * settings.feature_sz, alpha_eps=0.05, normalize_label=True, init_initializer='zero') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'clf_ce': klreg_losses.KLRegressionGrid()} + + loss_weight = {'bb_ce': 0.0025, 'clf_ce': 0.25, 'clf_ce_init': 0.25, 'clf_ce_iter': 1.0} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.parameters(), 'lr': 1e-3}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters()}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/dimp/prdimp50.py b/ltr/train_settings/dimp/prdimp50.py new file mode 100755 index 0000000..55cfe4f --- /dev/null +++ b/ltr/train_settings/dimp/prdimp50.py @@ -0,0 +1,120 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'Default train settings for PrDiMP with ResNet50 as backbone.' + settings.batch_size = 10 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 5.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 18 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 4.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + settings.print_stats = ['Loss/total', 'Loss/bb_ce', 'ClfTrain/clf_ce'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz, 'normalize': True} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [0.25,1,1,1], + samples_per_epoch=26000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=5000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.klcedimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=1.0, optim_init_reg=0.05, optim_min_reg=0.05, + gauss_sigma=output_sigma * settings.feature_sz, alpha_eps=0.05, normalize_label=True, init_initializer='zero') + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'clf_ce': klreg_losses.KLRegressionGrid()} + + loss_weight = {'bb_ce': 0.0025, 'clf_ce': 0.25, 'clf_ce_init': 0.25, 'clf_ce_iter': 1.0} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.parameters(), 'lr': 1e-3}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/train_settings/dimp/super_dimp.py b/ltr/train_settings/dimp/super_dimp.py new file mode 100755 index 0000000..a43575d --- /dev/null +++ b/ltr/train_settings/dimp/super_dimp.py @@ -0,0 +1,132 @@ +import torch.optim as optim +from ltr.dataset import Lasot, Got10k, TrackingNet, MSCOCOSeq +from ltr.data import processing, sampler, LTRLoader +from ltr.models.tracking import dimpnet +import ltr.models.loss as ltr_losses +import ltr.models.loss.kl_regression as klreg_losses +import ltr.actors.tracking as tracking_actors +from ltr.trainers import LTRTrainer +import ltr.data.transforms as tfm +from ltr import MultiGPU + + +def run(settings): + settings.description = 'SuperDiMP: Combines the DiMP classifier with the PrDiMP bounding box regressor and better' \ + 'training settings (larger batch size, inside_major cropping, and flipping augmentation.' \ + 'Gives results significantly better than both DiMP-50 and PrDiMP-50.' + settings.batch_size = 20 + settings.num_workers = 8 + settings.multi_gpu = False + settings.print_interval = 1 + settings.normalize_mean = [0.485, 0.456, 0.406] + settings.normalize_std = [0.229, 0.224, 0.225] + settings.search_area_factor = 6.0 + settings.output_sigma_factor = 1/4 + settings.target_filter_sz = 4 + settings.feature_sz = 22 + settings.output_sz = settings.feature_sz * 16 + settings.center_jitter_factor = {'train': 3, 'test': 5.5} + settings.scale_jitter_factor = {'train': 0.25, 'test': 0.5} + settings.hinge_threshold = 0.05 + # settings.print_stats = ['Loss/total', 'Loss/iou', 'ClfTrain/init_loss', 'ClfTrain/test_loss'] + + # Train datasets + lasot_train = Lasot(settings.env.lasot_dir, split='train') + got10k_train = Got10k(settings.env.got10k_dir, split='vottrain') + trackingnet_train = TrackingNet(settings.env.trackingnet_dir, set_ids=list(range(4))) + coco_train = MSCOCOSeq(settings.env.coco_dir) + + # Validation datasets + got10k_val = Got10k(settings.env.got10k_dir, split='votval') + + + # Data transform + transform_joint = tfm.Transform(tfm.ToGrayscale(probability=0.05), + tfm.RandomHorizontalFlip(probability=0.5)) + + transform_train = tfm.Transform(tfm.ToTensorAndJitter(0.2), + tfm.RandomHorizontalFlip(probability=0.5), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + transform_val = tfm.Transform(tfm.ToTensor(), + tfm.Normalize(mean=settings.normalize_mean, std=settings.normalize_std)) + + # The tracking pairs processing module + output_sigma = settings.output_sigma_factor / settings.search_area_factor + proposal_params = {'boxes_per_frame': 128, 'gt_sigma': (0.05, 0.05), 'proposal_sigma': [(0.05, 0.05), (0.5, 0.5)]} + label_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + label_density_params = {'feature_sz': settings.feature_sz, 'sigma_factor': output_sigma, 'kernel_sz': settings.target_filter_sz} + + data_processing_train = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + crop_type='inside_major', + max_scale_change=1.5, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_train, + joint_transform=transform_joint) + + data_processing_val = processing.KLDiMPProcessing(search_area_factor=settings.search_area_factor, + output_sz=settings.output_sz, + center_jitter_factor=settings.center_jitter_factor, + scale_jitter_factor=settings.scale_jitter_factor, + crop_type='inside_major', + max_scale_change=1.5, + mode='sequence', + proposal_params=proposal_params, + label_function_params=label_params, + label_density_params=label_density_params, + transform=transform_val, + joint_transform=transform_joint) + + # Train sampler and loader + dataset_train = sampler.DiMPSampler([lasot_train, got10k_train, trackingnet_train, coco_train], [1,1,1,1], + samples_per_epoch=40000, max_gap=200, num_test_frames=3, num_train_frames=3, + processing=data_processing_train) + + loader_train = LTRLoader('train', dataset_train, training=True, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=True, drop_last=True, stack_dim=1) + + # Validation samplers and loaders + dataset_val = sampler.DiMPSampler([got10k_val], [1], samples_per_epoch=10000, max_gap=200, + num_test_frames=3, num_train_frames=3, + processing=data_processing_val) + + loader_val = LTRLoader('val', dataset_val, training=False, batch_size=settings.batch_size, num_workers=settings.num_workers, + shuffle=False, drop_last=True, epoch_interval=5, stack_dim=1) + + # Create network and actor + net = dimpnet.dimpnet50(filter_size=settings.target_filter_sz, backbone_pretrained=True, optim_iter=5, + clf_feat_norm=True, clf_feat_blocks=0, final_conv=True, out_feature_dim=512, + optim_init_step=0.9, optim_init_reg=0.1, + init_gauss_sigma=output_sigma * settings.feature_sz, num_dist_bins=100, + bin_displacement=0.1, mask_init_factor=3.0, target_mask_act='sigmoid', score_act='relu', + frozen_backbone_layers=['conv1', 'bn1', 'layer1', 'layer2']) + + # Wrap the network for multi GPU training + if settings.multi_gpu: + net = MultiGPU(net, dim=1) + + objective = {'bb_ce': klreg_losses.KLRegression(), 'test_clf': ltr_losses.LBHinge(threshold=settings.hinge_threshold)} + + loss_weight = {'bb_ce': 0.01, 'test_clf': 100, 'test_init_clf': 100, 'test_iter_clf': 400} + + actor = tracking_actors.KLDiMPActor(net=net, objective=objective, loss_weight=loss_weight) + + # Optimizer + optimizer = optim.Adam([{'params': actor.net.classifier.filter_initializer.parameters(), 'lr': 5e-5}, + {'params': actor.net.classifier.filter_optimizer.parameters(), 'lr': 5e-4}, + {'params': actor.net.classifier.feature_extractor.parameters(), 'lr': 5e-5}, + {'params': actor.net.bb_regressor.parameters(), 'lr': 1e-3}, + {'params': actor.net.feature_extractor.layer3.parameters(), 'lr': 2e-5}], + lr=2e-4) + + lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.2) + + trainer = LTRTrainer(actor, [loader_train, loader_val], optimizer, settings, lr_scheduler) + + trainer.train(50, load_latest=True, fail_safe=True) diff --git a/ltr/trainers/__init__.py b/ltr/trainers/__init__.py new file mode 100755 index 0000000..b4555a3 --- /dev/null +++ b/ltr/trainers/__init__.py @@ -0,0 +1,2 @@ +from .base_trainer import BaseTrainer +from .ltr_trainer import LTRTrainer \ No newline at end of file diff --git a/ltr/trainers/base_trainer.py b/ltr/trainers/base_trainer.py new file mode 100755 index 0000000..535211d --- /dev/null +++ b/ltr/trainers/base_trainer.py @@ -0,0 +1,206 @@ +import os +import glob +import torch +import traceback +from ltr.admin import loading, multigpu + + +class BaseTrainer: + """Base trainer class. Contains functions for training and saving/loading chackpoints. + Trainer classes should inherit from this one and overload the train_epoch function.""" + + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + self.actor = actor + self.optimizer = optimizer + self.lr_scheduler = lr_scheduler + self.loaders = loaders + + self.update_settings(settings) + + self.epoch = 0 + self.stats = {} + + self.device = getattr(settings, 'device', None) + if self.device is None: + self.device = torch.device("cuda:0" if torch.cuda.is_available() and settings.use_gpu else "cpu") + + self.actor.to(self.device) + + def update_settings(self, settings=None): + """Updates the trainer settings. Must be called to update internal settings.""" + if settings is not None: + self.settings = settings + + if self.settings.env.workspace_dir is not None: + self.settings.env.workspace_dir = os.path.expanduser(self.settings.env.workspace_dir) + self._checkpoint_dir = os.path.join(self.settings.env.workspace_dir, 'checkpoints') + if not os.path.exists(self._checkpoint_dir): + os.makedirs(self._checkpoint_dir) + else: + self._checkpoint_dir = None + + + def train(self, max_epochs, load_latest=False, fail_safe=True): + """Do training for the given number of epochs. + args: + max_epochs - Max number of training epochs, + load_latest - Bool indicating whether to resume from latest epoch. + fail_safe - Bool indicating whether the training to automatically restart in case of any crashes. + """ + + epoch = -1 + num_tries = 10 + for i in range(num_tries): + try: + if load_latest: + self.load_checkpoint() + + for epoch in range(self.epoch+1, max_epochs+1): + self.epoch = epoch + + self.train_epoch() + + if self.lr_scheduler is not None: + self.lr_scheduler.step() + + if self._checkpoint_dir: + self.save_checkpoint() + except: + print('Training crashed at epoch {}'.format(epoch)) + if fail_safe: + self.epoch -= 1 + load_latest = True + print('Traceback for the error!') + print(traceback.format_exc()) + print('Restarting training from last epoch ...') + else: + raise + + print('Finished training!') + + + def train_epoch(self): + raise NotImplementedError + + + def save_checkpoint(self): + """Saves a checkpoint of the network and other variables.""" + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + state = { + 'epoch': self.epoch, + 'actor_type': actor_type, + 'net_type': net_type, + 'net': net.state_dict(), + 'net_info': getattr(net, 'info', None), + 'constructor': getattr(net, 'constructor', None), + 'optimizer': self.optimizer.state_dict(), + 'stats': self.stats, + 'settings': self.settings + } + + + directory = '{}/{}'.format(self._checkpoint_dir, self.settings.project_path) + if not os.path.exists(directory): + os.makedirs(directory) + + # First save as a tmp file + tmp_file_path = '{}/{}_ep{:04d}.tmp'.format(directory, net_type, self.epoch) + torch.save(state, tmp_file_path) + + file_path = '{}/{}_ep{:04d}.pth.tar'.format(directory, net_type, self.epoch) + + # Now rename to actual checkpoint. os.rename seems to be atomic if files are on same filesystem. Not 100% sure + os.rename(tmp_file_path, file_path) + + + def load_checkpoint(self, checkpoint = None, fields = None, ignore_fields = None, load_constructor = False): + """Loads a network checkpoint file. + + Can be called in three different ways: + load_checkpoint(): + Loads the latest epoch from the workspace. Use this to continue training. + load_checkpoint(epoch_num): + Loads the network at the given epoch number (int). + load_checkpoint(path_to_checkpoint): + Loads the file from the given absolute path (str). + """ + + net = self.actor.net.module if multigpu.is_multi_gpu(self.actor.net) else self.actor.net + + actor_type = type(self.actor).__name__ + net_type = type(net).__name__ + + if checkpoint is None: + # Load most recent checkpoint + checkpoint_list = sorted(glob.glob('{}/{}/{}_ep*.pth.tar'.format(self._checkpoint_dir, + self.settings.project_path, net_type))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + print('No matching checkpoint file found') + return + elif isinstance(checkpoint, int): + # Checkpoint is the epoch number + checkpoint_path = '{}/{}/{}_ep{:04d}.pth.tar'.format(self._checkpoint_dir, self.settings.project_path, + net_type, checkpoint) + elif isinstance(checkpoint, str): + # checkpoint is the path + if os.path.isdir(checkpoint): + checkpoint_list = sorted(glob.glob('{}/*_ep*.pth.tar'.format(checkpoint))) + if checkpoint_list: + checkpoint_path = checkpoint_list[-1] + else: + raise Exception('No checkpoint found') + else: + checkpoint_path = os.path.expanduser(checkpoint) + else: + raise TypeError + + # Load network + checkpoint_dict = loading.torch_load_legacy(checkpoint_path) + + assert net_type == checkpoint_dict['net_type'], 'Network is not of correct type.' + + if fields is None: + fields = checkpoint_dict.keys() + if ignore_fields is None: + ignore_fields = ['settings'] + + # Never load the scheduler. It exists in older checkpoints. + ignore_fields.extend(['lr_scheduler', 'constructor', 'net_type', 'actor_type', 'net_info']) + + # Load all fields + for key in fields: + if key in ignore_fields: + continue + if key == 'net': + net.load_state_dict(checkpoint_dict[key]) + elif key == 'optimizer': + self.optimizer.load_state_dict(checkpoint_dict[key]) + else: + setattr(self, key, checkpoint_dict[key]) + + # Set the net info + if load_constructor and 'constructor' in checkpoint_dict and checkpoint_dict['constructor'] is not None: + net.constructor = checkpoint_dict['constructor'] + if 'net_info' in checkpoint_dict and checkpoint_dict['net_info'] is not None: + net.info = checkpoint_dict['net_info'] + + # Update the epoch in lr scheduler + if 'epoch' in fields: + self.lr_scheduler.last_epoch = self.epoch + + return True diff --git a/ltr/trainers/ltr_trainer.py b/ltr/trainers/ltr_trainer.py new file mode 100755 index 0000000..25030ac --- /dev/null +++ b/ltr/trainers/ltr_trainer.py @@ -0,0 +1,136 @@ +import os +from collections import OrderedDict +from ltr.trainers import BaseTrainer +from ltr.admin.stats import AverageMeter, StatValue +from ltr.admin.tensorboard import TensorboardWriter +import torch +import time + + +class LTRTrainer(BaseTrainer): + def __init__(self, actor, loaders, optimizer, settings, lr_scheduler=None): + """ + args: + actor - The actor for training the network + loaders - list of dataset loaders, e.g. [train_loader, val_loader]. In each epoch, the trainer runs one + epoch for each loader. + optimizer - The optimizer used for training, e.g. Adam + settings - Training settings + lr_scheduler - Learning rate scheduler + """ + super().__init__(actor, loaders, optimizer, settings, lr_scheduler) + + self._set_default_settings() + + # Initialize statistics variables + self.stats = OrderedDict({loader.name: None for loader in self.loaders}) + + # Initialize tensorboard + tensorboard_writer_dir = os.path.join(self.settings.env.tensorboard_dir, self.settings.project_path) + self.tensorboard_writer = TensorboardWriter(tensorboard_writer_dir, [l.name for l in loaders]) + + self.move_data_to_gpu = getattr(settings, 'move_data_to_gpu', True) + + def _set_default_settings(self): + # Dict of all default values + default = {'print_interval': 10, + 'print_stats': None, + 'description': ''} + + for param, default_value in default.items(): + if getattr(self.settings, param, None) is None: + setattr(self.settings, param, default_value) + + def cycle_dataset(self, loader): + """Do a cycle of training or validation.""" + + self.actor.train(loader.training) + torch.set_grad_enabled(loader.training) + + self._init_timing() + + for i, data in enumerate(loader, 1): + # get inputs + if self.move_data_to_gpu: + data = data.to(self.device) + + data['epoch'] = self.epoch + data['settings'] = self.settings + + # forward pass + loss, stats = self.actor(data) + + # backward pass and update weights + if loader.training: + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + + # update statistics + batch_size = data['train_images'].shape[loader.stack_dim] + self._update_stats(stats, batch_size, loader) + + # print statistics + self._print_stats(i, loader, batch_size) + + def train_epoch(self): + """Do one epoch for each loader.""" + for loader in self.loaders: + if self.epoch % loader.epoch_interval == 0: + self.cycle_dataset(loader) + + self._stats_new_epoch() + self._write_tensorboard() + + def _init_timing(self): + self.num_frames = 0 + self.start_time = time.time() + self.prev_time = self.start_time + + def _update_stats(self, new_stats: OrderedDict, batch_size, loader): + # Initialize stats if not initialized yet + if loader.name not in self.stats.keys() or self.stats[loader.name] is None: + self.stats[loader.name] = OrderedDict({name: AverageMeter() for name in new_stats.keys()}) + + for name, val in new_stats.items(): + if name not in self.stats[loader.name].keys(): + self.stats[loader.name][name] = AverageMeter() + self.stats[loader.name][name].update(val, batch_size) + + def _print_stats(self, i, loader, batch_size): + self.num_frames += batch_size + current_time = time.time() + batch_fps = batch_size / (current_time - self.prev_time) + average_fps = self.num_frames / (current_time - self.start_time) + self.prev_time = current_time + if i % self.settings.print_interval == 0 or i == loader.__len__(): + print_str = '[%s: %d, %d / %d] ' % (loader.name, self.epoch, i, loader.__len__()) + print_str += 'FPS: %.1f (%.1f) , ' % (average_fps, batch_fps) + for name, val in self.stats[loader.name].items(): + if (self.settings.print_stats is None or name in self.settings.print_stats) and hasattr(val, 'avg'): + print_str += '%s: %.5f , ' % (name, val.avg) + print(print_str[:-5]) + + def _stats_new_epoch(self): + # Record learning rate + for loader in self.loaders: + if loader.training: + lr_list = self.lr_scheduler.get_lr() + for i, lr in enumerate(lr_list): + var_name = 'LearningRate/group{}'.format(i) + if var_name not in self.stats[loader.name].keys(): + self.stats[loader.name][var_name] = StatValue() + self.stats[loader.name][var_name].update(lr) + + for loader_stats in self.stats.values(): + if loader_stats is None: + continue + for stat_value in loader_stats.values(): + if hasattr(stat_value, 'new_epoch'): + stat_value.new_epoch() + + def _write_tensorboard(self): + if self.epoch == 1: + self.tensorboard_writer.write_info(self.settings.module_name, self.settings.script_name, self.settings.description) + + self.tensorboard_writer.write_epoch(self.stats, self.epoch) \ No newline at end of file diff --git a/meta_updater/__pycache__/tcNet.cpython-37.pyc b/meta_updater/__pycache__/tcNet.cpython-37.pyc new file mode 100755 index 0000000..42c0116 Binary files /dev/null and b/meta_updater/__pycache__/tcNet.cpython-37.pyc differ diff --git a/meta_updater/__pycache__/tcopt.cpython-37.pyc b/meta_updater/__pycache__/tcopt.cpython-37.pyc new file mode 100755 index 0000000..10e6a47 Binary files /dev/null and b/meta_updater/__pycache__/tcopt.cpython-37.pyc differ diff --git a/meta_updater/dimp_mu_votlt/checkpoint b/meta_updater/dimp_mu_votlt/checkpoint new file mode 100755 index 0000000..ff36490 --- /dev/null +++ b/meta_updater/dimp_mu_votlt/checkpoint @@ -0,0 +1,6 @@ +model_checkpoint_path: "lstm_model.ckpt-220000" +all_model_checkpoint_paths: "lstm_model.ckpt-200000" +all_model_checkpoint_paths: "lstm_model.ckpt-205000" +all_model_checkpoint_paths: "lstm_model.ckpt-210000" +all_model_checkpoint_paths: "lstm_model.ckpt-215000" +all_model_checkpoint_paths: "lstm_model.ckpt-220000" diff --git a/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.data-00000-of-00001 b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.data-00000-of-00001 new file mode 100755 index 0000000..e246c5f Binary files /dev/null and b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.data-00000-of-00001 differ diff --git a/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.index b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.index new file mode 100755 index 0000000..61f00ea Binary files /dev/null and b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.index differ diff --git a/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.meta b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.meta new file mode 100755 index 0000000..2d75ffb Binary files /dev/null and b/meta_updater/dimp_mu_votlt/lstm_model.ckpt-220000.meta differ diff --git a/meta_updater/rtmd_MU_0_5_2/checkpoint b/meta_updater/rtmd_MU_0_5_2/checkpoint new file mode 100755 index 0000000..f9c8e94 --- /dev/null +++ b/meta_updater/rtmd_MU_0_5_2/checkpoint @@ -0,0 +1,4 @@ +model_checkpoint_path: "lstm_model.ckpt-30000" +all_model_checkpoint_paths: "lstm_model.ckpt-21000" +all_model_checkpoint_paths: "lstm_model.ckpt-27000" +all_model_checkpoint_paths: "lstm_model.ckpt-30000" diff --git a/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.data-00000-of-00001 b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.data-00000-of-00001 new file mode 100755 index 0000000..4623763 Binary files /dev/null and b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.data-00000-of-00001 differ diff --git a/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.index b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.index new file mode 100755 index 0000000..d777d62 Binary files /dev/null and b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.index differ diff --git a/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.meta b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.meta new file mode 100755 index 0000000..842185e Binary files /dev/null and b/meta_updater/rtmd_MU_0_5_2/lstm_model.ckpt-30000.meta differ diff --git a/meta_updater/super_dimp_mu_1/checkpoint b/meta_updater/super_dimp_mu_1/checkpoint new file mode 100755 index 0000000..7cdfd74 --- /dev/null +++ b/meta_updater/super_dimp_mu_1/checkpoint @@ -0,0 +1,6 @@ +model_checkpoint_path: "lstm_model.ckpt-105000" +all_model_checkpoint_paths: "lstm_model.ckpt-90000" +all_model_checkpoint_paths: "lstm_model.ckpt-95000" +all_model_checkpoint_paths: "lstm_model.ckpt-100000" +all_model_checkpoint_paths: "lstm_model.ckpt-103000" +all_model_checkpoint_paths: "lstm_model.ckpt-105000" diff --git a/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.data-00000-of-00001 b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.data-00000-of-00001 new file mode 100755 index 0000000..814aa4e Binary files /dev/null and b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.data-00000-of-00001 differ diff --git a/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.index b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.index new file mode 100755 index 0000000..5fc734b Binary files /dev/null and b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.index differ diff --git a/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.meta b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.meta new file mode 100755 index 0000000..e071aa5 Binary files /dev/null and b/meta_updater/super_dimp_mu_1/lstm_model.ckpt-105000.meta differ diff --git a/meta_updater/tcNet.py b/meta_updater/tcNet.py new file mode 100755 index 0000000..e24c430 --- /dev/null +++ b/meta_updater/tcNet.py @@ -0,0 +1,78 @@ +import tensorflow as tf +from tensorflow.contrib import rnn +from tcopt import tcopts + + +class tclstm: + def map_net(self, maps, reuse=False): + with tf.variable_scope('mapnet') as scope: + if reuse: + scope.reuse_variables() + with tf.variable_scope('conv1'): + weights = tf.get_variable("weights", shape=(3, 3, 1, 32), dtype=tf.float32, + initializer=tf.truncated_normal_initializer(0.01), trainable=True) + biases = tf.get_variable("biases", shape=(32,), dtype=tf.float32, + initializer=tf.constant_initializer(0.0), trainable=True) + map_outputs = tf.nn.conv2d(maps, weights, strides=[1, 1, 1, 1], padding='VALID') + biases + map_outputs = tf.nn.relu(map_outputs) + map_outputs = tf.nn.max_pool(map_outputs, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID') + with tf.variable_scope('conv2'): + weights = tf.get_variable("weights", shape=(3, 3, 32, 64), dtype=tf.float32, + initializer=tf.truncated_normal_initializer(0.01), trainable=True) + biases = tf.get_variable("biases", shape=(64,), dtype=tf.float32, + initializer=tf.constant_initializer(0.0), trainable=True) + map_outputs = tf.nn.conv2d(map_outputs, weights, strides=[1, 1, 1, 1], padding='VALID') + biases + map_outputs = tf.nn.relu(map_outputs) + with tf.variable_scope('conv3'): + weights = tf.get_variable("weights", shape=(1, 1, 64, tcopts['map_units']), dtype=tf.float32, + initializer=tf.truncated_normal_initializer(0.01), trainable=True) + biases = tf.get_variable("biases", shape=(tcopts['map_units'],), dtype=tf.float32, + initializer=tf.constant_initializer(0.0), trainable=True) + map_outputs = tf.nn.conv2d(map_outputs, weights, strides=[1, 1, 1, 1], padding='VALID') + biases + map_outputs = tf.nn.relu(map_outputs) + # GAP + map_outputs = tf.reduce_mean(map_outputs, axis=[1, 2]) + map_outputs = tf.reshape(map_outputs, [-1, tcopts['time_steps'], tcopts['map_units']]) + return map_outputs + + def net(self, inputs, reuse=False): + with tf.variable_scope('tclstm') as scope: + if reuse: + scope.reuse_variables() + with tf.variable_scope('lstm_layer1'): + + # Unstack to get a list of 'timesteps' tensors of shape (batch_size, n_input) + x = tf.unstack(inputs, tcopts['time_steps'], 1) + + # Define a lstm cell with tensorflow + lstm_cell = rnn.BasicLSTMCell(64, forget_bias=1.0) + + # Get lstm cell output + outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32) + with tf.variable_scope('lstm_layer2'): + lstm_cell = rnn.BasicLSTMCell(64, forget_bias=1.0) + outputs, states = rnn.static_rnn(lstm_cell, outputs[-8:], dtype=tf.float32, initial_state=states) + with tf.variable_scope('lstm_layer3'): + lstm_cell = rnn.BasicLSTMCell(64, forget_bias=1.0) + outputs, states = rnn.static_rnn(lstm_cell, outputs[-3:], dtype=tf.float32, initial_state=states) + DQN_Inputs = outputs + with tf.variable_scope('fc1'): + weights = tf.get_variable("weights", shape=(64, 64), dtype=tf.float32, + initializer=tf.contrib.layers.xavier_initializer(), + regularizer=tf.contrib.layers.l2_regularizer(5e-4), trainable=True) + biases = tf.get_variable("biases", shape=(64,), dtype=tf.float32, + initializer=tf.constant_initializer(0.0), + regularizer=tf.contrib.layers.l2_regularizer(5e-4), trainable=True) + outputs = tf.matmul(outputs[-1], weights) + biases + with tf.variable_scope('fc2'): + weights = tf.get_variable("weights", shape=(64, 2), dtype=tf.float32, + initializer=tf.contrib.layers.xavier_initializer(), + regularizer=tf.contrib.layers.l2_regularizer(5e-4), trainable=True) + biases = tf.get_variable("biases", shape=(2,), dtype=tf.float32, + initializer=tf.constant_initializer(0.0), + regularizer=tf.contrib.layers.l2_regularizer(5e-4), trainable=True) + outputs = tf.matmul(outputs, weights) + biases + return outputs, DQN_Inputs + + + diff --git a/meta_updater/tcNet.pyc b/meta_updater/tcNet.pyc new file mode 100755 index 0000000..a141725 Binary files /dev/null and b/meta_updater/tcNet.pyc differ diff --git a/meta_updater/tcopt.py b/meta_updater/tcopt.py new file mode 100755 index 0000000..752a9ca --- /dev/null +++ b/meta_updater/tcopt.py @@ -0,0 +1,44 @@ +from collections import OrderedDict + +tcopts = OrderedDict() + +# training batch +tcopts['batch_size'] = 32 # peer gpu +tcopts['num_examples_per_epoch'] = 1400000 +tcopts['NUM_EPOCHS_PER_DECAY'] = 2.5 +tcopts['num_of_step'] = 400000 +tcopts['keep_checkpoint_every_n_hours'] = 1 +tcopts['initial_lr'] = 1e-4 +tcopts['lr_decay_factor'] = 0.1 +tcopts['num_threads'] = 8 +tcopts['capacity'] = 32 + + +tcopts['train_dir'] = './save_path' +tcopts['model_name'] = 'model.ckpt' + +# slim config +tcopts['save_summaries_secs'] = 120 +tcopts['save_interval_secs'] = 600 +# NOT use slim config + +tcopts['summary_save_interval'] = 50 +tcopts['model_save_interval'] = 5000 +tcopts['eval_interval'] = 500 + +# lstm +tcopts['lstm_train_dir'] = './test3_new' +tcopts['train_data_dir'] = '/media/dkn/Data2/dimp/test3/lasot' +tcopts['pos_thr'] = 0.5 +tcopts['lstm_initial_lr'] = 1e-3 +tcopts['lstm_decay_steps'] = 50000 +tcopts['lstm_input'] = [0, 1, 2, 3, 6, 7] +tcopts['sampling_interval'] = 4 +tcopts['lstm_num_input'] = len(tcopts['lstm_input']) +tcopts['lstm_num_classes'] = 2 +tcopts['time_steps'] = 20 +tcopts['start_frame'] = 20 +tcopts['map_units'] = 4 +tcopts['save_pos_thr'] = 0.83 +tcopts['save_neg_thr'] = 0.83 +tcopts['display_step'] = 50 diff --git a/meta_updater/train_lstm.py b/meta_updater/train_lstm.py new file mode 100755 index 0000000..18ffbd9 --- /dev/null +++ b/meta_updater/train_lstm.py @@ -0,0 +1,284 @@ +from __future__ import print_function +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +from tensorflow.contrib import rnn +from tcNet import tclstm +import os +from tcopt import tcopts +import tensorflow.contrib.slim as slim +os.environ["CUDA_VISIBLE_DEVICES"] = "0" + + +def prepare_test_data(Dataset, seq_len, mode=None): + base_dir = tcopts['train_data_dir'] + data_dir = os.path.join(base_dir, Dataset) + train_list = os.listdir(data_dir) + train_list.sort() + np.random.shuffle(train_list) + + testing_set_dir = '../../utils/testing_set.txt' + testing_set = list(np.loadtxt(testing_set_dir, dtype=str)) + if mode == 'test': + print('test data') + train_list = [vid for vid in train_list if vid[:-4] in testing_set] + elif mode == 'train': + print('train data') + train_list = [vid for vid in train_list if vid[:-4] not in testing_set] + else: + print("all data") + pos_data, neg_data = prepare_data(data_dir, seq_len, train_list) + np.save('test_neg_data.npy', np.array(neg_data)) + np.save('test_pos_data.npy', np.array(pos_data)) + return pos_data, neg_data + +def prepare_train_data(Dataset, seq_len, mode=None): + base_dir = tcopts['train_data_dir'] + data_dir = os.path.join(base_dir, Dataset) + train_list = os.listdir(data_dir) + train_list.sort() + np.random.shuffle(train_list) + + testing_set_dir = '../../utils/testing_set.txt' + testing_set = list(np.loadtxt(testing_set_dir, dtype=str)) + if mode == 'test': + print('test data') + train_list = [vid for vid in train_list if vid[:-4] in testing_set and vid.endswith('.txt')] + elif mode == 'train': + print('train data') + train_list = [vid for vid in train_list if vid[:-4] not in testing_set and vid.endswith('.txt')] + else: + print("all data") + + pos_data, neg_data = prepare_data(data_dir, seq_len,train_list) + np.save('neg_data.npy', np.array(neg_data)) + np.save('pos_data.npy', np.array(pos_data)) + return pos_data, neg_data + +def prepare_data(data_dir, seq_len, train_list): + + + pos_data = [] + neg_data = [] + sampling_interval = tcopts['sampling_interval'] + # video + for id, video in enumerate(train_list): + print(str(id) + ':' + video) + txt_tmp = np.loadtxt(os.path.join(data_dir, train_list[id]), delimiter=',') + map_tmp = np.load(os.path.join(data_dir, train_list[id][:-4]+'_map.npy')) + loss_list = np.where(txt_tmp[:, 5] == 0)[0] + for i in range((len(txt_tmp) - seq_len)//sampling_interval): + if sampling_interval * i + seq_len + 1 >= len(txt_tmp): + continue + data_tmp = txt_tmp[sampling_interval*i+1:sampling_interval*i + seq_len+1] + loss_index = np.concatenate([np.where(data_tmp[:, 5] == -1)[0], np.where(data_tmp[:, 5] == 0)[0]]) + if data_tmp[-1, 5] > tcopts['pos_thr']: + # pos data + pos_data.append([data_tmp, train_list[id][:-4]+'_map.npy']) + elif data_tmp[-1, 5] == 0: + neg_data.append([data_tmp, train_list[id][:-4]+'_map.npy']) + return pos_data, neg_data + +def get_batch_input(pos_data, neg_data, batch_size): + + pos_id = np.random.randint(0, len(pos_data), batch_size) + neg_id = np.random.randint(0, len(neg_data), batch_size) + pos_map = [] + neg_map = [] + + for i in range(len(pos_data[pos_id])): + map_tmp = np.load(os.path.join(tcopts['train_data_dir'], pos_data[pos_id][i][1]), allow_pickle=True) + frame_index = pos_data[pos_id][i][0][:, 4] + map_tmp = np.reshape(map_tmp[np.array(frame_index, dtype='int16') - 1], [tcopts['time_steps'], 1, 19, 19]) + map_tmp = map_tmp.transpose((0, 2, 3, 1)) + pos_map.append(map_tmp) + for i in range(len(neg_data[neg_id])): + map_tmp = np.load(os.path.join(tcopts['train_data_dir'], neg_data[neg_id][i][1]), allow_pickle=True) + frame_index = neg_data[neg_id][i][0][:, 4] + map_tmp = np.reshape(map_tmp[np.array(frame_index, dtype='int16') - 1], [tcopts['time_steps'], 1, 19, 19]) + map_tmp = map_tmp.transpose((0, 2, 3, 1)) + neg_map.append(map_tmp) + batch_X_input = np.concatenate((pos_data[pos_id][:, 0], neg_data[neg_id][:, 0]), axis=0) + batch_X_input = np.array(list(batch_X_input)) + batch_map_input = np.concatenate((pos_map, neg_map), axis=0) + labels1 = np.array([0, 1]).reshape((1, 2)) + labels1 = np.tile(labels1, (batch_size, 1)) + labels2 = np.array([1, 0]).reshape((1, 2)) + labels2 = np.tile(labels2, (batch_size, 1)) + labels = np.concatenate((labels1, labels2), axis=0) + batch_map_input = np.reshape(batch_map_input, + [batch_map_input.shape[0] * batch_map_input.shape[1], batch_map_input.shape[2], + batch_map_input.shape[3], + batch_map_input.shape[4]]) + return batch_X_input, batch_map_input, labels +def get_test_batch_input(pos_data, neg_data): + batch_size = 1000 + pos_id = np.random.randint(0, len(pos_data), batch_size) + neg_id = np.random.randint(0, len(neg_data), batch_size) + pos_map = [] + neg_map = [] + + for i in range(len(pos_data[pos_id])): + map_tmp = np.load(os.path.join(tcopts['train_data_dir'], pos_data[pos_id][i][1]), allow_pickle=True) + frame_index = pos_data[pos_id][i][0][:, 4] + map_tmp = np.reshape(map_tmp[np.array(frame_index, dtype='int16') - 1], [tcopts['time_steps'], 1, 19, 19]) + map_tmp = map_tmp.transpose((0, 2, 3, 1)) + pos_map.append(map_tmp) + for i in range(len(neg_data[neg_id])): + map_tmp = np.load(os.path.join(tcopts['train_data_dir'], neg_data[neg_id][i][1]), allow_pickle=True) + frame_index = neg_data[neg_id][i][0][:, 4] + map_tmp = np.reshape(map_tmp[np.array(frame_index, dtype='int16') - 1], [tcopts['time_steps'], 1, 19, 19]) + map_tmp = map_tmp.transpose((0, 2, 3, 1)) + neg_map.append(map_tmp) + batch_X_input = np.concatenate((pos_data[pos_id][:, 0], neg_data[neg_id][:, 0]), axis=0) + batch_X_input = np.array(list(batch_X_input)) + batch_map_input = np.concatenate((pos_map, neg_map), axis=0) + labels1 = np.array([0, 1]).reshape((1, 2)) + labels1 = np.tile(labels1, (batch_size, 1)) + labels2 = np.array([1, 0]).reshape((1, 2)) + labels2 = np.tile(labels2, (batch_size, 1)) + labels = np.concatenate((labels1, labels2), axis=0) + batch_map_input = np.reshape(batch_map_input, + [batch_map_input.shape[0] * batch_map_input.shape[1], batch_map_input.shape[2], + batch_map_input.shape[3], + batch_map_input.shape[4]]) + + return len(pos_data[pos_id]), len(neg_data[neg_id]), batch_X_input, batch_map_input, labels + +def load_training_data(pos_name, neg_name): + pos_data = np.load(pos_name, allow_pickle=True) + neg_data = np.load(neg_name, allow_pickle=True) + return pos_data, neg_data + +def train(): + model = tclstm() + training_steps = 50000 + display_step = tcopts['display_step'] + + with tf.device('cpu:0'): + global_step = slim.create_global_step() + # tf Graph input + maps = tf.placeholder("float", [None, 19, 19, 1]) + map_logits = model.map_net(maps) + X = tf.placeholder("float", [None, tcopts['time_steps'], tcopts['lstm_num_input']]) + Inputs = tf.concat((X, map_logits), axis=2) + Y = tf.placeholder("float", [None, tcopts['lstm_num_classes']]) + lrOp = tf.train.exponential_decay(tcopts['lstm_initial_lr'], + global_step, + tcopts['lstm_decay_steps'], + tcopts['lr_decay_factor'], + staircase=True) + logits, _ = model.net(Inputs) + # optimizer = tf.train.GradientDescentOptimizer(learning_rate=lrOp) + optimizer = tf.train.MomentumOptimizer(learning_rate=lrOp, momentum=0.9) + loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits( + logits=logits, labels=Y)) + prediction = tf.nn.softmax(logits) + grads = optimizer.compute_gradients(loss_op) + train_op = optimizer.apply_gradients(grads, global_step=global_step) + # Evaluate model (with test logits, for dropout to be disabled) + correct_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(Y, 1)) + accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) + test_accuracy = accuracy + + # Initialize the variables (i.e. assign their default value) + init = tf.global_variables_initializer() + + pos_data, neg_data = load_training_data('pos_data.npy', 'neg_data.npy') + test_pos_data, test_neg_data = load_training_data('test_pos_data.npy', 'test_neg_data.npy') + test_pos_num, test_neg_num, test_batch_X_input, test_batch_map_input, test_labels = get_test_batch_input( + test_pos_data, test_neg_data) + + test_accuracy_pos = tf.reduce_mean(tf.cast(correct_pred[:test_pos_num], tf.float32)) + test_accuracy_neg = tf.reduce_mean(tf.cast(correct_pred[test_pos_num:], tf.float32)) + accuracy_pos = tf.reduce_mean(tf.cast(correct_pred[:tcopts['batch_size']], tf.float32)) + accuracy_neg = tf.reduce_mean(tf.cast(correct_pred[tcopts['batch_size']:], tf.float32)) + + saver = tf.train.Saver(keep_checkpoint_every_n_hours=tcopts['keep_checkpoint_every_n_hours']) + # add summary + tf.summary.scalar('learning_rate', lrOp) + tf.summary.scalar('loss', loss_op) + tf.summary.scalar('training_accuracy', accuracy) + tf.summary.scalar('training_accuracy_pos', accuracy_pos) + tf.summary.scalar('training_accuracy_neg', accuracy_neg) + # grads + for grad, var in grads: + if grad is not None: + tf.summary.histogram(var.op.name + '/gradients', grad) + # # trainable var + for var in tf.trainable_variables(): + tf.summary.histogram(var.op.name, var) + + summary_op = tf.summary.merge_all() + tf.summary.scalar('testing_accuracy_pos', test_accuracy_pos) + tf.summary.scalar('testing_accuracy_neg', test_accuracy_neg) + tf.summary.scalar('testing_accuracy', test_accuracy) + test_merge_summary = tf.summary.merge([tf.get_collection(tf.GraphKeys.SUMMARIES, 'testing_accuracy')]) + + summary_writer = tf.summary.FileWriter(tcopts['lstm_train_dir'], graph=tf.get_default_graph()) + tfconfig = tf.ConfigProto() + # tfconfig.gpu_options.per_process_gpu_memory_fraction = 1 + # Start training + with tf.Session(config=tfconfig) as sess: + + # Run the initializer + sess.run(init) + checkpoint = tf.train.latest_checkpoint(tcopts['lstm_train_dir']) + if checkpoint is not None: + saver.restore(sess, checkpoint) + best_model = (tcopts['save_neg_thr']+tcopts['save_pos_thr'])/2 + while True: + batch_X_input, batch_map_input, labels = get_batch_input(pos_data, neg_data, tcopts['batch_size']) + # Reshape data to get 28 seq of 28 elements + # Run optimization op (backprop) + _, g_step = sess.run([train_op, global_step], feed_dict={X: batch_X_input[:, :, tcopts['lstm_input']], Y: labels, maps: batch_map_input}) + if g_step % display_step == 0: + # Calculate batch loss and accuracy + loss, acc, acc_pos, acc_neg, summary_str = sess.run( + [loss_op, accuracy, accuracy_pos, accuracy_neg, summary_op], + feed_dict={X: batch_X_input[:, :, tcopts['lstm_input']], + Y: labels, + maps: batch_map_input}) + summary_writer.add_summary(summary_str, g_step) + print("Step " + str(g_step) + ", Minibatch Loss= " + \ + "{:.4f}".format(loss) + ", Training Accuracy= " + \ + "{:.3f}".format(acc) + ", Accuracy pos= " + "{:.3f}".format( + acc_pos) + ", Accuracy neg= " + "{:.3f}".format(acc_neg)) + + if g_step % tcopts['model_save_interval'] == 0: + checkpoint_path = os.path.join(tcopts['lstm_train_dir'], 'lstm_model.ckpt') + saver.save(sess, checkpoint_path, global_step=g_step) + print('Save model, global step: %d' % g_step) + if g_step % tcopts['eval_interval'] == 0: + test_pos_num, test_neg_num, test_batch_X_input, test_batch_map_input, test_labels = get_test_batch_input( + test_pos_data, test_neg_data) + test_acc, test_acc_pos, test_acc_neg, test_summary_str = sess.run( + [test_accuracy, test_accuracy_pos, test_accuracy_neg, test_merge_summary], + feed_dict={X: test_batch_X_input[:, :, tcopts['lstm_input']], Y: test_labels, maps: test_batch_map_input}) + summary_writer.add_summary(test_summary_str, g_step) + print("test accuracy:" + "{:.4f}".format(test_acc) + " test accuracy pos:" + "{:.4f}".format( + test_acc_pos) + " test accuracy neg:" + "{:.4f}".format(test_acc_neg)) + if test_acc_pos > tcopts['save_pos_thr'] and test_acc_neg > tcopts['save_neg_thr'] and (test_acc_pos+test_acc_neg)/2>best_model: + best_model = (test_acc_pos+test_acc_neg)/2 + checkpoint_path = os.path.join(tcopts['lstm_train_dir'], 'lstm_model.ckpt') + saver.save(sess, checkpoint_path, global_step=g_step) + print('Save model, global step: %d' % g_step) + + + + + + + + + + + + + + +if __name__ == '__main__': + # prepare_train_data('', tcopts['time_steps'], mode='train') + # prepare_test_data('', tcopts['time_steps'], mode='test') + train() + diff --git a/meta_updater/venv/bin/activate b/meta_updater/venv/bin/activate new file mode 100755 index 0000000..4335040 --- /dev/null +++ b/meta_updater/venv/bin/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "$_OLD_VIRTUAL_PATH" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then + PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r + fi + + if [ -n "$_OLD_VIRTUAL_PS1" ] ; then + PS1="$_OLD_VIRTUAL_PS1" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "$1" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelavent variables +deactivate nondestructive + +VIRTUAL_ENV="/home/dkn/Tracking/tracker_controller/venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "$PYTHONHOME" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then + _OLD_VIRTUAL_PS1="$PS1" + if [ "x(venv) " != x ] ; then + PS1="(venv) $PS1" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + hash -r +fi diff --git a/meta_updater/venv/bin/activate.csh b/meta_updater/venv/bin/activate.csh new file mode 100755 index 0000000..adfebc2 --- /dev/null +++ b/meta_updater/venv/bin/activate.csh @@ -0,0 +1,37 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelavent variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/dkn/Tracking/tracker_controller/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + if ("venv" != "") then + set env_name = "venv" + else + if (`basename "VIRTUAL_ENV"` == "__") then + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` + else + set env_name = `basename "$VIRTUAL_ENV"` + endif + endif + set prompt = "[$env_name] $prompt" + unset env_name +endif + +alias pydoc python -m pydoc + +rehash diff --git a/meta_updater/venv/bin/activate.fish b/meta_updater/venv/bin/activate.fish new file mode 100755 index 0000000..b871efa --- /dev/null +++ b/meta_updater/venv/bin/activate.fish @@ -0,0 +1,74 @@ +# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) +# you cannot run it directly + +function deactivate -d "Exit virtualenv and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + . ( begin + printf "function fish_prompt\n\t#" + functions _old_fish_prompt + end | psub ) + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + if test "$argv[1]" != "nondestructive" + # Self destruct! + functions -e deactivate + end +end + +# unset irrelavent variables +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/dkn/Tracking/tracker_controller/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# unset PYTHONHOME if set +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # save the current fish_prompt function as the function _old_fish_prompt + . ( begin + printf "function _old_fish_prompt\n\t#" + functions fish_prompt + end | psub ) + + # with the original prompt function renamed, we can override with our own. + function fish_prompt + # Prompt override? + if test -n "$(venv) " + printf "%s%s%s" "$(venv) " (set_color normal) (_old_fish_prompt) + return + end + # ...Otherwise, prepend env + set -l _checkbase (basename "$VIRTUAL_ENV") + if test $_checkbase = "__" + # special case for Aspen magic directories + # see http://www.zetadev.com/software/aspen/ + printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt) + else + printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt) + end + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/meta_updater/venv/bin/easy_install b/meta_updater/venv/bin/easy_install new file mode 100755 index 0000000..54fb1b8 --- /dev/null +++ b/meta_updater/venv/bin/easy_install @@ -0,0 +1,12 @@ +#!/home/dkn/Tracking/tracker_controller/venv/bin/python +# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==39.1.0','console_scripts','easy_install' +__requires__ = 'setuptools==39.1.0' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('setuptools==39.1.0', 'console_scripts', 'easy_install')() + ) diff --git a/meta_updater/venv/bin/easy_install-3.5 b/meta_updater/venv/bin/easy_install-3.5 new file mode 100755 index 0000000..2178756 --- /dev/null +++ b/meta_updater/venv/bin/easy_install-3.5 @@ -0,0 +1,12 @@ +#!/home/dkn/Tracking/tracker_controller/venv/bin/python +# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==39.1.0','console_scripts','easy_install-3.5' +__requires__ = 'setuptools==39.1.0' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('setuptools==39.1.0', 'console_scripts', 'easy_install-3.5')() + ) diff --git a/meta_updater/venv/bin/pip b/meta_updater/venv/bin/pip new file mode 100755 index 0000000..f4e5bb9 --- /dev/null +++ b/meta_updater/venv/bin/pip @@ -0,0 +1,12 @@ +#!/home/dkn/Tracking/tracker_controller/venv/bin/python +# EASY-INSTALL-ENTRY-SCRIPT: 'pip==10.0.1','console_scripts','pip' +__requires__ = 'pip==10.0.1' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('pip==10.0.1', 'console_scripts', 'pip')() + ) diff --git a/meta_updater/venv/bin/pip3 b/meta_updater/venv/bin/pip3 new file mode 100755 index 0000000..15379fe --- /dev/null +++ b/meta_updater/venv/bin/pip3 @@ -0,0 +1,12 @@ +#!/home/dkn/Tracking/tracker_controller/venv/bin/python +# EASY-INSTALL-ENTRY-SCRIPT: 'pip==10.0.1','console_scripts','pip3' +__requires__ = 'pip==10.0.1' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('pip==10.0.1', 'console_scripts', 'pip3')() + ) diff --git a/meta_updater/venv/bin/pip3.5 b/meta_updater/venv/bin/pip3.5 new file mode 100755 index 0000000..64ffb58 --- /dev/null +++ b/meta_updater/venv/bin/pip3.5 @@ -0,0 +1,12 @@ +#!/home/dkn/Tracking/tracker_controller/venv/bin/python +# EASY-INSTALL-ENTRY-SCRIPT: 'pip==10.0.1','console_scripts','pip3.5' +__requires__ = 'pip==10.0.1' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('pip==10.0.1', 'console_scripts', 'pip3.5')() + ) diff --git a/meta_updater/venv/bin/python b/meta_updater/venv/bin/python new file mode 100755 index 0000000..d6cf967 Binary files /dev/null and b/meta_updater/venv/bin/python differ diff --git a/meta_updater/venv/bin/python3 b/meta_updater/venv/bin/python3 new file mode 100755 index 0000000..d6cf967 Binary files /dev/null and b/meta_updater/venv/bin/python3 differ diff --git a/meta_updater/venv/bin/python3.5 b/meta_updater/venv/bin/python3.5 new file mode 100755 index 0000000..d6cf967 Binary files /dev/null and b/meta_updater/venv/bin/python3.5 differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/easy-install.pth b/meta_updater/venv/lib/python3.5/site-packages/easy-install.pth new file mode 100755 index 0000000..8af99eb --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/easy-install.pth @@ -0,0 +1,2 @@ +./setuptools-39.1.0-py3.5.egg +./pip-10.0.1-py3.5.egg diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO new file mode 100755 index 0000000..c91d709 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO @@ -0,0 +1,69 @@ +Metadata-Version: 2.1 +Name: pip +Version: 10.0.1 +Summary: The PyPA recommended tool for installing Python packages. +Home-page: https://pip.pypa.io/ +Author: The pip developers +Author-email: python-virtualenv@groups.google.com +License: MIT +Description: pip + === + + The `PyPA recommended`_ tool for installing Python packages. + + .. image:: https://img.shields.io/pypi/v/pip.svg + :target: https://pypi.org/project/pip/ + + .. image:: https://img.shields.io/travis/pypa/pip/master.svg + :target: http://travis-ci.org/pypa/pip + + .. image:: https://img.shields.io/appveyor/ci/pypa/pip.svg + :target: https://ci.appveyor.com/project/pypa/pip/history + + .. image:: https://readthedocs.org/projects/pip/badge/?version=latest + :target: https://pip.pypa.io/en/latest + + * `Installation`_ + * `Documentation`_ + * `Changelog`_ + * `GitHub Page`_ + * `Issue Tracking`_ + * `User mailing list`_ + * `Dev mailing list`_ + * User IRC: #pypa on Freenode. + * Dev IRC: #pypa-dev on Freenode. + + Code of Conduct + --------------- + + Everyone interacting in the pip project's codebases, issue trackers, chat + rooms and mailing lists is expected to follow the `PyPA Code of Conduct`_. + + .. _PyPA recommended: https://packaging.python.org/en/latest/current/ + .. _Installation: https://pip.pypa.io/en/stable/installing.html + .. _Documentation: https://pip.pypa.io/en/stable/ + .. _Changelog: https://pip.pypa.io/en/stable/news.html + .. _GitHub Page: https://github.com/pypa/pip + .. _Issue Tracking: https://github.com/pypa/pip/issues + .. _User mailing list: http://groups.google.com/group/python-virtualenv + .. _Dev mailing list: http://groups.google.com/group/pypa-dev + .. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ + +Keywords: easy_install distutils setuptools egg virtualenv +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Build Tools +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.* +Provides-Extra: testing diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt new file mode 100755 index 0000000..5a15329 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt @@ -0,0 +1,347 @@ +AUTHORS.txt +LICENSE.txt +MANIFEST.in +NEWS.rst +README.rst +pyproject.toml +setup.cfg +setup.py +docs/Makefile +docs/__init__.py +docs/conf.py +docs/configuration.rst +docs/cookbook.rst +docs/development.rst +docs/docutils.conf +docs/index.rst +docs/installing.rst +docs/logic.rst +docs/make.bat +docs/news.rst +docs/pipext.py +docs/quickstart.rst +docs/usage.rst +docs/user_guide.rst +docs/man/pip.rst +docs/man/commands/check.rst +docs/man/commands/config.rst +docs/man/commands/download.rst +docs/man/commands/freeze.rst +docs/man/commands/hash.rst +docs/man/commands/help.rst +docs/man/commands/install.rst +docs/man/commands/list.rst +docs/man/commands/search.rst +docs/man/commands/show.rst +docs/man/commands/uninstall.rst +docs/man/commands/wheel.rst +docs/reference/index.rst +docs/reference/pip.rst +docs/reference/pip_check.rst +docs/reference/pip_config.rst +docs/reference/pip_download.rst +docs/reference/pip_freeze.rst +docs/reference/pip_hash.rst +docs/reference/pip_install.rst +docs/reference/pip_list.rst +docs/reference/pip_search.rst +docs/reference/pip_show.rst +docs/reference/pip_uninstall.rst +docs/reference/pip_wheel.rst +src/pip/__init__.py +src/pip/__main__.py +src/pip.egg-info/PKG-INFO +src/pip.egg-info/SOURCES.txt +src/pip.egg-info/dependency_links.txt +src/pip.egg-info/entry_points.txt +src/pip.egg-info/not-zip-safe +src/pip.egg-info/requires.txt +src/pip.egg-info/top_level.txt +src/pip/_internal/__init__.py +src/pip/_internal/basecommand.py +src/pip/_internal/baseparser.py +src/pip/_internal/build_env.py +src/pip/_internal/cache.py +src/pip/_internal/cmdoptions.py +src/pip/_internal/compat.py +src/pip/_internal/configuration.py +src/pip/_internal/download.py +src/pip/_internal/exceptions.py +src/pip/_internal/index.py +src/pip/_internal/locations.py +src/pip/_internal/pep425tags.py +src/pip/_internal/resolve.py +src/pip/_internal/status_codes.py +src/pip/_internal/wheel.py +src/pip/_internal/commands/__init__.py +src/pip/_internal/commands/check.py +src/pip/_internal/commands/completion.py +src/pip/_internal/commands/configuration.py +src/pip/_internal/commands/download.py +src/pip/_internal/commands/freeze.py +src/pip/_internal/commands/hash.py +src/pip/_internal/commands/help.py +src/pip/_internal/commands/install.py +src/pip/_internal/commands/list.py +src/pip/_internal/commands/search.py +src/pip/_internal/commands/show.py +src/pip/_internal/commands/uninstall.py +src/pip/_internal/commands/wheel.py +src/pip/_internal/models/__init__.py +src/pip/_internal/models/index.py +src/pip/_internal/operations/__init__.py +src/pip/_internal/operations/check.py +src/pip/_internal/operations/freeze.py +src/pip/_internal/operations/prepare.py +src/pip/_internal/req/__init__.py +src/pip/_internal/req/req_file.py +src/pip/_internal/req/req_install.py +src/pip/_internal/req/req_set.py +src/pip/_internal/req/req_uninstall.py +src/pip/_internal/utils/__init__.py +src/pip/_internal/utils/appdirs.py +src/pip/_internal/utils/deprecation.py +src/pip/_internal/utils/encoding.py +src/pip/_internal/utils/filesystem.py +src/pip/_internal/utils/glibc.py +src/pip/_internal/utils/hashes.py +src/pip/_internal/utils/logging.py +src/pip/_internal/utils/misc.py +src/pip/_internal/utils/outdated.py +src/pip/_internal/utils/packaging.py +src/pip/_internal/utils/setuptools_build.py +src/pip/_internal/utils/temp_dir.py +src/pip/_internal/utils/typing.py +src/pip/_internal/utils/ui.py +src/pip/_internal/vcs/__init__.py +src/pip/_internal/vcs/bazaar.py +src/pip/_internal/vcs/git.py +src/pip/_internal/vcs/mercurial.py +src/pip/_internal/vcs/subversion.py +src/pip/_vendor/README.rst +src/pip/_vendor/__init__.py +src/pip/_vendor/appdirs.py +src/pip/_vendor/distro.py +src/pip/_vendor/ipaddress.py +src/pip/_vendor/pyparsing.py +src/pip/_vendor/retrying.py +src/pip/_vendor/six.py +src/pip/_vendor/vendor.txt +src/pip/_vendor/cachecontrol/__init__.py +src/pip/_vendor/cachecontrol/_cmd.py +src/pip/_vendor/cachecontrol/adapter.py +src/pip/_vendor/cachecontrol/cache.py +src/pip/_vendor/cachecontrol/compat.py +src/pip/_vendor/cachecontrol/controller.py +src/pip/_vendor/cachecontrol/filewrapper.py +src/pip/_vendor/cachecontrol/heuristics.py +src/pip/_vendor/cachecontrol/serialize.py +src/pip/_vendor/cachecontrol/wrapper.py +src/pip/_vendor/cachecontrol/caches/__init__.py +src/pip/_vendor/cachecontrol/caches/file_cache.py +src/pip/_vendor/cachecontrol/caches/redis_cache.py +src/pip/_vendor/certifi/__init__.py +src/pip/_vendor/certifi/__main__.py +src/pip/_vendor/certifi/cacert.pem +src/pip/_vendor/certifi/core.py +src/pip/_vendor/chardet/__init__.py +src/pip/_vendor/chardet/big5freq.py +src/pip/_vendor/chardet/big5prober.py +src/pip/_vendor/chardet/chardistribution.py +src/pip/_vendor/chardet/charsetgroupprober.py +src/pip/_vendor/chardet/charsetprober.py +src/pip/_vendor/chardet/codingstatemachine.py +src/pip/_vendor/chardet/compat.py +src/pip/_vendor/chardet/cp949prober.py +src/pip/_vendor/chardet/enums.py +src/pip/_vendor/chardet/escprober.py +src/pip/_vendor/chardet/escsm.py +src/pip/_vendor/chardet/eucjpprober.py +src/pip/_vendor/chardet/euckrfreq.py +src/pip/_vendor/chardet/euckrprober.py +src/pip/_vendor/chardet/euctwfreq.py +src/pip/_vendor/chardet/euctwprober.py +src/pip/_vendor/chardet/gb2312freq.py +src/pip/_vendor/chardet/gb2312prober.py +src/pip/_vendor/chardet/hebrewprober.py +src/pip/_vendor/chardet/jisfreq.py +src/pip/_vendor/chardet/jpcntx.py +src/pip/_vendor/chardet/langbulgarianmodel.py +src/pip/_vendor/chardet/langcyrillicmodel.py +src/pip/_vendor/chardet/langgreekmodel.py +src/pip/_vendor/chardet/langhebrewmodel.py +src/pip/_vendor/chardet/langhungarianmodel.py +src/pip/_vendor/chardet/langthaimodel.py +src/pip/_vendor/chardet/langturkishmodel.py +src/pip/_vendor/chardet/latin1prober.py +src/pip/_vendor/chardet/mbcharsetprober.py +src/pip/_vendor/chardet/mbcsgroupprober.py +src/pip/_vendor/chardet/mbcssm.py +src/pip/_vendor/chardet/sbcharsetprober.py +src/pip/_vendor/chardet/sbcsgroupprober.py +src/pip/_vendor/chardet/sjisprober.py +src/pip/_vendor/chardet/universaldetector.py +src/pip/_vendor/chardet/utf8prober.py +src/pip/_vendor/chardet/version.py +src/pip/_vendor/chardet/cli/__init__.py +src/pip/_vendor/chardet/cli/chardetect.py +src/pip/_vendor/colorama/__init__.py +src/pip/_vendor/colorama/ansi.py +src/pip/_vendor/colorama/ansitowin32.py +src/pip/_vendor/colorama/initialise.py +src/pip/_vendor/colorama/win32.py +src/pip/_vendor/colorama/winterm.py +src/pip/_vendor/distlib/__init__.py +src/pip/_vendor/distlib/compat.py +src/pip/_vendor/distlib/database.py +src/pip/_vendor/distlib/index.py +src/pip/_vendor/distlib/locators.py +src/pip/_vendor/distlib/manifest.py +src/pip/_vendor/distlib/markers.py +src/pip/_vendor/distlib/metadata.py +src/pip/_vendor/distlib/resources.py +src/pip/_vendor/distlib/scripts.py +src/pip/_vendor/distlib/t32.exe +src/pip/_vendor/distlib/t64.exe +src/pip/_vendor/distlib/util.py +src/pip/_vendor/distlib/version.py +src/pip/_vendor/distlib/w32.exe +src/pip/_vendor/distlib/w64.exe +src/pip/_vendor/distlib/wheel.py +src/pip/_vendor/distlib/_backport/__init__.py +src/pip/_vendor/distlib/_backport/misc.py +src/pip/_vendor/distlib/_backport/shutil.py +src/pip/_vendor/distlib/_backport/sysconfig.cfg +src/pip/_vendor/distlib/_backport/sysconfig.py +src/pip/_vendor/distlib/_backport/tarfile.py +src/pip/_vendor/html5lib/__init__.py +src/pip/_vendor/html5lib/_ihatexml.py +src/pip/_vendor/html5lib/_inputstream.py +src/pip/_vendor/html5lib/_tokenizer.py +src/pip/_vendor/html5lib/_utils.py +src/pip/_vendor/html5lib/constants.py +src/pip/_vendor/html5lib/html5parser.py +src/pip/_vendor/html5lib/serializer.py +src/pip/_vendor/html5lib/_trie/__init__.py +src/pip/_vendor/html5lib/_trie/_base.py +src/pip/_vendor/html5lib/_trie/datrie.py +src/pip/_vendor/html5lib/_trie/py.py +src/pip/_vendor/html5lib/filters/__init__.py +src/pip/_vendor/html5lib/filters/alphabeticalattributes.py +src/pip/_vendor/html5lib/filters/base.py +src/pip/_vendor/html5lib/filters/inject_meta_charset.py +src/pip/_vendor/html5lib/filters/lint.py +src/pip/_vendor/html5lib/filters/optionaltags.py +src/pip/_vendor/html5lib/filters/sanitizer.py +src/pip/_vendor/html5lib/filters/whitespace.py +src/pip/_vendor/html5lib/treeadapters/__init__.py +src/pip/_vendor/html5lib/treeadapters/genshi.py +src/pip/_vendor/html5lib/treeadapters/sax.py +src/pip/_vendor/html5lib/treebuilders/__init__.py +src/pip/_vendor/html5lib/treebuilders/base.py +src/pip/_vendor/html5lib/treebuilders/dom.py +src/pip/_vendor/html5lib/treebuilders/etree.py +src/pip/_vendor/html5lib/treebuilders/etree_lxml.py +src/pip/_vendor/html5lib/treewalkers/__init__.py +src/pip/_vendor/html5lib/treewalkers/base.py +src/pip/_vendor/html5lib/treewalkers/dom.py +src/pip/_vendor/html5lib/treewalkers/etree.py +src/pip/_vendor/html5lib/treewalkers/etree_lxml.py +src/pip/_vendor/html5lib/treewalkers/genshi.py +src/pip/_vendor/idna/__init__.py +src/pip/_vendor/idna/codec.py +src/pip/_vendor/idna/compat.py +src/pip/_vendor/idna/core.py +src/pip/_vendor/idna/idnadata.py +src/pip/_vendor/idna/intranges.py +src/pip/_vendor/idna/package_data.py +src/pip/_vendor/idna/uts46data.py +src/pip/_vendor/lockfile/__init__.py +src/pip/_vendor/lockfile/linklockfile.py +src/pip/_vendor/lockfile/mkdirlockfile.py +src/pip/_vendor/lockfile/pidlockfile.py +src/pip/_vendor/lockfile/sqlitelockfile.py +src/pip/_vendor/lockfile/symlinklockfile.py +src/pip/_vendor/msgpack/__init__.py +src/pip/_vendor/msgpack/_version.py +src/pip/_vendor/msgpack/exceptions.py +src/pip/_vendor/msgpack/fallback.py +src/pip/_vendor/packaging/__about__.py +src/pip/_vendor/packaging/__init__.py +src/pip/_vendor/packaging/_compat.py +src/pip/_vendor/packaging/_structures.py +src/pip/_vendor/packaging/markers.py +src/pip/_vendor/packaging/requirements.py +src/pip/_vendor/packaging/specifiers.py +src/pip/_vendor/packaging/utils.py +src/pip/_vendor/packaging/version.py +src/pip/_vendor/pkg_resources/__init__.py +src/pip/_vendor/pkg_resources/py31compat.py +src/pip/_vendor/progress/__init__.py +src/pip/_vendor/progress/bar.py +src/pip/_vendor/progress/counter.py +src/pip/_vendor/progress/helpers.py +src/pip/_vendor/progress/spinner.py +src/pip/_vendor/pytoml/__init__.py +src/pip/_vendor/pytoml/core.py +src/pip/_vendor/pytoml/parser.py +src/pip/_vendor/pytoml/writer.py +src/pip/_vendor/requests/__init__.py +src/pip/_vendor/requests/__version__.py +src/pip/_vendor/requests/_internal_utils.py +src/pip/_vendor/requests/adapters.py +src/pip/_vendor/requests/api.py +src/pip/_vendor/requests/auth.py +src/pip/_vendor/requests/certs.py +src/pip/_vendor/requests/compat.py +src/pip/_vendor/requests/cookies.py +src/pip/_vendor/requests/exceptions.py +src/pip/_vendor/requests/help.py +src/pip/_vendor/requests/hooks.py +src/pip/_vendor/requests/models.py +src/pip/_vendor/requests/packages.py +src/pip/_vendor/requests/sessions.py +src/pip/_vendor/requests/status_codes.py +src/pip/_vendor/requests/structures.py +src/pip/_vendor/requests/utils.py +src/pip/_vendor/urllib3/__init__.py +src/pip/_vendor/urllib3/_collections.py +src/pip/_vendor/urllib3/connection.py +src/pip/_vendor/urllib3/connectionpool.py +src/pip/_vendor/urllib3/exceptions.py +src/pip/_vendor/urllib3/fields.py +src/pip/_vendor/urllib3/filepost.py +src/pip/_vendor/urllib3/poolmanager.py +src/pip/_vendor/urllib3/request.py +src/pip/_vendor/urllib3/response.py +src/pip/_vendor/urllib3/contrib/__init__.py +src/pip/_vendor/urllib3/contrib/appengine.py +src/pip/_vendor/urllib3/contrib/ntlmpool.py +src/pip/_vendor/urllib3/contrib/pyopenssl.py +src/pip/_vendor/urllib3/contrib/securetransport.py +src/pip/_vendor/urllib3/contrib/socks.py +src/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +src/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +src/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +src/pip/_vendor/urllib3/packages/__init__.py +src/pip/_vendor/urllib3/packages/ordered_dict.py +src/pip/_vendor/urllib3/packages/six.py +src/pip/_vendor/urllib3/packages/backports/__init__.py +src/pip/_vendor/urllib3/packages/backports/makefile.py +src/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py +src/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py +src/pip/_vendor/urllib3/util/__init__.py +src/pip/_vendor/urllib3/util/connection.py +src/pip/_vendor/urllib3/util/request.py +src/pip/_vendor/urllib3/util/response.py +src/pip/_vendor/urllib3/util/retry.py +src/pip/_vendor/urllib3/util/selectors.py +src/pip/_vendor/urllib3/util/ssl_.py +src/pip/_vendor/urllib3/util/timeout.py +src/pip/_vendor/urllib3/util/url.py +src/pip/_vendor/urllib3/util/wait.py +src/pip/_vendor/webencodings/__init__.py +src/pip/_vendor/webencodings/labels.py +src/pip/_vendor/webencodings/mklabels.py +src/pip/_vendor/webencodings/tests.py +src/pip/_vendor/webencodings/x_user_defined.py \ No newline at end of file diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt new file mode 100755 index 0000000..d6133a2 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +pip = pip._internal:main +pip3 = pip._internal:main +pip3.5 = pip._internal:main + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe new file mode 100755 index 0000000..d3f5a12 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt new file mode 100755 index 0000000..fdea1b5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt @@ -0,0 +1,8 @@ + +[testing] +pytest +mock +pretend +scripttest>=1.3 +virtualenv>=1.10 +freezegun diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt new file mode 100755 index 0000000..a1b589e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt @@ -0,0 +1 @@ +pip diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py new file mode 100755 index 0000000..0a3b850 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py @@ -0,0 +1 @@ +__version__ = "10.0.1" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py new file mode 100755 index 0000000..a128ee3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import + +import os +import sys + +# If we are running from a wheel, add the wheel to sys.path +# This allows the usage python pip-*.whl/pip install pip-*.whl +if __package__ == '': + # __file__ is pip-*.whl/pip/__main__.py + # first dirname call strips of '/__main__.py', second strips off '/pip' + # Resulting path is the name of the wheel itself + # Add that to sys.path so we can import pip + path = os.path.dirname(os.path.dirname(__file__)) + sys.path.insert(0, path) + +from pip._internal import main as _main # noqa + +if __name__ == '__main__': + sys.exit(_main()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py new file mode 100755 index 0000000..d713b0d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python +from __future__ import absolute_import + +import locale +import logging +import os +import optparse +import warnings + +import sys + +# 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks, +# but if invoked (i.e. imported), it will issue a warning to stderr if socks +# isn't available. requests unconditionally imports urllib3's socks contrib +# module, triggering this warning. The warning breaks DEP-8 tests (because of +# the stderr output) and is just plain annoying in normal usage. I don't want +# to add socks as yet another dependency for pip, nor do I want to allow-stder +# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to +# be done before the import of pip.vcs. +from pip._vendor.urllib3.exceptions import DependencyWarning +warnings.filterwarnings("ignore", category=DependencyWarning) # noqa + +# We want to inject the use of SecureTransport as early as possible so that any +# references or sessions or what have you are ensured to have it, however we +# only want to do this in the case that we're running on macOS and the linked +# OpenSSL is too old to handle TLSv1.2 +try: + import ssl +except ImportError: + pass +else: + # Checks for OpenSSL 1.0.1 on MacOS + if sys.platform == "darwin" and ssl.OPENSSL_VERSION_NUMBER < 0x1000100f: + try: + from pip._vendor.urllib3.contrib import securetransport + except (ImportError, OSError): + pass + else: + securetransport.inject_into_urllib3() + +from pip import __version__ +from pip._internal import cmdoptions +from pip._internal.exceptions import CommandError, PipError +from pip._internal.utils.misc import get_installed_distributions, get_prog +from pip._internal.utils import deprecation +from pip._internal.vcs import git, mercurial, subversion, bazaar # noqa +from pip._internal.baseparser import ( + ConfigOptionParser, UpdatingDefaultsHelpFormatter, +) +from pip._internal.commands import get_summaries, get_similar_commands +from pip._internal.commands import commands_dict +from pip._vendor.urllib3.exceptions import InsecureRequestWarning + +logger = logging.getLogger(__name__) + +# Hide the InsecureRequestWarning from urllib3 +warnings.filterwarnings("ignore", category=InsecureRequestWarning) + + +def autocomplete(): + """Command and option completion for the main option parser (and options) + and its subcommands (and options). + + Enable by sourcing one of the completion shell scripts (bash, zsh or fish). + """ + # Don't complete if user hasn't sourced bash_completion file. + if 'PIP_AUTO_COMPLETE' not in os.environ: + return + cwords = os.environ['COMP_WORDS'].split()[1:] + cword = int(os.environ['COMP_CWORD']) + try: + current = cwords[cword - 1] + except IndexError: + current = '' + + subcommands = [cmd for cmd, summary in get_summaries()] + options = [] + # subcommand + try: + subcommand_name = [w for w in cwords if w in subcommands][0] + except IndexError: + subcommand_name = None + + parser = create_main_parser() + # subcommand options + if subcommand_name: + # special case: 'help' subcommand has no options + if subcommand_name == 'help': + sys.exit(1) + # special case: list locally installed dists for show and uninstall + should_list_installed = ( + subcommand_name in ['show', 'uninstall'] and + not current.startswith('-') + ) + if should_list_installed: + installed = [] + lc = current.lower() + for dist in get_installed_distributions(local_only=True): + if dist.key.startswith(lc) and dist.key not in cwords[1:]: + installed.append(dist.key) + # if there are no dists installed, fall back to option completion + if installed: + for dist in installed: + print(dist) + sys.exit(1) + + subcommand = commands_dict[subcommand_name]() + + for opt in subcommand.parser.option_list_all: + if opt.help != optparse.SUPPRESS_HELP: + for opt_str in opt._long_opts + opt._short_opts: + options.append((opt_str, opt.nargs)) + + # filter out previously specified options from available options + prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] + options = [(x, v) for (x, v) in options if x not in prev_opts] + # filter options by current input + options = [(k, v) for k, v in options if k.startswith(current)] + for option in options: + opt_label = option[0] + # append '=' to options which require args + if option[1] and option[0][:2] == "--": + opt_label += '=' + print(opt_label) + else: + # show main parser options only when necessary + if current.startswith('-') or current.startswith('--'): + opts = [i.option_list for i in parser.option_groups] + opts.append(parser.option_list) + opts = (o for it in opts for o in it) + + for opt in opts: + if opt.help != optparse.SUPPRESS_HELP: + subcommands += opt._long_opts + opt._short_opts + + print(' '.join([x for x in subcommands if x.startswith(current)])) + sys.exit(1) + + +def create_main_parser(): + parser_kw = { + 'usage': '\n%prog [options]', + 'add_help_option': False, + 'formatter': UpdatingDefaultsHelpFormatter(), + 'name': 'global', + 'prog': get_prog(), + } + + parser = ConfigOptionParser(**parser_kw) + parser.disable_interspersed_args() + + pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + parser.version = 'pip %s from %s (python %s)' % ( + __version__, pip_pkg_dir, sys.version[:3], + ) + + # add the general options + gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) + parser.add_option_group(gen_opts) + + parser.main = True # so the help formatter knows + + # create command listing for description + command_summaries = get_summaries() + description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] + parser.description = '\n'.join(description) + + return parser + + +def parseopts(args): + parser = create_main_parser() + + # Note: parser calls disable_interspersed_args(), so the result of this + # call is to split the initial args into the general options before the + # subcommand and everything else. + # For example: + # args: ['--timeout=5', 'install', '--user', 'INITools'] + # general_options: ['--timeout==5'] + # args_else: ['install', '--user', 'INITools'] + general_options, args_else = parser.parse_args(args) + + # --version + if general_options.version: + sys.stdout.write(parser.version) + sys.stdout.write(os.linesep) + sys.exit() + + # pip || pip help -> print_help() + if not args_else or (args_else[0] == 'help' and len(args_else) == 1): + parser.print_help() + sys.exit() + + # the subcommand name + cmd_name = args_else[0] + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "%s"' % cmd_name] + if guess: + msg.append('maybe you meant "%s"' % guess) + + raise CommandError(' - '.join(msg)) + + # all the args without the subcommand + cmd_args = args[:] + cmd_args.remove(cmd_name) + + return cmd_name, cmd_args + + +def check_isolated(args): + isolated = False + + if "--isolated" in args: + isolated = True + + return isolated + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + # Configure our deprecation warnings to be sent through loggers + deprecation.install_warning_logger() + + autocomplete() + + try: + cmd_name, cmd_args = parseopts(args) + except PipError as exc: + sys.stderr.write("ERROR: %s" % exc) + sys.stderr.write(os.linesep) + sys.exit(1) + + # Needed for locale.getpreferredencoding(False) to work + # in pip._internal.utils.encoding.auto_decode + try: + locale.setlocale(locale.LC_ALL, '') + except locale.Error as e: + # setlocale can apparently crash if locale are uninitialized + logger.debug("Ignoring error %s when setting locale", e) + command = commands_dict[cmd_name](isolated=check_isolated(cmd_args)) + return command.main(cmd_args) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py new file mode 100755 index 0000000..e900928 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py @@ -0,0 +1,373 @@ +"""Base Command class, and related routines""" +from __future__ import absolute_import + +import logging +import logging.config +import optparse +import os +import sys +import warnings + +from pip._internal import cmdoptions +from pip._internal.baseparser import ( + ConfigOptionParser, UpdatingDefaultsHelpFormatter, +) +from pip._internal.compat import WINDOWS +from pip._internal.download import PipSession +from pip._internal.exceptions import ( + BadCommand, CommandError, InstallationError, PreviousBuildDirError, + UninstallationError, +) +from pip._internal.index import PackageFinder +from pip._internal.locations import running_under_virtualenv +from pip._internal.req.req_file import parse_requirements +from pip._internal.req.req_install import InstallRequirement +from pip._internal.status_codes import ( + ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR, + VIRTUALENV_NOT_FOUND, +) +from pip._internal.utils import deprecation +from pip._internal.utils.logging import IndentingFormatter +from pip._internal.utils.misc import get_prog, normalize_path +from pip._internal.utils.outdated import pip_version_check +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + +__all__ = ['Command'] + +logger = logging.getLogger(__name__) + + +class Command(object): + name = None # type: Optional[str] + usage = None # type: Optional[str] + hidden = False # type: bool + ignore_require_venv = False # type: bool + log_streams = ("ext://sys.stdout", "ext://sys.stderr") + + def __init__(self, isolated=False): + parser_kw = { + 'usage': self.usage, + 'prog': '%s %s' % (get_prog(), self.name), + 'formatter': UpdatingDefaultsHelpFormatter(), + 'add_help_option': False, + 'name': self.name, + 'description': self.__doc__, + 'isolated': isolated, + } + + self.parser = ConfigOptionParser(**parser_kw) + + # Commands should add options to this option group + optgroup_name = '%s Options' % self.name.capitalize() + self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) + + # Add the general options + gen_opts = cmdoptions.make_option_group( + cmdoptions.general_group, + self.parser, + ) + self.parser.add_option_group(gen_opts) + + def _build_session(self, options, retries=None, timeout=None): + session = PipSession( + cache=( + normalize_path(os.path.join(options.cache_dir, "http")) + if options.cache_dir else None + ), + retries=retries if retries is not None else options.retries, + insecure_hosts=options.trusted_hosts, + ) + + # Handle custom ca-bundles from the user + if options.cert: + session.verify = options.cert + + # Handle SSL client certificate + if options.client_cert: + session.cert = options.client_cert + + # Handle timeouts + if options.timeout or timeout: + session.timeout = ( + timeout if timeout is not None else options.timeout + ) + + # Handle configured proxies + if options.proxy: + session.proxies = { + "http": options.proxy, + "https": options.proxy, + } + + # Determine if we can prompt the user for authentication or not + session.auth.prompting = not options.no_input + + return session + + def parse_args(self, args): + # factored out for testability + return self.parser.parse_args(args) + + def main(self, args): + options, args = self.parse_args(args) + + # Set verbosity so that it can be used elsewhere. + self.verbosity = options.verbose - options.quiet + + if self.verbosity >= 1: + level = "DEBUG" + elif self.verbosity == -1: + level = "WARNING" + elif self.verbosity == -2: + level = "ERROR" + elif self.verbosity <= -3: + level = "CRITICAL" + else: + level = "INFO" + + # The root logger should match the "console" level *unless* we + # specified "--log" to send debug logs to a file. + root_level = level + if options.log: + root_level = "DEBUG" + + logger_class = "pip._internal.utils.logging.ColorizedStreamHandler" + handler_class = "pip._internal.utils.logging.BetterRotatingFileHandler" + + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "filters": { + "exclude_warnings": { + "()": "pip._internal.utils.logging.MaxLevelFilter", + "level": logging.WARNING, + }, + }, + "formatters": { + "indent": { + "()": IndentingFormatter, + "format": "%(message)s", + }, + }, + "handlers": { + "console": { + "level": level, + "class": logger_class, + "no_color": options.no_color, + "stream": self.log_streams[0], + "filters": ["exclude_warnings"], + "formatter": "indent", + }, + "console_errors": { + "level": "WARNING", + "class": logger_class, + "no_color": options.no_color, + "stream": self.log_streams[1], + "formatter": "indent", + }, + "user_log": { + "level": "DEBUG", + "class": handler_class, + "filename": options.log or "/dev/null", + "delay": True, + "formatter": "indent", + }, + }, + "root": { + "level": root_level, + "handlers": list(filter(None, [ + "console", + "console_errors", + "user_log" if options.log else None, + ])), + }, + # Disable any logging besides WARNING unless we have DEBUG level + # logging enabled. These use both pip._vendor and the bare names + # for the case where someone unbundles our libraries. + "loggers": { + name: { + "level": ( + "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" + ) + } for name in [ + "pip._vendor", "distlib", "requests", "urllib3" + ] + }, + }) + + if sys.version_info[:2] == (3, 3): + warnings.warn( + "Python 3.3 supported has been deprecated and support for it " + "will be dropped in the future. Please upgrade your Python.", + deprecation.RemovedInPip11Warning, + ) + + # TODO: try to get these passing down from the command? + # without resorting to os.environ to hold these. + + if options.no_input: + os.environ['PIP_NO_INPUT'] = '1' + + if options.exists_action: + os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) + + if options.require_venv and not self.ignore_require_venv: + # If a venv is required check if it can really be found + if not running_under_virtualenv(): + logger.critical( + 'Could not find an activated virtualenv (required).' + ) + sys.exit(VIRTUALENV_NOT_FOUND) + + original_root_handlers = set(logging.root.handlers) + + try: + status = self.run(options, args) + # FIXME: all commands should return an exit status + # and when it is done, isinstance is not needed anymore + if isinstance(status, int): + return status + except PreviousBuildDirError as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return PREVIOUS_BUILD_DIR_ERROR + except (InstallationError, UninstallationError, BadCommand) as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except CommandError as exc: + logger.critical('ERROR: %s', exc) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except KeyboardInterrupt: + logger.critical('Operation cancelled by user') + logger.debug('Exception information:', exc_info=True) + + return ERROR + except: + logger.critical('Exception:', exc_info=True) + + return UNKNOWN_ERROR + finally: + # Check if we're using the latest version of pip available + if (not options.disable_pip_version_check and not + getattr(options, "no_index", False)): + with self._build_session( + options, + retries=0, + timeout=min(5, options.timeout)) as session: + pip_version_check(session, options) + # Avoid leaking loggers + for handler in set(logging.root.handlers) - original_root_handlers: + # this method benefit from the Logger class internal lock + logging.root.removeHandler(handler) + + return SUCCESS + + +class RequirementCommand(Command): + + @staticmethod + def populate_requirement_set(requirement_set, args, options, finder, + session, name, wheel_cache): + """ + Marshal cmd line args into a requirement set. + """ + # NOTE: As a side-effect, options.require_hashes and + # requirement_set.require_hashes may be updated + + for filename in options.constraints: + for req_to_add in parse_requirements( + filename, + constraint=True, finder=finder, options=options, + session=session, wheel_cache=wheel_cache): + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in args: + req_to_add = InstallRequirement.from_line( + req, None, isolated=options.isolated_mode, + wheel_cache=wheel_cache + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in options.editables: + req_to_add = InstallRequirement.from_editable( + req, + isolated=options.isolated_mode, + wheel_cache=wheel_cache + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for filename in options.requirements: + for req_to_add in parse_requirements( + filename, + finder=finder, options=options, session=session, + wheel_cache=wheel_cache): + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + # If --require-hashes was a line in a requirements file, tell + # RequirementSet about it: + requirement_set.require_hashes = options.require_hashes + + if not (args or options.editables or options.requirements): + opts = {'name': name} + if options.find_links: + raise CommandError( + 'You must give at least one requirement to %(name)s ' + '(maybe you meant "pip %(name)s %(links)s"?)' % + dict(opts, links=' '.join(options.find_links))) + else: + raise CommandError( + 'You must give at least one requirement to %(name)s ' + '(see "pip help %(name)s")' % opts) + + # On Windows, any operation modifying pip should be run as: + # python -m pip ... + # See https://github.com/pypa/pip/issues/1299 for more discussion + should_show_use_python_msg = ( + WINDOWS and + requirement_set.has_requirement("pip") and + os.path.basename(sys.argv[0]).startswith("pip") + ) + if should_show_use_python_msg: + new_command = [ + sys.executable, "-m", "pip" + ] + sys.argv[1:] + raise CommandError( + 'To modify pip, please run the following command:\n{}' + .format(" ".join(new_command)) + ) + + def _build_package_finder(self, options, session, + platform=None, python_versions=None, + abi=None, implementation=None): + """ + Create a package finder appropriate to this requirement command. + """ + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + return PackageFinder( + find_links=options.find_links, + format_control=options.format_control, + index_urls=index_urls, + trusted_hosts=options.trusted_hosts, + allow_all_prereleases=options.pre, + process_dependency_links=options.process_dependency_links, + session=session, + platform=platform, + versions=python_versions, + abi=abi, + implementation=implementation, + ) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py new file mode 100755 index 0000000..ed28a1b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py @@ -0,0 +1,240 @@ +"""Base option parser setup""" +from __future__ import absolute_import + +import logging +import optparse +import sys +import textwrap +from distutils.util import strtobool + +from pip._vendor.six import string_types + +from pip._internal.compat import get_terminal_size +from pip._internal.configuration import Configuration, ConfigurationError + +logger = logging.getLogger(__name__) + + +class PrettyHelpFormatter(optparse.IndentedHelpFormatter): + """A prettier/less verbose help formatter for optparse.""" + + def __init__(self, *args, **kwargs): + # help position must be aligned with __init__.parseopts.description + kwargs['max_help_position'] = 30 + kwargs['indent_increment'] = 1 + kwargs['width'] = get_terminal_size()[0] - 2 + optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) + + def format_option_strings(self, option): + return self._format_option_strings(option, ' <%s>', ', ') + + def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '): + """ + Return a comma-separated list of option strings and metavars. + + :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') + :param mvarfmt: metavar format string - evaluated as mvarfmt % metavar + :param optsep: separator + """ + opts = [] + + if option._short_opts: + opts.append(option._short_opts[0]) + if option._long_opts: + opts.append(option._long_opts[0]) + if len(opts) > 1: + opts.insert(1, optsep) + + if option.takes_value(): + metavar = option.metavar or option.dest.lower() + opts.append(mvarfmt % metavar.lower()) + + return ''.join(opts) + + def format_heading(self, heading): + if heading == 'Options': + return '' + return heading + ':\n' + + def format_usage(self, usage): + """ + Ensure there is only one newline between usage and the first heading + if there is no description. + """ + msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), " ") + return msg + + def format_description(self, description): + # leave full control over description to us + if description: + if hasattr(self.parser, 'main'): + label = 'Commands' + else: + label = 'Description' + # some doc strings have initial newlines, some don't + description = description.lstrip('\n') + # some doc strings have final newlines and spaces, some don't + description = description.rstrip() + # dedent, then reindent + description = self.indent_lines(textwrap.dedent(description), " ") + description = '%s:\n%s\n' % (label, description) + return description + else: + return '' + + def format_epilog(self, epilog): + # leave full control over epilog to us + if epilog: + return epilog + else: + return '' + + def indent_lines(self, text, indent): + new_lines = [indent + line for line in text.split('\n')] + return "\n".join(new_lines) + + +class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): + """Custom help formatter for use in ConfigOptionParser. + + This is updates the defaults before expanding them, allowing + them to show up correctly in the help listing. + """ + + def expand_default(self, option): + if self.parser is not None: + self.parser._update_defaults(self.parser.defaults) + return optparse.IndentedHelpFormatter.expand_default(self, option) + + +class CustomOptionParser(optparse.OptionParser): + + def insert_option_group(self, idx, *args, **kwargs): + """Insert an OptionGroup at a given position.""" + group = self.add_option_group(*args, **kwargs) + + self.option_groups.pop() + self.option_groups.insert(idx, group) + + return group + + @property + def option_list_all(self): + """Get a list of all options, including those in option groups.""" + res = self.option_list[:] + for i in self.option_groups: + res.extend(i.option_list) + + return res + + +class ConfigOptionParser(CustomOptionParser): + """Custom option parser which updates its defaults by checking the + configuration files and environmental variables""" + + def __init__(self, *args, **kwargs): + self.name = kwargs.pop('name') + + isolated = kwargs.pop("isolated", False) + self.config = Configuration(isolated) + + assert self.name + optparse.OptionParser.__init__(self, *args, **kwargs) + + def check_default(self, option, key, val): + try: + return option.check_value(key, val) + except optparse.OptionValueError as exc: + print("An error occurred during configuration: %s" % exc) + sys.exit(3) + + def _get_ordered_configuration_items(self): + # Configuration gives keys in an unordered manner. Order them. + override_order = ["global", self.name, ":env:"] + + # Pool the options into different groups + section_items = {name: [] for name in override_order} + for section_key, val in self.config.items(): + # ignore empty values + if not val: + logger.debug( + "Ignoring configuration key '%s' as it's value is empty.", + section_key + ) + continue + + section, key = section_key.split(".", 1) + if section in override_order: + section_items[section].append((key, val)) + + # Yield each group in their override order + for section in override_order: + for key, val in section_items[section]: + yield key, val + + def _update_defaults(self, defaults): + """Updates the given defaults with values from the config files and + the environ. Does a little special handling for certain types of + options (lists).""" + + # Accumulate complex default state. + self.values = optparse.Values(self.defaults) + late_eval = set() + # Then set the options with those values + for key, val in self._get_ordered_configuration_items(): + # '--' because configuration supports only long names + option = self.get_option('--' + key) + + # Ignore options not present in this parser. E.g. non-globals put + # in [global] by users that want them to apply to all applicable + # commands. + if option is None: + continue + + if option.action in ('store_true', 'store_false', 'count'): + val = strtobool(val) + elif option.action == 'append': + val = val.split() + val = [self.check_default(option, key, v) for v in val] + elif option.action == 'callback': + late_eval.add(option.dest) + opt_str = option.get_opt_string() + val = option.convert_value(opt_str, val) + # From take_action + args = option.callback_args or () + kwargs = option.callback_kwargs or {} + option.callback(option, opt_str, val, self, *args, **kwargs) + else: + val = self.check_default(option, key, val) + + defaults[option.dest] = val + + for key in late_eval: + defaults[key] = getattr(self.values, key) + self.values = None + return defaults + + def get_default_values(self): + """Overriding to make updating the defaults after instantiation of + the option parser possible, _update_defaults() does the dirty work.""" + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return optparse.Values(self.defaults) + + # Load the configuration, or error out in case of an error + try: + self.config.load() + except ConfigurationError as err: + self.exit(2, err.args[0]) + + defaults = self._update_defaults(self.defaults.copy()) # ours + for option in self._get_all_options(): + default = defaults.get(option.dest) + if isinstance(default, string_types): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + return optparse.Values(defaults) + + def error(self, msg): + self.print_usage(sys.stderr) + self.exit(2, "%s\n" % msg) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py new file mode 100755 index 0000000..8ad7735 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py @@ -0,0 +1,92 @@ +"""Build Environment used for isolation during sdist building +""" + +import os +from distutils.sysconfig import get_python_lib +from sysconfig import get_paths + +from pip._internal.utils.temp_dir import TempDirectory + + +class BuildEnvironment(object): + """Creates and manages an isolated environment to install build deps + """ + + def __init__(self, no_clean): + self._temp_dir = TempDirectory(kind="build-env") + self._no_clean = no_clean + + @property + def path(self): + return self._temp_dir.path + + def __enter__(self): + self._temp_dir.create() + + self.save_path = os.environ.get('PATH', None) + self.save_pythonpath = os.environ.get('PYTHONPATH', None) + self.save_nousersite = os.environ.get('PYTHONNOUSERSITE', None) + + install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix' + install_dirs = get_paths(install_scheme, vars={ + 'base': self.path, + 'platbase': self.path, + }) + + scripts = install_dirs['scripts'] + if self.save_path: + os.environ['PATH'] = scripts + os.pathsep + self.save_path + else: + os.environ['PATH'] = scripts + os.pathsep + os.defpath + + # Note: prefer distutils' sysconfig to get the + # library paths so PyPy is correctly supported. + purelib = get_python_lib(plat_specific=0, prefix=self.path) + platlib = get_python_lib(plat_specific=1, prefix=self.path) + if purelib == platlib: + lib_dirs = purelib + else: + lib_dirs = purelib + os.pathsep + platlib + if self.save_pythonpath: + os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \ + self.save_pythonpath + else: + os.environ['PYTHONPATH'] = lib_dirs + + os.environ['PYTHONNOUSERSITE'] = '1' + + return self.path + + def __exit__(self, exc_type, exc_val, exc_tb): + if not self._no_clean: + self._temp_dir.cleanup() + + def restore_var(varname, old_value): + if old_value is None: + os.environ.pop(varname, None) + else: + os.environ[varname] = old_value + + restore_var('PATH', self.save_path) + restore_var('PYTHONPATH', self.save_pythonpath) + restore_var('PYTHONNOUSERSITE', self.save_nousersite) + + def cleanup(self): + self._temp_dir.cleanup() + + +class NoOpBuildEnvironment(BuildEnvironment): + """A no-op drop-in replacement for BuildEnvironment + """ + + def __init__(self, no_clean): + pass + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + def cleanup(self): + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py new file mode 100755 index 0000000..5547d73 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py @@ -0,0 +1,202 @@ +"""Cache Management +""" + +import errno +import hashlib +import logging +import os + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal import index +from pip._internal.compat import expanduser +from pip._internal.download import path_to_url +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import InvalidWheelFilename, Wheel + +logger = logging.getLogger(__name__) + + +class Cache(object): + """An abstract class - provides cache directories for data from links + + + :param cache_dir: The root of the cache. + :param format_control: A pip.index.FormatControl object to limit + binaries being read from the cache. + :param allowed_formats: which formats of files the cache should store. + ('binary' and 'source' are the only allowed values) + """ + + def __init__(self, cache_dir, format_control, allowed_formats): + super(Cache, self).__init__() + self.cache_dir = expanduser(cache_dir) if cache_dir else None + self.format_control = format_control + self.allowed_formats = allowed_formats + + _valid_formats = {"source", "binary"} + assert self.allowed_formats.union(_valid_formats) == _valid_formats + + def _get_cache_path_parts(self, link): + """Get parts of part that must be os.path.joined with cache_dir + """ + + # We want to generate an url to use as our cache key, we don't want to + # just re-use the URL because it might have other items in the fragment + # and we don't care about those. + key_parts = [link.url_without_fragment] + if link.hash_name is not None and link.hash is not None: + key_parts.append("=".join([link.hash_name, link.hash])) + key_url = "#".join(key_parts) + + # Encode our key url with sha224, we'll use this because it has similar + # security properties to sha256, but with a shorter total output (and + # thus less secure). However the differences don't make a lot of + # difference for our use case here. + hashed = hashlib.sha224(key_url.encode()).hexdigest() + + # We want to nest the directories some to prevent having a ton of top + # level directories where we might run out of sub directories on some + # FS. + parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] + + return parts + + def _get_candidates(self, link, package_name): + can_not_cache = ( + not self.cache_dir or + not package_name or + not link + ) + if can_not_cache: + return [] + + canonical_name = canonicalize_name(package_name) + formats = index.fmt_ctl_formats( + self.format_control, canonical_name + ) + if not self.allowed_formats.intersection(formats): + return [] + + root = self.get_path_for_link(link) + try: + return os.listdir(root) + except OSError as err: + if err.errno in {errno.ENOENT, errno.ENOTDIR}: + return [] + raise + + def get_path_for_link(self, link): + """Return a directory to store cached items in for link. + """ + raise NotImplementedError() + + def get(self, link, package_name): + """Returns a link to a cached item if it exists, otherwise returns the + passed link. + """ + raise NotImplementedError() + + def _link_for_candidate(self, link, candidate): + root = self.get_path_for_link(link) + path = os.path.join(root, candidate) + + return index.Link(path_to_url(path)) + + def cleanup(self): + pass + + +class SimpleWheelCache(Cache): + """A cache of wheels for future installs. + """ + + def __init__(self, cache_dir, format_control): + super(SimpleWheelCache, self).__init__( + cache_dir, format_control, {"binary"} + ) + + def get_path_for_link(self, link): + """Return a directory to store cached wheels for link + + Because there are M wheels for any one sdist, we provide a directory + to cache them in, and then consult that directory when looking up + cache hits. + + We only insert things into the cache if they have plausible version + numbers, so that we don't contaminate the cache with things that were + not unique. E.g. ./package might have dozens of installs done for it + and build a version of 0.0...and if we built and cached a wheel, we'd + end up using the same wheel even if the source has been edited. + + :param link: The link of the sdist for which this will cache wheels. + """ + parts = self._get_cache_path_parts(link) + + # Store wheels within the root cache_dir + return os.path.join(self.cache_dir, "wheels", *parts) + + def get(self, link, package_name): + candidates = [] + + for wheel_name in self._get_candidates(link, package_name): + try: + wheel = Wheel(wheel_name) + except InvalidWheelFilename: + continue + if not wheel.supported(): + # Built for a different python/arch/etc + continue + candidates.append((wheel.support_index_min(), wheel_name)) + + if not candidates: + return link + + return self._link_for_candidate(link, min(candidates)[1]) + + +class EphemWheelCache(SimpleWheelCache): + """A SimpleWheelCache that creates it's own temporary cache directory + """ + + def __init__(self, format_control): + self._temp_dir = TempDirectory(kind="ephem-wheel-cache") + self._temp_dir.create() + + super(EphemWheelCache, self).__init__( + self._temp_dir.path, format_control + ) + + def cleanup(self): + self._temp_dir.cleanup() + + +class WheelCache(Cache): + """Wraps EphemWheelCache and SimpleWheelCache into a single Cache + + This Cache allows for gracefully degradation, using the ephem wheel cache + when a certain link is not found in the simple wheel cache first. + """ + + def __init__(self, cache_dir, format_control): + super(WheelCache, self).__init__( + cache_dir, format_control, {'binary'} + ) + self._wheel_cache = SimpleWheelCache(cache_dir, format_control) + self._ephem_cache = EphemWheelCache(format_control) + + def get_path_for_link(self, link): + return self._wheel_cache.get_path_for_link(link) + + def get_ephem_path_for_link(self, link): + return self._ephem_cache.get_path_for_link(link) + + def get(self, link, package_name): + retval = self._wheel_cache.get(link, package_name) + if retval is link: + retval = self._ephem_cache.get(link, package_name) + return retval + + def cleanup(self): + self._wheel_cache.cleanup() + self._ephem_cache.cleanup() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py new file mode 100755 index 0000000..58854e3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py @@ -0,0 +1,609 @@ +""" +shared options and groups + +The principle here is to define options once, but *not* instantiate them +globally. One reason being that options with action='append' can carry state +between parses. pip parses general options twice internally, and shouldn't +pass on state. To be consistent, all options will follow this design. + +""" +from __future__ import absolute_import + +import warnings +from functools import partial +from optparse import SUPPRESS_HELP, Option, OptionGroup + +from pip._internal.index import ( + FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_binary, +) +from pip._internal.locations import USER_CACHE_DIR, src_prefix +from pip._internal.models import PyPI +from pip._internal.utils.hashes import STRONG_HASHES +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.ui import BAR_TYPES + +if MYPY_CHECK_RUNNING: + from typing import Any + + +def make_option_group(group, parser): + """ + Return an OptionGroup object + group -- assumed to be dict with 'name' and 'options' keys + parser -- an optparse Parser + """ + option_group = OptionGroup(parser, group['name']) + for option in group['options']: + option_group.add_option(option()) + return option_group + + +def check_install_build_global(options, check_options=None): + """Disable wheels if per-setup.py call options are set. + + :param options: The OptionParser options to update. + :param check_options: The options to check, if not supplied defaults to + options. + """ + if check_options is None: + check_options = options + + def getname(n): + return getattr(check_options, n, None) + names = ["build_options", "global_options", "install_options"] + if any(map(getname, names)): + control = options.format_control + fmt_ctl_no_binary(control) + warnings.warn( + 'Disabling all use of wheels due to the use of --build-options ' + '/ --global-options / --install-options.', stacklevel=2, + ) + + +########### +# options # +########### + +help_ = partial( + Option, + '-h', '--help', + dest='help', + action='help', + help='Show help.', +) # type: Any + +isolated_mode = partial( + Option, + "--isolated", + dest="isolated_mode", + action="store_true", + default=False, + help=( + "Run pip in an isolated mode, ignoring environment variables and user " + "configuration." + ), +) + +require_virtualenv = partial( + Option, + # Run only if inside a virtualenv, bail if not. + '--require-virtualenv', '--require-venv', + dest='require_venv', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Any + +verbose = partial( + Option, + '-v', '--verbose', + dest='verbose', + action='count', + default=0, + help='Give more output. Option is additive, and can be used up to 3 times.' +) + +no_color = partial( + Option, + '--no-color', + dest='no_color', + action='store_true', + default=False, + help="Suppress colored output", +) + +version = partial( + Option, + '-V', '--version', + dest='version', + action='store_true', + help='Show version and exit.', +) # type: Any + +quiet = partial( + Option, + '-q', '--quiet', + dest='quiet', + action='count', + default=0, + help=( + 'Give less output. Option is additive, and can be used up to 3' + ' times (corresponding to WARNING, ERROR, and CRITICAL logging' + ' levels).' + ), +) # type: Any + +progress_bar = partial( + Option, + '--progress-bar', + dest='progress_bar', + type='choice', + choices=list(BAR_TYPES.keys()), + default='on', + help=( + 'Specify type of progress to be displayed [' + + '|'.join(BAR_TYPES.keys()) + '] (default: %default)' + ), +) # type: Any + +log = partial( + Option, + "--log", "--log-file", "--local-log", + dest="log", + metavar="path", + help="Path to a verbose appending log." +) # type: Any + +no_input = partial( + Option, + # Don't ask for input + '--no-input', + dest='no_input', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Any + +proxy = partial( + Option, + '--proxy', + dest='proxy', + type='str', + default='', + help="Specify a proxy in the form [user:passwd@]proxy.server:port." +) # type: Any + +retries = partial( + Option, + '--retries', + dest='retries', + type='int', + default=5, + help="Maximum number of retries each connection should attempt " + "(default %default times).", +) # type: Any + +timeout = partial( + Option, + '--timeout', '--default-timeout', + metavar='sec', + dest='timeout', + type='float', + default=15, + help='Set the socket timeout (default %default seconds).', +) # type: Any + +skip_requirements_regex = partial( + Option, + # A regex to be used to skip requirements + '--skip-requirements-regex', + dest='skip_requirements_regex', + type='str', + default='', + help=SUPPRESS_HELP, +) # type: Any + + +def exists_action(): + return Option( + # Option when path already exist + '--exists-action', + dest='exists_action', + type='choice', + choices=['s', 'i', 'w', 'b', 'a'], + default=[], + action='append', + metavar='action', + help="Default action when a path already exists: " + "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).", + ) + + +cert = partial( + Option, + '--cert', + dest='cert', + type='str', + metavar='path', + help="Path to alternate CA bundle.", +) # type: Any + +client_cert = partial( + Option, + '--client-cert', + dest='client_cert', + type='str', + default=None, + metavar='path', + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM format.", +) # type: Any + +index_url = partial( + Option, + '-i', '--index-url', '--pypi-url', + dest='index_url', + metavar='URL', + default=PyPI.simple_url, + help="Base URL of Python Package Index (default %default). " + "This should point to a repository compliant with PEP 503 " + "(the simple repository API) or a local directory laid out " + "in the same format.", +) # type: Any + + +def extra_index_url(): + return Option( + '--extra-index-url', + dest='extra_index_urls', + metavar='URL', + action='append', + default=[], + help="Extra URLs of package indexes to use in addition to " + "--index-url. Should follow the same rules as " + "--index-url.", + ) + + +no_index = partial( + Option, + '--no-index', + dest='no_index', + action='store_true', + default=False, + help='Ignore package index (only looking at --find-links URLs instead).', +) # type: Any + + +def find_links(): + return Option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='url', + help="If a url or path to an html file, then parse for links to " + "archives. If a local path or file:// url that's a directory, " + "then look for archives in the directory listing.", + ) + + +def trusted_host(): + return Option( + "--trusted-host", + dest="trusted_hosts", + action="append", + metavar="HOSTNAME", + default=[], + help="Mark this host as trusted, even though it does not have valid " + "or any HTTPS.", + ) + + +# Remove after 1.5 +process_dependency_links = partial( + Option, + "--process-dependency-links", + dest="process_dependency_links", + action="store_true", + default=False, + help="Enable the processing of dependency links.", +) # type: Any + + +def constraints(): + return Option( + '-c', '--constraint', + dest='constraints', + action='append', + default=[], + metavar='file', + help='Constrain versions using the given constraints file. ' + 'This option can be used multiple times.' + ) + + +def requirements(): + return Option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Install from the given requirements file. ' + 'This option can be used multiple times.' + ) + + +def editable(): + return Option( + '-e', '--editable', + dest='editables', + action='append', + default=[], + metavar='path/url', + help=('Install a project in editable mode (i.e. setuptools ' + '"develop mode") from a local project path or a VCS url.'), + ) + + +src = partial( + Option, + '--src', '--source', '--source-dir', '--source-directory', + dest='src_dir', + metavar='dir', + default=src_prefix, + help='Directory to check out editable projects into. ' + 'The default in a virtualenv is "/src". ' + 'The default for global installs is "/src".' +) # type: Any + + +def _get_format_control(values, option): + """Get a format_control object.""" + return getattr(values, option.dest) + + +def _handle_no_binary(option, opt_str, value, parser): + existing = getattr(parser.values, option.dest) + fmt_ctl_handle_mutual_exclude( + value, existing.no_binary, existing.only_binary, + ) + + +def _handle_only_binary(option, opt_str, value, parser): + existing = getattr(parser.values, option.dest) + fmt_ctl_handle_mutual_exclude( + value, existing.only_binary, existing.no_binary, + ) + + +def no_binary(): + return Option( + "--no-binary", dest="format_control", action="callback", + callback=_handle_no_binary, type="str", + default=FormatControl(set(), set()), + help="Do not use binary packages. Can be supplied multiple times, and " + "each time adds to the existing value. Accepts either :all: to " + "disable all binary packages, :none: to empty the set, or one or " + "more package names with commas between them. Note that some " + "packages are tricky to compile and may fail to install when " + "this option is used on them.", + ) + + +def only_binary(): + return Option( + "--only-binary", dest="format_control", action="callback", + callback=_handle_only_binary, type="str", + default=FormatControl(set(), set()), + help="Do not use source packages. Can be supplied multiple times, and " + "each time adds to the existing value. Accepts either :all: to " + "disable all source packages, :none: to empty the set, or one or " + "more package names with commas between them. Packages without " + "binary distributions will fail to install when this option is " + "used on them.", + ) + + +cache_dir = partial( + Option, + "--cache-dir", + dest="cache_dir", + default=USER_CACHE_DIR, + metavar="dir", + help="Store the cache data in ." +) + +no_cache = partial( + Option, + "--no-cache-dir", + dest="cache_dir", + action="store_false", + help="Disable the cache.", +) + +no_deps = partial( + Option, + '--no-deps', '--no-dependencies', + dest='ignore_dependencies', + action='store_true', + default=False, + help="Don't install package dependencies.", +) # type: Any + +build_dir = partial( + Option, + '-b', '--build', '--build-dir', '--build-directory', + dest='build_dir', + metavar='dir', + help='Directory to unpack packages into and build in. Note that ' + 'an initial build still takes place in a temporary directory. ' + 'The location of temporary directories can be controlled by setting ' + 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' + 'When passed, build directories are not cleaned in case of failures.' +) # type: Any + +ignore_requires_python = partial( + Option, + '--ignore-requires-python', + dest='ignore_requires_python', + action='store_true', + help='Ignore the Requires-Python information.' +) # type: Any + +no_build_isolation = partial( + Option, + '--no-build-isolation', + dest='build_isolation', + action='store_false', + default=True, + help='Disable isolation when building a modern source distribution. ' + 'Build dependencies specified by PEP 518 must be already installed ' + 'if this option is used.' +) # type: Any + +install_options = partial( + Option, + '--install-option', + dest='install_options', + action='append', + metavar='options', + help="Extra arguments to be supplied to the setup.py install " + "command (use like --install-option=\"--install-scripts=/usr/local/" + "bin\"). Use multiple --install-option options to pass multiple " + "options to setup.py install. If you are using an option with a " + "directory path, be sure to use absolute path.", +) # type: Any + +global_options = partial( + Option, + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the install command.", +) # type: Any + +no_clean = partial( + Option, + '--no-clean', + action='store_true', + default=False, + help="Don't clean up build directories)." +) # type: Any + +pre = partial( + Option, + '--pre', + action='store_true', + default=False, + help="Include pre-release and development versions. By default, " + "pip only finds stable versions.", +) # type: Any + +disable_pip_version_check = partial( + Option, + "--disable-pip-version-check", + dest="disable_pip_version_check", + action="store_true", + default=False, + help="Don't periodically check PyPI to determine whether a new version " + "of pip is available for download. Implied with --no-index.", +) # type: Any + + +# Deprecated, Remove later +always_unzip = partial( + Option, + '-Z', '--always-unzip', + dest='always_unzip', + action='store_true', + help=SUPPRESS_HELP, +) # type: Any + + +def _merge_hash(option, opt_str, value, parser): + """Given a value spelled "algo:digest", append the digest to a list + pointed to in a dict by the algo name.""" + if not parser.values.hashes: + parser.values.hashes = {} + try: + algo, digest = value.split(':', 1) + except ValueError: + parser.error('Arguments to %s must be a hash name ' + 'followed by a value, like --hash=sha256:abcde...' % + opt_str) + if algo not in STRONG_HASHES: + parser.error('Allowed hash algorithms for %s are %s.' % + (opt_str, ', '.join(STRONG_HASHES))) + parser.values.hashes.setdefault(algo, []).append(digest) + + +hash = partial( + Option, + '--hash', + # Hash values eventually end up in InstallRequirement.hashes due to + # __dict__ copying in process_line(). + dest='hashes', + action='callback', + callback=_merge_hash, + type='string', + help="Verify that the package's archive matches this " + 'hash before installing. Example: --hash=sha256:abcdef...', +) # type: Any + + +require_hashes = partial( + Option, + '--require-hashes', + dest='require_hashes', + action='store_true', + default=False, + help='Require a hash to check each requirement against, for ' + 'repeatable installs. This option is implied when any package in a ' + 'requirements file has a --hash option.', +) # type: Any + + +########## +# groups # +########## + +general_group = { + 'name': 'General Options', + 'options': [ + help_, + isolated_mode, + require_virtualenv, + verbose, + version, + quiet, + log, + no_input, + proxy, + retries, + timeout, + skip_requirements_regex, + exists_action, + trusted_host, + cert, + client_cert, + cache_dir, + no_cache, + disable_pip_version_check, + no_color, + ] +} + +index_group = { + 'name': 'Package Index Options', + 'options': [ + index_url, + extra_index_url, + no_index, + find_links, + process_dependency_links, + ] +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py new file mode 100755 index 0000000..d44e6f1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py @@ -0,0 +1,79 @@ +""" +Package containing all pip commands +""" +from __future__ import absolute_import + +from pip._internal.commands.completion import CompletionCommand +from pip._internal.commands.configuration import ConfigurationCommand +from pip._internal.commands.download import DownloadCommand +from pip._internal.commands.freeze import FreezeCommand +from pip._internal.commands.hash import HashCommand +from pip._internal.commands.help import HelpCommand +from pip._internal.commands.list import ListCommand +from pip._internal.commands.check import CheckCommand +from pip._internal.commands.search import SearchCommand +from pip._internal.commands.show import ShowCommand +from pip._internal.commands.install import InstallCommand +from pip._internal.commands.uninstall import UninstallCommand +from pip._internal.commands.wheel import WheelCommand + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Type + from pip._internal.basecommand import Command + +commands_order = [ + InstallCommand, + DownloadCommand, + UninstallCommand, + FreezeCommand, + ListCommand, + ShowCommand, + CheckCommand, + ConfigurationCommand, + SearchCommand, + WheelCommand, + HashCommand, + CompletionCommand, + HelpCommand, +] # type: List[Type[Command]] + +commands_dict = {c.name: c for c in commands_order} + + +def get_summaries(ordered=True): + """Yields sorted (command name, command summary) tuples.""" + + if ordered: + cmditems = _sort_commands(commands_dict, commands_order) + else: + cmditems = commands_dict.items() + + for name, command_class in cmditems: + yield (name, command_class.summary) + + +def get_similar_commands(name): + """Command name auto-correct.""" + from difflib import get_close_matches + + name = name.lower() + + close_commands = get_close_matches(name, commands_dict.keys()) + + if close_commands: + return close_commands[0] + else: + return False + + +def _sort_commands(cmddict, order): + def keyfn(key): + try: + return order.index(key[1]) + except ValueError: + # unordered items should come last + return 0xff + + return sorted(cmddict.items(), key=keyfn) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py new file mode 100755 index 0000000..b1bf38a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py @@ -0,0 +1,42 @@ +import logging + +from pip._internal.basecommand import Command +from pip._internal.operations.check import ( + check_package_set, create_package_set_from_installed, +) +from pip._internal.utils.misc import get_installed_distributions + +logger = logging.getLogger(__name__) + + +class CheckCommand(Command): + """Verify installed packages have compatible dependencies.""" + name = 'check' + usage = """ + %prog [options]""" + summary = 'Verify installed packages have compatible dependencies.' + + def run(self, options, args): + package_set = create_package_set_from_installed() + missing, conflicting = check_package_set(package_set) + + for project_name in missing: + version = package_set[project_name].version + for dependency in missing[project_name]: + logger.info( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[0], + ) + + for project_name in conflicting: + version = package_set[project_name].version + for dep_name, dep_version, req in conflicting[project_name]: + logger.info( + "%s %s has requirement %s, but you have %s %s.", + project_name, version, req, dep_name, dep_version, + ) + + if missing or conflicting: + return 1 + else: + logger.info("No broken requirements found.") diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py new file mode 100755 index 0000000..8da1e83 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import + +import sys +import textwrap + +from pip._internal.basecommand import Command +from pip._internal.utils.misc import get_prog + +BASE_COMPLETION = """ +# pip %(shell)s completion start%(script)s# pip %(shell)s completion end +""" + +COMPLETION_SCRIPTS = { + 'bash': """ + _pip_completion() + { + COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 ) ) + } + complete -o default -F _pip_completion %(prog)s + """, + 'zsh': """ + function _pip_completion { + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] ) ) + } + compctl -K _pip_completion %(prog)s + """, + 'fish': """ + function __fish_complete_pip + set -lx COMP_WORDS (commandline -o) "" + set -lx COMP_CWORD ( \\ + math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ + ) + set -lx PIP_AUTO_COMPLETE 1 + string split \\ -- (eval $COMP_WORDS[1]) + end + complete -fa "(__fish_complete_pip)" -c %(prog)s + """, +} + + +class CompletionCommand(Command): + """A helper command to be used for command completion.""" + name = 'completion' + summary = 'A helper command used for command completion.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(CompletionCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '--bash', '-b', + action='store_const', + const='bash', + dest='shell', + help='Emit completion code for bash') + cmd_opts.add_option( + '--zsh', '-z', + action='store_const', + const='zsh', + dest='shell', + help='Emit completion code for zsh') + cmd_opts.add_option( + '--fish', '-f', + action='store_const', + const='fish', + dest='shell', + help='Emit completion code for fish') + + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ['--' + shell for shell in sorted(shells)] + if options.shell in shells: + script = textwrap.dedent( + COMPLETION_SCRIPTS.get(options.shell, '') % { + 'prog': get_prog(), + } + ) + print(BASE_COMPLETION % {'script': script, 'shell': options.shell}) + else: + sys.stderr.write( + 'ERROR: You must pass %s\n' % ' or '.join(shell_options) + ) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py new file mode 100755 index 0000000..e10d9a9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py @@ -0,0 +1,227 @@ +import logging +import os +import subprocess + +from pip._internal.basecommand import Command +from pip._internal.configuration import Configuration, kinds +from pip._internal.exceptions import PipError +from pip._internal.locations import venv_config_file +from pip._internal.status_codes import ERROR, SUCCESS +from pip._internal.utils.misc import get_prog + +logger = logging.getLogger(__name__) + + +class ConfigurationCommand(Command): + """Manage local and global configuration. + + Subcommands: + + list: List the active configuration (or from the file specified) + edit: Edit the configuration file in an editor + get: Get the value associated with name + set: Set the name=value + unset: Unset the value associated with name + + If none of --user, --global and --venv are passed, a virtual + environment configuration file is used if one is active and the file + exists. Otherwise, all modifications happen on the to the user file by + default. + """ + + name = 'config' + usage = """ + %prog [] list + %prog [] [--editor ] edit + + %prog [] get name + %prog [] set name value + %prog [] unset name + """ + + summary = "Manage local and global configuration." + + def __init__(self, *args, **kwargs): + super(ConfigurationCommand, self).__init__(*args, **kwargs) + + self.configuration = None + + self.cmd_opts.add_option( + '--editor', + dest='editor', + action='store', + default=None, + help=( + 'Editor to use to edit the file. Uses VISUAL or EDITOR ' + 'environment variables if not provided.' + ) + ) + + self.cmd_opts.add_option( + '--global', + dest='global_file', + action='store_true', + default=False, + help='Use the system-wide configuration file only' + ) + + self.cmd_opts.add_option( + '--user', + dest='user_file', + action='store_true', + default=False, + help='Use the user configuration file only' + ) + + self.cmd_opts.add_option( + '--venv', + dest='venv_file', + action='store_true', + default=False, + help='Use the virtualenv configuration file only' + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + handlers = { + "list": self.list_values, + "edit": self.open_in_editor, + "get": self.get_name, + "set": self.set_name_value, + "unset": self.unset_name + } + + # Determine action + if not args or args[0] not in handlers: + logger.error("Need an action ({}) to perform.".format( + ", ".join(sorted(handlers))) + ) + return ERROR + + action = args[0] + + # Determine which configuration files are to be loaded + # Depends on whether the command is modifying. + try: + load_only = self._determine_file( + options, need_value=(action in ["get", "set", "unset", "edit"]) + ) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + # Load a new configuration + self.configuration = Configuration( + isolated=options.isolated_mode, load_only=load_only + ) + self.configuration.load() + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _determine_file(self, options, need_value): + file_options = { + kinds.USER: options.user_file, + kinds.GLOBAL: options.global_file, + kinds.VENV: options.venv_file + } + + if sum(file_options.values()) == 0: + if not need_value: + return None + # Default to user, unless there's a virtualenv file. + elif os.path.exists(venv_config_file): + return kinds.VENV + else: + return kinds.USER + elif sum(file_options.values()) == 1: + # There's probably a better expression for this. + return [key for key in file_options if file_options[key]][0] + + raise PipError( + "Need exactly one file to operate upon " + "(--user, --venv, --global) to perform." + ) + + def list_values(self, options, args): + self._get_n_args(args, "list", n=0) + + for key, value in sorted(self.configuration.items()): + logger.info("%s=%r", key, value) + + def get_name(self, options, args): + key = self._get_n_args(args, "get [name]", n=1) + value = self.configuration.get_value(key) + + logger.info("%s", value) + + def set_name_value(self, options, args): + key, value = self._get_n_args(args, "set [name] [value]", n=2) + self.configuration.set_value(key, value) + + self._save_configuration() + + def unset_name(self, options, args): + key = self._get_n_args(args, "unset [name]", n=1) + self.configuration.unset_value(key) + + self._save_configuration() + + def open_in_editor(self, options, args): + editor = self._determine_editor(options) + + fname = self.configuration.get_file_to_edit() + if fname is None: + raise PipError("Could not determine appropriate file.") + + try: + subprocess.check_call([editor, fname]) + except subprocess.CalledProcessError as e: + raise PipError( + "Editor Subprocess exited with exit code {}" + .format(e.returncode) + ) + + def _get_n_args(self, args, example, n): + """Helper to make sure the command got the right number of arguments + """ + if len(args) != n: + msg = ( + 'Got unexpected number of arguments, expected {}. ' + '(example: "{} config {}")' + ).format(n, get_prog(), example) + raise PipError(msg) + + if n == 1: + return args[0] + else: + return args + + def _save_configuration(self): + # We successfully ran a modifying command. Need to save the + # configuration. + try: + self.configuration.save() + except Exception: + logger.error( + "Unable to save configuration. Please report this as a bug.", + exc_info=1 + ) + raise PipError("Internal Error.") + + def _determine_editor(self, options): + if options.editor is not None: + return options.editor + elif "VISUAL" in os.environ: + return os.environ["VISUAL"] + elif "EDITOR" in os.environ: + return os.environ["EDITOR"] + else: + raise PipError("Could not determine editor to use.") diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py new file mode 100755 index 0000000..916a470 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py @@ -0,0 +1,233 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.exceptions import CommandError +from pip._internal.index import FormatControl +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet +from pip._internal.resolve import Resolver +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, normalize_path +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +class DownloadCommand(RequirementCommand): + """ + Download packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports downloading from "requirements files", which provide + an easy way to specify a whole environment to be downloaded. + """ + name = 'download' + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] ... + %prog [options] ... + %prog [options] ...""" + + summary = 'Download packages.' + + def __init__(self, *args, **kw): + super(DownloadCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.global_options()) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.pre()) + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + + cmd_opts.add_option( + '-d', '--dest', '--destination-dir', '--destination-directory', + dest='download_dir', + metavar='dir', + default=os.curdir, + help=("Download packages into ."), + ) + + cmd_opts.add_option( + '--platform', + dest='platform', + metavar='platform', + default=None, + help=("Only download wheels compatible with . " + "Defaults to the platform of the running system."), + ) + + cmd_opts.add_option( + '--python-version', + dest='python_version', + metavar='python_version', + default=None, + help=("Only download wheels compatible with Python " + "interpreter version . If not specified, then the " + "current system interpreter minor version is used. A major " + "version (e.g. '2') can be specified to match all " + "minor revs of that major version. A minor version " + "(e.g. '34') can also be specified."), + ) + + cmd_opts.add_option( + '--implementation', + dest='implementation', + metavar='implementation', + default=None, + help=("Only download wheels compatible with Python " + "implementation , e.g. 'pp', 'jy', 'cp', " + " or 'ip'. If not specified, then the current " + "interpreter implementation is used. Use 'py' to force " + "implementation-agnostic wheels."), + ) + + cmd_opts.add_option( + '--abi', + dest='abi', + metavar='abi', + default=None, + help=("Only download wheels compatible with Python " + "abi , e.g. 'pypy_41'. If not specified, then the " + "current interpreter abi tag is used. Generally " + "you will need to specify --implementation, " + "--platform, and --python-version when using " + "this option."), + ) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + options.ignore_installed = True + # editable doesn't really make sense for `pip download`, but the bowels + # of the RequirementSet code require that property. + options.editables = [] + + if options.python_version: + python_versions = [options.python_version] + else: + python_versions = None + + dist_restriction_set = any([ + options.python_version, + options.platform, + options.abi, + options.implementation, + ]) + binary_only = FormatControl(set(), {':all:'}) + no_sdist_dependencies = ( + options.format_control != binary_only and + not options.ignore_dependencies + ) + if dist_restriction_set and no_sdist_dependencies: + raise CommandError( + "When restricting platform and interpreter constraints using " + "--python-version, --platform, --abi, or --implementation, " + "either --no-deps must be set, or --only-binary=:all: must be " + "set and --no-binary must not be set (or must be set to " + ":none:)." + ) + + options.src_dir = os.path.abspath(options.src_dir) + options.download_dir = normalize_path(options.download_dir) + + ensure_dir(options.download_dir) + + with self._build_session(options) as session: + finder = self._build_package_finder( + options=options, + session=session, + platform=options.platform, + python_versions=python_versions, + abi=options.abi, + implementation=options.implementation, + ) + build_delete = (not (options.no_clean or options.build_dir)) + if options.cache_dir and not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "by the current user and caching wheels has been " + "disabled. check the permissions and owner of that " + "directory. If executing pip with sudo, you may want " + "sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + with TempDirectory( + options.build_dir, delete=build_delete, kind="download" + ) as directory: + + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + self.populate_requirement_set( + requirement_set, + args, + options, + finder, + session, + self.name, + None + ) + + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=options.download_dir, + wheel_download_dir=None, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=None, + use_user_site=False, + upgrade_strategy="to-satisfy-only", + force_reinstall=False, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=False, + ignore_installed=True, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + downloaded = ' '.join([ + req.name for req in requirement_set.successfully_downloaded + ]) + if downloaded: + logger.info('Successfully downloaded %s', downloaded) + + # Clean up + if not options.no_clean: + requirement_set.cleanup_files() + + return requirement_set diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py new file mode 100755 index 0000000..ac562d7 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py @@ -0,0 +1,96 @@ +from __future__ import absolute_import + +import sys + +from pip._internal import index +from pip._internal.basecommand import Command +from pip._internal.cache import WheelCache +from pip._internal.compat import stdlib_pkgs +from pip._internal.operations.freeze import freeze + +DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} + + +class FreezeCommand(Command): + """ + Output installed packages in requirements format. + + packages are listed in a case-insensitive sorted order. + """ + name = 'freeze' + usage = """ + %prog [options]""" + summary = 'Output installed packages in requirements format.' + log_streams = ("ext://sys.stderr", "ext://sys.stderr") + + def __init__(self, *args, **kw): + super(FreezeCommand, self).__init__(*args, **kw) + + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help="Use the order in the given requirements file and its " + "comments when generating output. This option can be " + "used multiple times.") + self.cmd_opts.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL for finding packages, which will be added to the ' + 'output.') + self.cmd_opts.add_option( + '-l', '--local', + dest='local', + action='store_true', + default=False, + help='If in a virtualenv that has global access, do not output ' + 'globally-installed packages.') + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + self.cmd_opts.add_option( + '--all', + dest='freeze_all', + action='store_true', + help='Do not skip these packages in the output:' + ' %s' % ', '.join(DEV_PKGS)) + self.cmd_opts.add_option( + '--exclude-editable', + dest='exclude_editable', + action='store_true', + help='Exclude editable package from output.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + format_control = index.FormatControl(set(), set()) + wheel_cache = WheelCache(options.cache_dir, format_control) + skip = set(stdlib_pkgs) + if not options.freeze_all: + skip.update(DEV_PKGS) + + freeze_kwargs = dict( + requirement=options.requirements, + find_links=options.find_links, + local_only=options.local, + user_only=options.user, + skip_regex=options.skip_requirements_regex, + isolated=options.isolated_mode, + wheel_cache=wheel_cache, + skip=skip, + exclude_editable=options.exclude_editable, + ) + + try: + for line in freeze(**freeze_kwargs): + sys.stdout.write(line + '\n') + finally: + wheel_cache.cleanup() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py new file mode 100755 index 0000000..0ce1419 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py @@ -0,0 +1,57 @@ +from __future__ import absolute_import + +import hashlib +import logging +import sys + +from pip._internal.basecommand import Command +from pip._internal.status_codes import ERROR +from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES +from pip._internal.utils.misc import read_chunks + +logger = logging.getLogger(__name__) + + +class HashCommand(Command): + """ + Compute a hash of a local package archive. + + These can be used with --hash in a requirements file to do repeatable + installs. + + """ + name = 'hash' + usage = '%prog [options] ...' + summary = 'Compute hashes of package archives.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(HashCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-a', '--algorithm', + dest='algorithm', + choices=STRONG_HASHES, + action='store', + default=FAVORITE_HASH, + help='The hash algorithm to use: one of %s' % + ', '.join(STRONG_HASHES)) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + self.parser.print_usage(sys.stderr) + return ERROR + + algorithm = options.algorithm + for path in args: + logger.info('%s:\n--hash=%s:%s', + path, algorithm, _hash_of_file(path, algorithm)) + + +def _hash_of_file(path, algorithm): + """Return the hash digest of a file.""" + with open(path, 'rb') as archive: + hash = hashlib.new(algorithm) + for chunk in read_chunks(archive): + hash.update(chunk) + return hash.hexdigest() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py new file mode 100755 index 0000000..f4a0e40 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py @@ -0,0 +1,36 @@ +from __future__ import absolute_import + +from pip._internal.basecommand import SUCCESS, Command +from pip._internal.exceptions import CommandError + + +class HelpCommand(Command): + """Show help for commands""" + name = 'help' + usage = """ + %prog """ + summary = 'Show help for commands.' + ignore_require_venv = True + + def run(self, options, args): + from pip._internal.commands import commands_dict, get_similar_commands + + try: + # 'pip help' with no args is handled by pip.__init__.parseopt() + cmd_name = args[0] # the command we need help for + except IndexError: + return SUCCESS + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "%s"' % cmd_name] + if guess: + msg.append('maybe you meant "%s"' % guess) + + raise CommandError(' - '.join(msg)) + + command = commands_dict[cmd_name]() + command.parser.print_help() + + return SUCCESS diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py new file mode 100755 index 0000000..057a64e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py @@ -0,0 +1,502 @@ +from __future__ import absolute_import + +import errno +import logging +import operator +import os +import shutil +from optparse import SUPPRESS_HELP + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.cache import WheelCache +from pip._internal.exceptions import ( + CommandError, InstallationError, PreviousBuildDirError, +) +from pip._internal.locations import distutils_scheme, virtualenv_no_global +from pip._internal.operations.check import check_install_conflicts +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet, install_given_reqs +from pip._internal.resolve import Resolver +from pip._internal.status_codes import ERROR +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, get_installed_version +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import WheelBuilder + +try: + import wheel +except ImportError: + wheel = None + + +logger = logging.getLogger(__name__) + + +class InstallCommand(RequirementCommand): + """ + Install packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports installing from "requirements files", which provide + an easy way to specify a whole environment to be installed. + """ + name = 'install' + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + summary = 'Install packages.' + + def __init__(self, *args, **kw): + super(InstallCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.pre()) + + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option( + '-t', '--target', + dest='target_dir', + metavar='dir', + default=None, + help='Install packages into . ' + 'By default this will not replace existing files/folders in ' + '. Use --upgrade to replace existing packages in ' + 'with new versions.' + ) + cmd_opts.add_option( + '--user', + dest='use_user_site', + action='store_true', + help="Install to the Python user install directory for your " + "platform. Typically ~/.local/, or %APPDATA%\\Python on " + "Windows. (See the Python documentation for site.USER_BASE " + "for full details.)") + cmd_opts.add_option( + '--no-user', + dest='use_user_site', + action='store_false', + help=SUPPRESS_HELP) + cmd_opts.add_option( + '--root', + dest='root_path', + metavar='dir', + default=None, + help="Install everything relative to this alternate root " + "directory.") + cmd_opts.add_option( + '--prefix', + dest='prefix_path', + metavar='dir', + default=None, + help="Installation prefix where lib, bin and other top-level " + "folders are placed") + + cmd_opts.add_option(cmdoptions.build_dir()) + + cmd_opts.add_option(cmdoptions.src()) + + cmd_opts.add_option( + '-U', '--upgrade', + dest='upgrade', + action='store_true', + help='Upgrade all specified packages to the newest available ' + 'version. The handling of dependencies depends on the ' + 'upgrade-strategy used.' + ) + + cmd_opts.add_option( + '--upgrade-strategy', + dest='upgrade_strategy', + default='only-if-needed', + choices=['only-if-needed', 'eager'], + help='Determines how dependency upgrading should be handled ' + '[default: %default]. ' + '"eager" - dependencies are upgraded regardless of ' + 'whether the currently installed version satisfies the ' + 'requirements of the upgraded package(s). ' + '"only-if-needed" - are upgraded only when they do not ' + 'satisfy the requirements of the upgraded package(s).' + ) + + cmd_opts.add_option( + '--force-reinstall', + dest='force_reinstall', + action='store_true', + help='Reinstall all packages even if they are already ' + 'up-to-date.') + + cmd_opts.add_option( + '-I', '--ignore-installed', + dest='ignore_installed', + action='store_true', + help='Ignore the installed packages (reinstalling instead).') + + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + + cmd_opts.add_option(cmdoptions.install_options()) + cmd_opts.add_option(cmdoptions.global_options()) + + cmd_opts.add_option( + "--compile", + action="store_true", + dest="compile", + default=True, + help="Compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-compile", + action="store_false", + dest="compile", + help="Do not compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-warn-script-location", + action="store_false", + dest="warn_script_location", + default=True, + help="Do not warn when installing scripts outside PATH", + ) + cmd_opts.add_option( + "--no-warn-conflicts", + action="store_false", + dest="warn_about_conflicts", + default=True, + help="Do not warn about broken dependencies", + ) + + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + cmdoptions.check_install_build_global(options) + + upgrade_strategy = "to-satisfy-only" + if options.upgrade: + upgrade_strategy = options.upgrade_strategy + + if options.build_dir: + options.build_dir = os.path.abspath(options.build_dir) + + options.src_dir = os.path.abspath(options.src_dir) + install_options = options.install_options or [] + if options.use_user_site: + if options.prefix_path: + raise CommandError( + "Can not combine '--user' and '--prefix' as they imply " + "different installation locations" + ) + if virtualenv_no_global(): + raise InstallationError( + "Can not perform a '--user' install. User site-packages " + "are not visible in this virtualenv." + ) + install_options.append('--user') + install_options.append('--prefix=') + + target_temp_dir = TempDirectory(kind="target") + if options.target_dir: + options.ignore_installed = True + options.target_dir = os.path.abspath(options.target_dir) + if (os.path.exists(options.target_dir) and not + os.path.isdir(options.target_dir)): + raise CommandError( + "Target path exists but is not a directory, will not " + "continue." + ) + + # Create a target directory for using with the target option + target_temp_dir.create() + install_options.append('--home=' + target_temp_dir.path) + + global_options = options.global_options or [] + + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + if options.cache_dir and not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "by the current user and caching wheels has been " + "disabled. check the permissions and owner of that " + "directory. If executing pip with sudo, you may want " + "sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + with TempDirectory( + options.build_dir, delete=build_delete, kind="install" + ) as directory: + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + + try: + self.populate_requirement_set( + requirement_set, args, options, finder, session, + self.name, wheel_cache + ) + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=None, + wheel_download_dir=None, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=wheel_cache, + use_user_site=options.use_user_site, + upgrade_strategy=upgrade_strategy, + force_reinstall=options.force_reinstall, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=options.ignore_requires_python, + ignore_installed=options.ignore_installed, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + # If caching is disabled or wheel is not installed don't + # try to build wheels. + if wheel and options.cache_dir: + # build wheels before install. + wb = WheelBuilder( + finder, preparer, wheel_cache, + build_options=[], global_options=[], + ) + # Ignore the result: a failed wheel will be + # installed from the sdist/vcs whatever. + wb.build( + requirement_set.requirements.values(), + session=session, autobuilding=True + ) + + to_install = resolver.get_installation_order( + requirement_set + ) + + # Consistency Checking of the package set we're installing. + should_warn_about_conflicts = ( + not options.ignore_dependencies and + options.warn_about_conflicts + ) + if should_warn_about_conflicts: + self._warn_about_conflicts(to_install) + + # Don't warn about script install locations if + # --target has been specified + warn_script_location = options.warn_script_location + if options.target_dir: + warn_script_location = False + + installed = install_given_reqs( + to_install, + install_options, + global_options, + root=options.root_path, + home=target_temp_dir.path, + prefix=options.prefix_path, + pycompile=options.compile, + warn_script_location=warn_script_location, + use_user_site=options.use_user_site, + ) + + possible_lib_locations = get_lib_location_guesses( + user=options.use_user_site, + home=target_temp_dir.path, + root=options.root_path, + prefix=options.prefix_path, + isolated=options.isolated_mode, + ) + reqs = sorted(installed, key=operator.attrgetter('name')) + items = [] + for req in reqs: + item = req.name + try: + installed_version = get_installed_version( + req.name, possible_lib_locations + ) + if installed_version: + item += '-' + installed_version + except Exception: + pass + items.append(item) + installed = ' '.join(items) + if installed: + logger.info('Successfully installed %s', installed) + except EnvironmentError as error: + show_traceback = (self.verbosity >= 1) + + message = create_env_error_message( + error, show_traceback, options.use_user_site, + ) + logger.error(message, exc_info=show_traceback) + + return ERROR + except PreviousBuildDirError: + options.no_clean = True + raise + finally: + # Clean up + if not options.no_clean: + requirement_set.cleanup_files() + wheel_cache.cleanup() + + if options.target_dir: + self._handle_target_dir( + options.target_dir, target_temp_dir, options.upgrade + ) + return requirement_set + + def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): + ensure_dir(target_dir) + + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + lib_dir_list = [] + + with target_temp_dir: + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + scheme = distutils_scheme('', home=target_temp_dir.path) + purelib_dir = scheme['purelib'] + platlib_dir = scheme['platlib'] + data_dir = scheme['data'] + + if os.path.exists(purelib_dir): + lib_dir_list.append(purelib_dir) + if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: + lib_dir_list.append(platlib_dir) + if os.path.exists(data_dir): + lib_dir_list.append(data_dir) + + for lib_dir in lib_dir_list: + for item in os.listdir(lib_dir): + if lib_dir == data_dir: + ddir = os.path.join(data_dir, item) + if any(s.startswith(ddir) for s in lib_dir_list[:-1]): + continue + target_item_dir = os.path.join(target_dir, item) + if os.path.exists(target_item_dir): + if not upgrade: + logger.warning( + 'Target directory %s already exists. Specify ' + '--upgrade to force replacement.', + target_item_dir + ) + continue + if os.path.islink(target_item_dir): + logger.warning( + 'Target directory %s already exists and is ' + 'a link. Pip will not automatically replace ' + 'links, please remove if replacement is ' + 'desired.', + target_item_dir + ) + continue + if os.path.isdir(target_item_dir): + shutil.rmtree(target_item_dir) + else: + os.remove(target_item_dir) + + shutil.move( + os.path.join(lib_dir, item), + target_item_dir + ) + + def _warn_about_conflicts(self, to_install): + package_set, _dep_info = check_install_conflicts(to_install) + missing, conflicting = _dep_info + + # NOTE: There is some duplication here from pip check + for project_name in missing: + version = package_set[project_name][0] + for dependency in missing[project_name]: + logger.critical( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[1], + ) + + for project_name in conflicting: + version = package_set[project_name][0] + for dep_name, dep_version, req in conflicting[project_name]: + logger.critical( + "%s %s has requirement %s, but you'll have %s %s which is " + "incompatible.", + project_name, version, req, dep_name, dep_version, + ) + + +def get_lib_location_guesses(*args, **kwargs): + scheme = distutils_scheme('', *args, **kwargs) + return [scheme['purelib'], scheme['platlib']] + + +def create_env_error_message(error, show_traceback, using_user_site): + """Format an error message for an EnvironmentError + + It may occur anytime during the execution of the install command. + """ + parts = [] + + # Mention the error if we are not going to show a traceback + parts.append("Could not install packages due to an EnvironmentError") + if not show_traceback: + parts.append(": ") + parts.append(str(error)) + else: + parts.append(".") + + # Spilt the error indication from a helper message (if any) + parts[-1] += "\n" + + # Suggest useful actions to the user: + # (1) using user site-packages or (2) verifying the permissions + if error.errno == errno.EACCES: + user_option_part = "Consider using the `--user` option" + permissions_part = "Check the permissions" + + if not using_user_site: + parts.extend([ + user_option_part, " or ", + permissions_part.lower(), + ]) + else: + parts.append(permissions_part) + parts.append(".\n") + + return "".join(parts).strip() + "\n" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py new file mode 100755 index 0000000..1b46c6f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py @@ -0,0 +1,343 @@ +from __future__ import absolute_import + +import json +import logging +import warnings + +from pip._vendor import six +from pip._vendor.six.moves import zip_longest + +from pip._internal.basecommand import Command +from pip._internal.cmdoptions import index_group, make_option_group +from pip._internal.exceptions import CommandError +from pip._internal.index import PackageFinder +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.misc import ( + dist_is_editable, get_installed_distributions, +) +from pip._internal.utils.packaging import get_installer + +logger = logging.getLogger(__name__) + + +class ListCommand(Command): + """ + List installed packages, including editables. + + Packages are listed in a case-insensitive sorted order. + """ + name = 'list' + usage = """ + %prog [options]""" + summary = 'List installed packages.' + + def __init__(self, *args, **kw): + super(ListCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-o', '--outdated', + action='store_true', + default=False, + help='List outdated packages') + cmd_opts.add_option( + '-u', '--uptodate', + action='store_true', + default=False, + help='List uptodate packages') + cmd_opts.add_option( + '-e', '--editable', + action='store_true', + default=False, + help='List editable projects.') + cmd_opts.add_option( + '-l', '--local', + action='store_true', + default=False, + help=('If in a virtualenv that has global access, do not list ' + 'globally-installed packages.'), + ) + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option( + '--format', + action='store', + dest='list_format', + default="columns", + choices=('legacy', 'columns', 'freeze', 'json'), + help="Select the output format among: columns (default), freeze, " + "json, or legacy.", + ) + + cmd_opts.add_option( + '--not-required', + action='store_true', + dest='not_required', + help="List packages that are not dependencies of " + "installed packages.", + ) + + cmd_opts.add_option( + '--exclude-editable', + action='store_false', + dest='include_editable', + help='Exclude editable package from output.', + ) + cmd_opts.add_option( + '--include-editable', + action='store_true', + dest='include_editable', + help='Include editable package from output.', + default=True, + ) + index_opts = make_option_group(index_group, self.parser) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def _build_package_finder(self, options, index_urls, session): + """ + Create a package finder appropriate to this list command. + """ + return PackageFinder( + find_links=options.find_links, + index_urls=index_urls, + allow_all_prereleases=options.pre, + trusted_hosts=options.trusted_hosts, + process_dependency_links=options.process_dependency_links, + session=session, + ) + + def run(self, options, args): + if options.list_format == "legacy": + warnings.warn( + "The legacy format has been deprecated and will be removed " + "in the future.", + RemovedInPip11Warning, + ) + + if options.outdated and options.uptodate: + raise CommandError( + "Options --outdated and --uptodate cannot be combined.") + + packages = get_installed_distributions( + local_only=options.local, + user_only=options.user, + editables_only=options.editable, + include_editables=options.include_editable, + ) + + if options.outdated: + packages = self.get_outdated(packages, options) + elif options.uptodate: + packages = self.get_uptodate(packages, options) + + if options.not_required: + packages = self.get_not_required(packages, options) + + self.output_package_listing(packages, options) + + def get_outdated(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version > dist.parsed_version + ] + + def get_uptodate(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version == dist.parsed_version + ] + + def get_not_required(self, packages, options): + dep_keys = set() + for dist in packages: + dep_keys.update(requirement.key for requirement in dist.requires()) + return {pkg for pkg in packages if pkg.key not in dep_keys} + + def iter_packages_latest_infos(self, packages, options): + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + dependency_links = [] + for dist in packages: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend( + dist.get_metadata_lines('dependency_links.txt'), + ) + + with self._build_session(options) as session: + finder = self._build_package_finder(options, index_urls, session) + finder.add_dependency_links(dependency_links) + + for dist in packages: + typ = 'unknown' + all_candidates = finder.find_all_candidates(dist.key) + if not options.pre: + # Remove prereleases + all_candidates = [candidate for candidate in all_candidates + if not candidate.version.is_prerelease] + + if not all_candidates: + continue + best_candidate = max(all_candidates, + key=finder._candidate_sort_key) + remote_version = best_candidate.version + if best_candidate.location.is_wheel: + typ = 'wheel' + else: + typ = 'sdist' + # This is dirty but makes the rest of the code much cleaner + dist.latest_version = remote_version + dist.latest_filetype = typ + yield dist + + def output_legacy(self, dist, options): + if options.verbose >= 1: + return '%s (%s, %s, %s)' % ( + dist.project_name, + dist.version, + dist.location, + get_installer(dist), + ) + elif dist_is_editable(dist): + return '%s (%s, %s)' % ( + dist.project_name, + dist.version, + dist.location, + ) + else: + return '%s (%s)' % (dist.project_name, dist.version) + + def output_legacy_latest(self, dist, options): + return '%s - Latest: %s [%s]' % ( + self.output_legacy(dist, options), + dist.latest_version, + dist.latest_filetype, + ) + + def output_package_listing(self, packages, options): + packages = sorted( + packages, + key=lambda dist: dist.project_name.lower(), + ) + if options.list_format == 'columns' and packages: + data, header = format_for_columns(packages, options) + self.output_package_listing_columns(data, header) + elif options.list_format == 'freeze': + for dist in packages: + if options.verbose >= 1: + logger.info("%s==%s (%s)", dist.project_name, + dist.version, dist.location) + else: + logger.info("%s==%s", dist.project_name, dist.version) + elif options.list_format == 'json': + logger.info(format_for_json(packages, options)) + elif options.list_format == "legacy": + for dist in packages: + if options.outdated: + logger.info(self.output_legacy_latest(dist, options)) + else: + logger.info(self.output_legacy(dist, options)) + + def output_package_listing_columns(self, data, header): + # insert the header first: we need to know the size of column names + if len(data) > 0: + data.insert(0, header) + + pkg_strings, sizes = tabulate(data) + + # Create and add a separator. + if len(data) > 0: + pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) + + for val in pkg_strings: + logger.info(val) + + +def tabulate(vals): + # From pfmoore on GitHub: + # https://github.com/pypa/pip/issues/3651#issuecomment-216932564 + assert len(vals) > 0 + + sizes = [0] * max(len(x) for x in vals) + for row in vals: + sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)] + + result = [] + for row in vals: + display = " ".join([str(c).ljust(s) if c is not None else '' + for s, c in zip_longest(sizes, row)]) + result.append(display) + + return result, sizes + + +def format_for_columns(pkgs, options): + """ + Convert the package data into something usable + by output_package_listing_columns. + """ + running_outdated = options.outdated + # Adjust the header for the `pip list --outdated` case. + if running_outdated: + header = ["Package", "Version", "Latest", "Type"] + else: + header = ["Package", "Version"] + + data = [] + if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): + header.append("Location") + if options.verbose >= 1: + header.append("Installer") + + for proj in pkgs: + # if we're working on the 'outdated' list, separate out the + # latest_version and type + row = [proj.project_name, proj.version] + + if running_outdated: + row.append(proj.latest_version) + row.append(proj.latest_filetype) + + if options.verbose >= 1 or dist_is_editable(proj): + row.append(proj.location) + if options.verbose >= 1: + row.append(get_installer(proj)) + + data.append(row) + + return data, header + + +def format_for_json(packages, options): + data = [] + for dist in packages: + info = { + 'name': dist.project_name, + 'version': six.text_type(dist.version), + } + if options.verbose >= 1: + info['location'] = dist.location + info['installer'] = get_installer(dist) + if options.outdated: + info['latest_version'] = six.text_type(dist.latest_version) + info['latest_filetype'] = dist.latest_filetype + data.append(info) + return json.dumps(data) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py new file mode 100755 index 0000000..83895ce --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py @@ -0,0 +1,135 @@ +from __future__ import absolute_import + +import logging +import sys +import textwrap +from collections import OrderedDict + +from pip._vendor import pkg_resources +from pip._vendor.packaging.version import parse as parse_version +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore + +from pip._internal.basecommand import SUCCESS, Command +from pip._internal.compat import get_terminal_size +from pip._internal.download import PipXmlrpcTransport +from pip._internal.exceptions import CommandError +from pip._internal.models import PyPI +from pip._internal.status_codes import NO_MATCHES_FOUND +from pip._internal.utils.logging import indent_log + +logger = logging.getLogger(__name__) + + +class SearchCommand(Command): + """Search for PyPI packages whose name or summary contains .""" + name = 'search' + usage = """ + %prog [options] """ + summary = 'Search PyPI for packages.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(SearchCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-i', '--index', + dest='index', + metavar='URL', + default=PyPI.pypi_url, + help='Base URL of Python Package Index (default %default)') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + raise CommandError('Missing required argument (search query).') + query = args + pypi_hits = self.search(query, options) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + if pypi_hits: + return SUCCESS + return NO_MATCHES_FOUND + + def search(self, query, options): + index_url = options.index + with self._build_session(options) as session: + transport = PipXmlrpcTransport(index_url, session) + pypi = xmlrpc_client.ServerProxy(index_url, transport) + hits = pypi.search({'name': query, 'summary': query}, 'or') + return hits + + +def transform_hits(hits): + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages = OrderedDict() + for hit in hits: + name = hit['name'] + summary = hit['summary'] + version = hit['version'] + + if name not in packages.keys(): + packages[name] = { + 'name': name, + 'summary': summary, + 'versions': [version], + } + else: + packages[name]['versions'].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]['versions']): + packages[name]['summary'] = summary + + return list(packages.values()) + + +def print_results(hits, name_column_width=None, terminal_width=None): + if not hits: + return + if name_column_width is None: + name_column_width = max([ + len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) + for hit in hits + ]) + 4 + + installed_packages = [p.project_name for p in pkg_resources.working_set] + for hit in hits: + name = hit['name'] + summary = hit['summary'] or '' + latest = highest_version(hit.get('versions', ['-'])) + if terminal_width is not None: + target_width = terminal_width - name_column_width - 5 + if target_width > 10: + # wrap and indent summary to fit terminal + summary = textwrap.wrap(summary, target_width) + summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + + line = '%-*s - %s' % (name_column_width, + '%s (%s)' % (name, latest), summary) + try: + logger.info(line) + if name in installed_packages: + dist = pkg_resources.get_distribution(name) + with indent_log(): + if dist.version == latest: + logger.info('INSTALLED: %s (latest)', dist.version) + else: + logger.info('INSTALLED: %s', dist.version) + logger.info('LATEST: %s', latest) + except UnicodeEncodeError: + pass + + +def highest_version(versions): + return max(versions, key=parse_version) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py new file mode 100755 index 0000000..bad9628 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py @@ -0,0 +1,164 @@ +from __future__ import absolute_import + +import logging +import os +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.basecommand import Command +from pip._internal.status_codes import ERROR, SUCCESS + +logger = logging.getLogger(__name__) + + +class ShowCommand(Command): + """Show information about one or more installed packages.""" + name = 'show' + usage = """ + %prog [options] ...""" + summary = 'Show information about installed packages.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(ShowCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-f', '--files', + dest='files', + action='store_true', + default=False, + help='Show the full list of installed files for each package.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + logger.warning('ERROR: Please provide a package name or names.') + return ERROR + query = args + + results = search_packages_info(query) + if not print_results( + results, list_files=options.files, verbose=options.verbose): + return ERROR + return SUCCESS + + +def search_packages_info(query): + """ + Gather details from installed distributions. Print distribution name, + version, location, and installed files. Installed files requires a + pip generated 'installed-files.txt' in the distributions '.egg-info' + directory. + """ + installed = {} + for p in pkg_resources.working_set: + installed[canonicalize_name(p.project_name)] = p + + query_names = [canonicalize_name(name) for name in query] + + for dist in [installed[pkg] for pkg in query_names if pkg in installed]: + package = { + 'name': dist.project_name, + 'version': dist.version, + 'location': dist.location, + 'requires': [dep.project_name for dep in dist.requires()], + } + file_list = None + metadata = None + if isinstance(dist, pkg_resources.DistInfoDistribution): + # RECORDs should be part of .dist-info metadatas + if dist.has_metadata('RECORD'): + lines = dist.get_metadata_lines('RECORD') + paths = [l.split(',')[0] for l in lines] + paths = [os.path.join(dist.location, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('METADATA'): + metadata = dist.get_metadata('METADATA') + else: + # Otherwise use pip's log for .egg-info's + if dist.has_metadata('installed-files.txt'): + paths = dist.get_metadata_lines('installed-files.txt') + paths = [os.path.join(dist.egg_info, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('PKG-INFO'): + metadata = dist.get_metadata('PKG-INFO') + + if dist.has_metadata('entry_points.txt'): + entry_points = dist.get_metadata_lines('entry_points.txt') + package['entry_points'] = entry_points + + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + package['installer'] = line.strip() + break + + # @todo: Should pkg_resources.Distribution have a + # `get_pkg_info` method? + feed_parser = FeedParser() + feed_parser.feed(metadata) + pkg_info_dict = feed_parser.close() + for key in ('metadata-version', 'summary', + 'home-page', 'author', 'author-email', 'license'): + package[key] = pkg_info_dict.get(key) + + # It looks like FeedParser cannot deal with repeated headers + classifiers = [] + for line in metadata.splitlines(): + if line.startswith('Classifier: '): + classifiers.append(line[len('Classifier: '):]) + package['classifiers'] = classifiers + + if file_list: + package['files'] = sorted(file_list) + yield package + + +def print_results(distributions, list_files=False, verbose=False): + """ + Print the informations from installed distributions found. + """ + results_printed = False + for i, dist in enumerate(distributions): + results_printed = True + if i > 0: + logger.info("---") + + name = dist.get('name', '') + required_by = [ + pkg.project_name for pkg in pkg_resources.working_set + if name in [required.name for required in pkg.requires()] + ] + + logger.info("Name: %s", name) + logger.info("Version: %s", dist.get('version', '')) + logger.info("Summary: %s", dist.get('summary', '')) + logger.info("Home-page: %s", dist.get('home-page', '')) + logger.info("Author: %s", dist.get('author', '')) + logger.info("Author-email: %s", dist.get('author-email', '')) + logger.info("License: %s", dist.get('license', '')) + logger.info("Location: %s", dist.get('location', '')) + logger.info("Requires: %s", ', '.join(dist.get('requires', []))) + logger.info("Required-by: %s", ', '.join(required_by)) + + if verbose: + logger.info("Metadata-Version: %s", + dist.get('metadata-version', '')) + logger.info("Installer: %s", dist.get('installer', '')) + logger.info("Classifiers:") + for classifier in dist.get('classifiers', []): + logger.info(" %s", classifier) + logger.info("Entry-points:") + for entry in dist.get('entry_points', []): + logger.info(" %s", entry.strip()) + if list_files: + logger.info("Files:") + for line in dist.get('files', []): + logger.info(" %s", line.strip()) + if "files" not in dist: + logger.info("Cannot locate installed-files.txt") + return results_printed diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py new file mode 100755 index 0000000..3bfa07f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py @@ -0,0 +1,71 @@ +from __future__ import absolute_import + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.basecommand import Command +from pip._internal.exceptions import InstallationError +from pip._internal.req import InstallRequirement, parse_requirements + + +class UninstallCommand(Command): + """ + Uninstall packages. + + pip is able to uninstall most installed packages. Known exceptions are: + + - Pure distutils packages installed with ``python setup.py install``, which + leave behind no metadata to determine what files were installed. + - Script wrappers installed by ``python setup.py develop``. + """ + name = 'uninstall' + usage = """ + %prog [options] ... + %prog [options] -r ...""" + summary = 'Uninstall packages.' + + def __init__(self, *args, **kw): + super(UninstallCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Uninstall all the packages listed in the given requirements ' + 'file. This option can be used multiple times.', + ) + self.cmd_opts.add_option( + '-y', '--yes', + dest='yes', + action='store_true', + help="Don't ask for confirmation of uninstall deletions.") + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + with self._build_session(options) as session: + reqs_to_uninstall = {} + for name in args: + req = InstallRequirement.from_line( + name, isolated=options.isolated_mode, + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + for filename in options.requirements: + for req in parse_requirements( + filename, + options=options, + session=session): + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + if not reqs_to_uninstall: + raise InstallationError( + 'You must give at least one requirement to %(name)s (see ' + '"pip help %(name)s")' % dict(name=self.name) + ) + for req in reqs_to_uninstall.values(): + uninstall_pathset = req.uninstall( + auto_confirm=options.yes, verbose=self.verbosity > 0, + ) + if uninstall_pathset: + uninstall_pathset.commit() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py new file mode 100755 index 0000000..ed8cdfc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import logging +import os + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.cache import WheelCache +from pip._internal.exceptions import CommandError, PreviousBuildDirError +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet +from pip._internal.resolve import Resolver +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import WheelBuilder + +logger = logging.getLogger(__name__) + + +class WheelCommand(RequirementCommand): + """ + Build Wheel archives for your requirements and dependencies. + + Wheel is a built-package format, and offers the advantage of not + recompiling your software during every install. For more details, see the + wheel docs: https://wheel.readthedocs.io/en/latest/ + + Requirements: setuptools>=0.8, and wheel. + + 'pip wheel' uses the bdist_wheel setuptools extension from the wheel + package to build individual wheels. + + """ + + name = 'wheel' + usage = """ + %prog [options] ... + %prog [options] -r ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + summary = 'Build wheels from your requirements.' + + def __init__(self, *args, **kw): + super(WheelCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-w', '--wheel-dir', + dest='wheel_dir', + metavar='dir', + default=os.curdir, + help=("Build wheels into , where the default is the " + "current working directory."), + ) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option( + '--build-option', + dest='build_options', + metavar='options', + action='append', + help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", + ) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + cmd_opts.add_option( + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the 'bdist_wheel' command.") + + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + cmdoptions.check_install_build_global(options) + + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + if options.build_dir: + options.build_dir = os.path.abspath(options.build_dir) + + options.src_dir = os.path.abspath(options.src_dir) + + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + with TempDirectory( + options.build_dir, delete=build_delete, kind="wheel" + ) as directory: + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + + try: + self.populate_requirement_set( + requirement_set, args, options, finder, session, + self.name, wheel_cache + ) + + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=None, + wheel_download_dir=options.wheel_dir, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=wheel_cache, + use_user_site=False, + upgrade_strategy="to-satisfy-only", + force_reinstall=False, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=options.ignore_requires_python, + ignore_installed=True, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + # build wheels + wb = WheelBuilder( + finder, preparer, wheel_cache, + build_options=options.build_options or [], + global_options=options.global_options or [], + no_clean=options.no_clean, + ) + wheels_built_successfully = wb.build( + requirement_set.requirements.values(), session=session, + ) + if not wheels_built_successfully: + raise CommandError( + "Failed to build one or more wheels" + ) + except PreviousBuildDirError: + options.no_clean = True + raise + finally: + if not options.no_clean: + requirement_set.cleanup_files() + wheel_cache.cleanup() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py new file mode 100755 index 0000000..064717d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py @@ -0,0 +1,235 @@ +"""Stuff that differs in different Python versions and platform +distributions.""" +from __future__ import absolute_import, division + +import codecs +import locale +import logging +import os +import shutil +import sys + +from pip._vendor.six import text_type + +try: + import ipaddress +except ImportError: + try: + from pip._vendor import ipaddress # type: ignore + except ImportError: + import ipaddr as ipaddress # type: ignore + ipaddress.ip_address = ipaddress.IPAddress + ipaddress.ip_network = ipaddress.IPNetwork + + +__all__ = [ + "ipaddress", "uses_pycache", "console_to_str", "native_str", + "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", +] + + +logger = logging.getLogger(__name__) + +if sys.version_info >= (3, 4): + uses_pycache = True + from importlib.util import cache_from_source +else: + import imp + + try: + cache_from_source = imp.cache_from_source # type: ignore + except AttributeError: + # does not use __pycache__ + cache_from_source = None + + uses_pycache = cache_from_source is not None + + +if sys.version_info >= (3, 5): + backslashreplace_decode = "backslashreplace" +else: + # In version 3.4 and older, backslashreplace exists + # but does not support use for decoding. + # We implement our own replace handler for this + # situation, so that we can consistently use + # backslash replacement for all versions. + def backslashreplace_decode_fn(err): + raw_bytes = (err.object[i] for i in range(err.start, err.end)) + if sys.version_info[0] == 2: + # Python 2 gave us characters - convert to numeric bytes + raw_bytes = (ord(b) for b in raw_bytes) + return u"".join(u"\\x%x" % c for c in raw_bytes), err.end + codecs.register_error( + "backslashreplace_decode", + backslashreplace_decode_fn, + ) + backslashreplace_decode = "backslashreplace_decode" + + +def console_to_str(data): + """Return a string, safe for output, of subprocess output. + + We assume the data is in the locale preferred encoding. + If it won't decode properly, we warn the user but decode as + best we can. + + We also ensure that the output can be safely written to + standard output without encoding errors. + """ + + # First, get the encoding we assume. This is the preferred + # encoding for the locale, unless that is not found, or + # it is ASCII, in which case assume UTF-8 + encoding = locale.getpreferredencoding() + if (not encoding) or codecs.lookup(encoding).name == "ascii": + encoding = "utf-8" + + # Now try to decode the data - if we fail, warn the user and + # decode with replacement. + try: + s = data.decode(encoding) + except UnicodeDecodeError: + logger.warning( + "Subprocess output does not appear to be encoded as %s", + encoding, + ) + s = data.decode(encoding, errors=backslashreplace_decode) + + # Make sure we can print the output, by encoding it to the output + # encoding with replacement of unencodable characters, and then + # decoding again. + # We use stderr's encoding because it's less likely to be + # redirected and if we don't find an encoding we skip this + # step (on the assumption that output is wrapped by something + # that won't fail). + # The double getattr is to deal with the possibility that we're + # being called in a situation where sys.__stderr__ doesn't exist, + # or doesn't have an encoding attribute. Neither of these cases + # should occur in normal pip use, but there's no harm in checking + # in case people use pip in (unsupported) unusual situations. + output_encoding = getattr(getattr(sys, "__stderr__", None), + "encoding", None) + + if output_encoding: + s = s.encode(output_encoding, errors="backslashreplace") + s = s.decode(output_encoding) + + return s + + +if sys.version_info >= (3,): + def native_str(s, replace=False): + if isinstance(s, bytes): + return s.decode('utf-8', 'replace' if replace else 'strict') + return s + +else: + def native_str(s, replace=False): + # Replace is ignored -- unicode to UTF-8 can't fail + if isinstance(s, text_type): + return s.encode('utf-8') + return s + + +def get_path_uid(path): + """ + Return path's uid. + + Does not follow symlinks: + https://github.com/pypa/pip/pull/935#discussion_r5307003 + + Placed this function in compat due to differences on AIX and + Jython, that should eventually go away. + + :raises OSError: When path is a symlink or can't be read. + """ + if hasattr(os, 'O_NOFOLLOW'): + fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) + file_uid = os.fstat(fd).st_uid + os.close(fd) + else: # AIX and Jython + # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW + if not os.path.islink(path): + # older versions of Jython don't have `os.fstat` + file_uid = os.stat(path).st_uid + else: + # raise OSError for parity with os.O_NOFOLLOW above + raise OSError( + "%s is a symlink; Will not return uid for symlinks" % path + ) + return file_uid + + +def expanduser(path): + """ + Expand ~ and ~user constructions. + + Includes a workaround for http://bugs.python.org/issue14768 + """ + expanded = os.path.expanduser(path) + if path.startswith('~/') and expanded.startswith('//'): + expanded = expanded[1:] + return expanded + + +# packages in the stdlib that may have installation metadata, but should not be +# considered 'installed'. this theoretically could be determined based on +# dist.location (py27:`sysconfig.get_paths()['stdlib']`, +# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may +# make this ineffective, so hard-coding +stdlib_pkgs = {"python", "wsgiref", "argparse"} + + +# windows detection, covers cpython and ironpython +WINDOWS = (sys.platform.startswith("win") or + (sys.platform == 'cli' and os.name == 'nt')) + + +def samefile(file1, file2): + """Provide an alternative for os.path.samefile on Windows/Python2""" + if hasattr(os.path, 'samefile'): + return os.path.samefile(file1, file2) + else: + path1 = os.path.normcase(os.path.abspath(file1)) + path2 = os.path.normcase(os.path.abspath(file2)) + return path1 == path2 + + +if hasattr(shutil, 'get_terminal_size'): + def get_terminal_size(): + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + return tuple(shutil.get_terminal_size()) +else: + def get_terminal_size(): + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + def ioctl_GWINSZ(fd): + try: + import fcntl + import termios + import struct + cr = struct.unpack_from( + 'hh', + fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') + ) + except: + return None + if cr == (0, 0): + return None + return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + cr = ioctl_GWINSZ(fd) + os.close(fd) + except: + pass + if not cr: + cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) + return int(cr[1]), int(cr[0]) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py new file mode 100755 index 0000000..07af373 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py @@ -0,0 +1,378 @@ +"""Configuration management setup + +Some terminology: +- name + As written in config files. +- value + Value associated with a name +- key + Name combined with it's section (section.name) +- variant + A single word describing where the configuration key-value pair came from +""" + +import locale +import logging +import os + +from pip._vendor import six +from pip._vendor.six.moves import configparser + +from pip._internal.exceptions import ConfigurationError +from pip._internal.locations import ( + legacy_config_file, new_config_file, running_under_virtualenv, + site_config_files, venv_config_file, +) +from pip._internal.utils.misc import ensure_dir, enum +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple + + RawConfigParser = configparser.RawConfigParser # Shorthand + Kind = NewType("Kind", str) + +logger = logging.getLogger(__name__) + + +# NOTE: Maybe use the optionx attribute to normalize keynames. +def _normalize_name(name): + # type: (str) -> str + """Make a name consistent regardless of source (environment or file) + """ + name = name.lower().replace('_', '-') + if name.startswith('--'): + name = name[2:] # only prefer long opts + return name + + +def _disassemble_key(name): + # type: (str) -> List[str] + return name.split(".", 1) + + +# The kinds of configurations there are. +kinds = enum( + USER="user", # User Specific + GLOBAL="global", # System Wide + VENV="venv", # Virtual Environment Specific + ENV="env", # from PIP_CONFIG_FILE + ENV_VAR="env-var", # from Environment Variables +) + + +class Configuration(object): + """Handles management of configuration. + + Provides an interface to accessing and managing configuration files. + + This class converts provides an API that takes "section.key-name" style + keys and stores the value associated with it as "key-name" under the + section "section". + + This allows for a clean interface wherein the both the section and the + key-name are preserved in an easy to manage form in the configuration files + and the data stored is also nice. + """ + + def __init__(self, isolated, load_only=None): + # type: (bool, Kind) -> None + super(Configuration, self).__init__() + + _valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.VENV, None] + if load_only not in _valid_load_only: + raise ConfigurationError( + "Got invalid value for load_only - should be one of {}".format( + ", ".join(map(repr, _valid_load_only[:-1])) + ) + ) + self.isolated = isolated # type: bool + self.load_only = load_only # type: Optional[Kind] + + # The order here determines the override order. + self._override_order = [ + kinds.GLOBAL, kinds.USER, kinds.VENV, kinds.ENV, kinds.ENV_VAR + ] + + self._ignore_env_names = ["version", "help"] + + # Because we keep track of where we got the data from + self._parsers = { + variant: [] for variant in self._override_order + } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] + self._config = { + variant: {} for variant in self._override_order + } # type: Dict[Kind, Dict[str, Any]] + self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] + + def load(self): + # type: () -> None + """Loads configuration from configuration files and environment + """ + self._load_config_files() + if not self.isolated: + self._load_environment_vars() + + def get_file_to_edit(self): + # type: () -> Optional[str] + """Returns the file with highest priority in configuration + """ + assert self.load_only is not None, \ + "Need to be specified a file to be editing" + + try: + return self._get_parser_to_modify()[0] + except IndexError: + return None + + def items(self): + # type: () -> Iterable[Tuple[str, Any]] + """Returns key-value pairs like dict.items() representing the loaded + configuration + """ + return self._dictionary.items() + + def get_value(self, key): + # type: (str) -> Any + """Get a value from the configuration. + """ + try: + return self._dictionary[key] + except KeyError: + raise ConfigurationError("No such key - {}".format(key)) + + def set_value(self, key, value): + # type: (str, Any) -> None + """Modify a value in the configuration. + """ + self._ensure_have_load_only() + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Modify the parser and the configuration + if not parser.has_section(section): + parser.add_section(section) + parser.set(section, name, value) + + self._config[self.load_only][key] = value + self._mark_as_modified(fname, parser) + + def unset_value(self, key): + # type: (str) -> None + """Unset a value in the configuration. + """ + self._ensure_have_load_only() + + if key not in self._config[self.load_only]: + raise ConfigurationError("No such key - {}".format(key)) + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Remove the key in the parser + modified_something = False + if parser.has_section(section): + # Returns whether the option was removed or not + modified_something = parser.remove_option(section, name) + + if modified_something: + # name removed from parser, section may now be empty + section_iter = iter(parser.items(section)) + try: + val = six.next(section_iter) + except StopIteration: + val = None + + if val is None: + parser.remove_section(section) + + self._mark_as_modified(fname, parser) + else: + raise ConfigurationError( + "Fatal Internal error [id=1]. Please report as a bug." + ) + + del self._config[self.load_only][key] + + def save(self): + # type: () -> None + """Save the currentin-memory state. + """ + self._ensure_have_load_only() + + for fname, parser in self._modified_parsers: + logger.info("Writing to %s", fname) + + # Ensure directory exists. + ensure_dir(os.path.dirname(fname)) + + with open(fname, "w") as f: + parser.write(f) # type: ignore + + # + # Private routines + # + + def _ensure_have_load_only(self): + # type: () -> None + if self.load_only is None: + raise ConfigurationError("Needed a specific file to be modifying.") + logger.debug("Will be working with %s variant only", self.load_only) + + @property + def _dictionary(self): + # type: () -> Dict[str, Any] + """A dictionary representing the loaded configuration. + """ + # NOTE: Dictionaries are not populated if not loaded. So, conditionals + # are not needed here. + retval = {} + + for variant in self._override_order: + retval.update(self._config[variant]) + + return retval + + def _load_config_files(self): + # type: () -> None + """Loads configuration from configuration files + """ + config_files = dict(self._iter_config_files()) + if config_files[kinds.ENV][0:1] == [os.devnull]: + logger.debug( + "Skipping loading configuration files due to " + "environment's PIP_CONFIG_FILE being os.devnull" + ) + return + + for variant, files in config_files.items(): + for fname in files: + # If there's specific variant set in `load_only`, load only + # that variant, not the others. + if self.load_only is not None and variant != self.load_only: + logger.debug( + "Skipping file '%s' (variant: %s)", fname, variant + ) + continue + + parser = self._load_file(variant, fname) + + # Keeping track of the parsers used + self._parsers[variant].append((fname, parser)) + + def _load_file(self, variant, fname): + # type: (Kind, str) -> RawConfigParser + logger.debug("For variant '%s', will try loading '%s'", variant, fname) + parser = self._construct_parser(fname) + + for section in parser.sections(): + items = parser.items(section) + self._config[variant].update(self._normalized_keys(section, items)) + + return parser + + def _construct_parser(self, fname): + # type: (str) -> RawConfigParser + parser = configparser.RawConfigParser() + # If there is no such file, don't bother reading it but create the + # parser anyway, to hold the data. + # Doing this is useful when modifying and saving files, where we don't + # need to construct a parser. + if os.path.exists(fname): + try: + parser.read(fname) + except UnicodeDecodeError: + raise ConfigurationError(( + "ERROR: " + "Configuration file contains invalid %s characters.\n" + "Please fix your configuration, located at %s\n" + ) % (locale.getpreferredencoding(False), fname)) + return parser + + def _load_environment_vars(self): + # type: () -> None + """Loads configuration from environment variables + """ + self._config[kinds.ENV_VAR].update( + self._normalized_keys(":env:", self._get_environ_vars()) + ) + + def _normalized_keys(self, section, items): + # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] + """Normalizes items to construct a dictionary with normalized keys. + + This routine is where the names become keys and are made the same + regardless of source - configuration files or environment. + """ + normalized = {} + for name, val in items: + key = section + "." + _normalize_name(name) + normalized[key] = val + return normalized + + def _get_environ_vars(self): + # type: () -> Iterable[Tuple[str, str]] + """Returns a generator with all environmental vars with prefix PIP_""" + for key, val in os.environ.items(): + should_be_yielded = ( + key.startswith("PIP_") and + key[4:].lower() not in self._ignore_env_names + ) + if should_be_yielded: + yield key[4:].lower(), val + + # XXX: This is patched in the tests. + def _iter_config_files(self): + # type: () -> Iterable[Tuple[Kind, List[str]]] + """Yields variant and configuration files associated with it. + + This should be treated like items of a dictionary. + """ + # SMELL: Move the conditions out of this function + + # environment variables have the lowest priority + config_file = os.environ.get('PIP_CONFIG_FILE', None) + if config_file is not None: + yield kinds.ENV, [config_file] + else: + yield kinds.ENV, [] + + # at the base we have any global configuration + yield kinds.GLOBAL, list(site_config_files) + + # per-user configuration next + should_load_user_config = not self.isolated and not ( + config_file and os.path.exists(config_file) + ) + if should_load_user_config: + # The legacy config file is overridden by the new config file + yield kinds.USER, [legacy_config_file, new_config_file] + + # finally virtualenv configuration first trumping others + if running_under_virtualenv(): + yield kinds.VENV, [venv_config_file] + + def _get_parser_to_modify(self): + # type: () -> Tuple[str, RawConfigParser] + # Determine which parser to modify + parsers = self._parsers[self.load_only] + if not parsers: + # This should not happen if everything works correctly. + raise ConfigurationError( + "Fatal Internal error [id=2]. Please report as a bug." + ) + + # Use the highest priority parser. + return parsers[-1] + + # XXX: This is patched in the tests. + def _mark_as_modified(self, fname, parser): + # type: (str, RawConfigParser) -> None + file_parser_tuple = (fname, parser) + if file_parser_tuple not in self._modified_parsers: + self._modified_parsers.append(file_parser_tuple) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py new file mode 100755 index 0000000..e0e2d24 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py @@ -0,0 +1,922 @@ +from __future__ import absolute_import + +import cgi +import email.utils +import getpass +import json +import logging +import mimetypes +import os +import platform +import re +import shutil +import sys + +from pip._vendor import requests, six, urllib3 +from pip._vendor.cachecontrol import CacheControlAdapter +from pip._vendor.cachecontrol.caches import FileCache +from pip._vendor.lockfile import LockError +from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter +from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth +from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.requests.utils import get_netrc_auth +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request +from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote +from pip._vendor.urllib3.util import IS_PYOPENSSL + +import pip +from pip._internal.compat import WINDOWS +from pip._internal.exceptions import HashMismatch, InstallationError +from pip._internal.locations import write_delete_marker_file +from pip._internal.models import PyPI +from pip._internal.utils.encoding import auto_decode +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.glibc import libc_ver +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + ARCHIVE_EXTENSIONS, ask_path_exists, backup_dir, call_subprocess, consume, + display_path, format_size, get_installed_version, rmtree, splitext, + unpack_file, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.ui import DownloadProgressProvider +from pip._internal.vcs import vcs + +try: + import ssl # noqa +except ImportError: + ssl = None + +HAS_TLS = (ssl is not None) or IS_PYOPENSSL + +__all__ = ['get_file_content', + 'is_url', 'url_to_path', 'path_to_url', + 'is_archive_file', 'unpack_vcs_link', + 'unpack_file_url', 'is_vcs_url', 'is_file_url', + 'unpack_http_url', 'unpack_url'] + + +logger = logging.getLogger(__name__) + + +def user_agent(): + """ + Return a string representing the user agent. + """ + data = { + "installer": {"name": "pip", "version": pip.__version__}, + "python": platform.python_version(), + "implementation": { + "name": platform.python_implementation(), + }, + } + + if data["implementation"]["name"] == 'CPython': + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'PyPy': + if sys.pypy_version_info.releaselevel == 'final': + pypy_version_info = sys.pypy_version_info[:3] + else: + pypy_version_info = sys.pypy_version_info + data["implementation"]["version"] = ".".join( + [str(x) for x in pypy_version_info] + ) + elif data["implementation"]["name"] == 'Jython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'IronPython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + + if sys.platform.startswith("linux"): + from pip._vendor import distro + distro_infos = dict(filter( + lambda x: x[1], + zip(["name", "version", "id"], distro.linux_distribution()), + )) + libc = dict(filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + )) + if libc: + distro_infos["libc"] = libc + if distro_infos: + data["distro"] = distro_infos + + if sys.platform.startswith("darwin") and platform.mac_ver()[0]: + data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} + + if platform.system(): + data.setdefault("system", {})["name"] = platform.system() + + if platform.release(): + data.setdefault("system", {})["release"] = platform.release() + + if platform.machine(): + data["cpu"] = platform.machine() + + if HAS_TLS: + data["openssl_version"] = ssl.OPENSSL_VERSION + + setuptools_version = get_installed_version("setuptools") + if setuptools_version is not None: + data["setuptools_version"] = setuptools_version + + return "{data[installer][name]}/{data[installer][version]} {json}".format( + data=data, + json=json.dumps(data, separators=(",", ":"), sort_keys=True), + ) + + +class MultiDomainBasicAuth(AuthBase): + + def __init__(self, prompting=True): + self.prompting = prompting + self.passwords = {} + + def __call__(self, req): + parsed = urllib_parse.urlparse(req.url) + + # Get the netloc without any embedded credentials + netloc = parsed.netloc.rsplit("@", 1)[-1] + + # Set the url of the request to the url without any credentials + req.url = urllib_parse.urlunparse(parsed[:1] + (netloc,) + parsed[2:]) + + # Use any stored credentials that we have for this netloc + username, password = self.passwords.get(netloc, (None, None)) + + # Extract credentials embedded in the url if we have none stored + if username is None: + username, password = self.parse_credentials(parsed.netloc) + + # Get creds from netrc if we still don't have them + if username is None and password is None: + netrc_auth = get_netrc_auth(req.url) + username, password = netrc_auth if netrc_auth else (None, None) + + if username or password: + # Store the username and password + self.passwords[netloc] = (username, password) + + # Send the basic auth with this request + req = HTTPBasicAuth(username or "", password or "")(req) + + # Attach a hook to handle 401 responses + req.register_hook("response", self.handle_401) + + return req + + def handle_401(self, resp, **kwargs): + # We only care about 401 responses, anything else we want to just + # pass through the actual response + if resp.status_code != 401: + return resp + + # We are not able to prompt the user so simply return the response + if not self.prompting: + return resp + + parsed = urllib_parse.urlparse(resp.url) + + # Prompt the user for a new username and password + username = six.moves.input("User for %s: " % parsed.netloc) + password = getpass.getpass("Password: ") + + # Store the new username and password to use for future requests + if username or password: + self.passwords[parsed.netloc] = (username, password) + + # Consume content and release the original connection to allow our new + # request to reuse the same one. + resp.content + resp.raw.release_conn() + + # Add our new username and password to the request + req = HTTPBasicAuth(username or "", password or "")(resp.request) + + # Send our new request + new_resp = resp.connection.send(req, **kwargs) + new_resp.history.append(resp) + + return new_resp + + def parse_credentials(self, netloc): + if "@" in netloc: + userinfo = netloc.rsplit("@", 1)[0] + if ":" in userinfo: + user, pwd = userinfo.split(":", 1) + return (urllib_unquote(user), urllib_unquote(pwd)) + return urllib_unquote(userinfo), None + return None, None + + +class LocalFSAdapter(BaseAdapter): + + def send(self, request, stream=None, timeout=None, verify=None, cert=None, + proxies=None): + pathname = url_to_path(request.url) + + resp = Response() + resp.status_code = 200 + resp.url = request.url + + try: + stats = os.stat(pathname) + except OSError as exc: + resp.status_code = 404 + resp.raw = exc + else: + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + content_type = mimetypes.guess_type(pathname)[0] or "text/plain" + resp.headers = CaseInsensitiveDict({ + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + }) + + resp.raw = open(pathname, "rb") + resp.close = resp.raw.close + + return resp + + def close(self): + pass + + +class SafeFileCache(FileCache): + """ + A file based cache which is safe to use even when the target directory may + not be accessible or writable. + """ + + def __init__(self, *args, **kwargs): + super(SafeFileCache, self).__init__(*args, **kwargs) + + # Check to ensure that the directory containing our cache directory + # is owned by the user current executing pip. If it does not exist + # we will check the parent directory until we find one that does exist. + # If it is not owned by the user executing pip then we will disable + # the cache and log a warning. + if not check_path_owner(self.directory): + logger.warning( + "The directory '%s' or its parent directory is not owned by " + "the current user and the cache has been disabled. Please " + "check the permissions and owner of that directory. If " + "executing pip with sudo, you may want sudo's -H flag.", + self.directory, + ) + + # Set our directory to None to disable the Cache + self.directory = None + + def get(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).get(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + def set(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).set(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + def delete(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).delete(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + +class InsecureHTTPAdapter(HTTPAdapter): + + def cert_verify(self, conn, url, verify, cert): + conn.cert_reqs = 'CERT_NONE' + conn.ca_certs = None + + +class PipSession(requests.Session): + + timeout = None + + def __init__(self, *args, **kwargs): + retries = kwargs.pop("retries", 0) + cache = kwargs.pop("cache", None) + insecure_hosts = kwargs.pop("insecure_hosts", []) + + super(PipSession, self).__init__(*args, **kwargs) + + # Attach our User Agent to the request + self.headers["User-Agent"] = user_agent() + + # Attach our Authentication handler to the session + self.auth = MultiDomainBasicAuth() + + # Create our urllib3.Retry instance which will allow us to customize + # how we handle retries. + retries = urllib3.Retry( + # Set the total number of retries that a particular request can + # have. + total=retries, + + # A 503 error from PyPI typically means that the Fastly -> Origin + # connection got interrupted in some way. A 503 error in general + # is typically considered a transient error so we'll go ahead and + # retry it. + # A 500 may indicate transient error in Amazon S3 + # A 520 or 527 - may indicate transient error in CloudFlare + status_forcelist=[500, 503, 520, 527], + + # Add a small amount of back off between failed requests in + # order to prevent hammering the service. + backoff_factor=0.25, + ) + + # We want to _only_ cache responses on securely fetched origins. We do + # this because we can't validate the response of an insecurely fetched + # origin, and we don't want someone to be able to poison the cache and + # require manual eviction from the cache to fix it. + if cache: + secure_adapter = CacheControlAdapter( + cache=SafeFileCache(cache, use_dir_lock=True), + max_retries=retries, + ) + else: + secure_adapter = HTTPAdapter(max_retries=retries) + + # Our Insecure HTTPAdapter disables HTTPS validation. It does not + # support caching (see above) so we'll use it for all http:// URLs as + # well as any https:// host that we've marked as ignoring TLS errors + # for. + insecure_adapter = InsecureHTTPAdapter(max_retries=retries) + + self.mount("https://", secure_adapter) + self.mount("http://", insecure_adapter) + + # Enable file:// urls + self.mount("file://", LocalFSAdapter()) + + # We want to use a non-validating adapter for any requests which are + # deemed insecure. + for host in insecure_hosts: + self.mount("https://{}/".format(host), insecure_adapter) + + def request(self, method, url, *args, **kwargs): + # Allow setting a default timeout on a session + kwargs.setdefault("timeout", self.timeout) + + # Dispatch the actual request + return super(PipSession, self).request(method, url, *args, **kwargs) + + +def get_file_content(url, comes_from=None, session=None): + """Gets the content of a file; it may be a filename, file: URL, or + http: URL. Returns (location, content). Content is unicode. + + :param url: File path or url. + :param comes_from: Origin description of requirements. + :param session: Instance of pip.download.PipSession. + """ + if session is None: + raise TypeError( + "get_file_content() missing 1 required keyword argument: 'session'" + ) + + match = _scheme_re.search(url) + if match: + scheme = match.group(1).lower() + if (scheme == 'file' and comes_from and + comes_from.startswith('http')): + raise InstallationError( + 'Requirements file %s references URL %s, which is local' + % (comes_from, url)) + if scheme == 'file': + path = url.split(':', 1)[1] + path = path.replace('\\', '/') + match = _url_slash_drive_re.match(path) + if match: + path = match.group(1) + ':' + path.split('|', 1)[1] + path = urllib_parse.unquote(path) + if path.startswith('/'): + path = '/' + path.lstrip('/') + url = path + else: + # FIXME: catch some errors + resp = session.get(url) + resp.raise_for_status() + return resp.url, resp.text + try: + with open(url, 'rb') as f: + content = auto_decode(f.read()) + except IOError as exc: + raise InstallationError( + 'Could not open requirements file: %s' % str(exc) + ) + return url, content + + +_scheme_re = re.compile(r'^(http|https|file):', re.I) +_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) + + +def is_url(name): + """Returns true if the name looks like a URL""" + if ':' not in name: + return False + scheme = name.split(':', 1)[0].lower() + return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes + + +def url_to_path(url): + """ + Convert a file: URL to a path. + """ + assert url.startswith('file:'), ( + "You can only turn file: urls into filenames (not %r)" % url) + + _, netloc, path, _, _ = urllib_parse.urlsplit(url) + + # if we have a UNC path, prepend UNC share notation + if netloc: + netloc = '\\\\' + netloc + + path = urllib_request.url2pathname(netloc + path) + return path + + +def path_to_url(path): + """ + Convert a path to a file: URL. The path will be made absolute and have + quoted path parts. + """ + path = os.path.normpath(os.path.abspath(path)) + url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) + return url + + +def is_archive_file(name): + """Return True if `name` is a considered as an archive file.""" + ext = splitext(name)[1].lower() + if ext in ARCHIVE_EXTENSIONS: + return True + return False + + +def unpack_vcs_link(link, location): + vcs_backend = _get_used_vcs_backend(link) + vcs_backend.unpack(location) + + +def _get_used_vcs_backend(link): + for backend in vcs.backends: + if link.scheme in backend.schemes: + vcs_backend = backend(link.url) + return vcs_backend + + +def is_vcs_url(link): + return bool(_get_used_vcs_backend(link)) + + +def is_file_url(link): + return link.url.lower().startswith('file:') + + +def is_dir_url(link): + """Return whether a file:// Link points to a directory. + + ``link`` must not have any other scheme but file://. Call is_file_url() + first. + + """ + link_path = url_to_path(link.url_without_fragment) + return os.path.isdir(link_path) + + +def _progress_indicator(iterable, *args, **kwargs): + return iterable + + +def _download_url(resp, link, content_file, hashes, progress_bar): + try: + total_length = int(resp.headers['content-length']) + except (ValueError, KeyError, TypeError): + total_length = 0 + + cached_resp = getattr(resp, "from_cache", False) + if logger.getEffectiveLevel() > logging.INFO: + show_progress = False + elif cached_resp: + show_progress = False + elif total_length > (40 * 1000): + show_progress = True + elif not total_length: + show_progress = True + else: + show_progress = False + + show_url = link.show_url + + def resp_read(chunk_size): + try: + # Special case for urllib3. + for chunk in resp.raw.stream( + chunk_size, + # We use decode_content=False here because we don't + # want urllib3 to mess with the raw bytes we get + # from the server. If we decompress inside of + # urllib3 then we cannot verify the checksum + # because the checksum will be of the compressed + # file. This breakage will only occur if the + # server adds a Content-Encoding header, which + # depends on how the server was configured: + # - Some servers will notice that the file isn't a + # compressible file and will leave the file alone + # and with an empty Content-Encoding + # - Some servers will notice that the file is + # already compressed and will leave the file + # alone and will add a Content-Encoding: gzip + # header + # - Some servers won't notice anything at all and + # will take a file that's already been compressed + # and compress it again and set the + # Content-Encoding: gzip header + # + # By setting this not to decode automatically we + # hope to eliminate problems with the second case. + decode_content=False): + yield chunk + except AttributeError: + # Standard file-like object. + while True: + chunk = resp.raw.read(chunk_size) + if not chunk: + break + yield chunk + + def written_chunks(chunks): + for chunk in chunks: + content_file.write(chunk) + yield chunk + + progress_indicator = _progress_indicator + + if link.netloc == PyPI.netloc: + url = show_url + else: + url = link.url_without_fragment + + if show_progress: # We don't show progress on cached responses + progress_indicator = DownloadProgressProvider(progress_bar, + max=total_length) + if total_length: + logger.info("Downloading %s (%s)", url, format_size(total_length)) + else: + logger.info("Downloading %s", url) + elif cached_resp: + logger.info("Using cached %s", url) + else: + logger.info("Downloading %s", url) + + logger.debug('Downloading from URL %s', link) + + downloaded_chunks = written_chunks( + progress_indicator( + resp_read(CONTENT_CHUNK_SIZE), + CONTENT_CHUNK_SIZE + ) + ) + if hashes: + hashes.check_against_chunks(downloaded_chunks) + else: + consume(downloaded_chunks) + + +def _copy_file(filename, location, link): + copy = True + download_location = os.path.join(location, link.filename) + if os.path.exists(download_location): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)abort' % + display_path(download_location), ('i', 'w', 'b', 'a')) + if response == 'i': + copy = False + elif response == 'w': + logger.warning('Deleting %s', display_path(download_location)) + os.remove(download_location) + elif response == 'b': + dest_file = backup_dir(download_location) + logger.warning( + 'Backing up %s to %s', + display_path(download_location), + display_path(dest_file), + ) + shutil.move(download_location, dest_file) + elif response == 'a': + sys.exit(-1) + if copy: + shutil.copy(filename, download_location) + logger.info('Saved %s', display_path(download_location)) + + +def unpack_http_url(link, location, download_dir=None, + session=None, hashes=None, progress_bar="on"): + if session is None: + raise TypeError( + "unpack_http_url() missing 1 required keyword argument: 'session'" + ) + + with TempDirectory(kind="unpack") as temp_dir: + # If a download dir is specified, is the file already downloaded there? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, + download_dir, + hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + content_type = mimetypes.guess_type(from_path)[0] + else: + # let's download to a tmp dir + from_path, content_type = _download_http_url(link, + session, + temp_dir.path, + hashes, + progress_bar) + + # unpack the archive to the build dir location. even when only + # downloading archives, they have to be unpacked to parse dependencies + unpack_file(from_path, location, content_type, link) + + # a download dir is specified; let's copy the archive there + if download_dir and not already_downloaded_path: + _copy_file(from_path, download_dir, link) + + if not already_downloaded_path: + os.unlink(from_path) + + +def unpack_file_url(link, location, download_dir=None, hashes=None): + """Unpack link into location. + + If download_dir is provided and link points to a file, make a copy + of the link file inside download_dir. + """ + link_path = url_to_path(link.url_without_fragment) + + # If it's a url to a local directory + if is_dir_url(link): + if os.path.isdir(location): + rmtree(location) + shutil.copytree(link_path, location, symlinks=True) + if download_dir: + logger.info('Link is a directory, ignoring download_dir') + return + + # If --require-hashes is off, `hashes` is either empty, the + # link's embedded hash, or MissingHashes; it is required to + # match. If --require-hashes is on, we are satisfied by any + # hash in `hashes` matching: a URL-based or an option-based + # one; no internet-sourced hash will be in `hashes`. + if hashes: + hashes.check_against_path(link_path) + + # If a download dir is specified, is the file already there and valid? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, + download_dir, + hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + else: + from_path = link_path + + content_type = mimetypes.guess_type(from_path)[0] + + # unpack the archive to the build dir location. even when only downloading + # archives, they have to be unpacked to parse dependencies + unpack_file(from_path, location, content_type, link) + + # a download dir is specified and not already downloaded + if download_dir and not already_downloaded_path: + _copy_file(from_path, download_dir, link) + + +def _copy_dist_from_dir(link_path, location): + """Copy distribution files in `link_path` to `location`. + + Invoked when user requests to install a local directory. E.g.: + + pip install . + pip install ~/dev/git-repos/python-prompt-toolkit + + """ + + # Note: This is currently VERY SLOW if you have a lot of data in the + # directory, because it copies everything with `shutil.copytree`. + # What it should really do is build an sdist and install that. + # See https://github.com/pypa/pip/issues/2195 + + if os.path.isdir(location): + rmtree(location) + + # build an sdist + setup_py = 'setup.py' + sdist_args = [sys.executable] + sdist_args.append('-c') + sdist_args.append(SETUPTOOLS_SHIM % setup_py) + sdist_args.append('sdist') + sdist_args += ['--dist-dir', location] + logger.info('Running setup.py sdist for %s', link_path) + + with indent_log(): + call_subprocess(sdist_args, cwd=link_path, show_stdout=False) + + # unpack sdist into `location` + sdist = os.path.join(location, os.listdir(location)[0]) + logger.info('Unpacking sdist %s into %s', sdist, location) + unpack_file(sdist, location, content_type=None, link=None) + + +class PipXmlrpcTransport(xmlrpc_client.Transport): + """Provide a `xmlrpclib.Transport` implementation via a `PipSession` + object. + """ + + def __init__(self, index_url, session, use_datetime=False): + xmlrpc_client.Transport.__init__(self, use_datetime) + index_parts = urllib_parse.urlparse(index_url) + self._scheme = index_parts.scheme + self._session = session + + def request(self, host, handler, request_body, verbose=False): + parts = (self._scheme, host, handler, None, None, None) + url = urllib_parse.urlunparse(parts) + try: + headers = {'Content-Type': 'text/xml'} + response = self._session.post(url, data=request_body, + headers=headers, stream=True) + response.raise_for_status() + self.verbose = verbose + return self.parse_response(response.raw) + except requests.HTTPError as exc: + logger.critical( + "HTTP error %s while getting %s", + exc.response.status_code, url, + ) + raise + + +def unpack_url(link, location, download_dir=None, + only_download=False, session=None, hashes=None, + progress_bar="on"): + """Unpack link. + If link is a VCS link: + if only_download, export into download_dir and ignore location + else unpack into location + for other types of link: + - unpack into location + - if download_dir, copy the file into download_dir + - if only_download, mark location for deletion + + :param hashes: A Hashes object, one of whose embedded hashes must match, + or HashMismatch will be raised. If the Hashes is empty, no matches are + required, and unhashable types of requirements (like VCS ones, which + would ordinarily raise HashUnsupported) are allowed. + """ + # non-editable vcs urls + if is_vcs_url(link): + unpack_vcs_link(link, location) + + # file urls + elif is_file_url(link): + unpack_file_url(link, location, download_dir, hashes=hashes) + + # http urls + else: + if session is None: + session = PipSession() + + unpack_http_url( + link, + location, + download_dir, + session, + hashes=hashes, + progress_bar=progress_bar + ) + if only_download: + write_delete_marker_file(location) + + +def _download_http_url(link, session, temp_dir, hashes, progress_bar): + """Download link url into temp_dir using provided session""" + target_url = link.url.split('#', 1)[0] + try: + resp = session.get( + target_url, + # We use Accept-Encoding: identity here because requests + # defaults to accepting compressed responses. This breaks in + # a variety of ways depending on how the server is configured. + # - Some servers will notice that the file isn't a compressible + # file and will leave the file alone and with an empty + # Content-Encoding + # - Some servers will notice that the file is already + # compressed and will leave the file alone and will add a + # Content-Encoding: gzip header + # - Some servers won't notice anything at all and will take + # a file that's already been compressed and compress it again + # and set the Content-Encoding: gzip header + # By setting this to request only the identity encoding We're + # hoping to eliminate the third case. Hopefully there does not + # exist a server which when given a file will notice it is + # already compressed and that you're not asking for a + # compressed file and will then decompress it before sending + # because if that's the case I don't think it'll ever be + # possible to make this work. + headers={"Accept-Encoding": "identity"}, + stream=True, + ) + resp.raise_for_status() + except requests.HTTPError as exc: + logger.critical( + "HTTP error %s while getting %s", exc.response.status_code, link, + ) + raise + + content_type = resp.headers.get('content-type', '') + filename = link.filename # fallback + # Have a look at the Content-Disposition header for a better guess + content_disposition = resp.headers.get('content-disposition') + if content_disposition: + type, params = cgi.parse_header(content_disposition) + # We use ``or`` here because we don't want to use an "empty" value + # from the filename param. + filename = params.get('filename') or filename + ext = splitext(filename)[1] + if not ext: + ext = mimetypes.guess_extension(content_type) + if ext: + filename += ext + if not ext and link.url != resp.url: + ext = os.path.splitext(resp.url)[1] + if ext: + filename += ext + file_path = os.path.join(temp_dir, filename) + with open(file_path, 'wb') as content_file: + _download_url(resp, link, content_file, hashes, progress_bar) + return file_path, content_type + + +def _check_download_dir(link, download_dir, hashes): + """ Check download_dir for previously downloaded file with correct hash + If a correct file is found return its path else None + """ + download_path = os.path.join(download_dir, link.filename) + if os.path.exists(download_path): + # If already downloaded, does its hash match? + logger.info('File was already downloaded %s', download_path) + if hashes: + try: + hashes.check_against_path(download_path) + except HashMismatch: + logger.warning( + 'Previously-downloaded file %s has bad hash. ' + 'Re-downloading.', + download_path + ) + os.unlink(download_path) + return None + return download_path + return None diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py new file mode 100755 index 0000000..28705c8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py @@ -0,0 +1,249 @@ +"""Exceptions used throughout package""" +from __future__ import absolute_import + +from itertools import chain, groupby, repeat + +from pip._vendor.six import iteritems + + +class PipError(Exception): + """Base pip exception""" + + +class ConfigurationError(PipError): + """General exception in configuration""" + + +class InstallationError(PipError): + """General exception during installation""" + + +class UninstallationError(PipError): + """General exception during uninstallation""" + + +class DistributionNotFound(InstallationError): + """Raised when a distribution cannot be found to satisfy a requirement""" + + +class RequirementsFileParseError(InstallationError): + """Raised when a general error occurs parsing a requirements file line.""" + + +class BestVersionAlreadyInstalled(PipError): + """Raised when the most up-to-date version of a package is already + installed.""" + + +class BadCommand(PipError): + """Raised when virtualenv or a command is not found""" + + +class CommandError(PipError): + """Raised when there is an error in command-line arguments""" + + +class PreviousBuildDirError(PipError): + """Raised when there's a previous conflicting build directory""" + + +class InvalidWheelFilename(InstallationError): + """Invalid wheel filename.""" + + +class UnsupportedWheel(InstallationError): + """Unsupported wheel.""" + + +class HashErrors(InstallationError): + """Multiple HashError instances rolled into one for reporting""" + + def __init__(self): + self.errors = [] + + def append(self, error): + self.errors.append(error) + + def __str__(self): + lines = [] + self.errors.sort(key=lambda e: e.order) + for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): + lines.append(cls.head) + lines.extend(e.body() for e in errors_of_cls) + if lines: + return '\n'.join(lines) + + def __nonzero__(self): + return bool(self.errors) + + def __bool__(self): + return self.__nonzero__() + + +class HashError(InstallationError): + """ + A failure to verify a package against known-good hashes + + :cvar order: An int sorting hash exception classes by difficulty of + recovery (lower being harder), so the user doesn't bother fretting + about unpinned packages when he has deeper issues, like VCS + dependencies, to deal with. Also keeps error reports in a + deterministic order. + :cvar head: A section heading for display above potentially many + exceptions of this kind + :ivar req: The InstallRequirement that triggered this error. This is + pasted on after the exception is instantiated, because it's not + typically available earlier. + + """ + req = None + head = '' + + def body(self): + """Return a summary of me for display under the heading. + + This default implementation simply prints a description of the + triggering requirement. + + :param req: The InstallRequirement that provoked this error, with + populate_link() having already been called + + """ + return ' %s' % self._requirement_name() + + def __str__(self): + return '%s\n%s' % (self.head, self.body()) + + def _requirement_name(self): + """Return a description of the requirement that triggered me. + + This default implementation returns long description of the req, with + line numbers + + """ + return str(self.req) if self.req else 'unknown package' + + +class VcsHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 0 + head = ("Can't verify hashes for these requirements because we don't " + "have a way to hash version control repositories:") + + +class DirectoryUrlHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 1 + head = ("Can't verify hashes for these file:// requirements because they " + "point to directories:") + + +class HashMissing(HashError): + """A hash was needed for a requirement but is absent.""" + + order = 2 + head = ('Hashes are required in --require-hashes mode, but they are ' + 'missing from some requirements. Here is a list of those ' + 'requirements along with the hashes their downloaded archives ' + 'actually had. Add lines like these to your requirements files to ' + 'prevent tampering. (If you did not enable --require-hashes ' + 'manually, note that it turns on automatically when any package ' + 'has a hash.)') + + def __init__(self, gotten_hash): + """ + :param gotten_hash: The hash of the (possibly malicious) archive we + just downloaded + """ + self.gotten_hash = gotten_hash + + def body(self): + # Dodge circular import. + from pip._internal.utils.hashes import FAVORITE_HASH + + package = None + if self.req: + # In the case of URL-based requirements, display the original URL + # seen in the requirements file rather than the package name, + # so the output can be directly copied into the requirements file. + package = (self.req.original_link if self.req.original_link + # In case someone feeds something downright stupid + # to InstallRequirement's constructor. + else getattr(self.req, 'req', None)) + return ' %s --hash=%s:%s' % (package or 'unknown package', + FAVORITE_HASH, + self.gotten_hash) + + +class HashUnpinned(HashError): + """A requirement had a hash specified but was not pinned to a specific + version.""" + + order = 3 + head = ('In --require-hashes mode, all requirements must have their ' + 'versions pinned with ==. These do not:') + + +class HashMismatch(HashError): + """ + Distribution file hash values don't match. + + :ivar package_name: The name of the package that triggered the hash + mismatch. Feel free to write to this after the exception is raise to + improve its error message. + + """ + order = 4 + head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' + 'FILE. If you have updated the package versions, please update ' + 'the hashes. Otherwise, examine the package contents carefully; ' + 'someone may have tampered with them.') + + def __init__(self, allowed, gots): + """ + :param allowed: A dict of algorithm names pointing to lists of allowed + hex digests + :param gots: A dict of algorithm names pointing to hashes we + actually got from the files under suspicion + """ + self.allowed = allowed + self.gots = gots + + def body(self): + return ' %s:\n%s' % (self._requirement_name(), + self._hash_comparison()) + + def _hash_comparison(self): + """ + Return a comparison of actual and expected hash values. + + Example:: + + Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde + or 123451234512345123451234512345123451234512345 + Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef + + """ + def hash_then_or(hash_name): + # For now, all the decent hashes have 6-char names, so we can get + # away with hard-coding space literals. + return chain([hash_name], repeat(' or')) + + lines = [] + for hash_name, expecteds in iteritems(self.allowed): + prefix = hash_then_or(hash_name) + lines.extend((' Expected %s %s' % (next(prefix), e)) + for e in expecteds) + lines.append(' Got %s\n' % + self.gots[hash_name].hexdigest()) + prefix = ' or' + return '\n'.join(lines) + + +class UnsupportedPythonVersion(InstallationError): + """Unsupported python version according to Requires-Python package + metadata.""" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py new file mode 100755 index 0000000..15e0bf3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py @@ -0,0 +1,1117 @@ +"""Routines related to PyPI, indexes""" +from __future__ import absolute_import + +import cgi +import itertools +import logging +import mimetypes +import os +import posixpath +import re +import sys +import warnings +from collections import namedtuple + +from pip._vendor import html5lib, requests, six +from pip._vendor.distlib.compat import unescape +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.requests.exceptions import SSLError +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.compat import ipaddress +from pip._internal.download import HAS_TLS, is_url, path_to_url, url_to_path +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, DistributionNotFound, InvalidWheelFilename, + UnsupportedWheel, +) +from pip._internal.models import PyPI +from pip._internal.pep425tags import get_supported +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, cached_property, normalize_path, + splitext, +) +from pip._internal.utils.packaging import check_requires_python +from pip._internal.wheel import Wheel, wheel_ext + +__all__ = ['FormatControl', 'fmt_ctl_handle_mutual_exclude', 'PackageFinder'] + + +SECURE_ORIGINS = [ + # protocol, hostname, port + # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) + ("https", "*", "*"), + ("*", "localhost", "*"), + ("*", "127.0.0.0/8", "*"), + ("*", "::1/128", "*"), + ("file", "*", None), + # ssh is always secure. + ("ssh", "*", "*"), +] + + +logger = logging.getLogger(__name__) + + +class InstallationCandidate(object): + + def __init__(self, project, version, location): + self.project = project + self.version = parse_version(version) + self.location = location + self._key = (self.project, self.version, self.location) + + def __repr__(self): + return "".format( + self.project, self.version, self.location, + ) + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, InstallationCandidate): + return NotImplemented + + return method(self._key, other._key) + + +class PackageFinder(object): + """This finds packages. + + This is meant to match easy_install's technique for looking for + packages, by reading pages and looking for appropriate links. + """ + + def __init__(self, find_links, index_urls, allow_all_prereleases=False, + trusted_hosts=None, process_dependency_links=False, + session=None, format_control=None, platform=None, + versions=None, abi=None, implementation=None): + """Create a PackageFinder. + + :param format_control: A FormatControl object or None. Used to control + the selection of source packages / binary packages when consulting + the index and links. + :param platform: A string or None. If None, searches for packages + that are supported by the current system. Otherwise, will find + packages that can be built on the platform passed in. These + packages will only be downloaded for distribution: they will + not be built locally. + :param versions: A list of strings or None. This is passed directly + to pep425tags.py in the get_supported() method. + :param abi: A string or None. This is passed directly + to pep425tags.py in the get_supported() method. + :param implementation: A string or None. This is passed directly + to pep425tags.py in the get_supported() method. + """ + if session is None: + raise TypeError( + "PackageFinder() missing 1 required keyword argument: " + "'session'" + ) + + # Build find_links. If an argument starts with ~, it may be + # a local file relative to a home directory. So try normalizing + # it and if it exists, use the normalized version. + # This is deliberately conservative - it might be fine just to + # blindly normalize anything starting with a ~... + self.find_links = [] + for link in find_links: + if link.startswith('~'): + new_link = normalize_path(link) + if os.path.exists(new_link): + link = new_link + self.find_links.append(link) + + self.index_urls = index_urls + self.dependency_links = [] + + # These are boring links that have already been logged somehow: + self.logged_links = set() + + self.format_control = format_control or FormatControl(set(), set()) + + # Domains that we won't emit warnings for when not using HTTPS + self.secure_origins = [ + ("*", host, "*") + for host in (trusted_hosts if trusted_hosts else []) + ] + + # Do we want to allow _all_ pre-releases? + self.allow_all_prereleases = allow_all_prereleases + + # Do we process dependency links? + self.process_dependency_links = process_dependency_links + + # The Session we'll use to make requests + self.session = session + + # The valid tags to check potential found wheel candidates against + self.valid_tags = get_supported( + versions=versions, + platform=platform, + abi=abi, + impl=implementation, + ) + + # If we don't have TLS enabled, then WARN if anyplace we're looking + # relies on TLS. + if not HAS_TLS: + for link in itertools.chain(self.index_urls, self.find_links): + parsed = urllib_parse.urlparse(link) + if parsed.scheme == "https": + logger.warning( + "pip is configured with locations that require " + "TLS/SSL, however the ssl module in Python is not " + "available." + ) + break + + def get_formatted_locations(self): + lines = [] + if self.index_urls and self.index_urls != [PyPI.simple_url]: + lines.append( + "Looking in indexes: {}".format(", ".join(self.index_urls)) + ) + if self.find_links: + lines.append( + "Looking in links: {}".format(", ".join(self.find_links)) + ) + return "\n".join(lines) + + def add_dependency_links(self, links): + # # FIXME: this shouldn't be global list this, it should only + # # apply to requirements of the package that specifies the + # # dependency_links value + # # FIXME: also, we should track comes_from (i.e., use Link) + if self.process_dependency_links: + warnings.warn( + "Dependency Links processing has been deprecated and will be " + "removed in a future release.", + RemovedInPip11Warning, + ) + self.dependency_links.extend(links) + + @staticmethod + def _sort_locations(locations, expand_dir=False): + """ + Sort locations into "files" (archives) and "urls", and return + a pair of lists (files,urls) + """ + files = [] + urls = [] + + # puts the url for the given file path into the appropriate list + def sort_path(path): + url = path_to_url(path) + if mimetypes.guess_type(url, strict=False)[0] == 'text/html': + urls.append(url) + else: + files.append(url) + + for url in locations: + + is_local_path = os.path.exists(url) + is_file_url = url.startswith('file:') + + if is_local_path or is_file_url: + if is_local_path: + path = url + else: + path = url_to_path(url) + if os.path.isdir(path): + if expand_dir: + path = os.path.realpath(path) + for item in os.listdir(path): + sort_path(os.path.join(path, item)) + elif is_file_url: + urls.append(url) + elif os.path.isfile(path): + sort_path(path) + else: + logger.warning( + "Url '%s' is ignored: it is neither a file " + "nor a directory.", url, + ) + elif is_url(url): + # Only add url with clear scheme + urls.append(url) + else: + logger.warning( + "Url '%s' is ignored. It is either a non-existing " + "path or lacks a specific scheme.", url, + ) + + return files, urls + + def _candidate_sort_key(self, candidate): + """ + Function used to generate link sort key for link tuples. + The greater the return value, the more preferred it is. + If not finding wheels, then sorted by version only. + If finding wheels, then the sort order is by version, then: + 1. existing installs + 2. wheels ordered via Wheel.support_index_min(self.valid_tags) + 3. source archives + Note: it was considered to embed this logic into the Link + comparison operators, but then different sdist links + with the same version, would have to be considered equal + """ + support_num = len(self.valid_tags) + build_tag = tuple() + if candidate.location.is_wheel: + # can raise InvalidWheelFilename + wheel = Wheel(candidate.location.filename) + if not wheel.supported(self.valid_tags): + raise UnsupportedWheel( + "%s is not a supported wheel for this platform. It " + "can't be sorted." % wheel.filename + ) + pri = -(wheel.support_index_min(self.valid_tags)) + if wheel.build_tag is not None: + match = re.match(r'^(\d+)(.*)$', wheel.build_tag) + build_tag_groups = match.groups() + build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) + else: # sdist + pri = -(support_num) + return (candidate.version, build_tag, pri) + + def _validate_secure_origin(self, logger, location): + # Determine if this url used a secure transport mechanism + parsed = urllib_parse.urlparse(str(location)) + origin = (parsed.scheme, parsed.hostname, parsed.port) + + # The protocol to use to see if the protocol matches. + # Don't count the repository type as part of the protocol: in + # cases such as "git+ssh", only use "ssh". (I.e., Only verify against + # the last scheme.) + protocol = origin[0].rsplit('+', 1)[-1] + + # Determine if our origin is a secure origin by looking through our + # hardcoded list of secure origins, as well as any additional ones + # configured on this PackageFinder instance. + for secure_origin in (SECURE_ORIGINS + self.secure_origins): + if protocol != secure_origin[0] and secure_origin[0] != "*": + continue + + try: + # We need to do this decode dance to ensure that we have a + # unicode object, even on Python 2.x. + addr = ipaddress.ip_address( + origin[1] + if ( + isinstance(origin[1], six.text_type) or + origin[1] is None + ) + else origin[1].decode("utf8") + ) + network = ipaddress.ip_network( + secure_origin[1] + if isinstance(secure_origin[1], six.text_type) + else secure_origin[1].decode("utf8") + ) + except ValueError: + # We don't have both a valid address or a valid network, so + # we'll check this origin against hostnames. + if (origin[1] and + origin[1].lower() != secure_origin[1].lower() and + secure_origin[1] != "*"): + continue + else: + # We have a valid address and network, so see if the address + # is contained within the network. + if addr not in network: + continue + + # Check to see if the port patches + if (origin[2] != secure_origin[2] and + secure_origin[2] != "*" and + secure_origin[2] is not None): + continue + + # If we've gotten here, then this origin matches the current + # secure origin and we should return True + return True + + # If we've gotten to this point, then the origin isn't secure and we + # will not accept it as a valid location to search. We will however + # log a warning that we are ignoring it. + logger.warning( + "The repository located at %s is not a trusted or secure host and " + "is being ignored. If this repository is available via HTTPS we " + "recommend you use HTTPS instead, otherwise you may silence " + "this warning and allow it anyway with '--trusted-host %s'.", + parsed.hostname, + parsed.hostname, + ) + + return False + + def _get_index_urls_locations(self, project_name): + """Returns the locations found via self.index_urls + + Checks the url_name on the main (first in the list) index and + use this url_name to produce all locations + """ + + def mkurl_pypi_url(url): + loc = posixpath.join( + url, + urllib_parse.quote(canonicalize_name(project_name))) + # For maximum compatibility with easy_install, ensure the path + # ends in a trailing slash. Although this isn't in the spec + # (and PyPI can handle it without the slash) some other index + # implementations might break if they relied on easy_install's + # behavior. + if not loc.endswith('/'): + loc = loc + '/' + return loc + + return [mkurl_pypi_url(url) for url in self.index_urls] + + def find_all_candidates(self, project_name): + """Find all available InstallationCandidate for project_name + + This checks index_urls, find_links and dependency_links. + All versions found are returned as an InstallationCandidate list. + + See _link_package_versions for details on which files are accepted + """ + index_locations = self._get_index_urls_locations(project_name) + index_file_loc, index_url_loc = self._sort_locations(index_locations) + fl_file_loc, fl_url_loc = self._sort_locations( + self.find_links, expand_dir=True, + ) + dep_file_loc, dep_url_loc = self._sort_locations(self.dependency_links) + + file_locations = (Link(url) for url in itertools.chain( + index_file_loc, fl_file_loc, dep_file_loc, + )) + + # We trust every url that the user has given us whether it was given + # via --index-url or --find-links + # We explicitly do not trust links that came from dependency_links + # We want to filter out any thing which does not have a secure origin. + url_locations = [ + link for link in itertools.chain( + (Link(url) for url in index_url_loc), + (Link(url) for url in fl_url_loc), + (Link(url) for url in dep_url_loc), + ) + if self._validate_secure_origin(logger, link) + ] + + logger.debug('%d location(s) to search for versions of %s:', + len(url_locations), project_name) + + for location in url_locations: + logger.debug('* %s', location) + + canonical_name = canonicalize_name(project_name) + formats = fmt_ctl_formats(self.format_control, canonical_name) + search = Search(project_name, canonical_name, formats) + find_links_versions = self._package_versions( + # We trust every directly linked archive in find_links + (Link(url, '-f') for url in self.find_links), + search + ) + + page_versions = [] + for page in self._get_pages(url_locations, project_name): + logger.debug('Analyzing links from page %s', page.url) + with indent_log(): + page_versions.extend( + self._package_versions(page.links, search) + ) + + dependency_versions = self._package_versions( + (Link(url) for url in self.dependency_links), search + ) + if dependency_versions: + logger.debug( + 'dependency_links found: %s', + ', '.join([ + version.location.url for version in dependency_versions + ]) + ) + + file_versions = self._package_versions(file_locations, search) + if file_versions: + file_versions.sort(reverse=True) + logger.debug( + 'Local files found: %s', + ', '.join([ + url_to_path(candidate.location.url) + for candidate in file_versions + ]) + ) + + # This is an intentional priority ordering + return ( + file_versions + find_links_versions + page_versions + + dependency_versions + ) + + def find_requirement(self, req, upgrade): + """Try to find a Link matching req + + Expects req, an InstallRequirement and upgrade, a boolean + Returns a Link if found, + Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise + """ + all_candidates = self.find_all_candidates(req.name) + + # Filter out anything which doesn't match our specifier + compatible_versions = set( + req.specifier.filter( + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + [str(c.version) for c in all_candidates], + prereleases=( + self.allow_all_prereleases + if self.allow_all_prereleases else None + ), + ) + ) + applicable_candidates = [ + # Again, converting to str to deal with debundling. + c for c in all_candidates if str(c.version) in compatible_versions + ] + + if applicable_candidates: + best_candidate = max(applicable_candidates, + key=self._candidate_sort_key) + else: + best_candidate = None + + if req.satisfied_by is not None: + installed_version = parse_version(req.satisfied_by.version) + else: + installed_version = None + + if installed_version is None and best_candidate is None: + logger.critical( + 'Could not find a version that satisfies the requirement %s ' + '(from versions: %s)', + req, + ', '.join( + sorted( + {str(c.version) for c in all_candidates}, + key=parse_version, + ) + ) + ) + + raise DistributionNotFound( + 'No matching distribution found for %s' % req + ) + + best_installed = False + if installed_version and ( + best_candidate is None or + best_candidate.version <= installed_version): + best_installed = True + + if not upgrade and installed_version is not None: + if best_installed: + logger.debug( + 'Existing installed version (%s) is most up-to-date and ' + 'satisfies requirement', + installed_version, + ) + else: + logger.debug( + 'Existing installed version (%s) satisfies requirement ' + '(most up-to-date version is %s)', + installed_version, + best_candidate.version, + ) + return None + + if best_installed: + # We have an existing version, and its the best version + logger.debug( + 'Installed version (%s) is most up-to-date (past versions: ' + '%s)', + installed_version, + ', '.join(sorted(compatible_versions, key=parse_version)) or + "none", + ) + raise BestVersionAlreadyInstalled + + logger.debug( + 'Using version %s (newest of versions: %s)', + best_candidate.version, + ', '.join(sorted(compatible_versions, key=parse_version)) + ) + return best_candidate.location + + def _get_pages(self, locations, project_name): + """ + Yields (page, page_url) from the given locations, skipping + locations that have errors. + """ + seen = set() + for location in locations: + if location in seen: + continue + seen.add(location) + + page = self._get_page(location) + if page is None: + continue + + yield page + + _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') + + def _sort_links(self, links): + """ + Returns elements of links in order, non-egg links first, egg links + second, while eliminating duplicates + """ + eggs, no_eggs = [], [] + seen = set() + for link in links: + if link not in seen: + seen.add(link) + if link.egg_fragment: + eggs.append(link) + else: + no_eggs.append(link) + return no_eggs + eggs + + def _package_versions(self, links, search): + result = [] + for link in self._sort_links(links): + v = self._link_package_versions(link, search) + if v is not None: + result.append(v) + return result + + def _log_skipped_link(self, link, reason): + if link not in self.logged_links: + logger.debug('Skipping link %s; %s', link, reason) + self.logged_links.add(link) + + def _link_package_versions(self, link, search): + """Return an InstallationCandidate or None""" + version = None + if link.egg_fragment: + egg_info = link.egg_fragment + ext = link.ext + else: + egg_info, ext = link.splitext() + if not ext: + self._log_skipped_link(link, 'not a file') + return + if ext not in SUPPORTED_EXTENSIONS: + self._log_skipped_link( + link, 'unsupported archive format: %s' % ext, + ) + return + if "binary" not in search.formats and ext == wheel_ext: + self._log_skipped_link( + link, 'No binaries permitted for %s' % search.supplied, + ) + return + if "macosx10" in link.path and ext == '.zip': + self._log_skipped_link(link, 'macosx10 one') + return + if ext == wheel_ext: + try: + wheel = Wheel(link.filename) + except InvalidWheelFilename: + self._log_skipped_link(link, 'invalid wheel filename') + return + if canonicalize_name(wheel.name) != search.canonical: + self._log_skipped_link( + link, 'wrong project name (not %s)' % search.supplied) + return + + if not wheel.supported(self.valid_tags): + self._log_skipped_link( + link, 'it is not compatible with this Python') + return + + version = wheel.version + + # This should be up by the search.ok_binary check, but see issue 2700. + if "source" not in search.formats and ext != wheel_ext: + self._log_skipped_link( + link, 'No sources permitted for %s' % search.supplied, + ) + return + + if not version: + version = egg_info_matches(egg_info, search.supplied, link) + if version is None: + self._log_skipped_link( + link, 'wrong project name (not %s)' % search.supplied) + return + + match = self._py_version_re.search(version) + if match: + version = version[:match.start()] + py_version = match.group(1) + if py_version != sys.version[:3]: + self._log_skipped_link( + link, 'Python version is incorrect') + return + try: + support_this_python = check_requires_python(link.requires_python) + except specifiers.InvalidSpecifier: + logger.debug("Package %s has an invalid Requires-Python entry: %s", + link.filename, link.requires_python) + support_this_python = True + + if not support_this_python: + logger.debug("The package %s is incompatible with the python" + "version in use. Acceptable python versions are:%s", + link, link.requires_python) + return + logger.debug('Found link %s, version: %s', link, version) + + return InstallationCandidate(search.supplied, version, link) + + def _get_page(self, link): + return HTMLPage.get_page(link, session=self.session) + + +def egg_info_matches( + egg_info, search_name, link, + _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)): + """Pull the version part out of a string. + + :param egg_info: The string to parse. E.g. foo-2.1 + :param search_name: The name of the package this belongs to. None to + infer the name. Note that this cannot unambiguously parse strings + like foo-2-2 which might be foo, 2-2 or foo-2, 2. + :param link: The link the string came from, for logging on failure. + """ + match = _egg_info_re.search(egg_info) + if not match: + logger.debug('Could not parse version from link: %s', link) + return None + if search_name is None: + full_match = match.group(0) + return full_match[full_match.index('-'):] + name = match.group(0).lower() + # To match the "safe" name that pkg_resources creates: + name = name.replace('_', '-') + # project name and version must be separated by a dash + look_for = search_name.lower() + "-" + if name.startswith(look_for): + return match.group(0)[len(look_for):] + else: + return None + + +class HTMLPage(object): + """Represents one page, along with its URL""" + + def __init__(self, content, url, headers=None): + # Determine if we have any encoding information in our headers + encoding = None + if headers and "Content-Type" in headers: + content_type, params = cgi.parse_header(headers["Content-Type"]) + + if "charset" in params: + encoding = params['charset'] + + self.content = content + self.parsed = html5lib.parse( + self.content, + transport_encoding=encoding, + namespaceHTMLElements=False, + ) + self.url = url + self.headers = headers + + def __str__(self): + return self.url + + @classmethod + def get_page(cls, link, skip_archives=True, session=None): + if session is None: + raise TypeError( + "get_page() missing 1 required keyword argument: 'session'" + ) + + url = link.url + url = url.split('#', 1)[0] + + # Check for VCS schemes that do not support lookup as web pages. + from pip._internal.vcs import VcsSupport + for scheme in VcsSupport.schemes: + if url.lower().startswith(scheme) and url[len(scheme)] in '+:': + logger.debug('Cannot look at %s URL %s', scheme, link) + return None + + try: + if skip_archives: + filename = link.filename + for bad_ext in ARCHIVE_EXTENSIONS: + if filename.endswith(bad_ext): + content_type = cls._get_content_type( + url, session=session, + ) + if content_type.lower().startswith('text/html'): + break + else: + logger.debug( + 'Skipping page %s because of Content-Type: %s', + link, + content_type, + ) + return + + logger.debug('Getting page %s', url) + + # Tack index.html onto file:// URLs that point to directories + (scheme, netloc, path, params, query, fragment) = \ + urllib_parse.urlparse(url) + if (scheme == 'file' and + os.path.isdir(urllib_request.url2pathname(path))): + # add trailing slash if not present so urljoin doesn't trim + # final segment + if not url.endswith('/'): + url += '/' + url = urllib_parse.urljoin(url, 'index.html') + logger.debug(' file: URL is directory, getting %s', url) + + resp = session.get( + url, + headers={ + "Accept": "text/html", + "Cache-Control": "max-age=600", + }, + ) + resp.raise_for_status() + + # The check for archives above only works if the url ends with + # something that looks like an archive. However that is not a + # requirement of an url. Unless we issue a HEAD request on every + # url we cannot know ahead of time for sure if something is HTML + # or not. However we can check after we've downloaded it. + content_type = resp.headers.get('Content-Type', 'unknown') + if not content_type.lower().startswith("text/html"): + logger.debug( + 'Skipping page %s because of Content-Type: %s', + link, + content_type, + ) + return + + inst = cls(resp.content, resp.url, resp.headers) + except requests.HTTPError as exc: + cls._handle_fail(link, exc, url) + except SSLError as exc: + reason = "There was a problem confirming the ssl certificate: " + reason += str(exc) + cls._handle_fail(link, reason, url, meth=logger.info) + except requests.ConnectionError as exc: + cls._handle_fail(link, "connection error: %s" % exc, url) + except requests.Timeout: + cls._handle_fail(link, "timed out", url) + else: + return inst + + @staticmethod + def _handle_fail(link, reason, url, meth=None): + if meth is None: + meth = logger.debug + + meth("Could not fetch URL %s: %s - skipping", link, reason) + + @staticmethod + def _get_content_type(url, session): + """Get the Content-Type of the given url, using a HEAD request""" + scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) + if scheme not in {'http', 'https'}: + # FIXME: some warning or something? + # assertion error? + return '' + + resp = session.head(url, allow_redirects=True) + resp.raise_for_status() + + return resp.headers.get("Content-Type", "") + + @cached_property + def base_url(self): + bases = [ + x for x in self.parsed.findall(".//base") + if x.get("href") is not None + ] + if bases and bases[0].get("href"): + return bases[0].get("href") + else: + return self.url + + @property + def links(self): + """Yields all links in the page""" + for anchor in self.parsed.findall(".//a"): + if anchor.get("href"): + href = anchor.get("href") + url = self.clean_link( + urllib_parse.urljoin(self.base_url, href) + ) + pyrequire = anchor.get('data-requires-python') + pyrequire = unescape(pyrequire) if pyrequire else None + yield Link(url, self, requires_python=pyrequire) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + def clean_link(self, url): + """Makes sure a link is fully encoded. That is, if a ' ' shows up in + the link, it will be rewritten to %20 (while not over-quoting + % or other characters).""" + return self._clean_re.sub( + lambda match: '%%%2x' % ord(match.group(0)), url) + + +class Link(object): + + def __init__(self, url, comes_from=None, requires_python=None): + """ + Object representing a parsed link from https://pypi.org/simple/* + + url: + url of the resource pointed to (href of the link) + comes_from: + instance of HTMLPage where the link was found, or string. + requires_python: + String containing the `Requires-Python` metadata field, specified + in PEP 345. This may be specified by a data-requires-python + attribute in the HTML link tag, as described in PEP 503. + """ + + # url can be a UNC windows share + if url.startswith('\\\\'): + url = path_to_url(url) + + self.url = url + self.comes_from = comes_from + self.requires_python = requires_python if requires_python else None + + def __str__(self): + if self.requires_python: + rp = ' (requires-python:%s)' % self.requires_python + else: + rp = '' + if self.comes_from: + return '%s (from %s)%s' % (self.url, self.comes_from, rp) + else: + return str(self.url) + + def __repr__(self): + return '' % self + + def __eq__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url == other.url + + def __ne__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url != other.url + + def __lt__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url < other.url + + def __le__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url <= other.url + + def __gt__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url > other.url + + def __ge__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url >= other.url + + def __hash__(self): + return hash(self.url) + + @property + def filename(self): + _, netloc, path, _, _ = urllib_parse.urlsplit(self.url) + name = posixpath.basename(path.rstrip('/')) or netloc + name = urllib_parse.unquote(name) + assert name, ('URL %r produced no filename' % self.url) + return name + + @property + def scheme(self): + return urllib_parse.urlsplit(self.url)[0] + + @property + def netloc(self): + return urllib_parse.urlsplit(self.url)[1] + + @property + def path(self): + return urllib_parse.unquote(urllib_parse.urlsplit(self.url)[2]) + + def splitext(self): + return splitext(posixpath.basename(self.path.rstrip('/'))) + + @property + def ext(self): + return self.splitext()[1] + + @property + def url_without_fragment(self): + scheme, netloc, path, query, fragment = urllib_parse.urlsplit(self.url) + return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) + + _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') + + @property + def egg_fragment(self): + match = self._egg_fragment_re.search(self.url) + if not match: + return None + return match.group(1) + + _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') + + @property + def subdirectory_fragment(self): + match = self._subdirectory_fragment_re.search(self.url) + if not match: + return None + return match.group(1) + + _hash_re = re.compile( + r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' + ) + + @property + def hash(self): + match = self._hash_re.search(self.url) + if match: + return match.group(2) + return None + + @property + def hash_name(self): + match = self._hash_re.search(self.url) + if match: + return match.group(1) + return None + + @property + def show_url(self): + return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0]) + + @property + def is_wheel(self): + return self.ext == wheel_ext + + @property + def is_artifact(self): + """ + Determines if this points to an actual artifact (e.g. a tarball) or if + it points to an "abstract" thing like a path or a VCS location. + """ + from pip._internal.vcs import vcs + + if self.scheme in vcs.all_schemes: + return False + + return True + + +FormatControl = namedtuple('FormatControl', 'no_binary only_binary') +"""This object has two fields, no_binary and only_binary. + +If a field is falsy, it isn't set. If it is {':all:'}, it should match all +packages except those listed in the other field. Only one field can be set +to {':all:'} at a time. The rest of the time exact package name matches +are listed, with any given package only showing up in one field at a time. +""" + + +def fmt_ctl_handle_mutual_exclude(value, target, other): + new = value.split(',') + while ':all:' in new: + other.clear() + target.clear() + target.add(':all:') + del new[:new.index(':all:') + 1] + if ':none:' not in new: + # Without a none, we want to discard everything as :all: covers it + return + for name in new: + if name == ':none:': + target.clear() + continue + name = canonicalize_name(name) + other.discard(name) + target.add(name) + + +def fmt_ctl_formats(fmt_ctl, canonical_name): + result = {"binary", "source"} + if canonical_name in fmt_ctl.only_binary: + result.discard('source') + elif canonical_name in fmt_ctl.no_binary: + result.discard('binary') + elif ':all:' in fmt_ctl.only_binary: + result.discard('source') + elif ':all:' in fmt_ctl.no_binary: + result.discard('binary') + return frozenset(result) + + +def fmt_ctl_no_binary(fmt_ctl): + fmt_ctl_handle_mutual_exclude( + ':all:', fmt_ctl.no_binary, fmt_ctl.only_binary, + ) + + +Search = namedtuple('Search', 'supplied canonical formats') +"""Capture key aspects of a search. + +:attribute supplied: The user supplied package. +:attribute canonical: The canonical package name. +:attribute formats: The formats allowed for this package. Should be a set + with 'binary' or 'source' or both in it. +""" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py new file mode 100755 index 0000000..ce8f7e9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py @@ -0,0 +1,194 @@ +"""Locations where we look for configs, install stuff, etc""" +from __future__ import absolute_import + +import os +import os.path +import platform +import site +import sys +import sysconfig +from distutils import sysconfig as distutils_sysconfig +from distutils.command.install import SCHEME_KEYS, install # type: ignore + +from pip._internal.compat import WINDOWS, expanduser +from pip._internal.utils import appdirs + +# Application Directories +USER_CACHE_DIR = appdirs.user_cache_dir("pip") + + +DELETE_MARKER_MESSAGE = '''\ +This file is placed here by pip to indicate the source was put +here by pip. + +Once this package is successfully installed this source code will be +deleted (unless you remove this file). +''' +PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt' + + +def write_delete_marker_file(directory): + """ + Write the pip delete marker file into this directory. + """ + filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME) + with open(filepath, 'w') as marker_fp: + marker_fp.write(DELETE_MARKER_MESSAGE) + + +def running_under_virtualenv(): + """ + Return True if we're running inside a virtualenv, False otherwise. + + """ + if hasattr(sys, 'real_prefix'): + return True + elif sys.prefix != getattr(sys, "base_prefix", sys.prefix): + return True + + return False + + +def virtualenv_no_global(): + """ + Return True if in a venv and no system site packages. + """ + # this mirrors the logic in virtualenv.py for locating the + # no-global-site-packages.txt file + site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) + no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt') + if running_under_virtualenv() and os.path.isfile(no_global_file): + return True + + +if running_under_virtualenv(): + src_prefix = os.path.join(sys.prefix, 'src') +else: + # FIXME: keep src in cwd for now (it is not a temporary folder) + try: + src_prefix = os.path.join(os.getcwd(), 'src') + except OSError: + # In case the current working directory has been renamed or deleted + sys.exit( + "The folder you are executing pip from can no longer be found." + ) + +# under macOS + virtualenv sys.prefix is not properly resolved +# it is something like /path/to/python/bin/.. +# Note: using realpath due to tmp dirs on OSX being symlinks +src_prefix = os.path.abspath(src_prefix) + +# FIXME doesn't account for venv linked to global site-packages + +site_packages = sysconfig.get_path("purelib") +# This is because of a bug in PyPy's sysconfig module, see +# https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths +# for more information. +if platform.python_implementation().lower() == "pypy": + site_packages = distutils_sysconfig.get_python_lib() +try: + # Use getusersitepackages if this is present, as it ensures that the + # value is initialised properly. + user_site = site.getusersitepackages() +except AttributeError: + user_site = site.USER_SITE +user_dir = expanduser('~') +if WINDOWS: + bin_py = os.path.join(sys.prefix, 'Scripts') + bin_user = os.path.join(user_site, 'Scripts') + # buildout uses 'bin' on Windows too? + if not os.path.exists(bin_py): + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') + + config_basename = 'pip.ini' + + legacy_storage_dir = os.path.join(user_dir, 'pip') + legacy_config_file = os.path.join( + legacy_storage_dir, + config_basename, + ) +else: + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') + + config_basename = 'pip.conf' + + legacy_storage_dir = os.path.join(user_dir, '.pip') + legacy_config_file = os.path.join( + legacy_storage_dir, + config_basename, + ) + # Forcing to use /usr/local/bin for standard macOS framework installs + # Also log to ~/Library/Logs/ for use with the Console.app log viewer + if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': + bin_py = '/usr/local/bin' + +site_config_files = [ + os.path.join(path, config_basename) + for path in appdirs.site_config_dirs('pip') +] + +venv_config_file = os.path.join(sys.prefix, config_basename) +new_config_file = os.path.join(appdirs.user_config_dir("pip"), config_basename) + + +def distutils_scheme(dist_name, user=False, home=None, root=None, + isolated=False, prefix=None): + """ + Return a distutils install scheme + """ + from distutils.dist import Distribution + + scheme = {} + + if isolated: + extra_dist_args = {"script_args": ["--no-user-cfg"]} + else: + extra_dist_args = {} + dist_args = {'name': dist_name} + dist_args.update(extra_dist_args) + + d = Distribution(dist_args) + d.parse_config_files() + i = d.get_command_obj('install', create=True) + # NOTE: setting user or home has the side-effect of creating the home dir + # or user base for installations during finalize_options() + # ideally, we'd prefer a scheme class that has no side-effects. + assert not (user and prefix), "user={} prefix={}".format(user, prefix) + i.user = user or i.user + if user: + i.prefix = "" + i.prefix = prefix or i.prefix + i.home = home or i.home + i.root = root or i.root + i.finalize_options() + for key in SCHEME_KEYS: + scheme[key] = getattr(i, 'install_' + key) + + # install_lib specified in setup.cfg should install *everything* + # into there (i.e. it takes precedence over both purelib and + # platlib). Note, i.install_lib is *always* set after + # finalize_options(); we only want to override here if the user + # has explicitly requested it hence going back to the config + if 'install_lib' in d.get_option_dict('install'): + scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) + + if running_under_virtualenv(): + scheme['headers'] = os.path.join( + sys.prefix, + 'include', + 'site', + 'python' + sys.version[:3], + dist_name, + ) + + if root is not None: + path_no_drive = os.path.splitdrive( + os.path.abspath(scheme["headers"]))[1] + scheme["headers"] = os.path.join( + root, + path_no_drive[1:], + ) + + return scheme diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py new file mode 100755 index 0000000..2d080a4 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py @@ -0,0 +1,4 @@ +from pip._internal.models.index import Index, PyPI + + +__all__ = ["Index", "PyPI"] diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py new file mode 100755 index 0000000..161de50 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py @@ -0,0 +1,15 @@ +from pip._vendor.six.moves.urllib import parse as urllib_parse + + +class Index(object): + def __init__(self, url): + self.url = url + self.netloc = urllib_parse.urlsplit(url).netloc + self.simple_url = self.url_to_path('simple') + self.pypi_url = self.url_to_path('pypi') + + def url_to_path(self, path): + return urllib_parse.urljoin(self.url, path) + + +PyPI = Index('https://pypi.org/') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py new file mode 100755 index 0000000..bab6b9f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py @@ -0,0 +1,106 @@ +"""Validation of dependencies of packages +""" + +from collections import namedtuple + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.operations.prepare import make_abstract_dist + +from pip._internal.utils.misc import get_installed_distributions +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._internal.req.req_install import InstallRequirement + from typing import Any, Dict, Iterator, Set, Tuple, List + + # Shorthands + PackageSet = Dict[str, 'PackageDetails'] + Missing = Tuple[str, Any] + Conflicting = Tuple[str, str, Any] + + MissingDict = Dict[str, List[Missing]] + ConflictingDict = Dict[str, List[Conflicting]] + CheckResult = Tuple[MissingDict, ConflictingDict] + +PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) + + +def create_package_set_from_installed(**kwargs): + # type: (**Any) -> PackageSet + """Converts a list of distributions into a PackageSet. + """ + # Default to using all packages installed on the system + if kwargs == {}: + kwargs = {"local_only": False, "skip": ()} + retval = {} + for dist in get_installed_distributions(**kwargs): + name = canonicalize_name(dist.project_name) + retval[name] = PackageDetails(dist.version, dist.requires()) + return retval + + +def check_package_set(package_set): + # type: (PackageSet) -> CheckResult + """Check if a package set is consistent + """ + missing = dict() + conflicting = dict() + + for package_name in package_set: + # Info about dependencies of package_name + missing_deps = set() # type: Set[Missing] + conflicting_deps = set() # type: Set[Conflicting] + + for req in package_set[package_name].requires: + name = canonicalize_name(req.project_name) # type: str + + # Check if it's missing + if name not in package_set: + missed = True + if req.marker is not None: + missed = req.marker.evaluate() + if missed: + missing_deps.add((name, req)) + continue + + # Check if there's a conflict + version = package_set[name].version # type: str + if not req.specifier.contains(version, prereleases=True): + conflicting_deps.add((name, version, req)) + + def str_key(x): + return str(x) + + if missing_deps: + missing[package_name] = sorted(missing_deps, key=str_key) + if conflicting_deps: + conflicting[package_name] = sorted(conflicting_deps, key=str_key) + + return missing, conflicting + + +def check_install_conflicts(to_install): + # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] + """For checking if the dependency graph would be consistent after \ + installing given requirements + """ + # Start from the current state + state = create_package_set_from_installed() + _simulate_installation_of(to_install, state) + return state, check_package_set(state) + + +# NOTE from @pradyunsg +# This required a minor update in dependency link handling logic over at +# operations.prepare.IsSDist.dist() to get it working +def _simulate_installation_of(to_install, state): + # type: (List[InstallRequirement], PackageSet) -> None + """Computes the version of packages after installing to_install. + """ + + # Modify it as installing requirement_set would (assuming no errors) + for inst_req in to_install: + dist = make_abstract_dist(inst_req).dist(finder=None) + name = canonicalize_name(dist.key) + state[name] = PackageDetails(dist.version, dist.requires()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py new file mode 100755 index 0000000..000102d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py @@ -0,0 +1,252 @@ +from __future__ import absolute_import + +import collections +import logging +import os +import re +import warnings + +from pip._vendor import pkg_resources, six +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.pkg_resources import RequirementParseError + +from pip._internal.exceptions import InstallationError +from pip._internal.req import InstallRequirement +from pip._internal.req.req_file import COMMENT_RE +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.misc import ( + dist_is_editable, get_installed_distributions, +) + +logger = logging.getLogger(__name__) + + +def freeze( + requirement=None, + find_links=None, local_only=None, user_only=None, skip_regex=None, + isolated=False, + wheel_cache=None, + exclude_editable=False, + skip=()): + find_links = find_links or [] + skip_match = None + + if skip_regex: + skip_match = re.compile(skip_regex).search + + dependency_links = [] + + for dist in pkg_resources.working_set: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend( + dist.get_metadata_lines('dependency_links.txt') + ) + for link in find_links: + if '#egg=' in link: + dependency_links.append(link) + for link in find_links: + yield '-f %s' % link + installations = {} + for dist in get_installed_distributions(local_only=local_only, + skip=(), + user_only=user_only): + try: + req = FrozenRequirement.from_dist( + dist, + dependency_links + ) + except RequirementParseError: + logger.warning( + "Could not parse requirement: %s", + dist.project_name + ) + continue + if exclude_editable and req.editable: + continue + installations[req.name] = req + + if requirement: + # the options that don't get turned into an InstallRequirement + # should only be emitted once, even if the same option is in multiple + # requirements files, so we need to keep track of what has been emitted + # so that we don't emit it again if it's seen again + emitted_options = set() + # keep track of which files a requirement is in so that we can + # give an accurate warning if a requirement appears multiple times. + req_files = collections.defaultdict(list) + for req_file_path in requirement: + with open(req_file_path) as req_file: + for line in req_file: + if (not line.strip() or + line.strip().startswith('#') or + (skip_match and skip_match(line)) or + line.startswith(( + '-r', '--requirement', + '-Z', '--always-unzip', + '-f', '--find-links', + '-i', '--index-url', + '--pre', + '--trusted-host', + '--process-dependency-links', + '--extra-index-url'))): + line = line.rstrip() + if line not in emitted_options: + emitted_options.add(line) + yield line + continue + + if line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + line_req = InstallRequirement.from_editable( + line, + isolated=isolated, + wheel_cache=wheel_cache, + ) + else: + line_req = InstallRequirement.from_line( + COMMENT_RE.sub('', line).strip(), + isolated=isolated, + wheel_cache=wheel_cache, + ) + + if not line_req.name: + logger.info( + "Skipping line in requirement file [%s] because " + "it's not clear what it would install: %s", + req_file_path, line.strip(), + ) + logger.info( + " (add #egg=PackageName to the URL to avoid" + " this warning)" + ) + elif line_req.name not in installations: + # either it's not installed, or it is installed + # but has been processed already + if not req_files[line_req.name]: + logger.warning( + "Requirement file [%s] contains %s, but that " + "package is not installed", + req_file_path, + COMMENT_RE.sub('', line).strip(), + ) + else: + req_files[line_req.name].append(req_file_path) + else: + yield str(installations[line_req.name]).rstrip() + del installations[line_req.name] + req_files[line_req.name].append(req_file_path) + + # Warn about requirements that were included multiple times (in a + # single requirements file or in different requirements files). + for name, files in six.iteritems(req_files): + if len(files) > 1: + logger.warning("Requirement %s included multiple times [%s]", + name, ', '.join(sorted(set(files)))) + + yield( + '## The following requirements were added by ' + 'pip freeze:' + ) + for installation in sorted( + installations.values(), key=lambda x: x.name.lower()): + if canonicalize_name(installation.name) not in skip: + yield str(installation).rstrip() + + +class FrozenRequirement(object): + def __init__(self, name, req, editable, comments=()): + self.name = name + self.req = req + self.editable = editable + self.comments = comments + + _rev_re = re.compile(r'-r(\d+)$') + _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') + + @classmethod + def from_dist(cls, dist, dependency_links): + location = os.path.normcase(os.path.abspath(dist.location)) + comments = [] + from pip._internal.vcs import vcs, get_src_requirement + if dist_is_editable(dist) and vcs.get_backend_name(location): + editable = True + try: + req = get_src_requirement(dist, location) + except InstallationError as exc: + logger.warning( + "Error when trying to get requirement for VCS system %s, " + "falling back to uneditable format", exc + ) + req = None + if req is None: + logger.warning( + 'Could not determine repository location of %s', location + ) + comments.append( + '## !! Could not determine repository location' + ) + req = dist.as_requirement() + editable = False + else: + editable = False + req = dist.as_requirement() + specs = req.specs + assert len(specs) == 1 and specs[0][0] in ["==", "==="], \ + 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \ + (specs, dist) + version = specs[0][1] + ver_match = cls._rev_re.search(version) + date_match = cls._date_re.search(version) + if ver_match or date_match: + svn_backend = vcs.get_backend('svn') + if svn_backend: + svn_location = svn_backend().get_location( + dist, + dependency_links, + ) + if not svn_location: + logger.warning( + 'Warning: cannot find svn location for %s', req, + ) + comments.append( + '## FIXME: could not find svn URL in dependency_links ' + 'for this package:' + ) + else: + warnings.warn( + "SVN editable detection based on dependency links " + "will be dropped in the future.", + RemovedInPip11Warning, + ) + comments.append( + '# Installing as editable to satisfy requirement %s:' % + req + ) + if ver_match: + rev = ver_match.group(1) + else: + rev = '{%s}' % date_match.group(1) + editable = True + req = '%s@%s#egg=%s' % ( + svn_location, + rev, + cls.egg_name(dist) + ) + return cls(dist.project_name, req, editable, comments) + + @staticmethod + def egg_name(dist): + name = dist.egg_name() + match = re.search(r'-py\d\.\d$', name) + if match: + name = name[:match.start()] + return name + + def __str__(self): + req = self.req + if self.editable: + req = '-e %s' % req + return '\n'.join(list(self.comments) + [str(req)]) + '\n' diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py new file mode 100755 index 0000000..c1e8158 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py @@ -0,0 +1,380 @@ +"""Prepares a distribution for installation +""" + +import itertools +import logging +import os +import sys +from copy import copy + +from pip._vendor import pkg_resources, requests + +from pip._internal.build_env import NoOpBuildEnvironment +from pip._internal.compat import expanduser +from pip._internal.download import ( + is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path, +) +from pip._internal.exceptions import ( + DirectoryUrlHashUnsupported, HashUnpinned, InstallationError, + PreviousBuildDirError, VcsHashUnsupported, +) +from pip._internal.index import FormatControl +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.hashes import MissingHashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + call_subprocess, display_path, normalize_path, +) +from pip._internal.utils.ui import open_spinner +from pip._internal.vcs import vcs + +logger = logging.getLogger(__name__) + + +def make_abstract_dist(req): + """Factory to make an abstract dist object. + + Preconditions: Either an editable req with a source_dir, or satisfied_by or + a wheel link, or a non-editable req with a source_dir. + + :return: A concrete DistAbstraction. + """ + if req.editable: + return IsSDist(req) + elif req.link and req.link.is_wheel: + return IsWheel(req) + else: + return IsSDist(req) + + +def _install_build_reqs(finder, prefix, build_requirements): + # NOTE: What follows is not a very good thing. + # Eventually, this should move into the BuildEnvironment class and + # that should handle all the isolation and sub-process invocation. + finder = copy(finder) + finder.format_control = FormatControl(set(), set([":all:"])) + urls = [ + finder.find_requirement( + InstallRequirement.from_line(r), upgrade=False).url + for r in build_requirements + ] + args = [ + sys.executable, '-m', 'pip', 'install', '--ignore-installed', + '--no-user', '--prefix', prefix, + ] + list(urls) + + with open_spinner("Installing build dependencies") as spinner: + call_subprocess(args, show_stdout=False, spinner=spinner) + + +class DistAbstraction(object): + """Abstracts out the wheel vs non-wheel Resolver.resolve() logic. + + The requirements for anything installable are as follows: + - we must be able to determine the requirement name + (or we can't correctly handle the non-upgrade case). + - we must be able to generate a list of run-time dependencies + without installing any additional packages (or we would + have to either burn time by doing temporary isolated installs + or alternatively violate pips 'don't start installing unless + all requirements are available' rule - neither of which are + desirable). + - for packages with setup requirements, we must also be able + to determine their requirements without installing additional + packages (for the same reason as run-time dependencies) + - we must be able to create a Distribution object exposing the + above metadata. + """ + + def __init__(self, req): + self.req = req + + def dist(self, finder): + """Return a setuptools Dist object.""" + raise NotImplementedError(self.dist) + + def prep_for_dist(self, finder): + """Ensure that we can get a Dist for this requirement.""" + raise NotImplementedError(self.dist) + + +class IsWheel(DistAbstraction): + + def dist(self, finder): + return list(pkg_resources.find_distributions( + self.req.source_dir))[0] + + def prep_for_dist(self, finder, build_isolation): + # FIXME:https://github.com/pypa/pip/issues/1112 + pass + + +class IsSDist(DistAbstraction): + + def dist(self, finder): + dist = self.req.get_dist() + # FIXME: shouldn't be globally added. + if finder and dist.has_metadata('dependency_links.txt'): + finder.add_dependency_links( + dist.get_metadata_lines('dependency_links.txt') + ) + return dist + + def prep_for_dist(self, finder, build_isolation): + # Before calling "setup.py egg_info", we need to set-up the build + # environment. + build_requirements, isolate = self.req.get_pep_518_info() + should_isolate = build_isolation and isolate + + minimum_requirements = ('setuptools', 'wheel') + missing_requirements = set(minimum_requirements) - set( + pkg_resources.Requirement(r).key + for r in build_requirements + ) + if missing_requirements: + def format_reqs(rs): + return ' and '.join(map(repr, sorted(rs))) + logger.warning( + "Missing build time requirements in pyproject.toml for %s: " + "%s.", self.req, format_reqs(missing_requirements) + ) + logger.warning( + "This version of pip does not implement PEP 517 so it cannot " + "build a wheel without %s.", format_reqs(minimum_requirements) + ) + + if should_isolate: + with self.req.build_env: + pass + _install_build_reqs(finder, self.req.build_env.path, + build_requirements) + else: + self.req.build_env = NoOpBuildEnvironment(no_clean=False) + + self.req.run_egg_info() + self.req.assert_source_matches_version() + + +class Installed(DistAbstraction): + + def dist(self, finder): + return self.req.satisfied_by + + def prep_for_dist(self, finder): + pass + + +class RequirementPreparer(object): + """Prepares a Requirement + """ + + def __init__(self, build_dir, download_dir, src_dir, wheel_download_dir, + progress_bar, build_isolation): + super(RequirementPreparer, self).__init__() + + self.src_dir = src_dir + self.build_dir = build_dir + + # Where still packed archives should be written to. If None, they are + # not saved, and are deleted immediately after unpacking. + self.download_dir = download_dir + + # Where still-packed .whl files should be written to. If None, they are + # written to the download_dir parameter. Separate to download_dir to + # permit only keeping wheel archives for pip wheel. + if wheel_download_dir: + wheel_download_dir = normalize_path(wheel_download_dir) + self.wheel_download_dir = wheel_download_dir + + # NOTE + # download_dir and wheel_download_dir overlap semantically and may + # be combined if we're willing to have non-wheel archives present in + # the wheelhouse output by 'pip wheel'. + + self.progress_bar = progress_bar + + # Is build isolation allowed? + self.build_isolation = build_isolation + + @property + def _download_should_save(self): + # TODO: Modify to reduce indentation needed + if self.download_dir: + self.download_dir = expanduser(self.download_dir) + if os.path.exists(self.download_dir): + return True + else: + logger.critical('Could not find download directory') + raise InstallationError( + "Could not find or access download directory '%s'" + % display_path(self.download_dir)) + return False + + def prepare_linked_requirement(self, req, session, finder, + upgrade_allowed, require_hashes): + """Prepare a requirement that would be obtained from req.link + """ + # TODO: Breakup into smaller functions + if req.link and req.link.scheme == 'file': + path = url_to_path(req.link.url) + logger.info('Processing %s', display_path(path)) + else: + logger.info('Collecting %s', req) + + with indent_log(): + # @@ if filesystem packages are not marked + # editable in a req, a non deterministic error + # occurs when the script attempts to unpack the + # build directory + req.ensure_has_source_dir(self.build_dir) + # If a checkout exists, it's unwise to keep going. version + # inconsistencies are logged later, but do not fail the + # installation. + # FIXME: this won't upgrade when there's an existing + # package unpacked in `req.source_dir` + # package unpacked in `req.source_dir` + if os.path.exists(os.path.join(req.source_dir, 'setup.py')): + raise PreviousBuildDirError( + "pip can't proceed with requirements '%s' due to a" + " pre-existing build directory (%s). This is " + "likely due to a previous installation that failed" + ". pip is being responsible and not assuming it " + "can delete this. Please delete it and try again." + % (req, req.source_dir) + ) + req.populate_link(finder, upgrade_allowed, require_hashes) + + # We can't hit this spot and have populate_link return None. + # req.satisfied_by is None here (because we're + # guarded) and upgrade has no impact except when satisfied_by + # is not None. + # Then inside find_requirement existing_applicable -> False + # If no new versions are found, DistributionNotFound is raised, + # otherwise a result is guaranteed. + assert req.link + link = req.link + + # Now that we have the real link, we can tell what kind of + # requirements we have and raise some more informative errors + # than otherwise. (For example, we can raise VcsHashUnsupported + # for a VCS URL rather than HashMissing.) + if require_hashes: + # We could check these first 2 conditions inside + # unpack_url and save repetition of conditions, but then + # we would report less-useful error messages for + # unhashable requirements, complaining that there's no + # hash provided. + if is_vcs_url(link): + raise VcsHashUnsupported() + elif is_file_url(link) and is_dir_url(link): + raise DirectoryUrlHashUnsupported() + if not req.original_link and not req.is_pinned: + # Unpinned packages are asking for trouble when a new + # version is uploaded. This isn't a security check, but + # it saves users a surprising hash mismatch in the + # future. + # + # file:/// URLs aren't pinnable, so don't complain + # about them not being pinned. + raise HashUnpinned() + + hashes = req.hashes(trust_internet=not require_hashes) + if require_hashes and not hashes: + # Known-good hashes are missing for this requirement, so + # shim it with a facade object that will provoke hash + # computation and then raise a HashMissing exception + # showing the user what the hash should be. + hashes = MissingHashes() + + try: + download_dir = self.download_dir + # We always delete unpacked sdists after pip ran. + autodelete_unpacked = True + if req.link.is_wheel and self.wheel_download_dir: + # when doing 'pip wheel` we download wheels to a + # dedicated dir. + download_dir = self.wheel_download_dir + if req.link.is_wheel: + if download_dir: + # When downloading, we only unpack wheels to get + # metadata. + autodelete_unpacked = True + else: + # When installing a wheel, we use the unpacked + # wheel. + autodelete_unpacked = False + unpack_url( + req.link, req.source_dir, + download_dir, autodelete_unpacked, + session=session, hashes=hashes, + progress_bar=self.progress_bar + ) + except requests.HTTPError as exc: + logger.critical( + 'Could not install requirement %s because of error %s', + req, + exc, + ) + raise InstallationError( + 'Could not install requirement %s because of HTTP ' + 'error %s for URL %s' % + (req, exc, req.link) + ) + abstract_dist = make_abstract_dist(req) + abstract_dist.prep_for_dist(finder, self.build_isolation) + if self._download_should_save: + # Make a .zip of the source_dir we already created. + if req.link.scheme in vcs.all_schemes: + req.archive(self.download_dir) + return abstract_dist + + def prepare_editable_requirement(self, req, require_hashes, use_user_site, + finder): + """Prepare an editable requirement + """ + assert req.editable, "cannot prepare a non-editable req as editable" + + logger.info('Obtaining %s', req) + + with indent_log(): + if require_hashes: + raise InstallationError( + 'The editable requirement %s cannot be installed when ' + 'requiring hashes, because there is no single file to ' + 'hash.' % req + ) + req.ensure_has_source_dir(self.src_dir) + req.update_editable(not self._download_should_save) + + abstract_dist = make_abstract_dist(req) + abstract_dist.prep_for_dist(finder, self.build_isolation) + + if self._download_should_save: + req.archive(self.download_dir) + req.check_if_exists(use_user_site) + + return abstract_dist + + def prepare_installed_requirement(self, req, require_hashes, skip_reason): + """Prepare an already-installed requirement + """ + assert req.satisfied_by, "req should have been satisfied but isn't" + assert skip_reason is not None, ( + "did not get skip reason skipped but req.satisfied_by " + "is set to %r" % (req.satisfied_by,) + ) + logger.info( + 'Requirement %s: %s (%s)', + skip_reason, req, req.satisfied_by.version + ) + with indent_log(): + if require_hashes: + logger.debug( + 'Since it is already installed, we are trusting this ' + 'package without checking its hash. To ensure a ' + 'completely repeatable environment, install into an ' + 'empty virtualenv.' + ) + abstract_dist = Installed(req) + + return abstract_dist diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py new file mode 100755 index 0000000..5d31310 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py @@ -0,0 +1,317 @@ +"""Generate and work with PEP 425 Compatibility Tags.""" +from __future__ import absolute_import + +import distutils.util +import logging +import platform +import re +import sys +import sysconfig +import warnings +from collections import OrderedDict + +import pip._internal.utils.glibc + +logger = logging.getLogger(__name__) + +_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') + + +def get_config_var(var): + try: + return sysconfig.get_config_var(var) + except IOError as e: # Issue #1074 + warnings.warn("{}".format(e), RuntimeWarning) + return None + + +def get_abbr_impl(): + """Return abbreviated implementation name.""" + if hasattr(sys, 'pypy_version_info'): + pyimpl = 'pp' + elif sys.platform.startswith('java'): + pyimpl = 'jy' + elif sys.platform == 'cli': + pyimpl = 'ip' + else: + pyimpl = 'cp' + return pyimpl + + +def get_impl_ver(): + """Return implementation version.""" + impl_ver = get_config_var("py_version_nodot") + if not impl_ver or get_abbr_impl() == 'pp': + impl_ver = ''.join(map(str, get_impl_version_info())) + return impl_ver + + +def get_impl_version_info(): + """Return sys.version_info-like tuple for use in decrementing the minor + version.""" + if get_abbr_impl() == 'pp': + # as per https://github.com/pypa/pip/issues/2882 + return (sys.version_info[0], sys.pypy_version_info.major, + sys.pypy_version_info.minor) + else: + return sys.version_info[0], sys.version_info[1] + + +def get_impl_tag(): + """ + Returns the Tag for this specific implementation. + """ + return "{}{}".format(get_abbr_impl(), get_impl_ver()) + + +def get_flag(var, fallback, expected=True, warn=True): + """Use a fallback method for determining SOABI flags if the needed config + var is unset or unavailable.""" + val = get_config_var(var) + if val is None: + if warn: + logger.debug("Config variable '%s' is unset, Python ABI tag may " + "be incorrect", var) + return fallback() + return val == expected + + +def get_abi_tag(): + """Return the ABI tag based on SOABI (if available) or emulate SOABI + (CPython 2, PyPy).""" + soabi = get_config_var('SOABI') + impl = get_abbr_impl() + if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'): + d = '' + m = '' + u = '' + if get_flag('Py_DEBUG', + lambda: hasattr(sys, 'gettotalrefcount'), + warn=(impl == 'cp')): + d = 'd' + if get_flag('WITH_PYMALLOC', + lambda: impl == 'cp', + warn=(impl == 'cp')): + m = 'm' + if get_flag('Py_UNICODE_SIZE', + lambda: sys.maxunicode == 0x10ffff, + expected=4, + warn=(impl == 'cp' and + sys.version_info < (3, 3))) \ + and sys.version_info < (3, 3): + u = 'u' + abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u) + elif soabi and soabi.startswith('cpython-'): + abi = 'cp' + soabi.split('-')[1] + elif soabi: + abi = soabi.replace('.', '_').replace('-', '_') + else: + abi = None + return abi + + +def _is_running_32bit(): + return sys.maxsize == 2147483647 + + +def get_platform(): + """Return our platform name 'win32', 'linux_x86_64'""" + if sys.platform == 'darwin': + # distutils.util.get_platform() returns the release based on the value + # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may + # be significantly older than the user's current machine. + release, _, machine = platform.mac_ver() + split_ver = release.split('.') + + if machine == "x86_64" and _is_running_32bit(): + machine = "i386" + elif machine == "ppc64" and _is_running_32bit(): + machine = "ppc" + + return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine) + + # XXX remove distutils dependency + result = distutils.util.get_platform().replace('.', '_').replace('-', '_') + if result == "linux_x86_64" and _is_running_32bit(): + # 32 bit Python program (running on a 64 bit Linux): pip should only + # install and run 32 bit compiled extensions in that case. + result = "linux_i686" + + return result + + +def is_manylinux1_compatible(): + # Only Linux, and only x86-64 / i686 + if get_platform() not in {"linux_x86_64", "linux_i686"}: + return False + + # Check for presence of _manylinux module + try: + import _manylinux + return bool(_manylinux.manylinux1_compatible) + except (ImportError, AttributeError): + # Fall through to heuristic check below + pass + + # Check glibc version. CentOS 5 uses glibc 2.5. + return pip._internal.utils.glibc.have_compatible_glibc(2, 5) + + +def get_darwin_arches(major, minor, machine): + """Return a list of supported arches (including group arches) for + the given major, minor and machine architecture of an macOS machine. + """ + arches = [] + + def _supports_arch(major, minor, arch): + # Looking at the application support for macOS versions in the chart + # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears + # our timeline looks roughly like: + # + # 10.0 - Introduces ppc support. + # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64 + # and x86_64 support is CLI only, and cannot be used for GUI + # applications. + # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications. + # 10.6 - Drops support for ppc64 + # 10.7 - Drops support for ppc + # + # Given that we do not know if we're installing a CLI or a GUI + # application, we must be conservative and assume it might be a GUI + # application and behave as if ppc64 and x86_64 support did not occur + # until 10.5. + # + # Note: The above information is taken from the "Application support" + # column in the chart not the "Processor support" since I believe + # that we care about what instruction sets an application can use + # not which processors the OS supports. + if arch == 'ppc': + return (major, minor) <= (10, 5) + if arch == 'ppc64': + return (major, minor) == (10, 5) + if arch == 'i386': + return (major, minor) >= (10, 4) + if arch == 'x86_64': + return (major, minor) >= (10, 5) + if arch in groups: + for garch in groups[arch]: + if _supports_arch(major, minor, garch): + return True + return False + + groups = OrderedDict([ + ("fat", ("i386", "ppc")), + ("intel", ("x86_64", "i386")), + ("fat64", ("x86_64", "ppc64")), + ("fat32", ("x86_64", "i386", "ppc")), + ]) + + if _supports_arch(major, minor, machine): + arches.append(machine) + + for garch in groups: + if machine in groups[garch] and _supports_arch(major, minor, garch): + arches.append(garch) + + arches.append('universal') + + return arches + + +def get_supported(versions=None, noarch=False, platform=None, + impl=None, abi=None): + """Return a list of supported tags for each version specified in + `versions`. + + :param versions: a list of string versions, of the form ["33", "32"], + or None. The first version will be assumed to support our ABI. + :param platform: specify the exact platform you want valid + tags for, or None. If None, use the local system platform. + :param impl: specify the exact implementation you want valid + tags for, or None. If None, use the local interpreter impl. + :param abi: specify the exact abi you want valid + tags for, or None. If None, use the local interpreter abi. + """ + supported = [] + + # Versions must be given with respect to the preference + if versions is None: + versions = [] + version_info = get_impl_version_info() + major = version_info[:-1] + # Support all previous minor Python versions. + for minor in range(version_info[-1], -1, -1): + versions.append(''.join(map(str, major + (minor,)))) + + impl = impl or get_abbr_impl() + + abis = [] + + abi = abi or get_abi_tag() + if abi: + abis[0:0] = [abi] + + abi3s = set() + import imp + for suffix in imp.get_suffixes(): + if suffix[0].startswith('.abi'): + abi3s.add(suffix[0].split('.', 2)[1]) + + abis.extend(sorted(list(abi3s))) + + abis.append('none') + + if not noarch: + arch = platform or get_platform() + if arch.startswith('macosx'): + # support macosx-10.6-intel on macosx-10.9-x86_64 + match = _osx_arch_pat.match(arch) + if match: + name, major, minor, actual_arch = match.groups() + tpl = '{}_{}_%i_%s'.format(name, major) + arches = [] + for m in reversed(range(int(minor) + 1)): + for a in get_darwin_arches(int(major), m, actual_arch): + arches.append(tpl % (m, a)) + else: + # arch pattern didn't match (?!) + arches = [arch] + elif platform is None and is_manylinux1_compatible(): + arches = [arch.replace('linux', 'manylinux1'), arch] + else: + arches = [arch] + + # Current version, current API (built specifically for our Python): + for abi in abis: + for arch in arches: + supported.append(('%s%s' % (impl, versions[0]), abi, arch)) + + # abi3 modules compatible with older version of Python + for version in versions[1:]: + # abi3 was introduced in Python 3.2 + if version in {'31', '30'}: + break + for abi in abi3s: # empty set if not Python 3 + for arch in arches: + supported.append(("%s%s" % (impl, version), abi, arch)) + + # Has binaries, does not use the Python API: + for arch in arches: + supported.append(('py%s' % (versions[0][0]), 'none', arch)) + + # No abi / arch, but requires our implementation: + supported.append(('%s%s' % (impl, versions[0]), 'none', 'any')) + # Tagged specifically as being cross-version compatible + # (with just the major version specified) + supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any')) + + # No abi / arch, generic Python + for i, version in enumerate(versions): + supported.append(('py%s' % (version,), 'none', 'any')) + if i == 0: + supported.append(('py%s' % (version[0]), 'none', 'any')) + + return supported + + +implementation_tag = get_impl_tag() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py new file mode 100755 index 0000000..07ae607 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py @@ -0,0 +1,69 @@ +from __future__ import absolute_import + +import logging + +from .req_install import InstallRequirement +from .req_set import RequirementSet +from .req_file import parse_requirements +from pip._internal.utils.logging import indent_log + + +__all__ = [ + "RequirementSet", "InstallRequirement", + "parse_requirements", "install_given_reqs", +] + +logger = logging.getLogger(__name__) + + +def install_given_reqs(to_install, install_options, global_options=(), + *args, **kwargs): + """ + Install everything in the given list. + + (to be called after having downloaded and unpacked the packages) + """ + + if to_install: + logger.info( + 'Installing collected packages: %s', + ', '.join([req.name for req in to_install]), + ) + + with indent_log(): + for requirement in to_install: + if requirement.conflicts_with: + logger.info( + 'Found existing installation: %s', + requirement.conflicts_with, + ) + with indent_log(): + uninstalled_pathset = requirement.uninstall( + auto_confirm=True + ) + try: + requirement.install( + install_options, + global_options, + *args, + **kwargs + ) + except: + should_rollback = ( + requirement.conflicts_with and + not requirement.install_succeeded + ) + # if install did not succeed, rollback previous uninstall + if should_rollback: + uninstalled_pathset.rollback() + raise + else: + should_commit = ( + requirement.conflicts_with and + requirement.install_succeeded + ) + if should_commit: + uninstalled_pathset.commit() + requirement.remove_temporary_source() + + return to_install diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py new file mode 100755 index 0000000..9e6ef41 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py @@ -0,0 +1,338 @@ +""" +Requirements file parsing +""" + +from __future__ import absolute_import + +import optparse +import os +import re +import shlex +import sys + +from pip._vendor.six.moves import filterfalse +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal import cmdoptions +from pip._internal.download import get_file_content +from pip._internal.exceptions import RequirementsFileParseError +from pip._internal.req.req_install import InstallRequirement + +__all__ = ['parse_requirements'] + +SCHEME_RE = re.compile(r'^(http|https|file):', re.I) +COMMENT_RE = re.compile(r'(^|\s)+#.*$') + +# Matches environment variable-style values in '${MY_VARIABLE_1}' with the +# variable name consisting of only uppercase letters, digits or the '_' +# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, +# 2013 Edition. +ENV_VAR_RE = re.compile(r'(?P\$\{(?P[A-Z0-9_]+)\})') + +SUPPORTED_OPTIONS = [ + cmdoptions.constraints, + cmdoptions.editable, + cmdoptions.requirements, + cmdoptions.no_index, + cmdoptions.index_url, + cmdoptions.find_links, + cmdoptions.extra_index_url, + cmdoptions.always_unzip, + cmdoptions.no_binary, + cmdoptions.only_binary, + cmdoptions.pre, + cmdoptions.process_dependency_links, + cmdoptions.trusted_host, + cmdoptions.require_hashes, +] + +# options to be passed to requirements +SUPPORTED_OPTIONS_REQ = [ + cmdoptions.install_options, + cmdoptions.global_options, + cmdoptions.hash, +] + +# the 'dest' string values +SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ] + + +def parse_requirements(filename, finder=None, comes_from=None, options=None, + session=None, constraint=False, wheel_cache=None): + """Parse a requirements file and yield InstallRequirement instances. + + :param filename: Path or url of requirements file. + :param finder: Instance of pip.index.PackageFinder. + :param comes_from: Origin description of requirements. + :param options: cli options. + :param session: Instance of pip.download.PipSession. + :param constraint: If true, parsing a constraint file rather than + requirements file. + :param wheel_cache: Instance of pip.wheel.WheelCache + """ + if session is None: + raise TypeError( + "parse_requirements() missing 1 required keyword argument: " + "'session'" + ) + + _, content = get_file_content( + filename, comes_from=comes_from, session=session + ) + + lines_enum = preprocess(content, options) + + for line_number, line in lines_enum: + req_iter = process_line(line, filename, line_number, finder, + comes_from, options, session, wheel_cache, + constraint=constraint) + for req in req_iter: + yield req + + +def preprocess(content, options): + """Split, filter, and join lines, and return a line iterator + + :param content: the content of the requirements file + :param options: cli options + """ + lines_enum = enumerate(content.splitlines(), start=1) + lines_enum = join_lines(lines_enum) + lines_enum = ignore_comments(lines_enum) + lines_enum = skip_regex(lines_enum, options) + lines_enum = expand_env_variables(lines_enum) + return lines_enum + + +def process_line(line, filename, line_number, finder=None, comes_from=None, + options=None, session=None, wheel_cache=None, + constraint=False): + """Process a single requirements line; This can result in creating/yielding + requirements, or updating the finder. + + For lines that contain requirements, the only options that have an effect + are from SUPPORTED_OPTIONS_REQ, and they are scoped to the + requirement. Other options from SUPPORTED_OPTIONS may be present, but are + ignored. + + For lines that do not contain requirements, the only options that have an + effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may + be present, but are ignored. These lines may contain multiple options + (although our docs imply only one is supported), and all our parsed and + affect the finder. + + :param constraint: If True, parsing a constraints file. + :param options: OptionParser options that we may update + """ + parser = build_parser(line) + defaults = parser.get_default_values() + defaults.index_url = None + if finder: + # `finder.format_control` will be updated during parsing + defaults.format_control = finder.format_control + args_str, options_str = break_args_options(line) + if sys.version_info < (2, 7, 3): + # Prior to 2.7.3, shlex cannot deal with unicode entries + options_str = options_str.encode('utf8') + opts, _ = parser.parse_args(shlex.split(options_str), defaults) + + # preserve for the nested code path + line_comes_from = '%s %s (line %s)' % ( + '-c' if constraint else '-r', filename, line_number, + ) + + # yield a line requirement + if args_str: + isolated = options.isolated_mode if options else False + if options: + cmdoptions.check_install_build_global(options, opts) + # get the options that apply to requirements + req_options = {} + for dest in SUPPORTED_OPTIONS_REQ_DEST: + if dest in opts.__dict__ and opts.__dict__[dest]: + req_options[dest] = opts.__dict__[dest] + yield InstallRequirement.from_line( + args_str, line_comes_from, constraint=constraint, + isolated=isolated, options=req_options, wheel_cache=wheel_cache + ) + + # yield an editable requirement + elif opts.editables: + isolated = options.isolated_mode if options else False + yield InstallRequirement.from_editable( + opts.editables[0], comes_from=line_comes_from, + constraint=constraint, isolated=isolated, wheel_cache=wheel_cache + ) + + # parse a nested requirements file + elif opts.requirements or opts.constraints: + if opts.requirements: + req_path = opts.requirements[0] + nested_constraint = False + else: + req_path = opts.constraints[0] + nested_constraint = True + # original file is over http + if SCHEME_RE.search(filename): + # do a url join so relative paths work + req_path = urllib_parse.urljoin(filename, req_path) + # original file and nested file are paths + elif not SCHEME_RE.search(req_path): + # do a join so relative paths work + req_path = os.path.join(os.path.dirname(filename), req_path) + # TODO: Why not use `comes_from='-r {} (line {})'` here as well? + parser = parse_requirements( + req_path, finder, comes_from, options, session, + constraint=nested_constraint, wheel_cache=wheel_cache + ) + for req in parser: + yield req + + # percolate hash-checking option upward + elif opts.require_hashes: + options.require_hashes = opts.require_hashes + + # set finder options + elif finder: + if opts.index_url: + finder.index_urls = [opts.index_url] + if opts.no_index is True: + finder.index_urls = [] + if opts.extra_index_urls: + finder.index_urls.extend(opts.extra_index_urls) + if opts.find_links: + # FIXME: it would be nice to keep track of the source + # of the find_links: support a find-links local path + # relative to a requirements file. + value = opts.find_links[0] + req_dir = os.path.dirname(os.path.abspath(filename)) + relative_to_reqs_file = os.path.join(req_dir, value) + if os.path.exists(relative_to_reqs_file): + value = relative_to_reqs_file + finder.find_links.append(value) + if opts.pre: + finder.allow_all_prereleases = True + if opts.process_dependency_links: + finder.process_dependency_links = True + if opts.trusted_hosts: + finder.secure_origins.extend( + ("*", host, "*") for host in opts.trusted_hosts) + + +def break_args_options(line): + """Break up the line into an args and options string. We only want to shlex + (and then optparse) the options, not the args. args can contain markers + which are corrupted by shlex. + """ + tokens = line.split(' ') + args = [] + options = tokens[:] + for token in tokens: + if token.startswith('-') or token.startswith('--'): + break + else: + args.append(token) + options.pop(0) + return ' '.join(args), ' '.join(options) + + +def build_parser(line): + """ + Return a parser for parsing requirement lines + """ + parser = optparse.OptionParser(add_help_option=False) + + option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ + for option_factory in option_factories: + option = option_factory() + parser.add_option(option) + + # By default optparse sys.exits on parsing errors. We want to wrap + # that in our own exception. + def parser_exit(self, msg): + # add offending line + msg = 'Invalid requirement: %s\n%s' % (line, msg) + raise RequirementsFileParseError(msg) + parser.exit = parser_exit + + return parser + + +def join_lines(lines_enum): + """Joins a line ending in '\' with the previous line (except when following + comments). The joined line takes on the index of the first line. + """ + primary_line_number = None + new_line = [] + for line_number, line in lines_enum: + if not line.endswith('\\') or COMMENT_RE.match(line): + if COMMENT_RE.match(line): + # this ensures comments are always matched later + line = ' ' + line + if new_line: + new_line.append(line) + yield primary_line_number, ''.join(new_line) + new_line = [] + else: + yield line_number, line + else: + if not new_line: + primary_line_number = line_number + new_line.append(line.strip('\\')) + + # last line contains \ + if new_line: + yield primary_line_number, ''.join(new_line) + + # TODO: handle space after '\'. + + +def ignore_comments(lines_enum): + """ + Strips comments and filter empty lines. + """ + for line_number, line in lines_enum: + line = COMMENT_RE.sub('', line) + line = line.strip() + if line: + yield line_number, line + + +def skip_regex(lines_enum, options): + """ + Skip lines that match '--skip-requirements-regex' pattern + + Note: the regex pattern is only built once + """ + skip_regex = options.skip_requirements_regex if options else None + if skip_regex: + pattern = re.compile(skip_regex) + lines_enum = filterfalse(lambda e: pattern.search(e[1]), lines_enum) + return lines_enum + + +def expand_env_variables(lines_enum): + """Replace all environment variables that can be retrieved via `os.getenv`. + + The only allowed format for environment variables defined in the + requirement file is `${MY_VARIABLE_1}` to ensure two things: + + 1. Strings that contain a `$` aren't accidentally (partially) expanded. + 2. Ensure consistency across platforms for requirement files. + + These points are the result of a discusssion on the `github pull + request #3514 `_. + + Valid characters in variable names follow the `POSIX standard + `_ and are limited + to uppercase letter, digits and the `_` (underscore). + """ + for line_number, line in lines_enum: + for env_var, var_name in ENV_VAR_RE.findall(line): + value = os.getenv(var_name) + if not value: + continue + + line = line.replace(env_var, value) + + yield line_number, line diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py new file mode 100755 index 0000000..9dd1523 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py @@ -0,0 +1,1115 @@ +from __future__ import absolute_import + +import logging +import os +import re +import shutil +import sys +import sysconfig +import traceback +import warnings +import zipfile +from distutils.util import change_root +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources, pytoml, six +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.markers import Marker +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.packaging.version import Version +from pip._vendor.pkg_resources import RequirementParseError, parse_requirements + +from pip._internal import wheel +from pip._internal.build_env import BuildEnvironment +from pip._internal.compat import native_str +from pip._internal.download import ( + is_archive_file, is_url, path_to_url, url_to_path, +) +from pip._internal.exceptions import InstallationError, UninstallationError +from pip._internal.locations import ( + PIP_DELETE_MARKER_FILENAME, running_under_virtualenv, +) +from pip._internal.req.req_uninstall import UninstallPathSet +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + _make_build_dir, ask_path_exists, backup_dir, call_subprocess, + display_path, dist_in_site_packages, dist_in_usersite, ensure_dir, + get_installed_version, is_installable_dir, read_text_file, rmtree, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.ui import open_spinner +from pip._internal.vcs import vcs +from pip._internal.wheel import Wheel, move_wheel_files + +logger = logging.getLogger(__name__) + +operators = specifiers.Specifier._operators.keys() + + +def _strip_extras(path): + m = re.match(r'^(.+)(\[[^\]]+\])$', path) + extras = None + if m: + path_no_extras = m.group(1) + extras = m.group(2) + else: + path_no_extras = path + + return path_no_extras, extras + + +class InstallRequirement(object): + """ + Represents something that may be installed later on, may have information + about where to fetch the relavant requirement and also contains logic for + installing the said requirement. + """ + + def __init__(self, req, comes_from, source_dir=None, editable=False, + link=None, update=True, markers=None, + isolated=False, options=None, wheel_cache=None, + constraint=False, extras=()): + assert req is None or isinstance(req, Requirement), req + self.req = req + self.comes_from = comes_from + self.constraint = constraint + if source_dir is not None: + self.source_dir = os.path.normpath(os.path.abspath(source_dir)) + else: + self.source_dir = None + self.editable = editable + + self._wheel_cache = wheel_cache + if link is not None: + self.link = self.original_link = link + else: + from pip._internal.index import Link + self.link = self.original_link = req and req.url and Link(req.url) + + if extras: + self.extras = extras + elif req: + self.extras = { + pkg_resources.safe_extra(extra) for extra in req.extras + } + else: + self.extras = set() + if markers is not None: + self.markers = markers + else: + self.markers = req and req.marker + self._egg_info_path = None + # This holds the pkg_resources.Distribution object if this requirement + # is already available: + self.satisfied_by = None + # This hold the pkg_resources.Distribution object if this requirement + # conflicts with another installed distribution: + self.conflicts_with = None + # Temporary build location + self._temp_build_dir = TempDirectory(kind="req-build") + # Used to store the global directory where the _temp_build_dir should + # have been created. Cf _correct_build_location method. + self._ideal_build_dir = None + # True if the editable should be updated: + self.update = update + # Set to True after successful installation + self.install_succeeded = None + # UninstallPathSet of uninstalled distribution (for possible rollback) + self.uninstalled_pathset = None + self.options = options if options else {} + # Set to True after successful preparation of this requirement + self.prepared = False + self.is_direct = False + + self.isolated = isolated + self.build_env = BuildEnvironment(no_clean=True) + + @classmethod + def from_editable(cls, editable_req, comes_from=None, isolated=False, + options=None, wheel_cache=None, constraint=False): + from pip._internal.index import Link + + name, url, extras_override = parse_editable(editable_req) + if url.startswith('file:'): + source_dir = url_to_path(url) + else: + source_dir = None + + if name is not None: + try: + req = Requirement(name) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '%s'" % name) + else: + req = None + return cls( + req, comes_from, source_dir=source_dir, + editable=True, + link=Link(url), + constraint=constraint, + isolated=isolated, + options=options if options else {}, + wheel_cache=wheel_cache, + extras=extras_override or (), + ) + + @classmethod + def from_req(cls, req, comes_from=None, isolated=False, wheel_cache=None): + try: + req = Requirement(req) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '%s'" % req) + if req.url: + raise InstallationError( + "Direct url requirement (like %s) are not allowed for " + "dependencies" % req + ) + return cls(req, comes_from, isolated=isolated, wheel_cache=wheel_cache) + + @classmethod + def from_line( + cls, name, comes_from=None, isolated=False, options=None, + wheel_cache=None, constraint=False): + """Creates an InstallRequirement from a name, which might be a + requirement, directory containing 'setup.py', filename, or URL. + """ + from pip._internal.index import Link + + if is_url(name): + marker_sep = '; ' + else: + marker_sep = ';' + if marker_sep in name: + name, markers = name.split(marker_sep, 1) + markers = markers.strip() + if not markers: + markers = None + else: + markers = Marker(markers) + else: + markers = None + name = name.strip() + req = None + path = os.path.normpath(os.path.abspath(name)) + link = None + extras = None + + if is_url(name): + link = Link(name) + else: + p, extras = _strip_extras(path) + looks_like_dir = os.path.isdir(p) and ( + os.path.sep in name or + (os.path.altsep is not None and os.path.altsep in name) or + name.startswith('.') + ) + if looks_like_dir: + if not is_installable_dir(p): + raise InstallationError( + "Directory %r is not installable. File 'setup.py' " + "not found." % name + ) + link = Link(path_to_url(p)) + elif is_archive_file(p): + if not os.path.isfile(p): + logger.warning( + 'Requirement %r looks like a filename, but the ' + 'file does not exist', + name + ) + link = Link(path_to_url(p)) + + # it's a local file, dir, or url + if link: + # Handle relative file URLs + if link.scheme == 'file' and re.search(r'\.\./', link.url): + link = Link( + path_to_url(os.path.normpath(os.path.abspath(link.path)))) + # wheel file + if link.is_wheel: + wheel = Wheel(link.filename) # can raise InvalidWheelFilename + req = "%s==%s" % (wheel.name, wheel.version) + else: + # set the req to the egg fragment. when it's not there, this + # will become an 'unnamed' requirement + req = link.egg_fragment + + # a requirement specifier + else: + req = name + + if extras: + extras = Requirement("placeholder" + extras.lower()).extras + else: + extras = () + if req is not None: + try: + req = Requirement(req) + except InvalidRequirement: + if os.path.sep in req: + add_msg = "It looks like a path." + add_msg += deduce_helpful_msg(req) + elif '=' in req and not any(op in req for op in operators): + add_msg = "= is not a valid operator. Did you mean == ?" + else: + add_msg = traceback.format_exc() + raise InstallationError( + "Invalid requirement: '%s'\n%s" % (req, add_msg)) + return cls( + req, comes_from, link=link, markers=markers, + isolated=isolated, + options=options if options else {}, + wheel_cache=wheel_cache, + constraint=constraint, + extras=extras, + ) + + def __str__(self): + if self.req: + s = str(self.req) + if self.link: + s += ' from %s' % self.link.url + else: + s = self.link.url if self.link else None + if self.satisfied_by is not None: + s += ' in %s' % display_path(self.satisfied_by.location) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += ' (from %s)' % comes_from + return s + + def __repr__(self): + return '<%s object: %s editable=%r>' % ( + self.__class__.__name__, str(self), self.editable) + + def populate_link(self, finder, upgrade, require_hashes): + """Ensure that if a link can be found for this, that it is found. + + Note that self.link may still be None - if Upgrade is False and the + requirement is already installed. + + If require_hashes is True, don't use the wheel cache, because cached + wheels, always built locally, have different hashes than the files + downloaded from the index server and thus throw false hash mismatches. + Furthermore, cached wheels at present have undeterministic contents due + to file modification times. + """ + if self.link is None: + self.link = finder.find_requirement(self, upgrade) + if self._wheel_cache is not None and not require_hashes: + old_link = self.link + self.link = self._wheel_cache.get(self.link, self.name) + if old_link != self.link: + logger.debug('Using cached wheel link: %s', self.link) + + @property + def specifier(self): + return self.req.specifier + + @property + def is_pinned(self): + """Return whether I am pinned to an exact version. + + For example, some-package==1.2 is pinned; some-package>1.2 is not. + """ + specifiers = self.specifier + return (len(specifiers) == 1 and + next(iter(specifiers)).operator in {'==', '==='}) + + def from_path(self): + if self.req is None: + return None + s = str(self.req) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += '->' + comes_from + return s + + def build_location(self, build_dir): + assert build_dir is not None + if self._temp_build_dir.path is not None: + return self._temp_build_dir.path + if self.req is None: + # for requirement via a path to a directory: the name of the + # package is not available yet so we create a temp directory + # Once run_egg_info will have run, we'll be able + # to fix it via _correct_build_location + # Some systems have /tmp as a symlink which confuses custom + # builds (such as numpy). Thus, we ensure that the real path + # is returned. + self._temp_build_dir.create() + self._ideal_build_dir = build_dir + + return self._temp_build_dir.path + if self.editable: + name = self.name.lower() + else: + name = self.name + # FIXME: Is there a better place to create the build_dir? (hg and bzr + # need this) + if not os.path.exists(build_dir): + logger.debug('Creating directory %s', build_dir) + _make_build_dir(build_dir) + return os.path.join(build_dir, name) + + def _correct_build_location(self): + """Move self._temp_build_dir to self._ideal_build_dir/self.req.name + + For some requirements (e.g. a path to a directory), the name of the + package is not available until we run egg_info, so the build_location + will return a temporary directory and store the _ideal_build_dir. + + This is only called by self.egg_info_path to fix the temporary build + directory. + """ + if self.source_dir is not None: + return + assert self.req is not None + assert self._temp_build_dir.path + assert self._ideal_build_dir.path + old_location = self._temp_build_dir.path + self._temp_build_dir.path = None + + new_location = self.build_location(self._ideal_build_dir) + if os.path.exists(new_location): + raise InstallationError( + 'A package already exists in %s; please remove it to continue' + % display_path(new_location)) + logger.debug( + 'Moving package %s from %s to new location %s', + self, display_path(old_location), display_path(new_location), + ) + shutil.move(old_location, new_location) + self._temp_build_dir.path = new_location + self._ideal_build_dir = None + self.source_dir = os.path.normpath(os.path.abspath(new_location)) + self._egg_info_path = None + + @property + def name(self): + if self.req is None: + return None + return native_str(pkg_resources.safe_name(self.req.name)) + + @property + def setup_py_dir(self): + return os.path.join( + self.source_dir, + self.link and self.link.subdirectory_fragment or '') + + @property + def setup_py(self): + assert self.source_dir, "No source dir for %s" % self + + setup_py = os.path.join(self.setup_py_dir, 'setup.py') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(setup_py, six.text_type): + setup_py = setup_py.encode(sys.getfilesystemencoding()) + + return setup_py + + @property + def pyproject_toml(self): + assert self.source_dir, "No source dir for %s" % self + + pp_toml = os.path.join(self.setup_py_dir, 'pyproject.toml') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(pp_toml, six.text_type): + pp_toml = pp_toml.encode(sys.getfilesystemencoding()) + + return pp_toml + + def get_pep_518_info(self): + """Get a list of the packages required to build the project, if any, + and a flag indicating whether pyproject.toml is present, indicating + that the build should be isolated. + + Build requirements can be specified in a pyproject.toml, as described + in PEP 518. If this file exists but doesn't specify build + requirements, pip will default to installing setuptools and wheel. + """ + if os.path.isfile(self.pyproject_toml): + with open(self.pyproject_toml) as f: + pp_toml = pytoml.load(f) + build_sys = pp_toml.get('build-system', {}) + return (build_sys.get('requires', ['setuptools', 'wheel']), True) + return (['setuptools', 'wheel'], False) + + def run_egg_info(self): + assert self.source_dir + if self.name: + logger.debug( + 'Running setup.py (path:%s) egg_info for package %s', + self.setup_py, self.name, + ) + else: + logger.debug( + 'Running setup.py (path:%s) egg_info for package from %s', + self.setup_py, self.link, + ) + + with indent_log(): + script = SETUPTOOLS_SHIM % self.setup_py + base_cmd = [sys.executable, '-c', script] + if self.isolated: + base_cmd += ["--no-user-cfg"] + egg_info_cmd = base_cmd + ['egg_info'] + # We can't put the .egg-info files at the root, because then the + # source code will be mistaken for an installed egg, causing + # problems + if self.editable: + egg_base_option = [] + else: + egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') + ensure_dir(egg_info_dir) + egg_base_option = ['--egg-base', 'pip-egg-info'] + with self.build_env: + call_subprocess( + egg_info_cmd + egg_base_option, + cwd=self.setup_py_dir, + show_stdout=False, + command_desc='python setup.py egg_info') + + if not self.req: + if isinstance(parse_version(self.pkg_info()["Version"]), Version): + op = "==" + else: + op = "===" + self.req = Requirement( + "".join([ + self.pkg_info()["Name"], + op, + self.pkg_info()["Version"], + ]) + ) + self._correct_build_location() + else: + metadata_name = canonicalize_name(self.pkg_info()["Name"]) + if canonicalize_name(self.req.name) != metadata_name: + logger.warning( + 'Running setup.py (path:%s) egg_info for package %s ' + 'produced metadata for project name %s. Fix your ' + '#egg=%s fragments.', + self.setup_py, self.name, metadata_name, self.name + ) + self.req = Requirement(metadata_name) + + def egg_info_data(self, filename): + if self.satisfied_by is not None: + if not self.satisfied_by.has_metadata(filename): + return None + return self.satisfied_by.get_metadata(filename) + assert self.source_dir + filename = self.egg_info_path(filename) + if not os.path.exists(filename): + return None + data = read_text_file(filename) + return data + + def egg_info_path(self, filename): + if self._egg_info_path is None: + if self.editable: + base = self.source_dir + else: + base = os.path.join(self.setup_py_dir, 'pip-egg-info') + filenames = os.listdir(base) + if self.editable: + filenames = [] + for root, dirs, files in os.walk(base): + for dir in vcs.dirnames: + if dir in dirs: + dirs.remove(dir) + # Iterate over a copy of ``dirs``, since mutating + # a list while iterating over it can cause trouble. + # (See https://github.com/pypa/pip/pull/462.) + for dir in list(dirs): + # Don't search in anything that looks like a virtualenv + # environment + if ( + os.path.lexists( + os.path.join(root, dir, 'bin', 'python') + ) or + os.path.exists( + os.path.join( + root, dir, 'Scripts', 'Python.exe' + ) + )): + dirs.remove(dir) + # Also don't search through tests + elif dir == 'test' or dir == 'tests': + dirs.remove(dir) + filenames.extend([os.path.join(root, dir) + for dir in dirs]) + filenames = [f for f in filenames if f.endswith('.egg-info')] + + if not filenames: + raise InstallationError( + 'No files/directories in %s (from %s)' % (base, filename) + ) + assert filenames, \ + "No files/directories in %s (from %s)" % (base, filename) + + # if we have more than one match, we pick the toplevel one. This + # can easily be the case if there is a dist folder which contains + # an extracted tarball for testing purposes. + if len(filenames) > 1: + filenames.sort( + key=lambda x: x.count(os.path.sep) + + (os.path.altsep and x.count(os.path.altsep) or 0) + ) + self._egg_info_path = os.path.join(base, filenames[0]) + return os.path.join(self._egg_info_path, filename) + + def pkg_info(self): + p = FeedParser() + data = self.egg_info_data('PKG-INFO') + if not data: + logger.warning( + 'No PKG-INFO file found in %s', + display_path(self.egg_info_path('PKG-INFO')), + ) + p.feed(data or '') + return p.close() + + _requirements_section_re = re.compile(r'\[(.*?)\]') + + @property + def installed_version(self): + return get_installed_version(self.name) + + def assert_source_matches_version(self): + assert self.source_dir + version = self.pkg_info()['version'] + if self.req.specifier and version not in self.req.specifier: + logger.warning( + 'Requested %s, but installing version %s', + self, + version, + ) + else: + logger.debug( + 'Source in %s has version %s, which satisfies requirement %s', + display_path(self.source_dir), + version, + self, + ) + + def update_editable(self, obtain=True): + if not self.link: + logger.debug( + "Cannot update repository at %s; repository location is " + "unknown", + self.source_dir, + ) + return + assert self.editable + assert self.source_dir + if self.link.scheme == 'file': + # Static paths don't get updated + return + assert '+' in self.link.url, "bad url: %r" % self.link.url + if not self.update: + return + vc_type, url = self.link.url.split('+', 1) + backend = vcs.get_backend(vc_type) + if backend: + vcs_backend = backend(self.link.url) + if obtain: + vcs_backend.obtain(self.source_dir) + else: + vcs_backend.export(self.source_dir) + else: + assert 0, ( + 'Unexpected version control type (in %s): %s' + % (self.link, vc_type)) + + def uninstall(self, auto_confirm=False, verbose=False, + use_user_site=False): + """ + Uninstall the distribution currently satisfying this requirement. + + Prompts before removing or modifying files unless + ``auto_confirm`` is True. + + Refuses to delete or modify files outside of ``sys.prefix`` - + thus uninstallation within a virtual environment can only + modify that virtual environment, even if the virtualenv is + linked to global site-packages. + + """ + if not self.check_if_exists(use_user_site): + logger.warning("Skipping %s as it is not installed.", self.name) + return + dist = self.satisfied_by or self.conflicts_with + + uninstalled_pathset = UninstallPathSet.from_dist(dist) + uninstalled_pathset.remove(auto_confirm, verbose) + return uninstalled_pathset + + def archive(self, build_dir): + assert self.source_dir + create_archive = True + archive_name = '%s-%s.zip' % (self.name, self.pkg_info()["version"]) + archive_path = os.path.join(build_dir, archive_name) + if os.path.exists(archive_path): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' % + display_path(archive_path), ('i', 'w', 'b', 'a')) + if response == 'i': + create_archive = False + elif response == 'w': + logger.warning('Deleting %s', display_path(archive_path)) + os.remove(archive_path) + elif response == 'b': + dest_file = backup_dir(archive_path) + logger.warning( + 'Backing up %s to %s', + display_path(archive_path), + display_path(dest_file), + ) + shutil.move(archive_path, dest_file) + elif response == 'a': + sys.exit(-1) + if create_archive: + zip = zipfile.ZipFile( + archive_path, 'w', zipfile.ZIP_DEFLATED, + allowZip64=True + ) + dir = os.path.normcase(os.path.abspath(self.setup_py_dir)) + for dirpath, dirnames, filenames in os.walk(dir): + if 'pip-egg-info' in dirnames: + dirnames.remove('pip-egg-info') + for dirname in dirnames: + dirname = os.path.join(dirpath, dirname) + name = self._clean_zip_name(dirname, dir) + zipdir = zipfile.ZipInfo(self.name + '/' + name + '/') + zipdir.external_attr = 0x1ED << 16 # 0o755 + zip.writestr(zipdir, '') + for filename in filenames: + if filename == PIP_DELETE_MARKER_FILENAME: + continue + filename = os.path.join(dirpath, filename) + name = self._clean_zip_name(filename, dir) + zip.write(filename, self.name + '/' + name) + zip.close() + logger.info('Saved %s', display_path(archive_path)) + + def _clean_zip_name(self, name, prefix): + assert name.startswith(prefix + os.path.sep), ( + "name %r doesn't start with prefix %r" % (name, prefix) + ) + name = name[len(prefix) + 1:] + name = name.replace(os.path.sep, '/') + return name + + def match_markers(self, extras_requested=None): + if not extras_requested: + # Provide an extra to safely evaluate the markers + # without matching any extra + extras_requested = ('',) + if self.markers is not None: + return any( + self.markers.evaluate({'extra': extra}) + for extra in extras_requested) + else: + return True + + def install(self, install_options, global_options=None, root=None, + home=None, prefix=None, warn_script_location=True, + use_user_site=False, pycompile=True): + global_options = global_options if global_options is not None else [] + if self.editable: + self.install_editable( + install_options, global_options, prefix=prefix, + ) + return + if self.is_wheel: + version = wheel.wheel_version(self.source_dir) + wheel.check_compatibility(version, self.name) + + self.move_wheel_files( + self.source_dir, root=root, prefix=prefix, home=home, + warn_script_location=warn_script_location, + use_user_site=use_user_site, pycompile=pycompile, + ) + self.install_succeeded = True + return + + # Extend the list of global and install options passed on to + # the setup.py call with the ones from the requirements file. + # Options specified in requirements file override those + # specified on the command line, since the last option given + # to setup.py is the one that is used. + global_options = list(global_options) + \ + self.options.get('global_options', []) + install_options = list(install_options) + \ + self.options.get('install_options', []) + + if self.isolated: + global_options = global_options + ["--no-user-cfg"] + + with TempDirectory(kind="record") as temp_dir: + record_filename = os.path.join(temp_dir.path, 'install-record.txt') + install_args = self.get_install_args( + global_options, record_filename, root, prefix, pycompile, + ) + msg = 'Running setup.py install for %s' % (self.name,) + with open_spinner(msg) as spinner: + with indent_log(): + with self.build_env: + call_subprocess( + install_args + install_options, + cwd=self.setup_py_dir, + show_stdout=False, + spinner=spinner, + ) + + if not os.path.exists(record_filename): + logger.debug('Record file %s not found', record_filename) + return + self.install_succeeded = True + + def prepend_root(path): + if root is None or not os.path.isabs(path): + return path + else: + return change_root(root, path) + + with open(record_filename) as f: + for line in f: + directory = os.path.dirname(line) + if directory.endswith('.egg-info'): + egg_info_dir = prepend_root(directory) + break + else: + logger.warning( + 'Could not find .egg-info directory in install record' + ' for %s', + self, + ) + # FIXME: put the record somewhere + # FIXME: should this be an error? + return + new_lines = [] + with open(record_filename) as f: + for line in f: + filename = line.strip() + if os.path.isdir(filename): + filename += os.path.sep + new_lines.append( + os.path.relpath(prepend_root(filename), egg_info_dir) + ) + new_lines.sort() + ensure_dir(egg_info_dir) + inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') + with open(inst_files_path, 'w') as f: + f.write('\n'.join(new_lines) + '\n') + + def ensure_has_source_dir(self, parent_dir): + """Ensure that a source_dir is set. + + This will create a temporary build dir if the name of the requirement + isn't known yet. + + :param parent_dir: The ideal pip parent_dir for the source_dir. + Generally src_dir for editables and build_dir for sdists. + :return: self.source_dir + """ + if self.source_dir is None: + self.source_dir = self.build_location(parent_dir) + return self.source_dir + + def get_install_args(self, global_options, record_filename, root, prefix, + pycompile): + install_args = [sys.executable, "-u"] + install_args.append('-c') + install_args.append(SETUPTOOLS_SHIM % self.setup_py) + install_args += list(global_options) + \ + ['install', '--record', record_filename] + install_args += ['--single-version-externally-managed'] + + if root is not None: + install_args += ['--root', root] + if prefix is not None: + install_args += ['--prefix', prefix] + + if pycompile: + install_args += ["--compile"] + else: + install_args += ["--no-compile"] + + if running_under_virtualenv(): + py_ver_str = 'python' + sysconfig.get_python_version() + install_args += ['--install-headers', + os.path.join(sys.prefix, 'include', 'site', + py_ver_str, self.name)] + + return install_args + + def remove_temporary_source(self): + """Remove the source files from this requirement, if they are marked + for deletion""" + if self.source_dir and os.path.exists( + os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)): + logger.debug('Removing source in %s', self.source_dir) + rmtree(self.source_dir) + self.source_dir = None + self._temp_build_dir.cleanup() + self.build_env.cleanup() + + def install_editable(self, install_options, + global_options=(), prefix=None): + logger.info('Running setup.py develop for %s', self.name) + + if self.isolated: + global_options = list(global_options) + ["--no-user-cfg"] + + if prefix: + prefix_param = ['--prefix={}'.format(prefix)] + install_options = list(install_options) + prefix_param + + with indent_log(): + # FIXME: should we do --install-headers here too? + with self.build_env: + call_subprocess( + [ + sys.executable, + '-c', + SETUPTOOLS_SHIM % self.setup_py + ] + + list(global_options) + + ['develop', '--no-deps'] + + list(install_options), + + cwd=self.setup_py_dir, + show_stdout=False, + ) + + self.install_succeeded = True + + def check_if_exists(self, use_user_site): + """Find an installed distribution that satisfies or conflicts + with this requirement, and set self.satisfied_by or + self.conflicts_with appropriately. + """ + if self.req is None: + return False + try: + # get_distribution() will resolve the entire list of requirements + # anyway, and we've already determined that we need the requirement + # in question, so strip the marker so that we don't try to + # evaluate it. + no_marker = Requirement(str(self.req)) + no_marker.marker = None + self.satisfied_by = pkg_resources.get_distribution(str(no_marker)) + if self.editable and self.satisfied_by: + self.conflicts_with = self.satisfied_by + # when installing editables, nothing pre-existing should ever + # satisfy + self.satisfied_by = None + return True + except pkg_resources.DistributionNotFound: + return False + except pkg_resources.VersionConflict: + existing_dist = pkg_resources.get_distribution( + self.req.name + ) + if use_user_site: + if dist_in_usersite(existing_dist): + self.conflicts_with = existing_dist + elif (running_under_virtualenv() and + dist_in_site_packages(existing_dist)): + raise InstallationError( + "Will not install to the user site because it will " + "lack sys.path precedence to %s in %s" % + (existing_dist.project_name, existing_dist.location) + ) + else: + self.conflicts_with = existing_dist + return True + + @property + def is_wheel(self): + return self.link and self.link.is_wheel + + def move_wheel_files(self, wheeldir, root=None, home=None, prefix=None, + warn_script_location=True, use_user_site=False, + pycompile=True): + move_wheel_files( + self.name, self.req, wheeldir, + user=use_user_site, + home=home, + root=root, + prefix=prefix, + pycompile=pycompile, + isolated=self.isolated, + warn_script_location=warn_script_location, + ) + + def get_dist(self): + """Return a pkg_resources.Distribution built from self.egg_info_path""" + egg_info = self.egg_info_path('').rstrip(os.path.sep) + base_dir = os.path.dirname(egg_info) + metadata = pkg_resources.PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + return pkg_resources.Distribution( + os.path.dirname(egg_info), + project_name=dist_name, + metadata=metadata, + ) + + @property + def has_hash_options(self): + """Return whether any known-good hashes are specified as options. + + These activate --require-hashes mode; hashes specified as part of a + URL do not. + + """ + return bool(self.options.get('hashes', {})) + + def hashes(self, trust_internet=True): + """Return a hash-comparer that considers my option- and URL-based + hashes to be known-good. + + Hashes in URLs--ones embedded in the requirements file, not ones + downloaded from an index server--are almost peers with ones from + flags. They satisfy --require-hashes (whether it was implicitly or + explicitly activated) but do not activate it. md5 and sha224 are not + allowed in flags, which should nudge people toward good algos. We + always OR all hashes together, even ones from URLs. + + :param trust_internet: Whether to trust URL-based (#md5=...) hashes + downloaded from the internet, as by populate_link() + + """ + good_hashes = self.options.get('hashes', {}).copy() + link = self.link if trust_internet else self.original_link + if link and link.hash: + good_hashes.setdefault(link.hash_name, []).append(link.hash) + return Hashes(good_hashes) + + +def _strip_postfix(req): + """ + Strip req postfix ( -dev, 0.2, etc ) + """ + # FIXME: use package_to_requirement? + match = re.search(r'^(.*?)(?:-dev|-\d.*)$', req) + if match: + # Strip off -dev, -0.2, etc. + warnings.warn( + "#egg cleanup for editable urls will be dropped in the future", + RemovedInPip11Warning, + ) + req = match.group(1) + return req + + +def parse_editable(editable_req): + """Parses an editable requirement into: + - a requirement name + - an URL + - extras + - editable options + Accepted requirements: + svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir + .[some_extra] + """ + + from pip._internal.index import Link + + url = editable_req + + # If a file path is specified with extras, strip off the extras. + url_no_extras, extras = _strip_extras(url) + + if os.path.isdir(url_no_extras): + if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): + raise InstallationError( + "Directory %r is not installable. File 'setup.py' not found." % + url_no_extras + ) + # Treating it as code that has already been checked out + url_no_extras = path_to_url(url_no_extras) + + if url_no_extras.lower().startswith('file:'): + package_name = Link(url_no_extras).egg_fragment + if extras: + return ( + package_name, + url_no_extras, + Requirement("placeholder" + extras.lower()).extras, + ) + else: + return package_name, url_no_extras, None + + for version_control in vcs: + if url.lower().startswith('%s:' % version_control): + url = '%s+%s' % (version_control, url) + break + + if '+' not in url: + raise InstallationError( + '%s should either be a path to a local project or a VCS url ' + 'beginning with svn+, git+, hg+, or bzr+' % + editable_req + ) + + vc_type = url.split('+', 1)[0].lower() + + if not vcs.get_backend(vc_type): + error_message = 'For --editable=%s only ' % editable_req + \ + ', '.join([backend.name + '+URL' for backend in vcs.backends]) + \ + ' is currently supported' + raise InstallationError(error_message) + + package_name = Link(url).egg_fragment + if not package_name: + raise InstallationError( + "Could not detect requirement name for '%s', please specify one " + "with #egg=your_package_name" % editable_req + ) + return _strip_postfix(package_name), url, None + + +def deduce_helpful_msg(req): + """Returns helpful msg in case requirements file does not exist, + or cannot be parsed. + + :params req: Requirements file path + """ + msg = "" + if os.path.exists(req): + msg = " It does exist." + # Try to parse and check if it is a requirements file. + try: + with open(req, 'r') as fp: + # parse first line only + next(parse_requirements(fp.read())) + msg += " The argument you provided " + \ + "(%s) appears to be a" % (req) + \ + " requirements file. If that is the" + \ + " case, use the '-r' flag to install" + \ + " the packages specified within it." + except RequirementParseError: + logger.debug("Cannot parse '%s' as requirements \ + file" % (req), exc_info=1) + else: + msg += " File '%s' does not exist." % (req) + return msg diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py new file mode 100755 index 0000000..78b7d32 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py @@ -0,0 +1,164 @@ +from __future__ import absolute_import + +import logging +from collections import OrderedDict + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.logging import indent_log +from pip._internal.wheel import Wheel + +logger = logging.getLogger(__name__) + + +class RequirementSet(object): + + def __init__(self, require_hashes=False): + """Create a RequirementSet. + + :param wheel_cache: The pip wheel cache, for passing to + InstallRequirement. + """ + + self.requirements = OrderedDict() + self.require_hashes = require_hashes + + # Mapping of alias: real_name + self.requirement_aliases = {} + self.unnamed_requirements = [] + self.successfully_downloaded = [] + self.reqs_to_cleanup = [] + + def __str__(self): + reqs = [req for req in self.requirements.values() + if not req.comes_from] + reqs.sort(key=lambda req: req.name.lower()) + return ' '.join([str(req.req) for req in reqs]) + + def __repr__(self): + reqs = [req for req in self.requirements.values()] + reqs.sort(key=lambda req: req.name.lower()) + reqs_str = ', '.join([str(req.req) for req in reqs]) + return ('<%s object; %d requirement(s): %s>' + % (self.__class__.__name__, len(reqs), reqs_str)) + + def add_requirement(self, install_req, parent_req_name=None, + extras_requested=None): + """Add install_req as a requirement to install. + + :param parent_req_name: The name of the requirement that needed this + added. The name is used because when multiple unnamed requirements + resolve to the same name, we could otherwise end up with dependency + links that point outside the Requirements set. parent_req must + already be added. Note that None implies that this is a user + supplied requirement, vs an inferred one. + :param extras_requested: an iterable of extras used to evaluate the + environment markers. + :return: Additional requirements to scan. That is either [] if + the requirement is not applicable, or [install_req] if the + requirement is applicable and has just been added. + """ + name = install_req.name + if not install_req.match_markers(extras_requested): + logger.info("Ignoring %s: markers '%s' don't match your " + "environment", install_req.name, + install_req.markers) + return [], None + + # This check has to come after we filter requirements with the + # environment markers. + if install_req.link and install_req.link.is_wheel: + wheel = Wheel(install_req.link.filename) + if not wheel.supported(): + raise InstallationError( + "%s is not a supported wheel on this platform." % + wheel.filename + ) + + # This next bit is really a sanity check. + assert install_req.is_direct == (parent_req_name is None), ( + "a direct req shouldn't have a parent and also, " + "a non direct req should have a parent" + ) + + if not name: + # url or path requirement w/o an egg fragment + self.unnamed_requirements.append(install_req) + return [install_req], None + else: + try: + existing_req = self.get_requirement(name) + except KeyError: + existing_req = None + if (parent_req_name is None and existing_req and not + existing_req.constraint and + existing_req.extras == install_req.extras and not + existing_req.req.specifier == install_req.req.specifier): + raise InstallationError( + 'Double requirement given: %s (already in %s, name=%r)' + % (install_req, existing_req, name)) + if not existing_req: + # Add requirement + self.requirements[name] = install_req + # FIXME: what about other normalizations? E.g., _ vs. -? + if name.lower() != name: + self.requirement_aliases[name.lower()] = name + result = [install_req] + else: + # Assume there's no need to scan, and that we've already + # encountered this for scanning. + result = [] + if not install_req.constraint and existing_req.constraint: + if (install_req.link and not (existing_req.link and + install_req.link.path == existing_req.link.path)): + self.reqs_to_cleanup.append(install_req) + raise InstallationError( + "Could not satisfy constraints for '%s': " + "installation from path or url cannot be " + "constrained to a version" % name, + ) + # If we're now installing a constraint, mark the existing + # object for real installation. + existing_req.constraint = False + existing_req.extras = tuple( + sorted(set(existing_req.extras).union( + set(install_req.extras)))) + logger.debug("Setting %s extras to: %s", + existing_req, existing_req.extras) + # And now we need to scan this. + result = [existing_req] + # Canonicalise to the already-added object for the backref + # check below. + install_req = existing_req + + # We return install_req here to allow for the caller to add it to + # the dependency information for the parent package. + return result, install_req + + def has_requirement(self, project_name): + name = project_name.lower() + if (name in self.requirements and + not self.requirements[name].constraint or + name in self.requirement_aliases and + not self.requirements[self.requirement_aliases[name]].constraint): + return True + return False + + @property + def has_requirements(self): + return list(req for req in self.requirements.values() if not + req.constraint) or self.unnamed_requirements + + def get_requirement(self, project_name): + for name in project_name, project_name.lower(): + if name in self.requirements: + return self.requirements[name] + if name in self.requirement_aliases: + return self.requirements[self.requirement_aliases[name]] + raise KeyError("No project with the name %r" % project_name) + + def cleanup_files(self): + """Clean up files, remove builds.""" + logger.debug('Cleaning up...') + with indent_log(): + for req in self.reqs_to_cleanup: + req.remove_temporary_source() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py new file mode 100755 index 0000000..a47520f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py @@ -0,0 +1,455 @@ +from __future__ import absolute_import + +import csv +import functools +import logging +import os +import sys +import sysconfig + +from pip._vendor import pkg_resources + +from pip._internal.compat import WINDOWS, cache_from_source, uses_pycache +from pip._internal.exceptions import UninstallationError +from pip._internal.locations import bin_py, bin_user +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + FakeFile, ask, dist_in_usersite, dist_is_local, egg_link_path, is_local, + normalize_path, renames, +) +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +def _script_names(dist, script_name, is_gui): + """Create the fully qualified name of the files created by + {console,gui}_scripts for the given ``dist``. + Returns the list of file names + """ + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + exe_name = os.path.join(bin_dir, script_name) + paths_to_remove = [exe_name] + if WINDOWS: + paths_to_remove.append(exe_name + '.exe') + paths_to_remove.append(exe_name + '.exe.manifest') + if is_gui: + paths_to_remove.append(exe_name + '-script.pyw') + else: + paths_to_remove.append(exe_name + '-script.py') + return paths_to_remove + + +def _unique(fn): + @functools.wraps(fn) + def unique(*args, **kw): + seen = set() + for item in fn(*args, **kw): + if item not in seen: + seen.add(item) + yield item + return unique + + +@_unique +def uninstallation_paths(dist): + """ + Yield all the uninstallation paths for dist based on RECORD-without-.pyc + + Yield paths to all the files in RECORD. For each .py file in RECORD, add + the .pyc in the same directory. + + UninstallPathSet.add() takes care of the __pycache__ .pyc. + """ + r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) + for row in r: + path = os.path.join(dist.location, row[0]) + yield path + if path.endswith('.py'): + dn, fn = os.path.split(path) + base = fn[:-3] + path = os.path.join(dn, base + '.pyc') + yield path + + +def compact(paths): + """Compact a path set to contain the minimal number of paths + necessary to contain all paths in the set. If /a/path/ and + /a/path/to/a/file.txt are both in the set, leave only the + shorter path.""" + + sep = os.path.sep + short_paths = set() + for path in sorted(paths, key=len): + should_add = any( + path.startswith(shortpath.rstrip("*")) and + path[len(shortpath.rstrip("*").rstrip(sep))] == sep + for shortpath in short_paths + ) + if not should_add: + short_paths.add(path) + return short_paths + + +def compress_for_output_listing(paths): + """Returns a tuple of 2 sets of which paths to display to user + + The first set contains paths that would be deleted. Files of a package + are not added and the top-level directory of the package has a '*' added + at the end - to signify that all it's contents are removed. + + The second set contains files that would have been skipped in the above + folders. + """ + + will_remove = list(paths) + will_skip = set() + + # Determine folders and files + folders = set() + files = set() + for path in will_remove: + if path.endswith(".pyc"): + continue + if path.endswith("__init__.py") or ".dist-info" in path: + folders.add(os.path.dirname(path)) + files.add(path) + + folders = compact(folders) + + # This walks the tree using os.walk to not miss extra folders + # that might get added. + for folder in folders: + for dirpath, _, dirfiles in os.walk(folder): + for fname in dirfiles: + if fname.endswith(".pyc"): + continue + + file_ = os.path.normcase(os.path.join(dirpath, fname)) + if os.path.isfile(file_) and file_ not in files: + # We are skipping this file. Add it to the set. + will_skip.add(file_) + + will_remove = files | { + os.path.join(folder, "*") for folder in folders + } + + return will_remove, will_skip + + +class UninstallPathSet(object): + """A set of file paths to be removed in the uninstallation of a + requirement.""" + def __init__(self, dist): + self.paths = set() + self._refuse = set() + self.pth = {} + self.dist = dist + self.save_dir = TempDirectory(kind="uninstall") + self._moved_paths = [] + + def _permitted(self, path): + """ + Return True if the given path is one we are permitted to + remove/modify, False otherwise. + + """ + return is_local(path) + + def add(self, path): + head, tail = os.path.split(path) + + # we normalize the head to resolve parent directory symlinks, but not + # the tail, since we only want to uninstall symlinks, not their targets + path = os.path.join(normalize_path(head), os.path.normcase(tail)) + + if not os.path.exists(path): + return + if self._permitted(path): + self.paths.add(path) + else: + self._refuse.add(path) + + # __pycache__ files can show up after 'installed-files.txt' is created, + # due to imports + if os.path.splitext(path)[1] == '.py' and uses_pycache: + self.add(cache_from_source(path)) + + def add_pth(self, pth_file, entry): + pth_file = normalize_path(pth_file) + if self._permitted(pth_file): + if pth_file not in self.pth: + self.pth[pth_file] = UninstallPthEntries(pth_file) + self.pth[pth_file].add(entry) + else: + self._refuse.add(pth_file) + + def _stash(self, path): + return os.path.join( + self.save_dir.path, os.path.splitdrive(path)[1].lstrip(os.path.sep) + ) + + def remove(self, auto_confirm=False, verbose=False): + """Remove paths in ``self.paths`` with confirmation (unless + ``auto_confirm`` is True).""" + + if not self.paths: + logger.info( + "Can't uninstall '%s'. No files were found to uninstall.", + self.dist.project_name, + ) + return + + dist_name_version = ( + self.dist.project_name + "-" + self.dist.version + ) + logger.info('Uninstalling %s:', dist_name_version) + + with indent_log(): + if auto_confirm or self._allowed_to_proceed(verbose): + self.save_dir.create() + + for path in sorted(compact(self.paths)): + new_path = self._stash(path) + logger.debug('Removing file or directory %s', path) + self._moved_paths.append(path) + renames(path, new_path) + for pth in self.pth.values(): + pth.remove() + + logger.info('Successfully uninstalled %s', dist_name_version) + + def _allowed_to_proceed(self, verbose): + """Display which files would be deleted and prompt for confirmation + """ + + def _display(msg, paths): + if not paths: + return + + logger.info(msg) + with indent_log(): + for path in sorted(compact(paths)): + logger.info(path) + + if not verbose: + will_remove, will_skip = compress_for_output_listing(self.paths) + else: + # In verbose mode, display all the files that are going to be + # deleted. + will_remove = list(self.paths) + will_skip = set() + + _display('Would remove:', will_remove) + _display('Would not remove (might be manually added):', will_skip) + _display('Would not remove (outside of prefix):', self._refuse) + + return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' + + def rollback(self): + """Rollback the changes previously made by remove().""" + if self.save_dir.path is None: + logger.error( + "Can't roll back %s; was not uninstalled", + self.dist.project_name, + ) + return False + logger.info('Rolling back uninstall of %s', self.dist.project_name) + for path in self._moved_paths: + tmp_path = self._stash(path) + logger.debug('Replacing %s', path) + renames(tmp_path, path) + for pth in self.pth.values(): + pth.rollback() + + def commit(self): + """Remove temporary save dir: rollback will no longer be possible.""" + self.save_dir.cleanup() + self._moved_paths = [] + + @classmethod + def from_dist(cls, dist): + dist_path = normalize_path(dist.location) + if not dist_is_local(dist): + logger.info( + "Not uninstalling %s at %s, outside environment %s", + dist.key, + dist_path, + sys.prefix, + ) + return cls(dist) + + if dist_path in {p for p in {sysconfig.get_path("stdlib"), + sysconfig.get_path("platstdlib")} + if p}: + logger.info( + "Not uninstalling %s at %s, as it is in the standard library.", + dist.key, + dist_path, + ) + return cls(dist) + + paths_to_remove = cls(dist) + develop_egg_link = egg_link_path(dist) + develop_egg_link_egg_info = '{}.egg-info'.format( + pkg_resources.to_filename(dist.project_name)) + egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) + # Special case for distutils installed package + distutils_egg_info = getattr(dist._provider, 'path', None) + + # Uninstall cases order do matter as in the case of 2 installs of the + # same package, pip needs to uninstall the currently detected version + if (egg_info_exists and dist.egg_info.endswith('.egg-info') and + not dist.egg_info.endswith(develop_egg_link_egg_info)): + # if dist.egg_info.endswith(develop_egg_link_egg_info), we + # are in fact in the develop_egg_link case + paths_to_remove.add(dist.egg_info) + if dist.has_metadata('installed-files.txt'): + for installed_file in dist.get_metadata( + 'installed-files.txt').splitlines(): + path = os.path.normpath( + os.path.join(dist.egg_info, installed_file) + ) + paths_to_remove.add(path) + # FIXME: need a test for this elif block + # occurs with --single-version-externally-managed/--record outside + # of pip + elif dist.has_metadata('top_level.txt'): + if dist.has_metadata('namespace_packages.txt'): + namespaces = dist.get_metadata('namespace_packages.txt') + else: + namespaces = [] + for top_level_pkg in [ + p for p + in dist.get_metadata('top_level.txt').splitlines() + if p and p not in namespaces]: + path = os.path.join(dist.location, top_level_pkg) + paths_to_remove.add(path) + paths_to_remove.add(path + '.py') + paths_to_remove.add(path + '.pyc') + paths_to_remove.add(path + '.pyo') + + elif distutils_egg_info: + raise UninstallationError( + "Cannot uninstall {!r}. It is a distutils installed project " + "and thus we cannot accurately determine which files belong " + "to it which would lead to only a partial uninstall.".format( + dist.project_name, + ) + ) + + elif dist.location.endswith('.egg'): + # package installed by easy_install + # We cannot match on dist.egg_name because it can slightly vary + # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg + paths_to_remove.add(dist.location) + easy_install_egg = os.path.split(dist.location)[1] + easy_install_pth = os.path.join(os.path.dirname(dist.location), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) + + elif egg_info_exists and dist.egg_info.endswith('.dist-info'): + for path in uninstallation_paths(dist): + paths_to_remove.add(path) + + elif develop_egg_link: + # develop egg + with open(develop_egg_link, 'r') as fh: + link_pointer = os.path.normcase(fh.readline().strip()) + assert (link_pointer == dist.location), ( + 'Egg-link %s does not match installed location of %s ' + '(at %s)' % (link_pointer, dist.project_name, dist.location) + ) + paths_to_remove.add(develop_egg_link) + easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, dist.location) + + else: + logger.debug( + 'Not sure how to uninstall: %s - Check: %s', + dist, dist.location, + ) + + # find distutils scripts= scripts + if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): + for script in dist.metadata_listdir('scripts'): + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + paths_to_remove.add(os.path.join(bin_dir, script)) + if WINDOWS: + paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') + + # find console_scripts + _scripts_to_remove = [] + console_scripts = dist.get_entry_map(group='console_scripts') + for name in console_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, False)) + # find gui_scripts + gui_scripts = dist.get_entry_map(group='gui_scripts') + for name in gui_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, True)) + + for s in _scripts_to_remove: + paths_to_remove.add(s) + + return paths_to_remove + + +class UninstallPthEntries(object): + def __init__(self, pth_file): + if not os.path.isfile(pth_file): + raise UninstallationError( + "Cannot remove entries from nonexistent file %s" % pth_file + ) + self.file = pth_file + self.entries = set() + self._saved_lines = None + + def add(self, entry): + entry = os.path.normcase(entry) + # On Windows, os.path.normcase converts the entry to use + # backslashes. This is correct for entries that describe absolute + # paths outside of site-packages, but all the others use forward + # slashes. + if WINDOWS and not os.path.splitdrive(entry)[0]: + entry = entry.replace('\\', '/') + self.entries.add(entry) + + def remove(self): + logger.debug('Removing pth entries from %s:', self.file) + with open(self.file, 'rb') as fh: + # windows uses '\r\n' with py3k, but uses '\n' with py2.x + lines = fh.readlines() + self._saved_lines = lines + if any(b'\r\n' in line for line in lines): + endline = '\r\n' + else: + endline = '\n' + # handle missing trailing newline + if lines and not lines[-1].endswith(endline.encode("utf-8")): + lines[-1] = lines[-1] + endline.encode("utf-8") + for entry in self.entries: + try: + logger.debug('Removing entry: %s', entry) + lines.remove((entry + endline).encode("utf-8")) + except ValueError: + pass + with open(self.file, 'wb') as fh: + fh.writelines(lines) + + def rollback(self): + if self._saved_lines is None: + logger.error( + 'Cannot roll back changes to %s, none were made', self.file + ) + return False + logger.debug('Rolling %s back to previous state', self.file) + with open(self.file, 'wb') as fh: + fh.writelines(self._saved_lines) + return True diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py new file mode 100755 index 0000000..189827e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py @@ -0,0 +1,354 @@ +"""Dependency Resolution + +The dependency resolution in pip is performed as follows: + +for top-level requirements: + a. only one spec allowed per project, regardless of conflicts or not. + otherwise a "double requirement" exception is raised + b. they override sub-dependency requirements. +for sub-dependencies + a. "first found, wins" (where the order is breadth first) +""" + +import logging +from collections import defaultdict +from itertools import chain + +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, DistributionNotFound, HashError, HashErrors, + UnsupportedPythonVersion, +) + +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import dist_in_usersite, ensure_dir +from pip._internal.utils.packaging import check_dist_requires_python + +logger = logging.getLogger(__name__) + + +class Resolver(object): + """Resolves which packages need to be installed/uninstalled to perform \ + the requested operation without breaking the requirements of any package. + """ + + _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} + + def __init__(self, preparer, session, finder, wheel_cache, use_user_site, + ignore_dependencies, ignore_installed, ignore_requires_python, + force_reinstall, isolated, upgrade_strategy): + super(Resolver, self).__init__() + assert upgrade_strategy in self._allowed_strategies + + self.preparer = preparer + self.finder = finder + self.session = session + + # NOTE: This would eventually be replaced with a cache that can give + # information about both sdist and wheels transparently. + self.wheel_cache = wheel_cache + + self.require_hashes = None # This is set in resolve + + self.upgrade_strategy = upgrade_strategy + self.force_reinstall = force_reinstall + self.isolated = isolated + self.ignore_dependencies = ignore_dependencies + self.ignore_installed = ignore_installed + self.ignore_requires_python = ignore_requires_python + self.use_user_site = use_user_site + + self._discovered_dependencies = defaultdict(list) + + def resolve(self, requirement_set): + """Resolve what operations need to be done + + As a side-effect of this method, the packages (and their dependencies) + are downloaded, unpacked and prepared for installation. This + preparation is done by ``pip.operations.prepare``. + + Once PyPI has static dependency metadata available, it would be + possible to move the preparation to become a step separated from + dependency resolution. + """ + # make the wheelhouse + if self.preparer.wheel_download_dir: + ensure_dir(self.preparer.wheel_download_dir) + + # If any top-level requirement has a hash specified, enter + # hash-checking mode, which requires hashes from all. + root_reqs = ( + requirement_set.unnamed_requirements + + list(requirement_set.requirements.values()) + ) + self.require_hashes = ( + requirement_set.require_hashes or + any(req.has_hash_options for req in root_reqs) + ) + + # Display where finder is looking for packages + locations = self.finder.get_formatted_locations() + if locations: + logger.info(locations) + + # Actually prepare the files, and collect any exceptions. Most hash + # exceptions cannot be checked ahead of time, because + # req.populate_link() needs to be called before we can make decisions + # based on link type. + discovered_reqs = [] + hash_errors = HashErrors() + for req in chain(root_reqs, discovered_reqs): + try: + discovered_reqs.extend( + self._resolve_one(requirement_set, req) + ) + except HashError as exc: + exc.req = req + hash_errors.append(exc) + + if hash_errors: + raise hash_errors + + def _is_upgrade_allowed(self, req): + if self.upgrade_strategy == "to-satisfy-only": + return False + elif self.upgrade_strategy == "eager": + return True + else: + assert self.upgrade_strategy == "only-if-needed" + return req.is_direct + + def _set_req_to_reinstall(self, req): + """ + Set a requirement to be installed. + """ + # Don't uninstall the conflict if doing a user install and the + # conflict is not a user install. + if not self.use_user_site or dist_in_usersite(req.satisfied_by): + req.conflicts_with = req.satisfied_by + req.satisfied_by = None + + # XXX: Stop passing requirement_set for options + def _check_skip_installed(self, req_to_install): + """Check if req_to_install should be skipped. + + This will check if the req is installed, and whether we should upgrade + or reinstall it, taking into account all the relevant user options. + + After calling this req_to_install will only have satisfied_by set to + None if the req_to_install is to be upgraded/reinstalled etc. Any + other value will be a dist recording the current thing installed that + satisfies the requirement. + + Note that for vcs urls and the like we can't assess skipping in this + routine - we simply identify that we need to pull the thing down, + then later on it is pulled down and introspected to assess upgrade/ + reinstalls etc. + + :return: A text reason for why it was skipped, or None. + """ + if self.ignore_installed: + return None + + req_to_install.check_if_exists(self.use_user_site) + if not req_to_install.satisfied_by: + return None + + if self.force_reinstall: + self._set_req_to_reinstall(req_to_install) + return None + + if not self._is_upgrade_allowed(req_to_install): + if self.upgrade_strategy == "only-if-needed": + return 'not upgraded as not directly required' + return 'already satisfied' + + # Check for the possibility of an upgrade. For link-based + # requirements we have to pull the tree down and inspect to assess + # the version #, so it's handled way down. + if not req_to_install.link: + try: + self.finder.find_requirement(req_to_install, upgrade=True) + except BestVersionAlreadyInstalled: + # Then the best version is installed. + return 'already up-to-date' + except DistributionNotFound: + # No distribution found, so we squash the error. It will + # be raised later when we re-try later to do the install. + # Why don't we just raise here? + pass + + self._set_req_to_reinstall(req_to_install) + return None + + def _get_abstract_dist_for(self, req): + """Takes a InstallRequirement and returns a single AbstractDist \ + representing a prepared variant of the same. + """ + assert self.require_hashes is not None, ( + "require_hashes should have been set in Resolver.resolve()" + ) + + if req.editable: + return self.preparer.prepare_editable_requirement( + req, self.require_hashes, self.use_user_site, self.finder, + ) + + # satisfied_by is only evaluated by calling _check_skip_installed, + # so it must be None here. + assert req.satisfied_by is None + skip_reason = self._check_skip_installed(req) + + if req.satisfied_by: + return self.preparer.prepare_installed_requirement( + req, self.require_hashes, skip_reason + ) + + upgrade_allowed = self._is_upgrade_allowed(req) + abstract_dist = self.preparer.prepare_linked_requirement( + req, self.session, self.finder, upgrade_allowed, + self.require_hashes + ) + + # NOTE + # The following portion is for determining if a certain package is + # going to be re-installed/upgraded or not and reporting to the user. + # This should probably get cleaned up in a future refactor. + + # req.req is only avail after unpack for URL + # pkgs repeat check_if_exists to uninstall-on-upgrade + # (#14) + if not self.ignore_installed: + req.check_if_exists(self.use_user_site) + + if req.satisfied_by: + should_modify = ( + self.upgrade_strategy != "to-satisfy-only" or + self.force_reinstall or + self.ignore_installed or + req.link.scheme == 'file' + ) + if should_modify: + self._set_req_to_reinstall(req) + else: + logger.info( + 'Requirement already satisfied (use --upgrade to upgrade):' + ' %s', req, + ) + + return abstract_dist + + def _resolve_one(self, requirement_set, req_to_install): + """Prepare a single requirements file. + + :return: A list of additional InstallRequirements to also install. + """ + # Tell user what we are doing for this requirement: + # obtain (editable), skipping, processing (local url), collecting + # (remote url or package name) + if req_to_install.constraint or req_to_install.prepared: + return [] + + req_to_install.prepared = True + + # register tmp src for cleanup in case something goes wrong + requirement_set.reqs_to_cleanup.append(req_to_install) + + abstract_dist = self._get_abstract_dist_for(req_to_install) + + # Parse and return dependencies + dist = abstract_dist.dist(self.finder) + try: + check_dist_requires_python(dist) + except UnsupportedPythonVersion as err: + if self.ignore_requires_python: + logger.warning(err.args[0]) + else: + raise + + more_reqs = [] + + def add_req(subreq, extras_requested): + sub_install_req = InstallRequirement.from_req( + str(subreq), + req_to_install, + isolated=self.isolated, + wheel_cache=self.wheel_cache, + ) + parent_req_name = req_to_install.name + to_scan_again, add_to_parent = requirement_set.add_requirement( + sub_install_req, + parent_req_name=parent_req_name, + extras_requested=extras_requested, + ) + if parent_req_name and add_to_parent: + self._discovered_dependencies[parent_req_name].append( + add_to_parent + ) + more_reqs.extend(to_scan_again) + + with indent_log(): + # We add req_to_install before its dependencies, so that we + # can refer to it when adding dependencies. + if not requirement_set.has_requirement(req_to_install.name): + # 'unnamed' requirements will get added here + req_to_install.is_direct = True + requirement_set.add_requirement( + req_to_install, parent_req_name=None, + ) + + if not self.ignore_dependencies: + if req_to_install.extras: + logger.debug( + "Installing extra requirements: %r", + ','.join(req_to_install.extras), + ) + missing_requested = sorted( + set(req_to_install.extras) - set(dist.extras) + ) + for missing in missing_requested: + logger.warning( + '%s does not provide the extra \'%s\'', + dist, missing + ) + + available_requested = sorted( + set(dist.extras) & set(req_to_install.extras) + ) + for subreq in dist.requires(available_requested): + add_req(subreq, extras_requested=available_requested) + + if not req_to_install.editable and not req_to_install.satisfied_by: + # XXX: --no-install leads this to report 'Successfully + # downloaded' for only non-editable reqs, even though we took + # action on them. + requirement_set.successfully_downloaded.append(req_to_install) + + return more_reqs + + def get_installation_order(self, req_set): + """Create the installation order. + + The installation order is topological - requirements are installed + before the requiring thing. We break cycles at an arbitrary point, + and make no other guarantees. + """ + # The current implementation, which we may change at any point + # installs the user specified things in the order given, except when + # dependencies must come earlier to achieve topological order. + order = [] + ordered_reqs = set() + + def schedule(req): + if req.satisfied_by or req in ordered_reqs: + return + if req.constraint: + return + ordered_reqs.add(req) + for dep in self._discovered_dependencies[req.name]: + schedule(dep) + order.append(req) + + for install_req in req_set.requirements.values(): + schedule(install_req) + return order diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py new file mode 100755 index 0000000..2b56931 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +SUCCESS = 0 +ERROR = 1 +UNKNOWN_ERROR = 2 +VIRTUALENV_NOT_FOUND = 3 +PREVIOUS_BUILD_DIR_ERROR = 4 +NO_MATCHES_FOUND = 23 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py new file mode 100755 index 0000000..0eb87ca --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py @@ -0,0 +1,258 @@ +""" +This code was taken from https://github.com/ActiveState/appdirs and modified +to suit our purposes. +""" +from __future__ import absolute_import + +import os +import sys + +from pip._vendor.six import PY2, text_type + +from pip._internal.compat import WINDOWS, expanduser + + +def user_cache_dir(appname): + r""" + Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + + Typical user cache directories are: + macOS: ~/Library/Caches/ + Unix: ~/.cache/ (XDG default) + Windows: C:\Users\\AppData\Local\\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go + in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the + non-roaming app data dir (the default returned by `user_data_dir`). Apps + typically put cache data somewhere *under* the given dir here. Some + examples: + ...\Mozilla\Firefox\Profiles\\Cache + ...\Acme\SuperApp\Cache\1.0 + + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + """ + if WINDOWS: + # Get the base path + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + + # When using Python 2, return paths as bytes on Windows like we do on + # other operating systems. See helper function docs for more details. + if PY2 and isinstance(path, text_type): + path = _win_path_to_bytes(path) + + # Add our app name and Cache directory to it + path = os.path.join(path, appname, "Cache") + elif sys.platform == "darwin": + # Get the base path + path = expanduser("~/Library/Caches") + + # Add our app name to it + path = os.path.join(path, appname) + else: + # Get the base path + path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache")) + + # Add our app name to it + path = os.path.join(path, appname) + + return path + + +def user_data_dir(appname, roaming=False): + r""" + Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user data directories are: + macOS: ~/Library/Application Support/ + if it exists, else ~/.config/ + Unix: ~/.local/share/ # or in + $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\\ ... + ...Application Data\ + Win XP (roaming): C:\Documents and Settings\\Local ... + ...Settings\Application Data\ + Win 7 (not roaming): C:\\Users\\AppData\Local\ + Win 7 (roaming): C:\\Users\\AppData\Roaming\ + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/". + """ + if WINDOWS: + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.join(os.path.normpath(_get_win_folder(const)), appname) + elif sys.platform == "darwin": + path = os.path.join( + expanduser('~/Library/Application Support/'), + appname, + ) if os.path.isdir(os.path.join( + expanduser('~/Library/Application Support/'), + appname, + ) + ) else os.path.join( + expanduser('~/.config/'), + appname, + ) + else: + path = os.path.join( + os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")), + appname, + ) + + return path + + +def user_config_dir(appname, roaming=True): + """Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "roaming" (boolean, default True) can be set False to not use the + Windows roaming appdata directory. That means that for users on a + Windows network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user data directories are: + macOS: same as user_data_dir + Unix: ~/.config/ + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/". + """ + if WINDOWS: + path = user_data_dir(appname, roaming=roaming) + elif sys.platform == "darwin": + path = user_data_dir(appname) + else: + path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config")) + path = os.path.join(path, appname) + + return path + + +# for the discussion regarding site_config_dirs locations +# see +def site_config_dirs(appname): + r"""Return a list of potential user-shared config dirs for this application. + + "appname" is the name of application. + + Typical user config directories are: + macOS: /Library/Application Support// + Unix: /etc or $XDG_CONFIG_DIRS[i]// for each value in + $XDG_CONFIG_DIRS + Win XP: C:\Documents and Settings\All Users\Application ... + ...Data\\ + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory + on Vista.) + Win 7: Hidden, but writeable on Win 7: + C:\ProgramData\\ + """ + if WINDOWS: + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + pathlist = [os.path.join(path, appname)] + elif sys.platform == 'darwin': + pathlist = [os.path.join('/Library/Application Support', appname)] + else: + # try looking in $XDG_CONFIG_DIRS + xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + if xdg_config_dirs: + pathlist = [ + os.path.join(expanduser(x), appname) + for x in xdg_config_dirs.split(os.pathsep) + ] + else: + pathlist = [] + + # always look in /etc directly as well + pathlist.append('/etc') + + return pathlist + + +# -- Windows support functions -- + +def _get_win_folder_from_registry(csidl_name): + """ + This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + directory, _type = _winreg.QueryValueEx(key, shell_folder_name) + return directory + + +def _get_win_folder_with_ctypes(csidl_name): + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + + +if WINDOWS: + try: + import ctypes + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +def _win_path_to_bytes(path): + """Encode Windows paths to bytes. Only used on Python 2. + + Motivation is to be consistent with other operating systems where paths + are also returned as bytes. This avoids problems mixing bytes and Unicode + elsewhere in the codebase. For more details and discussion see + . + + If encoding using ASCII and MBCS fails, return the original Unicode path. + """ + for encoding in ('ASCII', 'MBCS'): + try: + return path.encode(encoding) + except (UnicodeEncodeError, LookupError): + pass + return path diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py new file mode 100755 index 0000000..c0e3884 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py @@ -0,0 +1,77 @@ +""" +A module that implements tooling to enable easy warnings about deprecations. +""" +from __future__ import absolute_import + +import logging +import warnings + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any + + +class PipDeprecationWarning(Warning): + pass + + +class Pending(object): + pass + + +class RemovedInPip11Warning(PipDeprecationWarning): + pass + + +class RemovedInPip12Warning(PipDeprecationWarning, Pending): + pass + + +# Warnings <-> Logging Integration + + +_warnings_showwarning = None # type: Any + + +def _showwarning(message, category, filename, lineno, file=None, line=None): + if file is not None: + if _warnings_showwarning is not None: + _warnings_showwarning( + message, category, filename, lineno, file, line, + ) + else: + if issubclass(category, PipDeprecationWarning): + # We use a specially named logger which will handle all of the + # deprecation messages for pip. + logger = logging.getLogger("pip._internal.deprecations") + + # This is purposely using the % formatter here instead of letting + # the logging module handle the interpolation. This is because we + # want it to appear as if someone typed this entire message out. + log_message = "DEPRECATION: %s" % message + + # PipDeprecationWarnings that are Pending still have at least 2 + # versions to go until they are removed so they can just be + # warnings. Otherwise, they will be removed in the very next + # version of pip. We want these to be more obvious so we use the + # ERROR logging level. + if issubclass(category, Pending): + logger.warning(log_message) + else: + logger.error(log_message) + else: + _warnings_showwarning( + message, category, filename, lineno, file, line, + ) + + +def install_warning_logger(): + # Enable our Deprecation Warnings + warnings.simplefilter("default", PipDeprecationWarning, append=True) + + global _warnings_showwarning + + if _warnings_showwarning is None: + _warnings_showwarning = warnings.showwarning + warnings.showwarning = _showwarning diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py new file mode 100755 index 0000000..831f3f6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py @@ -0,0 +1,33 @@ +import codecs +import locale +import re +import sys + +BOMS = [ + (codecs.BOM_UTF8, 'utf8'), + (codecs.BOM_UTF16, 'utf16'), + (codecs.BOM_UTF16_BE, 'utf16-be'), + (codecs.BOM_UTF16_LE, 'utf16-le'), + (codecs.BOM_UTF32, 'utf32'), + (codecs.BOM_UTF32_BE, 'utf32-be'), + (codecs.BOM_UTF32_LE, 'utf32-le'), +] + +ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') + + +def auto_decode(data): + """Check a bytes string for a BOM to correctly detect the encoding + + Fallback to locale.getpreferredencoding(False) like open() on Python3""" + for bom, encoding in BOMS: + if data.startswith(bom): + return data[len(bom):].decode(encoding) + # Lets check the first two lines as in PEP263 + for line in data.split(b'\n')[:2]: + if line[0:1] == b'#' and ENCODING_RE.search(line): + encoding = ENCODING_RE.search(line).groups()[0].decode('ascii') + return data.decode(encoding) + return data.decode( + locale.getpreferredencoding(False) or sys.getdefaultencoding(), + ) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py new file mode 100755 index 0000000..94fa2c6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py @@ -0,0 +1,28 @@ +import os +import os.path + +from pip._internal.compat import get_path_uid + + +def check_path_owner(path): + # If we don't have a way to check the effective uid of this process, then + # we'll just assume that we own the directory. + if not hasattr(os, "geteuid"): + return True + + previous = None + while path != previous: + if os.path.lexists(path): + # Check if path is writable by current user. + if os.geteuid() == 0: + # Special handling for root user in order to handle properly + # cases where users use sudo without -H flag. + try: + path_uid = get_path_uid(path) + except OSError: + return False + return path_uid == 0 + else: + return os.access(path, os.W_OK) + else: + previous, path = path, os.path.dirname(path) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py new file mode 100755 index 0000000..5900a10 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py @@ -0,0 +1,84 @@ +from __future__ import absolute_import + +import ctypes +import re +import warnings + + +def glibc_version_string(): + "Returns glibc version string, or None if not using glibc." + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + process_namespace = ctypes.CDLL(None) + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# Separated out from have_compatible_glibc for easier unit testing +def check_glibc_version(version_str, required_major, minimum_minor): + # Parse string and check against requested version. + # + # We use a regexp instead of str.split because we want to discard any + # random junk that might come after the minor version -- this might happen + # in patched/forked versions of glibc (e.g. Linaro's version of glibc + # uses version strings like "2.20-2014.11"). See gh-3588. + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn("Expected glibc version with 2 components major.minor," + " got: %s" % version_str, RuntimeWarning) + return False + return (int(m.group("major")) == required_major and + int(m.group("minor")) >= minimum_minor) + + +def have_compatible_glibc(required_major, minimum_minor): + version_str = glibc_version_string() + if version_str is None: + return False + return check_glibc_version(version_str, required_major, minimum_minor) + + +# platform.libc_ver regularly returns completely nonsensical glibc +# versions. E.g. on my computer, platform says: +# +# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.7') +# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.9') +# +# But the truth is: +# +# ~$ ldd --version +# ldd (Debian GLIBC 2.22-11) 2.22 +# +# This is unfortunate, because it means that the linehaul data on libc +# versions that was generated by pip 8.1.2 and earlier is useless and +# misleading. Solution: instead of using platform, use our code that actually +# works. +def libc_ver(): + """Try to determine the glibc version + + Returns a tuple of strings (lib, version) which default to empty strings + in case the lookup fails. + """ + glibc_version = glibc_version_string() + if glibc_version is None: + return ("", "") + else: + return ("glibc", glibc_version) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py new file mode 100755 index 0000000..8cf6367 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import + +import hashlib + +from pip._vendor.six import iteritems, iterkeys, itervalues + +from pip._internal.exceptions import ( + HashMismatch, HashMissing, InstallationError, +) +from pip._internal.utils.misc import read_chunks + +# The recommended hash algo of the moment. Change this whenever the state of +# the art changes; it won't hurt backward compatibility. +FAVORITE_HASH = 'sha256' + + +# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` +# Currently, those are the ones at least as collision-resistant as sha256. +STRONG_HASHES = ['sha256', 'sha384', 'sha512'] + + +class Hashes(object): + """A wrapper that builds multiple hashes at once and checks them against + known-good values + + """ + def __init__(self, hashes=None): + """ + :param hashes: A dict of algorithm names pointing to lists of allowed + hex digests + """ + self._allowed = {} if hashes is None else hashes + + def check_against_chunks(self, chunks): + """Check good hashes against ones built from iterable of chunks of + data. + + Raise HashMismatch if none match. + + """ + gots = {} + for hash_name in iterkeys(self._allowed): + try: + gots[hash_name] = hashlib.new(hash_name) + except (ValueError, TypeError): + raise InstallationError('Unknown hash name: %s' % hash_name) + + for chunk in chunks: + for hash in itervalues(gots): + hash.update(chunk) + + for hash_name, got in iteritems(gots): + if got.hexdigest() in self._allowed[hash_name]: + return + self._raise(gots) + + def _raise(self, gots): + raise HashMismatch(self._allowed, gots) + + def check_against_file(self, file): + """Check good hashes against a file-like object + + Raise HashMismatch if none match. + + """ + return self.check_against_chunks(read_chunks(file)) + + def check_against_path(self, path): + with open(path, 'rb') as file: + return self.check_against_file(file) + + def __nonzero__(self): + """Return whether I know any known-good hashes.""" + return bool(self._allowed) + + def __bool__(self): + return self.__nonzero__() + + +class MissingHashes(Hashes): + """A workalike for Hashes used when we're missing a hash for a requirement + + It computes the actual hash of the requirement and raises a HashMissing + exception showing it to the user. + + """ + def __init__(self): + """Don't offer the ``hashes`` kwarg.""" + # Pass our favorite hash in to generate a "gotten hash". With the + # empty list, it will never match, so an error will always raise. + super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []}) + + def _raise(self, gots): + raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py new file mode 100755 index 0000000..1fb3e8a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py @@ -0,0 +1,132 @@ +from __future__ import absolute_import + +import contextlib +import logging +import logging.handlers +import os + +from pip._internal.compat import WINDOWS +from pip._internal.utils.misc import ensure_dir + +try: + import threading +except ImportError: + import dummy_threading as threading # type: ignore + + +try: + from pip._vendor import colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None + + +_log_state = threading.local() +_log_state.indentation = 0 + + +@contextlib.contextmanager +def indent_log(num=2): + """ + A context manager which will cause the log output to be indented for any + log messages emitted inside it. + """ + _log_state.indentation += num + try: + yield + finally: + _log_state.indentation -= num + + +def get_indentation(): + return getattr(_log_state, 'indentation', 0) + + +class IndentingFormatter(logging.Formatter): + + def format(self, record): + """ + Calls the standard formatter, but will indent all of the log messages + by our current indentation level. + """ + formatted = logging.Formatter.format(self, record) + formatted = "".join([ + (" " * get_indentation()) + line + for line in formatted.splitlines(True) + ]) + return formatted + + +def _color_wrap(*colors): + def wrapped(inp): + return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) + return wrapped + + +class ColorizedStreamHandler(logging.StreamHandler): + + # Don't build up a list of colors if we don't have colorama + if colorama: + COLORS = [ + # This needs to be in order from highest logging level to lowest. + (logging.ERROR, _color_wrap(colorama.Fore.RED)), + (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)), + ] + else: + COLORS = [] + + def __init__(self, stream=None, no_color=None): + logging.StreamHandler.__init__(self, stream) + self._no_color = no_color + + if WINDOWS and colorama: + self.stream = colorama.AnsiToWin32(self.stream) + + def should_color(self): + # Don't colorize things if we do not have colorama or if told not to + if not colorama or self._no_color: + return False + + real_stream = ( + self.stream if not isinstance(self.stream, colorama.AnsiToWin32) + else self.stream.wrapped + ) + + # If the stream is a tty we should color it + if hasattr(real_stream, "isatty") and real_stream.isatty(): + return True + + # If we have an ASNI term we should color it + if os.environ.get("TERM") == "ANSI": + return True + + # If anything else we should not color it + return False + + def format(self, record): + msg = logging.StreamHandler.format(self, record) + + if self.should_color(): + for level, color in self.COLORS: + if record.levelno >= level: + msg = color(msg) + break + + return msg + + +class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): + + def _open(self): + ensure_dir(os.path.dirname(self.baseFilename)) + return logging.handlers.RotatingFileHandler._open(self) + + +class MaxLevelFilter(logging.Filter): + + def __init__(self, level): + self.level = level + + def filter(self, record): + return record.levelno < self.level diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py new file mode 100755 index 0000000..db84a7c --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py @@ -0,0 +1,851 @@ +from __future__ import absolute_import + +import contextlib +import errno +import io +import locale +# we have a submodule named 'logging' which would shadow this if we used the +# regular name: +import logging as std_logging +import os +import posixpath +import re +import shutil +import stat +import subprocess +import sys +import tarfile +import zipfile +from collections import deque + +from pip._vendor import pkg_resources +# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import. +from pip._vendor.retrying import retry # type: ignore +from pip._vendor.six import PY2 +from pip._vendor.six.moves import input + +from pip._internal.compat import console_to_str, expanduser, stdlib_pkgs +from pip._internal.exceptions import InstallationError +from pip._internal.locations import ( + running_under_virtualenv, site_packages, user_site, virtualenv_no_global, + write_delete_marker_file, +) + +if PY2: + from io import BytesIO as StringIO +else: + from io import StringIO + +__all__ = ['rmtree', 'display_path', 'backup_dir', + 'ask', 'splitext', + 'format_size', 'is_installable_dir', + 'is_svn_page', 'file_contents', + 'split_leading_dir', 'has_leading_dir', + 'normalize_path', + 'renames', 'get_prog', + 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', + 'captured_stdout', 'ensure_dir', + 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS', + 'get_installed_version'] + + +logger = std_logging.getLogger(__name__) + +BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') +XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', '.tar.lz', '.tar.lzma') +ZIP_EXTENSIONS = ('.zip', '.whl') +TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') +ARCHIVE_EXTENSIONS = ( + ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS) +SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS +try: + import bz2 # noqa + SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS +except ImportError: + logger.debug('bz2 module is not available') + +try: + # Only for Python 3.3+ + import lzma # noqa + SUPPORTED_EXTENSIONS += XZ_EXTENSIONS +except ImportError: + logger.debug('lzma module is not available') + + +def import_or_raise(pkg_or_module_string, ExceptionType, *args, **kwargs): + try: + return __import__(pkg_or_module_string) + except ImportError: + raise ExceptionType(*args, **kwargs) + + +def ensure_dir(path): + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def get_prog(): + try: + prog = os.path.basename(sys.argv[0]) + if prog in ('__main__.py', '-c'): + return "%s -m pip" % sys.executable + else: + return prog + except (AttributeError, TypeError, IndexError): + pass + return 'pip' + + +# Retry every half second for up to 3 seconds +@retry(stop_max_delay=3000, wait_fixed=500) +def rmtree(dir, ignore_errors=False): + shutil.rmtree(dir, ignore_errors=ignore_errors, + onerror=rmtree_errorhandler) + + +def rmtree_errorhandler(func, path, exc_info): + """On Windows, the files in .svn are read-only, so when rmtree() tries to + remove them, an exception is thrown. We catch that here, remove the + read-only attribute, and hopefully continue without problems.""" + # if file type currently read only + if os.stat(path).st_mode & stat.S_IREAD: + # convert to read/write + os.chmod(path, stat.S_IWRITE) + # use the original function to repeat the operation + func(path) + return + else: + raise + + +def display_path(path): + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if sys.version_info[0] == 2: + path = path.decode(sys.getfilesystemencoding(), 'replace') + path = path.encode(sys.getdefaultencoding(), 'replace') + if path.startswith(os.getcwd() + os.path.sep): + path = '.' + path[len(os.getcwd()):] + return path + + +def backup_dir(dir, ext='.bak'): + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def ask_path_exists(message, options): + for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): + if action in options: + return action + return ask(message, options) + + +def ask(message, options): + """Ask the message interactively, with the given possible responses""" + while 1: + if os.environ.get('PIP_NO_INPUT'): + raise Exception( + 'No input was expected ($PIP_NO_INPUT set); question: %s' % + message + ) + response = input(message) + response = response.strip().lower() + if response not in options: + print( + 'Your response (%r) was not one of the expected responses: ' + '%s' % (response, ', '.join(options)) + ) + else: + return response + + +def format_size(bytes): + if bytes > 1000 * 1000: + return '%.1fMB' % (bytes / 1000.0 / 1000) + elif bytes > 10 * 1000: + return '%ikB' % (bytes / 1000) + elif bytes > 1000: + return '%.1fkB' % (bytes / 1000.0) + else: + return '%ibytes' % bytes + + +def is_installable_dir(path): + """Return True if `path` is a directory containing a setup.py file.""" + if not os.path.isdir(path): + return False + setup_py = os.path.join(path, 'setup.py') + if os.path.isfile(setup_py): + return True + return False + + +def is_svn_page(html): + """ + Returns true if the page appears to be the index page of an svn repository + """ + return (re.search(r'[^<]*Revision \d+:', html) and + re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I)) + + +def file_contents(filename): + with open(filename, 'rb') as fp: + return fp.read().decode('utf-8') + + +def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): + """Yield pieces of data from a file-like object until EOF.""" + while True: + chunk = file.read(size) + if not chunk: + break + yield chunk + + +def split_leading_dir(path): + path = path.lstrip('/').lstrip('\\') + if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or + '\\' not in path): + return path.split('/', 1) + elif '\\' in path: + return path.split('\\', 1) + else: + return path, '' + + +def has_leading_dir(paths): + """Returns true if all the paths have the same leading path name + (i.e., everything is in one subdirectory in an archive)""" + common_prefix = None + for path in paths: + prefix, rest = split_leading_dir(path) + if not prefix: + return False + elif common_prefix is None: + common_prefix = prefix + elif prefix != common_prefix: + return False + return True + + +def normalize_path(path, resolve_symlinks=True): + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + path = expanduser(path) + if resolve_symlinks: + path = os.path.realpath(path) + else: + path = os.path.abspath(path) + return os.path.normcase(path) + + +def splitext(path): + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith('.tar'): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old, new): + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path): + """ + Return True if path is within sys.prefix, if we're running in a virtualenv. + + If we're not in a virtualenv, all paths are considered "local." + + """ + if not running_under_virtualenv(): + return True + return normalize_path(path).startswith(normalize_path(sys.prefix)) + + +def dist_is_local(dist): + """ + Return True if given Distribution object is installed locally + (i.e. within current virtualenv). + + Always True if we're not in a virtualenv. + + """ + return is_local(dist_location(dist)) + + +def dist_in_usersite(dist): + """ + Return True if given Distribution is installed in user site. + """ + norm_path = normalize_path(dist_location(dist)) + return norm_path.startswith(normalize_path(user_site)) + + +def dist_in_site_packages(dist): + """ + Return True if given Distribution is installed in + sysconfig.get_python_lib(). + """ + return normalize_path( + dist_location(dist) + ).startswith(normalize_path(site_packages)) + + +def dist_is_editable(dist): + """Is distribution an editable install?""" + for path_item in sys.path: + egg_link = os.path.join(path_item, dist.project_name + '.egg-link') + if os.path.isfile(egg_link): + return True + return False + + +def get_installed_distributions(local_only=True, + skip=stdlib_pkgs, + include_editables=True, + editables_only=False, + user_only=False): + """ + Return a list of installed Distribution objects. + + If ``local_only`` is True (default), only return installations + local to the current virtualenv, if in a virtualenv. + + ``skip`` argument is an iterable of lower-case project names to + ignore; defaults to stdlib_pkgs + + If ``include_editables`` is False, don't report editables. + + If ``editables_only`` is True , only report editables. + + If ``user_only`` is True , only report installations in the user + site directory. + + """ + if local_only: + local_test = dist_is_local + else: + def local_test(d): + return True + + if include_editables: + def editable_test(d): + return True + else: + def editable_test(d): + return not dist_is_editable(d) + + if editables_only: + def editables_only_test(d): + return dist_is_editable(d) + else: + def editables_only_test(d): + return True + + if user_only: + user_test = dist_in_usersite + else: + def user_test(d): + return True + + return [d for d in pkg_resources.working_set + if local_test(d) and + d.key not in skip and + editable_test(d) and + editables_only_test(d) and + user_test(d) + ] + + +def egg_link_path(dist): + """ + Return the path for the .egg-link file if it exists, otherwise, None. + + There's 3 scenarios: + 1) not in a virtualenv + try to find in site.USER_SITE, then site_packages + 2) in a no-global virtualenv + try to find in site_packages + 3) in a yes-global virtualenv + try to find in site_packages, then site.USER_SITE + (don't look in global location) + + For #1 and #3, there could be odd cases, where there's an egg-link in 2 + locations. + + This method will just return the first one found. + """ + sites = [] + if running_under_virtualenv(): + if virtualenv_no_global(): + sites.append(site_packages) + else: + sites.append(site_packages) + if user_site: + sites.append(user_site) + else: + if user_site: + sites.append(user_site) + sites.append(site_packages) + + for site in sites: + egglink = os.path.join(site, dist.project_name) + '.egg-link' + if os.path.isfile(egglink): + return egglink + + +def dist_location(dist): + """ + Get the site-packages location of this distribution. Generally + this is dist.location, except in the case of develop-installed + packages, where dist.location is the source code location, and we + want to know where the egg-link file is. + + """ + egg_link = egg_link_path(dist) + if egg_link: + return egg_link + return dist.location + + +def current_umask(): + """Get the current umask which involves having to set it temporarily.""" + mask = os.umask(0) + os.umask(mask) + return mask + + +def unzip_file(filename, location, flatten=True): + """ + Unzip the file (with path `filename`) to the destination `location`. All + files are written based on system defaults and umask (i.e. permissions are + not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + zipfp = open(filename, 'rb') + try: + zip = zipfile.ZipFile(zipfp, allowZip64=True) + leading = has_leading_dir(zip.namelist()) and flatten + for info in zip.infolist(): + name = info.filename + data = zip.read(name) + fn = name + if leading: + fn = split_leading_dir(name)[1] + fn = os.path.join(location, fn) + dir = os.path.dirname(fn) + if fn.endswith('/') or fn.endswith('\\'): + # A directory + ensure_dir(fn) + else: + ensure_dir(dir) + fp = open(fn, 'wb') + try: + fp.write(data) + finally: + fp.close() + mode = info.external_attr >> 16 + # if mode and regular file and any execute permissions for + # user/group/world? + if mode and stat.S_ISREG(mode) and mode & 0o111: + # make dest file have execute for user/group/world + # (chmod +x) no-op on windows per python docs + os.chmod(fn, (0o777 - current_umask() | 0o111)) + finally: + zipfp.close() + + +def untar_file(filename, location): + """ + Untar the file (with path `filename`) to the destination `location`. + All files are written based on system defaults and umask (i.e. permissions + are not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): + mode = 'r:gz' + elif filename.lower().endswith(BZ2_EXTENSIONS): + mode = 'r:bz2' + elif filename.lower().endswith(XZ_EXTENSIONS): + mode = 'r:xz' + elif filename.lower().endswith('.tar'): + mode = 'r' + else: + logger.warning( + 'Cannot determine compression type for file %s', filename, + ) + mode = 'r:*' + tar = tarfile.open(filename, mode) + try: + # note: python<=2.5 doesn't seem to know about pax headers, filter them + leading = has_leading_dir([ + member.name for member in tar.getmembers() + if member.name != 'pax_global_header' + ]) + for member in tar.getmembers(): + fn = member.name + if fn == 'pax_global_header': + continue + if leading: + fn = split_leading_dir(fn)[1] + path = os.path.join(location, fn) + if member.isdir(): + ensure_dir(path) + elif member.issym(): + try: + tar._extract_member(member, path) + except Exception as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + else: + try: + fp = tar.extractfile(member) + except (KeyError, AttributeError) as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + ensure_dir(os.path.dirname(path)) + with open(path, 'wb') as destfp: + shutil.copyfileobj(fp, destfp) + fp.close() + # Update the timestamp (useful for cython compiled files) + tar.utime(member, path) + # member have any execute permissions for user/group/world? + if member.mode & 0o111: + # make dest file have execute for user/group/world + # no-op on windows per python docs + os.chmod(path, (0o777 - current_umask() | 0o111)) + finally: + tar.close() + + +def unpack_file(filename, location, content_type, link): + filename = os.path.realpath(filename) + if (content_type == 'application/zip' or + filename.lower().endswith(ZIP_EXTENSIONS) or + zipfile.is_zipfile(filename)): + unzip_file( + filename, + location, + flatten=not filename.endswith('.whl') + ) + elif (content_type == 'application/x-gzip' or + tarfile.is_tarfile(filename) or + filename.lower().endswith( + TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)): + untar_file(filename, location) + elif (content_type and content_type.startswith('text/html') and + is_svn_page(file_contents(filename))): + # We don't really care about this + from pip._internal.vcs.subversion import Subversion + Subversion('svn+' + link.url).unpack(location) + else: + # FIXME: handle? + # FIXME: magic signatures? + logger.critical( + 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' + 'cannot detect archive format', + filename, location, content_type, + ) + raise InstallationError( + 'Cannot determine archive format of %s' % location + ) + + +def call_subprocess(cmd, show_stdout=True, cwd=None, + on_returncode='raise', + command_desc=None, + extra_environ=None, unset_environ=None, spinner=None): + """ + Args: + unset_environ: an iterable of environment variable names to unset + prior to calling subprocess.Popen(). + """ + if unset_environ is None: + unset_environ = [] + # This function's handling of subprocess output is confusing and I + # previously broke it terribly, so as penance I will write a long comment + # explaining things. + # + # The obvious thing that affects output is the show_stdout= + # kwarg. show_stdout=True means, let the subprocess write directly to our + # stdout. Even though it is nominally the default, it is almost never used + # inside pip (and should not be used in new code without a very good + # reason); as of 2016-02-22 it is only used in a few places inside the VCS + # wrapper code. Ideally we should get rid of it entirely, because it + # creates a lot of complexity here for a rarely used feature. + # + # Most places in pip set show_stdout=False. What this means is: + # - We connect the child stdout to a pipe, which we read. + # - By default, we hide the output but show a spinner -- unless the + # subprocess exits with an error, in which case we show the output. + # - If the --verbose option was passed (= loglevel is DEBUG), then we show + # the output unconditionally. (But in this case we don't want to show + # the output a second time if it turns out that there was an error.) + # + # stderr is always merged with stdout (even if show_stdout=True). + if show_stdout: + stdout = None + else: + stdout = subprocess.PIPE + if command_desc is None: + cmd_parts = [] + for part in cmd: + if ' ' in part or '\n' in part or '"' in part or "'" in part: + part = '"%s"' % part.replace('"', '\\"') + cmd_parts.append(part) + command_desc = ' '.join(cmd_parts) + logger.debug("Running command %s", command_desc) + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + for name in unset_environ: + env.pop(name, None) + try: + proc = subprocess.Popen( + cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, + stdout=stdout, cwd=cwd, env=env, + ) + proc.stdin.close() + except Exception as exc: + logger.critical( + "Error %s while executing command %s", exc, command_desc, + ) + raise + all_output = [] + if stdout is not None: + while True: + line = console_to_str(proc.stdout.readline()) + if not line: + break + line = line.rstrip() + all_output.append(line + '\n') + if logger.getEffectiveLevel() <= std_logging.DEBUG: + # Show the line immediately + logger.debug(line) + else: + # Update the spinner + if spinner is not None: + spinner.spin() + try: + proc.wait() + finally: + if proc.stdout: + proc.stdout.close() + if spinner is not None: + if proc.returncode: + spinner.finish("error") + else: + spinner.finish("done") + if proc.returncode: + if on_returncode == 'raise': + if (logger.getEffectiveLevel() > std_logging.DEBUG and + not show_stdout): + logger.info( + 'Complete output from command %s:', command_desc, + ) + logger.info( + ''.join(all_output) + + '\n----------------------------------------' + ) + raise InstallationError( + 'Command "%s" failed with error code %s in %s' + % (command_desc, proc.returncode, cwd)) + elif on_returncode == 'warn': + logger.warning( + 'Command "%s" had error code %s in %s', + command_desc, proc.returncode, cwd, + ) + elif on_returncode == 'ignore': + pass + else: + raise ValueError('Invalid value: on_returncode=%s' % + repr(on_returncode)) + if not show_stdout: + return ''.join(all_output) + + +def read_text_file(filename): + """Return the contents of *filename*. + + Try to decode the file contents with utf-8, the preferred system encoding + (e.g., cp1252 on some Windows machines), and latin1, in that order. + Decoding a byte string with latin1 will never raise an error. In the worst + case, the returned string will contain some garbage characters. + + """ + with open(filename, 'rb') as fp: + data = fp.read() + + encodings = ['utf-8', locale.getpreferredencoding(False), 'latin1'] + for enc in encodings: + try: + data = data.decode(enc) + except UnicodeDecodeError: + continue + break + + assert type(data) != bytes # Latin1 should have worked. + return data + + +def _make_build_dir(build_dir): + os.makedirs(build_dir) + write_delete_marker_file(build_dir) + + +class FakeFile(object): + """Wrap a list of lines in an object with readline() to make + ConfigParser happy.""" + def __init__(self, lines): + self._gen = (l for l in lines) + + def readline(self): + try: + try: + return next(self._gen) + except NameError: + return self._gen.next() + except StopIteration: + return '' + + def __iter__(self): + return self._gen + + +class StreamWrapper(StringIO): + + @classmethod + def from_stream(cls, orig_stream): + cls.orig_stream = orig_stream + return cls() + + # compileall.compile_dir() needs stdout.encoding to print to stdout + @property + def encoding(self): + return self.orig_stream.encoding + + +@contextlib.contextmanager +def captured_output(stream_name): + """Return a context manager used by captured_stdout/stdin/stderr + that temporarily replaces the sys stream *stream_name* with a StringIO. + + Taken from Lib/support/__init__.py in the CPython repo. + """ + orig_stdout = getattr(sys, stream_name) + setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) + try: + yield getattr(sys, stream_name) + finally: + setattr(sys, stream_name, orig_stdout) + + +def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as stdout: + print('hello') + self.assertEqual(stdout.getvalue(), 'hello\n') + + Taken from Lib/support/__init__.py in the CPython repo. + """ + return captured_output('stdout') + + +class cached_property(object): + """A property that is only computed once per instance and then replaces + itself with an ordinary attribute. Deleting the attribute resets the + property. + + Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175 + """ + + def __init__(self, func): + self.__doc__ = getattr(func, '__doc__') + self.func = func + + def __get__(self, obj, cls): + if obj is None: + # We're being accessed from the class itself, not from an object + return self + value = obj.__dict__[self.func.__name__] = self.func(obj) + return value + + +def get_installed_version(dist_name, lookup_dirs=None): + """Get the installed version of dist_name avoiding pkg_resources cache""" + # Create a requirement that we'll look for inside of setuptools. + req = pkg_resources.Requirement.parse(dist_name) + + # We want to avoid having this cached, so we need to construct a new + # working set each time. + if lookup_dirs is None: + working_set = pkg_resources.WorkingSet() + else: + working_set = pkg_resources.WorkingSet(lookup_dirs) + + # Get the installed distribution from our working set + dist = working_set.find(req) + + # Check to see if we got an installed distribution or not, if we did + # we want to return it's version. + return dist.version if dist else None + + +def consume(iterator): + """Consume an iterable at C speed.""" + deque(iterator, maxlen=0) + + +# Simulates an enum +def enum(*sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = {value: key for key, value in enums.items()} + enums['reverse_mapping'] = reverse + return type('Enum', (), enums) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py new file mode 100755 index 0000000..f4572ab --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py @@ -0,0 +1,163 @@ +from __future__ import absolute_import + +import datetime +import json +import logging +import os.path +import sys + +from pip._vendor import lockfile +from pip._vendor.packaging import version as packaging_version + +from pip._internal.compat import WINDOWS +from pip._internal.index import PackageFinder +from pip._internal.locations import USER_CACHE_DIR, running_under_virtualenv +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, get_installed_version + +SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" + + +logger = logging.getLogger(__name__) + + +class VirtualenvSelfCheckState(object): + def __init__(self): + self.statefile_path = os.path.join(sys.prefix, "pip-selfcheck.json") + + # Load the existing state + try: + with open(self.statefile_path) as statefile: + self.state = json.load(statefile) + except (IOError, ValueError): + self.state = {} + + def save(self, pypi_version, current_time): + # Attempt to write out our version check file + with open(self.statefile_path, "w") as statefile: + json.dump( + { + "last_check": current_time.strftime(SELFCHECK_DATE_FMT), + "pypi_version": pypi_version, + }, + statefile, + sort_keys=True, + separators=(",", ":") + ) + + +class GlobalSelfCheckState(object): + def __init__(self): + self.statefile_path = os.path.join(USER_CACHE_DIR, "selfcheck.json") + + # Load the existing state + try: + with open(self.statefile_path) as statefile: + self.state = json.load(statefile)[sys.prefix] + except (IOError, ValueError, KeyError): + self.state = {} + + def save(self, pypi_version, current_time): + # Check to make sure that we own the directory + if not check_path_owner(os.path.dirname(self.statefile_path)): + return + + # Now that we've ensured the directory is owned by this user, we'll go + # ahead and make sure that all our directories are created. + ensure_dir(os.path.dirname(self.statefile_path)) + + # Attempt to write out our version check file + with lockfile.LockFile(self.statefile_path): + if os.path.exists(self.statefile_path): + with open(self.statefile_path) as statefile: + state = json.load(statefile) + else: + state = {} + + state[sys.prefix] = { + "last_check": current_time.strftime(SELFCHECK_DATE_FMT), + "pypi_version": pypi_version, + } + + with open(self.statefile_path, "w") as statefile: + json.dump(state, statefile, sort_keys=True, + separators=(",", ":")) + + +def load_selfcheck_statefile(): + if running_under_virtualenv(): + return VirtualenvSelfCheckState() + else: + return GlobalSelfCheckState() + + +def pip_version_check(session, options): + """Check for an update for pip. + + Limit the frequency of checks to once per week. State is stored either in + the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix + of the pip script path. + """ + installed_version = get_installed_version("pip") + if not installed_version: + return + + pip_version = packaging_version.parse(installed_version) + pypi_version = None + + try: + state = load_selfcheck_statefile() + + current_time = datetime.datetime.utcnow() + # Determine if we need to refresh the state + if "last_check" in state.state and "pypi_version" in state.state: + last_check = datetime.datetime.strptime( + state.state["last_check"], + SELFCHECK_DATE_FMT + ) + if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: + pypi_version = state.state["pypi_version"] + + # Refresh the version if we need to or just see if we need to warn + if pypi_version is None: + # Lets use PackageFinder to see what the latest pip version is + finder = PackageFinder( + find_links=options.find_links, + index_urls=[options.index_url] + options.extra_index_urls, + allow_all_prereleases=False, # Explicitly set to False + trusted_hosts=options.trusted_hosts, + process_dependency_links=options.process_dependency_links, + session=session, + ) + all_candidates = finder.find_all_candidates("pip") + if not all_candidates: + return + pypi_version = str( + max(all_candidates, key=lambda c: c.version).version + ) + + # save that we've performed a check + state.save(pypi_version, current_time) + + remote_version = packaging_version.parse(pypi_version) + + # Determine if our pypi_version is older + if (pip_version < remote_version and + pip_version.base_version != remote_version.base_version): + # Advise "python -m pip" on Windows to avoid issues + # with overwriting pip.exe. + if WINDOWS: + pip_cmd = "python -m pip" + else: + pip_cmd = "pip" + logger.warning( + "You are using pip version %s, however version %s is " + "available.\nYou should consider upgrading via the " + "'%s install --upgrade pip' command.", + pip_version, pypi_version, pip_cmd + ) + except Exception: + logger.debug( + "There was an error checking the latest version of pip", + exc_info=True, + ) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py new file mode 100755 index 0000000..d523953 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import + +import logging +import sys +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources +from pip._vendor.packaging import specifiers, version + +from pip._internal import exceptions + +logger = logging.getLogger(__name__) + + +def check_requires_python(requires_python): + """ + Check if the python version in use match the `requires_python` specifier. + + Returns `True` if the version of python in use matches the requirement. + Returns `False` if the version of python in use does not matches the + requirement. + + Raises an InvalidSpecifier if `requires_python` have an invalid format. + """ + if requires_python is None: + # The package provides no information + return True + requires_python_specifier = specifiers.SpecifierSet(requires_python) + + # We only use major.minor.micro + python_version = version.parse('.'.join(map(str, sys.version_info[:3]))) + return python_version in requires_python_specifier + + +def get_metadata(dist): + if (isinstance(dist, pkg_resources.DistInfoDistribution) and + dist.has_metadata('METADATA')): + return dist.get_metadata('METADATA') + elif dist.has_metadata('PKG-INFO'): + return dist.get_metadata('PKG-INFO') + + +def check_dist_requires_python(dist): + metadata = get_metadata(dist) + feed_parser = FeedParser() + feed_parser.feed(metadata) + pkg_info_dict = feed_parser.close() + requires_python = pkg_info_dict.get('Requires-Python') + try: + if not check_requires_python(requires_python): + raise exceptions.UnsupportedPythonVersion( + "%s requires Python '%s' but the running Python is %s" % ( + dist.project_name, + requires_python, + '.'.join(map(str, sys.version_info[:3])),) + ) + except specifiers.InvalidSpecifier as e: + logger.warning( + "Package %s has an invalid Requires-Python entry %s - %s", + dist.project_name, requires_python, e, + ) + return + + +def get_installer(dist): + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + return line.strip() + return '' diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py new file mode 100755 index 0000000..9d32174 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py @@ -0,0 +1,8 @@ +# Shim to wrap setup.py invocation with setuptools +SETUPTOOLS_SHIM = ( + "import setuptools, tokenize;__file__=%r;" + "f=getattr(tokenize, 'open', open)(__file__);" + "code=f.read().replace('\\r\\n', '\\n');" + "f.close();" + "exec(compile(code, __file__, 'exec'))" +) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py new file mode 100755 index 0000000..25bc0d9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py @@ -0,0 +1,82 @@ +from __future__ import absolute_import + +import logging +import os.path +import tempfile + +from pip._internal.utils.misc import rmtree + +logger = logging.getLogger(__name__) + + +class TempDirectory(object): + """Helper class that owns and cleans up a temporary directory. + + This class can be used as a context manager or as an OO representation of a + temporary directory. + + Attributes: + path + Location to the created temporary directory or None + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + Methods: + create() + Creates a temporary directory and stores its path in the path + attribute. + cleanup() + Deletes the temporary directory and sets path attribute to None + + When used as a context manager, a temporary directory is created on + entering the context and, if the delete attribute is True, on exiting the + context the created directory is deleted. + """ + + def __init__(self, path=None, delete=None, kind="temp"): + super(TempDirectory, self).__init__() + + if path is None and delete is None: + # If we were not given an explicit directory, and we were not given + # an explicit delete option, then we'll default to deleting. + delete = True + + self.path = path + self.delete = delete + self.kind = kind + + def __repr__(self): + return "<{} {!r}>".format(self.__class__.__name__, self.path) + + def __enter__(self): + self.create() + return self + + def __exit__(self, exc, value, tb): + if self.delete: + self.cleanup() + + def create(self): + """Create a temporary directory and store it's path in self.path + """ + if self.path is not None: + logger.debug( + "Skipped creation of temporary directory: {}".format(self.path) + ) + return + # We realpath here because some systems have their default tmpdir + # symlinked to another directory. This tends to confuse build + # scripts, so we canonicalize the path by traversing potential + # symlinks here. + self.path = os.path.realpath( + tempfile.mkdtemp(prefix="pip-{}-".format(self.kind)) + ) + logger.debug("Created temporary directory: {}".format(self.path)) + + def cleanup(self): + """Remove the temporary directory created and reset state + """ + if self.path is not None and os.path.exists(self.path): + rmtree(self.path) + self.path = None diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py new file mode 100755 index 0000000..4e25ae6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py @@ -0,0 +1,29 @@ +"""For neatly implementing static typing in pip. + +`mypy` - the static type analysis tool we use - uses the `typing` module, which +provides core functionality fundamental to mypy's functioning. + +Generally, `typing` would be imported at runtime and used in that fashion - +it acts as a no-op at runtime and does not have any run-time overhead by +design. + +As it turns out, `typing` is not vendorable - it uses separate sources for +Python 2/Python 3. Thus, this codebase can not expect it to be present. +To work around this, mypy allows the typing import to be behind a False-y +optional to prevent it from running at runtime and type-comments can be used +to remove the need for the types to be accessible directly during runtime. + +This module provides the False-y guard in a nicely named fashion so that a +curious maintainer can reach here to read this. + +In pip, all static-typing related imports should be guarded as follows: + + from pip.utils.typing import MYPY_CHECK_RUNNING + + if MYPY_CHECK_RUNNING: + from typing import ... + +Ref: https://github.com/python/mypy/issues/3216 +""" + +MYPY_CHECK_RUNNING = False diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py new file mode 100755 index 0000000..d97ea36 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py @@ -0,0 +1,421 @@ +from __future__ import absolute_import, division + +import contextlib +import itertools +import logging +import sys +import time +from signal import SIGINT, default_int_handler, signal + +from pip._vendor import six +from pip._vendor.progress.bar import ( + Bar, ChargingBar, FillingCirclesBar, FillingSquaresBar, IncrementalBar, + ShadyBar, +) +from pip._vendor.progress.helpers import HIDE_CURSOR, SHOW_CURSOR, WritelnMixin +from pip._vendor.progress.spinner import Spinner + +from pip._internal.compat import WINDOWS +from pip._internal.utils.logging import get_indentation +from pip._internal.utils.misc import format_size +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any + +try: + from pip._vendor import colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None + +logger = logging.getLogger(__name__) + + +def _select_progress_class(preferred, fallback): + encoding = getattr(preferred.file, "encoding", None) + + # If we don't know what encoding this file is in, then we'll just assume + # that it doesn't support unicode and use the ASCII bar. + if not encoding: + return fallback + + # Collect all of the possible characters we want to use with the preferred + # bar. + characters = [ + getattr(preferred, "empty_fill", six.text_type()), + getattr(preferred, "fill", six.text_type()), + ] + characters += list(getattr(preferred, "phases", [])) + + # Try to decode the characters we're using for the bar using the encoding + # of the given file, if this works then we'll assume that we can use the + # fancier bar and if not we'll fall back to the plaintext bar. + try: + six.text_type().join(characters).encode(encoding) + except UnicodeEncodeError: + return fallback + else: + return preferred + + +_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any + + +class InterruptibleMixin(object): + """ + Helper to ensure that self.finish() gets called on keyboard interrupt. + + This allows downloads to be interrupted without leaving temporary state + (like hidden cursors) behind. + + This class is similar to the progress library's existing SigIntMixin + helper, but as of version 1.2, that helper has the following problems: + + 1. It calls sys.exit(). + 2. It discards the existing SIGINT handler completely. + 3. It leaves its own handler in place even after an uninterrupted finish, + which will have unexpected delayed effects if the user triggers an + unrelated keyboard interrupt some time after a progress-displaying + download has already completed, for example. + """ + + def __init__(self, *args, **kwargs): + """ + Save the original SIGINT handler for later. + """ + super(InterruptibleMixin, self).__init__(*args, **kwargs) + + self.original_handler = signal(SIGINT, self.handle_sigint) + + # If signal() returns None, the previous handler was not installed from + # Python, and we cannot restore it. This probably should not happen, + # but if it does, we must restore something sensible instead, at least. + # The least bad option should be Python's default SIGINT handler, which + # just raises KeyboardInterrupt. + if self.original_handler is None: + self.original_handler = default_int_handler + + def finish(self): + """ + Restore the original SIGINT handler after finishing. + + This should happen regardless of whether the progress display finishes + normally, or gets interrupted. + """ + super(InterruptibleMixin, self).finish() + signal(SIGINT, self.original_handler) + + def handle_sigint(self, signum, frame): + """ + Call self.finish() before delegating to the original SIGINT handler. + + This handler should only be in place while the progress display is + active. + """ + self.finish() + self.original_handler(signum, frame) + + +class SilentBar(Bar): + + def update(self): + pass + + +class BlueEmojiBar(IncrementalBar): + + suffix = "%(percent)d%%" + bar_prefix = " " + bar_suffix = " " + phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any + + +class DownloadProgressMixin(object): + + def __init__(self, *args, **kwargs): + super(DownloadProgressMixin, self).__init__(*args, **kwargs) + self.message = (" " * (get_indentation() + 2)) + self.message + + @property + def downloaded(self): + return format_size(self.index) + + @property + def download_speed(self): + # Avoid zero division errors... + if self.avg == 0.0: + return "..." + return format_size(1 / self.avg) + "/s" + + @property + def pretty_eta(self): + if self.eta: + return "eta %s" % self.eta_td + return "" + + def iter(self, it, n=1): + for x in it: + yield x + self.next(n) + self.finish() + + +class WindowsMixin(object): + + def __init__(self, *args, **kwargs): + # The Windows terminal does not support the hide/show cursor ANSI codes + # even with colorama. So we'll ensure that hide_cursor is False on + # Windows. + # This call neds to go before the super() call, so that hide_cursor + # is set in time. The base progress bar class writes the "hide cursor" + # code to the terminal in its init, so if we don't set this soon + # enough, we get a "hide" with no corresponding "show"... + if WINDOWS and self.hide_cursor: + self.hide_cursor = False + + super(WindowsMixin, self).__init__(*args, **kwargs) + + # Check if we are running on Windows and we have the colorama module, + # if we do then wrap our file with it. + if WINDOWS and colorama: + self.file = colorama.AnsiToWin32(self.file) + # The progress code expects to be able to call self.file.isatty() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.isatty = lambda: self.file.wrapped.isatty() + # The progress code expects to be able to call self.file.flush() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.flush = lambda: self.file.wrapped.flush() + + +class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin): + + file = sys.stdout + message = "%(percent)d%%" + suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" + +# NOTE: The "type: ignore" comments on the following classes are there to +# work around https://github.com/python/typing/issues/241 + + +class DefaultDownloadProgressBar(BaseDownloadProgressBar, + _BaseBar): # type: ignore + pass + + +class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore + pass + + +class DownloadIncrementalBar(BaseDownloadProgressBar, # type: ignore + IncrementalBar): + pass + + +class DownloadChargingBar(BaseDownloadProgressBar, # type: ignore + ChargingBar): + pass + + +class DownloadShadyBar(BaseDownloadProgressBar, ShadyBar): # type: ignore + pass + + +class DownloadFillingSquaresBar(BaseDownloadProgressBar, # type: ignore + FillingSquaresBar): + pass + + +class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore + FillingCirclesBar): + pass + + +class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore + BlueEmojiBar): + pass + + +class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin, WritelnMixin, Spinner): + + file = sys.stdout + suffix = "%(downloaded)s %(download_speed)s" + + def next_phase(self): + if not hasattr(self, "_phaser"): + self._phaser = itertools.cycle(self.phases) + return next(self._phaser) + + def update(self): + message = self.message % self + phase = self.next_phase() + suffix = self.suffix % self + line = ''.join([ + message, + " " if message else "", + phase, + " " if suffix else "", + suffix, + ]) + + self.writeln(line) + + +BAR_TYPES = { + "off": (DownloadSilentBar, DownloadSilentBar), + "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), + "ascii": (DownloadIncrementalBar, DownloadProgressSpinner), + "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), + "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) +} + + +def DownloadProgressProvider(progress_bar, max=None): + if max is None or max == 0: + return BAR_TYPES[progress_bar][1]().iter + else: + return BAR_TYPES[progress_bar][0](max=max).iter + + +################################################################ +# Generic "something is happening" spinners +# +# We don't even try using progress.spinner.Spinner here because it's actually +# simpler to reimplement from scratch than to coerce their code into doing +# what we need. +################################################################ + +@contextlib.contextmanager +def hidden_cursor(file): + # The Windows terminal does not support the hide/show cursor ANSI codes, + # even via colorama. So don't even try. + if WINDOWS: + yield + # We don't want to clutter the output with control characters if we're + # writing to a file, or if the user is running with --quiet. + # See https://github.com/pypa/pip/issues/3418 + elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: + yield + else: + file.write(HIDE_CURSOR) + try: + yield + finally: + file.write(SHOW_CURSOR) + + +class RateLimiter(object): + def __init__(self, min_update_interval_seconds): + self._min_update_interval_seconds = min_update_interval_seconds + self._last_update = 0 + + def ready(self): + now = time.time() + delta = now - self._last_update + return delta >= self._min_update_interval_seconds + + def reset(self): + self._last_update = time.time() + + +class InteractiveSpinner(object): + def __init__(self, message, file=None, spin_chars="-\\|/", + # Empirically, 8 updates/second looks nice + min_update_interval_seconds=0.125): + self._message = message + if file is None: + file = sys.stdout + self._file = file + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._finished = False + + self._spin_cycle = itertools.cycle(spin_chars) + + self._file.write(" " * get_indentation() + self._message + " ... ") + self._width = 0 + + def _write(self, status): + assert not self._finished + # Erase what we wrote before by backspacing to the beginning, writing + # spaces to overwrite the old text, and then backspacing again + backup = "\b" * self._width + self._file.write(backup + " " * self._width + backup) + # Now we have a blank slate to add our status + self._file.write(status) + self._width = len(status) + self._file.flush() + self._rate_limiter.reset() + + def spin(self): + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._write(next(self._spin_cycle)) + + def finish(self, final_status): + if self._finished: + return + self._write(final_status) + self._file.write("\n") + self._file.flush() + self._finished = True + + +# Used for dumb terminals, non-interactive installs (no tty), etc. +# We still print updates occasionally (once every 60 seconds by default) to +# act as a keep-alive for systems like Travis-CI that take lack-of-output as +# an indication that a task has frozen. +class NonInteractiveSpinner(object): + def __init__(self, message, min_update_interval_seconds=60): + self._message = message + self._finished = False + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._update("started") + + def _update(self, status): + assert not self._finished + self._rate_limiter.reset() + logger.info("%s: %s", self._message, status) + + def spin(self): + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._update("still running...") + + def finish(self, final_status): + if self._finished: + return + self._update("finished with status '%s'" % (final_status,)) + self._finished = True + + +@contextlib.contextmanager +def open_spinner(message): + # Interactive spinner goes directly to sys.stdout rather than being routed + # through the logging system, but it acts like it has level INFO, + # i.e. it's only displayed if we're at level INFO or better. + # Non-interactive spinner goes through the logging system, so it is always + # in sync with logging configuration. + if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: + spinner = InteractiveSpinner(message) + else: + spinner = NonInteractiveSpinner(message) + try: + with hidden_cursor(sys.stdout): + yield spinner + except KeyboardInterrupt: + spinner.finish("canceled") + raise + except Exception: + spinner.finish("error") + raise + else: + spinner.finish("done") diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py new file mode 100755 index 0000000..bff94fa --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py @@ -0,0 +1,471 @@ +"""Handles all VCS (version control) support""" +from __future__ import absolute_import + +import copy +import errno +import logging +import os +import shutil +import sys + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.exceptions import BadCommand +from pip._internal.utils.misc import ( + display_path, backup_dir, call_subprocess, rmtree, ask_path_exists, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Dict, Optional, Tuple + from pip._internal.basecommand import Command + +__all__ = ['vcs', 'get_src_requirement'] + + +logger = logging.getLogger(__name__) + + +class RevOptions(object): + + """ + Encapsulates a VCS-specific revision to install, along with any VCS + install options. + + Instances of this class should be treated as if immutable. + """ + + def __init__(self, vcs, rev=None, extra_args=None): + """ + Args: + vcs: a VersionControl object. + rev: the name of the revision to install. + extra_args: a list of extra options. + """ + if extra_args is None: + extra_args = [] + + self.extra_args = extra_args + self.rev = rev + self.vcs = vcs + + def __repr__(self): + return '<RevOptions {}: rev={!r}>'.format(self.vcs.name, self.rev) + + @property + def arg_rev(self): + if self.rev is None: + return self.vcs.default_arg_rev + + return self.rev + + def to_args(self): + """ + Return the VCS-specific command arguments. + """ + args = [] + rev = self.arg_rev + if rev is not None: + args += self.vcs.get_base_rev_args(rev) + args += self.extra_args + + return args + + def to_display(self): + if not self.rev: + return '' + + return ' (to revision {})'.format(self.rev) + + def make_new(self, rev): + """ + Make a copy of the current instance, but with a new rev. + + Args: + rev: the name of the revision for the new object. + """ + return self.vcs.make_rev_options(rev, extra_args=self.extra_args) + + +class VcsSupport(object): + _registry = {} # type: Dict[str, Command] + schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] + + def __init__(self): + # Register more schemes with urlparse for various version control + # systems + urllib_parse.uses_netloc.extend(self.schemes) + # Python >= 2.7.4, 3.3 doesn't have uses_fragment + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(self.schemes) + super(VcsSupport, self).__init__() + + def __iter__(self): + return self._registry.__iter__() + + @property + def backends(self): + return list(self._registry.values()) + + @property + def dirnames(self): + return [backend.dirname for backend in self.backends] + + @property + def all_schemes(self): + schemes = [] + for backend in self.backends: + schemes.extend(backend.schemes) + return schemes + + def register(self, cls): + if not hasattr(cls, 'name'): + logger.warning('Cannot register VCS %s', cls.__name__) + return + if cls.name not in self._registry: + self._registry[cls.name] = cls + logger.debug('Registered VCS backend: %s', cls.name) + + def unregister(self, cls=None, name=None): + if name in self._registry: + del self._registry[name] + elif cls in self._registry.values(): + del self._registry[cls.name] + else: + logger.warning('Cannot unregister because no class or name given') + + def get_backend_name(self, location): + """ + Return the name of the version control backend if found at given + location, e.g. vcs.get_backend_name('/path/to/vcs/checkout') + """ + for vc_type in self._registry.values(): + if vc_type.controls_location(location): + logger.debug('Determine that %s uses VCS: %s', + location, vc_type.name) + return vc_type.name + return None + + def get_backend(self, name): + name = name.lower() + if name in self._registry: + return self._registry[name] + + def get_backend_from_location(self, location): + vc_type = self.get_backend_name(location) + if vc_type: + return self.get_backend(vc_type) + return None + + +vcs = VcsSupport() + + +class VersionControl(object): + name = '' + dirname = '' + # List of supported schemes for this Version Control + schemes = () # type: Tuple[str, ...] + # Iterable of environment variable names to pass to call_subprocess(). + unset_environ = () # type: Tuple[str, ...] + default_arg_rev = None # type: Optional[str] + + def __init__(self, url=None, *args, **kwargs): + self.url = url + super(VersionControl, self).__init__(*args, **kwargs) + + def get_base_rev_args(self, rev): + """ + Return the base revision arguments for a vcs command. + + Args: + rev: the name of a revision to install. Cannot be None. + """ + raise NotImplementedError + + def make_rev_options(self, rev=None, extra_args=None): + """ + Return a RevOptions object. + + Args: + rev: the name of a revision to install. + extra_args: a list of extra options. + """ + return RevOptions(self, rev, extra_args=extra_args) + + def _is_local_repository(self, repo): + """ + posix absolute paths start with os.path.sep, + win32 ones start with drive (like c:\\folder) + """ + drive, tail = os.path.splitdrive(repo) + return repo.startswith(os.path.sep) or drive + + # See issue #1083 for why this method was introduced: + # https://github.com/pypa/pip/issues/1083 + def translate_egg_surname(self, surname): + # For example, Django has branches of the form "stable/1.7.x". + return surname.replace('/', '_') + + def export(self, location): + """ + Export the repository at the url to the destination location + i.e. only download the files, without vcs informations + """ + raise NotImplementedError + + def get_url_rev(self): + """ + Returns the correct repository URL and revision by parsing the given + repository URL + """ + error_message = ( + "Sorry, '%s' is a malformed VCS url. " + "The format is <vcs>+<protocol>://<url>, " + "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" + ) + assert '+' in self.url, error_message % self.url + url = self.url.split('+', 1)[1] + scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) + return url, rev + + def get_info(self, location): + """ + Returns (url, revision), where both are strings + """ + assert not location.rstrip('/').endswith(self.dirname), \ + 'Bad directory: %s' % location + return self.get_url(location), self.get_revision(location) + + def normalize_url(self, url): + """ + Normalize a URL for comparison by unquoting it and removing any + trailing slash. + """ + return urllib_parse.unquote(url).rstrip('/') + + def compare_urls(self, url1, url2): + """ + Compare two repo URLs for identity, ignoring incidental differences. + """ + return (self.normalize_url(url1) == self.normalize_url(url2)) + + def obtain(self, dest): + """ + Called when installing or updating an editable package, takes the + source path of the checkout. + """ + raise NotImplementedError + + def switch(self, dest, url, rev_options): + """ + Switch the repo at ``dest`` to point to ``URL``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def update(self, dest, rev_options): + """ + Update an already-existing repo to the given ``rev_options``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def is_commit_id_equal(self, dest, name): + """ + Return whether the id of the current commit equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + raise NotImplementedError + + def check_destination(self, dest, url, rev_options): + """ + Prepare a location to receive a checkout/clone. + + Return True if the location is ready for (and requires) a + checkout/clone, False otherwise. + + Args: + rev_options: a RevOptions object. + """ + checkout = True + prompt = False + rev_display = rev_options.to_display() + if os.path.exists(dest): + checkout = False + if os.path.exists(os.path.join(dest, self.dirname)): + existing_url = self.get_url(dest) + if self.compare_urls(existing_url, url): + logger.debug( + '%s in %s exists, and has correct URL (%s)', + self.repo_name.title(), + display_path(dest), + url, + ) + if not self.is_commit_id_equal(dest, rev_options.rev): + logger.info( + 'Updating %s %s%s', + display_path(dest), + self.repo_name, + rev_display, + ) + self.update(dest, rev_options) + else: + logger.info( + 'Skipping because already up-to-date.') + else: + logger.warning( + '%s %s in %s exists with URL %s', + self.name, + self.repo_name, + display_path(dest), + existing_url, + ) + prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', + ('s', 'i', 'w', 'b')) + else: + logger.warning( + 'Directory %s already exists, and is not a %s %s.', + dest, + self.name, + self.repo_name, + ) + prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b')) + if prompt: + logger.warning( + 'The plan is to install the %s repository %s', + self.name, + url, + ) + response = ask_path_exists('What to do? %s' % prompt[0], + prompt[1]) + + if response == 's': + logger.info( + 'Switching %s %s to %s%s', + self.repo_name, + display_path(dest), + url, + rev_display, + ) + self.switch(dest, url, rev_options) + elif response == 'i': + # do nothing + pass + elif response == 'w': + logger.warning('Deleting %s', display_path(dest)) + rmtree(dest) + checkout = True + elif response == 'b': + dest_dir = backup_dir(dest) + logger.warning( + 'Backing up %s to %s', display_path(dest), dest_dir, + ) + shutil.move(dest, dest_dir) + checkout = True + elif response == 'a': + sys.exit(-1) + return checkout + + def unpack(self, location): + """ + Clean up current location and download the url repository + (and vcs infos) into location + """ + if os.path.exists(location): + rmtree(location) + self.obtain(location) + + def get_src_requirement(self, dist, location): + """ + Return a string representing the requirement needed to + redownload the files currently present in location, something + like: + {repository_url}@{revision}#egg={project_name}-{version_identifier} + """ + raise NotImplementedError + + def get_url(self, location): + """ + Return the url used at location + Used in get_info or check_destination + """ + raise NotImplementedError + + def get_revision(self, location): + """ + Return the current commit id of the files at the given location. + """ + raise NotImplementedError + + def run_command(self, cmd, show_stdout=True, cwd=None, + on_returncode='raise', + command_desc=None, + extra_environ=None, spinner=None): + """ + Run a VCS subcommand + This is simply a wrapper around call_subprocess that adds the VCS + command name, and checks that the VCS is available + """ + cmd = [self.name] + cmd + try: + return call_subprocess(cmd, show_stdout, cwd, + on_returncode, + command_desc, extra_environ, + unset_environ=self.unset_environ, + spinner=spinner) + except OSError as e: + # errno.ENOENT = no such file or directory + # In other words, the VCS executable isn't available + if e.errno == errno.ENOENT: + raise BadCommand( + 'Cannot find command %r - do you have ' + '%r installed and in your ' + 'PATH?' % (self.name, self.name)) + else: + raise # re-raise exception if a different error occurred + + @classmethod + def controls_location(cls, location): + """ + Check if a location is controlled by the vcs. + It is meant to be overridden to implement smarter detection + mechanisms for specific vcs. + """ + logger.debug('Checking in %s for %s (%s)...', + location, cls.dirname, cls.name) + path = os.path.join(location, cls.dirname) + return os.path.exists(path) + + +def get_src_requirement(dist, location): + version_control = vcs.get_backend_from_location(location) + if version_control: + try: + return version_control().get_src_requirement(dist, + location) + except BadCommand: + logger.warning( + 'cannot determine version of editable source in %s ' + '(%s command not found in path)', + location, + version_control.name, + ) + return dist.as_requirement() + logger.warning( + 'cannot determine version of editable source in %s (is not SVN ' + 'checkout, Git clone, Mercurial clone or Bazaar branch)', + location, + ) + return dist.as_requirement() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py new file mode 100755 index 0000000..6ed629a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py @@ -0,0 +1,113 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.download import path_to_url +from pip._internal.utils.misc import display_path, rmtree +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +logger = logging.getLogger(__name__) + + +class Bazaar(VersionControl): + name = 'bzr' + dirname = '.bzr' + repo_name = 'branch' + schemes = ( + 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', + 'bzr+lp', + ) + + def __init__(self, url=None, *args, **kwargs): + super(Bazaar, self).__init__(url, *args, **kwargs) + # This is only needed for python <2.7.5 + # Register lp but do not expose as a scheme to support bzr+lp. + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(['lp']) + + def get_base_rev_args(self, rev): + return ['-r', rev] + + def export(self, location): + """ + Export the Bazaar repository at the url to the destination location + """ + # Remove the location to make sure Bazaar can export it correctly + if os.path.exists(location): + rmtree(location) + + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + + self.run_command( + ['export', location], + cwd=temp_dir.path, show_stdout=False, + ) + + def switch(self, dest, url, rev_options): + self.run_command(['switch', url], cwd=dest) + + def update(self, dest, rev_options): + cmd_args = ['pull', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = ['branch', '-q'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def get_url_rev(self): + # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it + url, rev = super(Bazaar, self).get_url_rev() + if url.startswith('ssh://'): + url = 'bzr+' + url + return url, rev + + def get_url(self, location): + urls = self.run_command(['info'], show_stdout=False, cwd=location) + for line in urls.splitlines(): + line = line.strip() + for x in ('checkout of branch: ', + 'parent branch: '): + if line.startswith(x): + repo = line.split(x)[1] + if self._is_local_repository(repo): + return path_to_url(repo) + return repo + return None + + def get_revision(self, location): + revision = self.run_command( + ['revno'], show_stdout=False, cwd=location, + ) + return revision.splitlines()[-1] + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo: + return None + if not repo.lower().startswith('bzr:'): + repo = 'bzr+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + current_rev = self.get_revision(location) + return '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + +vcs.register(Bazaar) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py new file mode 100755 index 0000000..7a63dfa --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py @@ -0,0 +1,311 @@ +from __future__ import absolute_import + +import logging +import os.path +import re + +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.compat import samefile +from pip._internal.exceptions import BadCommand +from pip._internal.utils.misc import display_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +urlsplit = urllib_parse.urlsplit +urlunsplit = urllib_parse.urlunsplit + + +logger = logging.getLogger(__name__) + + +HASH_REGEX = re.compile('[a-fA-F0-9]{40}') + + +def looks_like_hash(sha): + return bool(HASH_REGEX.match(sha)) + + +class Git(VersionControl): + name = 'git' + dirname = '.git' + repo_name = 'clone' + schemes = ( + 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', + ) + # Prevent the user's environment variables from interfering with pip: + # https://github.com/pypa/pip/issues/1130 + unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') + default_arg_rev = 'HEAD' + + def __init__(self, url=None, *args, **kwargs): + + # Works around an apparent Git bug + # (see http://article.gmane.org/gmane.comp.version-control.git/146500) + if url: + scheme, netloc, path, query, fragment = urlsplit(url) + if scheme.endswith('file'): + initial_slashes = path[:-len(path.lstrip('/'))] + newpath = ( + initial_slashes + + urllib_request.url2pathname(path) + .replace('\\', '/').lstrip('/') + ) + url = urlunsplit((scheme, netloc, newpath, query, fragment)) + after_plus = scheme.find('+') + 1 + url = scheme[:after_plus] + urlunsplit( + (scheme[after_plus:], netloc, newpath, query, fragment), + ) + + super(Git, self).__init__(url, *args, **kwargs) + + def get_base_rev_args(self, rev): + return [rev] + + def get_git_version(self): + VERSION_PFX = 'git version ' + version = self.run_command(['version'], show_stdout=False) + if version.startswith(VERSION_PFX): + version = version[len(VERSION_PFX):].split()[0] + else: + version = '' + # get first 3 positions of the git version becasue + # on windows it is x.y.z.windows.t, and this parses as + # LegacyVersion which always smaller than a Version. + version = '.'.join(version.split('.')[:3]) + return parse_version(version) + + def export(self, location): + """Export the Git repository at the url to the destination location""" + if not location.endswith('/'): + location = location + '/' + + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + self.run_command( + ['checkout-index', '-a', '-f', '--prefix', location], + show_stdout=False, cwd=temp_dir.path + ) + + def get_revision_sha(self, dest, rev): + """ + Return a commit hash for the given revision if it names a remote + branch or tag. Otherwise, return None. + + Args: + dest: the repository directory. + rev: the revision name. + """ + # Pass rev to pre-filter the list. + output = self.run_command(['show-ref', rev], cwd=dest, + show_stdout=False, on_returncode='ignore') + refs = {} + for line in output.strip().splitlines(): + try: + sha, ref = line.split() + except ValueError: + # Include the offending line to simplify troubleshooting if + # this error ever occurs. + raise ValueError('unexpected show-ref line: {!r}'.format(line)) + + refs[ref] = sha + + branch_ref = 'refs/remotes/origin/{}'.format(rev) + tag_ref = 'refs/tags/{}'.format(rev) + + return refs.get(branch_ref) or refs.get(tag_ref) + + def check_rev_options(self, dest, rev_options): + """Check the revision options before checkout. + + Returns a new RevOptions object for the SHA1 of the branch or tag + if found. + + Args: + rev_options: a RevOptions object. + """ + rev = rev_options.arg_rev + sha = self.get_revision_sha(dest, rev) + + if sha is not None: + return rev_options.make_new(sha) + + # Do not show a warning for the common case of something that has + # the form of a Git commit hash. + if not looks_like_hash(rev): + logger.warning( + "Did not find branch or tag '%s', assuming revision or ref.", + rev, + ) + return rev_options + + def is_commit_id_equal(self, dest, name): + """ + Return whether the current commit hash equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + if not name: + # Then avoid an unnecessary subprocess call. + return False + + return self.get_revision(dest) == name + + def switch(self, dest, url, rev_options): + self.run_command(['config', 'remote.origin.url', url], cwd=dest) + cmd_args = ['checkout', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + self.update_submodules(dest) + + def update(self, dest, rev_options): + # First fetch changes from the default remote + if self.get_git_version() >= parse_version('1.9.0'): + # fetch tags in addition to everything else + self.run_command(['fetch', '-q', '--tags'], cwd=dest) + else: + self.run_command(['fetch', '-q'], cwd=dest) + # Then reset to wanted revision (maybe even origin/master) + rev_options = self.check_rev_options(dest, rev_options) + cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + #: update submodules + self.update_submodules(dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Cloning %s%s to %s', url, rev_display, display_path(dest), + ) + self.run_command(['clone', '-q', url, dest]) + + if rev: + rev_options = self.check_rev_options(dest, rev_options) + # Only do a checkout if the current commit id doesn't match + # the requested revision. + if not self.is_commit_id_equal(dest, rev_options.rev): + rev = rev_options.rev + # Only fetch the revision if it's a ref + if rev.startswith('refs/'): + self.run_command( + ['fetch', '-q', url] + rev_options.to_args(), + cwd=dest, + ) + # Change the revision to the SHA of the ref we fetched + rev = 'FETCH_HEAD' + self.run_command(['checkout', '-q', rev], cwd=dest) + + #: repo may contain submodules + self.update_submodules(dest) + + def get_url(self, location): + """Return URL of the first remote encountered.""" + remotes = self.run_command( + ['config', '--get-regexp', r'remote\..*\.url'], + show_stdout=False, cwd=location, + ) + remotes = remotes.splitlines() + found_remote = remotes[0] + for remote in remotes: + if remote.startswith('remote.origin.url '): + found_remote = remote + break + url = found_remote.split(' ')[1] + return url.strip() + + def get_revision(self, location): + current_rev = self.run_command( + ['rev-parse', 'HEAD'], show_stdout=False, cwd=location, + ) + return current_rev.strip() + + def _get_subdirectory(self, location): + """Return the relative path of setup.py to the git repo root.""" + # find the repo root + git_dir = self.run_command(['rev-parse', '--git-dir'], + show_stdout=False, cwd=location).strip() + if not os.path.isabs(git_dir): + git_dir = os.path.join(location, git_dir) + root_dir = os.path.join(git_dir, '..') + # find setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + # relative path of setup.py to repo root + if samefile(root_dir, location): + return None + return os.path.relpath(location, root_dir) + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo.lower().startswith('git:'): + repo = 'git+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev = self.get_revision(location) + req = '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) + subdirectory = self._get_subdirectory(location) + if subdirectory: + req += '&subdirectory=' + subdirectory + return req + + def get_url_rev(self): + """ + Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. + That's required because although they use SSH they sometimes doesn't + work with a ssh:// scheme (e.g. Github). But we need a scheme for + parsing. Hence we remove it again afterwards and return it as a stub. + """ + if '://' not in self.url: + assert 'file:' not in self.url + self.url = self.url.replace('git+', 'git+ssh://') + url, rev = super(Git, self).get_url_rev() + url = url.replace('ssh://', '') + else: + url, rev = super(Git, self).get_url_rev() + + return url, rev + + def update_submodules(self, location): + if not os.path.exists(os.path.join(location, '.gitmodules')): + return + self.run_command( + ['submodule', 'update', '--init', '--recursive', '-q'], + cwd=location, + ) + + @classmethod + def controls_location(cls, location): + if super(Git, cls).controls_location(location): + return True + try: + r = cls().run_command(['rev-parse'], + cwd=location, + show_stdout=False, + on_returncode='ignore') + return not r + except BadCommand: + logger.debug("could not determine if %s is under git control " + "because git is not available", location) + return False + + +vcs.register(Git) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py new file mode 100755 index 0000000..3936473 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py @@ -0,0 +1,105 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves import configparser + +from pip._internal.download import path_to_url +from pip._internal.utils.misc import display_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +logger = logging.getLogger(__name__) + + +class Mercurial(VersionControl): + name = 'hg' + dirname = '.hg' + repo_name = 'clone' + schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http') + + def get_base_rev_args(self, rev): + return [rev] + + def export(self, location): + """Export the Hg repository at the url to the destination location""" + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + + self.run_command( + ['archive', location], show_stdout=False, cwd=temp_dir.path + ) + + def switch(self, dest, url, rev_options): + repo_config = os.path.join(dest, self.dirname, 'hgrc') + config = configparser.SafeConfigParser() + try: + config.read(repo_config) + config.set('paths', 'default', url) + with open(repo_config, 'w') as config_file: + config.write(config_file) + except (OSError, configparser.NoSectionError) as exc: + logger.warning( + 'Could not switch Mercurial repository to %s: %s', url, exc, + ) + else: + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def update(self, dest, rev_options): + self.run_command(['pull', '-q'], cwd=dest) + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Cloning hg %s%s to %s', + url, + rev_display, + display_path(dest), + ) + self.run_command(['clone', '--noupdate', '-q', url, dest]) + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def get_url(self, location): + url = self.run_command( + ['showconfig', 'paths.default'], + show_stdout=False, cwd=location).strip() + if self._is_local_repository(url): + url = path_to_url(url) + return url.strip() + + def get_revision(self, location): + current_revision = self.run_command( + ['parents', '--template={rev}'], + show_stdout=False, cwd=location).strip() + return current_revision + + def get_revision_hash(self, location): + current_rev_hash = self.run_command( + ['parents', '--template={node}'], + show_stdout=False, cwd=location).strip() + return current_rev_hash + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo.lower().startswith('hg:'): + repo = 'hg+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev_hash = self.get_revision_hash(location) + return '%s@%s#egg=%s' % (repo, current_rev_hash, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + +vcs.register(Mercurial) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py new file mode 100755 index 0000000..95e5440 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py @@ -0,0 +1,271 @@ +from __future__ import absolute_import + +import logging +import os +import re + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.index import Link +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import display_path, rmtree +from pip._internal.vcs import VersionControl, vcs + +_svn_xml_url_re = re.compile('url="([^"]+)"') +_svn_rev_re = re.compile(r'committed-rev="(\d+)"') +_svn_url_re = re.compile(r'URL: (.+)') +_svn_revision_re = re.compile(r'Revision: (.+)') +_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') +_svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') + + +logger = logging.getLogger(__name__) + + +class Subversion(VersionControl): + name = 'svn' + dirname = '.svn' + repo_name = 'checkout' + schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') + + def get_base_rev_args(self, rev): + return ['-r', rev] + + def get_info(self, location): + """Returns (url, revision), where both are strings""" + assert not location.rstrip('/').endswith(self.dirname), \ + 'Bad directory: %s' % location + output = self.run_command( + ['info', location], + show_stdout=False, + extra_environ={'LANG': 'C'}, + ) + match = _svn_url_re.search(output) + if not match: + logger.warning( + 'Cannot determine URL of svn checkout %s', + display_path(location), + ) + logger.debug('Output that cannot be parsed: \n%s', output) + return None, None + url = match.group(1).strip() + match = _svn_revision_re.search(output) + if not match: + logger.warning( + 'Cannot determine revision of svn checkout %s', + display_path(location), + ) + logger.debug('Output that cannot be parsed: \n%s', output) + return url, None + return url, match.group(1) + + def export(self, location): + """Export the svn repository at the url to the destination location""" + url, rev = self.get_url_rev() + rev_options = get_rev_options(self, url, rev) + url = self.remove_auth_from_url(url) + logger.info('Exporting svn repository %s to %s', url, location) + with indent_log(): + if os.path.exists(location): + # Subversion doesn't like to check out over an existing + # directory --force fixes this, but was only added in svn 1.5 + rmtree(location) + cmd_args = ['export'] + rev_options.to_args() + [url, location] + self.run_command(cmd_args, show_stdout=False) + + def switch(self, dest, url, rev_options): + cmd_args = ['switch'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def update(self, dest, rev_options): + cmd_args = ['update'] + rev_options.to_args() + [dest] + self.run_command(cmd_args) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = get_rev_options(self, url, rev) + url = self.remove_auth_from_url(url) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = ['checkout', '-q'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def get_location(self, dist, dependency_links): + for url in dependency_links: + egg_fragment = Link(url).egg_fragment + if not egg_fragment: + continue + if '-' in egg_fragment: + # FIXME: will this work when a package has - in the name? + key = '-'.join(egg_fragment.split('-')[:-1]).lower() + else: + key = egg_fragment + if key == dist.key: + return url.split('#', 1)[0] + return None + + def get_revision(self, location): + """ + Return the maximum revision for all files under a given location + """ + # Note: taken from setuptools.command.egg_info + revision = 0 + + for base, dirs, files in os.walk(location): + if self.dirname not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove(self.dirname) + entries_fn = os.path.join(base, self.dirname, 'entries') + if not os.path.exists(entries_fn): + # FIXME: should we warn? + continue + + dirurl, localrev = self._get_svn_url_rev(base) + + if base == location: + base = dirurl + '/' # save the root url + elif not dirurl or not dirurl.startswith(base): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + return revision + + def get_url_rev(self): + # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it + url, rev = super(Subversion, self).get_url_rev() + if url.startswith('ssh://'): + url = 'svn+' + url + return url, rev + + def get_url(self, location): + # In cases where the source is in a subdirectory, not alongside + # setup.py we have to look up in the location until we find a real + # setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + + return self._get_svn_url_rev(location)[0] + + def _get_svn_url_rev(self, location): + from pip._internal.exceptions import InstallationError + + entries_path = os.path.join(location, self.dirname, 'entries') + if os.path.exists(entries_path): + with open(entries_path) as f: + data = f.read() + else: # subversion >= 1.7 does not have the 'entries' file + data = '' + + if (data.startswith('8') or + data.startswith('9') or + data.startswith('10')): + data = list(map(str.splitlines, data.split('\n\x0c\n'))) + del data[0][0] # get rid of the '8' + url = data[0][3] + revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] + elif data.startswith('<?xml'): + match = _svn_xml_url_re.search(data) + if not match: + raise ValueError('Badly formatted data: %r' % data) + url = match.group(1) # get repository URL + revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)] + [0] + else: + try: + # subversion >= 1.7 + xml = self.run_command( + ['info', '--xml', location], + show_stdout=False, + ) + url = _svn_info_xml_url_re.search(xml).group(1) + revs = [ + int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) + ] + except InstallationError: + url, revs = None, [] + + if revs: + rev = max(revs) + else: + rev = 0 + + return url, rev + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if repo is None: + return None + # FIXME: why not project name? + egg_project_name = dist.egg_name().split('-', 1)[0] + rev = self.get_revision(location) + return 'svn+%s@%s#egg=%s' % (repo, rev, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + @staticmethod + def remove_auth_from_url(url): + # Return a copy of url with 'username:password@' removed. + # username/pass params are passed to subversion through flags + # and are not recognized in the url. + + # parsed url + purl = urllib_parse.urlsplit(url) + stripped_netloc = \ + purl.netloc.split('@')[-1] + + # stripped url + url_pieces = ( + purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment + ) + surl = urllib_parse.urlunsplit(url_pieces) + return surl + + +def get_rev_options(vcs, url, rev): + """ + Return a RevOptions object. + """ + r = urllib_parse.urlsplit(url) + if hasattr(r, 'username'): + # >= Python-2.5 + username, password = r.username, r.password + else: + netloc = r[1] + if '@' in netloc: + auth = netloc.split('@')[0] + if ':' in auth: + username, password = auth.split(':', 1) + else: + username, password = auth, None + else: + username, password = None, None + + extra_args = [] + if username: + extra_args += ['--username', username] + if password: + extra_args += ['--password', password] + + return vcs.make_rev_options(rev, extra_args=extra_args) + + +vcs.register(Subversion) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py new file mode 100755 index 0000000..36459dd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py @@ -0,0 +1,817 @@ +""" +Support for installing and building the "wheel" binary package format. +""" +from __future__ import absolute_import + +import collections +import compileall +import copy +import csv +import hashlib +import logging +import os.path +import re +import shutil +import stat +import sys +import warnings +from base64 import urlsafe_b64encode +from email.parser import Parser + +from pip._vendor import pkg_resources +from pip._vendor.distlib.scripts import ScriptMaker +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.six import StringIO + +from pip._internal import pep425tags +from pip._internal.build_env import BuildEnvironment +from pip._internal.download import path_to_url, unpack_url +from pip._internal.exceptions import ( + InstallationError, InvalidWheelFilename, UnsupportedWheel, +) +from pip._internal.locations import ( + PIP_DELETE_MARKER_FILENAME, distutils_scheme, +) +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + call_subprocess, captured_stdout, ensure_dir, read_chunks, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.ui import open_spinner + +if MYPY_CHECK_RUNNING: + from typing import Dict, List, Optional + +wheel_ext = '.whl' + +VERSION_COMPATIBLE = (1, 0) + + +logger = logging.getLogger(__name__) + + +def rehash(path, algo='sha256', blocksize=1 << 20): + """Return (hash, length) for path using hashlib.new(algo)""" + h = hashlib.new(algo) + length = 0 + with open(path, 'rb') as f: + for block in read_chunks(f, size=blocksize): + length += len(block) + h.update(block) + digest = 'sha256=' + urlsafe_b64encode( + h.digest() + ).decode('latin1').rstrip('=') + return (digest, length) + + +def open_for_csv(name, mode): + if sys.version_info[0] < 3: + nl = {} + bin = 'b' + else: + nl = {'newline': ''} + bin = '' + return open(name, mode + bin, **nl) + + +def fix_script(path): + """Replace #!python with #!/path/to/python + Return True if file was changed.""" + # XXX RECORD hashes will need to be updated + if os.path.isfile(path): + with open(path, 'rb') as script: + firstline = script.readline() + if not firstline.startswith(b'#!python'): + return False + exename = sys.executable.encode(sys.getfilesystemencoding()) + firstline = b'#!' + exename + os.linesep.encode("ascii") + rest = script.read() + with open(path, 'wb') as script: + script.write(firstline) + script.write(rest) + return True + + +dist_info_re = re.compile(r"""^(?P<namever>(?P<name>.+?)(-(?P<ver>.+?))?) + \.dist-info$""", re.VERBOSE) + + +def root_is_purelib(name, wheeldir): + """ + Return True if the extracted wheel in wheeldir should go into purelib. + """ + name_folded = name.replace("-", "_") + for item in os.listdir(wheeldir): + match = dist_info_re.match(item) + if match and match.group('name') == name_folded: + with open(os.path.join(wheeldir, item, 'WHEEL')) as wheel: + for line in wheel: + line = line.lower().rstrip() + if line == "root-is-purelib: true": + return True + return False + + +def get_entrypoints(filename): + if not os.path.exists(filename): + return {}, {} + + # This is done because you can pass a string to entry_points wrappers which + # means that they may or may not be valid INI files. The attempt here is to + # strip leading and trailing whitespace in order to make them valid INI + # files. + with open(filename) as fp: + data = StringIO() + for line in fp: + data.write(line.strip()) + data.write("\n") + data.seek(0) + + # get the entry points and then the script names + entry_points = pkg_resources.EntryPoint.parse_map(data) + console = entry_points.get('console_scripts', {}) + gui = entry_points.get('gui_scripts', {}) + + def _split_ep(s): + """get the string representation of EntryPoint, remove space and split + on '='""" + return str(s).replace(" ", "").split("=") + + # convert the EntryPoint objects into strings with module:function + console = dict(_split_ep(v) for v in console.values()) + gui = dict(_split_ep(v) for v in gui.values()) + return console, gui + + +def message_about_scripts_not_on_PATH(scripts): + # type: (List[str]) -> Optional[str] + """Determine if any scripts are not on PATH and format a warning. + + Returns a warning message if one or more scripts are not on PATH, + otherwise None. + """ + if not scripts: + return None + + # Group scripts by the path they were installed in + grouped_by_dir = collections.defaultdict(set) # type: Dict[str, set] + for destfile in scripts: + parent_dir = os.path.dirname(destfile) + script_name = os.path.basename(destfile) + grouped_by_dir[parent_dir].add(script_name) + + # We don't want to warn for directories that are on PATH. + not_warn_dirs = [ + os.path.normcase(i) for i in os.environ["PATH"].split(os.pathsep) + ] + # If an executable sits with sys.executable, we don't warn for it. + # This covers the case of venv invocations without activating the venv. + not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) + warn_for = { + parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() + if os.path.normcase(parent_dir) not in not_warn_dirs + } + if not warn_for: + return None + + # Format a message + msg_lines = [] + for parent_dir, scripts in warn_for.items(): + scripts = sorted(scripts) + if len(scripts) == 1: + start_text = "script {} is".format(scripts[0]) + else: + start_text = "scripts {} are".format( + ", ".join(scripts[:-1]) + " and " + scripts[-1] + ) + + msg_lines.append( + "The {} installed in '{}' which is not on PATH." + .format(start_text, parent_dir) + ) + + last_line_fmt = ( + "Consider adding {} to PATH or, if you prefer " + "to suppress this warning, use --no-warn-script-location." + ) + if len(msg_lines) == 1: + msg_lines.append(last_line_fmt.format("this directory")) + else: + msg_lines.append(last_line_fmt.format("these directories")) + + # Returns the formatted multiline message + return "\n".join(msg_lines) + + +def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, + pycompile=True, scheme=None, isolated=False, prefix=None, + warn_script_location=True): + """Install a wheel""" + + if not scheme: + scheme = distutils_scheme( + name, user=user, home=home, root=root, isolated=isolated, + prefix=prefix, + ) + + if root_is_purelib(name, wheeldir): + lib_dir = scheme['purelib'] + else: + lib_dir = scheme['platlib'] + + info_dir = [] + data_dirs = [] + source = wheeldir.rstrip(os.path.sep) + os.path.sep + + # Record details of the files moved + # installed = files copied from the wheel to the destination + # changed = files changed while installing (scripts #! line typically) + # generated = files newly generated during the install (script wrappers) + installed = {} + changed = set() + generated = [] + + # Compile all of the pyc files that we're going to be installing + if pycompile: + with captured_stdout() as stdout: + with warnings.catch_warnings(): + warnings.filterwarnings('ignore') + compileall.compile_dir(source, force=True, quiet=True) + logger.debug(stdout.getvalue()) + + def normpath(src, p): + return os.path.relpath(src, p).replace(os.path.sep, '/') + + def record_installed(srcfile, destfile, modified=False): + """Map archive RECORD paths to installation RECORD paths.""" + oldpath = normpath(srcfile, wheeldir) + newpath = normpath(destfile, lib_dir) + installed[oldpath] = newpath + if modified: + changed.add(destfile) + + def clobber(source, dest, is_base, fixer=None, filter=None): + ensure_dir(dest) # common for the 'include' path + + for dir, subdirs, files in os.walk(source): + basedir = dir[len(source):].lstrip(os.path.sep) + destdir = os.path.join(dest, basedir) + if is_base and basedir.split(os.path.sep, 1)[0].endswith('.data'): + continue + for s in subdirs: + destsubdir = os.path.join(dest, basedir, s) + if is_base and basedir == '' and destsubdir.endswith('.data'): + data_dirs.append(s) + continue + elif (is_base and + s.endswith('.dist-info') and + canonicalize_name(s).startswith( + canonicalize_name(req.name))): + assert not info_dir, ('Multiple .dist-info directories: ' + + destsubdir + ', ' + + ', '.join(info_dir)) + info_dir.append(destsubdir) + for f in files: + # Skip unwanted files + if filter and filter(f): + continue + srcfile = os.path.join(dir, f) + destfile = os.path.join(dest, basedir, f) + # directory creation is lazy and after the file filtering above + # to ensure we don't install empty dirs; empty dirs can't be + # uninstalled. + ensure_dir(destdir) + + # We use copyfile (not move, copy, or copy2) to be extra sure + # that we are not moving directories over (copyfile fails for + # directories) as well as to ensure that we are not copying + # over any metadata because we want more control over what + # metadata we actually copy over. + shutil.copyfile(srcfile, destfile) + + # Copy over the metadata for the file, currently this only + # includes the atime and mtime. + st = os.stat(srcfile) + if hasattr(os, "utime"): + os.utime(destfile, (st.st_atime, st.st_mtime)) + + # If our file is executable, then make our destination file + # executable. + if os.access(srcfile, os.X_OK): + st = os.stat(srcfile) + permissions = ( + st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + ) + os.chmod(destfile, permissions) + + changed = False + if fixer: + changed = fixer(destfile) + record_installed(srcfile, destfile, changed) + + clobber(source, lib_dir, True) + + assert info_dir, "%s .dist-info directory not found" % req + + # Get the defined entry points + ep_file = os.path.join(info_dir[0], 'entry_points.txt') + console, gui = get_entrypoints(ep_file) + + def is_entrypoint_wrapper(name): + # EP, EP.exe and EP-script.py are scripts generated for + # entry point EP by setuptools + if name.lower().endswith('.exe'): + matchname = name[:-4] + elif name.lower().endswith('-script.py'): + matchname = name[:-10] + elif name.lower().endswith(".pya"): + matchname = name[:-4] + else: + matchname = name + # Ignore setuptools-generated scripts + return (matchname in console or matchname in gui) + + for datadir in data_dirs: + fixer = None + filter = None + for subdir in os.listdir(os.path.join(wheeldir, datadir)): + fixer = None + if subdir == 'scripts': + fixer = fix_script + filter = is_entrypoint_wrapper + source = os.path.join(wheeldir, datadir, subdir) + dest = scheme[subdir] + clobber(source, dest, False, fixer=fixer, filter=filter) + + maker = ScriptMaker(None, scheme['scripts']) + + # Ensure old scripts are overwritten. + # See https://github.com/pypa/pip/issues/1800 + maker.clobber = True + + # Ensure we don't generate any variants for scripts because this is almost + # never what somebody wants. + # See https://bitbucket.org/pypa/distlib/issue/35/ + maker.variants = {''} + + # This is required because otherwise distlib creates scripts that are not + # executable. + # See https://bitbucket.org/pypa/distlib/issue/32/ + maker.set_mode = True + + # Simplify the script and fix the fact that the default script swallows + # every single stack trace. + # See https://bitbucket.org/pypa/distlib/issue/34/ + # See https://bitbucket.org/pypa/distlib/issue/33/ + def _get_script_text(entry): + if entry.suffix is None: + raise InstallationError( + "Invalid script entry point: %s for req: %s - A callable " + "suffix is required. Cf https://packaging.python.org/en/" + "latest/distributing.html#console-scripts for more " + "information." % (entry, req) + ) + return maker.script_template % { + "module": entry.prefix, + "import_name": entry.suffix.split(".")[0], + "func": entry.suffix, + } + + maker._get_script_text = _get_script_text + maker.script_template = r"""# -*- coding: utf-8 -*- +import re +import sys + +from %(module)s import %(import_name)s + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(%(func)s()) +""" + + # Special case pip and setuptools to generate versioned wrappers + # + # The issue is that some projects (specifically, pip and setuptools) use + # code in setup.py to create "versioned" entry points - pip2.7 on Python + # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into + # the wheel metadata at build time, and so if the wheel is installed with + # a *different* version of Python the entry points will be wrong. The + # correct fix for this is to enhance the metadata to be able to describe + # such versioned entry points, but that won't happen till Metadata 2.0 is + # available. + # In the meantime, projects using versioned entry points will either have + # incorrect versioned entry points, or they will not be able to distribute + # "universal" wheels (i.e., they will need a wheel per Python version). + # + # Because setuptools and pip are bundled with _ensurepip and virtualenv, + # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we + # override the versioned entry points in the wheel and generate the + # correct ones. This code is purely a short-term measure until Metadata 2.0 + # is available. + # + # To add the level of hack in this section of code, in order to support + # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment + # variable which will control which version scripts get installed. + # + # ENSUREPIP_OPTIONS=altinstall + # - Only pipX.Y and easy_install-X.Y will be generated and installed + # ENSUREPIP_OPTIONS=install + # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note + # that this option is technically if ENSUREPIP_OPTIONS is set and is + # not altinstall + # DEFAULT + # - The default behavior is to install pip, pipX, pipX.Y, easy_install + # and easy_install-X.Y. + pip_script = console.pop('pip', None) + if pip_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + spec = 'pip = ' + pip_script + generated.extend(maker.make(spec)) + + if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": + spec = 'pip%s = %s' % (sys.version[:1], pip_script) + generated.extend(maker.make(spec)) + + spec = 'pip%s = %s' % (sys.version[:3], pip_script) + generated.extend(maker.make(spec)) + # Delete any other versioned pip entry points + pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] + for k in pip_ep: + del console[k] + easy_install_script = console.pop('easy_install', None) + if easy_install_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + spec = 'easy_install = ' + easy_install_script + generated.extend(maker.make(spec)) + + spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script) + generated.extend(maker.make(spec)) + # Delete any other versioned easy_install entry points + easy_install_ep = [ + k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) + ] + for k in easy_install_ep: + del console[k] + + # Generate the console and GUI entry points specified in the wheel + if len(console) > 0: + generated_console_scripts = maker.make_multiple( + ['%s = %s' % kv for kv in console.items()] + ) + generated.extend(generated_console_scripts) + + if warn_script_location: + msg = message_about_scripts_not_on_PATH(generated_console_scripts) + if msg is not None: + logger.warn(msg) + + if len(gui) > 0: + generated.extend( + maker.make_multiple( + ['%s = %s' % kv for kv in gui.items()], + {'gui': True} + ) + ) + + # Record pip as the installer + installer = os.path.join(info_dir[0], 'INSTALLER') + temp_installer = os.path.join(info_dir[0], 'INSTALLER.pip') + with open(temp_installer, 'wb') as installer_file: + installer_file.write(b'pip\n') + shutil.move(temp_installer, installer) + generated.append(installer) + + # Record details of all files installed + record = os.path.join(info_dir[0], 'RECORD') + temp_record = os.path.join(info_dir[0], 'RECORD.pip') + with open_for_csv(record, 'r') as record_in: + with open_for_csv(temp_record, 'w+') as record_out: + reader = csv.reader(record_in) + writer = csv.writer(record_out) + for row in reader: + row[0] = installed.pop(row[0], row[0]) + if row[0] in changed: + row[1], row[2] = rehash(row[0]) + writer.writerow(row) + for f in generated: + h, l = rehash(f) + writer.writerow((normpath(f, lib_dir), h, l)) + for f in installed: + writer.writerow((installed[f], '', '')) + shutil.move(temp_record, record) + + +def wheel_version(source_dir): + """ + Return the Wheel-Version of an extracted wheel, if possible. + + Otherwise, return False if we couldn't parse / extract it. + """ + try: + dist = [d for d in pkg_resources.find_on_path(None, source_dir)][0] + + wheel_data = dist.get_metadata('WHEEL') + wheel_data = Parser().parsestr(wheel_data) + + version = wheel_data['Wheel-Version'].strip() + version = tuple(map(int, version.split('.'))) + return version + except: + return False + + +def check_compatibility(version, name): + """ + Raises errors or warns if called with an incompatible Wheel-Version. + + Pip should refuse to install a Wheel-Version that's a major series + ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when + installing a version only minor version ahead (e.g 1.2 > 1.1). + + version: a 2-tuple representing a Wheel-Version (Major, Minor) + name: name of wheel or package to raise exception about + + :raises UnsupportedWheel: when an incompatible Wheel-Version is given + """ + if not version: + raise UnsupportedWheel( + "%s is in an unsupported or invalid wheel" % name + ) + if version[0] > VERSION_COMPATIBLE[0]: + raise UnsupportedWheel( + "%s's Wheel-Version (%s) is not compatible with this version " + "of pip" % (name, '.'.join(map(str, version))) + ) + elif version > VERSION_COMPATIBLE: + logger.warning( + 'Installing from a newer Wheel-Version (%s)', + '.'.join(map(str, version)), + ) + + +class Wheel(object): + """A wheel file""" + + # TODO: maybe move the install code into this class + + wheel_file_re = re.compile( + r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) + ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) + \.whl|\.dist-info)$""", + re.VERBOSE + ) + + def __init__(self, filename): + """ + :raises InvalidWheelFilename: when the filename is invalid for a wheel + """ + wheel_info = self.wheel_file_re.match(filename) + if not wheel_info: + raise InvalidWheelFilename( + "%s is not a valid wheel filename." % filename + ) + self.filename = filename + self.name = wheel_info.group('name').replace('_', '-') + # we'll assume "_" means "-" due to wheel naming scheme + # (https://github.com/pypa/pip/issues/1150) + self.version = wheel_info.group('ver').replace('_', '-') + self.build_tag = wheel_info.group('build') + self.pyversions = wheel_info.group('pyver').split('.') + self.abis = wheel_info.group('abi').split('.') + self.plats = wheel_info.group('plat').split('.') + + # All the tag combinations from this file + self.file_tags = { + (x, y, z) for x in self.pyversions + for y in self.abis for z in self.plats + } + + def support_index_min(self, tags=None): + """ + Return the lowest index that one of the wheel's file_tag combinations + achieves in the supported_tags list e.g. if there are 8 supported tags, + and one of the file tags is first in the list, then return 0. Returns + None is the wheel is not supported. + """ + if tags is None: # for mock + tags = pep425tags.get_supported() + indexes = [tags.index(c) for c in self.file_tags if c in tags] + return min(indexes) if indexes else None + + def supported(self, tags=None): + """Is this wheel supported on this system?""" + if tags is None: # for mock + tags = pep425tags.get_supported() + return bool(set(tags).intersection(self.file_tags)) + + +class WheelBuilder(object): + """Build wheels from a RequirementSet.""" + + def __init__(self, finder, preparer, wheel_cache, + build_options=None, global_options=None, no_clean=False): + self.finder = finder + self.preparer = preparer + self.wheel_cache = wheel_cache + + self._wheel_dir = preparer.wheel_download_dir + + self.build_options = build_options or [] + self.global_options = global_options or [] + self.no_clean = no_clean + + def _build_one(self, req, output_dir, python_tag=None): + """Build one wheel. + + :return: The filename of the built wheel, or None if the build failed. + """ + # Install build deps into temporary directory (PEP 518) + with req.build_env: + return self._build_one_inside_env(req, output_dir, + python_tag=python_tag) + + def _build_one_inside_env(self, req, output_dir, python_tag=None): + with TempDirectory(kind="wheel") as temp_dir: + if self.__build_one(req, temp_dir.path, python_tag=python_tag): + try: + wheel_name = os.listdir(temp_dir.path)[0] + wheel_path = os.path.join(output_dir, wheel_name) + shutil.move( + os.path.join(temp_dir.path, wheel_name), wheel_path + ) + logger.info('Stored in directory: %s', output_dir) + return wheel_path + except: + pass + # Ignore return, we can't do anything else useful. + self._clean_one(req) + return None + + def _base_setup_args(self, req): + # NOTE: Eventually, we'd want to also -S to the flags here, when we're + # isolating. Currently, it breaks Python in virtualenvs, because it + # relies on site.py to find parts of the standard library outside the + # virtualenv. + return [ + sys.executable, '-u', '-c', + SETUPTOOLS_SHIM % req.setup_py + ] + list(self.global_options) + + def __build_one(self, req, tempd, python_tag=None): + base_args = self._base_setup_args(req) + + spin_message = 'Running setup.py bdist_wheel for %s' % (req.name,) + with open_spinner(spin_message) as spinner: + logger.debug('Destination directory: %s', tempd) + wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + + self.build_options + + if python_tag is not None: + wheel_args += ["--python-tag", python_tag] + + try: + call_subprocess(wheel_args, cwd=req.setup_py_dir, + show_stdout=False, spinner=spinner) + return True + except: + spinner.finish("error") + logger.error('Failed building wheel for %s', req.name) + return False + + def _clean_one(self, req): + base_args = self._base_setup_args(req) + + logger.info('Running setup.py clean for %s', req.name) + clean_args = base_args + ['clean', '--all'] + try: + call_subprocess(clean_args, cwd=req.source_dir, show_stdout=False) + return True + except: + logger.error('Failed cleaning build dir for %s', req.name) + return False + + def build(self, requirements, session, autobuilding=False): + """Build wheels. + + :param unpack: If True, replace the sdist we built from with the + newly built wheel, in preparation for installation. + :return: True if all the wheels built correctly. + """ + from pip._internal import index + + building_is_possible = self._wheel_dir or ( + autobuilding and self.wheel_cache.cache_dir + ) + assert building_is_possible + + buildset = [] + for req in requirements: + if req.constraint: + continue + if req.is_wheel: + if not autobuilding: + logger.info( + 'Skipping %s, due to already being wheel.', req.name, + ) + elif autobuilding and req.editable: + pass + elif autobuilding and not req.source_dir: + pass + elif autobuilding and req.link and not req.link.is_artifact: + # VCS checkout. Build wheel just for this run. + buildset.append((req, True)) + else: + ephem_cache = False + if autobuilding: + link = req.link + base, ext = link.splitext() + if index.egg_info_matches(base, None, link) is None: + # E.g. local directory. Build wheel just for this run. + ephem_cache = True + if "binary" not in index.fmt_ctl_formats( + self.finder.format_control, + canonicalize_name(req.name)): + logger.info( + "Skipping bdist_wheel for %s, due to binaries " + "being disabled for it.", req.name, + ) + continue + buildset.append((req, ephem_cache)) + + if not buildset: + return True + + # Build the wheels. + logger.info( + 'Building wheels for collected packages: %s', + ', '.join([req.name for (req, _) in buildset]), + ) + _cache = self.wheel_cache # shorter name + with indent_log(): + build_success, build_failure = [], [] + for req, ephem in buildset: + python_tag = None + if autobuilding: + python_tag = pep425tags.implementation_tag + if ephem: + output_dir = _cache.get_ephem_path_for_link(req.link) + else: + output_dir = _cache.get_path_for_link(req.link) + try: + ensure_dir(output_dir) + except OSError as e: + logger.warning("Building wheel for %s failed: %s", + req.name, e) + build_failure.append(req) + continue + else: + output_dir = self._wheel_dir + wheel_file = self._build_one( + req, output_dir, + python_tag=python_tag, + ) + if wheel_file: + build_success.append(req) + if autobuilding: + # XXX: This is mildly duplicative with prepare_files, + # but not close enough to pull out to a single common + # method. + # The code below assumes temporary source dirs - + # prevent it doing bad things. + if req.source_dir and not os.path.exists(os.path.join( + req.source_dir, PIP_DELETE_MARKER_FILENAME)): + raise AssertionError( + "bad source dir - missing marker") + # Delete the source we built the wheel from + req.remove_temporary_source() + # set the build directory again - name is known from + # the work prepare_files did. + req.source_dir = req.build_location( + self.preparer.build_dir + ) + # Update the link for this. + req.link = index.Link(path_to_url(wheel_file)) + assert req.link.is_wheel + # extract the wheel into the dir + unpack_url( + req.link, req.source_dir, None, False, + session=session, + ) + else: + build_failure.append(req) + + # notify success/failure + if build_success: + logger.info( + 'Successfully built %s', + ' '.join([req.name for req in build_success]), + ) + if build_failure: + logger.info( + 'Failed to build %s', + ' '.join([req.name for req in build_failure]), + ) + # Return True if all builds were successful + return len(build_failure) == 0 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py new file mode 100755 index 0000000..607757f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py @@ -0,0 +1,109 @@ +""" +pip._vendor is for vendoring dependencies of pip to prevent needing pip to +depend on something external. + +Files inside of pip._vendor should be considered immutable and should only be +updated to versions from upstream. +""" +from __future__ import absolute_import + +import glob +import os.path +import sys + +# Downstream redistributors which have debundled our dependencies should also +# patch this value to be true. This will trigger the additional patching +# to cause things like "six" to be available as pip. +DEBUNDLED = False + +# By default, look in this directory for a bunch of .whl files which we will +# add to the beginning of sys.path before attempting to import anything. This +# is done to support downstream re-distributors like Debian and Fedora who +# wish to create their own Wheels for our dependencies to aid in debundling. +WHEEL_DIR = os.path.abspath(os.path.dirname(__file__)) + + +# Define a small helper function to alias our vendored modules to the real ones +# if the vendored ones do not exist. This idea of this was taken from +# https://github.com/kennethreitz/requests/pull/2567. +def vendored(modulename): + vendored_name = "{0}.{1}".format(__name__, modulename) + + try: + __import__(vendored_name, globals(), locals(), level=0) + except ImportError: + try: + __import__(modulename, globals(), locals(), level=0) + except ImportError: + # We can just silently allow import failures to pass here. If we + # got to this point it means that ``import pip._vendor.whatever`` + # failed and so did ``import whatever``. Since we're importing this + # upfront in an attempt to alias imports, not erroring here will + # just mean we get a regular import error whenever pip *actually* + # tries to import one of these modules to use it, which actually + # gives us a better error message than we would have otherwise + # gotten. + pass + else: + sys.modules[vendored_name] = sys.modules[modulename] + base, head = vendored_name.rsplit(".", 1) + setattr(sys.modules[base], head, sys.modules[modulename]) + + +# If we're operating in a debundled setup, then we want to go ahead and trigger +# the aliasing of our vendored libraries as well as looking for wheels to add +# to our sys.path. This will cause all of this code to be a no-op typically +# however downstream redistributors can enable it in a consistent way across +# all platforms. +if DEBUNDLED: + # Actually look inside of WHEEL_DIR to find .whl files and add them to the + # front of our sys.path. + sys.path[:] = glob.glob(os.path.join(WHEEL_DIR, "*.whl")) + sys.path + + # Actually alias all of our vendored dependencies. + vendored("cachecontrol") + vendored("colorama") + vendored("distlib") + vendored("distro") + vendored("html5lib") + vendored("lockfile") + vendored("six") + vendored("six.moves") + vendored("six.moves.urllib") + vendored("six.moves.urllib.parse") + vendored("packaging") + vendored("packaging.version") + vendored("packaging.specifiers") + vendored("pkg_resources") + vendored("progress") + vendored("pytoml") + vendored("retrying") + vendored("requests") + vendored("requests.packages") + vendored("requests.packages.urllib3") + vendored("requests.packages.urllib3._collections") + vendored("requests.packages.urllib3.connection") + vendored("requests.packages.urllib3.connectionpool") + vendored("requests.packages.urllib3.contrib") + vendored("requests.packages.urllib3.contrib.ntlmpool") + vendored("requests.packages.urllib3.contrib.pyopenssl") + vendored("requests.packages.urllib3.exceptions") + vendored("requests.packages.urllib3.fields") + vendored("requests.packages.urllib3.filepost") + vendored("requests.packages.urllib3.packages") + vendored("requests.packages.urllib3.packages.ordered_dict") + vendored("requests.packages.urllib3.packages.six") + vendored("requests.packages.urllib3.packages.ssl_match_hostname") + vendored("requests.packages.urllib3.packages.ssl_match_hostname." + "_implementation") + vendored("requests.packages.urllib3.poolmanager") + vendored("requests.packages.urllib3.request") + vendored("requests.packages.urllib3.response") + vendored("requests.packages.urllib3.util") + vendored("requests.packages.urllib3.util.connection") + vendored("requests.packages.urllib3.util.request") + vendored("requests.packages.urllib3.util.response") + vendored("requests.packages.urllib3.util.retry") + vendored("requests.packages.urllib3.util.ssl_") + vendored("requests.packages.urllib3.util.timeout") + vendored("requests.packages.urllib3.util.url") diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py new file mode 100755 index 0000000..7ff6a07 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py @@ -0,0 +1,604 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2005-2010 ActiveState Software Inc. +# Copyright (c) 2013 Eddy Petrișor + +"""Utilities for determining application-specific dirs. + +See <http://github.com/ActiveState/appdirs> for details and usage. +""" +# Dev Notes: +# - MSDN on where to store app data files: +# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 +# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html +# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +__version_info__ = (1, 4, 3) +__version__ = '.'.join(map(str, __version_info__)) + + +import sys +import os + +PY3 = sys.version_info[0] == 3 + +if PY3: + unicode = str + +if sys.platform.startswith('java'): + import platform + os_name = platform.java_ver()[3][0] + if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. + system = 'win32' + elif os_name.startswith('Mac'): # "Mac OS X", etc. + system = 'darwin' + else: # "Linux", "SunOS", "FreeBSD", etc. + # Setting this to "linux2" is not ideal, but only Windows or Mac + # are actually checked for and the rest of the module expects + # *sys.platform* style strings. + system = 'linux2' +else: + system = sys.platform + + + +def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user data directories are: + Mac OS X: ~/Library/Application Support/<AppName> + Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName> + Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName> + Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName> + Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName> + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/<AppName>". + """ + if system == "win32": + if appauthor is None: + appauthor = appname + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(_get_win_folder(const)) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('~/Library/Application Support/') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of data dirs should be + returned. By default, the first item from XDG_DATA_DIRS is + returned, or '/usr/local/share/<AppName>', + if XDG_DATA_DIRS is not set + + Typical site data directories are: + Mac OS X: /Library/Application Support/<AppName> + Unix: /usr/local/share/<AppName> or /usr/share/<AppName> + Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName> + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7. + + For Unix, this is using the $XDG_DATA_DIRS[0] default. + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('/Library/Application Support') + if appname: + path = os.path.join(path, appname) + else: + # XDG default for $XDG_DATA_DIRS + # only first, if multipath is False + path = os.getenv('XDG_DATA_DIRS', + os.pathsep.join(['/usr/local/share', '/usr/share'])) + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + if appname and version: + path = os.path.join(path, version) + return path + + +def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user config directories are: + Mac OS X: same as user_data_dir + Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/<AppName>". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of config dirs should be + returned. By default, the first item from XDG_CONFIG_DIRS is + returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set + + Typical site config directories are: + Mac OS X: same as site_data_dir + Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in + $XDG_CONFIG_DIRS + Win *: same as site_data_dir + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + + For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system in ["win32", "darwin"]: + path = site_data_dir(appname, appauthor) + if appname and version: + path = os.path.join(path, version) + else: + # XDG default for $XDG_CONFIG_DIRS + # only first, if multipath is False + path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + +def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Cache" to the base app data dir for Windows. See + discussion below. + + Typical user cache directories are: + Mac OS X: ~/Library/Caches/<AppName> + Unix: ~/.cache/<AppName> (XDG default) + Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache + Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go in + the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming + app data dir (the default returned by `user_data_dir` above). Apps typically + put cache data somewhere *under* the given dir here. Some examples: + ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache + ...\Acme\SuperApp\Cache\1.0 + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + This can be disabled with the `opinion=False` option. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + if opinion: + path = os.path.join(path, "Cache") + elif system == 'darwin': + path = os.path.expanduser('~/Library/Caches') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state> + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/<AppName>". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific log dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Logs" to the base app data dir for Windows, and "log" to the + base cache dir for Unix. See discussion below. + + Typical user log directories are: + Mac OS X: ~/Library/Logs/<AppName> + Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined + Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs + Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs + + On Windows the only suggestion in the MSDN docs is that local settings + go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in + examples of what some windows apps use for a logs dir.) + + OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` + value for Windows and appends "log" to the user cache dir for Unix. + This can be disabled with the `opinion=False` option. + """ + if system == "darwin": + path = os.path.join( + os.path.expanduser('~/Library/Logs'), + appname) + elif system == "win32": + path = user_data_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "Logs") + else: + path = user_cache_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "log") + if appname and version: + path = os.path.join(path, version) + return path + + +class AppDirs(object): + """Convenience wrapper for getting application dirs.""" + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): + self.appname = appname + self.appauthor = appauthor + self.version = version + self.roaming = roaming + self.multipath = multipath + + @property + def user_data_dir(self): + return user_data_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_data_dir(self): + return site_data_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_config_dir(self): + return user_config_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_config_dir(self): + return site_config_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_cache_dir(self): + return user_cache_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_log_dir(self): + return user_log_dir(self.appname, self.appauthor, + version=self.version) + + +#---- internal support stuff + +def _get_win_folder_from_registry(csidl_name): + """This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + if PY3: + import winreg as _winreg + else: + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + dir, type = _winreg.QueryValueEx(key, shell_folder_name) + return dir + + +def _get_win_folder_with_pywin32(csidl_name): + from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) + # Try to make this a unicode path because SHGetFolderPath does + # not return unicode strings when there is unicode data in the + # path. + try: + dir = unicode(dir) + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + try: + import win32api + dir = win32api.GetShortPathName(dir) + except ImportError: + pass + except UnicodeError: + pass + return dir + + +def _get_win_folder_with_ctypes(csidl_name): + import ctypes + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + +def _get_win_folder_with_jna(csidl_name): + import array + from com.sun import jna + from com.sun.jna.platform import win32 + + buf_size = win32.WinDef.MAX_PATH * 2 + buf = array.zeros('c', buf_size) + shell = win32.Shell32.INSTANCE + shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf = array.zeros('c', buf_size) + kernel = win32.Kernel32.INSTANCE + if kernel.GetShortPathName(dir, buf, buf_size): + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + return dir + +if system == "win32": + try: + from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + try: + import com.sun.jna + _get_win_folder = _get_win_folder_with_jna + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +#---- self test code + +if __name__ == "__main__": + appname = "MyApp" + appauthor = "MyCompany" + + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) + + print("-- app dirs (with optional 'version')") + dirs = AppDirs(appname, appauthor, version="1.0") + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'version')") + dirs = AppDirs(appname, appauthor) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'appauthor')") + dirs = AppDirs(appname) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (with disabled 'appauthor')") + dirs = AppDirs(appname, appauthor=False) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py new file mode 100755 index 0000000..ced6d94 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py @@ -0,0 +1,11 @@ +"""CacheControl import Interface. + +Make it easy to import from cachecontrol without long namespaces. +""" +__author__ = 'Eric Larson' +__email__ = 'eric@ionrock.org' +__version__ = '0.12.4' + +from .wrapper import CacheControl +from .adapter import CacheControlAdapter +from .controller import CacheController diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py new file mode 100755 index 0000000..10bc01e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py @@ -0,0 +1,60 @@ +import logging + +from pip._vendor import requests + +from pip._vendor.cachecontrol.adapter import CacheControlAdapter +from pip._vendor.cachecontrol.cache import DictCache +from pip._vendor.cachecontrol.controller import logger + +from argparse import ArgumentParser + + +def setup_logging(): + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + logger.addHandler(handler) + + +def get_session(): + adapter = CacheControlAdapter( + DictCache(), + cache_etags=True, + serializer=None, + heuristic=None, + ) + sess = requests.Session() + sess.mount('http://', adapter) + sess.mount('https://', adapter) + + sess.cache_controller = adapter.controller + return sess + + +def get_args(): + parser = ArgumentParser() + parser.add_argument('url', help='The URL to try and cache') + return parser.parse_args() + + +def main(args=None): + args = get_args() + sess = get_session() + + # Make a request to get a response + resp = sess.get(args.url) + + # Turn on logging + setup_logging() + + # try setting the cache + sess.cache_controller.cache_response(resp.request, resp.raw) + + # Now try to get it + if sess.cache_controller.cached_request(resp.request): + print('Cached!') + else: + print('Not cached :(') + + +if __name__ == '__main__': + main() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py new file mode 100755 index 0000000..03c95c9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py @@ -0,0 +1,134 @@ +import types +import functools +import zlib + +from pip._vendor.requests.adapters import HTTPAdapter + +from .controller import CacheController +from .cache import DictCache +from .filewrapper import CallbackFileWrapper + + +class CacheControlAdapter(HTTPAdapter): + invalidating_methods = set(['PUT', 'DELETE']) + + def __init__(self, cache=None, + cache_etags=True, + controller_class=None, + serializer=None, + heuristic=None, + cacheable_methods=None, + *args, **kw): + super(CacheControlAdapter, self).__init__(*args, **kw) + self.cache = cache or DictCache() + self.heuristic = heuristic + self.cacheable_methods = cacheable_methods or ('GET',) + + controller_factory = controller_class or CacheController + self.controller = controller_factory( + self.cache, + cache_etags=cache_etags, + serializer=serializer, + ) + + def send(self, request, cacheable_methods=None, **kw): + """ + Send a request. Use the request information to see if it + exists in the cache and cache the response if we need to and can. + """ + cacheable = cacheable_methods or self.cacheable_methods + if request.method in cacheable: + try: + cached_response = self.controller.cached_request(request) + except zlib.error: + cached_response = None + if cached_response: + return self.build_response(request, cached_response, + from_cache=True) + + # check for etags and add headers if appropriate + request.headers.update( + self.controller.conditional_headers(request) + ) + + resp = super(CacheControlAdapter, self).send(request, **kw) + + return resp + + def build_response(self, request, response, from_cache=False, + cacheable_methods=None): + """ + Build a response by making a request or using the cache. + + This will end up calling send and returning a potentially + cached response + """ + cacheable = cacheable_methods or self.cacheable_methods + if not from_cache and request.method in cacheable: + # Check for any heuristics that might update headers + # before trying to cache. + if self.heuristic: + response = self.heuristic.apply(response) + + # apply any expiration heuristics + if response.status == 304: + # We must have sent an ETag request. This could mean + # that we've been expired already or that we simply + # have an etag. In either case, we want to try and + # update the cache if that is the case. + cached_response = self.controller.update_cached_response( + request, response + ) + + if cached_response is not response: + from_cache = True + + # We are done with the server response, read a + # possible response body (compliant servers will + # not return one, but we cannot be 100% sure) and + # release the connection back to the pool. + response.read(decode_content=False) + response.release_conn() + + response = cached_response + + # We always cache the 301 responses + elif response.status == 301: + self.controller.cache_response(request, response) + else: + # Wrap the response file with a wrapper that will cache the + # response when the stream has been consumed. + response._fp = CallbackFileWrapper( + response._fp, + functools.partial( + self.controller.cache_response, + request, + response, + ) + ) + if response.chunked: + super_update_chunk_length = response._update_chunk_length + + def _update_chunk_length(self): + super_update_chunk_length() + if self.chunk_left == 0: + self._fp._close() + response._update_chunk_length = types.MethodType(_update_chunk_length, response) + + resp = super(CacheControlAdapter, self).build_response( + request, response + ) + + # See if we should invalidate the cache. + if request.method in self.invalidating_methods and resp.ok: + cache_url = self.controller.cache_url(request.url) + self.cache.delete(cache_url) + + # Give the request a from_cache attr to let people use it + resp.from_cache = from_cache + + return resp + + def close(self): + self.cache.close() + super(CacheControlAdapter, self).close() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py new file mode 100755 index 0000000..04d1488 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py @@ -0,0 +1,39 @@ +""" +The cache object API for implementing caches. The default is a thread +safe in-memory dictionary. +""" +from threading import Lock + + +class BaseCache(object): + + def get(self, key): + raise NotImplemented() + + def set(self, key, value): + raise NotImplemented() + + def delete(self, key): + raise NotImplemented() + + def close(self): + pass + + +class DictCache(BaseCache): + + def __init__(self, init_dict=None): + self.lock = Lock() + self.data = init_dict or {} + + def get(self, key): + return self.data.get(key, None) + + def set(self, key, value): + with self.lock: + self.data.update({key: value}) + + def delete(self, key): + with self.lock: + if key in self.data: + self.data.pop(key) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py new file mode 100755 index 0000000..1193f26 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py @@ -0,0 +1,2 @@ +from .file_cache import FileCache # noqa +from .redis_cache import RedisCache # noqa diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py new file mode 100755 index 0000000..f7eb890 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py @@ -0,0 +1,133 @@ +import hashlib +import os +from textwrap import dedent + +from ..cache import BaseCache +from ..controller import CacheController + +try: + FileNotFoundError +except NameError: + # py2.X + FileNotFoundError = OSError + + +def _secure_open_write(filename, fmode): + # We only want to write to this file, so open it in write only mode + flags = os.O_WRONLY + + # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only + # will open *new* files. + # We specify this because we want to ensure that the mode we pass is the + # mode of the file. + flags |= os.O_CREAT | os.O_EXCL + + # Do not follow symlinks to prevent someone from making a symlink that + # we follow and insecurely open a cache file. + if hasattr(os, "O_NOFOLLOW"): + flags |= os.O_NOFOLLOW + + # On Windows we'll mark this file as binary + if hasattr(os, "O_BINARY"): + flags |= os.O_BINARY + + # Before we open our file, we want to delete any existing file that is + # there + try: + os.remove(filename) + except (IOError, OSError): + # The file must not exist already, so we can just skip ahead to opening + pass + + # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a + # race condition happens between the os.remove and this line, that an + # error will be raised. Because we utilize a lockfile this should only + # happen if someone is attempting to attack us. + fd = os.open(filename, flags, fmode) + try: + return os.fdopen(fd, "wb") + except: + # An error occurred wrapping our FD in a file object + os.close(fd) + raise + + +class FileCache(BaseCache): + def __init__(self, directory, forever=False, filemode=0o0600, + dirmode=0o0700, use_dir_lock=None, lock_class=None): + + if use_dir_lock is not None and lock_class is not None: + raise ValueError("Cannot use use_dir_lock and lock_class together") + + try: + from pip._vendor.lockfile import LockFile + from pip._vendor.lockfile.mkdirlockfile import MkdirLockFile + except ImportError: + notice = dedent(""" + NOTE: In order to use the FileCache you must have + lockfile installed. You can install it via pip: + pip install lockfile + """) + raise ImportError(notice) + else: + if use_dir_lock: + lock_class = MkdirLockFile + + elif lock_class is None: + lock_class = LockFile + + self.directory = directory + self.forever = forever + self.filemode = filemode + self.dirmode = dirmode + self.lock_class = lock_class + + @staticmethod + def encode(x): + return hashlib.sha224(x.encode()).hexdigest() + + def _fn(self, name): + # NOTE: This method should not change as some may depend on it. + # See: https://github.com/ionrock/cachecontrol/issues/63 + hashed = self.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key): + name = self._fn(key) + if not os.path.exists(name): + return None + + with open(name, 'rb') as fh: + return fh.read() + + def set(self, key, value): + name = self._fn(key) + + # Make sure the directory exists + try: + os.makedirs(os.path.dirname(name), self.dirmode) + except (IOError, OSError): + pass + + with self.lock_class(name) as lock: + # Write our actual file + with _secure_open_write(lock.path, self.filemode) as fh: + fh.write(value) + + def delete(self, key): + name = self._fn(key) + if not self.forever: + try: + os.remove(name) + except FileNotFoundError: + pass + + +def url_to_file_path(url, filecache): + """Return the file cache path based on the URL. + + This does not ensure the file exists! + """ + key = CacheController.cache_url(url) + return filecache._fn(key) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py new file mode 100755 index 0000000..db1e09d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py @@ -0,0 +1,43 @@ +from __future__ import division + +from datetime import datetime +from pip._vendor.cachecontrol.cache import BaseCache + + +def total_seconds(td): + """Python 2.6 compatability""" + if hasattr(td, 'total_seconds'): + return int(td.total_seconds()) + + ms = td.microseconds + secs = (td.seconds + td.days * 24 * 3600) + return int((ms + secs * 10**6) / 10**6) + + +class RedisCache(BaseCache): + + def __init__(self, conn): + self.conn = conn + + def get(self, key): + return self.conn.get(key) + + def set(self, key, value, expires=None): + if not expires: + self.conn.set(key, value) + else: + expires = expires - datetime.utcnow() + self.conn.setex(key, total_seconds(expires), value) + + def delete(self, key): + self.conn.delete(key) + + def clear(self): + """Helper for clearing all the keys in a database. Use with + caution!""" + for key in self.conn.keys(): + self.conn.delete(key) + + def close(self): + """Redis uses connection pooling, no need to close the connection.""" + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py new file mode 100755 index 0000000..e3f3243 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py @@ -0,0 +1,29 @@ +try: + from urllib.parse import urljoin +except ImportError: + from urlparse import urljoin + + +try: + import cPickle as pickle +except ImportError: + import pickle + + +# Handle the case where the requests module has been patched to not have +# urllib3 bundled as part of its source. +try: + from pip._vendor.requests.packages.urllib3.response import HTTPResponse +except ImportError: + from pip._vendor.urllib3.response import HTTPResponse + +try: + from pip._vendor.requests.packages.urllib3.util import is_fp_closed +except ImportError: + from pip._vendor.urllib3.util import is_fp_closed + +# Replicate some six behaviour +try: + text_type = unicode +except NameError: + text_type = str diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py new file mode 100755 index 0000000..bf4cc7f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py @@ -0,0 +1,373 @@ +""" +The httplib2 algorithms ported for use with requests. +""" +import logging +import re +import calendar +import time +from email.utils import parsedate_tz + +from pip._vendor.requests.structures import CaseInsensitiveDict + +from .cache import DictCache +from .serialize import Serializer + + +logger = logging.getLogger(__name__) + +URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") + + +def parse_uri(uri): + """Parses a URI using the regex given in Appendix B of RFC 3986. + + (scheme, authority, path, query, fragment) = parse_uri(uri) + """ + groups = URI.match(uri).groups() + return (groups[1], groups[3], groups[4], groups[6], groups[8]) + + +class CacheController(object): + """An interface to see if request should cached or not. + """ + def __init__(self, cache=None, cache_etags=True, serializer=None, + status_codes=None): + self.cache = cache or DictCache() + self.cache_etags = cache_etags + self.serializer = serializer or Serializer() + self.cacheable_status_codes = status_codes or (200, 203, 300, 301) + + @classmethod + def _urlnorm(cls, uri): + """Normalize the URL to create a safe key for the cache""" + (scheme, authority, path, query, fragment) = parse_uri(uri) + if not scheme or not authority: + raise Exception("Only absolute URIs are allowed. uri = %s" % uri) + + scheme = scheme.lower() + authority = authority.lower() + + if not path: + path = "/" + + # Could do syntax based normalization of the URI before + # computing the digest. See Section 6.2.2 of Std 66. + request_uri = query and "?".join([path, query]) or path + defrag_uri = scheme + "://" + authority + request_uri + + return defrag_uri + + @classmethod + def cache_url(cls, uri): + return cls._urlnorm(uri) + + def parse_cache_control(self, headers): + known_directives = { + # https://tools.ietf.org/html/rfc7234#section-5.2 + 'max-age': (int, True,), + 'max-stale': (int, False,), + 'min-fresh': (int, True,), + 'no-cache': (None, False,), + 'no-store': (None, False,), + 'no-transform': (None, False,), + 'only-if-cached' : (None, False,), + 'must-revalidate': (None, False,), + 'public': (None, False,), + 'private': (None, False,), + 'proxy-revalidate': (None, False,), + 's-maxage': (int, True,) + } + + cc_headers = headers.get('cache-control', + headers.get('Cache-Control', '')) + + retval = {} + + for cc_directive in cc_headers.split(','): + parts = cc_directive.split('=', 1) + directive = parts[0].strip() + + try: + typ, required = known_directives[directive] + except KeyError: + logger.debug('Ignoring unknown cache-control directive: %s', + directive) + continue + + if not typ or not required: + retval[directive] = None + if typ: + try: + retval[directive] = typ(parts[1].strip()) + except IndexError: + if required: + logger.debug('Missing value for cache-control ' + 'directive: %s', directive) + except ValueError: + logger.debug('Invalid value for cache-control directive ' + '%s, must be %s', directive, typ.__name__) + + return retval + + def cached_request(self, request): + """ + Return a cached response if it exists in the cache, otherwise + return False. + """ + cache_url = self.cache_url(request.url) + logger.debug('Looking up "%s" in the cache', cache_url) + cc = self.parse_cache_control(request.headers) + + # Bail out if the request insists on fresh data + if 'no-cache' in cc: + logger.debug('Request header has "no-cache", cache bypassed') + return False + + if 'max-age' in cc and cc['max-age'] == 0: + logger.debug('Request header has "max_age" as 0, cache bypassed') + return False + + # Request allows serving from the cache, let's see if we find something + cache_data = self.cache.get(cache_url) + if cache_data is None: + logger.debug('No cache entry available') + return False + + # Check whether it can be deserialized + resp = self.serializer.loads(request, cache_data) + if not resp: + logger.warning('Cache entry deserialization failed, entry ignored') + return False + + # If we have a cached 301, return it immediately. We don't + # need to test our response for other headers b/c it is + # intrinsically "cacheable" as it is Permanent. + # See: + # https://tools.ietf.org/html/rfc7231#section-6.4.2 + # + # Client can try to refresh the value by repeating the request + # with cache busting headers as usual (ie no-cache). + if resp.status == 301: + msg = ('Returning cached "301 Moved Permanently" response ' + '(ignoring date and etag information)') + logger.debug(msg) + return resp + + headers = CaseInsensitiveDict(resp.headers) + if not headers or 'date' not in headers: + if 'etag' not in headers: + # Without date or etag, the cached response can never be used + # and should be deleted. + logger.debug('Purging cached response: no date or etag') + self.cache.delete(cache_url) + logger.debug('Ignoring cached response: no date') + return False + + now = time.time() + date = calendar.timegm( + parsedate_tz(headers['date']) + ) + current_age = max(0, now - date) + logger.debug('Current age based on date: %i', current_age) + + # TODO: There is an assumption that the result will be a + # urllib3 response object. This may not be best since we + # could probably avoid instantiating or constructing the + # response until we know we need it. + resp_cc = self.parse_cache_control(headers) + + # determine freshness + freshness_lifetime = 0 + + # Check the max-age pragma in the cache control header + if 'max-age' in resp_cc: + freshness_lifetime = resp_cc['max-age'] + logger.debug('Freshness lifetime from max-age: %i', + freshness_lifetime) + + # If there isn't a max-age, check for an expires header + elif 'expires' in headers: + expires = parsedate_tz(headers['expires']) + if expires is not None: + expire_time = calendar.timegm(expires) - date + freshness_lifetime = max(0, expire_time) + logger.debug("Freshness lifetime from expires: %i", + freshness_lifetime) + + # Determine if we are setting freshness limit in the + # request. Note, this overrides what was in the response. + if 'max-age' in cc: + freshness_lifetime = cc['max-age'] + logger.debug('Freshness lifetime from request max-age: %i', + freshness_lifetime) + + if 'min-fresh' in cc: + min_fresh = cc['min-fresh'] + # adjust our current age by our min fresh + current_age += min_fresh + logger.debug('Adjusted current age from min-fresh: %i', + current_age) + + # Return entry if it is fresh enough + if freshness_lifetime > current_age: + logger.debug('The response is "fresh", returning cached response') + logger.debug('%i > %i', freshness_lifetime, current_age) + return resp + + # we're not fresh. If we don't have an Etag, clear it out + if 'etag' not in headers: + logger.debug( + 'The cached response is "stale" with no etag, purging' + ) + self.cache.delete(cache_url) + + # return the original handler + return False + + def conditional_headers(self, request): + cache_url = self.cache_url(request.url) + resp = self.serializer.loads(request, self.cache.get(cache_url)) + new_headers = {} + + if resp: + headers = CaseInsensitiveDict(resp.headers) + + if 'etag' in headers: + new_headers['If-None-Match'] = headers['ETag'] + + if 'last-modified' in headers: + new_headers['If-Modified-Since'] = headers['Last-Modified'] + + return new_headers + + def cache_response(self, request, response, body=None, + status_codes=None): + """ + Algorithm for caching requests. + + This assumes a requests Response object. + """ + # From httplib2: Don't cache 206's since we aren't going to + # handle byte range requests + cacheable_status_codes = status_codes or self.cacheable_status_codes + if response.status not in cacheable_status_codes: + logger.debug( + 'Status code %s not in %s', + response.status, + cacheable_status_codes + ) + return + + response_headers = CaseInsensitiveDict(response.headers) + + # If we've been given a body, our response has a Content-Length, that + # Content-Length is valid then we can check to see if the body we've + # been given matches the expected size, and if it doesn't we'll just + # skip trying to cache it. + if (body is not None and + "content-length" in response_headers and + response_headers["content-length"].isdigit() and + int(response_headers["content-length"]) != len(body)): + return + + cc_req = self.parse_cache_control(request.headers) + cc = self.parse_cache_control(response_headers) + + cache_url = self.cache_url(request.url) + logger.debug('Updating cache with response from "%s"', cache_url) + + # Delete it from the cache if we happen to have it stored there + no_store = False + if 'no-store' in cc: + no_store = True + logger.debug('Response header has "no-store"') + if 'no-store' in cc_req: + no_store = True + logger.debug('Request header has "no-store"') + if no_store and self.cache.get(cache_url): + logger.debug('Purging existing cache entry to honor "no-store"') + self.cache.delete(cache_url) + + # If we've been given an etag, then keep the response + if self.cache_etags and 'etag' in response_headers: + logger.debug('Caching due to etag') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + # Add to the cache any 301s. We do this before looking that + # the Date headers. + elif response.status == 301: + logger.debug('Caching permanant redirect') + self.cache.set( + cache_url, + self.serializer.dumps(request, response) + ) + + # Add to the cache if the response headers demand it. If there + # is no date header then we can't do anything about expiring + # the cache. + elif 'date' in response_headers: + # cache when there is a max-age > 0 + if 'max-age' in cc and cc['max-age'] > 0: + logger.debug('Caching b/c date exists and max-age > 0') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + # If the request can expire, it means we should cache it + # in the meantime. + elif 'expires' in response_headers: + if response_headers['expires']: + logger.debug('Caching b/c of expires header') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + def update_cached_response(self, request, response): + """On a 304 we will get a new set of headers that we want to + update our cached value with, assuming we have one. + + This should only ever be called when we've sent an ETag and + gotten a 304 as the response. + """ + cache_url = self.cache_url(request.url) + + cached_response = self.serializer.loads( + request, + self.cache.get(cache_url) + ) + + if not cached_response: + # we didn't have a cached response + return response + + # Lets update our headers with the headers from the new request: + # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1 + # + # The server isn't supposed to send headers that would make + # the cached body invalid. But... just in case, we'll be sure + # to strip out ones we know that might be problmatic due to + # typical assumptions. + excluded_headers = [ + "content-length", + ] + + cached_response.headers.update( + dict((k, v) for k, v in response.headers.items() + if k.lower() not in excluded_headers) + ) + + # we want a 200 b/c we have content via the cache + cached_response.status = 200 + + # update our cache + self.cache.set( + cache_url, + self.serializer.dumps(request, cached_response), + ) + + return cached_response diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py new file mode 100755 index 0000000..83ce912 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py @@ -0,0 +1,78 @@ +from io import BytesIO + + +class CallbackFileWrapper(object): + """ + Small wrapper around a fp object which will tee everything read into a + buffer, and when that file is closed it will execute a callback with the + contents of that buffer. + + All attributes are proxied to the underlying file object. + + This class uses members with a double underscore (__) leading prefix so as + not to accidentally shadow an attribute. + """ + + def __init__(self, fp, callback): + self.__buf = BytesIO() + self.__fp = fp + self.__callback = callback + + def __getattr__(self, name): + # The vaguaries of garbage collection means that self.__fp is + # not always set. By using __getattribute__ and the private + # name[0] allows looking up the attribute value and raising an + # AttributeError when it doesn't exist. This stop thigns from + # infinitely recursing calls to getattr in the case where + # self.__fp hasn't been set. + # + # [0] https://docs.python.org/2/reference/expressions.html#atom-identifiers + fp = self.__getattribute__('_CallbackFileWrapper__fp') + return getattr(fp, name) + + def __is_fp_closed(self): + try: + return self.__fp.fp is None + except AttributeError: + pass + + try: + return self.__fp.closed + except AttributeError: + pass + + # We just don't cache it then. + # TODO: Add some logging here... + return False + + def _close(self): + if self.__callback: + self.__callback(self.__buf.getvalue()) + + # We assign this to None here, because otherwise we can get into + # really tricky problems where the CPython interpreter dead locks + # because the callback is holding a reference to something which + # has a __del__ method. Setting this to None breaks the cycle + # and allows the garbage collector to do it's thing normally. + self.__callback = None + + def read(self, amt=None): + data = self.__fp.read(amt) + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data + + def _safe_read(self, amt): + data = self.__fp._safe_read(amt) + if amt == 2 and data == b'\r\n': + # urllib executes this read to toss the CRLF at the end + # of the chunk. + return data + + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py new file mode 100755 index 0000000..aad333d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py @@ -0,0 +1,138 @@ +import calendar +import time + +from email.utils import formatdate, parsedate, parsedate_tz + +from datetime import datetime, timedelta + +TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" + + +def expire_after(delta, date=None): + date = date or datetime.utcnow() + return date + delta + + +def datetime_to_header(dt): + return formatdate(calendar.timegm(dt.timetuple())) + + +class BaseHeuristic(object): + + def warning(self, response): + """ + Return a valid 1xx warning header value describing the cache + adjustments. + + The response is provided too allow warnings like 113 + http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need + to explicitly say response is over 24 hours old. + """ + return '110 - "Response is Stale"' + + def update_headers(self, response): + """Update the response headers with any new headers. + + NOTE: This SHOULD always include some Warning header to + signify that the response was cached by the client, not + by way of the provided headers. + """ + return {} + + def apply(self, response): + updated_headers = self.update_headers(response) + + if updated_headers: + response.headers.update(updated_headers) + warning_header_value = self.warning(response) + if warning_header_value is not None: + response.headers.update({'Warning': warning_header_value}) + + return response + + +class OneDayCache(BaseHeuristic): + """ + Cache the response by providing an expires 1 day in the + future. + """ + def update_headers(self, response): + headers = {} + + if 'expires' not in response.headers: + date = parsedate(response.headers['date']) + expires = expire_after(timedelta(days=1), + date=datetime(*date[:6])) + headers['expires'] = datetime_to_header(expires) + headers['cache-control'] = 'public' + return headers + + +class ExpiresAfter(BaseHeuristic): + """ + Cache **all** requests for a defined time period. + """ + + def __init__(self, **kw): + self.delta = timedelta(**kw) + + def update_headers(self, response): + expires = expire_after(self.delta) + return { + 'expires': datetime_to_header(expires), + 'cache-control': 'public', + } + + def warning(self, response): + tmpl = '110 - Automatically cached for %s. Response might be stale' + return tmpl % self.delta + + +class LastModified(BaseHeuristic): + """ + If there is no Expires header already, fall back on Last-Modified + using the heuristic from + http://tools.ietf.org/html/rfc7234#section-4.2.2 + to calculate a reasonable value. + + Firefox also does something like this per + https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ + http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 + Unlike mozilla we limit this to 24-hr. + """ + cacheable_by_default_statuses = set([ + 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 + ]) + + def update_headers(self, resp): + headers = resp.headers + + if 'expires' in headers: + return {} + + if 'cache-control' in headers and headers['cache-control'] != 'public': + return {} + + if resp.status not in self.cacheable_by_default_statuses: + return {} + + if 'date' not in headers or 'last-modified' not in headers: + return {} + + date = calendar.timegm(parsedate_tz(headers['date'])) + last_modified = parsedate(headers['last-modified']) + if date is None or last_modified is None: + return {} + + now = time.time() + current_age = max(0, now - date) + delta = date - calendar.timegm(last_modified) + freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) + if freshness_lifetime <= current_age: + return {} + + expires = date + freshness_lifetime + return {'expires': time.strftime(TIME_FMT, time.gmtime(expires))} + + def warning(self, resp): + return None diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py new file mode 100755 index 0000000..cd21cae --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py @@ -0,0 +1,194 @@ +import base64 +import io +import json +import zlib + +from pip._vendor import msgpack +from pip._vendor.requests.structures import CaseInsensitiveDict + +from .compat import HTTPResponse, pickle, text_type + + +def _b64_decode_bytes(b): + return base64.b64decode(b.encode("ascii")) + + +def _b64_decode_str(s): + return _b64_decode_bytes(s).decode("utf8") + + +class Serializer(object): + + def dumps(self, request, response, body=None): + response_headers = CaseInsensitiveDict(response.headers) + + if body is None: + body = response.read(decode_content=False) + + # NOTE: 99% sure this is dead code. I'm only leaving it + # here b/c I don't have a test yet to prove + # it. Basically, before using + # `cachecontrol.filewrapper.CallbackFileWrapper`, + # this made an effort to reset the file handle. The + # `CallbackFileWrapper` short circuits this code by + # setting the body as the content is consumed, the + # result being a `body` argument is *always* passed + # into cache_response, and in turn, + # `Serializer.dump`. + response._fp = io.BytesIO(body) + + # NOTE: This is all a bit weird, but it's really important that on + # Python 2.x these objects are unicode and not str, even when + # they contain only ascii. The problem here is that msgpack + # understands the difference between unicode and bytes and we + # have it set to differentiate between them, however Python 2 + # doesn't know the difference. Forcing these to unicode will be + # enough to have msgpack know the difference. + data = { + u"response": { + u"body": body, + u"headers": dict( + (text_type(k), text_type(v)) + for k, v in response.headers.items() + ), + u"status": response.status, + u"version": response.version, + u"reason": text_type(response.reason), + u"strict": response.strict, + u"decode_content": response.decode_content, + }, + } + + # Construct our vary headers + data[u"vary"] = {} + if u"vary" in response_headers: + varied_headers = response_headers[u'vary'].split(',') + for header in varied_headers: + header = header.strip() + header_value = request.headers.get(header, None) + if header_value is not None: + header_value = text_type(header_value) + data[u"vary"][header] = header_value + + return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)]) + + def loads(self, request, data): + # Short circuit if we've been given an empty set of data + if not data: + return + + # Determine what version of the serializer the data was serialized + # with + try: + ver, data = data.split(b",", 1) + except ValueError: + ver = b"cc=0" + + # Make sure that our "ver" is actually a version and isn't a false + # positive from a , being in the data stream. + if ver[:3] != b"cc=": + data = ver + data + ver = b"cc=0" + + # Get the version number out of the cc=N + ver = ver.split(b"=", 1)[-1].decode("ascii") + + # Dispatch to the actual load method for the given version + try: + return getattr(self, "_loads_v{0}".format(ver))(request, data) + except AttributeError: + # This is a version we don't have a loads function for, so we'll + # just treat it as a miss and return None + return + + def prepare_response(self, request, cached): + """Verify our vary headers match and construct a real urllib3 + HTTPResponse object. + """ + # Special case the '*' Vary value as it means we cannot actually + # determine if the cached response is suitable for this request. + if "*" in cached.get("vary", {}): + return + + # Ensure that the Vary headers for the cached response match our + # request + for header, value in cached.get("vary", {}).items(): + if request.headers.get(header, None) != value: + return + + body_raw = cached["response"].pop("body") + + headers = CaseInsensitiveDict(data=cached['response']['headers']) + if headers.get('transfer-encoding', '') == 'chunked': + headers.pop('transfer-encoding') + + cached['response']['headers'] = headers + + try: + body = io.BytesIO(body_raw) + except TypeError: + # This can happen if cachecontrol serialized to v1 format (pickle) + # using Python 2. A Python 2 str(byte string) will be unpickled as + # a Python 3 str (unicode string), which will cause the above to + # fail with: + # + # TypeError: 'str' does not support the buffer interface + body = io.BytesIO(body_raw.encode('utf8')) + + return HTTPResponse( + body=body, + preload_content=False, + **cached["response"] + ) + + def _loads_v0(self, request, data): + # The original legacy cache data. This doesn't contain enough + # information to construct everything we need, so we'll treat this as + # a miss. + return + + def _loads_v1(self, request, data): + try: + cached = pickle.loads(data) + except ValueError: + return + + return self.prepare_response(request, cached) + + def _loads_v2(self, request, data): + try: + cached = json.loads(zlib.decompress(data).decode("utf8")) + except (ValueError, zlib.error): + return + + # We need to decode the items that we've base64 encoded + cached["response"]["body"] = _b64_decode_bytes( + cached["response"]["body"] + ) + cached["response"]["headers"] = dict( + (_b64_decode_str(k), _b64_decode_str(v)) + for k, v in cached["response"]["headers"].items() + ) + cached["response"]["reason"] = _b64_decode_str( + cached["response"]["reason"], + ) + cached["vary"] = dict( + (_b64_decode_str(k), _b64_decode_str(v) if v is not None else v) + for k, v in cached["vary"].items() + ) + + return self.prepare_response(request, cached) + + def _loads_v3(self, request, data): + # Due to Python 2 encoding issues, it's impossible to know for sure + # exactly how to load v3 entries, thus we'll treat these as a miss so + # that they get rewritten out as v4 entries. + return + + def _loads_v4(self, request, data): + try: + cached = msgpack.loads(data, encoding='utf-8') + except ValueError: + return + + return self.prepare_response(request, cached) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py new file mode 100755 index 0000000..2ceac99 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py @@ -0,0 +1,27 @@ +from .adapter import CacheControlAdapter +from .cache import DictCache + + +def CacheControl(sess, + cache=None, + cache_etags=True, + serializer=None, + heuristic=None, + controller_class=None, + adapter_class=None, + cacheable_methods=None): + + cache = cache or DictCache() + adapter_class = adapter_class or CacheControlAdapter + adapter = adapter_class( + cache, + cache_etags=cache_etags, + serializer=serializer, + heuristic=heuristic, + controller_class=controller_class, + cacheable_methods=cacheable_methods + ) + sess.mount('http://', adapter) + sess.mount('https://', adapter) + + return sess diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py new file mode 100755 index 0000000..3d73ece --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import where, old_where + +__version__ = "2018.01.18" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py new file mode 100755 index 0000000..e30b50d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py @@ -0,0 +1,2 @@ +from certifi import where +print(where()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem new file mode 100755 index 0000000..101ac98 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem @@ -0,0 +1,4433 @@ + +# 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=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Label: "Verisign Class 3 Public Primary Certification Authority - G3" +# Serial: 206684696279472310254277870180966723415 +# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 +# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 +# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----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=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Label: "AddTrust External Root" +# Serial: 1 +# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f +# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 +# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----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=GeoTrust Global CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. +# Label: "GeoTrust Global CA" +# Serial: 144470 +# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 +# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 +# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Label: "GeoTrust Universal CA" +# Serial: 1 +# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 +# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 +# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Universal CA 2" +# Serial: 1 +# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 +# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 +# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Label: "Visa eCommerce Root" +# Serial: 25952180776285836048024890241505565794 +# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 +# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 +# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----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 Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Label: "QuoVadis Root CA" +# Serial: 985026699 +# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 +# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 +# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----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=Sonera Class2 CA O=Sonera +# Subject: CN=Sonera Class2 CA O=Sonera +# Label: "Sonera Class 2 Root CA" +# Serial: 29 +# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb +# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 +# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----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: O=Government Root Certification Authority +# Subject: O=Government Root Certification Authority +# Label: "Taiwan GRCA" +# Serial: 42023070807708724159991140556527066870 +# MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e +# SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9 +# SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3 +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----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=Class 2 Primary CA O=Certplus +# Subject: CN=Class 2 Primary CA O=Certplus +# Label: "Certplus Class 2 Primary CA" +# Serial: 177770208045934040241468760488327595043 +# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b +# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb +# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----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----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----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----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Label: "GeoTrust Primary Certification Authority" +# Serial: 32798226551256963324313806436981982369 +# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf +# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 +# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA" +# Serial: 69529181992039203566298953787712940909 +# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 +# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 +# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" +# Serial: 33037644167568058970164719475676101450 +# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c +# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 +# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----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=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GA CA" +# Serial: 86718877871133159090080555911823548314 +# MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93 +# SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9 +# SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5 +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----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=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Label: "Deutsche Telekom Root CA 2" +# Serial: 38 +# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08 +# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf +# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3 +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----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=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G3" +# Serial: 28809105769928564313984085209975885599 +# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 +# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd +# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G2" +# Serial: 71758320672825410020661621085256472406 +# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f +# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 +# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G3" +# Serial: 127614157056681299805556476275995414779 +# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 +# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 +# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G2" +# Serial: 80682863203381065782177908751794619243 +# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a +# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 +# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Universal Root Certification Authority" +# Serial: 85209574734084581917763752644031726877 +# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 +# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 +# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" +# Serial: 63143484348153506665311985501458640051 +# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 +# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a +# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----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=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G2" +# Serial: 10000012 +# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a +# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16 +# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----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----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Label: "Chambers of Commerce Root - 2008" +# Serial: 11806822484801597146 +# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 +# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c +# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- + +# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Label: "Global Chambersign Root - 2008" +# Serial: 14541511773111788494 +# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 +# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c +# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----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=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: O=Trustis Limited OU=Trustis FPS Root CA +# Subject: O=Trustis Limited OU=Trustis FPS Root CA +# Label: "Trustis FPS Root CA" +# Serial: 36053640375399034304724988975563710553 +# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d +# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 +# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----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=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Label: "EE Certification Centre Root CA" +# Serial: 112324828676200291871926431888494945866 +# MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f +# SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7 +# SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76 +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----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 Root CA - G3 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G3" +# Serial: 10003001 +# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37 +# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc +# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----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=T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5 O=T\xdcRKTRUST Bilgi \u0130leti\u015fim ve Bili\u015fim G\xfcvenli\u011fi Hizmetleri A.\u015e. +# Subject: CN=T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5 O=T\xdcRKTRUST Bilgi \u0130leti\u015fim ve Bili\u015fim G\xfcvenli\u011fi Hizmetleri A.\u015e. +# Label: "T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5" +# Serial: 156233699172481 +# MD5 Fingerprint: da:70:8e:f0:22:df:93:26:f6:5f:9f:d3:15:06:52:4e +# SHA1 Fingerprint: c4:18:f6:4d:46:d1:df:00:3d:27:30:13:72:43:a9:12:11:c6:75:fb +# SHA256 Fingerprint: 49:35:1b:90:34:44:c1:85:cc:dc:5c:69:3d:24:d8:55:5c:b2:08:d6:a8:14:13:07:69:9f:4a:f0:63:19:9d:78 +-----BEGIN CERTIFICATE----- +MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE +BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn +aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg +QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0 +MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD +VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 +dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom +/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR +Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3 +4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z +5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0 +hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID +AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX +SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l +VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq +URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf +peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF +Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW ++qtB4Uu2NQvAmxU= +-----END CERTIFICATE----- + +# Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Label: "Certinomis - Root CA" +# Serial: 1 +# MD5 Fingerprint: 14:0a:fd:8d:a8:28:b5:38:69:db:56:7e:61:22:03:3f +# SHA1 Fingerprint: 9d:70:bb:01:a5:a4:a0:18:11:2e:f7:1c:01:b9:32:c5:34:e7:88:a8 +# SHA256 Fingerprint: 2a:99:f5:bc:11:74:b7:3c:bb:1d:62:08:84:e0:1c:34:e5:1c:cb:39:78:da:12:5f:0e:33:26:88:83:bf:41:58 +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----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=Certplus Root CA G1 O=Certplus +# Subject: CN=Certplus Root CA G1 O=Certplus +# Label: "Certplus Root CA G1" +# Serial: 1491911565779898356709731176965615564637713 +# MD5 Fingerprint: 7f:09:9c:f7:d9:b9:5c:69:69:56:d5:37:3e:14:0d:42 +# SHA1 Fingerprint: 22:fd:d0:b7:fd:a2:4e:0d:ac:49:2c:a0:ac:a6:7b:6a:1f:e3:f7:66 +# SHA256 Fingerprint: 15:2a:40:2b:fc:df:2c:d5:48:05:4d:22:75:b3:9c:7f:ca:3e:c0:97:80:78:b0:f0:ea:76:e5:61:a6:c7:43:3e +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a +iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt +6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP +0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f +6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE +EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN +1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc +h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT +mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV +4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO +WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd +Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq +hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh +66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 +/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS +S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j +2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R +Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr +RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy +6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV +V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 +g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl +++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= +-----END CERTIFICATE----- + +# Issuer: CN=Certplus Root CA G2 O=Certplus +# Subject: CN=Certplus Root CA G2 O=Certplus +# Label: "Certplus Root CA G2" +# Serial: 1492087096131536844209563509228951875861589 +# MD5 Fingerprint: a7:ee:c4:78:2d:1b:ee:2d:b9:29:ce:d6:a7:96:32:31 +# SHA1 Fingerprint: 4f:65:8e:1f:e9:06:d8:28:02:e9:54:47:41:c9:54:25:5d:69:cc:1a +# SHA256 Fingerprint: 6c:c0:50:41:e6:44:5e:74:69:6c:4c:fb:c9:f8:0f:54:3b:7e:ab:bb:44:b4:ce:6f:78:7c:6a:99:71:c4:2f:17 +-----BEGIN CERTIFICATE----- +MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat +93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x +Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj +FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG +SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch +p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal +U5ORGpOucGpnutee5WEaXw== +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G1 O=OpenTrust +# Subject: CN=OpenTrust Root CA G1 O=OpenTrust +# Label: "OpenTrust Root CA G1" +# Serial: 1492036577811947013770400127034825178844775 +# MD5 Fingerprint: 76:00:cc:81:29:cd:55:5e:88:6a:7a:2e:f7:4d:39:da +# SHA1 Fingerprint: 79:91:e8:34:f7:e2:ee:dd:08:95:01:52:e9:55:2d:14:e9:58:d5:7e +# SHA256 Fingerprint: 56:c7:71:28:d9:8c:18:d9:1b:4c:fd:ff:bc:25:ee:91:03:d4:75:8e:a2:ab:ad:82:6a:90:f3:45:7d:46:0e:b4 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b +wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX +/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0 +77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP +uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx +p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx +Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2 +TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W +G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw +vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY +EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1 +2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw +DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E +PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf +gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS +FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0 +V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P +XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I +i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t +TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91 +09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky +Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ +AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj +1oxx +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G2 O=OpenTrust +# Subject: CN=OpenTrust Root CA G2 O=OpenTrust +# Label: "OpenTrust Root CA G2" +# Serial: 1492012448042702096986875987676935573415441 +# MD5 Fingerprint: 57:24:b6:59:24:6b:ae:c8:fe:1c:0c:20:f2:c0:4e:eb +# SHA1 Fingerprint: 79:5f:88:60:c5:ab:7c:3d:92:e6:cb:f4:8d:e1:45:cd:11:ef:60:0b +# SHA256 Fingerprint: 27:99:58:29:fe:6a:75:15:c1:bf:e8:48:f9:c4:76:1d:b1:6c:22:59:29:25:7b:f4:0d:08:94:f2:9e:a8:ba:f2 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh +/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e +CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 +1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE +FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS +gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X +G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy +YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH +vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 +t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ +gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 +5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w +DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz +Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 +nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT +RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT +wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 +t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa +TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 +o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU +3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA +iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f +WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM +S1IK +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G3 O=OpenTrust +# Subject: CN=OpenTrust Root CA G3 O=OpenTrust +# Label: "OpenTrust Root CA G3" +# Serial: 1492104908271485653071219941864171170455615 +# MD5 Fingerprint: 21:37:b4:17:16:92:7b:67:46:70:a9:96:d7:a8:13:24 +# SHA1 Fingerprint: 6e:26:64:f3:56:bf:34:55:bf:d1:93:3f:7c:01:de:d8:13:da:8a:a6 +# SHA256 Fingerprint: b7:c3:62:31:70:6e:81:07:8c:36:7c:b8:96:19:8f:1e:32:08:dd:92:69:49:dd:8f:57:09:a4:10:f7:5b:62:92 +-----BEGIN CERTIFICATE----- +MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx +CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U +cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow +QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl +blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm +3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d +oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 +DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK +BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q +j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx +4nxp5V2a+EEfOzmTk51V6s2N8fvB +-----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=LuxTrust Global Root 2 O=LuxTrust S.A. +# Subject: CN=LuxTrust Global Root 2 O=LuxTrust S.A. +# Label: "LuxTrust Global Root 2" +# Serial: 59914338225734147123941058376788110305822489521 +# MD5 Fingerprint: b2:e1:09:00:61:af:f7:f1:91:6f:c4:ad:8d:5e:3b:7c +# SHA1 Fingerprint: 1e:0e:56:19:0a:d1:8b:25:98:b2:04:44:ff:66:8a:04:17:99:5f:3f +# SHA256 Fingerprint: 54:45:5f:71:29:c2:0b:14:47:c4:18:f9:97:16:8f:24:c5:8f:c5:02:3b:f5:da:5b:e2:eb:6e:1d:d8:90:2e:d5 +-----BEGIN CERTIFICATE----- +MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL +BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV +BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw +MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B +LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F +ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem +hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1 +EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn +Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4 +zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ +96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m +j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g +DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+ +8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j +X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH +hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB +KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0 +Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT ++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL +BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9 +BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO +jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9 +loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c +qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+ +2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/ +JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre +zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf +LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+ +x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6 +oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr +-----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----- diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py new file mode 100755 index 0000000..0ac5ee1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem. +""" +import os +import warnings + + +class DeprecatedBundleWarning(DeprecationWarning): + """ + The weak security bundle is being deprecated. Please bother your service + provider to get them to stop using cross-signed roots. + """ + + +def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, 'cacert.pem') + + +def old_where(): + warnings.warn( + "The weak security bundle has been removed. certifi.old_where() is now an alias " + "of certifi.where(). Please update your code to use certifi.where() instead. " + "certifi.old_where() will be removed in 2018.", + DeprecatedBundleWarning + ) + return where() + +if __name__ == '__main__': + print(where()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py new file mode 100755 index 0000000..45bf7e6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py @@ -0,0 +1,39 @@ +######################## 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 .compat import PY2, PY3 +from .universaldetector import UniversalDetector +from .version import __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: ' + '{0}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5freq.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5freq.py new file mode 100755 index 0000000..88023ae --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 +# <http://www.edu.tw:81/mandr/> +# +# 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5prober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5prober.py new file mode 100755 index 0000000..5b1227a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/chardistribution.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/chardistribution.py new file mode 100755 index 0000000..e5509a0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py new file mode 100755 index 0000000..1720ddc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## 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 + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetprober.py new file mode 100755 index 0000000..1fc2746 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py new file mode 100755 index 0000000..d3f5a12 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py new file mode 100755 index 0000000..daabecd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" +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 pip._vendor.chardet import __version__ +from pip._vendor.chardet.compat import PY2 +from pip._vendor.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 '{0}: {1} with confidence {2}'.format(name, result['encoding'], + result['confidence']) + else: + return '{0}: 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 {0}'.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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/codingstatemachine.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/codingstatemachine.py new file mode 100755 index 0000000..c562e1d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py new file mode 100755 index 0000000..fa100a3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py @@ -0,0 +1,34 @@ +######################## 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 + base_str = (str, unicode) + text_type = unicode +else: + PY2 = False + PY3 = True + base_str = (bytes, str) + text_type = str diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cp949prober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cp949prober.py new file mode 100755 index 0000000..de0ceab --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/enums.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/enums.py new file mode 100755 index 0000000..c8e6001 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escprober.py new file mode 100755 index 0000000..c52060d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escsm.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escsm.py new file mode 100755 index 0000000..b837704 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/eucjpprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/eucjpprober.py new file mode 100755 index 0000000..a81ee1e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrfreq.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrfreq.py new file mode 100755 index 0000000..ae25c1b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrprober.py new file mode 100755 index 0000000..99d5b15 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwfreq.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwfreq.py new file mode 100755 index 0000000..5195275 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 +# <http:#www.edu.tw:81/mandr/> + +# 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwprober.py new file mode 100755 index 0000000..7dbc136 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312freq.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312freq.py new file mode 100755 index 0000000..a0167b3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312prober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312prober.py new file mode 100755 index 0000000..7cae6b5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/hebrewprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/hebrewprober.py new file mode 100755 index 0000000..10b8122 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jisfreq.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jisfreq.py new file mode 100755 index 0000000..510b940 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jpcntx.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jpcntx.py new file mode 100755 index 0000000..624d534 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py new file mode 100755 index 0000000..eb6f19a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { + 'char_to_order_map': Latin5_BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Bulgairan', +} + +Win1251BulgarianModel = { + 'char_to_order_map': win1251BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Bulgarian', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py new file mode 100755 index 0000000..bdbad70 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py @@ -0,0 +1,333 @@ +######################## 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 ######################### + +# KOI8-R language model +# Character Mapping Table: +KOI8R_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { + 'char_to_order_map': KOI8R_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "KOI8-R", + 'language': 'Russian', +} + +Win1251CyrillicModel = { + 'char_to_order_map': win1251_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Russian', +} + +Latin5CyrillicModel = { + 'char_to_order_map': latin5_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Russian', +} + +MacCyrillicModel = { + 'char_to_order_map': macCyrillic_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "MacCyrillic", + 'language': 'Russian', +} + +Ibm866Model = { + 'char_to_order_map': IBM866_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM866", + 'language': 'Russian', +} + +Ibm855Model = { + 'char_to_order_map': IBM855_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM855", + 'language': 'Russian', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py new file mode 100755 index 0000000..73541cc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { + 'char_to_order_map': Latin7_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-7", + 'language': 'Greek', +} + +Win1253GreekModel = { + 'char_to_order_map': win1253_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "windows-1253", + 'language': 'Greek', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py new file mode 100755 index 0000000..07029b6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +WIN1255_CHAR_TO_ORDER_MAP = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HEBREW_LANG_MODEL = ( +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { + 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, + 'precedence_matrix': HEBREW_LANG_MODEL, + 'typical_positive_ratio': 0.984004, + 'keep_english_letter': False, + 'charset_name': "windows-1255", + 'language': 'Hebrew', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py new file mode 100755 index 0000000..6de87b7 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { + 'char_to_order_map': Latin2_HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-2", + 'language': 'Hungarian', +} + +Win1250HungarianModel = { + 'char_to_order_map': win1250HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "windows-1250", + 'language': 'Hungarian', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py new file mode 100755 index 0000000..fdb3313 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py @@ -0,0 +1,199 @@ +######################## 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 ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { + 'char_to_order_map': TIS620CharToOrderMap, + 'precedence_matrix': ThaiLangModel, + 'typical_positive_ratio': 0.926386, + 'keep_english_letter': False, + 'charset_name': "TIS-620", + 'language': 'Thai', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py new file mode 100755 index 0000000..64ec9bd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +######################## 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 +# Özgür Baskın - Turkish Language Model +# +# 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 ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin5_TurkishCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, + 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, +255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, + 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, +180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, +164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, +150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, + 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, +124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, + 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, + 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, + 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, +) + +TurkishLangModel = ( +3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, +3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, +3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, +3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, +3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, +3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, +2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, +3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, +1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, +3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, +3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, +2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, +2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, +3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, +0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, +3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, +3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, +0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, +1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, +3,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, +3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, +3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, +0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, +3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, +1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, +1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, +2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, +2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, +1,0,0,1,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,1, +1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, +0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, +3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,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,0,0,0,0,0,0, +3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, +0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, +3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, +1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, +2,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, +3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, +0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, +3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, +0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, +0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, +3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, +0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, +0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, +3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, +0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, +3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, +0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, +0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, +3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, +0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, +3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, +0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, +0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, +0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, +0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, +0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, +0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, +1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, +0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, +0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, +3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, +0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, +2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, +2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, +0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, +0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,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,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin5TurkishModel = { + 'char_to_order_map': Latin5_TurkishCharToOrderMap, + 'precedence_matrix': TurkishLangModel, + 'typical_positive_ratio': 0.970290, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-9", + 'language': 'Turkish', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/latin1prober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/latin1prober.py new file mode 100755 index 0000000..7c37520 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcharsetprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcharsetprober.py new file mode 100755 index 0000000..4609154 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcsgroupprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcsgroupprober.py new file mode 100755 index 0000000..4b04929 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcssm.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcssm.py new file mode 100755 index 0000000..d68f6f6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py new file mode 100755 index 0000000..66e0dfc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py @@ -0,0 +1,132 @@ +######################## 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 CharacterCategory, ProbingState, SequenceLikelihood + + +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.get('language') + + def feed(self, byte_str): + if not self._model['keep_english_letter']: + 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'] + for i, c in enumerate(byte_str): + # XXX: Order is in range 1-64, so one would think we want 0-63 here, + # but that leads to 27 more test failures than before. + order = char_to_order_map[c] + # 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 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + i = (self._last_order * self.SAMPLE_SIZE) + order + model = self._model['precedence_matrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * self.SAMPLE_SIZE) + self._last_order + model = self._model['precedence_matrix'][i] + self._seq_counters[model] += 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py new file mode 100755 index 0000000..29bcc2a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py @@ -0,0 +1,73 @@ +######################## 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 .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, + Latin5CyrillicModel, MacCyrillicModel, + Ibm866Model, Ibm855Model) +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber +from .langturkishmodel import Latin5TurkishModel + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + self.probers = [ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(Latin2HungarianModel), + # SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + SingleByteCharSetProber(Latin5TurkishModel), + ] + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) + self.probers.extend([hebrew_prober, logical_hebrew_prober, + visual_hebrew_prober]) + + self.reset() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sjisprober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sjisprober.py new file mode 100755 index 0000000..683add0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/universaldetector.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/universaldetector.py new file mode 100755 index 0000000..8a6de3b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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', + prober.charset_name, + prober.language, + prober.get_confidence()) + return self.result diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/utf8prober.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/utf8prober.py new file mode 100755 index 0000000..4573267 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/version.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/version.py new file mode 100755 index 0000000..f24d042 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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__ = "3.0.4" +VERSION = __version__.split('.') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py new file mode 100755 index 0000000..10c372d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.3.9' + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py new file mode 100755 index 0000000..8530fd0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py @@ -0,0 +1,102 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' + +CSI = '\033[' +OSC = '\033]' +BEL = '\007' + + +def code_to_chars(code): + return CSI + str(code) + 'm' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py new file mode 100755 index 0000000..0cb9efc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py @@ -0,0 +1,236 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import re +import sys +import os + +from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style +from .winterm import WinTerm, WinColor, WinStyle +from .win32 import windll, winapi_test + + +winterm = None +if windll is not None: + winterm = WinTerm() + + +def is_stream_closed(stream): + return not hasattr(stream, 'closed') or stream.closed + + +def is_a_tty(stream): + return hasattr(stream, 'isatty') and stream.isatty() + + +class StreamWrapper(object): + ''' + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()', which is delegated to our + Converter instance. + ''' + def __init__(self, wrapped, converter): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + self.__convertor = converter + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def write(self, text): + self.__convertor.write(text) + + +class AnsiToWin32(object): + ''' + Implements a 'write()' method which, on Windows, will strip ANSI character + sequences from the text, and if outputting to a tty, will convert them into + win32 function calls. + ''' + ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile('\001?\033\\]((?:.|;)*?)(\x07)\002?') # Operating System Command + + def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + # The wrapped stream (normally sys.stdout or sys.stderr) + self.wrapped = wrapped + + # should we reset colors to defaults after every .write() + self.autoreset = autoreset + + # create the proxy wrapping our output stream + self.stream = StreamWrapper(wrapped, self) + + on_windows = os.name == 'nt' + # We test if the WinAPI works, because even if we are on Windows + # we may be using a terminal that doesn't support the WinAPI + # (e.g. Cygwin Terminal). In this case it's up to the terminal + # to support the ANSI codes. + conversion_supported = on_windows and winapi_test() + + # should we strip ANSI sequences from our output? + if strip is None: + strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped)) + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped) + self.convert = convert + + # dict of ansi codes to win32 functions and parameters + self.win32_calls = self.get_win32_calls() + + # are we wrapping stderr? + self.on_stderr = self.wrapped is sys.stderr + + def should_wrap(self): + ''' + True if this class is actually needed. If false, then the output + stream will not be affected, nor will win32 calls be issued, so + wrapping stdout is not actually required. This will generally be + False on non-Windows platforms, unless optional functionality like + autoreset has been requested using kwargs to init() + ''' + return self.convert or self.strip or self.autoreset + + def get_win32_calls(self): + if self.convert and winterm: + return { + AnsiStyle.RESET_ALL: (winterm.reset_all, ), + AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), + AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), + AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), + AnsiFore.RED: (winterm.fore, WinColor.RED), + AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), + AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), + AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), + AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), + AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), + AnsiFore.WHITE: (winterm.fore, WinColor.GREY), + AnsiFore.RESET: (winterm.fore, ), + AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), + AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), + AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), + AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), + AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), + AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), + AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), + AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), + AnsiBack.BLACK: (winterm.back, WinColor.BLACK), + AnsiBack.RED: (winterm.back, WinColor.RED), + AnsiBack.GREEN: (winterm.back, WinColor.GREEN), + AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), + AnsiBack.BLUE: (winterm.back, WinColor.BLUE), + AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), + AnsiBack.CYAN: (winterm.back, WinColor.CYAN), + AnsiBack.WHITE: (winterm.back, WinColor.GREY), + AnsiBack.RESET: (winterm.back, ), + AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), + AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), + AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), + AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), + AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), + AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), + AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), + AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), + } + return dict() + + def write(self, text): + if self.strip or self.convert: + self.write_and_convert(text) + else: + self.wrapped.write(text) + self.wrapped.flush() + if self.autoreset: + self.reset_all() + + + def reset_all(self): + if self.convert: + self.call_win32('m', (0,)) + elif not self.strip and not is_stream_closed(self.wrapped): + self.wrapped.write(Style.RESET_ALL) + + + def write_and_convert(self, text): + ''' + Write the given text to our wrapped stream, stripping any ANSI + sequences from the text, and optionally converting them into win32 + calls. + ''' + cursor = 0 + text = self.convert_osc(text) + for match in self.ANSI_CSI_RE.finditer(text): + start, end = match.span() + self.write_plain_text(text, cursor, start) + self.convert_ansi(*match.groups()) + cursor = end + self.write_plain_text(text, cursor, len(text)) + + + def write_plain_text(self, text, start, end): + if start < end: + self.wrapped.write(text[start:end]) + self.wrapped.flush() + + + def convert_ansi(self, paramstring, command): + if self.convert: + params = self.extract_params(command, paramstring) + self.call_win32(command, params) + + + def extract_params(self, command, paramstring): + if command in 'Hf': + params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) + while len(params) < 2: + # defaults: + params = params + (1,) + else: + params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) + if len(params) == 0: + # defaults: + if command in 'JKm': + params = (0,) + elif command in 'ABCD': + params = (1,) + + return params + + + def call_win32(self, command, params): + if command == 'm': + for param in params: + if param in self.win32_calls: + func_args = self.win32_calls[param] + func = func_args[0] + args = func_args[1:] + kwargs = dict(on_stderr=self.on_stderr) + func(*args, **kwargs) + elif command in 'J': + winterm.erase_screen(params[0], on_stderr=self.on_stderr) + elif command in 'K': + winterm.erase_line(params[0], on_stderr=self.on_stderr) + elif command in 'Hf': # cursor position - absolute + winterm.set_cursor_position(params, on_stderr=self.on_stderr) + elif command in 'ABCD': # cursor position - relative + n = params[0] + # A - up, B - down, C - forward, D - back + x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] + winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) + + + def convert_osc(self, text): + for match in self.ANSI_OSC_RE.finditer(text): + start, end = match.span() + text = text[:start] + text[end:] + paramstring, command = match.groups() + if command in '\x07': # \x07 = BEL + params = paramstring.split(";") + # 0 - change title and icon (we will only change title) + # 1 - change icon (we don't support this) + # 2 - change title + if params[0] in '02': + winterm.set_title(params[1]) + return text diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py new file mode 100755 index 0000000..7f03156 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py @@ -0,0 +1,82 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +orig_stdout = None +orig_stderr = None + +wrapped_stdout = None +wrapped_stderr = None + +atexit_done = False + + +def reset_all(): + if AnsiToWin32 is not None: # Issue #74: objects might become None at exit + AnsiToWin32(orig_stdout).reset_all() + + +def init(autoreset=False, convert=None, strip=None, wrap=True): + + if not wrap and any([autoreset, convert, strip]): + raise ValueError('wrap=False conflicts with any other arg=True') + + global wrapped_stdout, wrapped_stderr + global orig_stdout, orig_stderr + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + + if sys.stdout is None: + wrapped_stdout = None + else: + sys.stdout = wrapped_stdout = \ + wrap_stream(orig_stdout, convert, strip, autoreset, wrap) + if sys.stderr is None: + wrapped_stderr = None + else: + sys.stderr = wrapped_stderr = \ + wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + + global atexit_done + if not atexit_done: + atexit.register(reset_all) + atexit_done = True + + +def deinit(): + if orig_stdout is not None: + sys.stdout = orig_stdout + if orig_stderr is not None: + sys.stderr = orig_stderr + + +@contextlib.contextmanager +def colorama_text(*args, **kwargs): + init(*args, **kwargs) + try: + yield + finally: + deinit() + + +def reinit(): + if wrapped_stdout is not None: + sys.stdout = wrapped_stdout + if wrapped_stderr is not None: + sys.stderr = wrapped_stderr + + +def wrap_stream(stream, convert, strip, autoreset, wrap): + if wrap: + wrapper = AnsiToWin32(stream, + convert=convert, strip=strip, autoreset=autoreset) + if wrapper.should_wrap(): + stream = wrapper.stream + return stream + + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py new file mode 100755 index 0000000..1485e69 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py @@ -0,0 +1,156 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW + _SetConsoleTitleW.argtypes = [ + wintypes.LPCWSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + handles = { + STDOUT: _GetStdHandle(STDOUT), + STDERR: _GetStdHandle(STDERR), + } + + def _winapi_test(handle): + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def winapi_test(): + return any(_winapi_test(h) for h in handles.values()) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = handles[stream_id] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = handles[stream_id] + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = handles[stream_id] + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = handles[stream_id] + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = handles[stream_id] + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py new file mode 100755 index 0000000..385862e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py @@ -0,0 +1,162 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from . import win32 + + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + if mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + if mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py new file mode 100755 index 0000000..9430718 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import logging + +__version__ = '0.2.7' + +class DistlibException(Exception): + pass + +try: + from logging import NullHandler +except ImportError: # pragma: no cover + class NullHandler(logging.Handler): + def handle(self, record): pass + def emit(self, record): pass + def createLock(self): self.lock = None + +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py new file mode 100755 index 0000000..e6143f1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py @@ -0,0 +1,6 @@ +"""Modules copied from Python 3 standard libraries, for internal use only. + +Individual classes and functions are found in d2._backport.misc. Intended +usage is to always import things missing from 3.1 from that module: the +built-in/stdlib objects will be used if found. +""" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py new file mode 100755 index 0000000..6eb7b86 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Backports for individual classes and functions.""" + +import os +import sys + +__all__ = ['cache_from_source', 'callable', 'fsencode'] + + +try: + from imp import cache_from_source +except ImportError: + def cache_from_source(py_file, debug=__debug__): + ext = debug and 'c' or 'o' + return py_file + ext + + +try: + callable = callable +except NameError: + from collections import Callable + + def callable(obj): + return isinstance(obj, Callable) + + +try: + fsencode = os.fsencode +except AttributeError: + def fsencode(filename): + if isinstance(filename, bytes): + return filename + elif isinstance(filename, str): + return filename.encode(sys.getfilesystemencoding()) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py new file mode 100755 index 0000000..becbfd7 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py @@ -0,0 +1,761 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Utility functions for copying and archiving files and directory trees. + +XXX The functions here don't copy the resource fork or other metadata on Mac. + +""" + +import os +import sys +import stat +from os.path import abspath +import fnmatch +import collections +import errno +from . import tarfile + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False + +try: + from pwd import getpwnam +except ImportError: + getpwnam = None + +try: + from grp import getgrnam +except ImportError: + getgrnam = None + +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive", "ignore_patterns"] + +class Error(EnvironmentError): + pass + +class SpecialFileError(EnvironmentError): + """Raised when trying to do a kind of operation (e.g. copying) which is + not supported on a special file (e.g. a named pipe)""" + +class ExecError(EnvironmentError): + """Raised when a command could not be executed""" + +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registry operation with the archiving + and unpacking registries fails""" + + +try: + WindowsError +except NameError: + WindowsError = None + +def copyfileobj(fsrc, fdst, length=16*1024): + """copy data from file-like object fsrc to file-like object fdst""" + while 1: + buf = fsrc.read(length) + if not buf: + break + fdst.write(buf) + +def _samefile(src, dst): + # Macintosh, Unix. + if hasattr(os.path, 'samefile'): + try: + return os.path.samefile(src, dst) + except OSError: + return False + + # All other platforms: check for same pathname. + return (os.path.normcase(os.path.abspath(src)) == + os.path.normcase(os.path.abspath(dst))) + +def copyfile(src, dst): + """Copy data from src to dst""" + if _samefile(src, dst): + raise Error("`%s` and `%s` are the same file" % (src, dst)) + + for fn in [src, dst]: + try: + st = os.stat(fn) + except OSError: + # File most likely does not exist + pass + else: + # XXX What about other special files? (sockets, devices...) + if stat.S_ISFIFO(st.st_mode): + raise SpecialFileError("`%s` is a named pipe" % fn) + + with open(src, 'rb') as fsrc: + with open(dst, 'wb') as fdst: + copyfileobj(fsrc, fdst) + +def copymode(src, dst): + """Copy mode bits from src to dst""" + if hasattr(os, 'chmod'): + st = os.stat(src) + mode = stat.S_IMODE(st.st_mode) + os.chmod(dst, mode) + +def copystat(src, dst): + """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" + st = os.stat(src) + mode = stat.S_IMODE(st.st_mode) + if hasattr(os, 'utime'): + os.utime(dst, (st.st_atime, st.st_mtime)) + if hasattr(os, 'chmod'): + os.chmod(dst, mode) + if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): + try: + os.chflags(dst, st.st_flags) + except OSError as why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise + +def copy(src, dst): + """Copy data and mode bits ("cp src dst"). + + The destination may be a directory. + + """ + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + copyfile(src, dst) + copymode(src, dst) + +def copy2(src, dst): + """Copy data and all stat info ("cp -p src dst"). + + The destination may be a directory. + + """ + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + copyfile(src, dst) + copystat(src, dst) + +def ignore_patterns(*patterns): + """Function that can be used as copytree() ignore parameter. + + Patterns is a sequence of glob-style patterns + that are used to exclude files""" + def _ignore_patterns(path, names): + ignored_names = [] + for pattern in patterns: + ignored_names.extend(fnmatch.filter(names, pattern)) + return set(ignored_names) + return _ignore_patterns + +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. + + The destination directory must not already exist. + If exception(s) occur, an Error is raised with a list of reasons. + + If the optional symlinks flag is true, symbolic links in the + source tree result in symbolic links in the destination tree; if + it is false, the contents of the files pointed to by symbolic + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. + + The optional ignore argument is a callable. If given, it + is called with the `src` parameter, which is the directory + being visited by copytree(), and `names` which is the list of + `src` contents, as returned by os.listdir(): + + callable(src, names) -> ignored_names + + Since copytree() is called recursively, the callable will be + called once for each directory that is copied. It returns a + list of names relative to the `src` directory that should + not be copied. + + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. + + """ + names = os.listdir(src) + if ignore is not None: + ignored_names = ignore(src, names) + else: + ignored_names = set() + + os.makedirs(dst) + errors = [] + for name in names: + if name in ignored_names: + continue + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if os.path.islink(srcname): + linkto = os.readlink(srcname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) + elif os.path.isdir(srcname): + copytree(srcname, dstname, symlinks, ignore, copy_function) + else: + # Will raise a SpecialFileError for unsupported file types + copy_function(srcname, dstname) + # catch the Error from the recursive copytree so that we can + # continue with other files + except Error as err: + errors.extend(err.args[0]) + except EnvironmentError as why: + errors.append((srcname, dstname, str(why))) + try: + copystat(src, dst) + except OSError as why: + if WindowsError is not None and isinstance(why, WindowsError): + # Copying file access times may fail on Windows + pass + else: + errors.extend((src, dst, str(why))) + if errors: + raise Error(errors) + +def rmtree(path, ignore_errors=False, onerror=None): + """Recursively delete a directory tree. + + If ignore_errors is set, errors are ignored; otherwise, if onerror + is set, it is called to handle the error with arguments (func, + path, exc_info) where func is os.listdir, os.remove, or os.rmdir; + path is the argument to that function that caused it to fail; and + exc_info is a tuple returned by sys.exc_info(). If ignore_errors + is false and onerror is None, an exception is raised. + + """ + if ignore_errors: + def onerror(*args): + pass + elif onerror is None: + def onerror(*args): + raise + try: + if os.path.islink(path): + # symlinks to directories are forbidden, see bug #1669 + raise OSError("Cannot call rmtree on a symbolic link") + except OSError: + onerror(os.path.islink, path, sys.exc_info()) + # can't continue even if onerror hook returns + return + names = [] + try: + names = os.listdir(path) + except os.error: + onerror(os.listdir, path, sys.exc_info()) + for name in names: + fullname = os.path.join(path, name) + try: + mode = os.lstat(fullname).st_mode + except os.error: + mode = 0 + if stat.S_ISDIR(mode): + rmtree(fullname, ignore_errors, onerror) + else: + try: + os.remove(fullname) + except os.error: + onerror(os.remove, fullname, sys.exc_info()) + try: + os.rmdir(path) + except os.error: + onerror(os.rmdir, path, sys.exc_info()) + + +def _basename(path): + # A basename() variant which first strips the trailing slash, if present. + # Thus we always get the last component of the path, even for directories. + return os.path.basename(path.rstrip(os.path.sep)) + +def move(src, dst): + """Recursively move a file or directory to another location. This is + similar to the Unix "mv" command. + + If the destination is a directory or a symlink to a directory, the source + is moved inside the directory. The destination path must not already + exist. + + If the destination already exists but is not a directory, it may be + overwritten depending on os.rename() semantics. + + If the destination is on our current filesystem, then rename() is used. + Otherwise, src is copied to the destination and then removed. + A lot more could be done here... A look at a mv.c shows a lot of + the issues this implementation glosses over. + + """ + real_dst = dst + if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + + real_dst = os.path.join(dst, _basename(src)) + if os.path.exists(real_dst): + raise Error("Destination path '%s' already exists" % real_dst) + try: + os.rename(src, real_dst) + except OSError: + if os.path.isdir(src): + if _destinsrc(src, dst): + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) + copytree(src, real_dst, symlinks=True) + rmtree(src) + else: + copy2(src, real_dst) + os.unlink(src) + +def _destinsrc(src, dst): + src = abspath(src) + dst = abspath(dst) + if not src.endswith(os.path.sep): + src += os.path.sep + if not dst.endswith(os.path.sep): + dst += os.path.sep + return dst.startswith(src) + +def _get_gid(name): + """Returns a gid, given a group name.""" + if getgrnam is None or name is None: + return None + try: + result = getgrnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def _get_uid(name): + """Returns an uid, given a user name.""" + if getpwnam is None or name is None: + return None + try: + result = getpwnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, + owner=None, group=None, logger=None): + """Create a (possibly compressed) tar file from all the files under + 'base_dir'. + + 'compress' must be "gzip" (the default), "bzip2", or None. + + 'owner' and 'group' can be used to define an owner and a group for the + archive that is being built. If not provided, the current owner and group + will be used. + + The output tar file will be named 'base_name' + ".tar", possibly plus + the appropriate compression extension (".gz", or ".bz2"). + + Returns the output filename. + """ + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' + + # flags for compression program, each element of list will be an argument + if compress is not None and compress not in compress_ext: + raise ValueError("bad value for 'compress', or compression format not " + "supported : {0}".format(compress)) + + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) + + if not os.path.exists(archive_dir): + if logger is not None: + logger.info("creating %s", archive_dir) + if not dry_run: + os.makedirs(archive_dir) + + # creating the tarball + if logger is not None: + logger.info('Creating tar archive') + + uid = _get_uid(owner) + gid = _get_gid(group) + + def _set_uid_gid(tarinfo): + if gid is not None: + tarinfo.gid = gid + tarinfo.gname = group + if uid is not None: + tarinfo.uid = uid + tarinfo.uname = owner + return tarinfo + + if not dry_run: + tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) + try: + tar.add(base_dir, filter=_set_uid_gid) + finally: + tar.close() + + return archive_name + +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): + # XXX see if we want to keep an external call here + if verbose: + zipoptions = "-r" + else: + zipoptions = "-rq" + from distutils.errors import DistutilsExecError + from distutils.spawn import spawn + try: + spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) + except DistutilsExecError: + # XXX really should distinguish between "couldn't find + # external 'zip' command" and "zip failed". + raise ExecError("unable to create zip file '%s': " + "could neither import the 'zipfile' module nor " + "find a standalone zip utility") % zip_filename + +def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): + """Create a zip file from all the files under 'base_dir'. + + The output zip file will be named 'base_name' + ".zip". Uses either the + "zipfile" Python module (if available) or the InfoZIP "zip" utility + (if installed and found on the default search path). If neither tool is + available, raises ExecError. Returns the name of the output zip + file. + """ + zip_filename = base_name + ".zip" + archive_dir = os.path.dirname(base_name) + + if not os.path.exists(archive_dir): + if logger is not None: + logger.info("creating %s", archive_dir) + if not dry_run: + os.makedirs(archive_dir) + + # If zipfile module is not available, try spawning an external 'zip' + # command. + try: + import zipfile + except ImportError: + zipfile = None + + if zipfile is None: + _call_external_zip(base_dir, zip_filename, verbose, dry_run) + else: + if logger is not None: + logger.info("creating '%s' and adding '%s' to it", + zip_filename, base_dir) + + if not dry_run: + zip = zipfile.ZipFile(zip_filename, "w", + compression=zipfile.ZIP_DEFLATED) + + for dirpath, dirnames, filenames in os.walk(base_dir): + for name in filenames: + path = os.path.normpath(os.path.join(dirpath, name)) + if os.path.isfile(path): + zip.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) + zip.close() + + return zip_filename + +_ARCHIVE_FORMATS = { + 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), + 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), + 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), + 'zip': (_make_zipfile, [], "ZIP file"), + } + +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + +def get_archive_formats(): + """Returns a list of supported formats for archiving and unarchiving. + + Each element of the returned sequence is a tuple (name, description) + """ + formats = [(name, registry[2]) for name, registry in + _ARCHIVE_FORMATS.items()] + formats.sort() + return formats + +def register_archive_format(name, function, extra_args=None, description=''): + """Registers an archive format. + + name is the name of the format. function is the callable that will be + used to create archives. If provided, extra_args is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_archive_formats() function. + """ + if extra_args is None: + extra_args = [] + if not isinstance(function, collections.Callable): + raise TypeError('The %s object is not callable' % function) + if not isinstance(extra_args, (tuple, list)): + raise TypeError('extra_args needs to be a sequence') + for element in extra_args: + if not isinstance(element, (tuple, list)) or len(element) !=2: + raise TypeError('extra_args elements are : (arg_name, value)') + + _ARCHIVE_FORMATS[name] = (function, extra_args, description) + +def unregister_archive_format(name): + del _ARCHIVE_FORMATS[name] + +def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, + dry_run=0, owner=None, group=None, logger=None): + """Create an archive file (eg. zip or tar). + + 'base_name' is the name of the file to create, minus any format-specific + extension; 'format' is the archive format: one of "zip", "tar", "bztar" + or "gztar". + + 'root_dir' is a directory that will be the root directory of the + archive; ie. we typically chdir into 'root_dir' before creating the + archive. 'base_dir' is the directory where we start archiving from; + ie. 'base_dir' will be the common prefix of all files and + directories in the archive. 'root_dir' and 'base_dir' both default + to the current directory. Returns the name of the archive file. + + 'owner' and 'group' are used when creating a tar archive. By default, + uses the current owner and group. + """ + save_cwd = os.getcwd() + if root_dir is not None: + if logger is not None: + logger.debug("changing into '%s'", root_dir) + base_name = os.path.abspath(base_name) + if not dry_run: + os.chdir(root_dir) + + if base_dir is None: + base_dir = os.curdir + + kwargs = {'dry_run': dry_run, 'logger': logger} + + try: + format_info = _ARCHIVE_FORMATS[format] + except KeyError: + raise ValueError("unknown archive format '%s'" % format) + + func = format_info[0] + for arg, val in format_info[1]: + kwargs[arg] = val + + if format != 'zip': + kwargs['owner'] = owner + kwargs['group'] = group + + try: + filename = func(base_name, base_dir, **kwargs) + finally: + if root_dir is not None: + if logger is not None: + logger.debug("changing back to '%s'", save_cwd) + os.chdir(save_cwd) + + return filename + + +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.items()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.items(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not isinstance(function, collections.Callable): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registry.""" + del _UNPACK_FORMATS[name] + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target, 'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } + +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") + +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.items(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None + +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ + if extract_dir is None: + extract_dir = os.getcwd() + + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + + func = format_info[1] + func(filename, extract_dir, **dict(format_info[2])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) + func(filename, extract_dir, **kwargs) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg new file mode 100755 index 0000000..c92cd48 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg @@ -0,0 +1,84 @@ +[posix_prefix] +# Configuration directories. Some of these come straight out of the +# configure script. They are for implementing the other variables, not to +# be used directly in [resource_locations]. +confdir = /etc +datadir = /usr/share +libdir = /usr/lib +statedir = /var +# User resource directory +local = ~/.local/{distribution.name} + +stdlib = {base}/lib/python{py_version_short} +platstdlib = {platbase}/lib/python{py_version_short} +purelib = {base}/lib/python{py_version_short}/site-packages +platlib = {platbase}/lib/python{py_version_short}/site-packages +include = {base}/include/python{py_version_short}{abiflags} +platinclude = {platbase}/include/python{py_version_short}{abiflags} +data = {base} + +[posix_home] +stdlib = {base}/lib/python +platstdlib = {base}/lib/python +purelib = {base}/lib/python +platlib = {base}/lib/python +include = {base}/include/python +platinclude = {base}/include/python +scripts = {base}/bin +data = {base} + +[nt] +stdlib = {base}/Lib +platstdlib = {base}/Lib +purelib = {base}/Lib/site-packages +platlib = {base}/Lib/site-packages +include = {base}/Include +platinclude = {base}/Include +scripts = {base}/Scripts +data = {base} + +[os2] +stdlib = {base}/Lib +platstdlib = {base}/Lib +purelib = {base}/Lib/site-packages +platlib = {base}/Lib/site-packages +include = {base}/Include +platinclude = {base}/Include +scripts = {base}/Scripts +data = {base} + +[os2_home] +stdlib = {userbase}/lib/python{py_version_short} +platstdlib = {userbase}/lib/python{py_version_short} +purelib = {userbase}/lib/python{py_version_short}/site-packages +platlib = {userbase}/lib/python{py_version_short}/site-packages +include = {userbase}/include/python{py_version_short} +scripts = {userbase}/bin +data = {userbase} + +[nt_user] +stdlib = {userbase}/Python{py_version_nodot} +platstdlib = {userbase}/Python{py_version_nodot} +purelib = {userbase}/Python{py_version_nodot}/site-packages +platlib = {userbase}/Python{py_version_nodot}/site-packages +include = {userbase}/Python{py_version_nodot}/Include +scripts = {userbase}/Scripts +data = {userbase} + +[posix_user] +stdlib = {userbase}/lib/python{py_version_short} +platstdlib = {userbase}/lib/python{py_version_short} +purelib = {userbase}/lib/python{py_version_short}/site-packages +platlib = {userbase}/lib/python{py_version_short}/site-packages +include = {userbase}/include/python{py_version_short} +scripts = {userbase}/bin +data = {userbase} + +[osx_framework_user] +stdlib = {userbase}/lib/python +platstdlib = {userbase}/lib/python +purelib = {userbase}/lib/python/site-packages +platlib = {userbase}/lib/python/site-packages +include = {userbase}/include +scripts = {userbase}/bin +data = {userbase} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py new file mode 100755 index 0000000..b243da3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py @@ -0,0 +1,788 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Access to Python's configuration information.""" + +import codecs +import os +import re +import sys +from os.path import pardir, realpath +try: + import configparser +except ImportError: + import ConfigParser as configparser + + +__all__ = [ + 'get_config_h_filename', + 'get_config_var', + 'get_config_vars', + 'get_makefile_filename', + 'get_path', + 'get_path_names', + 'get_paths', + 'get_platform', + 'get_python_version', + 'get_scheme_names', + 'parse_config_h', +] + + +def _safe_realpath(path): + try: + return realpath(path) + except OSError: + return path + + +if sys.executable: + _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable)) +else: + # sys.executable can be empty if argv[0] has been changed and Python is + # unable to retrieve the real program name + _PROJECT_BASE = _safe_realpath(os.getcwd()) + +if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir)) +# PC/VS7.1 +if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) +# PC/AMD64 +if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) + + +def is_python_build(): + for fn in ("Setup.dist", "Setup.local"): + if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): + return True + return False + +_PYTHON_BUILD = is_python_build() + +_cfg_read = False + +def _ensure_cfg_read(): + global _cfg_read + if not _cfg_read: + from ..resources import finder + backport_package = __name__.rsplit('.', 1)[0] + _finder = finder(backport_package) + _cfgfile = _finder.find('sysconfig.cfg') + assert _cfgfile, 'sysconfig.cfg exists' + with _cfgfile.as_stream() as s: + _SCHEMES.readfp(s) + if _PYTHON_BUILD: + for scheme in ('posix_prefix', 'posix_home'): + _SCHEMES.set(scheme, 'include', '{srcdir}/Include') + _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') + + _cfg_read = True + + +_SCHEMES = configparser.RawConfigParser() +_VAR_REPL = re.compile(r'\{([^{]*?)\}') + +def _expand_globals(config): + _ensure_cfg_read() + if config.has_section('globals'): + globals = config.items('globals') + else: + globals = tuple() + + sections = config.sections() + for section in sections: + if section == 'globals': + continue + for option, value in globals: + if config.has_option(section, option): + continue + config.set(section, option, value) + config.remove_section('globals') + + # now expanding local variables defined in the cfg file + # + for section in config.sections(): + variables = dict(config.items(section)) + + def _replacer(matchobj): + name = matchobj.group(1) + if name in variables: + return variables[name] + return matchobj.group(0) + + for option, value in config.items(section): + config.set(section, option, _VAR_REPL.sub(_replacer, value)) + +#_expand_globals(_SCHEMES) + + # FIXME don't rely on sys.version here, its format is an implementation detail + # of CPython, use sys.version_info or sys.hexversion +_PY_VERSION = sys.version.split()[0] +_PY_VERSION_SHORT = sys.version[:3] +_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2] +_PREFIX = os.path.normpath(sys.prefix) +_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) +_CONFIG_VARS = None +_USER_BASE = None + + +def _subst_vars(path, local_vars): + """In the string `path`, replace tokens like {some.thing} with the + corresponding value from the map `local_vars`. + + If there is no corresponding value, leave the token unchanged. + """ + def _replacer(matchobj): + name = matchobj.group(1) + if name in local_vars: + return local_vars[name] + elif name in os.environ: + return os.environ[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, path) + + +def _extend_dict(target_dict, other_dict): + target_keys = target_dict.keys() + for key, value in other_dict.items(): + if key in target_keys: + continue + target_dict[key] = value + + +def _expand_vars(scheme, vars): + res = {} + if vars is None: + vars = {} + _extend_dict(vars, get_config_vars()) + + for key, value in _SCHEMES.items(scheme): + if os.name in ('posix', 'nt'): + value = os.path.expanduser(value) + res[key] = os.path.normpath(_subst_vars(value, vars)) + return res + + +def format_value(value, vars): + def _replacer(matchobj): + name = matchobj.group(1) + if name in vars: + return vars[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, value) + + +def _get_default_scheme(): + if os.name == 'posix': + # the default scheme for posix is posix_prefix + return 'posix_prefix' + return os.name + + +def _getuserbase(): + env_base = os.environ.get("PYTHONUSERBASE", None) + + def joinuser(*args): + return os.path.expanduser(os.path.join(*args)) + + # what about 'os2emx', 'riscos' ? + if os.name == "nt": + base = os.environ.get("APPDATA") or "~" + if env_base: + return env_base + else: + return joinuser(base, "Python") + + if sys.platform == "darwin": + framework = get_config_var("PYTHONFRAMEWORK") + if framework: + if env_base: + return env_base + else: + return joinuser("~", "Library", framework, "%d.%d" % + sys.version_info[:2]) + + if env_base: + return env_base + else: + return joinuser("~", ".local") + + +def _parse_makefile(filename, vars=None): + """Parse a Makefile-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + # Regexes needed for parsing Makefile (and similar syntaxes, + # like old-style Setup files). + _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") + _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") + _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + + if vars is None: + vars = {} + done = {} + notdone = {} + + with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f: + lines = f.readlines() + + for line in lines: + if line.startswith('#') or line.strip() == '': + continue + m = _variable_rx.match(line) + if m: + n, v = m.group(1, 2) + v = v.strip() + # `$$' is a literal `$' in make + tmpv = v.replace('$$', '') + + if "$" in tmpv: + notdone[n] = v + else: + try: + v = int(v) + except ValueError: + # insert literal `$' + done[n] = v.replace('$$', '$') + else: + done[n] = v + + # do variable interpolation here + variables = list(notdone.keys()) + + # Variables with a 'PY_' prefix in the makefile. These need to + # be made available without that prefix through sysconfig. + # Special care is needed to ensure that variable expansion works, even + # if the expansion uses the name without a prefix. + renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') + + while len(variables) > 0: + for name in tuple(variables): + value = notdone[name] + m = _findvar1_rx.search(value) or _findvar2_rx.search(value) + if m is not None: + n = m.group(1) + found = True + if n in done: + item = str(done[n]) + elif n in notdone: + # get it on a subsequent round + found = False + elif n in os.environ: + # do it like make: fall back to environment + item = os.environ[n] + + elif n in renamed_variables: + if (name.startswith('PY_') and + name[3:] in renamed_variables): + item = "" + + elif 'PY_' + n in notdone: + found = False + + else: + item = str(done['PY_' + n]) + + else: + done[n] = item = "" + + if found: + after = value[m.end():] + value = value[:m.start()] + item + after + if "$" in after: + notdone[name] = value + else: + try: + value = int(value) + except ValueError: + done[name] = value.strip() + else: + done[name] = value + variables.remove(name) + + if (name.startswith('PY_') and + name[3:] in renamed_variables): + + name = name[3:] + if name not in done: + done[name] = value + + else: + # bogus variable reference (e.g. "prefix=$/opt/python"); + # just drop it since we can't deal + done[name] = value + variables.remove(name) + + # strip spurious spaces + for k, v in done.items(): + if isinstance(v, str): + done[k] = v.strip() + + # save the results in the global dictionary + vars.update(done) + return vars + + +def get_makefile_filename(): + """Return the path of the Makefile.""" + if _PYTHON_BUILD: + return os.path.join(_PROJECT_BASE, "Makefile") + if hasattr(sys, 'abiflags'): + config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) + else: + config_dir_name = 'config' + return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') + + +def _init_posix(vars): + """Initialize the module as appropriate for POSIX systems.""" + # load the installed Makefile: + makefile = get_makefile_filename() + try: + _parse_makefile(makefile, vars) + except IOError as e: + msg = "invalid Python installation: unable to open %s" % makefile + if hasattr(e, "strerror"): + msg = msg + " (%s)" % e.strerror + raise IOError(msg) + # load the installed pyconfig.h: + config_h = get_config_h_filename() + try: + with open(config_h) as f: + parse_config_h(f, vars) + except IOError as e: + msg = "invalid Python installation: unable to open %s" % config_h + if hasattr(e, "strerror"): + msg = msg + " (%s)" % e.strerror + raise IOError(msg) + # On AIX, there are wrong paths to the linker scripts in the Makefile + # -- these paths are relative to the Python source, but when installed + # the scripts are in another directory. + if _PYTHON_BUILD: + vars['LDSHARED'] = vars['BLDSHARED'] + + +def _init_non_posix(vars): + """Initialize the module as appropriate for NT""" + # set basic install directories + vars['LIBDEST'] = get_path('stdlib') + vars['BINLIBDEST'] = get_path('platstdlib') + vars['INCLUDEPY'] = get_path('include') + vars['SO'] = '.pyd' + vars['EXE'] = '.exe' + vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT + vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) + +# +# public APIs +# + + +def parse_config_h(fp, vars=None): + """Parse a config.h-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + if vars is None: + vars = {} + define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") + undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") + + while True: + line = fp.readline() + if not line: + break + m = define_rx.match(line) + if m: + n, v = m.group(1, 2) + try: + v = int(v) + except ValueError: + pass + vars[n] = v + else: + m = undef_rx.match(line) + if m: + vars[m.group(1)] = 0 + return vars + + +def get_config_h_filename(): + """Return the path of pyconfig.h.""" + if _PYTHON_BUILD: + if os.name == "nt": + inc_dir = os.path.join(_PROJECT_BASE, "PC") + else: + inc_dir = _PROJECT_BASE + else: + inc_dir = get_path('platinclude') + return os.path.join(inc_dir, 'pyconfig.h') + + +def get_scheme_names(): + """Return a tuple containing the schemes names.""" + return tuple(sorted(_SCHEMES.sections())) + + +def get_path_names(): + """Return a tuple containing the paths names.""" + # xxx see if we want a static list + return _SCHEMES.options('posix_prefix') + + +def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): + """Return a mapping containing an install scheme. + + ``scheme`` is the install scheme name. If not provided, it will + return the default scheme for the current platform. + """ + _ensure_cfg_read() + if expand: + return _expand_vars(scheme, vars) + else: + return dict(_SCHEMES.items(scheme)) + + +def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): + """Return a path corresponding to the scheme. + + ``scheme`` is the install scheme name. + """ + return get_paths(scheme, vars, expand)[name] + + +def get_config_vars(*args): + """With no arguments, return a dictionary of all configuration + variables relevant for the current platform. + + On Unix, this means every variable defined in Python's installed Makefile; + On Windows and Mac OS it's a much smaller set. + + With arguments, return a list of values that result from looking up + each argument in the configuration variable dictionary. + """ + global _CONFIG_VARS + if _CONFIG_VARS is None: + _CONFIG_VARS = {} + # Normalized versions of prefix and exec_prefix are handy to have; + # in fact, these are the standard versions used most places in the + # distutils2 module. + _CONFIG_VARS['prefix'] = _PREFIX + _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX + _CONFIG_VARS['py_version'] = _PY_VERSION + _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT + _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] + _CONFIG_VARS['base'] = _PREFIX + _CONFIG_VARS['platbase'] = _EXEC_PREFIX + _CONFIG_VARS['projectbase'] = _PROJECT_BASE + try: + _CONFIG_VARS['abiflags'] = sys.abiflags + except AttributeError: + # sys.abiflags may not be defined on all platforms. + _CONFIG_VARS['abiflags'] = '' + + if os.name in ('nt', 'os2'): + _init_non_posix(_CONFIG_VARS) + if os.name == 'posix': + _init_posix(_CONFIG_VARS) + # Setting 'userbase' is done below the call to the + # init function to enable using 'get_config_var' in + # the init-function. + if sys.version >= '2.6': + _CONFIG_VARS['userbase'] = _getuserbase() + + if 'srcdir' not in _CONFIG_VARS: + _CONFIG_VARS['srcdir'] = _PROJECT_BASE + else: + _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) + + # Convert srcdir into an absolute path if it appears necessary. + # Normally it is relative to the build directory. However, during + # testing, for example, we might be running a non-installed python + # from a different directory. + if _PYTHON_BUILD and os.name == "posix": + base = _PROJECT_BASE + try: + cwd = os.getcwd() + except OSError: + cwd = None + if (not os.path.isabs(_CONFIG_VARS['srcdir']) and + base != cwd): + # srcdir is relative and we are not in the same directory + # as the executable. Assume executable is in the build + # directory and make srcdir absolute. + srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) + _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) + + if sys.platform == 'darwin': + kernel_version = os.uname()[2] # Kernel version (8.4.3) + major_version = int(kernel_version.split('.')[0]) + + if major_version < 8: + # On Mac OS X before 10.4, check if -arch and -isysroot + # are in CFLAGS or LDFLAGS and remove them if they are. + # This is needed when building extensions on a 10.3 system + # using a universal build of python. + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + flags = _CONFIG_VARS[key] + flags = re.sub(r'-arch\s+\w+\s', ' ', flags) + flags = re.sub('-isysroot [^ \t]*', ' ', flags) + _CONFIG_VARS[key] = flags + else: + # Allow the user to override the architecture flags using + # an environment variable. + # NOTE: This name was introduced by Apple in OSX 10.5 and + # is used by several scripting languages distributed with + # that OS release. + if 'ARCHFLAGS' in os.environ: + arch = os.environ['ARCHFLAGS'] + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + + flags = _CONFIG_VARS[key] + flags = re.sub(r'-arch\s+\w+\s', ' ', flags) + flags = flags + ' ' + arch + _CONFIG_VARS[key] = flags + + # If we're on OSX 10.5 or later and the user tries to + # compiles an extension using an SDK that is not present + # on the current machine it is better to not use an SDK + # than to fail. + # + # The major usecase for this is users using a Python.org + # binary installer on OSX 10.6: that installer uses + # the 10.4u SDK, but that SDK is not installed by default + # when you install Xcode. + # + CFLAGS = _CONFIG_VARS.get('CFLAGS', '') + m = re.search(r'-isysroot\s+(\S+)', CFLAGS) + if m is not None: + sdk = m.group(1) + if not os.path.exists(sdk): + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + + flags = _CONFIG_VARS[key] + flags = re.sub(r'-isysroot\s+\S+(\s|$)', ' ', flags) + _CONFIG_VARS[key] = flags + + if args: + vals = [] + for name in args: + vals.append(_CONFIG_VARS.get(name)) + return vals + else: + return _CONFIG_VARS + + +def get_config_var(name): + """Return the value of a single variable using the dictionary returned by + 'get_config_vars()'. + + Equivalent to get_config_vars().get(name) + """ + return get_config_vars().get(name) + + +def get_platform(): + """Return a string that identifies the current platform. + + This is used mainly to distinguish platform-specific build directories and + platform-specific built distributions. Typically includes the OS name + and version and the architecture (as supplied by 'os.uname()'), + although the exact information included depends on the OS; eg. for IRIX + the architecture isn't particularly important (IRIX only runs on SGI + hardware), but for Linux the kernel version isn't particularly + important. + + Examples of returned values: + linux-i586 + linux-alpha (?) + solaris-2.6-sun4u + irix-5.3 + irix64-6.2 + + Windows will return one of: + win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) + win-ia64 (64bit Windows on Itanium) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. + """ + if os.name == 'nt': + # sniff sys.version for architecture. + prefix = " bit (" + i = sys.version.find(prefix) + if i == -1: + return sys.platform + j = sys.version.find(")", i) + look = sys.version[i+len(prefix):j].lower() + if look == 'amd64': + return 'win-amd64' + if look == 'itanium': + return 'win-ia64' + return sys.platform + + if os.name != "posix" or not hasattr(os, 'uname'): + # XXX what about the architecture? NT is Intel or Alpha, + # Mac OS is M68k or PPC, etc. + return sys.platform + + # Try to distinguish various flavours of Unix + osname, host, release, version, machine = os.uname() + + # Convert the OS name to lowercase, remove '/' characters + # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") + osname = osname.lower().replace('/', '') + machine = machine.replace(' ', '_') + machine = machine.replace('/', '-') + + if osname[:5] == "linux": + # At least on Linux/Intel, 'machine' is the processor -- + # i386, etc. + # XXX what about Alpha, SPARC, etc? + return "%s-%s" % (osname, machine) + elif osname[:5] == "sunos": + if release[0] >= "5": # SunOS 5 == Solaris 2 + osname = "solaris" + release = "%d.%s" % (int(release[0]) - 3, release[2:]) + # fall through to standard osname-release-machine representation + elif osname[:4] == "irix": # could be "irix64"! + return "%s-%s" % (osname, release) + elif osname[:3] == "aix": + return "%s-%s.%s" % (osname, version, release) + elif osname[:6] == "cygwin": + osname = "cygwin" + rel_re = re.compile(r'[\d.]+') + m = rel_re.match(release) + if m: + release = m.group() + elif osname[:6] == "darwin": + # + # For our purposes, we'll assume that the system version from + # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set + # to. This makes the compatibility story a bit more sane because the + # machine is going to compile and link as if it were + # MACOSX_DEPLOYMENT_TARGET. + cfgvars = get_config_vars() + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + + if True: + # Always calculate the release of the running machine, + # needed to determine if we can build fat binaries or not. + + macrelease = macver + # Get the system version. Reading this plist is a documented + # way to get the system version (see the documentation for + # the Gestalt Manager) + try: + f = open('/System/Library/CoreServices/SystemVersion.plist') + except IOError: + # We're on a plain darwin box, fall back to the default + # behaviour. + pass + else: + try: + m = re.search(r'<key>ProductUserVisibleVersion</key>\s*' + r'<string>(.*?)</string>', f.read()) + finally: + f.close() + if m is not None: + macrelease = '.'.join(m.group(1).split('.')[:2]) + # else: fall back to the default behaviour + + if not macver: + macver = macrelease + + if macver: + release = macver + osname = "macosx" + + if ((macrelease + '.') >= '10.4.' and + '-arch' in get_config_vars().get('CFLAGS', '').strip()): + # The universal build will build fat binaries, but not on + # systems before 10.4 + # + # Try to detect 4-way universal builds, those have machine-type + # 'universal' instead of 'fat'. + + machine = 'fat' + cflags = get_config_vars().get('CFLAGS') + + archs = re.findall(r'-arch\s+(\S+)', cflags) + archs = tuple(sorted(set(archs))) + + if len(archs) == 1: + machine = archs[0] + elif archs == ('i386', 'ppc'): + machine = 'fat' + elif archs == ('i386', 'x86_64'): + machine = 'intel' + elif archs == ('i386', 'ppc', 'x86_64'): + machine = 'fat3' + elif archs == ('ppc64', 'x86_64'): + machine = 'fat64' + elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): + machine = 'universal' + else: + raise ValueError( + "Don't know machine value for archs=%r" % (archs,)) + + elif machine == 'i386': + # On OSX the machine type returned by uname is always the + # 32-bit variant, even if the executable architecture is + # the 64-bit variant + if sys.maxsize >= 2**32: + machine = 'x86_64' + + elif machine in ('PowerPC', 'Power_Macintosh'): + # Pick a sane name for the PPC architecture. + # See 'i386' case + if sys.maxsize >= 2**32: + machine = 'ppc64' + else: + machine = 'ppc' + + return "%s-%s-%s" % (osname, release, machine) + + +def get_python_version(): + return _PY_VERSION_SHORT + + +def _print_dict(title, data): + for index, (key, value) in enumerate(sorted(data.items())): + if index == 0: + print('%s: ' % (title)) + print('\t%s = "%s"' % (key, value)) + + +def _main(): + """Display all information sysconfig detains.""" + print('Platform: "%s"' % get_platform()) + print('Python version: "%s"' % get_python_version()) + print('Current installation scheme: "%s"' % _get_default_scheme()) + print() + _print_dict('Paths', get_paths()) + print() + _print_dict('Variables', get_config_vars()) + + +if __name__ == '__main__': + _main() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py new file mode 100755 index 0000000..b0599bc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py @@ -0,0 +1,2607 @@ +#------------------------------------------------------------------- +# tarfile.py +#------------------------------------------------------------------- +# Copyright (C) 2002 Lars Gustaebel <lars@gustaebel.de> +# All rights reserved. +# +# 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 print_function + +"""Read from and write to tar format archives. +""" + +__version__ = "$Revision$" + +version = "0.9.0" +__author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" +__date__ = "$Date: 2011-02-25 17:42:01 +0200 (Fri, 25 Feb 2011) $" +__cvsid__ = "$Id: tarfile.py 88586 2011-02-25 15:42:01Z marc-andre.lemburg $" +__credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." + +#--------- +# Imports +#--------- +import sys +import os +import stat +import errno +import time +import struct +import copy +import re + +try: + import grp, pwd +except ImportError: + grp = pwd = None + +# os.symlink on Windows prior to 6.0 raises NotImplementedError +symlink_exception = (AttributeError, NotImplementedError) +try: + # WindowsError (1314) will be raised if the caller does not hold the + # SeCreateSymbolicLinkPrivilege privilege + symlink_exception += (WindowsError,) +except NameError: + pass + +# from tarfile import * +__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] + +if sys.version_info[0] < 3: + import __builtin__ as builtins +else: + import builtins + +_open = builtins.open # Since 'open' is TarFile.open + +#--------------------------------------------------------- +# tar constants +#--------------------------------------------------------- +NUL = b"\0" # the null character +BLOCKSIZE = 512 # length of processing blocks +RECORDSIZE = BLOCKSIZE * 20 # length of records +GNU_MAGIC = b"ustar \0" # magic gnu tar string +POSIX_MAGIC = b"ustar\x0000" # magic posix tar string + +LENGTH_NAME = 100 # maximum length of a filename +LENGTH_LINK = 100 # maximum length of a linkname +LENGTH_PREFIX = 155 # maximum length of the prefix field + +REGTYPE = b"0" # regular file +AREGTYPE = b"\0" # regular file +LNKTYPE = b"1" # link (inside tarfile) +SYMTYPE = b"2" # symbolic link +CHRTYPE = b"3" # character special device +BLKTYPE = b"4" # block special device +DIRTYPE = b"5" # directory +FIFOTYPE = b"6" # fifo special device +CONTTYPE = b"7" # contiguous file + +GNUTYPE_LONGNAME = b"L" # GNU tar longname +GNUTYPE_LONGLINK = b"K" # GNU tar longlink +GNUTYPE_SPARSE = b"S" # GNU tar sparse file + +XHDTYPE = b"x" # POSIX.1-2001 extended header +XGLTYPE = b"g" # POSIX.1-2001 global header +SOLARIS_XHDTYPE = b"X" # Solaris extended header + +USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format +GNU_FORMAT = 1 # GNU tar format +PAX_FORMAT = 2 # POSIX.1-2001 (pax) format +DEFAULT_FORMAT = GNU_FORMAT + +#--------------------------------------------------------- +# tarfile constants +#--------------------------------------------------------- +# File types that tarfile supports: +SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, + SYMTYPE, DIRTYPE, FIFOTYPE, + CONTTYPE, CHRTYPE, BLKTYPE, + GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, + GNUTYPE_SPARSE) + +# File types that will be treated as a regular file. +REGULAR_TYPES = (REGTYPE, AREGTYPE, + CONTTYPE, GNUTYPE_SPARSE) + +# File types that are part of the GNU tar format. +GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, + GNUTYPE_SPARSE) + +# Fields from a pax header that override a TarInfo attribute. +PAX_FIELDS = ("path", "linkpath", "size", "mtime", + "uid", "gid", "uname", "gname") + +# Fields from a pax header that are affected by hdrcharset. +PAX_NAME_FIELDS = set(("path", "linkpath", "uname", "gname")) + +# Fields in a pax header that are numbers, all other fields +# are treated as strings. +PAX_NUMBER_FIELDS = { + "atime": float, + "ctime": float, + "mtime": float, + "uid": int, + "gid": int, + "size": int +} + +#--------------------------------------------------------- +# Bits used in the mode field, values in octal. +#--------------------------------------------------------- +S_IFLNK = 0o120000 # symbolic link +S_IFREG = 0o100000 # regular file +S_IFBLK = 0o060000 # block device +S_IFDIR = 0o040000 # directory +S_IFCHR = 0o020000 # character device +S_IFIFO = 0o010000 # fifo + +TSUID = 0o4000 # set UID on execution +TSGID = 0o2000 # set GID on execution +TSVTX = 0o1000 # reserved + +TUREAD = 0o400 # read by owner +TUWRITE = 0o200 # write by owner +TUEXEC = 0o100 # execute/search by owner +TGREAD = 0o040 # read by group +TGWRITE = 0o020 # write by group +TGEXEC = 0o010 # execute/search by group +TOREAD = 0o004 # read by other +TOWRITE = 0o002 # write by other +TOEXEC = 0o001 # execute/search by other + +#--------------------------------------------------------- +# initialization +#--------------------------------------------------------- +if os.name in ("nt", "ce"): + ENCODING = "utf-8" +else: + ENCODING = sys.getfilesystemencoding() + +#--------------------------------------------------------- +# Some useful functions +#--------------------------------------------------------- + +def stn(s, length, encoding, errors): + """Convert a string to a null-terminated bytes object. + """ + s = s.encode(encoding, errors) + return s[:length] + (length - len(s)) * NUL + +def nts(s, encoding, errors): + """Convert a null-terminated bytes object to a string. + """ + p = s.find(b"\0") + if p != -1: + s = s[:p] + return s.decode(encoding, errors) + +def nti(s): + """Convert a number field to a python number. + """ + # There are two possible encodings for a number field, see + # itn() below. + if s[0] != chr(0o200): + try: + n = int(nts(s, "ascii", "strict") or "0", 8) + except ValueError: + raise InvalidHeaderError("invalid header") + else: + n = 0 + for i in range(len(s) - 1): + n <<= 8 + n += ord(s[i + 1]) + return n + +def itn(n, digits=8, format=DEFAULT_FORMAT): + """Convert a python number to a number field. + """ + # POSIX 1003.1-1988 requires numbers to be encoded as a string of + # octal digits followed by a null-byte, this allows values up to + # (8**(digits-1))-1. GNU tar allows storing numbers greater than + # that if necessary. A leading 0o200 byte indicates this particular + # encoding, the following digits-1 bytes are a big-endian + # representation. This allows values up to (256**(digits-1))-1. + if 0 <= n < 8 ** (digits - 1): + s = ("%0*o" % (digits - 1, n)).encode("ascii") + NUL + else: + if format != GNU_FORMAT or n >= 256 ** (digits - 1): + raise ValueError("overflow in number field") + + if n < 0: + # XXX We mimic GNU tar's behaviour with negative numbers, + # this could raise OverflowError. + n = struct.unpack("L", struct.pack("l", n))[0] + + s = bytearray() + for i in range(digits - 1): + s.insert(0, n & 0o377) + n >>= 8 + s.insert(0, 0o200) + return s + +def calc_chksums(buf): + """Calculate the checksum for a member's header by summing up all + characters except for the chksum field which is treated as if + it was filled with spaces. According to the GNU tar sources, + some tars (Sun and NeXT) calculate chksum with signed char, + which will be different if there are chars in the buffer with + the high bit set. So we calculate two checksums, unsigned and + signed. + """ + unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) + signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) + return unsigned_chksum, signed_chksum + +def copyfileobj(src, dst, length=None): + """Copy length bytes from fileobj src to fileobj dst. + If length is None, copy the entire content. + """ + if length == 0: + return + if length is None: + while True: + buf = src.read(16*1024) + if not buf: + break + dst.write(buf) + return + + BUFSIZE = 16 * 1024 + blocks, remainder = divmod(length, BUFSIZE) + for b in range(blocks): + buf = src.read(BUFSIZE) + if len(buf) < BUFSIZE: + raise IOError("end of file reached") + dst.write(buf) + + if remainder != 0: + buf = src.read(remainder) + if len(buf) < remainder: + raise IOError("end of file reached") + dst.write(buf) + return + +filemode_table = ( + ((S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p")), + + ((TUREAD, "r"),), + ((TUWRITE, "w"),), + ((TUEXEC|TSUID, "s"), + (TSUID, "S"), + (TUEXEC, "x")), + + ((TGREAD, "r"),), + ((TGWRITE, "w"),), + ((TGEXEC|TSGID, "s"), + (TSGID, "S"), + (TGEXEC, "x")), + + ((TOREAD, "r"),), + ((TOWRITE, "w"),), + ((TOEXEC|TSVTX, "t"), + (TSVTX, "T"), + (TOEXEC, "x")) +) + +def filemode(mode): + """Convert a file's mode to a string of the form + -rwxrwxrwx. + Used by TarFile.list() + """ + perm = [] + for table in filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) + +class TarError(Exception): + """Base exception.""" + pass +class ExtractError(TarError): + """General exception for extract errors.""" + pass +class ReadError(TarError): + """Exception for unreadable tar archives.""" + pass +class CompressionError(TarError): + """Exception for unavailable compression methods.""" + pass +class StreamError(TarError): + """Exception for unsupported operations on stream-like TarFiles.""" + pass +class HeaderError(TarError): + """Base exception for header errors.""" + pass +class EmptyHeaderError(HeaderError): + """Exception for empty headers.""" + pass +class TruncatedHeaderError(HeaderError): + """Exception for truncated headers.""" + pass +class EOFHeaderError(HeaderError): + """Exception for end of file headers.""" + pass +class InvalidHeaderError(HeaderError): + """Exception for invalid headers.""" + pass +class SubsequentHeaderError(HeaderError): + """Exception for missing and invalid extended headers.""" + pass + +#--------------------------- +# internal stream interface +#--------------------------- +class _LowLevelFile(object): + """Low-level file object. Supports reading and writing. + It is used instead of a regular file object for streaming + access. + """ + + def __init__(self, name, mode): + mode = { + "r": os.O_RDONLY, + "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, + }[mode] + if hasattr(os, "O_BINARY"): + mode |= os.O_BINARY + self.fd = os.open(name, mode, 0o666) + + def close(self): + os.close(self.fd) + + def read(self, size): + return os.read(self.fd, size) + + def write(self, s): + os.write(self.fd, s) + +class _Stream(object): + """Class that serves as an adapter between TarFile and + a stream-like object. The stream-like object only + needs to have a read() or write() method and is accessed + blockwise. Use of gzip or bzip2 compression is possible. + A stream-like object could be for example: sys.stdin, + sys.stdout, a socket, a tape device etc. + + _Stream is intended to be used only internally. + """ + + def __init__(self, name, mode, comptype, fileobj, bufsize): + """Construct a _Stream object. + """ + self._extfileobj = True + if fileobj is None: + fileobj = _LowLevelFile(name, mode) + self._extfileobj = False + + if comptype == '*': + # Enable transparent compression detection for the + # stream interface + fileobj = _StreamProxy(fileobj) + comptype = fileobj.getcomptype() + + self.name = name or "" + self.mode = mode + self.comptype = comptype + self.fileobj = fileobj + self.bufsize = bufsize + self.buf = b"" + self.pos = 0 + self.closed = False + + try: + if comptype == "gz": + try: + import zlib + except ImportError: + raise CompressionError("zlib module is not available") + self.zlib = zlib + self.crc = zlib.crc32(b"") + if mode == "r": + self._init_read_gz() + else: + self._init_write_gz() + + if comptype == "bz2": + try: + import bz2 + except ImportError: + raise CompressionError("bz2 module is not available") + if mode == "r": + self.dbuf = b"" + self.cmp = bz2.BZ2Decompressor() + else: + self.cmp = bz2.BZ2Compressor() + except: + if not self._extfileobj: + self.fileobj.close() + self.closed = True + raise + + def __del__(self): + if hasattr(self, "closed") and not self.closed: + self.close() + + def _init_write_gz(self): + """Initialize for writing with gzip compression. + """ + self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, + -self.zlib.MAX_WBITS, + self.zlib.DEF_MEM_LEVEL, + 0) + timestamp = struct.pack("<L", int(time.time())) + self.__write(b"\037\213\010\010" + timestamp + b"\002\377") + if self.name.endswith(".gz"): + self.name = self.name[:-3] + # RFC1952 says we must use ISO-8859-1 for the FNAME field. + self.__write(self.name.encode("iso-8859-1", "replace") + NUL) + + def write(self, s): + """Write string s to the stream. + """ + if self.comptype == "gz": + self.crc = self.zlib.crc32(s, self.crc) + self.pos += len(s) + if self.comptype != "tar": + s = self.cmp.compress(s) + self.__write(s) + + def __write(self, s): + """Write string s to the stream if a whole new block + is ready to be written. + """ + self.buf += s + while len(self.buf) > self.bufsize: + self.fileobj.write(self.buf[:self.bufsize]) + self.buf = self.buf[self.bufsize:] + + def close(self): + """Close the _Stream object. No operation should be + done on it afterwards. + """ + if self.closed: + return + + if self.mode == "w" and self.comptype != "tar": + self.buf += self.cmp.flush() + + if self.mode == "w" and self.buf: + self.fileobj.write(self.buf) + self.buf = b"" + if self.comptype == "gz": + # The native zlib crc is an unsigned 32-bit integer, but + # the Python wrapper implicitly casts that to a signed C + # long. So, on a 32-bit box self.crc may "look negative", + # while the same crc on a 64-bit box may "look positive". + # To avoid irksome warnings from the `struct` module, force + # it to look positive on all boxes. + self.fileobj.write(struct.pack("<L", self.crc & 0xffffffff)) + self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFF)) + + if not self._extfileobj: + self.fileobj.close() + + self.closed = True + + def _init_read_gz(self): + """Initialize for reading a gzip compressed fileobj. + """ + self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS) + self.dbuf = b"" + + # taken from gzip.GzipFile with some alterations + if self.__read(2) != b"\037\213": + raise ReadError("not a gzip file") + if self.__read(1) != b"\010": + raise CompressionError("unsupported compression method") + + flag = ord(self.__read(1)) + self.__read(6) + + if flag & 4: + xlen = ord(self.__read(1)) + 256 * ord(self.__read(1)) + self.read(xlen) + if flag & 8: + while True: + s = self.__read(1) + if not s or s == NUL: + break + if flag & 16: + while True: + s = self.__read(1) + if not s or s == NUL: + break + if flag & 2: + self.__read(2) + + def tell(self): + """Return the stream's file pointer position. + """ + return self.pos + + def seek(self, pos=0): + """Set the stream's file pointer to pos. Negative seeking + is forbidden. + """ + if pos - self.pos >= 0: + blocks, remainder = divmod(pos - self.pos, self.bufsize) + for i in range(blocks): + self.read(self.bufsize) + self.read(remainder) + else: + raise StreamError("seeking backwards is not allowed") + return self.pos + + def read(self, size=None): + """Return the next size number of bytes from the stream. + If size is not defined, return all bytes of the stream + up to EOF. + """ + if size is None: + t = [] + while True: + buf = self._read(self.bufsize) + if not buf: + break + t.append(buf) + buf = "".join(t) + else: + buf = self._read(size) + self.pos += len(buf) + return buf + + def _read(self, size): + """Return size bytes from the stream. + """ + if self.comptype == "tar": + return self.__read(size) + + c = len(self.dbuf) + while c < size: + buf = self.__read(self.bufsize) + if not buf: + break + try: + buf = self.cmp.decompress(buf) + except IOError: + raise ReadError("invalid compressed data") + self.dbuf += buf + c += len(buf) + buf = self.dbuf[:size] + self.dbuf = self.dbuf[size:] + return buf + + def __read(self, size): + """Return size bytes from stream. If internal buffer is empty, + read another block from the stream. + """ + c = len(self.buf) + while c < size: + buf = self.fileobj.read(self.bufsize) + if not buf: + break + self.buf += buf + c += len(buf) + buf = self.buf[:size] + self.buf = self.buf[size:] + return buf +# class _Stream + +class _StreamProxy(object): + """Small proxy class that enables transparent compression + detection for the Stream interface (mode 'r|*'). + """ + + def __init__(self, fileobj): + self.fileobj = fileobj + self.buf = self.fileobj.read(BLOCKSIZE) + + def read(self, size): + self.read = self.fileobj.read + return self.buf + + def getcomptype(self): + if self.buf.startswith(b"\037\213\010"): + return "gz" + if self.buf.startswith(b"BZh91"): + return "bz2" + return "tar" + + def close(self): + self.fileobj.close() +# class StreamProxy + +class _BZ2Proxy(object): + """Small proxy class that enables external file object + support for "r:bz2" and "w:bz2" modes. This is actually + a workaround for a limitation in bz2 module's BZ2File + class which (unlike gzip.GzipFile) has no support for + a file object argument. + """ + + blocksize = 16 * 1024 + + def __init__(self, fileobj, mode): + self.fileobj = fileobj + self.mode = mode + self.name = getattr(self.fileobj, "name", None) + self.init() + + def init(self): + import bz2 + self.pos = 0 + if self.mode == "r": + self.bz2obj = bz2.BZ2Decompressor() + self.fileobj.seek(0) + self.buf = b"" + else: + self.bz2obj = bz2.BZ2Compressor() + + def read(self, size): + x = len(self.buf) + while x < size: + raw = self.fileobj.read(self.blocksize) + if not raw: + break + data = self.bz2obj.decompress(raw) + self.buf += data + x += len(data) + + buf = self.buf[:size] + self.buf = self.buf[size:] + self.pos += len(buf) + return buf + + def seek(self, pos): + if pos < self.pos: + self.init() + self.read(pos - self.pos) + + def tell(self): + return self.pos + + def write(self, data): + self.pos += len(data) + raw = self.bz2obj.compress(data) + self.fileobj.write(raw) + + def close(self): + if self.mode == "w": + raw = self.bz2obj.flush() + self.fileobj.write(raw) +# class _BZ2Proxy + +#------------------------ +# Extraction file object +#------------------------ +class _FileInFile(object): + """A thin wrapper around an existing file object that + provides a part of its data as an individual file + object. + """ + + def __init__(self, fileobj, offset, size, blockinfo=None): + self.fileobj = fileobj + self.offset = offset + self.size = size + self.position = 0 + + if blockinfo is None: + blockinfo = [(0, size)] + + # Construct a map with data and zero blocks. + self.map_index = 0 + self.map = [] + lastpos = 0 + realpos = self.offset + for offset, size in blockinfo: + if offset > lastpos: + self.map.append((False, lastpos, offset, None)) + self.map.append((True, offset, offset + size, realpos)) + realpos += size + lastpos = offset + size + if lastpos < self.size: + self.map.append((False, lastpos, self.size, None)) + + def seekable(self): + if not hasattr(self.fileobj, "seekable"): + # XXX gzip.GzipFile and bz2.BZ2File + return True + return self.fileobj.seekable() + + def tell(self): + """Return the current file position. + """ + return self.position + + def seek(self, position): + """Seek to a position in the file. + """ + self.position = position + + def read(self, size=None): + """Read data from the file. + """ + if size is None: + size = self.size - self.position + else: + size = min(size, self.size - self.position) + + buf = b"" + while size > 0: + while True: + data, start, stop, offset = self.map[self.map_index] + if start <= self.position < stop: + break + else: + self.map_index += 1 + if self.map_index == len(self.map): + self.map_index = 0 + length = min(size, stop - self.position) + if data: + self.fileobj.seek(offset + (self.position - start)) + buf += self.fileobj.read(length) + else: + buf += NUL * length + size -= length + self.position += length + return buf +#class _FileInFile + + +class ExFileObject(object): + """File-like object for reading an archive member. + Is returned by TarFile.extractfile(). + """ + blocksize = 1024 + + def __init__(self, tarfile, tarinfo): + self.fileobj = _FileInFile(tarfile.fileobj, + tarinfo.offset_data, + tarinfo.size, + tarinfo.sparse) + self.name = tarinfo.name + self.mode = "r" + self.closed = False + self.size = tarinfo.size + + self.position = 0 + self.buffer = b"" + + def readable(self): + return True + + def writable(self): + return False + + def seekable(self): + return self.fileobj.seekable() + + def read(self, size=None): + """Read at most size bytes from the file. If size is not + present or None, read all data until EOF is reached. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + buf = b"" + if self.buffer: + if size is None: + buf = self.buffer + self.buffer = b"" + else: + buf = self.buffer[:size] + self.buffer = self.buffer[size:] + + if size is None: + buf += self.fileobj.read() + else: + buf += self.fileobj.read(size - len(buf)) + + self.position += len(buf) + return buf + + # XXX TextIOWrapper uses the read1() method. + read1 = read + + def readline(self, size=-1): + """Read one entire line from the file. If size is present + and non-negative, return a string with at most that + size, which may be an incomplete line. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + pos = self.buffer.find(b"\n") + 1 + if pos == 0: + # no newline found. + while True: + buf = self.fileobj.read(self.blocksize) + self.buffer += buf + if not buf or b"\n" in buf: + pos = self.buffer.find(b"\n") + 1 + if pos == 0: + # no newline found. + pos = len(self.buffer) + break + + if size != -1: + pos = min(size, pos) + + buf = self.buffer[:pos] + self.buffer = self.buffer[pos:] + self.position += len(buf) + return buf + + def readlines(self): + """Return a list with all remaining lines. + """ + result = [] + while True: + line = self.readline() + if not line: break + result.append(line) + return result + + def tell(self): + """Return the current file position. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + return self.position + + def seek(self, pos, whence=os.SEEK_SET): + """Seek to a position in the file. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + if whence == os.SEEK_SET: + self.position = min(max(pos, 0), self.size) + elif whence == os.SEEK_CUR: + if pos < 0: + self.position = max(self.position + pos, 0) + else: + self.position = min(self.position + pos, self.size) + elif whence == os.SEEK_END: + self.position = max(min(self.size + pos, self.size), 0) + else: + raise ValueError("Invalid argument") + + self.buffer = b"" + self.fileobj.seek(self.position) + + def close(self): + """Close the file object. + """ + self.closed = True + + def __iter__(self): + """Get an iterator over the file's lines. + """ + while True: + line = self.readline() + if not line: + break + yield line +#class ExFileObject + +#------------------ +# Exported Classes +#------------------ +class TarInfo(object): + """Informational class which holds the details about an + archive member given by a tar header block. + TarInfo objects are returned by TarFile.getmember(), + TarFile.getmembers() and TarFile.gettarinfo() and are + usually created internally. + """ + + __slots__ = ("name", "mode", "uid", "gid", "size", "mtime", + "chksum", "type", "linkname", "uname", "gname", + "devmajor", "devminor", + "offset", "offset_data", "pax_headers", "sparse", + "tarfile", "_sparse_structs", "_link_target") + + def __init__(self, name=""): + """Construct a TarInfo object. name is the optional name + of the member. + """ + self.name = name # member name + self.mode = 0o644 # file permissions + self.uid = 0 # user id + self.gid = 0 # group id + self.size = 0 # file size + self.mtime = 0 # modification time + self.chksum = 0 # header checksum + self.type = REGTYPE # member type + self.linkname = "" # link name + self.uname = "" # user name + self.gname = "" # group name + self.devmajor = 0 # device major number + self.devminor = 0 # device minor number + + self.offset = 0 # the tar header starts here + self.offset_data = 0 # the file's data starts here + + self.sparse = None # sparse member information + self.pax_headers = {} # pax header information + + # In pax headers the "name" and "linkname" field are called + # "path" and "linkpath". + def _getpath(self): + return self.name + def _setpath(self, name): + self.name = name + path = property(_getpath, _setpath) + + def _getlinkpath(self): + return self.linkname + def _setlinkpath(self, linkname): + self.linkname = linkname + linkpath = property(_getlinkpath, _setlinkpath) + + def __repr__(self): + return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) + + def get_info(self): + """Return the TarInfo's attributes as a dictionary. + """ + info = { + "name": self.name, + "mode": self.mode & 0o7777, + "uid": self.uid, + "gid": self.gid, + "size": self.size, + "mtime": self.mtime, + "chksum": self.chksum, + "type": self.type, + "linkname": self.linkname, + "uname": self.uname, + "gname": self.gname, + "devmajor": self.devmajor, + "devminor": self.devminor + } + + if info["type"] == DIRTYPE and not info["name"].endswith("/"): + info["name"] += "/" + + return info + + def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescape"): + """Return a tar header as a string of 512 byte blocks. + """ + info = self.get_info() + + if format == USTAR_FORMAT: + return self.create_ustar_header(info, encoding, errors) + elif format == GNU_FORMAT: + return self.create_gnu_header(info, encoding, errors) + elif format == PAX_FORMAT: + return self.create_pax_header(info, encoding) + else: + raise ValueError("invalid format") + + def create_ustar_header(self, info, encoding, errors): + """Return the object as a ustar header block. + """ + info["magic"] = POSIX_MAGIC + + if len(info["linkname"]) > LENGTH_LINK: + raise ValueError("linkname is too long") + + if len(info["name"]) > LENGTH_NAME: + info["prefix"], info["name"] = self._posix_split_name(info["name"]) + + return self._create_header(info, USTAR_FORMAT, encoding, errors) + + def create_gnu_header(self, info, encoding, errors): + """Return the object as a GNU header block sequence. + """ + info["magic"] = GNU_MAGIC + + buf = b"" + if len(info["linkname"]) > LENGTH_LINK: + buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK, encoding, errors) + + if len(info["name"]) > LENGTH_NAME: + buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME, encoding, errors) + + return buf + self._create_header(info, GNU_FORMAT, encoding, errors) + + def create_pax_header(self, info, encoding): + """Return the object as a ustar header block. If it cannot be + represented this way, prepend a pax extended header sequence + with supplement information. + """ + info["magic"] = POSIX_MAGIC + pax_headers = self.pax_headers.copy() + + # Test string fields for values that exceed the field length or cannot + # be represented in ASCII encoding. + for name, hname, length in ( + ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), + ("uname", "uname", 32), ("gname", "gname", 32)): + + if hname in pax_headers: + # The pax header has priority. + continue + + # Try to encode the string as ASCII. + try: + info[name].encode("ascii", "strict") + except UnicodeEncodeError: + pax_headers[hname] = info[name] + continue + + if len(info[name]) > length: + pax_headers[hname] = info[name] + + # Test number fields for values that exceed the field limit or values + # that like to be stored as float. + for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): + if name in pax_headers: + # The pax header has priority. Avoid overflow. + info[name] = 0 + continue + + val = info[name] + if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): + pax_headers[name] = str(val) + info[name] = 0 + + # Create a pax extended header if necessary. + if pax_headers: + buf = self._create_pax_generic_header(pax_headers, XHDTYPE, encoding) + else: + buf = b"" + + return buf + self._create_header(info, USTAR_FORMAT, "ascii", "replace") + + @classmethod + def create_pax_global_header(cls, pax_headers): + """Return the object as a pax global header block sequence. + """ + return cls._create_pax_generic_header(pax_headers, XGLTYPE, "utf8") + + def _posix_split_name(self, name): + """Split a name longer than 100 chars into a prefix + and a name part. + """ + prefix = name[:LENGTH_PREFIX + 1] + while prefix and prefix[-1] != "/": + prefix = prefix[:-1] + + name = name[len(prefix):] + prefix = prefix[:-1] + + if not prefix or len(name) > LENGTH_NAME: + raise ValueError("name is too long") + return prefix, name + + @staticmethod + def _create_header(info, format, encoding, errors): + """Return a header block. info is a dictionary with file + information, format must be one of the *_FORMAT constants. + """ + parts = [ + stn(info.get("name", ""), 100, encoding, errors), + itn(info.get("mode", 0) & 0o7777, 8, format), + itn(info.get("uid", 0), 8, format), + itn(info.get("gid", 0), 8, format), + itn(info.get("size", 0), 12, format), + itn(info.get("mtime", 0), 12, format), + b" ", # checksum field + info.get("type", REGTYPE), + stn(info.get("linkname", ""), 100, encoding, errors), + info.get("magic", POSIX_MAGIC), + stn(info.get("uname", ""), 32, encoding, errors), + stn(info.get("gname", ""), 32, encoding, errors), + itn(info.get("devmajor", 0), 8, format), + itn(info.get("devminor", 0), 8, format), + stn(info.get("prefix", ""), 155, encoding, errors) + ] + + buf = struct.pack("%ds" % BLOCKSIZE, b"".join(parts)) + chksum = calc_chksums(buf[-BLOCKSIZE:])[0] + buf = buf[:-364] + ("%06o\0" % chksum).encode("ascii") + buf[-357:] + return buf + + @staticmethod + def _create_payload(payload): + """Return the string payload filled with zero bytes + up to the next 512 byte border. + """ + blocks, remainder = divmod(len(payload), BLOCKSIZE) + if remainder > 0: + payload += (BLOCKSIZE - remainder) * NUL + return payload + + @classmethod + def _create_gnu_long_header(cls, name, type, encoding, errors): + """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence + for name. + """ + name = name.encode(encoding, errors) + NUL + + info = {} + info["name"] = "././@LongLink" + info["type"] = type + info["size"] = len(name) + info["magic"] = GNU_MAGIC + + # create extended header + name blocks. + return cls._create_header(info, USTAR_FORMAT, encoding, errors) + \ + cls._create_payload(name) + + @classmethod + def _create_pax_generic_header(cls, pax_headers, type, encoding): + """Return a POSIX.1-2008 extended or global header sequence + that contains a list of keyword, value pairs. The values + must be strings. + """ + # Check if one of the fields contains surrogate characters and thereby + # forces hdrcharset=BINARY, see _proc_pax() for more information. + binary = False + for keyword, value in pax_headers.items(): + try: + value.encode("utf8", "strict") + except UnicodeEncodeError: + binary = True + break + + records = b"" + if binary: + # Put the hdrcharset field at the beginning of the header. + records += b"21 hdrcharset=BINARY\n" + + for keyword, value in pax_headers.items(): + keyword = keyword.encode("utf8") + if binary: + # Try to restore the original byte representation of `value'. + # Needless to say, that the encoding must match the string. + value = value.encode(encoding, "surrogateescape") + else: + value = value.encode("utf8") + + l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' + n = p = 0 + while True: + n = l + len(str(p)) + if n == p: + break + p = n + records += bytes(str(p), "ascii") + b" " + keyword + b"=" + value + b"\n" + + # We use a hardcoded "././@PaxHeader" name like star does + # instead of the one that POSIX recommends. + info = {} + info["name"] = "././@PaxHeader" + info["type"] = type + info["size"] = len(records) + info["magic"] = POSIX_MAGIC + + # Create pax header + record blocks. + return cls._create_header(info, USTAR_FORMAT, "ascii", "replace") + \ + cls._create_payload(records) + + @classmethod + def frombuf(cls, buf, encoding, errors): + """Construct a TarInfo object from a 512 byte bytes object. + """ + if len(buf) == 0: + raise EmptyHeaderError("empty header") + if len(buf) != BLOCKSIZE: + raise TruncatedHeaderError("truncated header") + if buf.count(NUL) == BLOCKSIZE: + raise EOFHeaderError("end of file header") + + chksum = nti(buf[148:156]) + if chksum not in calc_chksums(buf): + raise InvalidHeaderError("bad checksum") + + obj = cls() + obj.name = nts(buf[0:100], encoding, errors) + obj.mode = nti(buf[100:108]) + obj.uid = nti(buf[108:116]) + obj.gid = nti(buf[116:124]) + obj.size = nti(buf[124:136]) + obj.mtime = nti(buf[136:148]) + obj.chksum = chksum + obj.type = buf[156:157] + obj.linkname = nts(buf[157:257], encoding, errors) + obj.uname = nts(buf[265:297], encoding, errors) + obj.gname = nts(buf[297:329], encoding, errors) + obj.devmajor = nti(buf[329:337]) + obj.devminor = nti(buf[337:345]) + prefix = nts(buf[345:500], encoding, errors) + + # Old V7 tar format represents a directory as a regular + # file with a trailing slash. + if obj.type == AREGTYPE and obj.name.endswith("/"): + obj.type = DIRTYPE + + # The old GNU sparse format occupies some of the unused + # space in the buffer for up to 4 sparse structures. + # Save the them for later processing in _proc_sparse(). + if obj.type == GNUTYPE_SPARSE: + pos = 386 + structs = [] + for i in range(4): + try: + offset = nti(buf[pos:pos + 12]) + numbytes = nti(buf[pos + 12:pos + 24]) + except ValueError: + break + structs.append((offset, numbytes)) + pos += 24 + isextended = bool(buf[482]) + origsize = nti(buf[483:495]) + obj._sparse_structs = (structs, isextended, origsize) + + # Remove redundant slashes from directories. + if obj.isdir(): + obj.name = obj.name.rstrip("/") + + # Reconstruct a ustar longname. + if prefix and obj.type not in GNU_TYPES: + obj.name = prefix + "/" + obj.name + return obj + + @classmethod + def fromtarfile(cls, tarfile): + """Return the next TarInfo object from TarFile object + tarfile. + """ + buf = tarfile.fileobj.read(BLOCKSIZE) + obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors) + obj.offset = tarfile.fileobj.tell() - BLOCKSIZE + return obj._proc_member(tarfile) + + #-------------------------------------------------------------------------- + # The following are methods that are called depending on the type of a + # member. The entry point is _proc_member() which can be overridden in a + # subclass to add custom _proc_*() methods. A _proc_*() method MUST + # implement the following + # operations: + # 1. Set self.offset_data to the position where the data blocks begin, + # if there is data that follows. + # 2. Set tarfile.offset to the position where the next member's header will + # begin. + # 3. Return self or another valid TarInfo object. + def _proc_member(self, tarfile): + """Choose the right processing method depending on + the type and call it. + """ + if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): + return self._proc_gnulong(tarfile) + elif self.type == GNUTYPE_SPARSE: + return self._proc_sparse(tarfile) + elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): + return self._proc_pax(tarfile) + else: + return self._proc_builtin(tarfile) + + def _proc_builtin(self, tarfile): + """Process a builtin type or an unknown type which + will be treated as a regular file. + """ + self.offset_data = tarfile.fileobj.tell() + offset = self.offset_data + if self.isreg() or self.type not in SUPPORTED_TYPES: + # Skip the following data blocks. + offset += self._block(self.size) + tarfile.offset = offset + + # Patch the TarInfo object with saved global + # header information. + self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) + + return self + + def _proc_gnulong(self, tarfile): + """Process the blocks that hold a GNU longname + or longlink member. + """ + buf = tarfile.fileobj.read(self._block(self.size)) + + # Fetch the next header and process it. + try: + next = self.fromtarfile(tarfile) + except HeaderError: + raise SubsequentHeaderError("missing or bad subsequent header") + + # Patch the TarInfo object from the next header with + # the longname information. + next.offset = self.offset + if self.type == GNUTYPE_LONGNAME: + next.name = nts(buf, tarfile.encoding, tarfile.errors) + elif self.type == GNUTYPE_LONGLINK: + next.linkname = nts(buf, tarfile.encoding, tarfile.errors) + + return next + + def _proc_sparse(self, tarfile): + """Process a GNU sparse header plus extra headers. + """ + # We already collected some sparse structures in frombuf(). + structs, isextended, origsize = self._sparse_structs + del self._sparse_structs + + # Collect sparse structures from extended header blocks. + while isextended: + buf = tarfile.fileobj.read(BLOCKSIZE) + pos = 0 + for i in range(21): + try: + offset = nti(buf[pos:pos + 12]) + numbytes = nti(buf[pos + 12:pos + 24]) + except ValueError: + break + if offset and numbytes: + structs.append((offset, numbytes)) + pos += 24 + isextended = bool(buf[504]) + self.sparse = structs + + self.offset_data = tarfile.fileobj.tell() + tarfile.offset = self.offset_data + self._block(self.size) + self.size = origsize + return self + + def _proc_pax(self, tarfile): + """Process an extended or global header as described in + POSIX.1-2008. + """ + # Read the header information. + buf = tarfile.fileobj.read(self._block(self.size)) + + # A pax header stores supplemental information for either + # the following file (extended) or all following files + # (global). + if self.type == XGLTYPE: + pax_headers = tarfile.pax_headers + else: + pax_headers = tarfile.pax_headers.copy() + + # Check if the pax header contains a hdrcharset field. This tells us + # the encoding of the path, linkpath, uname and gname fields. Normally, + # these fields are UTF-8 encoded but since POSIX.1-2008 tar + # implementations are allowed to store them as raw binary strings if + # the translation to UTF-8 fails. + match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) + if match is not None: + pax_headers["hdrcharset"] = match.group(1).decode("utf8") + + # For the time being, we don't care about anything other than "BINARY". + # The only other value that is currently allowed by the standard is + # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. + hdrcharset = pax_headers.get("hdrcharset") + if hdrcharset == "BINARY": + encoding = tarfile.encoding + else: + encoding = "utf8" + + # Parse pax header information. A record looks like that: + # "%d %s=%s\n" % (length, keyword, value). length is the size + # of the complete record including the length field itself and + # the newline. keyword and value are both UTF-8 encoded strings. + regex = re.compile(br"(\d+) ([^=]+)=") + pos = 0 + while True: + match = regex.match(buf, pos) + if not match: + break + + length, keyword = match.groups() + length = int(length) + value = buf[match.end(2) + 1:match.start(1) + length - 1] + + # Normally, we could just use "utf8" as the encoding and "strict" + # as the error handler, but we better not take the risk. For + # example, GNU tar <= 1.23 is known to store filenames it cannot + # translate to UTF-8 as raw strings (unfortunately without a + # hdrcharset=BINARY header). + # We first try the strict standard encoding, and if that fails we + # fall back on the user's encoding and error handler. + keyword = self._decode_pax_field(keyword, "utf8", "utf8", + tarfile.errors) + if keyword in PAX_NAME_FIELDS: + value = self._decode_pax_field(value, encoding, tarfile.encoding, + tarfile.errors) + else: + value = self._decode_pax_field(value, "utf8", "utf8", + tarfile.errors) + + pax_headers[keyword] = value + pos += length + + # Fetch the next header. + try: + next = self.fromtarfile(tarfile) + except HeaderError: + raise SubsequentHeaderError("missing or bad subsequent header") + + # Process GNU sparse information. + if "GNU.sparse.map" in pax_headers: + # GNU extended sparse format version 0.1. + self._proc_gnusparse_01(next, pax_headers) + + elif "GNU.sparse.size" in pax_headers: + # GNU extended sparse format version 0.0. + self._proc_gnusparse_00(next, pax_headers, buf) + + elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": + # GNU extended sparse format version 1.0. + self._proc_gnusparse_10(next, pax_headers, tarfile) + + if self.type in (XHDTYPE, SOLARIS_XHDTYPE): + # Patch the TarInfo object with the extended header info. + next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) + next.offset = self.offset + + if "size" in pax_headers: + # If the extended header replaces the size field, + # we need to recalculate the offset where the next + # header starts. + offset = next.offset_data + if next.isreg() or next.type not in SUPPORTED_TYPES: + offset += next._block(next.size) + tarfile.offset = offset + + return next + + def _proc_gnusparse_00(self, next, pax_headers, buf): + """Process a GNU tar extended sparse header, version 0.0. + """ + offsets = [] + for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): + offsets.append(int(match.group(1))) + numbytes = [] + for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): + numbytes.append(int(match.group(1))) + next.sparse = list(zip(offsets, numbytes)) + + def _proc_gnusparse_01(self, next, pax_headers): + """Process a GNU tar extended sparse header, version 0.1. + """ + sparse = [int(x) for x in pax_headers["GNU.sparse.map"].split(",")] + next.sparse = list(zip(sparse[::2], sparse[1::2])) + + def _proc_gnusparse_10(self, next, pax_headers, tarfile): + """Process a GNU tar extended sparse header, version 1.0. + """ + fields = None + sparse = [] + buf = tarfile.fileobj.read(BLOCKSIZE) + fields, buf = buf.split(b"\n", 1) + fields = int(fields) + while len(sparse) < fields * 2: + if b"\n" not in buf: + buf += tarfile.fileobj.read(BLOCKSIZE) + number, buf = buf.split(b"\n", 1) + sparse.append(int(number)) + next.offset_data = tarfile.fileobj.tell() + next.sparse = list(zip(sparse[::2], sparse[1::2])) + + def _apply_pax_info(self, pax_headers, encoding, errors): + """Replace fields with supplemental information from a previous + pax extended or global header. + """ + for keyword, value in pax_headers.items(): + if keyword == "GNU.sparse.name": + setattr(self, "path", value) + elif keyword == "GNU.sparse.size": + setattr(self, "size", int(value)) + elif keyword == "GNU.sparse.realsize": + setattr(self, "size", int(value)) + elif keyword in PAX_FIELDS: + if keyword in PAX_NUMBER_FIELDS: + try: + value = PAX_NUMBER_FIELDS[keyword](value) + except ValueError: + value = 0 + if keyword == "path": + value = value.rstrip("/") + setattr(self, keyword, value) + + self.pax_headers = pax_headers.copy() + + def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors): + """Decode a single field from a pax record. + """ + try: + return value.decode(encoding, "strict") + except UnicodeDecodeError: + return value.decode(fallback_encoding, fallback_errors) + + def _block(self, count): + """Round up a byte count by BLOCKSIZE and return it, + e.g. _block(834) => 1024. + """ + blocks, remainder = divmod(count, BLOCKSIZE) + if remainder: + blocks += 1 + return blocks * BLOCKSIZE + + def isreg(self): + return self.type in REGULAR_TYPES + def isfile(self): + return self.isreg() + def isdir(self): + return self.type == DIRTYPE + def issym(self): + return self.type == SYMTYPE + def islnk(self): + return self.type == LNKTYPE + def ischr(self): + return self.type == CHRTYPE + def isblk(self): + return self.type == BLKTYPE + def isfifo(self): + return self.type == FIFOTYPE + def issparse(self): + return self.sparse is not None + def isdev(self): + return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) +# class TarInfo + +class TarFile(object): + """The TarFile Class provides an interface to tar archives. + """ + + debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) + + dereference = False # If true, add content of linked file to the + # tar file, else the link. + + ignore_zeros = False # If true, skips empty or invalid blocks and + # continues processing. + + errorlevel = 1 # If 0, fatal errors only appear in debug + # messages (if debug >= 0). If > 0, errors + # are passed to the caller as exceptions. + + format = DEFAULT_FORMAT # The format to use when creating an archive. + + encoding = ENCODING # Encoding for 8-bit character strings. + + errors = None # Error handler for unicode conversion. + + tarinfo = TarInfo # The default TarInfo class to use. + + fileobject = ExFileObject # The default ExFileObject class to use. + + def __init__(self, name=None, mode="r", fileobj=None, format=None, + tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, + errors="surrogateescape", pax_headers=None, debug=None, errorlevel=None): + """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to + read from an existing archive, 'a' to append data to an existing + file or 'w' to create a new file overwriting an existing one. `mode' + defaults to 'r'. + If `fileobj' is given, it is used for reading or writing data. If it + can be determined, `mode' is overridden by `fileobj's mode. + `fileobj' is not closed, when TarFile is closed. + """ + if len(mode) > 1 or mode not in "raw": + raise ValueError("mode must be 'r', 'a' or 'w'") + self.mode = mode + self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] + + if not fileobj: + if self.mode == "a" and not os.path.exists(name): + # Create nonexistent files in append mode. + self.mode = "w" + self._mode = "wb" + fileobj = bltn_open(name, self._mode) + self._extfileobj = False + else: + if name is None and hasattr(fileobj, "name"): + name = fileobj.name + if hasattr(fileobj, "mode"): + self._mode = fileobj.mode + self._extfileobj = True + self.name = os.path.abspath(name) if name else None + self.fileobj = fileobj + + # Init attributes. + if format is not None: + self.format = format + if tarinfo is not None: + self.tarinfo = tarinfo + if dereference is not None: + self.dereference = dereference + if ignore_zeros is not None: + self.ignore_zeros = ignore_zeros + if encoding is not None: + self.encoding = encoding + self.errors = errors + + if pax_headers is not None and self.format == PAX_FORMAT: + self.pax_headers = pax_headers + else: + self.pax_headers = {} + + if debug is not None: + self.debug = debug + if errorlevel is not None: + self.errorlevel = errorlevel + + # Init datastructures. + self.closed = False + self.members = [] # list of members as TarInfo objects + self._loaded = False # flag if all members have been read + self.offset = self.fileobj.tell() + # current position in the archive file + self.inodes = {} # dictionary caching the inodes of + # archive members already added + + try: + if self.mode == "r": + self.firstmember = None + self.firstmember = self.next() + + if self.mode == "a": + # Move to the end of the archive, + # before the first empty block. + while True: + self.fileobj.seek(self.offset) + try: + tarinfo = self.tarinfo.fromtarfile(self) + self.members.append(tarinfo) + except EOFHeaderError: + self.fileobj.seek(self.offset) + break + except HeaderError as e: + raise ReadError(str(e)) + + if self.mode in "aw": + self._loaded = True + + if self.pax_headers: + buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) + self.fileobj.write(buf) + self.offset += len(buf) + except: + if not self._extfileobj: + self.fileobj.close() + self.closed = True + raise + + #-------------------------------------------------------------------------- + # Below are the classmethods which act as alternate constructors to the + # TarFile class. The open() method is the only one that is needed for + # public use; it is the "super"-constructor and is able to select an + # adequate "sub"-constructor for a particular compression using the mapping + # from OPEN_METH. + # + # This concept allows one to subclass TarFile without losing the comfort of + # the super-constructor. A sub-constructor is registered and made available + # by adding it to the mapping in OPEN_METH. + + @classmethod + def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): + """Open a tar archive for reading, writing or appending. Return + an appropriate TarFile class. + + mode: + 'r' or 'r:*' open for reading with transparent compression + 'r:' open for reading exclusively uncompressed + 'r:gz' open for reading with gzip compression + 'r:bz2' open for reading with bzip2 compression + 'a' or 'a:' open for appending, creating the file if necessary + 'w' or 'w:' open for writing without compression + 'w:gz' open for writing with gzip compression + 'w:bz2' open for writing with bzip2 compression + + 'r|*' open a stream of tar blocks with transparent compression + 'r|' open an uncompressed stream of tar blocks for reading + 'r|gz' open a gzip compressed stream of tar blocks + 'r|bz2' open a bzip2 compressed stream of tar blocks + 'w|' open an uncompressed stream for writing + 'w|gz' open a gzip compressed stream for writing + 'w|bz2' open a bzip2 compressed stream for writing + """ + + if not name and not fileobj: + raise ValueError("nothing to open") + + if mode in ("r", "r:*"): + # Find out which *open() is appropriate for opening the file. + for comptype in cls.OPEN_METH: + func = getattr(cls, cls.OPEN_METH[comptype]) + if fileobj is not None: + saved_pos = fileobj.tell() + try: + return func(name, "r", fileobj, **kwargs) + except (ReadError, CompressionError) as e: + if fileobj is not None: + fileobj.seek(saved_pos) + continue + raise ReadError("file could not be opened successfully") + + elif ":" in mode: + filemode, comptype = mode.split(":", 1) + filemode = filemode or "r" + comptype = comptype or "tar" + + # Select the *open() function according to + # given compression. + if comptype in cls.OPEN_METH: + func = getattr(cls, cls.OPEN_METH[comptype]) + else: + raise CompressionError("unknown compression type %r" % comptype) + return func(name, filemode, fileobj, **kwargs) + + elif "|" in mode: + filemode, comptype = mode.split("|", 1) + filemode = filemode or "r" + comptype = comptype or "tar" + + if filemode not in "rw": + raise ValueError("mode must be 'r' or 'w'") + + stream = _Stream(name, filemode, comptype, fileobj, bufsize) + try: + t = cls(name, filemode, stream, **kwargs) + except: + stream.close() + raise + t._extfileobj = False + return t + + elif mode in "aw": + return cls.taropen(name, mode, fileobj, **kwargs) + + raise ValueError("undiscernible mode") + + @classmethod + def taropen(cls, name, mode="r", fileobj=None, **kwargs): + """Open uncompressed tar archive name for reading or writing. + """ + if len(mode) > 1 or mode not in "raw": + raise ValueError("mode must be 'r', 'a' or 'w'") + return cls(name, mode, fileobj, **kwargs) + + @classmethod + def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): + """Open gzip compressed tar archive name for reading or writing. + Appending is not allowed. + """ + if len(mode) > 1 or mode not in "rw": + raise ValueError("mode must be 'r' or 'w'") + + try: + import gzip + gzip.GzipFile + except (ImportError, AttributeError): + raise CompressionError("gzip module is not available") + + extfileobj = fileobj is not None + try: + fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) + t = cls.taropen(name, mode, fileobj, **kwargs) + except IOError: + if not extfileobj and fileobj is not None: + fileobj.close() + if fileobj is None: + raise + raise ReadError("not a gzip file") + except: + if not extfileobj and fileobj is not None: + fileobj.close() + raise + t._extfileobj = extfileobj + return t + + @classmethod + def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): + """Open bzip2 compressed tar archive name for reading or writing. + Appending is not allowed. + """ + if len(mode) > 1 or mode not in "rw": + raise ValueError("mode must be 'r' or 'w'.") + + try: + import bz2 + except ImportError: + raise CompressionError("bz2 module is not available") + + if fileobj is not None: + fileobj = _BZ2Proxy(fileobj, mode) + else: + fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) + + try: + t = cls.taropen(name, mode, fileobj, **kwargs) + except (IOError, EOFError): + fileobj.close() + raise ReadError("not a bzip2 file") + t._extfileobj = False + return t + + # All *open() methods are registered here. + OPEN_METH = { + "tar": "taropen", # uncompressed tar + "gz": "gzopen", # gzip compressed tar + "bz2": "bz2open" # bzip2 compressed tar + } + + #-------------------------------------------------------------------------- + # The public methods which TarFile provides: + + def close(self): + """Close the TarFile. In write-mode, two finishing zero blocks are + appended to the archive. + """ + if self.closed: + return + + if self.mode in "aw": + self.fileobj.write(NUL * (BLOCKSIZE * 2)) + self.offset += (BLOCKSIZE * 2) + # fill up the end with zero-blocks + # (like option -b20 for tar does) + blocks, remainder = divmod(self.offset, RECORDSIZE) + if remainder > 0: + self.fileobj.write(NUL * (RECORDSIZE - remainder)) + + if not self._extfileobj: + self.fileobj.close() + self.closed = True + + def getmember(self, name): + """Return a TarInfo object for member `name'. If `name' can not be + found in the archive, KeyError is raised. If a member occurs more + than once in the archive, its last occurrence is assumed to be the + most up-to-date version. + """ + tarinfo = self._getmember(name) + if tarinfo is None: + raise KeyError("filename %r not found" % name) + return tarinfo + + def getmembers(self): + """Return the members of the archive as a list of TarInfo objects. The + list has the same order as the members in the archive. + """ + self._check() + if not self._loaded: # if we want to obtain a list of + self._load() # all members, we first have to + # scan the whole archive. + return self.members + + def getnames(self): + """Return the members of the archive as a list of their names. It has + the same order as the list returned by getmembers(). + """ + return [tarinfo.name for tarinfo in self.getmembers()] + + def gettarinfo(self, name=None, arcname=None, fileobj=None): + """Create a TarInfo object for either the file `name' or the file + object `fileobj' (using os.fstat on its file descriptor). You can + modify some of the TarInfo's attributes before you add it using + addfile(). If given, `arcname' specifies an alternative name for the + file in the archive. + """ + self._check("aw") + + # When fileobj is given, replace name by + # fileobj's real name. + if fileobj is not None: + name = fileobj.name + + # Building the name of the member in the archive. + # Backward slashes are converted to forward slashes, + # Absolute paths are turned to relative paths. + if arcname is None: + arcname = name + drv, arcname = os.path.splitdrive(arcname) + arcname = arcname.replace(os.sep, "/") + arcname = arcname.lstrip("/") + + # Now, fill the TarInfo object with + # information specific for the file. + tarinfo = self.tarinfo() + tarinfo.tarfile = self + + # Use os.stat or os.lstat, depending on platform + # and if symlinks shall be resolved. + if fileobj is None: + if hasattr(os, "lstat") and not self.dereference: + statres = os.lstat(name) + else: + statres = os.stat(name) + else: + statres = os.fstat(fileobj.fileno()) + linkname = "" + + stmd = statres.st_mode + if stat.S_ISREG(stmd): + inode = (statres.st_ino, statres.st_dev) + if not self.dereference and statres.st_nlink > 1 and \ + inode in self.inodes and arcname != self.inodes[inode]: + # Is it a hardlink to an already + # archived file? + type = LNKTYPE + linkname = self.inodes[inode] + else: + # The inode is added only if its valid. + # For win32 it is always 0. + type = REGTYPE + if inode[0]: + self.inodes[inode] = arcname + elif stat.S_ISDIR(stmd): + type = DIRTYPE + elif stat.S_ISFIFO(stmd): + type = FIFOTYPE + elif stat.S_ISLNK(stmd): + type = SYMTYPE + linkname = os.readlink(name) + elif stat.S_ISCHR(stmd): + type = CHRTYPE + elif stat.S_ISBLK(stmd): + type = BLKTYPE + else: + return None + + # Fill the TarInfo object with all + # information we can get. + tarinfo.name = arcname + tarinfo.mode = stmd + tarinfo.uid = statres.st_uid + tarinfo.gid = statres.st_gid + if type == REGTYPE: + tarinfo.size = statres.st_size + else: + tarinfo.size = 0 + tarinfo.mtime = statres.st_mtime + tarinfo.type = type + tarinfo.linkname = linkname + if pwd: + try: + tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] + except KeyError: + pass + if grp: + try: + tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] + except KeyError: + pass + + if type in (CHRTYPE, BLKTYPE): + if hasattr(os, "major") and hasattr(os, "minor"): + tarinfo.devmajor = os.major(statres.st_rdev) + tarinfo.devminor = os.minor(statres.st_rdev) + return tarinfo + + def list(self, verbose=True): + """Print a table of contents to sys.stdout. If `verbose' is False, only + the names of the members are printed. If it is True, an `ls -l'-like + output is produced. + """ + self._check() + + for tarinfo in self: + if verbose: + print(filemode(tarinfo.mode), end=' ') + print("%s/%s" % (tarinfo.uname or tarinfo.uid, + tarinfo.gname or tarinfo.gid), end=' ') + if tarinfo.ischr() or tarinfo.isblk(): + print("%10s" % ("%d,%d" \ + % (tarinfo.devmajor, tarinfo.devminor)), end=' ') + else: + print("%10d" % tarinfo.size, end=' ') + print("%d-%02d-%02d %02d:%02d:%02d" \ + % time.localtime(tarinfo.mtime)[:6], end=' ') + + print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') + + if verbose: + if tarinfo.issym(): + print("->", tarinfo.linkname, end=' ') + if tarinfo.islnk(): + print("link to", tarinfo.linkname, end=' ') + print() + + def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): + """Add the file `name' to the archive. `name' may be any type of file + (directory, fifo, symbolic link, etc.). If given, `arcname' + specifies an alternative name for the file in the archive. + Directories are added recursively by default. This can be avoided by + setting `recursive' to False. `exclude' is a function that should + return True for each filename to be excluded. `filter' is a function + that expects a TarInfo object argument and returns the changed + TarInfo object, if it returns None the TarInfo object will be + excluded from the archive. + """ + self._check("aw") + + if arcname is None: + arcname = name + + # Exclude pathnames. + if exclude is not None: + import warnings + warnings.warn("use the filter argument instead", + DeprecationWarning, 2) + if exclude(name): + self._dbg(2, "tarfile: Excluded %r" % name) + return + + # Skip if somebody tries to archive the archive... + if self.name is not None and os.path.abspath(name) == self.name: + self._dbg(2, "tarfile: Skipped %r" % name) + return + + self._dbg(1, name) + + # Create a TarInfo object from the file. + tarinfo = self.gettarinfo(name, arcname) + + if tarinfo is None: + self._dbg(1, "tarfile: Unsupported type %r" % name) + return + + # Change or exclude the TarInfo object. + if filter is not None: + tarinfo = filter(tarinfo) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % name) + return + + # Append the tar header and data to the archive. + if tarinfo.isreg(): + f = bltn_open(name, "rb") + self.addfile(tarinfo, f) + f.close() + + elif tarinfo.isdir(): + self.addfile(tarinfo) + if recursive: + for f in os.listdir(name): + self.add(os.path.join(name, f), os.path.join(arcname, f), + recursive, exclude, filter=filter) + + else: + self.addfile(tarinfo) + + def addfile(self, tarinfo, fileobj=None): + """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is + given, tarinfo.size bytes are read from it and added to the archive. + You can create TarInfo objects using gettarinfo(). + On Windows platforms, `fileobj' should always be opened with mode + 'rb' to avoid irritation about the file size. + """ + self._check("aw") + + tarinfo = copy.copy(tarinfo) + + buf = tarinfo.tobuf(self.format, self.encoding, self.errors) + self.fileobj.write(buf) + self.offset += len(buf) + + # If there's data to follow, append it. + if fileobj is not None: + copyfileobj(fileobj, self.fileobj, tarinfo.size) + blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) + if remainder > 0: + self.fileobj.write(NUL * (BLOCKSIZE - remainder)) + blocks += 1 + self.offset += blocks * BLOCKSIZE + + self.members.append(tarinfo) + + def extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 0o700 + # Do not set_attrs directories, as we will do that further down + self.extract(tarinfo, path, set_attrs=not tarinfo.isdir()) + + # Reverse sort directories. + directories.sort(key=lambda a: a.name) + directories.reverse() + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError as e: + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def extract(self, member, path="", set_attrs=True): + """Extract a member from the archive to the current working directory, + using its full name. Its file information is extracted as accurately + as possible. `member' may be a filename or a TarInfo object. You can + specify a different directory using `path'. File attributes (owner, + mtime, mode) are set unless `set_attrs' is False. + """ + self._check("r") + + if isinstance(member, str): + tarinfo = self.getmember(member) + else: + tarinfo = member + + # Prepare the link target for makelink(). + if tarinfo.islnk(): + tarinfo._link_target = os.path.join(path, tarinfo.linkname) + + try: + self._extract_member(tarinfo, os.path.join(path, tarinfo.name), + set_attrs=set_attrs) + except EnvironmentError as e: + if self.errorlevel > 0: + raise + else: + if e.filename is None: + self._dbg(1, "tarfile: %s" % e.strerror) + else: + self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + except ExtractError as e: + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def extractfile(self, member): + """Extract a member from the archive as a file object. `member' may be + a filename or a TarInfo object. If `member' is a regular file, a + file-like object is returned. If `member' is a link, a file-like + object is constructed from the link's target. If `member' is none of + the above, None is returned. + The file-like object is read-only and provides the following + methods: read(), readline(), readlines(), seek() and tell() + """ + self._check("r") + + if isinstance(member, str): + tarinfo = self.getmember(member) + else: + tarinfo = member + + if tarinfo.isreg(): + return self.fileobject(self, tarinfo) + + elif tarinfo.type not in SUPPORTED_TYPES: + # If a member's type is unknown, it is treated as a + # regular file. + return self.fileobject(self, tarinfo) + + elif tarinfo.islnk() or tarinfo.issym(): + if isinstance(self.fileobj, _Stream): + # A small but ugly workaround for the case that someone tries + # to extract a (sym)link as a file-object from a non-seekable + # stream of tar blocks. + raise StreamError("cannot extract (sym)link as file object") + else: + # A (sym)link's file object is its target's file object. + return self.extractfile(self._find_link_target(tarinfo)) + else: + # If there's no data associated with the member (directory, chrdev, + # blkdev, etc.), return None instead of a file object. + return None + + def _extract_member(self, tarinfo, targetpath, set_attrs=True): + """Extract the TarInfo object tarinfo to a physical + file called targetpath. + """ + # Fetch the TarInfo object for the given name + # and build the destination pathname, replacing + # forward slashes to platform specific separators. + targetpath = targetpath.rstrip("/") + targetpath = targetpath.replace("/", os.sep) + + # Create all upper directories. + upperdirs = os.path.dirname(targetpath) + if upperdirs and not os.path.exists(upperdirs): + # Create directories that are not part of the archive with + # default permissions. + os.makedirs(upperdirs) + + if tarinfo.islnk() or tarinfo.issym(): + self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) + else: + self._dbg(1, tarinfo.name) + + if tarinfo.isreg(): + self.makefile(tarinfo, targetpath) + elif tarinfo.isdir(): + self.makedir(tarinfo, targetpath) + elif tarinfo.isfifo(): + self.makefifo(tarinfo, targetpath) + elif tarinfo.ischr() or tarinfo.isblk(): + self.makedev(tarinfo, targetpath) + elif tarinfo.islnk() or tarinfo.issym(): + self.makelink(tarinfo, targetpath) + elif tarinfo.type not in SUPPORTED_TYPES: + self.makeunknown(tarinfo, targetpath) + else: + self.makefile(tarinfo, targetpath) + + if set_attrs: + self.chown(tarinfo, targetpath) + if not tarinfo.issym(): + self.chmod(tarinfo, targetpath) + self.utime(tarinfo, targetpath) + + #-------------------------------------------------------------------------- + # Below are the different file methods. They are called via + # _extract_member() when extract() is called. They can be replaced in a + # subclass to implement other functionality. + + def makedir(self, tarinfo, targetpath): + """Make a directory called targetpath. + """ + try: + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0o700) + except EnvironmentError as e: + if e.errno != errno.EEXIST: + raise + + def makefile(self, tarinfo, targetpath): + """Make a file called targetpath. + """ + source = self.fileobj + source.seek(tarinfo.offset_data) + target = bltn_open(targetpath, "wb") + if tarinfo.sparse is not None: + for offset, size in tarinfo.sparse: + target.seek(offset) + copyfileobj(source, target, size) + else: + copyfileobj(source, target, tarinfo.size) + target.seek(tarinfo.size) + target.truncate() + target.close() + + def makeunknown(self, tarinfo, targetpath): + """Make a file from a TarInfo object with an unknown type + at targetpath. + """ + self.makefile(tarinfo, targetpath) + self._dbg(1, "tarfile: Unknown file type %r, " \ + "extracted as regular file." % tarinfo.type) + + def makefifo(self, tarinfo, targetpath): + """Make a fifo called targetpath. + """ + if hasattr(os, "mkfifo"): + os.mkfifo(targetpath) + else: + raise ExtractError("fifo not supported by system") + + def makedev(self, tarinfo, targetpath): + """Make a character or block device called targetpath. + """ + if not hasattr(os, "mknod") or not hasattr(os, "makedev"): + raise ExtractError("special devices not supported by system") + + mode = tarinfo.mode + if tarinfo.isblk(): + mode |= stat.S_IFBLK + else: + mode |= stat.S_IFCHR + + os.mknod(targetpath, mode, + os.makedev(tarinfo.devmajor, tarinfo.devminor)) + + def makelink(self, tarinfo, targetpath): + """Make a (symbolic) link called targetpath. If it cannot be created + (platform limitation), we try to make a copy of the referenced file + instead of a link. + """ + try: + # For systems that support symbolic and hard links. + if tarinfo.issym(): + os.symlink(tarinfo.linkname, targetpath) + else: + # See extract(). + if os.path.exists(tarinfo._link_target): + os.link(tarinfo._link_target, targetpath) + else: + self._extract_member(self._find_link_target(tarinfo), + targetpath) + except symlink_exception: + if tarinfo.issym(): + linkpath = os.path.join(os.path.dirname(tarinfo.name), + tarinfo.linkname) + else: + linkpath = tarinfo.linkname + else: + try: + self._extract_member(self._find_link_target(tarinfo), + targetpath) + except KeyError: + raise ExtractError("unable to resolve link inside archive") + + def chown(self, tarinfo, targetpath): + """Set owner of targetpath according to tarinfo. + """ + if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: + # We have to be root to do so. + try: + g = grp.getgrnam(tarinfo.gname)[2] + except KeyError: + g = tarinfo.gid + try: + u = pwd.getpwnam(tarinfo.uname)[2] + except KeyError: + u = tarinfo.uid + try: + if tarinfo.issym() and hasattr(os, "lchown"): + os.lchown(targetpath, u, g) + else: + if sys.platform != "os2emx": + os.chown(targetpath, u, g) + except EnvironmentError as e: + raise ExtractError("could not change owner") + + def chmod(self, tarinfo, targetpath): + """Set file permissions of targetpath according to tarinfo. + """ + if hasattr(os, 'chmod'): + try: + os.chmod(targetpath, tarinfo.mode) + except EnvironmentError as e: + raise ExtractError("could not change mode") + + def utime(self, tarinfo, targetpath): + """Set modification time of targetpath according to tarinfo. + """ + if not hasattr(os, 'utime'): + return + try: + os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) + except EnvironmentError as e: + raise ExtractError("could not change modification time") + + #-------------------------------------------------------------------------- + def next(self): + """Return the next member of the archive as a TarInfo object, when + TarFile is opened for reading. Return None if there is no more + available. + """ + self._check("ra") + if self.firstmember is not None: + m = self.firstmember + self.firstmember = None + return m + + # Read the next block. + self.fileobj.seek(self.offset) + tarinfo = None + while True: + try: + tarinfo = self.tarinfo.fromtarfile(self) + except EOFHeaderError as e: + if self.ignore_zeros: + self._dbg(2, "0x%X: %s" % (self.offset, e)) + self.offset += BLOCKSIZE + continue + except InvalidHeaderError as e: + if self.ignore_zeros: + self._dbg(2, "0x%X: %s" % (self.offset, e)) + self.offset += BLOCKSIZE + continue + elif self.offset == 0: + raise ReadError(str(e)) + except EmptyHeaderError: + if self.offset == 0: + raise ReadError("empty file") + except TruncatedHeaderError as e: + if self.offset == 0: + raise ReadError(str(e)) + except SubsequentHeaderError as e: + raise ReadError(str(e)) + break + + if tarinfo is not None: + self.members.append(tarinfo) + else: + self._loaded = True + + return tarinfo + + #-------------------------------------------------------------------------- + # Little helper methods: + + def _getmember(self, name, tarinfo=None, normalize=False): + """Find an archive member by name from bottom to top. + If tarinfo is given, it is used as the starting point. + """ + # Ensure that all members have been loaded. + members = self.getmembers() + + # Limit the member search list up to tarinfo. + if tarinfo is not None: + members = members[:members.index(tarinfo)] + + if normalize: + name = os.path.normpath(name) + + for member in reversed(members): + if normalize: + member_name = os.path.normpath(member.name) + else: + member_name = member.name + + if name == member_name: + return member + + def _load(self): + """Read through the entire archive file and look for readable + members. + """ + while True: + tarinfo = self.next() + if tarinfo is None: + break + self._loaded = True + + def _check(self, mode=None): + """Check if TarFile is still open, and if the operation's mode + corresponds to TarFile's mode. + """ + if self.closed: + raise IOError("%s is closed" % self.__class__.__name__) + if mode is not None and self.mode not in mode: + raise IOError("bad operation for mode %r" % self.mode) + + def _find_link_target(self, tarinfo): + """Find the target member of a symlink or hardlink member in the + archive. + """ + if tarinfo.issym(): + # Always search the entire archive. + linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname + limit = None + else: + # Search the archive before the link, because a hard link is + # just a reference to an already archived file. + linkname = tarinfo.linkname + limit = tarinfo + + member = self._getmember(linkname, tarinfo=limit, normalize=True) + if member is None: + raise KeyError("linkname %r not found" % linkname) + return member + + def __iter__(self): + """Provide an iterator object. + """ + if self._loaded: + return iter(self.members) + else: + return TarIter(self) + + def _dbg(self, level, msg): + """Write debugging output to sys.stderr. + """ + if level <= self.debug: + print(msg, file=sys.stderr) + + def __enter__(self): + self._check() + return self + + def __exit__(self, type, value, traceback): + if type is None: + self.close() + else: + # An exception occurred. We must not call close() because + # it would try to write end-of-archive blocks and padding. + if not self._extfileobj: + self.fileobj.close() + self.closed = True +# class TarFile + +class TarIter(object): + """Iterator Class. + + for tarinfo in TarFile(...): + suite... + """ + + def __init__(self, tarfile): + """Construct a TarIter object. + """ + self.tarfile = tarfile + self.index = 0 + def __iter__(self): + """Return iterator object. + """ + return self + + def __next__(self): + """Return the next item using TarFile's next() method. + When all members have been read, set TarFile as _loaded. + """ + # Fix for SF #1100429: Under rare circumstances it can + # happen that getmembers() is called during iteration, + # which will cause TarIter to stop prematurely. + if not self.tarfile._loaded: + tarinfo = self.tarfile.next() + if not tarinfo: + self.tarfile._loaded = True + raise StopIteration + else: + try: + tarinfo = self.tarfile.members[self.index] + except IndexError: + raise StopIteration + self.index += 1 + return tarinfo + + next = __next__ # for Python 2.x + +#-------------------- +# exported functions +#-------------------- +def is_tarfile(name): + """Return True if name points to a tar archive that we + are able to handle, else return False. + """ + try: + t = open(name) + t.close() + return True + except TarError: + return False + +bltn_open = open +open = TarFile.open diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py new file mode 100755 index 0000000..09929b0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py @@ -0,0 +1,1120 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import absolute_import + +import os +import re +import sys + +try: + import ssl +except ImportError: # pragma: no cover + ssl = None + +if sys.version_info[0] < 3: # pragma: no cover + from StringIO import StringIO + string_types = basestring, + text_type = unicode + from types import FileType as file_type + import __builtin__ as builtins + import ConfigParser as configparser + from ._backport import shutil + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit + from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, + pathname2url, ContentTooShortError, splittype) + + def quote(s): + if isinstance(s, unicode): + s = s.encode('utf-8') + return _quote(s) + + import urllib2 + from urllib2 import (Request, urlopen, URLError, HTTPError, + HTTPBasicAuthHandler, HTTPPasswordMgr, + HTTPHandler, HTTPRedirectHandler, + build_opener) + if ssl: + from urllib2 import HTTPSHandler + import httplib + import xmlrpclib + import Queue as queue + from HTMLParser import HTMLParser + import htmlentitydefs + raw_input = raw_input + from itertools import ifilter as filter + from itertools import ifilterfalse as filterfalse + + _userprog = None + def splituser(host): + """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" + global _userprog + if _userprog is None: + import re + _userprog = re.compile('^(.*)@(.*)$') + + match = _userprog.match(host) + if match: return match.group(1, 2) + return None, host + +else: # pragma: no cover + from io import StringIO + string_types = str, + text_type = str + from io import TextIOWrapper as file_type + import builtins + import configparser + import shutil + from urllib.parse import (urlparse, urlunparse, urljoin, splituser, quote, + unquote, urlsplit, urlunsplit, splittype) + from urllib.request import (urlopen, urlretrieve, Request, url2pathname, + pathname2url, + HTTPBasicAuthHandler, HTTPPasswordMgr, + HTTPHandler, HTTPRedirectHandler, + build_opener) + if ssl: + from urllib.request import HTTPSHandler + from urllib.error import HTTPError, URLError, ContentTooShortError + import http.client as httplib + import urllib.request as urllib2 + import xmlrpc.client as xmlrpclib + import queue + from html.parser import HTMLParser + import html.entities as htmlentitydefs + raw_input = input + from itertools import filterfalse + filter = filter + +try: + from ssl import match_hostname, CertificateError +except ImportError: # pragma: no cover + 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 + + parts = dn.split('.') + leftmost, remainder = parts[0], 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 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") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_match(value, hostname): + 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") + + +try: + from types import SimpleNamespace as Container +except ImportError: # pragma: no cover + class Container(object): + """ + A generic container for when multiple values need to be returned + """ + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +try: + from shutil import which +except ImportError: # pragma: no cover + # Implementation from Python 3.3 + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + + """ + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + + # If we're given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to the + # current directory, e.g. ./script + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + # The current directory takes precedence on Windows. + if not os.curdir in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given "python.exe". + # If it does match, only test that one, otherwise we have to try + # others. + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + # On other platforms you don't have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if not normdir in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None + + +# ZipFile is a context manager in 2.7, but not in 2.6 + +from zipfile import ZipFile as BaseZipFile + +if hasattr(BaseZipFile, '__enter__'): # pragma: no cover + ZipFile = BaseZipFile +else: # pragma: no cover + from zipfile import ZipExtFile as BaseZipExtFile + + class ZipExtFile(BaseZipExtFile): + def __init__(self, base): + self.__dict__.update(base.__dict__) + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + class ZipFile(BaseZipFile): + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + def open(self, *args, **kwargs): + base = BaseZipFile.open(self, *args, **kwargs) + return ZipExtFile(base) + +try: + from platform import python_implementation +except ImportError: # pragma: no cover + def python_implementation(): + """Return a string identifying the Python implementation.""" + if 'PyPy' in sys.version: + return 'PyPy' + if os.name == 'java': + return 'Jython' + if sys.version.startswith('IronPython'): + return 'IronPython' + return 'CPython' + +try: + import sysconfig +except ImportError: # pragma: no cover + from ._backport import sysconfig + +try: + callable = callable +except NameError: # pragma: no cover + from collections import Callable + + def callable(obj): + return isinstance(obj, Callable) + + +try: + fsencode = os.fsencode + fsdecode = os.fsdecode +except AttributeError: # pragma: no cover + # Issue #99: on some systems (e.g. containerised), + # sys.getfilesystemencoding() returns None, and we need a real value, + # so fall back to utf-8. From the CPython 2.7 docs relating to Unix and + # sys.getfilesystemencoding(): the return value is "the user’s preference + # according to the result of nl_langinfo(CODESET), or None if the + # nl_langinfo(CODESET) failed." + _fsencoding = sys.getfilesystemencoding() or 'utf-8' + if _fsencoding == 'mbcs': + _fserrors = 'strict' + else: + _fserrors = 'surrogateescape' + + def fsencode(filename): + if isinstance(filename, bytes): + return filename + elif isinstance(filename, text_type): + return filename.encode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + + def fsdecode(filename): + if isinstance(filename, text_type): + return filename + elif isinstance(filename, bytes): + return filename.decode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + +try: + from tokenize import detect_encoding +except ImportError: # pragma: no cover + from codecs import BOM_UTF8, lookup + import re + + cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)") + + def _get_normal_name(orig_enc): + """Imitates get_normal_name in tokenizer.c.""" + # Only care about the first 12 characters. + enc = orig_enc[:12].lower().replace("_", "-") + if enc == "utf-8" or enc.startswith("utf-8-"): + return "utf-8" + if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ + enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): + return "iso-8859-1" + return orig_enc + + def detect_encoding(readline): + """ + The detect_encoding() function is used to detect the encoding that should + be used to decode a Python source file. It requires one argument, readline, + in the same way as the tokenize() generator. + + It will call readline a maximum of twice, and return the encoding used + (as a string) and a list of any lines (left as bytes) it has read in. + + It detects the encoding from the presence of a utf-8 bom or an encoding + cookie as specified in pep-0263. If both a bom and a cookie are present, + but disagree, a SyntaxError will be raised. If the encoding cookie is an + invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, + 'utf-8-sig' is returned. + + If no encoding is specified, then the default of 'utf-8' will be returned. + """ + try: + filename = readline.__self__.name + except AttributeError: + filename = None + bom_found = False + encoding = None + default = 'utf-8' + def read_or_stop(): + try: + return readline() + except StopIteration: + return b'' + + def find_cookie(line): + try: + # Decode as UTF-8. Either the line is an encoding declaration, + # in which case it should be pure ASCII, or it must be UTF-8 + # per default encoding. + line_string = line.decode('utf-8') + except UnicodeDecodeError: + msg = "invalid or missing encoding declaration" + if filename is not None: + msg = '{} for {!r}'.format(msg, filename) + raise SyntaxError(msg) + + matches = cookie_re.findall(line_string) + if not matches: + return None + encoding = _get_normal_name(matches[0]) + try: + codec = lookup(encoding) + except LookupError: + # This behaviour mimics the Python interpreter + if filename is None: + msg = "unknown encoding: " + encoding + else: + msg = "unknown encoding for {!r}: {}".format(filename, + encoding) + raise SyntaxError(msg) + + if bom_found: + if codec.name != 'utf-8': + # This behaviour mimics the Python interpreter + if filename is None: + msg = 'encoding problem: utf-8' + else: + msg = 'encoding problem for {!r}: utf-8'.format(filename) + raise SyntaxError(msg) + encoding += '-sig' + return encoding + + first = read_or_stop() + if first.startswith(BOM_UTF8): + bom_found = True + first = first[3:] + default = 'utf-8-sig' + if not first: + return default, [] + + encoding = find_cookie(first) + if encoding: + return encoding, [first] + + second = read_or_stop() + if not second: + return default, [first] + + encoding = find_cookie(second) + if encoding: + return encoding, [first, second] + + return default, [first, second] + +# For converting & <-> & etc. +try: + from html import escape +except ImportError: + from cgi import escape +if sys.version_info[:2] < (3, 4): + unescape = HTMLParser().unescape +else: + from html import unescape + +try: + from collections import ChainMap +except ImportError: # pragma: no cover + from collections import MutableMapping + + try: + from reprlib import recursive_repr as _recursive_repr + except ImportError: + def _recursive_repr(fillvalue='...'): + ''' + Decorator to make a repr function return fillvalue for a recursive + call + ''' + + def decorating_function(user_function): + repr_running = set() + + def wrapper(self): + key = id(self), get_ident() + if key in repr_running: + return fillvalue + repr_running.add(key) + try: + result = user_function(self) + finally: + repr_running.discard(key) + return result + + # Can't use functools.wraps() here because of bootstrap issues + wrapper.__module__ = getattr(user_function, '__module__') + wrapper.__doc__ = getattr(user_function, '__doc__') + wrapper.__name__ = getattr(user_function, '__name__') + wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) + return wrapper + + return decorating_function + + class ChainMap(MutableMapping): + ''' A ChainMap groups multiple dicts (or other mappings) together + to create a single, updateable view. + + The underlying mappings are stored in a list. That list is public and can + accessed or updated using the *maps* attribute. There is no other state. + + Lookups search the underlying mappings successively until a key is found. + In contrast, writes, updates, and deletions only operate on the first + mapping. + + ''' + + def __init__(self, *maps): + '''Initialize a ChainMap by setting *maps* to the given mappings. + If no mappings are provided, a single empty dictionary is used. + + ''' + self.maps = list(maps) or [{}] # always at least one map + + def __missing__(self, key): + raise KeyError(key) + + def __getitem__(self, key): + for mapping in self.maps: + try: + return mapping[key] # can't use 'key in mapping' with defaultdict + except KeyError: + pass + return self.__missing__(key) # support subclasses that define __missing__ + + def get(self, key, default=None): + return self[key] if key in self else default + + def __len__(self): + return len(set().union(*self.maps)) # reuses stored hash values if possible + + def __iter__(self): + return iter(set().union(*self.maps)) + + def __contains__(self, key): + return any(key in m for m in self.maps) + + def __bool__(self): + return any(self.maps) + + @_recursive_repr() + def __repr__(self): + return '{0.__class__.__name__}({1})'.format( + self, ', '.join(map(repr, self.maps))) + + @classmethod + def fromkeys(cls, iterable, *args): + 'Create a ChainMap with a single dict created from the iterable.' + return cls(dict.fromkeys(iterable, *args)) + + def copy(self): + 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' + return self.__class__(self.maps[0].copy(), *self.maps[1:]) + + __copy__ = copy + + def new_child(self): # like Django's Context.push() + 'New ChainMap with a new dict followed by all previous maps.' + return self.__class__({}, *self.maps) + + @property + def parents(self): # like Django's Context.pop() + 'New ChainMap from maps[1:].' + return self.__class__(*self.maps[1:]) + + def __setitem__(self, key, value): + self.maps[0][key] = value + + def __delitem__(self, key): + try: + del self.maps[0][key] + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def popitem(self): + 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' + try: + return self.maps[0].popitem() + except KeyError: + raise KeyError('No keys found in the first mapping.') + + def pop(self, key, *args): + 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' + try: + return self.maps[0].pop(key, *args) + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def clear(self): + 'Clear maps[0], leaving maps[1:] intact.' + self.maps[0].clear() + +try: + from importlib.util import cache_from_source # Python >= 3.4 +except ImportError: # pragma: no cover + try: + from imp import cache_from_source + except ImportError: # pragma: no cover + def cache_from_source(path, debug_override=None): + assert path.endswith('.py') + if debug_override is None: + debug_override = __debug__ + if debug_override: + suffix = 'c' + else: + suffix = 'o' + return path + suffix + +try: + from collections import OrderedDict +except ImportError: # pragma: no cover +## {{{ http://code.activestate.com/recipes/576693/ (r9) +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. + try: + from thread import get_ident as _get_ident + except ImportError: + from dummy_thread import get_ident as _get_ident + + try: + from _abcoll import KeysView, ValuesView, ItemsView + except ImportError: + pass + + + class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running=None): + 'od.__repr__() <==> repr(od)' + if not _repr_running: _repr_running = {} + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + +try: + from logging.config import BaseConfigurator, valid_ident +except ImportError: # pragma: no cover + IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) + + + def valid_ident(s): + m = IDENTIFIER.match(s) + if not m: + raise ValueError('Not a valid Python identifier: %r' % s) + return True + + + # The ConvertingXXX classes are wrappers around standard Python containers, + # and they serve to convert any suitable values in the container. The + # conversion converts base dicts, lists and tuples to their wrapped + # equivalents, whereas strings which match a conversion format are converted + # appropriately. + # + # Each wrapper should have a configurator attribute holding the actual + # configurator to use for conversion. + + class ConvertingDict(dict): + """A converting dictionary wrapper.""" + + def __getitem__(self, key): + value = dict.__getitem__(self, key) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def get(self, key, default=None): + value = dict.get(self, key, default) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, key, default=None): + value = dict.pop(self, key, default) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class ConvertingList(list): + """A converting list wrapper.""" + def __getitem__(self, key): + value = list.__getitem__(self, key) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, idx=-1): + value = list.pop(self, idx) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + return result + + class ConvertingTuple(tuple): + """A converting tuple wrapper.""" + def __getitem__(self, key): + value = tuple.__getitem__(self, key) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class BaseConfigurator(object): + """ + The configurator base class which defines some useful defaults. + """ + + CONVERT_PATTERN = re.compile(r'^(?P<prefix>[a-z]+)://(?P<suffix>.*)$') + + WORD_PATTERN = re.compile(r'^\s*(\w+)\s*') + DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*') + INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*') + DIGIT_PATTERN = re.compile(r'^\d+$') + + value_converters = { + 'ext' : 'ext_convert', + 'cfg' : 'cfg_convert', + } + + # We might want to use a different one, e.g. importlib + importer = staticmethod(__import__) + + def __init__(self, config): + self.config = ConvertingDict(config) + self.config.configurator = self + + def resolve(self, s): + """ + Resolve strings to objects using standard import and attribute + syntax. + """ + name = s.split('.') + used = name.pop(0) + try: + found = self.importer(used) + for frag in name: + used += '.' + frag + try: + found = getattr(found, frag) + except AttributeError: + self.importer(used) + found = getattr(found, frag) + return found + except ImportError: + e, tb = sys.exc_info()[1:] + v = ValueError('Cannot resolve %r: %s' % (s, e)) + v.__cause__, v.__traceback__ = e, tb + raise v + + def ext_convert(self, value): + """Default converter for the ext:// protocol.""" + return self.resolve(value) + + def cfg_convert(self, value): + """Default converter for the cfg:// protocol.""" + rest = value + m = self.WORD_PATTERN.match(rest) + if m is None: + raise ValueError("Unable to convert %r" % value) + else: + rest = rest[m.end():] + d = self.config[m.groups()[0]] + #print d, rest + while rest: + m = self.DOT_PATTERN.match(rest) + if m: + d = d[m.groups()[0]] + else: + m = self.INDEX_PATTERN.match(rest) + if m: + idx = m.groups()[0] + if not self.DIGIT_PATTERN.match(idx): + d = d[idx] + else: + try: + n = int(idx) # try as number first (most likely) + d = d[n] + except TypeError: + d = d[idx] + if m: + rest = rest[m.end():] + else: + raise ValueError('Unable to convert ' + '%r at %r' % (value, rest)) + #rest should be empty + return d + + def convert(self, value): + """ + Convert values to an appropriate type. dicts, lists and tuples are + replaced by their converting alternatives. Strings are checked to + see if they have a conversion format and are converted if they do. + """ + if not isinstance(value, ConvertingDict) and isinstance(value, dict): + value = ConvertingDict(value) + value.configurator = self + elif not isinstance(value, ConvertingList) and isinstance(value, list): + value = ConvertingList(value) + value.configurator = self + elif not isinstance(value, ConvertingTuple) and\ + isinstance(value, tuple): + value = ConvertingTuple(value) + value.configurator = self + elif isinstance(value, string_types): + m = self.CONVERT_PATTERN.match(value) + if m: + d = m.groupdict() + prefix = d['prefix'] + converter = self.value_converters.get(prefix, None) + if converter: + suffix = d['suffix'] + converter = getattr(self, converter) + value = converter(suffix) + return value + + def configure_custom(self, config): + """Configure an object with a user-supplied factory.""" + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) + result = c(**kwargs) + if props: + for name, value in props.items(): + setattr(result, name, value) + return result + + def as_tuple(self, value): + """Utility function which converts lists to tuples.""" + if isinstance(value, list): + value = tuple(value) + return value diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py new file mode 100755 index 0000000..54483e1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py @@ -0,0 +1,1336 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""PEP 376 implementation.""" + +from __future__ import unicode_literals + +import base64 +import codecs +import contextlib +import hashlib +import logging +import os +import posixpath +import sys +import zipimport + +from . import DistlibException, resources +from .compat import StringIO +from .version import get_scheme, UnsupportedVersionError +from .metadata import Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME +from .util import (parse_requirement, cached_property, parse_name_and_version, + read_exports, write_exports, CSVReader, CSVWriter) + + +__all__ = ['Distribution', 'BaseInstalledDistribution', + 'InstalledDistribution', 'EggInfoDistribution', + 'DistributionPath'] + + +logger = logging.getLogger(__name__) + +EXPORTS_FILENAME = 'pydist-exports.json' +COMMANDS_FILENAME = 'pydist-commands.json' + +DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', + 'RESOURCES', EXPORTS_FILENAME, 'SHARED') + +DISTINFO_EXT = '.dist-info' + + +class _Cache(object): + """ + A simple cache mapping names and .dist-info paths to distributions + """ + def __init__(self): + """ + Initialise an instance. There is normally one for each DistributionPath. + """ + self.name = {} + self.path = {} + self.generated = False + + def clear(self): + """ + Clear the cache, setting it to its initial state. + """ + self.name.clear() + self.path.clear() + self.generated = False + + def add(self, dist): + """ + Add a distribution to the cache. + :param dist: The distribution to add. + """ + if dist.path not in self.path: + self.path[dist.path] = dist + self.name.setdefault(dist.key, []).append(dist) + + +class DistributionPath(object): + """ + Represents a set of distributions installed on a path (typically sys.path). + """ + def __init__(self, path=None, include_egg=False): + """ + Create an instance from a path, optionally including legacy (distutils/ + setuptools/distribute) distributions. + :param path: The path to use, as a list of directories. If not specified, + sys.path is used. + :param include_egg: If True, this instance will look for and return legacy + distributions as well as those based on PEP 376. + """ + if path is None: + path = sys.path + self.path = path + self._include_dist = True + self._include_egg = include_egg + + self._cache = _Cache() + self._cache_egg = _Cache() + self._cache_enabled = True + self._scheme = get_scheme('default') + + def _get_cache_enabled(self): + return self._cache_enabled + + def _set_cache_enabled(self, value): + self._cache_enabled = value + + cache_enabled = property(_get_cache_enabled, _set_cache_enabled) + + def clear_cache(self): + """ + Clears the internal cache. + """ + self._cache.clear() + self._cache_egg.clear() + + + def _yield_distributions(self): + """ + Yield .dist-info and/or .egg(-info) distributions. + """ + # We need to check if we've seen some resources already, because on + # some Linux systems (e.g. some Debian/Ubuntu variants) there are + # symlinks which alias other files in the environment. + seen = set() + for path in self.path: + finder = resources.finder_for_path(path) + if finder is None: + continue + r = finder.find('') + if not r or not r.is_container: + continue + rset = sorted(r.resources) + for entry in rset: + r = finder.find(entry) + if not r or r.path in seen: + continue + if self._include_dist and entry.endswith(DISTINFO_EXT): + possible_filenames = [METADATA_FILENAME, WHEEL_METADATA_FILENAME] + for metadata_filename in possible_filenames: + metadata_path = posixpath.join(entry, metadata_filename) + pydist = finder.find(metadata_path) + if pydist: + break + else: + continue + + with contextlib.closing(pydist.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + logger.debug('Found %s', r.path) + seen.add(r.path) + yield new_dist_class(r.path, metadata=metadata, + env=self) + elif self._include_egg and entry.endswith(('.egg-info', + '.egg')): + logger.debug('Found %s', r.path) + seen.add(r.path) + yield old_dist_class(r.path, self) + + def _generate_cache(self): + """ + Scan the path for distributions and populate the cache with + those that are found. + """ + gen_dist = not self._cache.generated + gen_egg = self._include_egg and not self._cache_egg.generated + if gen_dist or gen_egg: + for dist in self._yield_distributions(): + if isinstance(dist, InstalledDistribution): + self._cache.add(dist) + else: + self._cache_egg.add(dist) + + if gen_dist: + self._cache.generated = True + if gen_egg: + self._cache_egg.generated = True + + @classmethod + def distinfo_dirname(cls, name, version): + """ + The *name* and *version* parameters are converted into their + filename-escaped form, i.e. any ``'-'`` characters are replaced + with ``'_'`` other than the one in ``'dist-info'`` and the one + separating the name from the version number. + + :parameter name: is converted to a standard distribution name by replacing + any runs of non- alphanumeric characters with a single + ``'-'``. + :type name: string + :parameter version: is converted to a standard version string. Spaces + become dots, and all other non-alphanumeric characters + (except dots) become dashes, with runs of multiple + dashes condensed to a single dash. + :type version: string + :returns: directory name + :rtype: string""" + name = name.replace('-', '_') + return '-'.join([name, version]) + DISTINFO_EXT + + def get_distributions(self): + """ + Provides an iterator that looks for distributions and returns + :class:`InstalledDistribution` or + :class:`EggInfoDistribution` instances for each one of them. + + :rtype: iterator of :class:`InstalledDistribution` and + :class:`EggInfoDistribution` instances + """ + if not self._cache_enabled: + for dist in self._yield_distributions(): + yield dist + else: + self._generate_cache() + + for dist in self._cache.path.values(): + yield dist + + if self._include_egg: + for dist in self._cache_egg.path.values(): + yield dist + + def get_distribution(self, name): + """ + Looks for a named distribution on the path. + + This function only returns the first result found, as no more than one + value is expected. If nothing is found, ``None`` is returned. + + :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` + or ``None`` + """ + result = None + name = name.lower() + if not self._cache_enabled: + for dist in self._yield_distributions(): + if dist.key == name: + result = dist + break + else: + self._generate_cache() + + if name in self._cache.name: + result = self._cache.name[name][0] + elif self._include_egg and name in self._cache_egg.name: + result = self._cache_egg.name[name][0] + return result + + def provides_distribution(self, name, version=None): + """ + Iterates over all distributions to find which distributions provide *name*. + If a *version* is provided, it will be used to filter the results. + + This function only returns the first result found, since no more than + one values are expected. If the directory is not found, returns ``None``. + + :parameter version: a version specifier that indicates the version + required, conforming to the format in ``PEP-345`` + + :type name: string + :type version: string + """ + matcher = None + if version is not None: + try: + matcher = self._scheme.matcher('%s (%s)' % (name, version)) + except ValueError: + raise DistlibException('invalid name or version: %r, %r' % + (name, version)) + + for dist in self.get_distributions(): + # We hit a problem on Travis where enum34 was installed and doesn't + # have a provides attribute ... + if not hasattr(dist, 'provides'): + logger.debug('No "provides": %s', dist) + else: + provided = dist.provides + + for p in provided: + p_name, p_ver = parse_name_and_version(p) + if matcher is None: + if p_name == name: + yield dist + break + else: + if p_name == name and matcher.match(p_ver): + yield dist + break + + def get_file_path(self, name, relative_path): + """ + Return the path to a resource file. + """ + dist = self.get_distribution(name) + if dist is None: + raise LookupError('no distribution named %r found' % name) + return dist.get_resource_path(relative_path) + + def get_exported_entries(self, category, name=None): + """ + Return all of the exported entries in a particular category. + + :param category: The category to search for entries. + :param name: If specified, only entries with that name are returned. + """ + for dist in self.get_distributions(): + r = dist.exports + if category in r: + d = r[category] + if name is not None: + if name in d: + yield d[name] + else: + for v in d.values(): + yield v + + +class Distribution(object): + """ + A base class for distributions, whether installed or from indexes. + Either way, it must have some metadata, so that's all that's needed + for construction. + """ + + build_time_dependency = False + """ + Set to True if it's known to be only a build-time dependency (i.e. + not needed after installation). + """ + + requested = False + """A boolean that indicates whether the ``REQUESTED`` metadata file is + present (in other words, whether the package was installed by user + request or it was installed as a dependency).""" + + def __init__(self, metadata): + """ + Initialise an instance. + :param metadata: The instance of :class:`Metadata` describing this + distribution. + """ + self.metadata = metadata + self.name = metadata.name + self.key = self.name.lower() # for case-insensitive comparisons + self.version = metadata.version + self.locator = None + self.digest = None + self.extras = None # additional features requested + self.context = None # environment marker overrides + self.download_urls = set() + self.digests = {} + + @property + def source_url(self): + """ + The source archive download URL for this distribution. + """ + return self.metadata.source_url + + download_url = source_url # Backward compatibility + + @property + def name_and_version(self): + """ + A utility property which displays the name and version in parentheses. + """ + return '%s (%s)' % (self.name, self.version) + + @property + def provides(self): + """ + A set of distribution names and versions provided by this distribution. + :return: A set of "name (version)" strings. + """ + plist = self.metadata.provides + s = '%s (%s)' % (self.name, self.version) + if s not in plist: + plist.append(s) + return plist + + def _get_requirements(self, req_attr): + md = self.metadata + logger.debug('Getting requirements from metadata %r', md.todict()) + reqts = getattr(md, req_attr) + return set(md.get_requirements(reqts, extras=self.extras, + env=self.context)) + + @property + def run_requires(self): + return self._get_requirements('run_requires') + + @property + def meta_requires(self): + return self._get_requirements('meta_requires') + + @property + def build_requires(self): + return self._get_requirements('build_requires') + + @property + def test_requires(self): + return self._get_requirements('test_requires') + + @property + def dev_requires(self): + return self._get_requirements('dev_requires') + + def matches_requirement(self, req): + """ + Say if this instance matches (fulfills) a requirement. + :param req: The requirement to match. + :rtype req: str + :return: True if it matches, else False. + """ + # Requirement may contain extras - parse to lose those + # from what's passed to the matcher + r = parse_requirement(req) + scheme = get_scheme(self.metadata.scheme) + try: + matcher = scheme.matcher(r.requirement) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', + req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + result = False + for p in self.provides: + p_name, p_ver = parse_name_and_version(p) + if p_name != name: + continue + try: + result = matcher.match(p_ver) + break + except UnsupportedVersionError: + pass + return result + + def __repr__(self): + """ + Return a textual representation of this instance, + """ + if self.source_url: + suffix = ' [%s]' % self.source_url + else: + suffix = '' + return '<Distribution %s (%s)%s>' % (self.name, self.version, suffix) + + def __eq__(self, other): + """ + See if this distribution is the same as another. + :param other: The distribution to compare with. To be equal to one + another. distributions must have the same type, name, + version and source_url. + :return: True if it is the same, else False. + """ + if type(other) is not type(self): + result = False + else: + result = (self.name == other.name and + self.version == other.version and + self.source_url == other.source_url) + return result + + def __hash__(self): + """ + Compute hash in a way which matches the equality test. + """ + return hash(self.name) + hash(self.version) + hash(self.source_url) + + +class BaseInstalledDistribution(Distribution): + """ + This is the base class for installed distributions (whether PEP 376 or + legacy). + """ + + hasher = None + + def __init__(self, metadata, path, env=None): + """ + Initialise an instance. + :param metadata: An instance of :class:`Metadata` which describes the + distribution. This will normally have been initialised + from a metadata file in the ``path``. + :param path: The path of the ``.dist-info`` or ``.egg-info`` + directory for the distribution. + :param env: This is normally the :class:`DistributionPath` + instance where this distribution was found. + """ + super(BaseInstalledDistribution, self).__init__(metadata) + self.path = path + self.dist_path = env + + def get_hash(self, data, hasher=None): + """ + Get the hash of some data, using a particular hash algorithm, if + specified. + + :param data: The data to be hashed. + :type data: bytes + :param hasher: The name of a hash implementation, supported by hashlib, + or ``None``. Examples of valid values are ``'sha1'``, + ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and + ``'sha512'``. If no hasher is specified, the ``hasher`` + attribute of the :class:`InstalledDistribution` instance + is used. If the hasher is determined to be ``None``, MD5 + is used as the hashing algorithm. + :returns: The hash of the data. If a hasher was explicitly specified, + the returned hash will be prefixed with the specified hasher + followed by '='. + :rtype: str + """ + if hasher is None: + hasher = self.hasher + if hasher is None: + hasher = hashlib.md5 + prefix = '' + else: + hasher = getattr(hashlib, hasher) + prefix = '%s=' % self.hasher + digest = hasher(data).digest() + digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') + return '%s%s' % (prefix, digest) + + +class InstalledDistribution(BaseInstalledDistribution): + """ + Created with the *path* of the ``.dist-info`` directory provided to the + constructor. It reads the metadata contained in ``pydist.json`` when it is + instantiated., or uses a passed in Metadata instance (useful for when + dry-run mode is being used). + """ + + hasher = 'sha256' + + def __init__(self, path, metadata=None, env=None): + self.modules = [] + self.finder = finder = resources.finder_for_path(path) + if finder is None: + raise ValueError('finder unavailable for %s' % path) + if env and env._cache_enabled and path in env._cache.path: + metadata = env._cache.path[path].metadata + elif metadata is None: + r = finder.find(METADATA_FILENAME) + # Temporary - for Wheel 0.23 support + if r is None: + r = finder.find(WHEEL_METADATA_FILENAME) + # Temporary - for legacy support + if r is None: + r = finder.find('METADATA') + if r is None: + raise ValueError('no %s found in %s' % (METADATA_FILENAME, + path)) + with contextlib.closing(r.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + + super(InstalledDistribution, self).__init__(metadata, path, env) + + if env and env._cache_enabled: + env._cache.add(self) + + r = finder.find('REQUESTED') + self.requested = r is not None + p = os.path.join(path, 'top_level.txt') + if os.path.exists(p): + with open(p, 'rb') as f: + data = f.read() + self.modules = data.splitlines() + + def __repr__(self): + return '<InstalledDistribution %r %s at %r>' % ( + self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def _get_records(self): + """ + Get the list of installed files for the distribution + :return: A list of tuples of path, hash and size. Note that hash and + size might be ``None`` for some entries. The path is exactly + as stored in the file (which is as in PEP 376). + """ + results = [] + r = self.get_distinfo_resource('RECORD') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as record_reader: + # Base location is parent dir of .dist-info dir + #base_location = os.path.dirname(self.path) + #base_location = os.path.abspath(base_location) + for row in record_reader: + missing = [None for i in range(len(row), 3)] + path, checksum, size = row + missing + #if not os.path.isabs(path): + # path = path.replace('/', os.sep) + # path = os.path.join(base_location, path) + results.append((path, checksum, size)) + return results + + @cached_property + def exports(self): + """ + Return the information exported by this distribution. + :return: A dictionary of exports, mapping an export category to a dict + of :class:`ExportEntry` instances describing the individual + export entries, and keyed by name. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + result = self.read_exports() + return result + + def read_exports(self): + """ + Read exports data from a file in .ini format. + + :return: A dictionary of exports, mapping an export category to a list + of :class:`ExportEntry` instances describing the individual + export entries. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + with contextlib.closing(r.as_stream()) as stream: + result = read_exports(stream) + return result + + def write_exports(self, exports): + """ + Write a dictionary of exports to a file in .ini format. + :param exports: A dictionary of exports, mapping an export category to + a list of :class:`ExportEntry` instances describing the + individual export entries. + """ + rf = self.get_distinfo_file(EXPORTS_FILENAME) + with open(rf, 'w') as f: + write_exports(exports, f) + + def get_resource_path(self, relative_path): + """ + NOTE: This API may change in the future. + + Return the absolute path to a resource file with the given relative + path. + + :param relative_path: The path, relative to .dist-info, of the resource + of interest. + :return: The absolute path where the resource is to be found. + """ + r = self.get_distinfo_resource('RESOURCES') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as resources_reader: + for relative, destination in resources_reader: + if relative == relative_path: + return destination + raise KeyError('no resource file with relative path %r ' + 'is installed' % relative_path) + + def list_installed_files(self): + """ + Iterates over the ``RECORD`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: iterator of (path, hash, size) + """ + for result in self._get_records(): + yield result + + def write_installed_files(self, paths, prefix, dry_run=False): + """ + Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any + existing ``RECORD`` file is silently overwritten. + + prefix is used to determine when to write absolute paths. + """ + prefix = os.path.join(prefix, '') + base = os.path.dirname(self.path) + base_under_prefix = base.startswith(prefix) + base = os.path.join(base, '') + record_path = self.get_distinfo_file('RECORD') + logger.info('creating %s', record_path) + if dry_run: + return None + with CSVWriter(record_path) as writer: + for path in paths: + if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')): + # do not put size and hash, as in PEP-376 + hash_value = size = '' + else: + size = '%d' % os.path.getsize(path) + with open(path, 'rb') as fp: + hash_value = self.get_hash(fp.read()) + if path.startswith(base) or (base_under_prefix and + path.startswith(prefix)): + path = os.path.relpath(path, base) + writer.writerow((path, hash_value, size)) + + # add the RECORD file itself + if record_path.startswith(base): + record_path = os.path.relpath(record_path, base) + writer.writerow((record_path, '', '')) + return record_path + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + base = os.path.dirname(self.path) + record_path = self.get_distinfo_file('RECORD') + for path, hash_value, size in self.list_installed_files(): + if not os.path.isabs(path): + path = os.path.join(base, path) + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + elif os.path.isfile(path): + actual_size = str(os.path.getsize(path)) + if size and actual_size != size: + mismatches.append((path, 'size', size, actual_size)) + elif hash_value: + if '=' in hash_value: + hasher = hash_value.split('=', 1)[0] + else: + hasher = None + + with open(path, 'rb') as f: + actual_hash = self.get_hash(f.read(), hasher) + if actual_hash != hash_value: + mismatches.append((path, 'hash', hash_value, actual_hash)) + return mismatches + + @cached_property + def shared_locations(self): + """ + A dictionary of shared locations whose keys are in the set 'prefix', + 'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'. + The corresponding value is the absolute path of that category for + this distribution, and takes into account any paths selected by the + user at installation time (e.g. via command-line arguments). In the + case of the 'namespace' key, this would be a list of absolute paths + for the roots of namespace packages in this distribution. + + The first time this property is accessed, the relevant information is + read from the SHARED file in the .dist-info directory. + """ + result = {} + shared_path = os.path.join(self.path, 'SHARED') + if os.path.isfile(shared_path): + with codecs.open(shared_path, 'r', encoding='utf-8') as f: + lines = f.read().splitlines() + for line in lines: + key, value = line.split('=', 1) + if key == 'namespace': + result.setdefault(key, []).append(value) + else: + result[key] = value + return result + + def write_shared_locations(self, paths, dry_run=False): + """ + Write shared location information to the SHARED file in .dist-info. + :param paths: A dictionary as described in the documentation for + :meth:`shared_locations`. + :param dry_run: If True, the action is logged but no file is actually + written. + :return: The path of the file written to. + """ + shared_path = os.path.join(self.path, 'SHARED') + logger.info('creating %s', shared_path) + if dry_run: + return None + lines = [] + for key in ('prefix', 'lib', 'headers', 'scripts', 'data'): + path = paths[key] + if os.path.isdir(paths[key]): + lines.append('%s=%s' % (key, path)) + for ns in paths.get('namespace', ()): + lines.append('namespace=%s' % ns) + + with codecs.open(shared_path, 'w', encoding='utf-8') as f: + f.write('\n'.join(lines)) + return shared_path + + def get_distinfo_resource(self, path): + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + finder = resources.finder_for_path(self.path) + if finder is None: + raise DistlibException('Unable to get a finder for %s' % self.path) + return finder.find(path) + + def get_distinfo_file(self, path): + """ + Returns a path located under the ``.dist-info`` directory. Returns a + string representing the path. + + :parameter path: a ``'/'``-separated path relative to the + ``.dist-info`` directory or an absolute path; + If *path* is an absolute path and doesn't start + with the ``.dist-info`` directory path, + a :class:`DistlibException` is raised + :type path: str + :rtype: str + """ + # Check if it is an absolute path # XXX use relpath, add tests + if path.find(os.sep) >= 0: + # it's an absolute path? + distinfo_dirname, path = path.split(os.sep)[-2:] + if distinfo_dirname != self.path.split(os.sep)[-1]: + raise DistlibException( + 'dist-info file %r does not belong to the %r %s ' + 'distribution' % (path, self.name, self.version)) + + # The file must be relative + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + + return os.path.join(self.path, path) + + def list_distinfo_files(self): + """ + Iterates over the ``RECORD`` entries and returns paths for each line if + the path is pointing to a file located in the ``.dist-info`` directory + or one of its subdirectories. + + :returns: iterator of paths + """ + base = os.path.dirname(self.path) + for path, checksum, size in self._get_records(): + # XXX add separator or use real relpath algo + if not os.path.isabs(path): + path = os.path.join(base, path) + if path.startswith(self.path): + yield path + + def __eq__(self, other): + return (isinstance(other, InstalledDistribution) and + self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +class EggInfoDistribution(BaseInstalledDistribution): + """Created with the *path* of the ``.egg-info`` directory or file provided + to the constructor. It reads the metadata contained in the file itself, or + if the given path happens to be a directory, the metadata is read from the + file ``PKG-INFO`` under that directory.""" + + requested = True # as we have no way of knowing, assume it was + shared_locations = {} + + def __init__(self, path, env=None): + def set_name_and_version(s, n, v): + s.name = n + s.key = n.lower() # for case-insensitive comparisons + s.version = v + + self.path = path + self.dist_path = env + if env and env._cache_enabled and path in env._cache_egg.path: + metadata = env._cache_egg.path[path].metadata + set_name_and_version(self, metadata.name, metadata.version) + else: + metadata = self._get_metadata(path) + + # Need to be set before caching + set_name_and_version(self, metadata.name, metadata.version) + + if env and env._cache_enabled: + env._cache_egg.add(self) + super(EggInfoDistribution, self).__init__(metadata, path, env) + + def _get_metadata(self, path): + requires = None + + def parse_requires_data(data): + """Create a list of dependencies from a requires.txt file. + + *data*: the contents of a setuptools-produced requires.txt file. + """ + reqs = [] + lines = data.splitlines() + for line in lines: + line = line.strip() + if line.startswith('['): + logger.warning('Unexpected line: quitting requirement scan: %r', + line) + break + r = parse_requirement(line) + if not r: + logger.warning('Not recognised as a requirement: %r', line) + continue + if r.extras: + logger.warning('extra requirements in requires.txt are ' + 'not supported') + if not r.constraints: + reqs.append(r.name) + else: + cons = ', '.join('%s%s' % c for c in r.constraints) + reqs.append('%s (%s)' % (r.name, cons)) + return reqs + + def parse_requires_path(req_path): + """Create a list of dependencies from a requires.txt file. + + *req_path*: the path to a setuptools-produced requires.txt file. + """ + + reqs = [] + try: + with codecs.open(req_path, 'r', 'utf-8') as fp: + reqs = parse_requires_data(fp.read()) + except IOError: + pass + return reqs + + tl_path = tl_data = None + if path.endswith('.egg'): + if os.path.isdir(path): + p = os.path.join(path, 'EGG-INFO') + meta_path = os.path.join(p, 'PKG-INFO') + metadata = Metadata(path=meta_path, scheme='legacy') + req_path = os.path.join(p, 'requires.txt') + tl_path = os.path.join(p, 'top_level.txt') + requires = parse_requires_path(req_path) + else: + # FIXME handle the case where zipfile is not available + zipf = zipimport.zipimporter(path) + fileobj = StringIO( + zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) + metadata = Metadata(fileobj=fileobj, scheme='legacy') + try: + data = zipf.get_data('EGG-INFO/requires.txt') + tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode('utf-8') + requires = parse_requires_data(data.decode('utf-8')) + except IOError: + requires = None + elif path.endswith('.egg-info'): + if os.path.isdir(path): + req_path = os.path.join(path, 'requires.txt') + requires = parse_requires_path(req_path) + path = os.path.join(path, 'PKG-INFO') + tl_path = os.path.join(path, 'top_level.txt') + metadata = Metadata(path=path, scheme='legacy') + else: + raise DistlibException('path must end with .egg-info or .egg, ' + 'got %r' % path) + + if requires: + metadata.add_requirements(requires) + # look for top-level modules in top_level.txt, if present + if tl_data is None: + if tl_path is not None and os.path.exists(tl_path): + with open(tl_path, 'rb') as f: + tl_data = f.read().decode('utf-8') + if not tl_data: + tl_data = [] + else: + tl_data = tl_data.splitlines() + self.modules = tl_data + return metadata + + def __repr__(self): + return '<EggInfoDistribution %r %s at %r>' % ( + self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + for path, _, _ in self.list_installed_files(): + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + return mismatches + + def list_installed_files(self): + """ + Iterates over the ``installed-files.txt`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: a list of (path, hash, size) + """ + + def _md5(path): + f = open(path, 'rb') + try: + content = f.read() + finally: + f.close() + return hashlib.md5(content).hexdigest() + + def _size(path): + return os.stat(path).st_size + + record_path = os.path.join(self.path, 'installed-files.txt') + result = [] + if os.path.exists(record_path): + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + p = os.path.normpath(os.path.join(self.path, line)) + # "./" is present as a marker between installed files + # and installation metadata files + if not os.path.exists(p): + logger.warning('Non-existent file: %s', p) + if p.endswith(('.pyc', '.pyo')): + continue + #otherwise fall through and fail + if not os.path.isdir(p): + result.append((p, _md5(p), _size(p))) + result.append((record_path, None, None)) + return result + + def list_distinfo_files(self, absolute=False): + """ + Iterates over the ``installed-files.txt`` entries and returns paths for + each line if the path is pointing to a file located in the + ``.egg-info`` directory or one of its subdirectories. + + :parameter absolute: If *absolute* is ``True``, each returned path is + transformed into a local absolute path. Otherwise the + raw value from ``installed-files.txt`` is returned. + :type absolute: boolean + :returns: iterator of paths + """ + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + skip = True + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line == './': + skip = False + continue + if not skip: + p = os.path.normpath(os.path.join(self.path, line)) + if p.startswith(self.path): + if absolute: + yield p + else: + yield line + + def __eq__(self, other): + return (isinstance(other, EggInfoDistribution) and + self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + +new_dist_class = InstalledDistribution +old_dist_class = EggInfoDistribution + + +class DependencyGraph(object): + """ + Represents a dependency graph between distributions. + + The dependency relationships are stored in an ``adjacency_list`` that maps + distributions to a list of ``(other, label)`` tuples where ``other`` + is a distribution and the edge is labeled with ``label`` (i.e. the version + specifier, if such was provided). Also, for more efficient traversal, for + every distribution ``x``, a list of predecessors is kept in + ``reverse_list[x]``. An edge from distribution ``a`` to + distribution ``b`` means that ``a`` depends on ``b``. If any missing + dependencies are found, they are stored in ``missing``, which is a + dictionary that maps distributions to a list of requirements that were not + provided by any other distributions. + """ + + def __init__(self): + self.adjacency_list = {} + self.reverse_list = {} + self.missing = {} + + def add_distribution(self, distribution): + """Add the *distribution* to the graph. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + """ + self.adjacency_list[distribution] = [] + self.reverse_list[distribution] = [] + #self.missing[distribution] = [] + + def add_edge(self, x, y, label=None): + """Add an edge from distribution *x* to distribution *y* with the given + *label*. + + :type x: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type y: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type label: ``str`` or ``None`` + """ + self.adjacency_list[x].append((y, label)) + # multiple edges are allowed, so be careful + if x not in self.reverse_list[y]: + self.reverse_list[y].append(x) + + def add_missing(self, distribution, requirement): + """ + Add a missing *requirement* for the given *distribution*. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + :type requirement: ``str`` + """ + logger.debug('%s missing %r', distribution, requirement) + self.missing.setdefault(distribution, []).append(requirement) + + def _repr_dist(self, dist): + return '%s %s' % (dist.name, dist.version) + + def repr_node(self, dist, level=1): + """Prints only a subgraph""" + output = [self._repr_dist(dist)] + for other, label in self.adjacency_list[dist]: + dist = self._repr_dist(other) + if label is not None: + dist = '%s [%s]' % (dist, label) + output.append(' ' * level + str(dist)) + suboutput = self.repr_node(other, level + 1) + subs = suboutput.split('\n') + output.extend(subs[1:]) + return '\n'.join(output) + + def to_dot(self, f, skip_disconnected=True): + """Writes a DOT output for the graph to the provided file *f*. + + If *skip_disconnected* is set to ``True``, then all distributions + that are not dependent on any other distribution are skipped. + + :type f: has to support ``file``-like operations + :type skip_disconnected: ``bool`` + """ + disconnected = [] + + f.write("digraph dependencies {\n") + for dist, adjs in self.adjacency_list.items(): + if len(adjs) == 0 and not skip_disconnected: + disconnected.append(dist) + for other, label in adjs: + if not label is None: + f.write('"%s" -> "%s" [label="%s"]\n' % + (dist.name, other.name, label)) + else: + f.write('"%s" -> "%s"\n' % (dist.name, other.name)) + if not skip_disconnected and len(disconnected) > 0: + f.write('subgraph disconnected {\n') + f.write('label = "Disconnected"\n') + f.write('bgcolor = red\n') + + for dist in disconnected: + f.write('"%s"' % dist.name) + f.write('\n') + f.write('}\n') + f.write('}\n') + + def topological_sort(self): + """ + Perform a topological sort of the graph. + :return: A tuple, the first element of which is a topologically sorted + list of distributions, and the second element of which is a + list of distributions that cannot be sorted because they have + circular dependencies and so form a cycle. + """ + result = [] + # Make a shallow copy of the adjacency list + alist = {} + for k, v in self.adjacency_list.items(): + alist[k] = v[:] + while True: + # See what we can remove in this run + to_remove = [] + for k, v in list(alist.items())[:]: + if not v: + to_remove.append(k) + del alist[k] + if not to_remove: + # What's left in alist (if anything) is a cycle. + break + # Remove from the adjacency list of others + for k, v in alist.items(): + alist[k] = [(d, r) for d, r in v if d not in to_remove] + logger.debug('Moving to result: %s', + ['%s (%s)' % (d.name, d.version) for d in to_remove]) + result.extend(to_remove) + return result, list(alist.keys()) + + def __repr__(self): + """Representation of the graph""" + output = [] + for dist, adjs in self.adjacency_list.items(): + output.append(self.repr_node(dist)) + return '\n'.join(output) + + +def make_graph(dists, scheme='default'): + """Makes a dependency graph from the given distributions. + + :parameter dists: a list of distributions + :type dists: list of :class:`distutils2.database.InstalledDistribution` and + :class:`distutils2.database.EggInfoDistribution` instances + :rtype: a :class:`DependencyGraph` instance + """ + scheme = get_scheme(scheme) + graph = DependencyGraph() + provided = {} # maps names to lists of (version, dist) tuples + + # first, build the graph and find out what's provided + for dist in dists: + graph.add_distribution(dist) + + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + provided.setdefault(name, []).append((version, dist)) + + # now make the edges + for dist in dists: + requires = (dist.run_requires | dist.meta_requires | + dist.build_requires | dist.dev_requires) + for req in requires: + try: + matcher = scheme.matcher(req) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', + req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + matched = False + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + graph.add_edge(dist, provider, req) + matched = True + break + if not matched: + graph.add_missing(dist, req) + return graph + + +def get_dependent_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + dependent on *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + dep = [dist] # dependent distributions + todo = graph.reverse_list[dist] # list of nodes we should inspect + + while todo: + d = todo.pop() + dep.append(d) + for succ in graph.reverse_list[d]: + if succ not in dep: + todo.append(succ) + + dep.pop(0) # remove dist from dep, was there to prevent infinite loops + return dep + + +def get_required_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + required by *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + req = [] # required distributions + todo = graph.adjacency_list[dist] # list of nodes we should inspect + + while todo: + d = todo.pop()[0] + req.append(d) + for pred in graph.adjacency_list[d]: + if pred not in req: + todo.append(pred) + + return req + + +def make_dist(name, version, **kwargs): + """ + A convenience method for making a dist given just a name and version. + """ + summary = kwargs.pop('summary', 'Placeholder for summary') + md = Metadata(**kwargs) + md.name = name + md.version = version + md.summary = summary or 'Placeholder for summary' + return Distribution(md) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py new file mode 100755 index 0000000..7197238 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py @@ -0,0 +1,516 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import hashlib +import logging +import os +import shutil +import subprocess +import tempfile +try: + from threading import Thread +except ImportError: + from dummy_threading import Thread + +from . import DistlibException +from .compat import (HTTPBasicAuthHandler, Request, HTTPPasswordMgr, + urlparse, build_opener, string_types) +from .util import cached_property, zip_dir, ServerProxy + +logger = logging.getLogger(__name__) + +DEFAULT_INDEX = 'https://pypi.python.org/pypi' +DEFAULT_REALM = 'pypi' + +class PackageIndex(object): + """ + This class represents a package index compatible with PyPI, the Python + Package Index. + """ + + boundary = b'----------ThIs_Is_tHe_distlib_index_bouNdaRY_$' + + def __init__(self, url=None): + """ + Initialise an instance. + + :param url: The URL of the index. If not specified, the URL for PyPI is + used. + """ + self.url = url or DEFAULT_INDEX + self.read_configuration() + scheme, netloc, path, params, query, frag = urlparse(self.url) + if params or query or frag or scheme not in ('http', 'https'): + raise DistlibException('invalid repository: %s' % self.url) + self.password_handler = None + self.ssl_verifier = None + self.gpg = None + self.gpg_home = None + with open(os.devnull, 'w') as sink: + # Use gpg by default rather than gpg2, as gpg2 insists on + # prompting for passwords + for s in ('gpg', 'gpg2'): + try: + rc = subprocess.check_call([s, '--version'], stdout=sink, + stderr=sink) + if rc == 0: + self.gpg = s + break + except OSError: + pass + + def _get_pypirc_command(self): + """ + Get the distutils command for interacting with PyPI configurations. + :return: the command. + """ + from distutils.core import Distribution + from distutils.config import PyPIRCCommand + d = Distribution() + return PyPIRCCommand(d) + + def read_configuration(self): + """ + Read the PyPI access configuration as supported by distutils, getting + PyPI to do the actual work. This populates ``username``, ``password``, + ``realm`` and ``url`` attributes from the configuration. + """ + # get distutils to do the work + c = self._get_pypirc_command() + c.repository = self.url + cfg = c._read_pypirc() + self.username = cfg.get('username') + self.password = cfg.get('password') + self.realm = cfg.get('realm', 'pypi') + self.url = cfg.get('repository', self.url) + + def save_configuration(self): + """ + Save the PyPI access configuration. You must have set ``username`` and + ``password`` attributes before calling this method. + + Again, distutils is used to do the actual work. + """ + self.check_credentials() + # get distutils to do the work + c = self._get_pypirc_command() + c._store_pypirc(self.username, self.password) + + def check_credentials(self): + """ + Check that ``username`` and ``password`` have been set, and raise an + exception if not. + """ + if self.username is None or self.password is None: + raise DistlibException('username and password must be set') + pm = HTTPPasswordMgr() + _, netloc, _, _, _, _ = urlparse(self.url) + pm.add_password(self.realm, netloc, self.username, self.password) + self.password_handler = HTTPBasicAuthHandler(pm) + + def register(self, metadata): + """ + Register a distribution on PyPI, using the provided metadata. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the distribution to be + registered. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + metadata.validate() + d = metadata.todict() + d[':action'] = 'verify' + request = self.encode_request(d.items(), []) + response = self.send_request(request) + d[':action'] = 'submit' + request = self.encode_request(d.items(), []) + return self.send_request(request) + + def _reader(self, name, stream, outbuf): + """ + Thread runner for reading lines of from a subprocess into a buffer. + + :param name: The logical name of the stream (used for logging only). + :param stream: The stream to read from. This will typically a pipe + connected to the output stream of a subprocess. + :param outbuf: The list to append the read lines to. + """ + while True: + s = stream.readline() + if not s: + break + s = s.decode('utf-8').rstrip() + outbuf.append(s) + logger.debug('%s: %s' % (name, s)) + stream.close() + + def get_sign_command(self, filename, signer, sign_password, + keystore=None): + """ + Return a suitable command for signing a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The signing command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + if sign_password is not None: + cmd.extend(['--batch', '--passphrase-fd', '0']) + td = tempfile.mkdtemp() + sf = os.path.join(td, os.path.basename(filename) + '.asc') + cmd.extend(['--detach-sign', '--armor', '--local-user', + signer, '--output', sf, filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd, sf + + def run_command(self, cmd, input_data=None): + """ + Run a command in a child process , passing it any input data specified. + + :param cmd: The command to run. + :param input_data: If specified, this must be a byte string containing + data to be sent to the child process. + :return: A tuple consisting of the subprocess' exit code, a list of + lines read from the subprocess' ``stdout``, and a list of + lines read from the subprocess' ``stderr``. + """ + kwargs = { + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + } + if input_data is not None: + kwargs['stdin'] = subprocess.PIPE + stdout = [] + stderr = [] + p = subprocess.Popen(cmd, **kwargs) + # We don't use communicate() here because we may need to + # get clever with interacting with the command + t1 = Thread(target=self._reader, args=('stdout', p.stdout, stdout)) + t1.start() + t2 = Thread(target=self._reader, args=('stderr', p.stderr, stderr)) + t2.start() + if input_data is not None: + p.stdin.write(input_data) + p.stdin.close() + + p.wait() + t1.join() + t2.join() + return p.returncode, stdout, stderr + + def sign_file(self, filename, signer, sign_password, keystore=None): + """ + Sign a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The absolute pathname of the file where the signature is + stored. + """ + cmd, sig_file = self.get_sign_command(filename, signer, sign_password, + keystore) + rc, stdout, stderr = self.run_command(cmd, + sign_password.encode('utf-8')) + if rc != 0: + raise DistlibException('sign command failed with error ' + 'code %s' % rc) + return sig_file + + def upload_file(self, metadata, filename, signer=None, sign_password=None, + filetype='sdist', pyversion='source', keystore=None): + """ + Upload a release file to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the file to be uploaded. + :param filename: The pathname of the file to be uploaded. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param filetype: The type of the file being uploaded. This is the + distutils command which produced that file, e.g. + ``sdist`` or ``bdist_wheel``. + :param pyversion: The version of Python which the release relates + to. For code compatible with any Python, this would + be ``source``, otherwise it would be e.g. ``3.2``. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.exists(filename): + raise DistlibException('not found: %s' % filename) + metadata.validate() + d = metadata.todict() + sig_file = None + if signer: + if not self.gpg: + logger.warning('no signing program available - not signed') + else: + sig_file = self.sign_file(filename, signer, sign_password, + keystore) + with open(filename, 'rb') as f: + file_data = f.read() + md5_digest = hashlib.md5(file_data).hexdigest() + sha256_digest = hashlib.sha256(file_data).hexdigest() + d.update({ + ':action': 'file_upload', + 'protocol_version': '1', + 'filetype': filetype, + 'pyversion': pyversion, + 'md5_digest': md5_digest, + 'sha256_digest': sha256_digest, + }) + files = [('content', os.path.basename(filename), file_data)] + if sig_file: + with open(sig_file, 'rb') as f: + sig_data = f.read() + files.append(('gpg_signature', os.path.basename(sig_file), + sig_data)) + shutil.rmtree(os.path.dirname(sig_file)) + request = self.encode_request(d.items(), files) + return self.send_request(request) + + def upload_documentation(self, metadata, doc_dir): + """ + Upload documentation to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the documentation to be + uploaded. + :param doc_dir: The pathname of the directory which contains the + documentation. This should be the directory that + contains the ``index.html`` for the documentation. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.isdir(doc_dir): + raise DistlibException('not a directory: %r' % doc_dir) + fn = os.path.join(doc_dir, 'index.html') + if not os.path.exists(fn): + raise DistlibException('not found: %r' % fn) + metadata.validate() + name, version = metadata.name, metadata.version + zip_data = zip_dir(doc_dir).getvalue() + fields = [(':action', 'doc_upload'), + ('name', name), ('version', version)] + files = [('content', name, zip_data)] + request = self.encode_request(fields, files) + return self.send_request(request) + + def get_verify_command(self, signature_filename, data_filename, + keystore=None): + """ + Return a suitable command for verifying a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The verifying command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + cmd.extend(['--verify', signature_filename, data_filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd + + def verify_signature(self, signature_filename, data_filename, + keystore=None): + """ + Verify a signature for a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: True if the signature was verified, else False. + """ + if not self.gpg: + raise DistlibException('verification unavailable because gpg ' + 'unavailable') + cmd = self.get_verify_command(signature_filename, data_filename, + keystore) + rc, stdout, stderr = self.run_command(cmd) + if rc not in (0, 1): + raise DistlibException('verify command failed with error ' + 'code %s' % rc) + return rc == 0 + + def download_file(self, url, destfile, digest=None, reporthook=None): + """ + This is a convenience method for downloading a file from an URL. + Normally, this will be a file from the index, though currently + no check is made for this (i.e. a file can be downloaded from + anywhere). + + The method is just like the :func:`urlretrieve` function in the + standard library, except that it allows digest computation to be + done during download and checking that the downloaded data + matched any expected value. + + :param url: The URL of the file to be downloaded (assumed to be + available via an HTTP GET request). + :param destfile: The pathname where the downloaded file is to be + saved. + :param digest: If specified, this must be a (hasher, value) + tuple, where hasher is the algorithm used (e.g. + ``'md5'``) and ``value`` is the expected value. + :param reporthook: The same as for :func:`urlretrieve` in the + standard library. + """ + if digest is None: + digester = None + logger.debug('No digest specified') + else: + if isinstance(digest, (list, tuple)): + hasher, digest = digest + else: + hasher = 'md5' + digester = getattr(hashlib, hasher)() + logger.debug('Digest specified: %s' % digest) + # The following code is equivalent to urlretrieve. + # We need to do it this way so that we can compute the + # digest of the file as we go. + with open(destfile, 'wb') as dfp: + # addinfourl is not a context manager on 2.x + # so we have to use try/finally + sfp = self.send_request(Request(url)) + try: + headers = sfp.info() + blocksize = 8192 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + if reporthook: + reporthook(blocknum, blocksize, size) + while True: + block = sfp.read(blocksize) + if not block: + break + read += len(block) + dfp.write(block) + if digester: + digester.update(block) + blocknum += 1 + if reporthook: + reporthook(blocknum, blocksize, size) + finally: + sfp.close() + + # check that we got the whole file, if we can + if size >= 0 and read < size: + raise DistlibException( + 'retrieval incomplete: got only %d out of %d bytes' + % (read, size)) + # if we have a digest, it must match. + if digester: + actual = digester.hexdigest() + if digest != actual: + raise DistlibException('%s digest mismatch for %s: expected ' + '%s, got %s' % (hasher, destfile, + digest, actual)) + logger.debug('Digest verified: %s', digest) + + def send_request(self, req): + """ + Send a standard library :class:`Request` to PyPI and return its + response. + + :param req: The request to send. + :return: The HTTP response from PyPI (a standard library HTTPResponse). + """ + handlers = [] + if self.password_handler: + handlers.append(self.password_handler) + if self.ssl_verifier: + handlers.append(self.ssl_verifier) + opener = build_opener(*handlers) + return opener.open(req) + + def encode_request(self, fields, files): + """ + Encode fields and files for posting to an HTTP server. + + :param fields: The fields to send as a list of (fieldname, value) + tuples. + :param files: The files to send as a list of (fieldname, filename, + file_bytes) tuple. + """ + # Adapted from packaging, which in turn was adapted from + # http://code.activestate.com/recipes/146306 + + parts = [] + boundary = self.boundary + for k, values in fields: + if not isinstance(values, (list, tuple)): + values = [values] + + for v in values: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"' % + k).encode('utf-8'), + b'', + v.encode('utf-8'))) + for key, filename, value in files: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)).encode('utf-8'), + b'', + value)) + + parts.extend((b'--' + boundary + b'--', b'')) + + body = b'\r\n'.join(parts) + ct = b'multipart/form-data; boundary=' + boundary + headers = { + 'Content-type': ct, + 'Content-length': str(len(body)) + } + return Request(self.url, body, headers) + + def search(self, terms, operator=None): + if isinstance(terms, string_types): + terms = {'name': terms} + rpc_proxy = ServerProxy(self.url, timeout=3.0) + try: + return rpc_proxy.search(terms, operator or 'and') + finally: + rpc_proxy('close')() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py new file mode 100755 index 0000000..9131b77 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py @@ -0,0 +1,1292 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2015 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# + +import gzip +from io import BytesIO +import json +import logging +import os +import posixpath +import re +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import zlib + +from . import DistlibException +from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, + queue, quote, unescape, string_types, build_opener, + HTTPRedirectHandler as BaseRedirectHandler, text_type, + Request, HTTPError, URLError) +from .database import Distribution, DistributionPath, make_dist +from .metadata import Metadata, MetadataInvalidError +from .util import (cached_property, parse_credentials, ensure_slash, + split_filename, get_project_data, parse_requirement, + parse_name_and_version, ServerProxy, normalize_name) +from .version import get_scheme, UnsupportedVersionError +from .wheel import Wheel, is_compatible + +logger = logging.getLogger(__name__) + +HASHER_HASH = re.compile(r'^(\w+)=([a-f0-9]+)') +CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I) +HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml') +DEFAULT_INDEX = 'https://pypi.python.org/pypi' + +def get_all_distribution_names(url=None): + """ + Return all distribution names known by an index. + :param url: The URL of the index. + :return: A list of all known distribution names. + """ + if url is None: + url = DEFAULT_INDEX + client = ServerProxy(url, timeout=3.0) + try: + return client.list_packages() + finally: + client('close')() + +class RedirectHandler(BaseRedirectHandler): + """ + A class to work around a bug in some Python 3.2.x releases. + """ + # There's a bug in the base version for some 3.2.x + # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header + # returns e.g. /abc, it bails because it says the scheme '' + # is bogus, when actually it should use the request's + # URL for the scheme. See Python issue #13696. + def http_error_302(self, req, fp, code, msg, headers): + # Some servers (incorrectly) return multiple Location headers + # (so probably same goes for URI). Use first header. + newurl = None + for key in ('location', 'uri'): + if key in headers: + newurl = headers[key] + break + if newurl is None: # pragma: no cover + return + urlparts = urlparse(newurl) + if urlparts.scheme == '': + newurl = urljoin(req.get_full_url(), newurl) + if hasattr(headers, 'replace_header'): + headers.replace_header(key, newurl) + else: + headers[key] = newurl + return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, + headers) + + http_error_301 = http_error_303 = http_error_307 = http_error_302 + +class Locator(object): + """ + A base class for locators - things that locate distributions. + """ + source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz') + binary_extensions = ('.egg', '.exe', '.whl') + excluded_extensions = ('.pdf',) + + # A list of tags indicating which wheels you want to match. The default + # value of None matches against the tags compatible with the running + # Python. If you want to match other values, set wheel_tags on a locator + # instance to a list of tuples (pyver, abi, arch) which you want to match. + wheel_tags = None + + downloadable_extensions = source_extensions + ('.whl',) + + def __init__(self, scheme='default'): + """ + Initialise an instance. + :param scheme: Because locators look for most recent versions, they + need to know the version scheme to use. This specifies + the current PEP-recommended scheme - use ``'legacy'`` + if you need to support existing distributions on PyPI. + """ + self._cache = {} + self.scheme = scheme + # Because of bugs in some of the handlers on some of the platforms, + # we use our own opener rather than just using urlopen. + self.opener = build_opener(RedirectHandler()) + # If get_project() is called from locate(), the matcher instance + # is set from the requirement passed to locate(). See issue #18 for + # why this can be useful to know. + self.matcher = None + self.errors = queue.Queue() + + def get_errors(self): + """ + Return any errors which have occurred. + """ + result = [] + while not self.errors.empty(): # pragma: no cover + try: + e = self.errors.get(False) + result.append(e) + except self.errors.Empty: + continue + self.errors.task_done() + return result + + def clear_errors(self): + """ + Clear any errors which may have been logged. + """ + # Just get the errors and throw them away + self.get_errors() + + def clear_cache(self): + self._cache.clear() + + def _get_scheme(self): + return self._scheme + + def _set_scheme(self, value): + self._scheme = value + + scheme = property(_get_scheme, _set_scheme) + + def _get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This should be implemented in subclasses. + + If called from a locate() request, self.matcher will be set to a + matcher for the requirement to satisfy, otherwise it will be None. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This calls _get_project to do all the work, and just implements a caching layer on top. + """ + if self._cache is None: # pragma: no cover + result = self._get_project(name) + elif name in self._cache: + result = self._cache[name] + else: + self.clear_errors() + result = self._get_project(name) + self._cache[name] = result + return result + + def score_url(self, url): + """ + Give an url a score which can be used to choose preferred URLs + for a given project release. + """ + t = urlparse(url) + basename = posixpath.basename(t.path) + compatible = True + is_wheel = basename.endswith('.whl') + is_downloadable = basename.endswith(self.downloadable_extensions) + if is_wheel: + compatible = is_compatible(Wheel(basename), self.wheel_tags) + return (t.scheme == 'https', 'pypi.python.org' in t.netloc, + is_downloadable, is_wheel, compatible, basename) + + def prefer_url(self, url1, url2): + """ + Choose one of two URLs where both are candidates for distribution + archives for the same version of a distribution (for example, + .tar.gz vs. zip). + + The current implementation favours https:// URLs over http://, archives + from PyPI over those from other locations, wheel compatibility (if a + wheel) and then the archive name. + """ + result = url2 + if url1: + s1 = self.score_url(url1) + s2 = self.score_url(url2) + if s1 > s2: + result = url1 + if result != url2: + logger.debug('Not replacing %r with %r', url1, url2) + else: + logger.debug('Replacing %r with %r', url1, url2) + return result + + def split_filename(self, filename, project_name): + """ + Attempt to split a filename in project name, version and Python version. + """ + return split_filename(filename, project_name) + + def convert_url_to_download_info(self, url, project_name): + """ + See if a URL is a candidate for a download URL for a project (the URL + has typically been scraped from an HTML page). + + If it is, a dictionary is returned with keys "name", "version", + "filename" and "url"; otherwise, None is returned. + """ + def same_project(name1, name2): + return normalize_name(name1) == normalize_name(name2) + + result = None + scheme, netloc, path, params, query, frag = urlparse(url) + if frag.lower().startswith('egg='): # pragma: no cover + logger.debug('%s: version hint in fragment: %r', + project_name, frag) + m = HASHER_HASH.match(frag) + if m: + algo, digest = m.groups() + else: + algo, digest = None, None + origpath = path + if path and path[-1] == '/': # pragma: no cover + path = path[:-1] + if path.endswith('.whl'): + try: + wheel = Wheel(path) + if is_compatible(wheel, self.wheel_tags): + if project_name is None: + include = True + else: + include = same_project(wheel.name, project_name) + if include: + result = { + 'name': wheel.name, + 'version': wheel.version, + 'filename': wheel.filename, + 'url': urlunparse((scheme, netloc, origpath, + params, query, '')), + 'python-version': ', '.join( + ['.'.join(list(v[2:])) for v in wheel.pyver]), + } + except Exception as e: # pragma: no cover + logger.warning('invalid path for wheel: %s', path) + elif not path.endswith(self.downloadable_extensions): # pragma: no cover + logger.debug('Not downloadable: %s', path) + else: # downloadable extension + path = filename = posixpath.basename(path) + for ext in self.downloadable_extensions: + if path.endswith(ext): + path = path[:-len(ext)] + t = self.split_filename(path, project_name) + if not t: # pragma: no cover + logger.debug('No match for project/version: %s', path) + else: + name, version, pyver = t + if not project_name or same_project(project_name, name): + result = { + 'name': name, + 'version': version, + 'filename': filename, + 'url': urlunparse((scheme, netloc, origpath, + params, query, '')), + #'packagetype': 'sdist', + } + if pyver: # pragma: no cover + result['python-version'] = pyver + break + if result and algo: + result['%s_digest' % algo] = digest + return result + + def _get_digest(self, info): + """ + Get a digest from a dictionary by looking at keys of the form + 'algo_digest'. + + Returns a 2-tuple (algo, digest) if found, else None. Currently + looks only for SHA256, then MD5. + """ + result = None + for algo in ('sha256', 'md5'): + key = '%s_digest' % algo + if key in info: + result = (algo, info[key]) + break + return result + + def _update_version_data(self, result, info): + """ + Update a result dictionary (the final result from _get_project) with a + dictionary for a specific version, which typically holds information + gleaned from a filename or URL for an archive for the distribution. + """ + name = info.pop('name') + version = info.pop('version') + if version in result: + dist = result[version] + md = dist.metadata + else: + dist = make_dist(name, version, scheme=self.scheme) + md = dist.metadata + dist.digest = digest = self._get_digest(info) + url = info['url'] + result['digests'][url] = digest + if md.source_url != info['url']: + md.source_url = self.prefer_url(md.source_url, url) + result['urls'].setdefault(version, set()).add(url) + dist.locator = self + result[version] = dist + + def locate(self, requirement, prereleases=False): + """ + Find the most recent distribution which matches the given + requirement. + + :param requirement: A requirement of the form 'foo (1.0)' or perhaps + 'foo (>= 1.0, < 2.0, != 1.3)' + :param prereleases: If ``True``, allow pre-release versions + to be located. Otherwise, pre-release versions + are not returned. + :return: A :class:`Distribution` instance, or ``None`` if no such + distribution could be located. + """ + result = None + r = parse_requirement(requirement) + if r is None: # pragma: no cover + raise DistlibException('Not a valid requirement: %r' % requirement) + scheme = get_scheme(self.scheme) + self.matcher = matcher = scheme.matcher(r.requirement) + logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__) + versions = self.get_project(r.name) + if len(versions) > 2: # urls and digests keys are present + # sometimes, versions are invalid + slist = [] + vcls = matcher.version_class + for k in versions: + if k in ('urls', 'digests'): + continue + try: + if not matcher.match(k): + logger.debug('%s did not match %r', matcher, k) + else: + if prereleases or not vcls(k).is_prerelease: + slist.append(k) + else: + logger.debug('skipping pre-release ' + 'version %s of %s', k, matcher.name) + except Exception: # pragma: no cover + logger.warning('error matching %s with %r', matcher, k) + pass # slist.append(k) + if len(slist) > 1: + slist = sorted(slist, key=scheme.key) + if slist: + logger.debug('sorted list: %s', slist) + version = slist[-1] + result = versions[version] + if result: + if r.extras: + result.extras = r.extras + result.download_urls = versions.get('urls', {}).get(version, set()) + d = {} + sd = versions.get('digests', {}) + for url in result.download_urls: + if url in sd: # pragma: no cover + d[url] = sd[url] + result.digests = d + self.matcher = None + return result + + +class PyPIRPCLocator(Locator): + """ + This locator uses XML-RPC to locate distributions. It therefore + cannot be used with simple mirrors (that only mirror file content). + """ + def __init__(self, url, **kwargs): + """ + Initialise an instance. + + :param url: The URL to use for XML-RPC. + :param kwargs: Passed to the superclass constructor. + """ + super(PyPIRPCLocator, self).__init__(**kwargs) + self.base_url = url + self.client = ServerProxy(url, timeout=3.0) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + return set(self.client.list_packages()) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + versions = self.client.package_releases(name, True) + for v in versions: + urls = self.client.release_urls(name, v) + data = self.client.release_data(name, v) + metadata = Metadata(scheme=self.scheme) + metadata.name = data['name'] + metadata.version = data['version'] + metadata.license = data.get('license') + metadata.keywords = data.get('keywords', []) + metadata.summary = data.get('summary') + dist = Distribution(metadata) + if urls: + info = urls[0] + metadata.source_url = info['url'] + dist.digest = self._get_digest(info) + dist.locator = self + result[v] = dist + for info in urls: + url = info['url'] + digest = self._get_digest(info) + result['urls'].setdefault(v, set()).add(url) + result['digests'][url] = digest + return result + +class PyPIJSONLocator(Locator): + """ + This locator uses PyPI's JSON interface. It's very limited in functionality + and probably not worth using. + """ + def __init__(self, url, **kwargs): + super(PyPIJSONLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + url = urljoin(self.base_url, '%s/json' % quote(name)) + try: + resp = self.opener.open(url) + data = resp.read().decode() # for now + d = json.loads(data) + md = Metadata(scheme=self.scheme) + data = d['info'] + md.name = data['name'] + md.version = data['version'] + md.license = data.get('license') + md.keywords = data.get('keywords', []) + md.summary = data.get('summary') + dist = Distribution(md) + dist.locator = self + urls = d['urls'] + result[md.version] = dist + for info in d['urls']: + url = info['url'] + dist.download_urls.add(url) + dist.digests[url] = self._get_digest(info) + result['urls'].setdefault(md.version, set()).add(url) + result['digests'][url] = self._get_digest(info) + # Now get other releases + for version, infos in d['releases'].items(): + if version == md.version: + continue # already done + omd = Metadata(scheme=self.scheme) + omd.name = md.name + omd.version = version + odist = Distribution(omd) + odist.locator = self + result[version] = odist + for info in infos: + url = info['url'] + odist.download_urls.add(url) + odist.digests[url] = self._get_digest(info) + result['urls'].setdefault(version, set()).add(url) + result['digests'][url] = self._get_digest(info) +# for info in urls: +# md.source_url = info['url'] +# dist.digest = self._get_digest(info) +# dist.locator = self +# for info in urls: +# url = info['url'] +# result['urls'].setdefault(md.version, set()).add(url) +# result['digests'][url] = self._get_digest(info) + except Exception as e: + self.errors.put(text_type(e)) + logger.exception('JSON fetch failed: %s', e) + return result + + +class Page(object): + """ + This class represents a scraped HTML page. + """ + # The following slightly hairy-looking regex just looks for the contents of + # an anchor link, which has an attribute "href" either immediately preceded + # or immediately followed by a "rel" attribute. The attribute values can be + # declared with double quotes, single quotes or no quotes - which leads to + # the length of the expression. + _href = re.compile(""" +(rel\\s*=\\s*(?:"(?P<rel1>[^"]*)"|'(?P<rel2>[^']*)'|(?P<rel3>[^>\\s\n]*))\\s+)? +href\\s*=\\s*(?:"(?P<url1>[^"]*)"|'(?P<url2>[^']*)'|(?P<url3>[^>\\s\n]*)) +(\\s+rel\\s*=\\s*(?:"(?P<rel4>[^"]*)"|'(?P<rel5>[^']*)'|(?P<rel6>[^>\\s\n]*)))? +""", re.I | re.S | re.X) + _base = re.compile(r"""<base\s+href\s*=\s*['"]?([^'">]+)""", re.I | re.S) + + def __init__(self, data, url): + """ + Initialise an instance with the Unicode page contents and the URL they + came from. + """ + self.data = data + self.base_url = self.url = url + m = self._base.search(self.data) + if m: + self.base_url = m.group(1) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + @cached_property + def links(self): + """ + Return the URLs of all the links on a page together with information + about their "rel" attribute, for determining which ones to treat as + downloads and which ones to queue for further scraping. + """ + def clean(url): + "Tidy up an URL." + scheme, netloc, path, params, query, frag = urlparse(url) + return urlunparse((scheme, netloc, quote(path), + params, query, frag)) + + result = set() + for match in self._href.finditer(self.data): + d = match.groupdict('') + rel = (d['rel1'] or d['rel2'] or d['rel3'] or + d['rel4'] or d['rel5'] or d['rel6']) + url = d['url1'] or d['url2'] or d['url3'] + url = urljoin(self.base_url, url) + url = unescape(url) + url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url) + result.add((url, rel)) + # We sort the result, hoping to bring the most recent versions + # to the front + result = sorted(result, key=lambda t: t[0], reverse=True) + return result + + +class SimpleScrapingLocator(Locator): + """ + A locator which scrapes HTML pages to locate downloads for a distribution. + This runs multiple threads to do the I/O; performance is at least as good + as pip's PackageFinder, which works in an analogous fashion. + """ + + # These are used to deal with various Content-Encoding schemes. + decoders = { + 'deflate': zlib.decompress, + 'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(d)).read(), + 'none': lambda b: b, + } + + def __init__(self, url, timeout=None, num_workers=10, **kwargs): + """ + Initialise an instance. + :param url: The root URL to use for scraping. + :param timeout: The timeout, in seconds, to be applied to requests. + This defaults to ``None`` (no timeout specified). + :param num_workers: The number of worker threads you want to do I/O, + This defaults to 10. + :param kwargs: Passed to the superclass. + """ + super(SimpleScrapingLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + self.timeout = timeout + self._page_cache = {} + self._seen = set() + self._to_fetch = queue.Queue() + self._bad_hosts = set() + self.skip_externals = False + self.num_workers = num_workers + self._lock = threading.RLock() + # See issue #45: we need to be resilient when the locator is used + # in a thread, e.g. with concurrent.futures. We can't use self._lock + # as it is for coordinating our internal threads - the ones created + # in _prepare_threads. + self._gplock = threading.RLock() + + def _prepare_threads(self): + """ + Threads are created only when get_project is called, and terminate + before it returns. They are there primarily to parallelise I/O (i.e. + fetching web pages). + """ + self._threads = [] + for i in range(self.num_workers): + t = threading.Thread(target=self._fetch) + t.setDaemon(True) + t.start() + self._threads.append(t) + + def _wait_threads(self): + """ + Tell all the threads to terminate (by sending a sentinel value) and + wait for them to do so. + """ + # Note that you need two loops, since you can't say which + # thread will get each sentinel + for t in self._threads: + self._to_fetch.put(None) # sentinel + for t in self._threads: + t.join() + self._threads = [] + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + with self._gplock: + self.result = result + self.project_name = name + url = urljoin(self.base_url, '%s/' % quote(name)) + self._seen.clear() + self._page_cache.clear() + self._prepare_threads() + try: + logger.debug('Queueing %s', url) + self._to_fetch.put(url) + self._to_fetch.join() + finally: + self._wait_threads() + del self.result + return result + + platform_dependent = re.compile(r'\b(linux-(i\d86|x86_64|arm\w+)|' + r'win(32|-amd64)|macosx-?\d+)\b', re.I) + + def _is_platform_dependent(self, url): + """ + Does an URL refer to a platform-specific download? + """ + return self.platform_dependent.search(url) + + def _process_download(self, url): + """ + See if an URL is a suitable download for a project. + + If it is, register information in the result dictionary (for + _get_project) about the specific version it's for. + + Note that the return value isn't actually used other than as a boolean + value. + """ + if self._is_platform_dependent(url): + info = None + else: + info = self.convert_url_to_download_info(url, self.project_name) + logger.debug('process_download: %s -> %s', url, info) + if info: + with self._lock: # needed because self.result is shared + self._update_version_data(self.result, info) + return info + + def _should_queue(self, link, referrer, rel): + """ + Determine whether a link URL from a referring page and with a + particular "rel" attribute should be queued for scraping. + """ + scheme, netloc, path, _, _, _ = urlparse(link) + if path.endswith(self.source_extensions + self.binary_extensions + + self.excluded_extensions): + result = False + elif self.skip_externals and not link.startswith(self.base_url): + result = False + elif not referrer.startswith(self.base_url): + result = False + elif rel not in ('homepage', 'download'): + result = False + elif scheme not in ('http', 'https', 'ftp'): + result = False + elif self._is_platform_dependent(link): + result = False + else: + host = netloc.split(':', 1)[0] + if host.lower() == 'localhost': + result = False + else: + result = True + logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, + referrer, result) + return result + + def _fetch(self): + """ + Get a URL to fetch from the work queue, get the HTML page, examine its + links for download candidates and candidates for further scraping. + + This is a handy method to run in a thread. + """ + while True: + url = self._to_fetch.get() + try: + if url: + page = self.get_page(url) + if page is None: # e.g. after an error + continue + for link, rel in page.links: + if link not in self._seen: + try: + self._seen.add(link) + if (not self._process_download(link) and + self._should_queue(link, url, rel)): + logger.debug('Queueing %s from %s', link, url) + self._to_fetch.put(link) + except MetadataInvalidError: # e.g. invalid versions + pass + except Exception as e: # pragma: no cover + self.errors.put(text_type(e)) + finally: + # always do this, to avoid hangs :-) + self._to_fetch.task_done() + if not url: + #logger.debug('Sentinel seen, quitting.') + break + + def get_page(self, url): + """ + Get the HTML for an URL, possibly from an in-memory cache. + + XXX TODO Note: this cache is never actually cleared. It's assumed that + the data won't get stale over the lifetime of a locator instance (not + necessarily true for the default_locator). + """ + # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api + scheme, netloc, path, _, _, _ = urlparse(url) + if scheme == 'file' and os.path.isdir(url2pathname(path)): + url = urljoin(ensure_slash(url), 'index.html') + + if url in self._page_cache: + result = self._page_cache[url] + logger.debug('Returning %s from cache: %s', url, result) + else: + host = netloc.split(':', 1)[0] + result = None + if host in self._bad_hosts: + logger.debug('Skipping %s due to bad host %s', url, host) + else: + req = Request(url, headers={'Accept-encoding': 'identity'}) + try: + logger.debug('Fetching %s', url) + resp = self.opener.open(req, timeout=self.timeout) + logger.debug('Fetched %s', url) + headers = resp.info() + content_type = headers.get('Content-Type', '') + if HTML_CONTENT_TYPE.match(content_type): + final_url = resp.geturl() + data = resp.read() + encoding = headers.get('Content-Encoding') + if encoding: + decoder = self.decoders[encoding] # fail if not found + data = decoder(data) + encoding = 'utf-8' + m = CHARSET.search(content_type) + if m: + encoding = m.group(1) + try: + data = data.decode(encoding) + except UnicodeError: # pragma: no cover + data = data.decode('latin-1') # fallback + result = Page(data, final_url) + self._page_cache[final_url] = result + except HTTPError as e: + if e.code != 404: + logger.exception('Fetch failed: %s: %s', url, e) + except URLError as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + with self._lock: + self._bad_hosts.add(host) + except Exception as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + finally: + self._page_cache[url] = result # even if None (failure) + return result + + _distname_re = re.compile('<a href=[^>]*>([^<]+)<') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + page = self.get_page(self.base_url) + if not page: + raise DistlibException('Unable to get %s' % self.base_url) + for match in self._distname_re.finditer(page.data): + result.add(match.group(1)) + return result + +class DirectoryLocator(Locator): + """ + This class locates distributions in a directory tree. + """ + + def __init__(self, path, **kwargs): + """ + Initialise an instance. + :param path: The root of the directory tree to search. + :param kwargs: Passed to the superclass constructor, + except for: + * recursive - if True (the default), subdirectories are + recursed into. If False, only the top-level directory + is searched, + """ + self.recursive = kwargs.pop('recursive', True) + super(DirectoryLocator, self).__init__(**kwargs) + path = os.path.abspath(path) + if not os.path.isdir(path): # pragma: no cover + raise DistlibException('Not a directory: %r' % path) + self.base_dir = path + + def should_include(self, filename, parent): + """ + Should a filename be considered as a candidate for a distribution + archive? As well as the filename, the directory which contains it + is provided, though not used by the current implementation. + """ + return filename.endswith(self.downloadable_extensions) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', + pathname2url(os.path.abspath(fn)), + '', '', '')) + info = self.convert_url_to_download_info(url, name) + if info: + self._update_version_data(result, info) + if not self.recursive: + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', + pathname2url(os.path.abspath(fn)), + '', '', '')) + info = self.convert_url_to_download_info(url, None) + if info: + result.add(info['name']) + if not self.recursive: + break + return result + +class JSONLocator(Locator): + """ + This locator uses special extended metadata (not available on PyPI) and is + the basis of performant dependency resolution in distlib. Other locators + require archive downloads before dependencies can be determined! As you + might imagine, that can be slow. + """ + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + data = get_project_data(name) + if data: + for info in data.get('files', []): + if info['ptype'] != 'sdist' or info['pyversion'] != 'source': + continue + # We don't store summary in project metadata as it makes + # the data bigger for no benefit during dependency + # resolution + dist = make_dist(data['name'], info['version'], + summary=data.get('summary', + 'Placeholder for summary'), + scheme=self.scheme) + md = dist.metadata + md.source_url = info['url'] + # TODO SHA256 digest + if 'digest' in info and info['digest']: + dist.digest = ('md5', info['digest']) + md.dependencies = info.get('requirements', {}) + dist.exports = info.get('exports', {}) + result[dist.version] = dist + result['urls'].setdefault(dist.version, set()).add(info['url']) + return result + +class DistPathLocator(Locator): + """ + This locator finds installed distributions in a path. It can be useful for + adding to an :class:`AggregatingLocator`. + """ + def __init__(self, distpath, **kwargs): + """ + Initialise an instance. + + :param distpath: A :class:`DistributionPath` instance to search. + """ + super(DistPathLocator, self).__init__(**kwargs) + assert isinstance(distpath, DistributionPath) + self.distpath = distpath + + def _get_project(self, name): + dist = self.distpath.get_distribution(name) + if dist is None: + result = {'urls': {}, 'digests': {}} + else: + result = { + dist.version: dist, + 'urls': {dist.version: set([dist.source_url])}, + 'digests': {dist.version: set([None])} + } + return result + + +class AggregatingLocator(Locator): + """ + This class allows you to chain and/or merge a list of locators. + """ + def __init__(self, *locators, **kwargs): + """ + Initialise an instance. + + :param locators: The list of locators to search. + :param kwargs: Passed to the superclass constructor, + except for: + * merge - if False (the default), the first successful + search from any of the locators is returned. If True, + the results from all locators are merged (this can be + slow). + """ + self.merge = kwargs.pop('merge', False) + self.locators = locators + super(AggregatingLocator, self).__init__(**kwargs) + + def clear_cache(self): + super(AggregatingLocator, self).clear_cache() + for locator in self.locators: + locator.clear_cache() + + def _set_scheme(self, value): + self._scheme = value + for locator in self.locators: + locator.scheme = value + + scheme = property(Locator.scheme.fget, _set_scheme) + + def _get_project(self, name): + result = {} + for locator in self.locators: + d = locator.get_project(name) + if d: + if self.merge: + files = result.get('urls', {}) + digests = result.get('digests', {}) + # next line could overwrite result['urls'], result['digests'] + result.update(d) + df = result.get('urls') + if files and df: + for k, v in files.items(): + if k in df: + df[k] |= v + else: + df[k] = v + dd = result.get('digests') + if digests and dd: + dd.update(digests) + else: + # See issue #18. If any dists are found and we're looking + # for specific constraints, we only return something if + # a match is found. For example, if a DirectoryLocator + # returns just foo (1.0) while we're looking for + # foo (>= 2.0), we'll pretend there was nothing there so + # that subsequent locators can be queried. Otherwise we + # would just return foo (1.0) which would then lead to a + # failure to find foo (>= 2.0), because other locators + # weren't searched. Note that this only matters when + # merge=False. + if self.matcher is None: + found = True + else: + found = False + for k in d: + if self.matcher.match(k): + found = True + break + if found: + result = d + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for locator in self.locators: + try: + result |= locator.get_distribution_names() + except NotImplementedError: + pass + return result + + +# We use a legacy scheme simply because most of the dists on PyPI use legacy +# versions which don't conform to PEP 426 / PEP 440. +default_locator = AggregatingLocator( + JSONLocator(), + SimpleScrapingLocator('https://pypi.python.org/simple/', + timeout=3.0), + scheme='legacy') + +locate = default_locator.locate + +NAME_VERSION_RE = re.compile(r'(?P<name>[\w-]+)\s*' + r'\(\s*(==\s*)?(?P<ver>[^)]+)\)$') + +class DependencyFinder(object): + """ + Locate dependencies for distributions. + """ + + def __init__(self, locator=None): + """ + Initialise an instance, using the specified locator + to locate distributions. + """ + self.locator = locator or default_locator + self.scheme = get_scheme(self.locator.scheme) + + def add_distribution(self, dist): + """ + Add a distribution to the finder. This will update internal information + about who provides what. + :param dist: The distribution to add. + """ + logger.debug('adding distribution %s', dist) + name = dist.key + self.dists_by_name[name] = dist + self.dists[(name, dist.version)] = dist + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + self.provided.setdefault(name, set()).add((version, dist)) + + def remove_distribution(self, dist): + """ + Remove a distribution from the finder. This will update internal + information about who provides what. + :param dist: The distribution to remove. + """ + logger.debug('removing distribution %s', dist) + name = dist.key + del self.dists_by_name[name] + del self.dists[(name, dist.version)] + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Remove from provided: %s, %s, %s', name, version, dist) + s = self.provided[name] + s.remove((version, dist)) + if not s: + del self.provided[name] + + def get_matcher(self, reqt): + """ + Get a version matcher for a requirement. + :param reqt: The requirement + :type reqt: str + :return: A version matcher (an instance of + :class:`distlib.version.Matcher`). + """ + try: + matcher = self.scheme.matcher(reqt) + except UnsupportedVersionError: # pragma: no cover + # XXX compat-mode if cannot read the version + name = reqt.split()[0] + matcher = self.scheme.matcher(name) + return matcher + + def find_providers(self, reqt): + """ + Find the distributions which can fulfill a requirement. + + :param reqt: The requirement. + :type reqt: str + :return: A set of distribution which can fulfill the requirement. + """ + matcher = self.get_matcher(reqt) + name = matcher.key # case-insensitive + result = set() + provided = self.provided + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + result.add(provider) + break + return result + + def try_to_replace(self, provider, other, problems): + """ + Attempt to replace one provider with another. This is typically used + when resolving dependencies from multiple sources, e.g. A requires + (B >= 1.0) while C requires (B >= 1.1). + + For successful replacement, ``provider`` must meet all the requirements + which ``other`` fulfills. + + :param provider: The provider we are trying to replace with. + :param other: The provider we're trying to replace. + :param problems: If False is returned, this will contain what + problems prevented replacement. This is currently + a tuple of the literal string 'cantreplace', + ``provider``, ``other`` and the set of requirements + that ``provider`` couldn't fulfill. + :return: True if we can replace ``other`` with ``provider``, else + False. + """ + rlist = self.reqts[other] + unmatched = set() + for s in rlist: + matcher = self.get_matcher(s) + if not matcher.match(provider.version): + unmatched.add(s) + if unmatched: + # can't replace other with provider + problems.add(('cantreplace', provider, other, + frozenset(unmatched))) + result = False + else: + # can replace other with provider + self.remove_distribution(other) + del self.reqts[other] + for s in rlist: + self.reqts.setdefault(provider, set()).add(s) + self.add_distribution(provider) + result = True + return result + + def find(self, requirement, meta_extras=None, prereleases=False): + """ + Find a distribution and all distributions it depends on. + + :param requirement: The requirement specifying the distribution to + find, or a Distribution instance. + :param meta_extras: A list of meta extras such as :test:, :build: and + so on. + :param prereleases: If ``True``, allow pre-release versions to be + returned - otherwise, don't return prereleases + unless they're all that's available. + + Return a set of :class:`Distribution` instances and a set of + problems. + + The distributions returned should be such that they have the + :attr:`required` attribute set to ``True`` if they were + from the ``requirement`` passed to ``find()``, and they have the + :attr:`build_time_dependency` attribute set to ``True`` unless they + are post-installation dependencies of the ``requirement``. + + The problems should be a tuple consisting of the string + ``'unsatisfied'`` and the requirement which couldn't be satisfied + by any distribution known to the locator. + """ + + self.provided = {} + self.dists = {} + self.dists_by_name = {} + self.reqts = {} + + meta_extras = set(meta_extras or []) + if ':*:' in meta_extras: + meta_extras.remove(':*:') + # :meta: and :run: are implicitly included + meta_extras |= set([':test:', ':build:', ':dev:']) + + if isinstance(requirement, Distribution): + dist = odist = requirement + logger.debug('passed %s as requirement', odist) + else: + dist = odist = self.locator.locate(requirement, + prereleases=prereleases) + if dist is None: + raise DistlibException('Unable to locate %r' % requirement) + logger.debug('located %s', odist) + dist.requested = True + problems = set() + todo = set([dist]) + install_dists = set([odist]) + while todo: + dist = todo.pop() + name = dist.key # case-insensitive + if name not in self.dists_by_name: + self.add_distribution(dist) + else: + #import pdb; pdb.set_trace() + other = self.dists_by_name[name] + if other != dist: + self.try_to_replace(dist, other, problems) + + ireqts = dist.run_requires | dist.meta_requires + sreqts = dist.build_requires + ereqts = set() + if meta_extras and dist in install_dists: + for key in ('test', 'build', 'dev'): + e = ':%s:' % key + if e in meta_extras: + ereqts |= getattr(dist, '%s_requires' % key) + all_reqts = ireqts | sreqts | ereqts + for r in all_reqts: + providers = self.find_providers(r) + if not providers: + logger.debug('No providers found for %r', r) + provider = self.locator.locate(r, prereleases=prereleases) + # If no provider is found and we didn't consider + # prereleases, consider them now. + if provider is None and not prereleases: + provider = self.locator.locate(r, prereleases=True) + if provider is None: + logger.debug('Cannot satisfy %r', r) + problems.add(('unsatisfied', r)) + else: + n, v = provider.key, provider.version + if (n, v) not in self.dists: + todo.add(provider) + providers.add(provider) + if r in ireqts and dist in install_dists: + install_dists.add(provider) + logger.debug('Adding %s to install_dists', + provider.name_and_version) + for p in providers: + name = p.key + if name not in self.dists_by_name: + self.reqts.setdefault(p, set()).add(r) + else: + other = self.dists_by_name[name] + if other != p: + # see if other can be replaced by p + self.try_to_replace(p, other, problems) + + dists = set(self.dists.values()) + for dist in dists: + dist.build_time_dependency = dist not in install_dists + if dist.build_time_dependency: + logger.debug('%s is a build-time dependency only.', + dist.name_and_version) + logger.debug('find done for %s', odist) + return dists, problems diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py new file mode 100755 index 0000000..92688d0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py @@ -0,0 +1,393 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Class representing the list of files in a distribution. + +Equivalent to distutils.filelist, but fixes some problems. +""" +import fnmatch +import logging +import os +import re +import sys + +from . import DistlibException +from .compat import fsdecode +from .util import convert_path + + +__all__ = ['Manifest'] + +logger = logging.getLogger(__name__) + +# a \ followed by some spaces + EOL +_COLLAPSE_PATTERN = re.compile('\\\\w*\n', re.M) +_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) + +# +# Due to the different results returned by fnmatch.translate, we need +# to do slightly different processing for Python 2.7 and 3.2 ... this needed +# to be brought in for Python 3.6 onwards. +# +_PYTHON_VERSION = sys.version_info[:2] + +class Manifest(object): + """A list of files built by on exploring the filesystem and filtered by + applying various patterns to what we find there. + """ + + def __init__(self, base=None): + """ + Initialise an instance. + + :param base: The base directory to explore under. + """ + self.base = os.path.abspath(os.path.normpath(base or os.getcwd())) + self.prefix = self.base + os.sep + self.allfiles = None + self.files = set() + + # + # Public API + # + + def findall(self): + """Find all files under the base and set ``allfiles`` to the absolute + pathnames of files found. + """ + from stat import S_ISREG, S_ISDIR, S_ISLNK + + self.allfiles = allfiles = [] + root = self.base + stack = [root] + pop = stack.pop + push = stack.append + + while stack: + root = pop() + names = os.listdir(root) + + for name in names: + fullname = os.path.join(root, name) + + # Avoid excess stat calls -- just one will do, thank you! + stat = os.stat(fullname) + mode = stat.st_mode + if S_ISREG(mode): + allfiles.append(fsdecode(fullname)) + elif S_ISDIR(mode) and not S_ISLNK(mode): + push(fullname) + + def add(self, item): + """ + Add a file to the manifest. + + :param item: The pathname to add. This can be relative to the base. + """ + if not item.startswith(self.prefix): + item = os.path.join(self.base, item) + self.files.add(os.path.normpath(item)) + + def add_many(self, items): + """ + Add a list of files to the manifest. + + :param items: The pathnames to add. These can be relative to the base. + """ + for item in items: + self.add(item) + + def sorted(self, wantdirs=False): + """ + Return sorted files in directory order + """ + + def add_dir(dirs, d): + dirs.add(d) + logger.debug('add_dir added %s', d) + if d != self.base: + parent, _ = os.path.split(d) + assert parent not in ('', '/') + add_dir(dirs, parent) + + result = set(self.files) # make a copy! + if wantdirs: + dirs = set() + for f in result: + add_dir(dirs, os.path.dirname(f)) + result |= dirs + return [os.path.join(*path_tuple) for path_tuple in + sorted(os.path.split(path) for path in result)] + + def clear(self): + """Clear all collected files.""" + self.files = set() + self.allfiles = [] + + def process_directive(self, directive): + """ + Process a directive which either adds some files from ``allfiles`` to + ``files``, or removes some files from ``files``. + + :param directive: The directive to process. This should be in a format + compatible with distutils ``MANIFEST.in`` files: + + http://docs.python.org/distutils/sourcedist.html#commands + """ + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dirpattern). + action, patterns, thedir, dirpattern = self._parse_directive(directive) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=True): + logger.warning('no files found matching %r', pattern) + + elif action == 'exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, anchor=True) + #if not found: + # logger.warning('no previously-included files ' + # 'found matching %r', pattern) + + elif action == 'global-include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=False): + logger.warning('no files found matching %r ' + 'anywhere in distribution', pattern) + + elif action == 'global-exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, anchor=False) + #if not found: + # logger.warning('no previously-included files ' + # 'matching %r found anywhere in ' + # 'distribution', pattern) + + elif action == 'recursive-include': + for pattern in patterns: + if not self._include_pattern(pattern, prefix=thedir): + logger.warning('no files found matching %r ' + 'under directory %r', pattern, thedir) + + elif action == 'recursive-exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, prefix=thedir) + #if not found: + # logger.warning('no previously-included files ' + # 'matching %r found under directory %r', + # pattern, thedir) + + elif action == 'graft': + if not self._include_pattern(None, prefix=dirpattern): + logger.warning('no directories found matching %r', + dirpattern) + + elif action == 'prune': + if not self._exclude_pattern(None, prefix=dirpattern): + logger.warning('no previously-included directories found ' + 'matching %r', dirpattern) + else: # pragma: no cover + # This should never happen, as it should be caught in + # _parse_template_line + raise DistlibException( + 'invalid action %r' % action) + + # + # Private API + # + + def _parse_directive(self, directive): + """ + Validate a directive. + :param directive: The directive to validate. + :return: A tuple of action, patterns, thedir, dir_patterns + """ + words = directive.split() + if len(words) == 1 and words[0] not in ('include', 'exclude', + 'global-include', + 'global-exclude', + 'recursive-include', + 'recursive-exclude', + 'graft', 'prune'): + # no action given, let's use the default 'include' + words.insert(0, 'include') + + action = words[0] + patterns = thedir = dir_pattern = None + + if action in ('include', 'exclude', + 'global-include', 'global-exclude'): + if len(words) < 2: + raise DistlibException( + '%r expects <pattern1> <pattern2> ...' % action) + + patterns = [convert_path(word) for word in words[1:]] + + elif action in ('recursive-include', 'recursive-exclude'): + if len(words) < 3: + raise DistlibException( + '%r expects <dir> <pattern1> <pattern2> ...' % action) + + thedir = convert_path(words[1]) + patterns = [convert_path(word) for word in words[2:]] + + elif action in ('graft', 'prune'): + if len(words) != 2: + raise DistlibException( + '%r expects a single <dir_pattern>' % action) + + dir_pattern = convert_path(words[1]) + + else: + raise DistlibException('unknown action %r' % action) + + return action, patterns, thedir, dir_pattern + + def _include_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Select strings (presumably filenames) from 'self.files' that + match 'pattern', a Unix-style wildcard (glob) pattern. + + Patterns are not quite the same as implemented by the 'fnmatch' + module: '*' and '?' match non-special characters, where "special" + is platform-dependent: slash on Unix; colon, slash, and backslash on + DOS/Windows; and colon on Mac OS. + + If 'anchor' is true (the default), then the pattern match is more + stringent: "*.py" will match "foo.py" but not "foo/bar.py". If + 'anchor' is false, both of these will match. + + If 'prefix' is supplied, then only filenames starting with 'prefix' + (itself a pattern) and ending with 'pattern', with anything in between + them, will match. 'anchor' is ignored in this case. + + If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and + 'pattern' is assumed to be either a string containing a regex or a + regex object -- no translation is done, the regex is just compiled + and used as-is. + + Selected strings will be added to self.files. + + Return True if files are found. + """ + # XXX docstring lying about what the special chars are? + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + + # delayed loading of allfiles list + if self.allfiles is None: + self.findall() + + for name in self.allfiles: + if pattern_re.search(name): + self.files.add(name) + found = True + return found + + def _exclude_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Remove strings (presumably filenames) from 'files' that match + 'pattern'. + + Other parameters are the same as for 'include_pattern()', above. + The list 'self.files' is modified in place. Return True if files are + found. + + This API is public to allow e.g. exclusion of SCM subdirs, e.g. when + packaging source distributions + """ + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + for f in list(self.files): + if pattern_re.search(f): + self.files.remove(f) + found = True + return found + + def _translate_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Translate a shell-like wildcard pattern to a compiled regular + expression. + + Return the compiled regex. If 'is_regex' true, + then 'pattern' is directly compiled to a regex (if it's a string) + or just returned as-is (assumes it's a regex object). + """ + if is_regex: + if isinstance(pattern, str): + return re.compile(pattern) + else: + return pattern + + if _PYTHON_VERSION > (3, 2): + # ditch start and end characters + start, _, end = self._glob_to_re('_').partition('_') + + if pattern: + pattern_re = self._glob_to_re(pattern) + if _PYTHON_VERSION > (3, 2): + assert pattern_re.startswith(start) and pattern_re.endswith(end) + else: + pattern_re = '' + + base = re.escape(os.path.join(self.base, '')) + if prefix is not None: + # ditch end of pattern character + if _PYTHON_VERSION <= (3, 2): + empty_pattern = self._glob_to_re('') + prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)] + else: + prefix_re = self._glob_to_re(prefix) + assert prefix_re.startswith(start) and prefix_re.endswith(end) + prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] + sep = os.sep + if os.sep == '\\': + sep = r'\\' + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + sep.join((prefix_re, + '.*' + pattern_re)) + else: + pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] + pattern_re = r'%s%s%s%s.*%s%s' % (start, base, prefix_re, sep, + pattern_re, end) + else: # no prefix -- respect anchor flag + if anchor: + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + pattern_re + else: + pattern_re = r'%s%s%s' % (start, base, pattern_re[len(start):]) + + return re.compile(pattern_re) + + def _glob_to_re(self, pattern): + """Translate a shell-like glob pattern to a regular expression. + + Return a string containing the regex. Differs from + 'fnmatch.translate()' in that '*' does not match "special characters" + (which are platform-specific). + """ + pattern_re = fnmatch.translate(pattern) + + # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which + # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, + # and by extension they shouldn't match such "special characters" under + # any OS. So change all non-escaped dots in the RE to match any + # character except the special characters (currently: just os.sep). + sep = os.sep + if os.sep == '\\': + # we're using a regex to manipulate a regex, so we need + # to escape the backslash twice + sep = r'\\\\' + escaped = r'\1[^%s]' % sep + pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', escaped, pattern_re) + return pattern_re diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py new file mode 100755 index 0000000..82fcfb8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Parser for the environment markers micro-language defined in PEP 508. +""" + +# Note: In PEP 345, the micro-language was Python compatible, so the ast +# module could be used to parse it. However, PEP 508 introduced operators such +# as ~= and === which aren't in Python, necessitating a different approach. + +import os +import sys +import platform +import re + +from .compat import python_implementation, urlparse, string_types +from .util import in_venv, parse_marker + +__all__ = ['interpret'] + +def _is_literal(o): + if not isinstance(o, string_types) or not o: + return False + return o[0] in '\'"' + +class Evaluator(object): + """ + This class is used to evaluate marker expessions. + """ + + operations = { + '==': lambda x, y: x == y, + '===': lambda x, y: x == y, + '~=': lambda x, y: x == y or x > y, + '!=': lambda x, y: x != y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x == y or x < y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x == y or x > y, + 'and': lambda x, y: x and y, + 'or': lambda x, y: x or y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y, + } + + def evaluate(self, expr, context): + """ + Evaluate a marker expression returned by the :func:`parse_requirement` + function in the specified context. + """ + if isinstance(expr, string_types): + if expr[0] in '\'"': + result = expr[1:-1] + else: + if expr not in context: + raise SyntaxError('unknown variable: %s' % expr) + result = context[expr] + else: + assert isinstance(expr, dict) + op = expr['op'] + if op not in self.operations: + raise NotImplementedError('op not implemented: %s' % op) + elhs = expr['lhs'] + erhs = expr['rhs'] + if _is_literal(expr['lhs']) and _is_literal(expr['rhs']): + raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs)) + + lhs = self.evaluate(elhs, context) + rhs = self.evaluate(erhs, context) + result = self.operations[op](lhs, rhs) + return result + +def default_context(): + def format_full_version(info): + version = '%s.%s.%s' % (info.major, info.minor, info.micro) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + if hasattr(sys, 'implementation'): + implementation_version = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + implementation_version = '0' + implementation_name = '' + + result = { + 'implementation_name': implementation_name, + 'implementation_version': implementation_version, + 'os_name': os.name, + 'platform_machine': platform.machine(), + 'platform_python_implementation': platform.python_implementation(), + 'platform_release': platform.release(), + 'platform_system': platform.system(), + 'platform_version': platform.version(), + 'platform_in_venv': str(in_venv()), + 'python_full_version': platform.python_version(), + 'python_version': platform.python_version()[:3], + 'sys_platform': sys.platform, + } + return result + +DEFAULT_CONTEXT = default_context() +del default_context + +evaluator = Evaluator() + +def interpret(marker, execution_context=None): + """ + Interpret a marker and return a result depending on environment. + + :param marker: The marker to interpret. + :type marker: str + :param execution_context: The context used for name lookup. + :type execution_context: mapping + """ + try: + expr, rest = parse_marker(marker) + except Exception as e: + raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e)) + if rest and rest[0] != '#': + raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest)) + context = dict(DEFAULT_CONTEXT) + if execution_context: + context.update(execution_context) + return evaluator.evaluate(expr, context) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py new file mode 100755 index 0000000..10a1fee --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py @@ -0,0 +1,1091 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Implementation of the Metadata for Python packages PEPs. + +Supports all metadata formats (1.0, 1.1, 1.2, and 2.0 experimental). +""" +from __future__ import unicode_literals + +import codecs +from email import message_from_file +import json +import logging +import re + + +from . import DistlibException, __version__ +from .compat import StringIO, string_types, text_type +from .markers import interpret +from .util import extract_by_key, get_extras +from .version import get_scheme, PEP440_VERSION_RE + +logger = logging.getLogger(__name__) + + +class MetadataMissingError(DistlibException): + """A required metadata is missing""" + + +class MetadataConflictError(DistlibException): + """Attempt to read or write metadata fields that are conflictual.""" + + +class MetadataUnrecognizedVersionError(DistlibException): + """Unknown metadata version number.""" + + +class MetadataInvalidError(DistlibException): + """A metadata value is invalid""" + +# public API of this module +__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] + +# Encoding used for the PKG-INFO files +PKG_INFO_ENCODING = 'utf-8' + +# preferred version. Hopefully will be changed +# to 1.2 once PEP 345 is supported everywhere +PKG_INFO_PREFERRED_VERSION = '1.1' + +_LINE_PREFIX_1_2 = re.compile('\n \\|') +_LINE_PREFIX_PRE_1_2 = re.compile('\n ') +_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License') + +_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License', 'Classifier', 'Download-URL', 'Obsoletes', + 'Provides', 'Requires') + +_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', + 'Download-URL') + +_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', + 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External') + +_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', + 'Obsoletes-Dist', 'Requires-External', 'Maintainer', + 'Maintainer-email', 'Project-URL') + +_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', + 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External', 'Private-Version', + 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension', + 'Provides-Extra') + +_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', + 'Setup-Requires-Dist', 'Extension') + +_566_FIELDS = _426_FIELDS + ('Description-Content-Type',) + +_566_MARKERS = ('Description-Content-Type',) + +_ALL_FIELDS = set() +_ALL_FIELDS.update(_241_FIELDS) +_ALL_FIELDS.update(_314_FIELDS) +_ALL_FIELDS.update(_345_FIELDS) +_ALL_FIELDS.update(_426_FIELDS) +_ALL_FIELDS.update(_566_FIELDS) + +EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') + + +def _version2fieldlist(version): + if version == '1.0': + return _241_FIELDS + elif version == '1.1': + return _314_FIELDS + elif version == '1.2': + return _345_FIELDS + elif version in ('1.3', '2.1'): + return _345_FIELDS + _566_FIELDS + elif version == '2.0': + return _426_FIELDS + raise MetadataUnrecognizedVersionError(version) + + +def _best_version(fields): + """Detect the best version depending on the fields used.""" + def _has_marker(keys, markers): + for marker in markers: + if marker in keys: + return True + return False + + keys = [] + for key, value in fields.items(): + if value in ([], 'UNKNOWN', None): + continue + keys.append(key) + + possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.0', '2.1'] + + # first let's try to see if a field is not part of one of the version + for key in keys: + if key not in _241_FIELDS and '1.0' in possible_versions: + possible_versions.remove('1.0') + logger.debug('Removed 1.0 due to %s', key) + if key not in _314_FIELDS and '1.1' in possible_versions: + possible_versions.remove('1.1') + logger.debug('Removed 1.1 due to %s', key) + if key not in _345_FIELDS and '1.2' in possible_versions: + possible_versions.remove('1.2') + logger.debug('Removed 1.2 due to %s', key) + if key not in _566_FIELDS and '1.3' in possible_versions: + possible_versions.remove('1.3') + logger.debug('Removed 1.3 due to %s', key) + if key not in _566_FIELDS and '2.1' in possible_versions: + if key != 'Description': # In 2.1, description allowed after headers + possible_versions.remove('2.1') + logger.debug('Removed 2.1 due to %s', key) + if key not in _426_FIELDS and '2.0' in possible_versions: + possible_versions.remove('2.0') + logger.debug('Removed 2.0 due to %s', key) + + # possible_version contains qualified versions + if len(possible_versions) == 1: + return possible_versions[0] # found ! + elif len(possible_versions) == 0: + logger.debug('Out of options - unknown metadata set: %s', fields) + raise MetadataConflictError('Unknown metadata set') + + # let's see if one unique marker is found + is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) + is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) + is_2_1 = '2.1' in possible_versions and _has_marker(keys, _566_MARKERS) + is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) + if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_0) > 1: + raise MetadataConflictError('You used incompatible 1.1/1.2/2.0/2.1 fields') + + # we have the choice, 1.0, or 1.2, or 2.0 + # - 1.0 has a broken Summary field but works with all tools + # - 1.1 is to avoid + # - 1.2 fixes Summary but has little adoption + # - 2.0 adds more features and is very new + if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_0: + # we couldn't find any specific marker + if PKG_INFO_PREFERRED_VERSION in possible_versions: + return PKG_INFO_PREFERRED_VERSION + if is_1_1: + return '1.1' + if is_1_2: + return '1.2' + if is_2_1: + return '2.1' + + return '2.0' + +_ATTR2FIELD = { + 'metadata_version': 'Metadata-Version', + 'name': 'Name', + 'version': 'Version', + 'platform': 'Platform', + 'supported_platform': 'Supported-Platform', + 'summary': 'Summary', + 'description': 'Description', + 'keywords': 'Keywords', + 'home_page': 'Home-page', + 'author': 'Author', + 'author_email': 'Author-email', + 'maintainer': 'Maintainer', + 'maintainer_email': 'Maintainer-email', + 'license': 'License', + 'classifier': 'Classifier', + 'download_url': 'Download-URL', + 'obsoletes_dist': 'Obsoletes-Dist', + 'provides_dist': 'Provides-Dist', + 'requires_dist': 'Requires-Dist', + 'setup_requires_dist': 'Setup-Requires-Dist', + 'requires_python': 'Requires-Python', + 'requires_external': 'Requires-External', + 'requires': 'Requires', + 'provides': 'Provides', + 'obsoletes': 'Obsoletes', + 'project_url': 'Project-URL', + 'private_version': 'Private-Version', + 'obsoleted_by': 'Obsoleted-By', + 'extension': 'Extension', + 'provides_extra': 'Provides-Extra', +} + +_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') +_VERSIONS_FIELDS = ('Requires-Python',) +_VERSION_FIELDS = ('Version',) +_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', + 'Requires', 'Provides', 'Obsoletes-Dist', + 'Provides-Dist', 'Requires-Dist', 'Requires-External', + 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', + 'Provides-Extra', 'Extension') +_LISTTUPLEFIELDS = ('Project-URL',) + +_ELEMENTSFIELD = ('Keywords',) + +_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') + +_MISSING = object() + +_FILESAFE = re.compile('[^A-Za-z0-9.]+') + + +def _get_name_and_version(name, version, for_filename=False): + """Return the distribution name with version. + + If for_filename is true, return a filename-escaped form.""" + if for_filename: + # For both name and version any runs of non-alphanumeric or '.' + # characters are replaced with a single '-'. Additionally any + # spaces in the version string become '.' + name = _FILESAFE.sub('-', name) + version = _FILESAFE.sub('-', version.replace(' ', '.')) + return '%s-%s' % (name, version) + + +class LegacyMetadata(object): + """The legacy metadata of a release. + + Supports versions 1.0, 1.1 and 1.2 (auto-detected). You can + instantiate the class with one of these arguments (or none): + - *path*, the path to a metadata file + - *fileobj* give a file-like object with metadata as content + - *mapping* is a dict-like object + - *scheme* is a version scheme name + """ + # TODO document the mapping API and UNKNOWN default key + + def __init__(self, path=None, fileobj=None, mapping=None, + scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._fields = {} + self.requires_files = [] + self._dependencies = None + self.scheme = scheme + if path is not None: + self.read(path) + elif fileobj is not None: + self.read_file(fileobj) + elif mapping is not None: + self.update(mapping) + self.set_metadata_version() + + def set_metadata_version(self): + self._fields['Metadata-Version'] = _best_version(self._fields) + + def _write_field(self, fileobj, name, value): + fileobj.write('%s: %s\n' % (name, value)) + + def __getitem__(self, name): + return self.get(name) + + def __setitem__(self, name, value): + return self.set(name, value) + + def __delitem__(self, name): + field_name = self._convert_name(name) + try: + del self._fields[field_name] + except KeyError: + raise KeyError(name) + + def __contains__(self, name): + return (name in self._fields or + self._convert_name(name) in self._fields) + + def _convert_name(self, name): + if name in _ALL_FIELDS: + return name + name = name.replace('-', '_').lower() + return _ATTR2FIELD.get(name, name) + + def _default_value(self, name): + if name in _LISTFIELDS or name in _ELEMENTSFIELD: + return [] + return 'UNKNOWN' + + def _remove_line_prefix(self, value): + if self.metadata_version in ('1.0', '1.1'): + return _LINE_PREFIX_PRE_1_2.sub('\n', value) + else: + return _LINE_PREFIX_1_2.sub('\n', value) + + def __getattr__(self, name): + if name in _ATTR2FIELD: + return self[name] + raise AttributeError(name) + + # + # Public API + # + +# dependencies = property(_get_dependencies, _set_dependencies) + + def get_fullname(self, filesafe=False): + """Return the distribution name with version. + + If filesafe is true, return a filename-escaped form.""" + return _get_name_and_version(self['Name'], self['Version'], filesafe) + + def is_field(self, name): + """return True if name is a valid metadata key""" + name = self._convert_name(name) + return name in _ALL_FIELDS + + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + + def read(self, filepath): + """Read the metadata values from a file path.""" + fp = codecs.open(filepath, 'r', encoding='utf-8') + try: + self.read_file(fp) + finally: + fp.close() + + def read_file(self, fileob): + """Read the metadata values from a file object.""" + msg = message_from_file(fileob) + self._fields['Metadata-Version'] = msg['metadata-version'] + + # When reading, get all the fields we can + for field in _ALL_FIELDS: + if field not in msg: + continue + if field in _LISTFIELDS: + # we can have multiple lines + values = msg.get_all(field) + if field in _LISTTUPLEFIELDS and values is not None: + values = [tuple(value.split(',')) for value in values] + self.set(field, values) + else: + # single line + value = msg[field] + if value is not None and value != 'UNKNOWN': + self.set(field, value) + logger.debug('Attempting to set metadata for %s', self) + self.set_metadata_version() + + def write(self, filepath, skip_unknown=False): + """Write the metadata fields to filepath.""" + fp = codecs.open(filepath, 'w', encoding='utf-8') + try: + self.write_file(fp, skip_unknown) + finally: + fp.close() + + def write_file(self, fileobject, skip_unknown=False): + """Write the PKG-INFO format data to a file object.""" + self.set_metadata_version() + + for field in _version2fieldlist(self['Metadata-Version']): + values = self.get(field) + if skip_unknown and values in ('UNKNOWN', [], ['UNKNOWN']): + continue + if field in _ELEMENTSFIELD: + self._write_field(fileobject, field, ','.join(values)) + continue + if field not in _LISTFIELDS: + if field == 'Description': + if self.metadata_version in ('1.0', '1.1'): + values = values.replace('\n', '\n ') + else: + values = values.replace('\n', '\n |') + values = [values] + + if field in _LISTTUPLEFIELDS: + values = [','.join(value) for value in values] + + for value in values: + self._write_field(fileobject, field, value) + + def update(self, other=None, **kwargs): + """Set metadata values from the given iterable `other` and kwargs. + + Behavior is like `dict.update`: If `other` has a ``keys`` method, + they are looped over and ``self[key]`` is assigned ``other[key]``. + Else, ``other`` is an iterable of ``(key, value)`` iterables. + + Keys that don't match a metadata field or that have an empty value are + dropped. + """ + def _set(key, value): + if key in _ATTR2FIELD and value: + self.set(self._convert_name(key), value) + + if not other: + # other is None or empty container + pass + elif hasattr(other, 'keys'): + for k in other.keys(): + _set(k, other[k]) + else: + for k, v in other: + _set(k, v) + + if kwargs: + for k, v in kwargs.items(): + _set(k, v) + + def set(self, name, value): + """Control then set a metadata field.""" + name = self._convert_name(name) + + if ((name in _ELEMENTSFIELD or name == 'Platform') and + not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [v.strip() for v in value.split(',')] + else: + value = [] + elif (name in _LISTFIELDS and + not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [value] + else: + value = [] + + if logger.isEnabledFor(logging.WARNING): + project_name = self['Name'] + + scheme = get_scheme(self.scheme) + if name in _PREDICATE_FIELDS and value is not None: + for v in value: + # check that the values are valid + if not scheme.is_valid_matcher(v.split(';')[0]): + logger.warning( + "'%s': '%s' is not valid (field '%s')", + project_name, v, name) + # FIXME this rejects UNKNOWN, is that right? + elif name in _VERSIONS_FIELDS and value is not None: + if not scheme.is_valid_constraint_list(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", + project_name, value, name) + elif name in _VERSION_FIELDS and value is not None: + if not scheme.is_valid_version(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", + project_name, value, name) + + if name in _UNICODEFIELDS: + if name == 'Description': + value = self._remove_line_prefix(value) + + self._fields[name] = value + + def get(self, name, default=_MISSING): + """Get a metadata field.""" + name = self._convert_name(name) + if name not in self._fields: + if default is _MISSING: + default = self._default_value(name) + return default + if name in _UNICODEFIELDS: + value = self._fields[name] + return value + elif name in _LISTFIELDS: + value = self._fields[name] + if value is None: + return [] + res = [] + for val in value: + if name not in _LISTTUPLEFIELDS: + res.append(val) + else: + # That's for Project-URL + res.append((val[0], val[1])) + return res + + elif name in _ELEMENTSFIELD: + value = self._fields[name] + if isinstance(value, string_types): + return value.split(',') + return self._fields[name] + + def check(self, strict=False): + """Check if the metadata is compliant. If strict is True then raise if + no Name or Version are provided""" + self.set_metadata_version() + + # XXX should check the versions (if the file was loaded) + missing, warnings = [], [] + + for attr in ('Name', 'Version'): # required by PEP 345 + if attr not in self: + missing.append(attr) + + if strict and missing != []: + msg = 'missing required metadata: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + + for attr in ('Home-page', 'Author'): + if attr not in self: + missing.append(attr) + + # checking metadata 1.2 (XXX needs to check 1.1, 1.0) + if self['Metadata-Version'] != '1.2': + return missing, warnings + + scheme = get_scheme(self.scheme) + + def are_valid_constraints(value): + for v in value: + if not scheme.is_valid_matcher(v.split(';')[0]): + return False + return True + + for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints), + (_VERSIONS_FIELDS, + scheme.is_valid_constraint_list), + (_VERSION_FIELDS, + scheme.is_valid_version)): + for field in fields: + value = self.get(field, None) + if value is not None and not controller(value): + warnings.append("Wrong value for '%s': %s" % (field, value)) + + return missing, warnings + + def todict(self, skip_missing=False): + """Return fields as a dict. + + Field names will be converted to use the underscore-lowercase style + instead of hyphen-mixed case (i.e. home_page instead of Home-page). + """ + self.set_metadata_version() + + mapping_1_0 = ( + ('metadata_version', 'Metadata-Version'), + ('name', 'Name'), + ('version', 'Version'), + ('summary', 'Summary'), + ('home_page', 'Home-page'), + ('author', 'Author'), + ('author_email', 'Author-email'), + ('license', 'License'), + ('description', 'Description'), + ('keywords', 'Keywords'), + ('platform', 'Platform'), + ('classifiers', 'Classifier'), + ('download_url', 'Download-URL'), + ) + + data = {} + for key, field_name in mapping_1_0: + if not skip_missing or field_name in self._fields: + data[key] = self[field_name] + + if self['Metadata-Version'] == '1.2': + mapping_1_2 = ( + ('requires_dist', 'Requires-Dist'), + ('requires_python', 'Requires-Python'), + ('requires_external', 'Requires-External'), + ('provides_dist', 'Provides-Dist'), + ('obsoletes_dist', 'Obsoletes-Dist'), + ('project_url', 'Project-URL'), + ('maintainer', 'Maintainer'), + ('maintainer_email', 'Maintainer-email'), + ) + for key, field_name in mapping_1_2: + if not skip_missing or field_name in self._fields: + if key != 'project_url': + data[key] = self[field_name] + else: + data[key] = [','.join(u) for u in self[field_name]] + + elif self['Metadata-Version'] == '1.1': + mapping_1_1 = ( + ('provides', 'Provides'), + ('requires', 'Requires'), + ('obsoletes', 'Obsoletes'), + ) + for key, field_name in mapping_1_1: + if not skip_missing or field_name in self._fields: + data[key] = self[field_name] + + return data + + def add_requirements(self, requirements): + if self['Metadata-Version'] == '1.1': + # we can't have 1.1 metadata *and* Setuptools requires + for field in ('Obsoletes', 'Requires', 'Provides'): + if field in self: + del self[field] + self['Requires-Dist'] += requirements + + # Mapping API + # TODO could add iter* variants + + def keys(self): + return list(_version2fieldlist(self['Metadata-Version'])) + + def __iter__(self): + for key in self.keys(): + yield key + + def values(self): + return [self[key] for key in self.keys()] + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def __repr__(self): + return '<%s %s %s>' % (self.__class__.__name__, self.name, + self.version) + + +METADATA_FILENAME = 'pydist.json' +WHEEL_METADATA_FILENAME = 'metadata.json' + + +class Metadata(object): + """ + The metadata of a release. This implementation uses 2.0 (JSON) + metadata where possible. If not possible, it wraps a LegacyMetadata + instance which handles the key-value metadata format. + """ + + METADATA_VERSION_MATCHER = re.compile(r'^\d+(\.\d+)*$') + + NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) + + VERSION_MATCHER = PEP440_VERSION_RE + + SUMMARY_MATCHER = re.compile('.{1,2047}') + + METADATA_VERSION = '2.0' + + GENERATOR = 'distlib (%s)' % __version__ + + MANDATORY_KEYS = { + 'name': (), + 'version': (), + 'summary': ('legacy',), + } + + INDEX_KEYS = ('name version license summary description author ' + 'author_email keywords platform home_page classifiers ' + 'download_url') + + DEPENDENCY_KEYS = ('extras run_requires test_requires build_requires ' + 'dev_requires provides meta_requires obsoleted_by ' + 'supports_environments') + + SYNTAX_VALIDATORS = { + 'metadata_version': (METADATA_VERSION_MATCHER, ()), + 'name': (NAME_MATCHER, ('legacy',)), + 'version': (VERSION_MATCHER, ('legacy',)), + 'summary': (SUMMARY_MATCHER, ('legacy',)), + } + + __slots__ = ('_legacy', '_data', 'scheme') + + def __init__(self, path=None, fileobj=None, mapping=None, + scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._legacy = None + self._data = None + self.scheme = scheme + #import pdb; pdb.set_trace() + if mapping is not None: + try: + self._validate_mapping(mapping, scheme) + self._data = mapping + except MetadataUnrecognizedVersionError: + self._legacy = LegacyMetadata(mapping=mapping, scheme=scheme) + self.validate() + else: + data = None + if path: + with open(path, 'rb') as f: + data = f.read() + elif fileobj: + data = fileobj.read() + if data is None: + # Initialised with no args - to be added + self._data = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + else: + if not isinstance(data, text_type): + data = data.decode('utf-8') + try: + self._data = json.loads(data) + self._validate_mapping(self._data, scheme) + except ValueError: + # Note: MetadataUnrecognizedVersionError does not + # inherit from ValueError (it's a DistlibException, + # which should not inherit from ValueError). + # The ValueError comes from the json.load - if that + # succeeds and we get a validation error, we want + # that to propagate + self._legacy = LegacyMetadata(fileobj=StringIO(data), + scheme=scheme) + self.validate() + + common_keys = set(('name', 'version', 'license', 'keywords', 'summary')) + + none_list = (None, list) + none_dict = (None, dict) + + mapped_keys = { + 'run_requires': ('Requires-Dist', list), + 'build_requires': ('Setup-Requires-Dist', list), + 'dev_requires': none_list, + 'test_requires': none_list, + 'meta_requires': none_list, + 'extras': ('Provides-Extra', list), + 'modules': none_list, + 'namespaces': none_list, + 'exports': none_dict, + 'commands': none_dict, + 'classifiers': ('Classifier', list), + 'source_url': ('Download-URL', None), + 'metadata_version': ('Metadata-Version', None), + } + + del none_list, none_dict + + def __getattribute__(self, key): + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, maker = mapped[key] + if self._legacy: + if lk is None: + result = None if maker is None else maker() + else: + result = self._legacy.get(lk) + else: + value = None if maker is None else maker() + if key not in ('commands', 'exports', 'modules', 'namespaces', + 'classifiers'): + result = self._data.get(key, value) + else: + # special cases for PEP 459 + sentinel = object() + result = sentinel + d = self._data.get('extensions') + if d: + if key == 'commands': + result = d.get('python.commands', value) + elif key == 'classifiers': + d = d.get('python.details') + if d: + result = d.get(key, value) + else: + d = d.get('python.exports') + if not d: + d = self._data.get('python.exports') + if d: + result = d.get(key, value) + if result is sentinel: + result = value + elif key not in common: + result = object.__getattribute__(self, key) + elif self._legacy: + result = self._legacy.get(key) + else: + result = self._data.get(key) + return result + + def _validate_value(self, key, value, scheme=None): + if key in self.SYNTAX_VALIDATORS: + pattern, exclusions = self.SYNTAX_VALIDATORS[key] + if (scheme or self.scheme) not in exclusions: + m = pattern.match(value) + if not m: + raise MetadataInvalidError("'%s' is an invalid value for " + "the '%s' property" % (value, + key)) + + def __setattr__(self, key, value): + self._validate_value(key, value) + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, _ = mapped[key] + if self._legacy: + if lk is None: + raise NotImplementedError + self._legacy[lk] = value + elif key not in ('commands', 'exports', 'modules', 'namespaces', + 'classifiers'): + self._data[key] = value + else: + # special cases for PEP 459 + d = self._data.setdefault('extensions', {}) + if key == 'commands': + d['python.commands'] = value + elif key == 'classifiers': + d = d.setdefault('python.details', {}) + d[key] = value + else: + d = d.setdefault('python.exports', {}) + d[key] = value + elif key not in common: + object.__setattr__(self, key, value) + else: + if key == 'keywords': + if isinstance(value, string_types): + value = value.strip() + if value: + value = value.split() + else: + value = [] + if self._legacy: + self._legacy[key] = value + else: + self._data[key] = value + + @property + def name_and_version(self): + return _get_name_and_version(self.name, self.version, True) + + @property + def provides(self): + if self._legacy: + result = self._legacy['Provides-Dist'] + else: + result = self._data.setdefault('provides', []) + s = '%s (%s)' % (self.name, self.version) + if s not in result: + result.append(s) + return result + + @provides.setter + def provides(self, value): + if self._legacy: + self._legacy['Provides-Dist'] = value + else: + self._data['provides'] = value + + def get_requirements(self, reqts, extras=None, env=None): + """ + Base method to get dependencies, given a set of extras + to satisfy and an optional environment context. + :param reqts: A list of sometimes-wanted dependencies, + perhaps dependent on extras and environment. + :param extras: A list of optional components being requested. + :param env: An optional environment for marker evaluation. + """ + if self._legacy: + result = reqts + else: + result = [] + extras = get_extras(extras or [], self.extras) + for d in reqts: + if 'extra' not in d and 'environment' not in d: + # unconditional + include = True + else: + if 'extra' not in d: + # Not extra-dependent - only environment-dependent + include = True + else: + include = d.get('extra') in extras + if include: + # Not excluded because of extras, check environment + marker = d.get('environment') + if marker: + include = interpret(marker, env) + if include: + result.extend(d['requires']) + for key in ('build', 'dev', 'test'): + e = ':%s:' % key + if e in extras: + extras.remove(e) + # A recursive call, but it should terminate since 'test' + # has been removed from the extras + reqts = self._data.get('%s_requires' % key, []) + result.extend(self.get_requirements(reqts, extras=extras, + env=env)) + return result + + @property + def dictionary(self): + if self._legacy: + return self._from_legacy() + return self._data + + @property + def dependencies(self): + if self._legacy: + raise NotImplementedError + else: + return extract_by_key(self._data, self.DEPENDENCY_KEYS) + + @dependencies.setter + def dependencies(self, value): + if self._legacy: + raise NotImplementedError + else: + self._data.update(value) + + def _validate_mapping(self, mapping, scheme): + if mapping.get('metadata_version') != self.METADATA_VERSION: + raise MetadataUnrecognizedVersionError() + missing = [] + for key, exclusions in self.MANDATORY_KEYS.items(): + if key not in mapping: + if scheme not in exclusions: + missing.append(key) + if missing: + msg = 'Missing metadata items: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + for k, v in mapping.items(): + self._validate_value(k, v, scheme) + + def validate(self): + if self._legacy: + missing, warnings = self._legacy.check(True) + if missing or warnings: + logger.warning('Metadata: missing: %s, warnings: %s', + missing, warnings) + else: + self._validate_mapping(self._data, self.scheme) + + def todict(self): + if self._legacy: + return self._legacy.todict(True) + else: + result = extract_by_key(self._data, self.INDEX_KEYS) + return result + + def _from_legacy(self): + assert self._legacy and not self._data + result = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + lmd = self._legacy.todict(True) # skip missing ones + for k in ('name', 'version', 'license', 'summary', 'description', + 'classifier'): + if k in lmd: + if k == 'classifier': + nk = 'classifiers' + else: + nk = k + result[nk] = lmd[k] + kw = lmd.get('Keywords', []) + if kw == ['']: + kw = [] + result['keywords'] = kw + keys = (('requires_dist', 'run_requires'), + ('setup_requires_dist', 'build_requires')) + for ok, nk in keys: + if ok in lmd and lmd[ok]: + result[nk] = [{'requires': lmd[ok]}] + result['provides'] = self.provides + author = {} + maintainer = {} + return result + + LEGACY_MAPPING = { + 'name': 'Name', + 'version': 'Version', + 'license': 'License', + 'summary': 'Summary', + 'description': 'Description', + 'classifiers': 'Classifier', + } + + def _to_legacy(self): + def process_entries(entries): + reqts = set() + for e in entries: + extra = e.get('extra') + env = e.get('environment') + rlist = e['requires'] + for r in rlist: + if not env and not extra: + reqts.add(r) + else: + marker = '' + if extra: + marker = 'extra == "%s"' % extra + if env: + if marker: + marker = '(%s) and %s' % (env, marker) + else: + marker = env + reqts.add(';'.join((r, marker))) + return reqts + + assert self._data and not self._legacy + result = LegacyMetadata() + nmd = self._data + for nk, ok in self.LEGACY_MAPPING.items(): + if nk in nmd: + result[ok] = nmd[nk] + r1 = process_entries(self.run_requires + self.meta_requires) + r2 = process_entries(self.build_requires + self.dev_requires) + if self.extras: + result['Provides-Extra'] = sorted(self.extras) + result['Requires-Dist'] = sorted(r1) + result['Setup-Requires-Dist'] = sorted(r2) + # TODO: other fields such as contacts + return result + + def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True): + if [path, fileobj].count(None) != 1: + raise ValueError('Exactly one of path and fileobj is needed') + self.validate() + if legacy: + if self._legacy: + legacy_md = self._legacy + else: + legacy_md = self._to_legacy() + if path: + legacy_md.write(path, skip_unknown=skip_unknown) + else: + legacy_md.write_file(fileobj, skip_unknown=skip_unknown) + else: + if self._legacy: + d = self._from_legacy() + else: + d = self._data + if fileobj: + json.dump(d, fileobj, ensure_ascii=True, indent=2, + sort_keys=True) + else: + with codecs.open(path, 'w', 'utf-8') as f: + json.dump(d, f, ensure_ascii=True, indent=2, + sort_keys=True) + + def add_requirements(self, requirements): + if self._legacy: + self._legacy.add_requirements(requirements) + else: + run_requires = self._data.setdefault('run_requires', []) + always = None + for entry in run_requires: + if 'environment' not in entry and 'extra' not in entry: + always = entry + break + if always is None: + always = { 'requires': requirements } + run_requires.insert(0, always) + else: + rset = set(always['requires']) | set(requirements) + always['requires'] = sorted(rset) + + def __repr__(self): + name = self.name or '(no name)' + version = self.version or 'no version' + return '<%s %s %s (%s)>' % (self.__class__.__name__, + self.metadata_version, name, version) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py new file mode 100755 index 0000000..cd618a6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py @@ -0,0 +1,355 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import bisect +import io +import logging +import os +import pkgutil +import shutil +import sys +import types +import zipimport + +from . import DistlibException +from .util import cached_property, get_cache_base, path_to_cache_dir, Cache + +logger = logging.getLogger(__name__) + + +cache = None # created when needed + + +class ResourceCache(Cache): + def __init__(self, base=None): + if base is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('resource-cache')) + super(ResourceCache, self).__init__(base) + + def is_stale(self, resource, path): + """ + Is the cache stale for the given resource? + + :param resource: The :class:`Resource` being cached. + :param path: The path of the resource in the cache. + :return: True if the cache is stale. + """ + # Cache invalidation is a hard problem :-) + return True + + def get(self, resource): + """ + Get a resource into the cache, + + :param resource: A :class:`Resource` instance. + :return: The pathname of the resource in the cache. + """ + prefix, path = resource.finder.get_cache_info(resource) + if prefix is None: + result = path + else: + result = os.path.join(self.base, self.prefix_to_dir(prefix), path) + dirname = os.path.dirname(result) + if not os.path.isdir(dirname): + os.makedirs(dirname) + if not os.path.exists(result): + stale = True + else: + stale = self.is_stale(resource, path) + if stale: + # write the bytes of the resource to the cache location + with open(result, 'wb') as f: + f.write(resource.bytes) + return result + + +class ResourceBase(object): + def __init__(self, finder, name): + self.finder = finder + self.name = name + + +class Resource(ResourceBase): + """ + A class representing an in-package resource, such as a data file. This is + not normally instantiated by user code, but rather by a + :class:`ResourceFinder` which manages the resource. + """ + is_container = False # Backwards compatibility + + def as_stream(self): + """ + Get the resource as a stream. + + This is not a property to make it obvious that it returns a new stream + each time. + """ + return self.finder.get_stream(self) + + @cached_property + def file_path(self): + global cache + if cache is None: + cache = ResourceCache() + return cache.get(self) + + @cached_property + def bytes(self): + return self.finder.get_bytes(self) + + @cached_property + def size(self): + return self.finder.get_size(self) + + +class ResourceContainer(ResourceBase): + is_container = True # Backwards compatibility + + @cached_property + def resources(self): + return self.finder.get_resources(self) + + +class ResourceFinder(object): + """ + Resource finder for file system resources. + """ + + if sys.platform.startswith('java'): + skipped_extensions = ('.pyc', '.pyo', '.class') + else: + skipped_extensions = ('.pyc', '.pyo') + + def __init__(self, module): + self.module = module + self.loader = getattr(module, '__loader__', None) + self.base = os.path.dirname(getattr(module, '__file__', '')) + + def _adjust_path(self, path): + return os.path.realpath(path) + + def _make_path(self, resource_name): + # Issue #50: need to preserve type of path on Python 2.x + # like os.path._get_sep + if isinstance(resource_name, bytes): # should only happen on 2.x + sep = b'/' + else: + sep = '/' + parts = resource_name.split(sep) + parts.insert(0, self.base) + result = os.path.join(*parts) + return self._adjust_path(result) + + def _find(self, path): + return os.path.exists(path) + + def get_cache_info(self, resource): + return None, resource.path + + def find(self, resource_name): + path = self._make_path(resource_name) + if not self._find(path): + result = None + else: + if self._is_directory(path): + result = ResourceContainer(self, resource_name) + else: + result = Resource(self, resource_name) + result.path = path + return result + + def get_stream(self, resource): + return open(resource.path, 'rb') + + def get_bytes(self, resource): + with open(resource.path, 'rb') as f: + return f.read() + + def get_size(self, resource): + return os.path.getsize(resource.path) + + def get_resources(self, resource): + def allowed(f): + return (f != '__pycache__' and not + f.endswith(self.skipped_extensions)) + return set([f for f in os.listdir(resource.path) if allowed(f)]) + + def is_container(self, resource): + return self._is_directory(resource.path) + + _is_directory = staticmethod(os.path.isdir) + + def iterator(self, resource_name): + resource = self.find(resource_name) + if resource is not None: + todo = [resource] + while todo: + resource = todo.pop(0) + yield resource + if resource.is_container: + rname = resource.name + for name in resource.resources: + if not rname: + new_name = name + else: + new_name = '/'.join([rname, name]) + child = self.find(new_name) + if child.is_container: + todo.append(child) + else: + yield child + + +class ZipResourceFinder(ResourceFinder): + """ + Resource finder for resources in .zip files. + """ + def __init__(self, module): + super(ZipResourceFinder, self).__init__(module) + archive = self.loader.archive + self.prefix_len = 1 + len(archive) + # PyPy doesn't have a _files attr on zipimporter, and you can't set one + if hasattr(self.loader, '_files'): + self._files = self.loader._files + else: + self._files = zipimport._zip_directory_cache[archive] + self.index = sorted(self._files) + + def _adjust_path(self, path): + return path + + def _find(self, path): + path = path[self.prefix_len:] + if path in self._files: + result = True + else: + if path and path[-1] != os.sep: + path = path + os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + if not result: + logger.debug('_find failed: %r %r', path, self.loader.prefix) + else: + logger.debug('_find worked: %r %r', path, self.loader.prefix) + return result + + def get_cache_info(self, resource): + prefix = self.loader.archive + path = resource.path[1 + len(prefix):] + return prefix, path + + def get_bytes(self, resource): + return self.loader.get_data(resource.path) + + def get_stream(self, resource): + return io.BytesIO(self.get_bytes(resource)) + + def get_size(self, resource): + path = resource.path[self.prefix_len:] + return self._files[path][3] + + def get_resources(self, resource): + path = resource.path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + plen = len(path) + result = set() + i = bisect.bisect(self.index, path) + while i < len(self.index): + if not self.index[i].startswith(path): + break + s = self.index[i][plen:] + result.add(s.split(os.sep, 1)[0]) # only immediate children + i += 1 + return result + + def _is_directory(self, path): + path = path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + return result + +_finder_registry = { + type(None): ResourceFinder, + zipimport.zipimporter: ZipResourceFinder +} + +try: + # In Python 3.6, _frozen_importlib -> _frozen_importlib_external + try: + import _frozen_importlib_external as _fi + except ImportError: + import _frozen_importlib as _fi + _finder_registry[_fi.SourceFileLoader] = ResourceFinder + _finder_registry[_fi.FileFinder] = ResourceFinder + del _fi +except (ImportError, AttributeError): + pass + + +def register_finder(loader, finder_maker): + _finder_registry[type(loader)] = finder_maker + +_finder_cache = {} + + +def finder(package): + """ + Return a resource finder for a package. + :param package: The name of the package. + :return: A :class:`ResourceFinder` instance for the package. + """ + if package in _finder_cache: + result = _finder_cache[package] + else: + if package not in sys.modules: + __import__(package) + module = sys.modules[package] + path = getattr(module, '__path__', None) + if path is None: + raise DistlibException('You cannot get a finder for a module, ' + 'only for a package') + loader = getattr(module, '__loader__', None) + finder_maker = _finder_registry.get(type(loader)) + if finder_maker is None: + raise DistlibException('Unable to locate finder for %r' % package) + result = finder_maker(module) + _finder_cache[package] = result + return result + + +_dummy_module = types.ModuleType(str('__dummy__')) + + +def finder_for_path(path): + """ + Return a resource finder for a path, which should represent a container. + + :param path: The path. + :return: A :class:`ResourceFinder` instance for the path. + """ + result = None + # calls any path hooks, gets importer into cache + pkgutil.get_importer(path) + loader = sys.path_importer_cache.get(path) + finder = _finder_registry.get(type(loader)) + if finder: + module = _dummy_module + module.__file__ = os.path.join(path, '') + module.__loader__ = loader + result = finder(module) + return result diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py new file mode 100755 index 0000000..440bd30 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py @@ -0,0 +1,415 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2015 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from io import BytesIO +import logging +import os +import re +import struct +import sys + +from .compat import sysconfig, detect_encoding, ZipFile +from .resources import finder +from .util import (FileOperator, get_export_entry, convert_path, + get_executable, in_venv) + +logger = logging.getLogger(__name__) + +_DEFAULT_MANIFEST = ''' +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity version="1.0.0.0" + processorArchitecture="X86" + name="%s" + type="win32"/> + + <!-- Identify the application security requirements. --> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> +</assembly>'''.strip() + +# check if Python is called on the first line with this expression +FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$') +SCRIPT_TEMPLATE = r'''# -*- coding: utf-8 -*- +if __name__ == '__main__': + import sys, re + + def _resolve(module, func): + __import__(module) + mod = sys.modules[module] + parts = func.split('.') + result = getattr(mod, parts.pop(0)) + for p in parts: + result = getattr(result, p) + return result + + try: + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + + func = _resolve('%(module)s', '%(func)s') + rc = func() # None interpreted as 0 + except Exception as e: # only supporting Python >= 2.6 + sys.stderr.write('%%s\n' %% e) + rc = 1 + sys.exit(rc) +''' + + +def _enquote_executable(executable): + if ' ' in executable: + # make sure we quote only the executable in case of env + # for example /usr/bin/env "/dir with spaces/bin/jython" + # instead of "/usr/bin/env /dir with spaces/bin/jython" + # otherwise whole + if executable.startswith('/usr/bin/env '): + env, _executable = executable.split(' ', 1) + if ' ' in _executable and not _executable.startswith('"'): + executable = '%s "%s"' % (env, _executable) + else: + if not executable.startswith('"'): + executable = '"%s"' % executable + return executable + + +class ScriptMaker(object): + """ + A class to copy or create scripts from source scripts or callable + specifications. + """ + script_template = SCRIPT_TEMPLATE + + executable = None # for shebangs + + def __init__(self, source_dir, target_dir, add_launchers=True, + dry_run=False, fileop=None): + self.source_dir = source_dir + self.target_dir = target_dir + self.add_launchers = add_launchers + self.force = False + self.clobber = False + # It only makes sense to set mode bits on POSIX. + self.set_mode = (os.name == 'posix') or (os.name == 'java' and + os._name == 'posix') + self.variants = set(('', 'X.Y')) + self._fileop = fileop or FileOperator(dry_run) + + self._is_nt = os.name == 'nt' or ( + os.name == 'java' and os._name == 'nt') + + def _get_alternate_executable(self, executable, options): + if options.get('gui', False) and self._is_nt: # pragma: no cover + dn, fn = os.path.split(executable) + fn = fn.replace('python', 'pythonw') + executable = os.path.join(dn, fn) + return executable + + if sys.platform.startswith('java'): # pragma: no cover + def _is_shell(self, executable): + """ + Determine if the specified executable is a script + (contains a #! line) + """ + try: + with open(executable) as fp: + return fp.read(2) == '#!' + except (OSError, IOError): + logger.warning('Failed to open %s', executable) + return False + + def _fix_jython_executable(self, executable): + if self._is_shell(executable): + # Workaround for Jython is not needed on Linux systems. + import java + + if java.lang.System.getProperty('os.name') == 'Linux': + return executable + elif executable.lower().endswith('jython.exe'): + # Use wrapper exe for Jython on Windows + return executable + return '/usr/bin/env %s' % executable + + def _build_shebang(self, executable, post_interp): + """ + Build a shebang line. In the simple case (on Windows, or a shebang line + which is not too long or contains spaces) use a simple formulation for + the shebang. Otherwise, use /bin/sh as the executable, with a contrived + shebang which allows the script to run either under Python or sh, using + suitable quoting. Thanks to Harald Nordgren for his input. + + See also: http://www.in-ulm.de/~mascheck/various/shebang/#length + https://hg.mozilla.org/mozilla-central/file/tip/mach + """ + if os.name != 'posix': + simple_shebang = True + else: + # Add 3 for '#!' prefix and newline suffix. + shebang_length = len(executable) + len(post_interp) + 3 + if sys.platform == 'darwin': + max_shebang_length = 512 + else: + max_shebang_length = 127 + simple_shebang = ((b' ' not in executable) and + (shebang_length <= max_shebang_length)) + + if simple_shebang: + result = b'#!' + executable + post_interp + b'\n' + else: + result = b'#!/bin/sh\n' + result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n' + result += b"' '''" + return result + + def _get_shebang(self, encoding, post_interp=b'', options=None): + enquote = True + if self.executable: + executable = self.executable + enquote = False # assume this will be taken care of + elif not sysconfig.is_python_build(): + executable = get_executable() + elif in_venv(): # pragma: no cover + executable = os.path.join(sysconfig.get_path('scripts'), + 'python%s' % sysconfig.get_config_var('EXE')) + else: # pragma: no cover + executable = os.path.join( + sysconfig.get_config_var('BINDIR'), + 'python%s%s' % (sysconfig.get_config_var('VERSION'), + sysconfig.get_config_var('EXE'))) + if options: + executable = self._get_alternate_executable(executable, options) + + if sys.platform.startswith('java'): # pragma: no cover + executable = self._fix_jython_executable(executable) + # Normalise case for Windows + executable = os.path.normcase(executable) + # If the user didn't specify an executable, it may be necessary to + # cater for executable paths with spaces (not uncommon on Windows) + if enquote: + executable = _enquote_executable(executable) + # Issue #51: don't use fsencode, since we later try to + # check that the shebang is decodable using utf-8. + executable = executable.encode('utf-8') + # in case of IronPython, play safe and enable frames support + if (sys.platform == 'cli' and '-X:Frames' not in post_interp + and '-X:FullFrames' not in post_interp): # pragma: no cover + post_interp += b' -X:Frames' + shebang = self._build_shebang(executable, post_interp) + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: # pragma: no cover + raise ValueError( + 'The shebang (%r) is not decodable from utf-8' % shebang) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + if encoding != 'utf-8': + try: + shebang.decode(encoding) + except UnicodeDecodeError: # pragma: no cover + raise ValueError( + 'The shebang (%r) is not decodable ' + 'from the script encoding (%r)' % (shebang, encoding)) + return shebang + + def _get_script_text(self, entry): + return self.script_template % dict(module=entry.prefix, + func=entry.suffix) + + manifest = _DEFAULT_MANIFEST + + def get_manifest(self, exename): + base = os.path.basename(exename) + return self.manifest % base + + def _write_script(self, names, shebang, script_bytes, filenames, ext): + use_launcher = self.add_launchers and self._is_nt + linesep = os.linesep.encode('utf-8') + if not use_launcher: + script_bytes = shebang + linesep + script_bytes + else: # pragma: no cover + if ext == 'py': + launcher = self._get_launcher('t') + else: + launcher = self._get_launcher('w') + stream = BytesIO() + with ZipFile(stream, 'w') as zf: + zf.writestr('__main__.py', script_bytes) + zip_data = stream.getvalue() + script_bytes = launcher + shebang + linesep + zip_data + for name in names: + outname = os.path.join(self.target_dir, name) + if use_launcher: # pragma: no cover + n, e = os.path.splitext(outname) + if e.startswith('.py'): + outname = n + outname = '%s.exe' % outname + try: + self._fileop.write_binary_file(outname, script_bytes) + except Exception: + # Failed writing an executable - it might be in use. + logger.warning('Failed to write executable - trying to ' + 'use .deleteme logic') + dfname = '%s.deleteme' % outname + if os.path.exists(dfname): + os.remove(dfname) # Not allowed to fail here + os.rename(outname, dfname) # nor here + self._fileop.write_binary_file(outname, script_bytes) + logger.debug('Able to replace executable using ' + '.deleteme logic') + try: + os.remove(dfname) + except Exception: + pass # still in use - ignore error + else: + if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover + outname = '%s.%s' % (outname, ext) + if os.path.exists(outname) and not self.clobber: + logger.warning('Skipping existing file %s', outname) + continue + self._fileop.write_binary_file(outname, script_bytes) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + + def _make_script(self, entry, filenames, options=None): + post_interp = b'' + if options: + args = options.get('interpreter_args', []) + if args: + args = ' %s' % ' '.join(args) + post_interp = args.encode('utf-8') + shebang = self._get_shebang('utf-8', post_interp, options=options) + script = self._get_script_text(entry).encode('utf-8') + name = entry.name + scriptnames = set() + if '' in self.variants: + scriptnames.add(name) + if 'X' in self.variants: + scriptnames.add('%s%s' % (name, sys.version[0])) + if 'X.Y' in self.variants: + scriptnames.add('%s-%s' % (name, sys.version[:3])) + if options and options.get('gui', False): + ext = 'pyw' + else: + ext = 'py' + self._write_script(scriptnames, shebang, script, filenames, ext) + + def _copy_script(self, script, filenames): + adjust = False + script = os.path.join(self.source_dir, convert_path(script)) + outname = os.path.join(self.target_dir, os.path.basename(script)) + if not self.force and not self._fileop.newer(script, outname): + logger.debug('not copying %s (up-to-date)', script) + return + + # Always open the file, but ignore failures in dry-run mode -- + # that way, we'll get accurate feedback if we can read the + # script. + try: + f = open(script, 'rb') + except IOError: # pragma: no cover + if not self.dry_run: + raise + f = None + else: + first_line = f.readline() + if not first_line: # pragma: no cover + logger.warning('%s: %s is an empty file (skipping)', + self.get_command_name(), script) + return + + match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n')) + if match: + adjust = True + post_interp = match.group(1) or b'' + + if not adjust: + if f: + f.close() + self._fileop.copy_file(script, outname) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + else: + logger.info('copying and adjusting %s -> %s', script, + self.target_dir) + if not self._fileop.dry_run: + encoding, lines = detect_encoding(f.readline) + f.seek(0) + shebang = self._get_shebang(encoding, post_interp) + if b'pythonw' in first_line: # pragma: no cover + ext = 'pyw' + else: + ext = 'py' + n = os.path.basename(outname) + self._write_script([n], shebang, f.read(), filenames, ext) + if f: + f.close() + + @property + def dry_run(self): + return self._fileop.dry_run + + @dry_run.setter + def dry_run(self, value): + self._fileop.dry_run = value + + if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover + # Executable launcher support. + # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/ + + def _get_launcher(self, kind): + if struct.calcsize('P') == 8: # 64-bit + bits = '64' + else: + bits = '32' + name = '%s%s.exe' % (kind, bits) + # Issue 31: don't hardcode an absolute package name, but + # determine it relative to the current package + distlib_package = __name__.rsplit('.', 1)[0] + result = finder(distlib_package).find(name).bytes + return result + + # Public API follows + + def make(self, specification, options=None): + """ + Make a script. + + :param specification: The specification, which is either a valid export + entry specification (to make a script from a + callable) or a filename (to make a script by + copying from a source location). + :param options: A dictionary of options controlling script generation. + :return: A list of all absolute pathnames written to. + """ + filenames = [] + entry = get_export_entry(specification) + if entry is None: + self._copy_script(specification, filenames) + else: + self._make_script(entry, filenames, options=options) + return filenames + + def make_multiple(self, specifications, options=None): + """ + Take a list of specifications and make scripts from them, + :param specifications: A list of specifications. + :return: A list of all absolute pathnames written to, + """ + filenames = [] + for specification in specifications: + filenames.extend(self.make(specification, options)) + return filenames diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe new file mode 100755 index 0000000..a09d926 Binary files /dev/null and b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe new file mode 100755 index 0000000..9da9b40 Binary files /dev/null and b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py new file mode 100755 index 0000000..b1d3f90 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py @@ -0,0 +1,1755 @@ +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import codecs +from collections import deque +import contextlib +import csv +from glob import iglob as std_iglob +import io +import json +import logging +import os +import py_compile +import re +import socket +try: + import ssl +except ImportError: # pragma: no cover + ssl = None +import subprocess +import sys +import tarfile +import tempfile +import textwrap + +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import time + +from . import DistlibException +from .compat import (string_types, text_type, shutil, raw_input, StringIO, + cache_from_source, urlopen, urljoin, httplib, xmlrpclib, + splittype, HTTPHandler, BaseConfigurator, valid_ident, + Container, configparser, URLError, ZipFile, fsdecode, + unquote, urlparse) + +logger = logging.getLogger(__name__) + +# +# Requirement parsing code as per PEP 508 +# + +IDENTIFIER = re.compile(r'^([\w\.-]+)\s*') +VERSION_IDENTIFIER = re.compile(r'^([\w\.*+-]+)\s*') +COMPARE_OP = re.compile(r'^(<=?|>=?|={2,3}|[~!]=)\s*') +MARKER_OP = re.compile(r'^((<=?)|(>=?)|={2,3}|[~!]=|in|not\s+in)\s*') +OR = re.compile(r'^or\b\s*') +AND = re.compile(r'^and\b\s*') +NON_SPACE = re.compile(r'(\S+)\s*') +STRING_CHUNK = re.compile(r'([\s\w\.{}()*+#:;,/?!~`@$%^&=|<>\[\]-]+)') + + +def parse_marker(marker_string): + """ + Parse a marker string and return a dictionary containing a marker expression. + + The dictionary will contain keys "op", "lhs" and "rhs" for non-terminals in + the expression grammar, or strings. A string contained in quotes is to be + interpreted as a literal string, and a string not contained in quotes is a + variable (such as os_name). + """ + def marker_var(remaining): + # either identifier, or literal string + m = IDENTIFIER.match(remaining) + if m: + result = m.groups()[0] + remaining = remaining[m.end():] + elif not remaining: + raise SyntaxError('unexpected end of input') + else: + q = remaining[0] + if q not in '\'"': + raise SyntaxError('invalid expression: %s' % remaining) + oq = '\'"'.replace(q, '') + remaining = remaining[1:] + parts = [q] + while remaining: + # either a string chunk, or oq, or q to terminate + if remaining[0] == q: + break + elif remaining[0] == oq: + parts.append(oq) + remaining = remaining[1:] + else: + m = STRING_CHUNK.match(remaining) + if not m: + raise SyntaxError('error in string literal: %s' % remaining) + parts.append(m.groups()[0]) + remaining = remaining[m.end():] + else: + s = ''.join(parts) + raise SyntaxError('unterminated string: %s' % s) + parts.append(q) + result = ''.join(parts) + remaining = remaining[1:].lstrip() # skip past closing quote + return result, remaining + + def marker_expr(remaining): + if remaining and remaining[0] == '(': + result, remaining = marker(remaining[1:].lstrip()) + if remaining[0] != ')': + raise SyntaxError('unterminated parenthesis: %s' % remaining) + remaining = remaining[1:].lstrip() + else: + lhs, remaining = marker_var(remaining) + while remaining: + m = MARKER_OP.match(remaining) + if not m: + break + op = m.groups()[0] + remaining = remaining[m.end():] + rhs, remaining = marker_var(remaining) + lhs = {'op': op, 'lhs': lhs, 'rhs': rhs} + result = lhs + return result, remaining + + def marker_and(remaining): + lhs, remaining = marker_expr(remaining) + while remaining: + m = AND.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_expr(remaining) + lhs = {'op': 'and', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + def marker(remaining): + lhs, remaining = marker_and(remaining) + while remaining: + m = OR.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_and(remaining) + lhs = {'op': 'or', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + return marker(marker_string) + + +def parse_requirement(req): + """ + Parse a requirement passed in as a string. Return a Container + whose attributes contain the various parts of the requirement. + """ + remaining = req.strip() + if not remaining or remaining.startswith('#'): + return None + m = IDENTIFIER.match(remaining) + if not m: + raise SyntaxError('name expected: %s' % remaining) + distname = m.groups()[0] + remaining = remaining[m.end():] + extras = mark_expr = versions = uri = None + if remaining and remaining[0] == '[': + i = remaining.find(']', 1) + if i < 0: + raise SyntaxError('unterminated extra: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + extras = [] + while s: + m = IDENTIFIER.match(s) + if not m: + raise SyntaxError('malformed extra: %s' % s) + extras.append(m.groups()[0]) + s = s[m.end():] + if not s: + break + if s[0] != ',': + raise SyntaxError('comma expected in extras: %s' % s) + s = s[1:].lstrip() + if not extras: + extras = None + if remaining: + if remaining[0] == '@': + # it's a URI + remaining = remaining[1:].lstrip() + m = NON_SPACE.match(remaining) + if not m: + raise SyntaxError('invalid URI: %s' % remaining) + uri = m.groups()[0] + t = urlparse(uri) + # there are issues with Python and URL parsing, so this test + # is a bit crude. See bpo-20271, bpo-23505. Python doesn't + # always parse invalid URLs correctly - it should raise + # exceptions for malformed URLs + if not (t.scheme and t.netloc): + raise SyntaxError('Invalid URL: %s' % uri) + remaining = remaining[m.end():].lstrip() + else: + + def get_versions(ver_remaining): + """ + Return a list of operator, version tuples if any are + specified, else None. + """ + m = COMPARE_OP.match(ver_remaining) + versions = None + if m: + versions = [] + while True: + op = m.groups()[0] + ver_remaining = ver_remaining[m.end():] + m = VERSION_IDENTIFIER.match(ver_remaining) + if not m: + raise SyntaxError('invalid version: %s' % ver_remaining) + v = m.groups()[0] + versions.append((op, v)) + ver_remaining = ver_remaining[m.end():] + if not ver_remaining or ver_remaining[0] != ',': + break + ver_remaining = ver_remaining[1:].lstrip() + m = COMPARE_OP.match(ver_remaining) + if not m: + raise SyntaxError('invalid constraint: %s' % ver_remaining) + if not versions: + versions = None + return versions, ver_remaining + + if remaining[0] != '(': + versions, remaining = get_versions(remaining) + else: + i = remaining.find(')', 1) + if i < 0: + raise SyntaxError('unterminated parenthesis: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + # As a special diversion from PEP 508, allow a version number + # a.b.c in parentheses as a synonym for ~= a.b.c (because this + # is allowed in earlier PEPs) + if COMPARE_OP.match(s): + versions, _ = get_versions(s) + else: + m = VERSION_IDENTIFIER.match(s) + if not m: + raise SyntaxError('invalid constraint: %s' % s) + v = m.groups()[0] + s = s[m.end():].lstrip() + if s: + raise SyntaxError('invalid constraint: %s' % s) + versions = [('~=', v)] + + if remaining: + if remaining[0] != ';': + raise SyntaxError('invalid requirement: %s' % remaining) + remaining = remaining[1:].lstrip() + + mark_expr, remaining = parse_marker(remaining) + + if remaining and remaining[0] != '#': + raise SyntaxError('unexpected trailing data: %s' % remaining) + + if not versions: + rs = distname + else: + rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions])) + return Container(name=distname, extras=extras, constraints=versions, + marker=mark_expr, url=uri, requirement=rs) + + +def get_resources_dests(resources_root, rules): + """Find destinations for resources files""" + + def get_rel_path(root, path): + # normalizes and returns a lstripped-/-separated path + root = root.replace(os.path.sep, '/') + path = path.replace(os.path.sep, '/') + assert path.startswith(root) + return path[len(root):].lstrip('/') + + destinations = {} + for base, suffix, dest in rules: + prefix = os.path.join(resources_root, base) + for abs_base in iglob(prefix): + abs_glob = os.path.join(abs_base, suffix) + for abs_path in iglob(abs_glob): + resource_file = get_rel_path(resources_root, abs_path) + if dest is None: # remove the entry if it was here + destinations.pop(resource_file, None) + else: + rel_path = get_rel_path(abs_base, abs_path) + rel_dest = dest.replace(os.path.sep, '/').rstrip('/') + destinations[resource_file] = rel_dest + '/' + rel_path + return destinations + + +def in_venv(): + if hasattr(sys, 'real_prefix'): + # virtualenv venvs + result = True + else: + # PEP 405 venvs + result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix) + return result + + +def get_executable(): +# The __PYVENV_LAUNCHER__ dance is apparently no longer needed, as +# changes to the stub launcher mean that sys.executable always points +# to the stub on OS X +# if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__' +# in os.environ): +# result = os.environ['__PYVENV_LAUNCHER__'] +# else: +# result = sys.executable +# return result + result = os.path.normcase(sys.executable) + if not isinstance(result, text_type): + result = fsdecode(result) + return result + + +def proceed(prompt, allowed_chars, error_prompt=None, default=None): + p = prompt + while True: + s = raw_input(p) + p = prompt + if not s and default: + s = default + if s: + c = s[0].lower() + if c in allowed_chars: + break + if error_prompt: + p = '%c: %s\n%s' % (c, error_prompt, prompt) + return c + + +def extract_by_key(d, keys): + if isinstance(keys, string_types): + keys = keys.split() + result = {} + for key in keys: + if key in d: + result[key] = d[key] + return result + +def read_exports(stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + # Try to load as JSON, falling back on legacy format + data = stream.read() + stream = StringIO(data) + try: + jdata = json.load(stream) + result = jdata['extensions']['python.exports']['exports'] + for group, entries in result.items(): + for k, v in entries.items(): + s = '%s = %s' % (k, v) + entry = get_export_entry(s) + assert entry is not None + entries[k] = entry + return result + except Exception: + stream.seek(0, 0) + + def read_stream(cp, stream): + if hasattr(cp, 'read_file'): + cp.read_file(stream) + else: + cp.readfp(stream) + + cp = configparser.ConfigParser() + try: + read_stream(cp, stream) + except configparser.MissingSectionHeaderError: + stream.close() + data = textwrap.dedent(data) + stream = StringIO(data) + read_stream(cp, stream) + + result = {} + for key in cp.sections(): + result[key] = entries = {} + for name, value in cp.items(key): + s = '%s = %s' % (name, value) + entry = get_export_entry(s) + assert entry is not None + #entry.dist = self + entries[name] = entry + return result + + +def write_exports(exports, stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getwriter('utf-8')(stream) + cp = configparser.ConfigParser() + for k, v in exports.items(): + # TODO check k, v for valid values + cp.add_section(k) + for entry in v.values(): + if entry.suffix is None: + s = entry.prefix + else: + s = '%s:%s' % (entry.prefix, entry.suffix) + if entry.flags: + s = '%s [%s]' % (s, ', '.join(entry.flags)) + cp.set(k, entry.name, s) + cp.write(stream) + + +@contextlib.contextmanager +def tempdir(): + td = tempfile.mkdtemp() + try: + yield td + finally: + shutil.rmtree(td) + +@contextlib.contextmanager +def chdir(d): + cwd = os.getcwd() + try: + os.chdir(d) + yield + finally: + os.chdir(cwd) + + +@contextlib.contextmanager +def socket_timeout(seconds=15): + cto = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(seconds) + yield + finally: + socket.setdefaulttimeout(cto) + + +class cached_property(object): + def __init__(self, func): + self.func = func + #for attr in ('__name__', '__module__', '__doc__'): + # setattr(self, attr, getattr(func, attr, None)) + + def __get__(self, obj, cls=None): + if obj is None: + return self + value = self.func(obj) + object.__setattr__(obj, self.func.__name__, value) + #obj.__dict__[self.func.__name__] = value = self.func(obj) + return value + +def convert_path(pathname): + """Return 'pathname' as a name that will work on the native filesystem. + + The path is split on '/' and put back together again using the current + directory separator. Needed because filenames in the setup script are + always supplied in Unix style, and have to be converted to the local + convention before we can actually use them in the filesystem. Raises + ValueError on non-Unix-ish systems if 'pathname' either starts or + ends with a slash. + """ + if os.sep == '/': + return pathname + if not pathname: + return pathname + if pathname[0] == '/': + raise ValueError("path '%s' cannot be absolute" % pathname) + if pathname[-1] == '/': + raise ValueError("path '%s' cannot end with '/'" % pathname) + + paths = pathname.split('/') + while os.curdir in paths: + paths.remove(os.curdir) + if not paths: + return os.curdir + return os.path.join(*paths) + + +class FileOperator(object): + def __init__(self, dry_run=False): + self.dry_run = dry_run + self.ensured = set() + self._init_record() + + def _init_record(self): + self.record = False + self.files_written = set() + self.dirs_created = set() + + def record_as_written(self, path): + if self.record: + self.files_written.add(path) + + def newer(self, source, target): + """Tell if the target is newer than the source. + + Returns true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. + + Returns false if both exist and 'target' is the same age or younger + than 'source'. Raise PackagingFileError if 'source' does not exist. + + Note that this test is not very accurate: files created in the same + second will have the same "age". + """ + if not os.path.exists(source): + raise DistlibException("file '%r' does not exist" % + os.path.abspath(source)) + if not os.path.exists(target): + return True + + return os.stat(source).st_mtime > os.stat(target).st_mtime + + def copy_file(self, infile, outfile, check=True): + """Copy a file respecting dry-run and force flags. + """ + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying %s to %s', infile, outfile) + if not self.dry_run: + msg = None + if check: + if os.path.islink(outfile): + msg = '%s is a symlink' % outfile + elif os.path.exists(outfile) and not os.path.isfile(outfile): + msg = '%s is a non-regular file' % outfile + if msg: + raise ValueError(msg + ' which would be overwritten') + shutil.copyfile(infile, outfile) + self.record_as_written(outfile) + + def copy_stream(self, instream, outfile, encoding=None): + assert not os.path.isdir(outfile) + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying stream %s to %s', instream, outfile) + if not self.dry_run: + if encoding is None: + outstream = open(outfile, 'wb') + else: + outstream = codecs.open(outfile, 'w', encoding=encoding) + try: + shutil.copyfileobj(instream, outstream) + finally: + outstream.close() + self.record_as_written(outfile) + + def write_binary_file(self, path, data): + self.ensure_dir(os.path.dirname(path)) + if not self.dry_run: + with open(path, 'wb') as f: + f.write(data) + self.record_as_written(path) + + def write_text_file(self, path, data, encoding): + self.ensure_dir(os.path.dirname(path)) + if not self.dry_run: + with open(path, 'wb') as f: + f.write(data.encode(encoding)) + self.record_as_written(path) + + def set_mode(self, bits, mask, files): + if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'): + # Set the executable bits (owner, group, and world) on + # all the files specified. + for f in files: + if self.dry_run: + logger.info("changing mode of %s", f) + else: + mode = (os.stat(f).st_mode | bits) & mask + logger.info("changing mode of %s to %o", f, mode) + os.chmod(f, mode) + + set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f) + + def ensure_dir(self, path): + path = os.path.abspath(path) + if path not in self.ensured and not os.path.exists(path): + self.ensured.add(path) + d, f = os.path.split(path) + self.ensure_dir(d) + logger.info('Creating %s' % path) + if not self.dry_run: + os.mkdir(path) + if self.record: + self.dirs_created.add(path) + + def byte_compile(self, path, optimize=False, force=False, prefix=None): + dpath = cache_from_source(path, not optimize) + logger.info('Byte-compiling %s to %s', path, dpath) + if not self.dry_run: + if force or self.newer(path, dpath): + if not prefix: + diagpath = None + else: + assert path.startswith(prefix) + diagpath = path[len(prefix):] + py_compile.compile(path, dpath, diagpath, True) # raise error + self.record_as_written(dpath) + return dpath + + def ensure_removed(self, path): + if os.path.exists(path): + if os.path.isdir(path) and not os.path.islink(path): + logger.debug('Removing directory tree at %s', path) + if not self.dry_run: + shutil.rmtree(path) + if self.record: + if path in self.dirs_created: + self.dirs_created.remove(path) + else: + if os.path.islink(path): + s = 'link' + else: + s = 'file' + logger.debug('Removing %s %s', s, path) + if not self.dry_run: + os.remove(path) + if self.record: + if path in self.files_written: + self.files_written.remove(path) + + def is_writable(self, path): + result = False + while not result: + if os.path.exists(path): + result = os.access(path, os.W_OK) + break + parent = os.path.dirname(path) + if parent == path: + break + path = parent + return result + + def commit(self): + """ + Commit recorded changes, turn off recording, return + changes. + """ + assert self.record + result = self.files_written, self.dirs_created + self._init_record() + return result + + def rollback(self): + if not self.dry_run: + for f in list(self.files_written): + if os.path.exists(f): + os.remove(f) + # dirs should all be empty now, except perhaps for + # __pycache__ subdirs + # reverse so that subdirs appear before their parents + dirs = sorted(self.dirs_created, reverse=True) + for d in dirs: + flist = os.listdir(d) + if flist: + assert flist == ['__pycache__'] + sd = os.path.join(d, flist[0]) + os.rmdir(sd) + os.rmdir(d) # should fail if non-empty + self._init_record() + +def resolve(module_name, dotted_path): + if module_name in sys.modules: + mod = sys.modules[module_name] + else: + mod = __import__(module_name) + if dotted_path is None: + result = mod + else: + parts = dotted_path.split('.') + result = getattr(mod, parts.pop(0)) + for p in parts: + result = getattr(result, p) + return result + + +class ExportEntry(object): + def __init__(self, name, prefix, suffix, flags): + self.name = name + self.prefix = prefix + self.suffix = suffix + self.flags = flags + + @cached_property + def value(self): + return resolve(self.prefix, self.suffix) + + def __repr__(self): # pragma: no cover + return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix, + self.suffix, self.flags) + + def __eq__(self, other): + if not isinstance(other, ExportEntry): + result = False + else: + result = (self.name == other.name and + self.prefix == other.prefix and + self.suffix == other.suffix and + self.flags == other.flags) + return result + + __hash__ = object.__hash__ + + +ENTRY_RE = re.compile(r'''(?P<name>(\w|[-.+])+) + \s*=\s*(?P<callable>(\w+)([:\.]\w+)*) + \s*(\[\s*(?P<flags>\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])? + ''', re.VERBOSE) + +def get_export_entry(specification): + m = ENTRY_RE.search(specification) + if not m: + result = None + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + else: + d = m.groupdict() + name = d['name'] + path = d['callable'] + colons = path.count(':') + if colons == 0: + prefix, suffix = path, None + else: + if colons != 1: + raise DistlibException("Invalid specification " + "'%s'" % specification) + prefix, suffix = path.split(':') + flags = d['flags'] + if flags is None: + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + flags = [] + else: + flags = [f.strip() for f in flags.split(',')] + result = ExportEntry(name, prefix, suffix, flags) + return result + + +def get_cache_base(suffix=None): + """ + Return the default base location for distlib caches. If the directory does + not exist, it is created. Use the suffix provided for the base directory, + and default to '.distlib' if it isn't provided. + + On Windows, if LOCALAPPDATA is defined in the environment, then it is + assumed to be a directory, and will be the parent directory of the result. + On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home + directory - using os.expanduser('~') - will be the parent directory of + the result. + + The result is just the directory '.distlib' in the parent directory as + determined above, or with the name specified with ``suffix``. + """ + if suffix is None: + suffix = '.distlib' + if os.name == 'nt' and 'LOCALAPPDATA' in os.environ: + result = os.path.expandvars('$localappdata') + else: + # Assume posix, or old Windows + result = os.path.expanduser('~') + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if os.path.isdir(result): + usable = os.access(result, os.W_OK) + if not usable: + logger.warning('Directory exists but is not writable: %s', result) + else: + try: + os.makedirs(result) + usable = True + except OSError: + logger.warning('Unable to create %s', result, exc_info=True) + usable = False + if not usable: + result = tempfile.mkdtemp() + logger.warning('Default location unusable, using %s', result) + return os.path.join(result, suffix) + + +def path_to_cache_dir(path): + """ + Convert an absolute path to a directory name for use in a cache. + + The algorithm used is: + + #. On Windows, any ``':'`` in the drive is replaced with ``'---'``. + #. Any occurrence of ``os.sep`` is replaced with ``'--'``. + #. ``'.cache'`` is appended. + """ + d, p = os.path.splitdrive(os.path.abspath(path)) + if d: + d = d.replace(':', '---') + p = p.replace(os.sep, '--') + return d + p + '.cache' + + +def ensure_slash(s): + if not s.endswith('/'): + return s + '/' + return s + + +def parse_credentials(netloc): + username = password = None + if '@' in netloc: + prefix, netloc = netloc.split('@', 1) + if ':' not in prefix: + username = prefix + else: + username, password = prefix.split(':', 1) + return username, password, netloc + + +def get_process_umask(): + result = os.umask(0o22) + os.umask(result) + return result + +def is_string_sequence(seq): + result = True + i = None + for i, s in enumerate(seq): + if not isinstance(s, string_types): + result = False + break + assert i is not None + return result + +PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-' + '([a-z0-9_.+-]+)', re.I) +PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)') + + +def split_filename(filename, project_name=None): + """ + Extract name, version, python version from a filename (no extension) + + Return name, version, pyver or None + """ + result = None + pyver = None + filename = unquote(filename).replace(' ', '-') + m = PYTHON_VERSION.search(filename) + if m: + pyver = m.group(1) + filename = filename[:m.start()] + if project_name and len(filename) > len(project_name) + 1: + m = re.match(re.escape(project_name) + r'\b', filename) + if m: + n = m.end() + result = filename[:n], filename[n + 1:], pyver + if result is None: + m = PROJECT_NAME_AND_VERSION.match(filename) + if m: + result = m.group(1), m.group(3), pyver + return result + +# Allow spaces in name because of legacy dists like "Twisted Core" +NAME_VERSION_RE = re.compile(r'(?P<name>[\w .-]+)\s*' + r'\(\s*(?P<ver>[^\s)]+)\)$') + +def parse_name_and_version(p): + """ + A utility method used to get name and version from a string. + + From e.g. a Provides-Dist value. + + :param p: A value in a form 'foo (1.0)' + :return: The name and version as a tuple. + """ + m = NAME_VERSION_RE.match(p) + if not m: + raise DistlibException('Ill-formed name/version string: \'%s\'' % p) + d = m.groupdict() + return d['name'].strip().lower(), d['ver'] + +def get_extras(requested, available): + result = set() + requested = set(requested or []) + available = set(available or []) + if '*' in requested: + requested.remove('*') + result |= available + for r in requested: + if r == '-': + result.add(r) + elif r.startswith('-'): + unwanted = r[1:] + if unwanted not in available: + logger.warning('undeclared extra: %s' % unwanted) + if unwanted in result: + result.remove(unwanted) + else: + if r not in available: + logger.warning('undeclared extra: %s' % r) + result.add(r) + return result +# +# Extended metadata functionality +# + +def _get_external_data(url): + result = {} + try: + # urlopen might fail if it runs into redirections, + # because of Python issue #13696. Fixed in locators + # using a custom redirect handler. + resp = urlopen(url) + headers = resp.info() + ct = headers.get('Content-Type') + if not ct.startswith('application/json'): + logger.debug('Unexpected response for JSON request: %s', ct) + else: + reader = codecs.getreader('utf-8')(resp) + #data = reader.read().decode('utf-8') + #result = json.loads(data) + result = json.load(reader) + except Exception as e: + logger.exception('Failed to get external data for %s: %s', url, e) + return result + +_external_data_base_url = 'https://www.red-dove.com/pypi/projects/' + +def get_project_data(name): + url = '%s/%s/project.json' % (name[0].upper(), name) + url = urljoin(_external_data_base_url, url) + result = _get_external_data(url) + return result + +def get_package_data(name, version): + url = '%s/%s/package-%s.json' % (name[0].upper(), name, version) + url = urljoin(_external_data_base_url, url) + return _get_external_data(url) + + +class Cache(object): + """ + A class implementing a cache for resources that need to live in the file system + e.g. shared libraries. This class was moved from resources to here because it + could be used by other modules, e.g. the wheel module. + """ + + def __init__(self, base): + """ + Initialise an instance. + + :param base: The base directory where the cache should be located. + """ + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if not os.path.isdir(base): # pragma: no cover + os.makedirs(base) + if (os.stat(base).st_mode & 0o77) != 0: + logger.warning('Directory \'%s\' is not private', base) + self.base = os.path.abspath(os.path.normpath(base)) + + def prefix_to_dir(self, prefix): + """ + Converts a resource prefix to a directory name in the cache. + """ + return path_to_cache_dir(prefix) + + def clear(self): + """ + Clear the cache. + """ + not_removed = [] + for fn in os.listdir(self.base): + fn = os.path.join(self.base, fn) + try: + if os.path.islink(fn) or os.path.isfile(fn): + os.remove(fn) + elif os.path.isdir(fn): + shutil.rmtree(fn) + except Exception: + not_removed.append(fn) + return not_removed + + +class EventMixin(object): + """ + A very simple publish/subscribe system. + """ + def __init__(self): + self._subscribers = {} + + def add(self, event, subscriber, append=True): + """ + Add a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be added (and called when the + event is published). + :param append: Whether to append or prepend the subscriber to an + existing subscriber list for the event. + """ + subs = self._subscribers + if event not in subs: + subs[event] = deque([subscriber]) + else: + sq = subs[event] + if append: + sq.append(subscriber) + else: + sq.appendleft(subscriber) + + def remove(self, event, subscriber): + """ + Remove a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be removed. + """ + subs = self._subscribers + if event not in subs: + raise ValueError('No subscribers: %r' % event) + subs[event].remove(subscriber) + + def get_subscribers(self, event): + """ + Return an iterator for the subscribers for an event. + :param event: The event to return subscribers for. + """ + return iter(self._subscribers.get(event, ())) + + def publish(self, event, *args, **kwargs): + """ + Publish a event and return a list of values returned by its + subscribers. + + :param event: The event to publish. + :param args: The positional arguments to pass to the event's + subscribers. + :param kwargs: The keyword arguments to pass to the event's + subscribers. + """ + result = [] + for subscriber in self.get_subscribers(event): + try: + value = subscriber(event, *args, **kwargs) + except Exception: + logger.exception('Exception during event publication') + value = None + result.append(value) + logger.debug('publish %s: args = %s, kwargs = %s, result = %s', + event, args, kwargs, result) + return result + +# +# Simple sequencing +# +class Sequencer(object): + def __init__(self): + self._preds = {} + self._succs = {} + self._nodes = set() # nodes with no preds/succs + + def add_node(self, node): + self._nodes.add(node) + + def remove_node(self, node, edges=False): + if node in self._nodes: + self._nodes.remove(node) + if edges: + for p in set(self._preds.get(node, ())): + self.remove(p, node) + for s in set(self._succs.get(node, ())): + self.remove(node, s) + # Remove empties + for k, v in list(self._preds.items()): + if not v: + del self._preds[k] + for k, v in list(self._succs.items()): + if not v: + del self._succs[k] + + def add(self, pred, succ): + assert pred != succ + self._preds.setdefault(succ, set()).add(pred) + self._succs.setdefault(pred, set()).add(succ) + + def remove(self, pred, succ): + assert pred != succ + try: + preds = self._preds[succ] + succs = self._succs[pred] + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of anything' % succ) + try: + preds.remove(pred) + succs.remove(succ) + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of %r' % (succ, pred)) + + def is_step(self, step): + return (step in self._preds or step in self._succs or + step in self._nodes) + + def get_steps(self, final): + if not self.is_step(final): + raise ValueError('Unknown: %r' % final) + result = [] + todo = [] + seen = set() + todo.append(final) + while todo: + step = todo.pop(0) + if step in seen: + # if a step was already seen, + # move it to the end (so it will appear earlier + # when reversed on return) ... but not for the + # final step, as that would be confusing for + # users + if step != final: + result.remove(step) + result.append(step) + else: + seen.add(step) + result.append(step) + preds = self._preds.get(step, ()) + todo.extend(preds) + return reversed(result) + + @property + def strong_connections(self): + #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + index_counter = [0] + stack = [] + lowlinks = {} + index = {} + result = [] + + graph = self._succs + + def strongconnect(node): + # set the depth index for this node to the smallest unused index + index[node] = index_counter[0] + lowlinks[node] = index_counter[0] + index_counter[0] += 1 + stack.append(node) + + # Consider successors + try: + successors = graph[node] + except Exception: + successors = [] + for successor in successors: + if successor not in lowlinks: + # Successor has not yet been visited + strongconnect(successor) + lowlinks[node] = min(lowlinks[node],lowlinks[successor]) + elif successor in stack: + # the successor is in the stack and hence in the current + # strongly connected component (SCC) + lowlinks[node] = min(lowlinks[node],index[successor]) + + # If `node` is a root node, pop the stack and generate an SCC + if lowlinks[node] == index[node]: + connected_component = [] + + while True: + successor = stack.pop() + connected_component.append(successor) + if successor == node: break + component = tuple(connected_component) + # storing the result + result.append(component) + + for node in graph: + if node not in lowlinks: + strongconnect(node) + + return result + + @property + def dot(self): + result = ['digraph G {'] + for succ in self._preds: + preds = self._preds[succ] + for pred in preds: + result.append(' %s -> %s;' % (pred, succ)) + for node in self._nodes: + result.append(' %s;' % node) + result.append('}') + return '\n'.join(result) + +# +# Unarchiving functionality for zip, tar, tgz, tbz, whl +# + +ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', + '.tgz', '.tbz', '.whl') + +def unarchive(archive_filename, dest_dir, format=None, check=True): + + def check_path(path): + if not isinstance(path, text_type): + path = path.decode('utf-8') + p = os.path.abspath(os.path.join(dest_dir, path)) + if not p.startswith(dest_dir) or p[plen] != os.sep: + raise ValueError('path outside destination: %r' % p) + + dest_dir = os.path.abspath(dest_dir) + plen = len(dest_dir) + archive = None + if format is None: + if archive_filename.endswith(('.zip', '.whl')): + format = 'zip' + elif archive_filename.endswith(('.tar.gz', '.tgz')): + format = 'tgz' + mode = 'r:gz' + elif archive_filename.endswith(('.tar.bz2', '.tbz')): + format = 'tbz' + mode = 'r:bz2' + elif archive_filename.endswith('.tar'): + format = 'tar' + mode = 'r' + else: # pragma: no cover + raise ValueError('Unknown format for %r' % archive_filename) + try: + if format == 'zip': + archive = ZipFile(archive_filename, 'r') + if check: + names = archive.namelist() + for name in names: + check_path(name) + else: + archive = tarfile.open(archive_filename, mode) + if check: + names = archive.getnames() + for name in names: + check_path(name) + if format != 'zip' and sys.version_info[0] < 3: + # See Python issue 17153. If the dest path contains Unicode, + # tarfile extraction fails on Python 2.x if a member path name + # contains non-ASCII characters - it leads to an implicit + # bytes -> unicode conversion using ASCII to decode. + for tarinfo in archive.getmembers(): + if not isinstance(tarinfo.name, text_type): + tarinfo.name = tarinfo.name.decode('utf-8') + archive.extractall(dest_dir) + + finally: + if archive: + archive.close() + + +def zip_dir(directory): + """zip a directory tree into a BytesIO object""" + result = io.BytesIO() + dlen = len(directory) + with ZipFile(result, "w") as zf: + for root, dirs, files in os.walk(directory): + for name in files: + full = os.path.join(root, name) + rel = root[dlen:] + dest = os.path.join(rel, name) + zf.write(full, dest) + return result + +# +# Simple progress bar +# + +UNITS = ('', 'K', 'M', 'G','T','P') + + +class Progress(object): + unknown = 'UNKNOWN' + + def __init__(self, minval=0, maxval=100): + assert maxval is None or maxval >= minval + self.min = self.cur = minval + self.max = maxval + self.started = None + self.elapsed = 0 + self.done = False + + def update(self, curval): + assert self.min <= curval + assert self.max is None or curval <= self.max + self.cur = curval + now = time.time() + if self.started is None: + self.started = now + else: + self.elapsed = now - self.started + + def increment(self, incr): + assert incr >= 0 + self.update(self.cur + incr) + + def start(self): + self.update(self.min) + return self + + def stop(self): + if self.max is not None: + self.update(self.max) + self.done = True + + @property + def maximum(self): + return self.unknown if self.max is None else self.max + + @property + def percentage(self): + if self.done: + result = '100 %' + elif self.max is None: + result = ' ?? %' + else: + v = 100.0 * (self.cur - self.min) / (self.max - self.min) + result = '%3d %%' % v + return result + + def format_duration(self, duration): + if (duration <= 0) and self.max is None or self.cur == self.min: + result = '??:??:??' + #elif duration < 1: + # result = '--:--:--' + else: + result = time.strftime('%H:%M:%S', time.gmtime(duration)) + return result + + @property + def ETA(self): + if self.done: + prefix = 'Done' + t = self.elapsed + #import pdb; pdb.set_trace() + else: + prefix = 'ETA ' + if self.max is None: + t = -1 + elif self.elapsed == 0 or (self.cur == self.min): + t = 0 + else: + #import pdb; pdb.set_trace() + t = float(self.max - self.min) + t /= self.cur - self.min + t = (t - 1) * self.elapsed + return '%s: %s' % (prefix, self.format_duration(t)) + + @property + def speed(self): + if self.elapsed == 0: + result = 0.0 + else: + result = (self.cur - self.min) / self.elapsed + for unit in UNITS: + if result < 1000: + break + result /= 1000.0 + return '%d %sB/s' % (result, unit) + +# +# Glob functionality +# + +RICH_GLOB = re.compile(r'\{([^}]*)\}') +_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]') +_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$') + + +def iglob(path_glob): + """Extended globbing function that supports ** and {opt1,opt2,opt3}.""" + if _CHECK_RECURSIVE_GLOB.search(path_glob): + msg = """invalid glob %r: recursive glob "**" must be used alone""" + raise ValueError(msg % path_glob) + if _CHECK_MISMATCH_SET.search(path_glob): + msg = """invalid glob %r: mismatching set marker '{' or '}'""" + raise ValueError(msg % path_glob) + return _iglob(path_glob) + + +def _iglob(path_glob): + rich_path_glob = RICH_GLOB.split(path_glob, 1) + if len(rich_path_glob) > 1: + assert len(rich_path_glob) == 3, rich_path_glob + prefix, set, suffix = rich_path_glob + for item in set.split(','): + for path in _iglob(''.join((prefix, item, suffix))): + yield path + else: + if '**' not in path_glob: + for item in std_iglob(path_glob): + yield item + else: + prefix, radical = path_glob.split('**', 1) + if prefix == '': + prefix = '.' + if radical == '': + radical = '*' + else: + # we support both + radical = radical.lstrip('/') + radical = radical.lstrip('\\') + for path, dir, files in os.walk(prefix): + path = os.path.normpath(path) + for fn in _iglob(os.path.join(path, radical)): + yield fn + +if ssl: + from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname, + CertificateError) + + +# +# HTTPSConnection which verifies certificates/matches domains +# + + class HTTPSConnection(httplib.HTTPSConnection): + ca_certs = None # set this to the path to the certs file (.pem) + check_domain = True # only used if ca_certs is not None + + # noinspection PyPropertyAccess + def connect(self): + sock = socket.create_connection((self.host, self.port), self.timeout) + if getattr(self, '_tunnel_host', False): + self.sock = sock + self._tunnel() + + if not hasattr(ssl, 'SSLContext'): + # For 2.x + if self.ca_certs: + cert_reqs = ssl.CERT_REQUIRED + else: + cert_reqs = ssl.CERT_NONE + self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, + cert_reqs=cert_reqs, + ssl_version=ssl.PROTOCOL_SSLv23, + ca_certs=self.ca_certs) + else: # pragma: no cover + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + context.options |= ssl.OP_NO_SSLv2 + if self.cert_file: + context.load_cert_chain(self.cert_file, self.key_file) + kwargs = {} + if self.ca_certs: + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(cafile=self.ca_certs) + if getattr(ssl, 'HAS_SNI', False): + kwargs['server_hostname'] = self.host + self.sock = context.wrap_socket(sock, **kwargs) + if self.ca_certs and self.check_domain: + try: + match_hostname(self.sock.getpeercert(), self.host) + logger.debug('Host verified: %s', self.host) + except CertificateError: # pragma: no cover + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + + class HTTPSHandler(BaseHTTPSHandler): + def __init__(self, ca_certs, check_domain=True): + BaseHTTPSHandler.__init__(self) + self.ca_certs = ca_certs + self.check_domain = check_domain + + def _conn_maker(self, *args, **kwargs): + """ + This is called to create a connection instance. Normally you'd + pass a connection class to do_open, but it doesn't actually check for + a class, and just expects a callable. As long as we behave just as a + constructor would have, we should be OK. If it ever changes so that + we *must* pass a class, we'll create an UnsafeHTTPSConnection class + which just sets check_domain to False in the class definition, and + choose which one to pass to do_open. + """ + result = HTTPSConnection(*args, **kwargs) + if self.ca_certs: + result.ca_certs = self.ca_certs + result.check_domain = self.check_domain + return result + + def https_open(self, req): + try: + return self.do_open(self._conn_maker, req) + except URLError as e: + if 'certificate verify failed' in str(e.reason): + raise CertificateError('Unable to verify server certificate ' + 'for %s' % req.host) + else: + raise + + # + # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The- + # Middle proxy using HTTP listens on port 443, or an index mistakenly serves + # HTML containing a http://xyz link when it should be https://xyz), + # you can use the following handler class, which does not allow HTTP traffic. + # + # It works by inheriting from HTTPHandler - so build_opener won't add a + # handler for HTTP itself. + # + class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler): + def http_open(self, req): + raise URLError('Unexpected HTTP request on what should be a secure ' + 'connection: %s' % req) + +# +# XML-RPC with timeouts +# + +_ver_info = sys.version_info[:2] + +if _ver_info == (2, 6): + class HTTP(httplib.HTTP): + def __init__(self, host='', port=None, **kwargs): + if port == 0: # 0 means use port 0, not the default port + port = None + self._setup(self._connection_class(host, port, **kwargs)) + + + if ssl: + class HTTPS(httplib.HTTPS): + def __init__(self, host='', port=None, **kwargs): + if port == 0: # 0 means use port 0, not the default port + port = None + self._setup(self._connection_class(host, port, **kwargs)) + + +class Transport(xmlrpclib.Transport): + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.Transport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, x509 = self.get_host_info(host) + if _ver_info == (2, 6): + result = HTTP(h, timeout=self.timeout) + else: + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPConnection(h) + result = self._connection[1] + return result + +if ssl: + class SafeTransport(xmlrpclib.SafeTransport): + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.SafeTransport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, kwargs = self.get_host_info(host) + if not kwargs: + kwargs = {} + kwargs['timeout'] = self.timeout + if _ver_info == (2, 6): + result = HTTPS(host, None, **kwargs) + else: + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPSConnection(h, None, + **kwargs) + result = self._connection[1] + return result + + +class ServerProxy(xmlrpclib.ServerProxy): + def __init__(self, uri, **kwargs): + self.timeout = timeout = kwargs.pop('timeout', None) + # The above classes only come into play if a timeout + # is specified + if timeout is not None: + scheme, _ = splittype(uri) + use_datetime = kwargs.get('use_datetime', 0) + if scheme == 'https': + tcls = SafeTransport + else: + tcls = Transport + kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime) + self.transport = t + xmlrpclib.ServerProxy.__init__(self, uri, **kwargs) + +# +# CSV functionality. This is provided because on 2.x, the csv module can't +# handle Unicode. However, we need to deal with Unicode in e.g. RECORD files. +# + +def _csv_open(fn, mode, **kwargs): + if sys.version_info[0] < 3: + mode += 'b' + else: + kwargs['newline'] = '' + # Python 3 determines encoding from locale. Force 'utf-8' + # file encoding to match other forced utf-8 encoding + kwargs['encoding'] = 'utf-8' + return open(fn, mode, **kwargs) + + +class CSVBase(object): + defaults = { + 'delimiter': str(','), # The strs are used because we need native + 'quotechar': str('"'), # str in the csv API (2.x won't take + 'lineterminator': str('\n') # Unicode) + } + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.stream.close() + + +class CSVReader(CSVBase): + def __init__(self, **kwargs): + if 'stream' in kwargs: + stream = kwargs['stream'] + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + self.stream = stream + else: + self.stream = _csv_open(kwargs['path'], 'r') + self.reader = csv.reader(self.stream, **self.defaults) + + def __iter__(self): + return self + + def next(self): + result = next(self.reader) + if sys.version_info[0] < 3: + for i, item in enumerate(result): + if not isinstance(item, text_type): + result[i] = item.decode('utf-8') + return result + + __next__ = next + +class CSVWriter(CSVBase): + def __init__(self, fn, **kwargs): + self.stream = _csv_open(fn, 'w') + self.writer = csv.writer(self.stream, **self.defaults) + + def writerow(self, row): + if sys.version_info[0] < 3: + r = [] + for item in row: + if isinstance(item, text_type): + item = item.encode('utf-8') + r.append(item) + row = r + self.writer.writerow(row) + +# +# Configurator functionality +# + +class Configurator(BaseConfigurator): + + value_converters = dict(BaseConfigurator.value_converters) + value_converters['inc'] = 'inc_convert' + + def __init__(self, config, base=None): + super(Configurator, self).__init__(config) + self.base = base or os.getcwd() + + def configure_custom(self, config): + def convert(o): + if isinstance(o, (list, tuple)): + result = type(o)([convert(i) for i in o]) + elif isinstance(o, dict): + if '()' in o: + result = self.configure_custom(o) + else: + result = {} + for k in o: + result[k] = convert(o[k]) + else: + result = self.convert(o) + return result + + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + args = config.pop('[]', ()) + if args: + args = tuple([convert(o) for o in args]) + items = [(k, convert(config[k])) for k in config if valid_ident(k)] + kwargs = dict(items) + result = c(*args, **kwargs) + if props: + for n, v in props.items(): + setattr(result, n, convert(v)) + return result + + def __getitem__(self, key): + result = self.config[key] + if isinstance(result, dict) and '()' in result: + self.config[key] = result = self.configure_custom(result) + return result + + def inc_convert(self, value): + """Default converter for the inc:// protocol.""" + if not os.path.isabs(value): + value = os.path.join(self.base, value) + with codecs.open(value, 'r', encoding='utf-8') as f: + result = json.load(f) + return result + + +class SubprocessMixin(object): + """ + Mixin for running subprocesses and capturing their output + """ + def __init__(self, verbose=False, progress=None): + self.verbose = verbose + self.progress = progress + + def reader(self, stream, context): + """ + Read lines from a subprocess' output stream and either pass to a progress + callable (if specified) or write progress information to sys.stderr. + """ + progress = self.progress + verbose = self.verbose + while True: + s = stream.readline() + if not s: + break + if progress is not None: + progress(s, context) + else: + if not verbose: + sys.stderr.write('.') + else: + sys.stderr.write(s.decode('utf-8')) + sys.stderr.flush() + stream.close() + + def run_command(self, cmd, **kwargs): + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, **kwargs) + t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout')) + t1.start() + t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr')) + t2.start() + p.wait() + t1.join() + t2.join() + if self.progress is not None: + self.progress('done.', 'main') + elif self.verbose: + sys.stderr.write('done.\n') + return p + + +def normalize_name(name): + """Normalize a python package name a la PEP 503""" + # https://www.python.org/dev/peps/pep-0503/#normalized-names + return re.sub('[-_.]+', '-', name).lower() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py new file mode 100755 index 0000000..959f153 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py @@ -0,0 +1,736 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Implementation of a flexible versioning scheme providing support for PEP-440, +setuptools-compatible and semantic versioning. +""" + +import logging +import re + +from .compat import string_types +from .util import parse_requirement + +__all__ = ['NormalizedVersion', 'NormalizedMatcher', + 'LegacyVersion', 'LegacyMatcher', + 'SemanticVersion', 'SemanticMatcher', + 'UnsupportedVersionError', 'get_scheme'] + +logger = logging.getLogger(__name__) + + +class UnsupportedVersionError(ValueError): + """This is an unsupported version.""" + pass + + +class Version(object): + def __init__(self, s): + self._string = s = s.strip() + self._parts = parts = self.parse(s) + assert isinstance(parts, tuple) + assert len(parts) > 0 + + def parse(self, s): + raise NotImplementedError('please implement in a subclass') + + def _check_compatible(self, other): + if type(self) != type(other): + raise TypeError('cannot compare %r and %r' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + def __lt__(self, other): + self._check_compatible(other) + return self._parts < other._parts + + def __gt__(self, other): + return not (self.__lt__(other) or self.__eq__(other)) + + def __le__(self, other): + return self.__lt__(other) or self.__eq__(other) + + def __ge__(self, other): + return self.__gt__(other) or self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self._parts) + + def __repr__(self): + return "%s('%s')" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + @property + def is_prerelease(self): + raise NotImplementedError('Please implement in subclasses.') + + +class Matcher(object): + version_class = None + + # value is either a callable or the name of a method + _operators = { + '<': lambda v, c, p: v < c, + '>': lambda v, c, p: v > c, + '<=': lambda v, c, p: v == c or v < c, + '>=': lambda v, c, p: v == c or v > c, + '==': lambda v, c, p: v == c, + '===': lambda v, c, p: v == c, + # by default, compatible => >=. + '~=': lambda v, c, p: v == c or v > c, + '!=': lambda v, c, p: v != c, + } + + # this is a method only to support alternative implementations + # via overriding + def parse_requirement(self, s): + return parse_requirement(s) + + def __init__(self, s): + if self.version_class is None: + raise ValueError('Please specify a version class') + self._string = s = s.strip() + r = self.parse_requirement(s) + if not r: + raise ValueError('Not valid: %r' % s) + self.name = r.name + self.key = self.name.lower() # for case-insensitive comparisons + clist = [] + if r.constraints: + # import pdb; pdb.set_trace() + for op, s in r.constraints: + if s.endswith('.*'): + if op not in ('==', '!='): + raise ValueError('\'.*\' not allowed for ' + '%r constraints' % op) + # Could be a partial version (e.g. for '2.*') which + # won't parse as a version, so keep it as a string + vn, prefix = s[:-2], True + # Just to check that vn is a valid version + self.version_class(vn) + else: + # Should parse as a version, so we can create an + # instance for the comparison + vn, prefix = self.version_class(s), False + clist.append((op, vn, prefix)) + self._parts = tuple(clist) + + def match(self, version): + """ + Check if the provided version matches the constraints. + + :param version: The version to match against this instance. + :type version: String or :class:`Version` instance. + """ + if isinstance(version, string_types): + version = self.version_class(version) + for operator, constraint, prefix in self._parts: + f = self._operators.get(operator) + if isinstance(f, string_types): + f = getattr(self, f) + if not f: + msg = ('%r not implemented ' + 'for %s' % (operator, self.__class__.__name__)) + raise NotImplementedError(msg) + if not f(version, constraint, prefix): + return False + return True + + @property + def exact_version(self): + result = None + if len(self._parts) == 1 and self._parts[0][0] in ('==', '==='): + result = self._parts[0][1] + return result + + def _check_compatible(self, other): + if type(self) != type(other) or self.name != other.name: + raise TypeError('cannot compare %s and %s' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self.key == other.key and self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self.key) + hash(self._parts) + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + +PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|b|c|rc)(\d+))?' + r'(\.(post)(\d+))?(\.(dev)(\d+))?' + r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$') + + +def _pep_440_key(s): + s = s.strip() + m = PEP440_VERSION_RE.match(s) + if not m: + raise UnsupportedVersionError('Not a valid version: %s' % s) + groups = m.groups() + nums = tuple(int(v) for v in groups[1].split('.')) + while len(nums) > 1 and nums[-1] == 0: + nums = nums[:-1] + + if not groups[0]: + epoch = 0 + else: + epoch = int(groups[0]) + pre = groups[4:6] + post = groups[7:9] + dev = groups[10:12] + local = groups[13] + if pre == (None, None): + pre = () + else: + pre = pre[0], int(pre[1]) + if post == (None, None): + post = () + else: + post = post[0], int(post[1]) + if dev == (None, None): + dev = () + else: + dev = dev[0], int(dev[1]) + if local is None: + local = () + else: + parts = [] + for part in local.split('.'): + # to ensure that numeric compares as > lexicographic, avoid + # comparing them directly, but encode a tuple which ensures + # correct sorting + if part.isdigit(): + part = (1, int(part)) + else: + part = (0, part) + parts.append(part) + local = tuple(parts) + if not pre: + # either before pre-release, or final release and after + if not post and dev: + # before pre-release + pre = ('a', -1) # to sort before a0 + else: + pre = ('z',) # to sort after all pre-releases + # now look at the state of post and dev. + if not post: + post = ('_',) # sort before 'a' + if not dev: + dev = ('final',) + + #print('%s -> %s' % (s, m.groups())) + return epoch, nums, pre, post, dev, local + + +_normalized_key = _pep_440_key + + +class NormalizedVersion(Version): + """A rational version. + + Good: + 1.2 # equivalent to "1.2.0" + 1.2.0 + 1.2a1 + 1.2.3a2 + 1.2.3b1 + 1.2.3c1 + 1.2.3.4 + TODO: fill this out + + Bad: + 1 # minimum two numbers + 1.2a # release level must have a release serial + 1.2.3b + """ + def parse(self, s): + result = _normalized_key(s) + # _normalized_key loses trailing zeroes in the release + # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0 + # However, PEP 440 prefix matching needs it: for example, + # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0). + m = PEP440_VERSION_RE.match(s) # must succeed + groups = m.groups() + self._release_clause = tuple(int(v) for v in groups[1].split('.')) + return result + + PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev']) + + @property + def is_prerelease(self): + return any(t[0] in self.PREREL_TAGS for t in self._parts if t) + + +def _match_prefix(x, y): + x = str(x) + y = str(y) + if x == y: + return True + if not x.startswith(y): + return False + n = len(y) + return x[n] == '.' + + +class NormalizedMatcher(Matcher): + version_class = NormalizedVersion + + # value is either a callable or the name of a method + _operators = { + '~=': '_match_compatible', + '<': '_match_lt', + '>': '_match_gt', + '<=': '_match_le', + '>=': '_match_ge', + '==': '_match_eq', + '===': '_match_arbitrary', + '!=': '_match_ne', + } + + def _adjust_local(self, version, constraint, prefix): + if prefix: + strip_local = '+' not in constraint and version._parts[-1] + else: + # both constraint and version are + # NormalizedVersion instances. + # If constraint does not have a local component, + # ensure the version doesn't, either. + strip_local = not constraint._parts[-1] and version._parts[-1] + if strip_local: + s = version._string.split('+', 1)[0] + version = self.version_class(s) + return version, constraint + + def _match_lt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version >= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_gt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version <= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_le(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version <= constraint + + def _match_ge(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version >= constraint + + def _match_eq(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version == constraint) + else: + result = _match_prefix(version, constraint) + return result + + def _match_arbitrary(self, version, constraint, prefix): + return str(version) == str(constraint) + + def _match_ne(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version != constraint) + else: + result = not _match_prefix(version, constraint) + return result + + def _match_compatible(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version == constraint: + return True + if version < constraint: + return False +# if not prefix: +# return True + release_clause = constraint._release_clause + if len(release_clause) > 1: + release_clause = release_clause[:-1] + pfx = '.'.join([str(i) for i in release_clause]) + return _match_prefix(version, pfx) + +_REPLACEMENTS = ( + (re.compile('[.+-]$'), ''), # remove trailing puncts + (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start + (re.compile('^[.-]'), ''), # remove leading puncts + (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses + (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha + (re.compile(r'\b(pre-alpha|prealpha)\b'), + 'pre.alpha'), # standardise + (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses +) + +_SUFFIX_REPLACEMENTS = ( + (re.compile('^[:~._+-]+'), ''), # remove leading puncts + (re.compile('[,*")([\\]]'), ''), # remove unwanted chars + (re.compile('[~:+_ -]'), '.'), # replace illegal chars + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\.$'), ''), # trailing '.' +) + +_NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)') + + +def _suggest_semantic_version(s): + """ + Try to suggest a semantic form for a version for which + _suggest_normalized_version couldn't come up with anything. + """ + result = s.strip().lower() + for pat, repl in _REPLACEMENTS: + result = pat.sub(repl, result) + if not result: + result = '0.0.0' + + # Now look for numeric prefix, and separate it out from + # the rest. + #import pdb; pdb.set_trace() + m = _NUMERIC_PREFIX.match(result) + if not m: + prefix = '0.0.0' + suffix = result + else: + prefix = m.groups()[0].split('.') + prefix = [int(i) for i in prefix] + while len(prefix) < 3: + prefix.append(0) + if len(prefix) == 3: + suffix = result[m.end():] + else: + suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():] + prefix = prefix[:3] + prefix = '.'.join([str(i) for i in prefix]) + suffix = suffix.strip() + if suffix: + #import pdb; pdb.set_trace() + # massage the suffix. + for pat, repl in _SUFFIX_REPLACEMENTS: + suffix = pat.sub(repl, suffix) + + if not suffix: + result = prefix + else: + sep = '-' if 'dev' in suffix else '+' + result = prefix + sep + suffix + if not is_semver(result): + result = None + return result + + +def _suggest_normalized_version(s): + """Suggest a normalized version close to the given version string. + + If you have a version string that isn't rational (i.e. NormalizedVersion + doesn't like it) then you might be able to get an equivalent (or close) + rational version from this function. + + This does a number of simple normalizations to the given string, based + on observation of versions currently in use on PyPI. Given a dump of + those version during PyCon 2009, 4287 of them: + - 2312 (53.93%) match NormalizedVersion without change + with the automatic suggestion + - 3474 (81.04%) match when using this suggestion method + + @param s {str} An irrational version string. + @returns A rational version string, or None, if couldn't determine one. + """ + try: + _normalized_key(s) + return s # already rational + except UnsupportedVersionError: + pass + + rs = s.lower() + + # part of this could use maketrans + for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), + ('beta', 'b'), ('rc', 'c'), ('-final', ''), + ('-pre', 'c'), + ('-release', ''), ('.release', ''), ('-stable', ''), + ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), + ('final', '')): + rs = rs.replace(orig, repl) + + # if something ends with dev or pre, we add a 0 + rs = re.sub(r"pre$", r"pre0", rs) + rs = re.sub(r"dev$", r"dev0", rs) + + # if we have something like "b-2" or "a.2" at the end of the + # version, that is probably beta, alpha, etc + # let's remove the dash or dot + rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs) + + # 1.0-dev-r371 -> 1.0.dev371 + # 0.1-dev-r79 -> 0.1.dev79 + rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) + + # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 + rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) + + # Clean: v0.3, v1.0 + if rs.startswith('v'): + rs = rs[1:] + + # Clean leading '0's on numbers. + #TODO: unintended side-effect on, e.g., "2003.05.09" + # PyPI stats: 77 (~2%) better + rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) + + # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers + # zero. + # PyPI stats: 245 (7.56%) better + rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) + + # the 'dev-rNNN' tag is a dev tag + rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) + + # clean the - when used as a pre delimiter + rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) + + # a terminal "dev" or "devel" can be changed into ".dev0" + rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) + + # a terminal "dev" can be changed into ".dev0" + rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) + + # a terminal "final" or "stable" can be removed + rs = re.sub(r"(final|stable)$", "", rs) + + # The 'r' and the '-' tags are post release tags + # 0.4a1.r10 -> 0.4a1.post10 + # 0.9.33-17222 -> 0.9.33.post17222 + # 0.9.33-r17222 -> 0.9.33.post17222 + rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) + + # Clean 'r' instead of 'dev' usage: + # 0.9.33+r17222 -> 0.9.33.dev17222 + # 1.0dev123 -> 1.0.dev123 + # 1.0.git123 -> 1.0.dev123 + # 1.0.bzr123 -> 1.0.dev123 + # 0.1a0dev.123 -> 0.1a0.dev123 + # PyPI stats: ~150 (~4%) better + rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) + + # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: + # 0.2.pre1 -> 0.2c1 + # 0.2-c1 -> 0.2c1 + # 1.0preview123 -> 1.0c123 + # PyPI stats: ~21 (0.62%) better + rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) + + # Tcl/Tk uses "px" for their post release markers + rs = re.sub(r"p(\d+)$", r".post\1", rs) + + try: + _normalized_key(rs) + except UnsupportedVersionError: + rs = None + return rs + +# +# Legacy version processing (distribute-compatible) +# + +_VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I) +_VERSION_REPLACE = { + 'pre': 'c', + 'preview': 'c', + '-': 'final-', + 'rc': 'c', + 'dev': '@', + '': None, + '.': None, +} + + +def _legacy_key(s): + def get_parts(s): + result = [] + for p in _VERSION_PART.split(s.lower()): + p = _VERSION_REPLACE.get(p, p) + if p: + if '0' <= p[:1] <= '9': + p = p.zfill(8) + else: + p = '*' + p + result.append(p) + result.append('*final') + return result + + result = [] + for p in get_parts(s): + if p.startswith('*'): + if p < '*final': + while result and result[-1] == '*final-': + result.pop() + while result and result[-1] == '00000000': + result.pop() + result.append(p) + return tuple(result) + + +class LegacyVersion(Version): + def parse(self, s): + return _legacy_key(s) + + @property + def is_prerelease(self): + result = False + for x in self._parts: + if (isinstance(x, string_types) and x.startswith('*') and + x < '*final'): + result = True + break + return result + + +class LegacyMatcher(Matcher): + version_class = LegacyVersion + + _operators = dict(Matcher._operators) + _operators['~='] = '_match_compatible' + + numeric_re = re.compile(r'^(\d+(\.\d+)*)') + + def _match_compatible(self, version, constraint, prefix): + if version < constraint: + return False + m = self.numeric_re.match(str(constraint)) + if not m: + logger.warning('Cannot compute compatible match for version %s ' + ' and constraint %s', version, constraint) + return True + s = m.groups()[0] + if '.' in s: + s = s.rsplit('.', 1)[0] + return _match_prefix(version, s) + +# +# Semantic versioning +# + +_SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)' + r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?' + r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I) + + +def is_semver(s): + return _SEMVER_RE.match(s) + + +def _semantic_key(s): + def make_tuple(s, absent): + if s is None: + result = (absent,) + else: + parts = s[1:].split('.') + # We can't compare ints and strings on Python 3, so fudge it + # by zero-filling numeric values so simulate a numeric comparison + result = tuple([p.zfill(8) if p.isdigit() else p for p in parts]) + return result + + m = is_semver(s) + if not m: + raise UnsupportedVersionError(s) + groups = m.groups() + major, minor, patch = [int(i) for i in groups[:3]] + # choose the '|' and '*' so that versions sort correctly + pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*') + return (major, minor, patch), pre, build + + +class SemanticVersion(Version): + def parse(self, s): + return _semantic_key(s) + + @property + def is_prerelease(self): + return self._parts[1][0] != '|' + + +class SemanticMatcher(Matcher): + version_class = SemanticVersion + + +class VersionScheme(object): + def __init__(self, key, matcher, suggester=None): + self.key = key + self.matcher = matcher + self.suggester = suggester + + def is_valid_version(self, s): + try: + self.matcher.version_class(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_matcher(self, s): + try: + self.matcher(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_constraint_list(self, s): + """ + Used for processing some metadata fields + """ + return self.is_valid_matcher('dummy_name (%s)' % s) + + def suggest(self, s): + if self.suggester is None: + result = None + else: + result = self.suggester(s) + return result + +_SCHEMES = { + 'normalized': VersionScheme(_normalized_key, NormalizedMatcher, + _suggest_normalized_version), + 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s), + 'semantic': VersionScheme(_semantic_key, SemanticMatcher, + _suggest_semantic_version), +} + +_SCHEMES['default'] = _SCHEMES['normalized'] + + +def get_scheme(name): + if name not in _SCHEMES: + raise ValueError('unknown scheme name: %r' % name) + return _SCHEMES[name] diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe new file mode 100755 index 0000000..732215a Binary files /dev/null and b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe new file mode 100755 index 0000000..c41bd0a Binary files /dev/null and b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py new file mode 100755 index 0000000..3693410 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py @@ -0,0 +1,984 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import base64 +import codecs +import datetime +import distutils.util +from email import message_from_file +import hashlib +import imp +import json +import logging +import os +import posixpath +import re +import shutil +import sys +import tempfile +import zipfile + +from . import __version__, DistlibException +from .compat import sysconfig, ZipFile, fsdecode, text_type, filter +from .database import InstalledDistribution +from .metadata import Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME +from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, + cached_property, get_cache_base, read_exports, tempdir) +from .version import NormalizedVersion, UnsupportedVersionError + +logger = logging.getLogger(__name__) + +cache = None # created when needed + +if hasattr(sys, 'pypy_version_info'): # pragma: no cover + IMP_PREFIX = 'pp' +elif sys.platform.startswith('java'): # pragma: no cover + IMP_PREFIX = 'jy' +elif sys.platform == 'cli': # pragma: no cover + IMP_PREFIX = 'ip' +else: + IMP_PREFIX = 'cp' + +VER_SUFFIX = sysconfig.get_config_var('py_version_nodot') +if not VER_SUFFIX: # pragma: no cover + VER_SUFFIX = '%s%s' % sys.version_info[:2] +PYVER = 'py' + VER_SUFFIX +IMPVER = IMP_PREFIX + VER_SUFFIX + +ARCH = distutils.util.get_platform().replace('-', '_').replace('.', '_') + +ABI = sysconfig.get_config_var('SOABI') +if ABI and ABI.startswith('cpython-'): + ABI = ABI.replace('cpython-', 'cp') +else: + def _derive_abi(): + parts = ['cp', VER_SUFFIX] + if sysconfig.get_config_var('Py_DEBUG'): + parts.append('d') + if sysconfig.get_config_var('WITH_PYMALLOC'): + parts.append('m') + if sysconfig.get_config_var('Py_UNICODE_SIZE') == 4: + parts.append('u') + return ''.join(parts) + ABI = _derive_abi() + del _derive_abi + +FILENAME_RE = re.compile(r''' +(?P<nm>[^-]+) +-(?P<vn>\d+[^-]*) +(-(?P<bn>\d+[^-]*))? +-(?P<py>\w+\d+(\.\w+\d+)*) +-(?P<bi>\w+) +-(?P<ar>\w+(\.\w+)*) +\.whl$ +''', re.IGNORECASE | re.VERBOSE) + +NAME_VERSION_RE = re.compile(r''' +(?P<nm>[^-]+) +-(?P<vn>\d+[^-]*) +(-(?P<bn>\d+[^-]*))?$ +''', re.IGNORECASE | re.VERBOSE) + +SHEBANG_RE = re.compile(br'\s*#![^\r\n]*') +SHEBANG_DETAIL_RE = re.compile(br'^(\s*#!("[^"]+"|\S+))\s+(.*)$') +SHEBANG_PYTHON = b'#!python' +SHEBANG_PYTHONW = b'#!pythonw' + +if os.sep == '/': + to_posix = lambda o: o +else: + to_posix = lambda o: o.replace(os.sep, '/') + + +class Mounter(object): + def __init__(self): + self.impure_wheels = {} + self.libs = {} + + def add(self, pathname, extensions): + self.impure_wheels[pathname] = extensions + self.libs.update(extensions) + + def remove(self, pathname): + extensions = self.impure_wheels.pop(pathname) + for k, v in extensions: + if k in self.libs: + del self.libs[k] + + def find_module(self, fullname, path=None): + if fullname in self.libs: + result = self + else: + result = None + return result + + def load_module(self, fullname): + if fullname in sys.modules: + result = sys.modules[fullname] + else: + if fullname not in self.libs: + raise ImportError('unable to find extension for %s' % fullname) + result = imp.load_dynamic(fullname, self.libs[fullname]) + result.__loader__ = self + parts = fullname.rsplit('.', 1) + if len(parts) > 1: + result.__package__ = parts[0] + return result + +_hook = Mounter() + + +class Wheel(object): + """ + Class to build and install from Wheel files (PEP 427). + """ + + wheel_version = (1, 1) + hash_kind = 'sha256' + + def __init__(self, filename=None, sign=False, verify=False): + """ + Initialise an instance using a (valid) filename. + """ + self.sign = sign + self.should_verify = verify + self.buildver = '' + self.pyver = [PYVER] + self.abi = ['none'] + self.arch = ['any'] + self.dirname = os.getcwd() + if filename is None: + self.name = 'dummy' + self.version = '0.1' + self._filename = self.filename + else: + m = NAME_VERSION_RE.match(filename) + if m: + info = m.groupdict('') + self.name = info['nm'] + # Reinstate the local version separator + self.version = info['vn'].replace('_', '-') + self.buildver = info['bn'] + self._filename = self.filename + else: + dirname, filename = os.path.split(filename) + m = FILENAME_RE.match(filename) + if not m: + raise DistlibException('Invalid name or ' + 'filename: %r' % filename) + if dirname: + self.dirname = os.path.abspath(dirname) + self._filename = filename + info = m.groupdict('') + self.name = info['nm'] + self.version = info['vn'] + self.buildver = info['bn'] + self.pyver = info['py'].split('.') + self.abi = info['bi'].split('.') + self.arch = info['ar'].split('.') + + @property + def filename(self): + """ + Build and return a filename from the various components. + """ + if self.buildver: + buildver = '-' + self.buildver + else: + buildver = '' + pyver = '.'.join(self.pyver) + abi = '.'.join(self.abi) + arch = '.'.join(self.arch) + # replace - with _ as a local version separator + version = self.version.replace('-', '_') + return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, + pyver, abi, arch) + + @property + def exists(self): + path = os.path.join(self.dirname, self.filename) + return os.path.isfile(path) + + @property + def tags(self): + for pyver in self.pyver: + for abi in self.abi: + for arch in self.arch: + yield pyver, abi, arch + + @cached_property + def metadata(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + wrapper = codecs.getreader('utf-8') + with ZipFile(pathname, 'r') as zf: + wheel_metadata = self.get_wheel_metadata(zf) + wv = wheel_metadata['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + if file_version < (1, 1): + fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME, 'METADATA'] + else: + fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME] + result = None + for fn in fns: + try: + metadata_filename = posixpath.join(info_dir, fn) + with zf.open(metadata_filename) as bf: + wf = wrapper(bf) + result = Metadata(fileobj=wf) + if result: + break + except KeyError: + pass + if not result: + raise ValueError('Invalid wheel, because metadata is ' + 'missing: looked in %s' % ', '.join(fns)) + return result + + def get_wheel_metadata(self, zf): + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + metadata_filename = posixpath.join(info_dir, 'WHEEL') + with zf.open(metadata_filename) as bf: + wf = codecs.getreader('utf-8')(bf) + message = message_from_file(wf) + return dict(message) + + @cached_property + def info(self): + pathname = os.path.join(self.dirname, self.filename) + with ZipFile(pathname, 'r') as zf: + result = self.get_wheel_metadata(zf) + return result + + def process_shebang(self, data): + m = SHEBANG_RE.match(data) + if m: + end = m.end() + shebang, data_after_shebang = data[:end], data[end:] + # Preserve any arguments after the interpreter + if b'pythonw' in shebang.lower(): + shebang_python = SHEBANG_PYTHONW + else: + shebang_python = SHEBANG_PYTHON + m = SHEBANG_DETAIL_RE.match(shebang) + if m: + args = b' ' + m.groups()[-1] + else: + args = b'' + shebang = shebang_python + args + data = shebang + data_after_shebang + else: + cr = data.find(b'\r') + lf = data.find(b'\n') + if cr < 0 or cr > lf: + term = b'\n' + else: + if data[cr:cr + 2] == b'\r\n': + term = b'\r\n' + else: + term = b'\r' + data = SHEBANG_PYTHON + term + data + return data + + def get_hash(self, data, hash_kind=None): + if hash_kind is None: + hash_kind = self.hash_kind + try: + hasher = getattr(hashlib, hash_kind) + except AttributeError: + raise DistlibException('Unsupported hash algorithm: %r' % hash_kind) + result = hasher(data).digest() + result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') + return hash_kind, result + + def write_record(self, records, record_path, base): + records = list(records) # make a copy for sorting + p = to_posix(os.path.relpath(record_path, base)) + records.append((p, '', '')) + records.sort() + with CSVWriter(record_path) as writer: + for row in records: + writer.writerow(row) + + def write_records(self, info, libdir, archive_paths): + records = [] + distinfo, info_dir = info + hasher = getattr(hashlib, self.hash_kind) + for ap, p in archive_paths: + with open(p, 'rb') as f: + data = f.read() + digest = '%s=%s' % self.get_hash(data) + size = os.path.getsize(p) + records.append((ap, digest, size)) + + p = os.path.join(distinfo, 'RECORD') + self.write_record(records, p, libdir) + ap = to_posix(os.path.join(info_dir, 'RECORD')) + archive_paths.append((ap, p)) + + def build_zip(self, pathname, archive_paths): + with ZipFile(pathname, 'w', zipfile.ZIP_DEFLATED) as zf: + for ap, p in archive_paths: + logger.debug('Wrote %s to %s in wheel', p, ap) + zf.write(p, ap) + + def build(self, paths, tags=None, wheel_version=None): + """ + Build a wheel from files in specified paths, and use any specified tags + when determining the name of the wheel. + """ + if tags is None: + tags = {} + + libkey = list(filter(lambda o: o in paths, ('purelib', 'platlib')))[0] + if libkey == 'platlib': + is_pure = 'false' + default_pyver = [IMPVER] + default_abi = [ABI] + default_arch = [ARCH] + else: + is_pure = 'true' + default_pyver = [PYVER] + default_abi = ['none'] + default_arch = ['any'] + + self.pyver = tags.get('pyver', default_pyver) + self.abi = tags.get('abi', default_abi) + self.arch = tags.get('arch', default_arch) + + libdir = paths[libkey] + + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + archive_paths = [] + + # First, stuff which is not in site-packages + for key in ('data', 'headers', 'scripts'): + if key not in paths: + continue + path = paths[key] + if os.path.isdir(path): + for root, dirs, files in os.walk(path): + for fn in files: + p = fsdecode(os.path.join(root, fn)) + rp = os.path.relpath(p, path) + ap = to_posix(os.path.join(data_dir, key, rp)) + archive_paths.append((ap, p)) + if key == 'scripts' and not p.endswith('.exe'): + with open(p, 'rb') as f: + data = f.read() + data = self.process_shebang(data) + with open(p, 'wb') as f: + f.write(data) + + # Now, stuff which is in site-packages, other than the + # distinfo stuff. + path = libdir + distinfo = None + for root, dirs, files in os.walk(path): + if root == path: + # At the top level only, save distinfo for later + # and skip it for now + for i, dn in enumerate(dirs): + dn = fsdecode(dn) + if dn.endswith('.dist-info'): + distinfo = os.path.join(root, dn) + del dirs[i] + break + assert distinfo, '.dist-info directory expected, not found' + + for fn in files: + # comment out next suite to leave .pyc files in + if fsdecode(fn).endswith(('.pyc', '.pyo')): + continue + p = os.path.join(root, fn) + rp = to_posix(os.path.relpath(p, path)) + archive_paths.append((rp, p)) + + # Now distinfo. Assumed to be flat, i.e. os.listdir is enough. + files = os.listdir(distinfo) + for fn in files: + if fn not in ('RECORD', 'INSTALLER', 'SHARED', 'WHEEL'): + p = fsdecode(os.path.join(distinfo, fn)) + ap = to_posix(os.path.join(info_dir, fn)) + archive_paths.append((ap, p)) + + wheel_metadata = [ + 'Wheel-Version: %d.%d' % (wheel_version or self.wheel_version), + 'Generator: distlib %s' % __version__, + 'Root-Is-Purelib: %s' % is_pure, + ] + for pyver, abi, arch in self.tags: + wheel_metadata.append('Tag: %s-%s-%s' % (pyver, abi, arch)) + p = os.path.join(distinfo, 'WHEEL') + with open(p, 'w') as f: + f.write('\n'.join(wheel_metadata)) + ap = to_posix(os.path.join(info_dir, 'WHEEL')) + archive_paths.append((ap, p)) + + # Now, at last, RECORD. + # Paths in here are archive paths - nothing else makes sense. + self.write_records((distinfo, info_dir), libdir, archive_paths) + # Now, ready to build the zip file + pathname = os.path.join(self.dirname, self.filename) + self.build_zip(pathname, archive_paths) + return pathname + + def install(self, paths, maker, **kwargs): + """ + Install a wheel to the specified paths. If kwarg ``warner`` is + specified, it should be a callable, which will be called with two + tuples indicating the wheel version of this software and the wheel + version in the file, if there is a discrepancy in the versions. + This can be used to issue any warnings to raise any exceptions. + If kwarg ``lib_only`` is True, only the purelib/platlib files are + installed, and the headers, scripts, data and dist-info metadata are + not written. + + The return value is a :class:`InstalledDistribution` instance unless + ``options.lib_only`` is True, in which case the return value is ``None``. + """ + + dry_run = maker.dry_run + warner = kwargs.get('warner') + lib_only = kwargs.get('lib_only', False) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + metadata_name = posixpath.join(info_dir, METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message = message_from_file(wf) + wv = message['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + if (file_version != self.wheel_version) and warner: + warner(self.wheel_version, file_version) + + if message['Root-Is-Purelib'] == 'true': + libdir = paths['purelib'] + else: + libdir = paths['platlib'] + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + data_pfx = posixpath.join(data_dir, '') + info_pfx = posixpath.join(info_dir, '') + script_pfx = posixpath.join(data_dir, 'scripts', '') + + # make a new instance rather than a copy of maker's, + # as we mutate it + fileop = FileOperator(dry_run=dry_run) + fileop.record = True # so we can rollback if needed + + bc = not sys.dont_write_bytecode # Double negatives. Lovely! + + outfiles = [] # for RECORD writing + + # for script copying/shebang processing + workdir = tempfile.mkdtemp() + # set target dir later + # we default add_launchers to False, as the + # Python Launcher should be used instead + maker.source_dir = workdir + maker.target_dir = None + try: + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + # The signature file won't be in RECORD, + # and we don't currently don't do anything with it + if u_arcname.endswith('/RECORD.jws'): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + if lib_only and u_arcname.startswith((info_pfx, data_pfx)): + logger.debug('lib_only: skipping %s', u_arcname) + continue + is_script = (u_arcname.startswith(script_pfx) + and not u_arcname.endswith('.exe')) + + if u_arcname.startswith(data_pfx): + _, where, rp = u_arcname.split('/', 2) + outfile = os.path.join(paths[where], convert_path(rp)) + else: + # meant for site-packages. + if u_arcname in (wheel_metadata_name, record_name): + continue + outfile = os.path.join(libdir, convert_path(u_arcname)) + if not is_script: + with zf.open(arcname) as bf: + fileop.copy_stream(bf, outfile) + outfiles.append(outfile) + # Double check the digest of the written file + if not dry_run and row[1]: + with open(outfile, 'rb') as bf: + data = bf.read() + _, newdigest = self.get_hash(data, kind) + if newdigest != digest: + raise DistlibException('digest mismatch ' + 'on write for ' + '%s' % outfile) + if bc and outfile.endswith('.py'): + try: + pyc = fileop.byte_compile(outfile) + outfiles.append(pyc) + except Exception: + # Don't give up if byte-compilation fails, + # but log it and perhaps warn the user + logger.warning('Byte-compilation failed', + exc_info=True) + else: + fn = os.path.basename(convert_path(arcname)) + workname = os.path.join(workdir, fn) + with zf.open(arcname) as bf: + fileop.copy_stream(bf, workname) + + dn, fn = os.path.split(outfile) + maker.target_dir = dn + filenames = maker.make(fn) + fileop.set_executable_mode(filenames) + outfiles.extend(filenames) + + if lib_only: + logger.debug('lib_only: returning None') + dist = None + else: + # Generate scripts + + # Try to get pydist.json so we can see if there are + # any commands to generate. If this fails (e.g. because + # of a legacy wheel), log a warning but don't give up. + commands = None + file_version = self.info['Wheel-Version'] + if file_version == '1.0': + # Use legacy info + ep = posixpath.join(info_dir, 'entry_points.txt') + try: + with zf.open(ep) as bwf: + epdata = read_exports(bwf) + commands = {} + for key in ('console', 'gui'): + k = '%s_scripts' % key + if k in epdata: + commands['wrap_%s' % key] = d = {} + for v in epdata[k].values(): + s = '%s:%s' % (v.prefix, v.suffix) + if v.flags: + s += ' %s' % v.flags + d[v.name] = s + except Exception: + logger.warning('Unable to read legacy script ' + 'metadata, so cannot generate ' + 'scripts') + else: + try: + with zf.open(metadata_name) as bwf: + wf = wrapper(bwf) + commands = json.load(wf).get('extensions') + if commands: + commands = commands.get('python.commands') + except Exception: + logger.warning('Unable to read JSON metadata, so ' + 'cannot generate scripts') + if commands: + console_scripts = commands.get('wrap_console', {}) + gui_scripts = commands.get('wrap_gui', {}) + if console_scripts or gui_scripts: + script_dir = paths.get('scripts', '') + if not os.path.isdir(script_dir): + raise ValueError('Valid script path not ' + 'specified') + maker.target_dir = script_dir + for k, v in console_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script) + fileop.set_executable_mode(filenames) + + if gui_scripts: + options = {'gui': True } + for k, v in gui_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script, options) + fileop.set_executable_mode(filenames) + + p = os.path.join(libdir, info_dir) + dist = InstalledDistribution(p) + + # Write SHARED + paths = dict(paths) # don't change passed in dict + del paths['purelib'] + del paths['platlib'] + paths['lib'] = libdir + p = dist.write_shared_locations(paths, dry_run) + if p: + outfiles.append(p) + + # Write RECORD + dist.write_installed_files(outfiles, paths['prefix'], + dry_run) + return dist + except Exception: # pragma: no cover + logger.exception('installation failed.') + fileop.rollback() + raise + finally: + shutil.rmtree(workdir) + + def _get_dylib_cache(self): + global cache + if cache is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('dylib-cache'), + sys.version[:3]) + cache = Cache(base) + return cache + + def _get_extensions(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + arcname = posixpath.join(info_dir, 'EXTENSIONS') + wrapper = codecs.getreader('utf-8') + result = [] + with ZipFile(pathname, 'r') as zf: + try: + with zf.open(arcname) as bf: + wf = wrapper(bf) + extensions = json.load(wf) + cache = self._get_dylib_cache() + prefix = cache.prefix_to_dir(pathname) + cache_base = os.path.join(cache.base, prefix) + if not os.path.isdir(cache_base): + os.makedirs(cache_base) + for name, relpath in extensions.items(): + dest = os.path.join(cache_base, convert_path(relpath)) + if not os.path.exists(dest): + extract = True + else: + file_time = os.stat(dest).st_mtime + file_time = datetime.datetime.fromtimestamp(file_time) + info = zf.getinfo(relpath) + wheel_time = datetime.datetime(*info.date_time) + extract = wheel_time > file_time + if extract: + zf.extract(relpath, cache_base) + result.append((name, dest)) + except KeyError: + pass + return result + + def is_compatible(self): + """ + Determine if a wheel is compatible with the running system. + """ + return is_compatible(self) + + def is_mountable(self): + """ + Determine if a wheel is asserted as mountable by its metadata. + """ + return True # for now - metadata details TBD + + def mount(self, append=False): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if not self.is_compatible(): + msg = 'Wheel %s not compatible with this Python.' % pathname + raise DistlibException(msg) + if not self.is_mountable(): + msg = 'Wheel %s is marked as not mountable.' % pathname + raise DistlibException(msg) + if pathname in sys.path: + logger.debug('%s already in path', pathname) + else: + if append: + sys.path.append(pathname) + else: + sys.path.insert(0, pathname) + extensions = self._get_extensions() + if extensions: + if _hook not in sys.meta_path: + sys.meta_path.append(_hook) + _hook.add(pathname, extensions) + + def unmount(self): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if pathname not in sys.path: + logger.debug('%s not in path', pathname) + else: + sys.path.remove(pathname) + if pathname in _hook.impure_wheels: + _hook.remove(pathname) + if not _hook.impure_wheels: + if _hook in sys.meta_path: + sys.meta_path.remove(_hook) + + def verify(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + metadata_name = posixpath.join(info_dir, METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message = message_from_file(wf) + wv = message['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + # TODO version verification + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if '..' in u_arcname: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + + # The signature file won't be in RECORD, + # and we don't currently don't do anything with it + if u_arcname.endswith('/RECORD.jws'): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + def update(self, modifier, dest_dir=None, **kwargs): + """ + Update the contents of a wheel in a generic way. The modifier should + be a callable which expects a dictionary argument: its keys are + archive-entry paths, and its values are absolute filesystem paths + where the contents the corresponding archive entries can be found. The + modifier is free to change the contents of the files pointed to, add + new entries and remove entries, before returning. This method will + extract the entire contents of the wheel to a temporary location, call + the modifier, and then use the passed (and possibly updated) + dictionary to write a new wheel. If ``dest_dir`` is specified, the new + wheel is written there -- otherwise, the original wheel is overwritten. + + The modifier should return True if it updated the wheel, else False. + This method returns the same value the modifier returns. + """ + + def get_version(path_map, info_dir): + version = path = None + key = '%s/%s' % (info_dir, METADATA_FILENAME) + if key not in path_map: + key = '%s/PKG-INFO' % info_dir + if key in path_map: + path = path_map[key] + version = Metadata(path=path).version + return version, path + + def update_version(version, path): + updated = None + try: + v = NormalizedVersion(version) + i = version.find('-') + if i < 0: + updated = '%s+1' % version + else: + parts = [int(s) for s in version[i + 1:].split('.')] + parts[-1] += 1 + updated = '%s+%s' % (version[:i], + '.'.join(str(i) for i in parts)) + except UnsupportedVersionError: + logger.debug('Cannot update non-compliant (PEP-440) ' + 'version %r', version) + if updated: + md = Metadata(path=path) + md.version = updated + legacy = not path.endswith(METADATA_FILENAME) + md.write(path=path, legacy=legacy) + logger.debug('Version updated from %r to %r', version, + updated) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + record_name = posixpath.join(info_dir, 'RECORD') + with tempdir() as workdir: + with ZipFile(pathname, 'r') as zf: + path_map = {} + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if u_arcname == record_name: + continue + if '..' in u_arcname: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + zf.extract(zinfo, workdir) + path = os.path.join(workdir, convert_path(u_arcname)) + path_map[u_arcname] = path + + # Remember the version. + original_version, _ = get_version(path_map, info_dir) + # Files extracted. Call the modifier. + modified = modifier(path_map, **kwargs) + if modified: + # Something changed - need to build a new wheel. + current_version, path = get_version(path_map, info_dir) + if current_version and (current_version == original_version): + # Add or update local version to signify changes. + update_version(current_version, path) + # Decide where the new wheel goes. + if dest_dir is None: + fd, newpath = tempfile.mkstemp(suffix='.whl', + prefix='wheel-update-', + dir=workdir) + os.close(fd) + else: + if not os.path.isdir(dest_dir): + raise DistlibException('Not a directory: %r' % dest_dir) + newpath = os.path.join(dest_dir, self.filename) + archive_paths = list(path_map.items()) + distinfo = os.path.join(workdir, info_dir) + info = distinfo, info_dir + self.write_records(info, workdir, archive_paths) + self.build_zip(newpath, archive_paths) + if dest_dir is None: + shutil.copyfile(newpath, pathname) + return modified + +def compatible_tags(): + """ + Return (pyver, abi, arch) tuples compatible with this Python. + """ + versions = [VER_SUFFIX] + major = VER_SUFFIX[0] + for minor in range(sys.version_info[1] - 1, - 1, -1): + versions.append(''.join([major, str(minor)])) + + abis = [] + for suffix, _, _ in imp.get_suffixes(): + if suffix.startswith('.abi'): + abis.append(suffix.split('.', 2)[1]) + abis.sort() + if ABI != 'none': + abis.insert(0, ABI) + abis.append('none') + result = [] + + arches = [ARCH] + if sys.platform == 'darwin': + m = re.match(r'(\w+)_(\d+)_(\d+)_(\w+)$', ARCH) + if m: + name, major, minor, arch = m.groups() + minor = int(minor) + matches = [arch] + if arch in ('i386', 'ppc'): + matches.append('fat') + if arch in ('i386', 'ppc', 'x86_64'): + matches.append('fat3') + if arch in ('ppc64', 'x86_64'): + matches.append('fat64') + if arch in ('i386', 'x86_64'): + matches.append('intel') + if arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): + matches.append('universal') + while minor >= 0: + for match in matches: + s = '%s_%s_%s_%s' % (name, major, minor, match) + if s != ARCH: # already there + arches.append(s) + minor -= 1 + + # Most specific - our Python version, ABI and arch + for abi in abis: + for arch in arches: + result.append((''.join((IMP_PREFIX, versions[0])), abi, arch)) + + # where no ABI / arch dependency, but IMP_PREFIX dependency + for i, version in enumerate(versions): + result.append((''.join((IMP_PREFIX, version)), 'none', 'any')) + if i == 0: + result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any')) + + # no IMP_PREFIX, ABI or arch dependency + for i, version in enumerate(versions): + result.append((''.join(('py', version)), 'none', 'any')) + if i == 0: + result.append((''.join(('py', version[0])), 'none', 'any')) + return set(result) + + +COMPATIBLE_TAGS = compatible_tags() + +del compatible_tags + + +def is_compatible(wheel, tags=None): + if not isinstance(wheel, Wheel): + wheel = Wheel(wheel) # assume it's a filename + result = False + if tags is None: + tags = COMPATIBLE_TAGS + for ver, abi, arch in tags: + if ver in wheel.pyver and abi in wheel.abi and arch in wheel.arch: + result = True + break + return result diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py new file mode 100755 index 0000000..0f792ea --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py @@ -0,0 +1,1104 @@ +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The ``distro`` package (``distro`` stands for Linux Distribution) provides +information about the Linux distribution it runs on, such as a reliable +machine-readable distro ID, or version information. + +It is a renewed alternative implementation for Python's original +:py:func:`platform.linux_distribution` function, but it provides much more +functionality. An alternative implementation became necessary because Python +3.5 deprecated this function, and Python 3.7 is expected to remove it +altogether. Its predecessor function :py:func:`platform.dist` was already +deprecated since Python 2.6 and is also expected to be removed in Python 3.7. +Still, there are many cases in which access to Linux distribution information +is needed. See `Python issue 1322 <https://bugs.python.org/issue1322>`_ for +more information. +""" + +import os +import re +import sys +import json +import shlex +import logging +import argparse +import subprocess + + +_UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc') +_OS_RELEASE_BASENAME = 'os-release' + +#: Translation table for normalizing the "ID" attribute defined in os-release +#: files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as defined in the os-release file, translated to lower case, +#: with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_OS_ID = {} + +#: Translation table for normalizing the "Distributor ID" attribute returned by +#: the lsb_release command, for use by the :func:`distro.id` method. +#: +#: * Key: Value as returned by the lsb_release command, translated to lower +#: case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_LSB_ID = { + 'enterpriseenterprise': 'oracle', # Oracle Enterprise Linux + 'redhatenterpriseworkstation': 'rhel', # RHEL 6, 7 Workstation + 'redhatenterpriseserver': 'rhel', # RHEL 6, 7 Server +} + +#: Translation table for normalizing the distro ID derived from the file name +#: of distro release files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as derived from the file name of a distro release file, +#: translated to lower case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_DISTRO_ID = { + 'redhat': 'rhel', # RHEL 6.x, 7.x +} + +# Pattern for content of distro release file (reversed) +_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( + r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)') + +# Pattern for base file name of distro release file +_DISTRO_RELEASE_BASENAME_PATTERN = re.compile( + r'(\w+)[-_](release|version)$') + +# Base file names to be ignored when searching for distro release file +_DISTRO_RELEASE_IGNORE_BASENAMES = ( + 'debian_version', + 'lsb-release', + 'oem-release', + _OS_RELEASE_BASENAME, + 'system-release' +) + + +def linux_distribution(full_distribution_name=True): + """ + Return information about the current Linux distribution as a tuple + ``(id_name, version, codename)`` with items as follows: + + * ``id_name``: If *full_distribution_name* is false, the result of + :func:`distro.id`. Otherwise, the result of :func:`distro.name`. + + * ``version``: The result of :func:`distro.version`. + + * ``codename``: The result of :func:`distro.codename`. + + The interface of this function is compatible with the original + :py:func:`platform.linux_distribution` function, supporting a subset of + its parameters. + + The data it returns may not exactly be the same, because it uses more data + sources than the original function, and that may lead to different data if + the Linux distribution is not consistent across multiple data sources it + provides (there are indeed such distributions ...). + + Another reason for differences is the fact that the :func:`distro.id` + method normalizes the distro ID string to a reliable machine-readable value + for a number of popular Linux distributions. + """ + return _distro.linux_distribution(full_distribution_name) + + +def id(): + """ + Return the distro ID of the current Linux distribution, as a + machine-readable string. + + For a number of Linux distributions, the returned distro ID value is + *reliable*, in the sense that it is documented and that it does not change + across releases of the distribution. + + This package maintains the following reliable distro ID values: + + ============== ========================================= + Distro ID Distribution + ============== ========================================= + "ubuntu" Ubuntu + "debian" Debian + "rhel" RedHat Enterprise Linux + "centos" CentOS + "fedora" Fedora + "sles" SUSE Linux Enterprise Server + "opensuse" openSUSE + "amazon" Amazon Linux + "arch" Arch Linux + "cloudlinux" CloudLinux OS + "exherbo" Exherbo Linux + "gentoo" GenToo Linux + "ibm_powerkvm" IBM PowerKVM + "kvmibm" KVM for IBM z Systems + "linuxmint" Linux Mint + "mageia" Mageia + "mandriva" Mandriva Linux + "parallels" Parallels + "pidora" Pidora + "raspbian" Raspbian + "oracle" Oracle Linux (and Oracle Enterprise Linux) + "scientific" Scientific Linux + "slackware" Slackware + "xenserver" XenServer + ============== ========================================= + + If you have a need to get distros for reliable IDs added into this set, + or if you find that the :func:`distro.id` function returns a different + distro ID for one of the listed distros, please create an issue in the + `distro issue tracker`_. + + **Lookup hierarchy and transformations:** + + First, the ID is obtained from the following sources, in the specified + order. The first available and non-empty value is used: + + * the value of the "ID" attribute of the os-release file, + + * the value of the "Distributor ID" attribute returned by the lsb_release + command, + + * the first part of the file name of the distro release file, + + The so determined ID value then passes the following transformations, + before it is returned by this method: + + * it is translated to lower case, + + * blanks (which should not be there anyway) are translated to underscores, + + * a normalization of the ID is performed, based upon + `normalization tables`_. The purpose of this normalization is to ensure + that the ID is as reliable as possible, even across incompatible changes + in the Linux distributions. A common reason for an incompatible change is + the addition of an os-release file, or the addition of the lsb_release + command, with ID values that differ from what was previously determined + from the distro release file name. + """ + return _distro.id() + + +def name(pretty=False): + """ + Return the name of the current Linux distribution, as a human-readable + string. + + If *pretty* is false, the name is returned without version or codename. + (e.g. "CentOS Linux") + + If *pretty* is true, the version and codename are appended. + (e.g. "CentOS Linux 7.1.1503 (Core)") + + **Lookup hierarchy:** + + The name is obtained from the following sources, in the specified order. + The first available and non-empty value is used: + + * If *pretty* is false: + + - the value of the "NAME" attribute of the os-release file, + + - the value of the "Distributor ID" attribute returned by the lsb_release + command, + + - the value of the "<name>" field of the distro release file. + + * If *pretty* is true: + + - the value of the "PRETTY_NAME" attribute of the os-release file, + + - the value of the "Description" attribute returned by the lsb_release + command, + + - the value of the "<name>" field of the distro release file, appended + with the value of the pretty version ("<version_id>" and "<codename>" + fields) of the distro release file, if available. + """ + return _distro.name(pretty) + + +def version(pretty=False, best=False): + """ + Return the version of the current Linux distribution, as a human-readable + string. + + If *pretty* is false, the version is returned without codename (e.g. + "7.0"). + + If *pretty* is true, the codename in parenthesis is appended, if the + codename is non-empty (e.g. "7.0 (Maipo)"). + + Some distributions provide version numbers with different precisions in + the different sources of distribution information. Examining the different + sources in a fixed priority order does not always yield the most precise + version (e.g. for Debian 8.2, or CentOS 7.1). + + The *best* parameter can be used to control the approach for the returned + version: + + If *best* is false, the first non-empty version number in priority order of + the examined sources is returned. + + If *best* is true, the most precise version number out of all examined + sources is returned. + + **Lookup hierarchy:** + + In all cases, the version number is obtained from the following sources. + If *best* is false, this order represents the priority order: + + * the value of the "VERSION_ID" attribute of the os-release file, + * the value of the "Release" attribute returned by the lsb_release + command, + * the version number parsed from the "<version_id>" field of the first line + of the distro release file, + * the version number parsed from the "PRETTY_NAME" attribute of the + os-release file, if it follows the format of the distro release files. + * the version number parsed from the "Description" attribute returned by + the lsb_release command, if it follows the format of the distro release + files. + """ + return _distro.version(pretty, best) + + +def version_parts(best=False): + """ + Return the version of the current Linux distribution as a tuple + ``(major, minor, build_number)`` with items as follows: + + * ``major``: The result of :func:`distro.major_version`. + + * ``minor``: The result of :func:`distro.minor_version`. + + * ``build_number``: The result of :func:`distro.build_number`. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.version_parts(best) + + +def major_version(best=False): + """ + Return the major version of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The major version is the first + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.major_version(best) + + +def minor_version(best=False): + """ + Return the minor version of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The minor version is the second + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.minor_version(best) + + +def build_number(best=False): + """ + Return the build number of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The build number is the third part + of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.build_number(best) + + +def like(): + """ + Return a space-separated list of distro IDs of distributions that are + closely related to the current Linux distribution in regards to packaging + and programming interfaces, for example distributions the current + distribution is a derivative from. + + **Lookup hierarchy:** + + This information item is only provided by the os-release file. + For details, see the description of the "ID_LIKE" attribute in the + `os-release man page + <http://www.freedesktop.org/software/systemd/man/os-release.html>`_. + """ + return _distro.like() + + +def codename(): + """ + Return the codename for the release of the current Linux distribution, + as a string. + + If the distribution does not have a codename, an empty string is returned. + + Note that the returned codename is not always really a codename. For + example, openSUSE returns "x86_64". This function does not handle such + cases in any special way and just returns the string it finds, if any. + + **Lookup hierarchy:** + + * the codename within the "VERSION" attribute of the os-release file, if + provided, + + * the value of the "Codename" attribute returned by the lsb_release + command, + + * the value of the "<codename>" field of the distro release file. + """ + return _distro.codename() + + +def info(pretty=False, best=False): + """ + Return certain machine-readable information items about the current Linux + distribution in a dictionary, as shown in the following example: + + .. sourcecode:: python + + { + 'id': 'rhel', + 'version': '7.0', + 'version_parts': { + 'major': '7', + 'minor': '0', + 'build_number': '' + }, + 'like': 'fedora', + 'codename': 'Maipo' + } + + The dictionary structure and keys are always the same, regardless of which + information items are available in the underlying data sources. The values + for the various keys are as follows: + + * ``id``: The result of :func:`distro.id`. + + * ``version``: The result of :func:`distro.version`. + + * ``version_parts -> major``: The result of :func:`distro.major_version`. + + * ``version_parts -> minor``: The result of :func:`distro.minor_version`. + + * ``version_parts -> build_number``: The result of + :func:`distro.build_number`. + + * ``like``: The result of :func:`distro.like`. + + * ``codename``: The result of :func:`distro.codename`. + + For a description of the *pretty* and *best* parameters, see the + :func:`distro.version` method. + """ + return _distro.info(pretty, best) + + +def os_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the os-release file data source of the current Linux distribution. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_info() + + +def lsb_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the lsb_release command data source of the current Linux distribution. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_info() + + +def distro_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current Linux distribution. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_info() + + +def os_release_attr(attribute): + """ + Return a single named information item from the os-release file data source + of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_attr(attribute) + + +def lsb_release_attr(attribute): + """ + Return a single named information item from the lsb_release command output + data source of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_attr(attribute) + + +def distro_release_attr(attribute): + """ + Return a single named information item from the distro release file + data source of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_attr(attribute) + + +class cached_property(object): + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + def __init__(self, f): + self._fname = f.__name__ + self._f = f + + def __get__(self, obj, owner): + assert obj is not None, 'call {} on an instance'.format(self._fname) + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + +class LinuxDistribution(object): + """ + Provides information about a Linux distribution. + + This package creates a private module-global instance of this class with + default initialization arguments, that is used by the + `consolidated accessor functions`_ and `single source accessor functions`_. + By using default initialization arguments, that module-global instance + returns data about the current Linux distribution (i.e. the distro this + package runs on). + + Normally, it is not necessary to create additional instances of this class. + However, in situations where control is needed over the exact data sources + that are used, instances of this class can be created with a specific + distro release file, or a specific os-release file, or without invoking the + lsb_release command. + """ + + def __init__(self, + include_lsb=True, + os_release_file='', + distro_release_file=''): + """ + The initialization method of this class gathers information from the + available data sources, and stores that in private instance attributes. + Subsequent access to the information items uses these private instance + attributes, so that the data sources are read only once. + + Parameters: + + * ``include_lsb`` (bool): Controls whether the + `lsb_release command output`_ is included as a data source. + + If the lsb_release command is not available in the program execution + path, the data source for the lsb_release command will be empty. + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is to be used as a data source. + + An empty string (the default) will cause the default path name to + be used (see `os-release file`_ for details). + + If the specified or defaulted os-release file does not exist, the + data source for the os-release file will be empty. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is to be used as a data source. + + An empty string (the default) will cause a default search algorithm + to be used (see `distro release file`_ for details). + + If the specified distro release file does not exist, or if no default + distro release file can be found, the data source for the distro + release file will be empty. + + Public instance attributes: + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + + Raises: + + * :py:exc:`IOError`: Some I/O issue with an os-release file or distro + release file. + + * :py:exc:`subprocess.CalledProcessError`: The lsb_release command had + some issue (other than not being available in the program execution + path). + + * :py:exc:`UnicodeError`: A data source has unexpected characters or + uses an unexpected encoding. + """ + self.os_release_file = os_release_file or \ + os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME) + self.distro_release_file = distro_release_file or '' # updated later + self.include_lsb = include_lsb + + def __repr__(self): + """Return repr of all info + """ + return \ + "LinuxDistribution(" \ + "os_release_file={self.os_release_file!r}, " \ + "distro_release_file={self.distro_release_file!r}, " \ + "include_lsb={self.include_lsb!r}, " \ + "_os_release_info={self._os_release_info!r}, " \ + "_lsb_release_info={self._lsb_release_info!r}, " \ + "_distro_release_info={self._distro_release_info!r})".format( + self=self) + + def linux_distribution(self, full_distribution_name=True): + """ + Return information about the Linux distribution that is compatible + with Python's :func:`platform.linux_distribution`, supporting a subset + of its parameters. + + For details, see :func:`distro.linux_distribution`. + """ + return ( + self.name() if full_distribution_name else self.id(), + self.version(), + self.codename() + ) + + def id(self): + """Return the distro ID of the Linux distribution, as a string. + + For details, see :func:`distro.id`. + """ + def normalize(distro_id, table): + distro_id = distro_id.lower().replace(' ', '_') + return table.get(distro_id, distro_id) + + distro_id = self.os_release_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_OS_ID) + + distro_id = self.lsb_release_attr('distributor_id') + if distro_id: + return normalize(distro_id, NORMALIZED_LSB_ID) + + distro_id = self.distro_release_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + return '' + + def name(self, pretty=False): + """ + Return the name of the Linux distribution, as a string. + + For details, see :func:`distro.name`. + """ + name = self.os_release_attr('name') \ + or self.lsb_release_attr('distributor_id') \ + or self.distro_release_attr('name') + if pretty: + name = self.os_release_attr('pretty_name') \ + or self.lsb_release_attr('description') + if not name: + name = self.distro_release_attr('name') + version = self.version(pretty=True) + if version: + name = name + ' ' + version + return name or '' + + def version(self, pretty=False, best=False): + """ + Return the version of the Linux distribution, as a string. + + For details, see :func:`distro.version`. + """ + versions = [ + self.os_release_attr('version_id'), + self.lsb_release_attr('release'), + self.distro_release_attr('version_id'), + self._parse_distro_release_content( + self.os_release_attr('pretty_name')).get('version_id', ''), + self._parse_distro_release_content( + self.lsb_release_attr('description')).get('version_id', '') + ] + version = '' + if best: + # This algorithm uses the last version in priority order that has + # the best precision. If the versions are not in conflict, that + # does not matter; otherwise, using the last one instead of the + # first one might be considered a surprise. + for v in versions: + if v.count(".") > version.count(".") or version == '': + version = v + else: + for v in versions: + if v != '': + version = v + break + if pretty and version and self.codename(): + version = u'{0} ({1})'.format(version, self.codename()) + return version + + def version_parts(self, best=False): + """ + Return the version of the Linux distribution, as a tuple of version + numbers. + + For details, see :func:`distro.version_parts`. + """ + version_str = self.version(best=best) + if version_str: + version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?') + matches = version_regex.match(version_str) + if matches: + major, minor, build_number = matches.groups() + return major, minor or '', build_number or '' + return '', '', '' + + def major_version(self, best=False): + """ + Return the major version number of the current distribution. + + For details, see :func:`distro.major_version`. + """ + return self.version_parts(best)[0] + + def minor_version(self, best=False): + """ + Return the minor version number of the Linux distribution. + + For details, see :func:`distro.minor_version`. + """ + return self.version_parts(best)[1] + + def build_number(self, best=False): + """ + Return the build number of the Linux distribution. + + For details, see :func:`distro.build_number`. + """ + return self.version_parts(best)[2] + + def like(self): + """ + Return the IDs of distributions that are like the Linux distribution. + + For details, see :func:`distro.like`. + """ + return self.os_release_attr('id_like') or '' + + def codename(self): + """ + Return the codename of the Linux distribution. + + For details, see :func:`distro.codename`. + """ + return self.os_release_attr('codename') \ + or self.lsb_release_attr('codename') \ + or self.distro_release_attr('codename') \ + or '' + + def info(self, pretty=False, best=False): + """ + Return certain machine-readable information about the Linux + distribution. + + For details, see :func:`distro.info`. + """ + return dict( + id=self.id(), + version=self.version(pretty, best), + version_parts=dict( + major=self.major_version(best), + minor=self.minor_version(best), + build_number=self.build_number(best) + ), + like=self.like(), + codename=self.codename(), + ) + + def os_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the os-release file data source of the Linux distribution. + + For details, see :func:`distro.os_release_info`. + """ + return self._os_release_info + + def lsb_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the lsb_release command data source of the Linux + distribution. + + For details, see :func:`distro.lsb_release_info`. + """ + return self._lsb_release_info + + def distro_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the distro release file data source of the Linux + distribution. + + For details, see :func:`distro.distro_release_info`. + """ + return self._distro_release_info + + def os_release_attr(self, attribute): + """ + Return a single named information item from the os-release file data + source of the Linux distribution. + + For details, see :func:`distro.os_release_attr`. + """ + return self._os_release_info.get(attribute, '') + + def lsb_release_attr(self, attribute): + """ + Return a single named information item from the lsb_release command + output data source of the Linux distribution. + + For details, see :func:`distro.lsb_release_attr`. + """ + return self._lsb_release_info.get(attribute, '') + + def distro_release_attr(self, attribute): + """ + Return a single named information item from the distro release file + data source of the Linux distribution. + + For details, see :func:`distro.distro_release_attr`. + """ + return self._distro_release_info.get(attribute, '') + + @cached_property + def _os_release_info(self): + """ + Get the information items from the specified os-release file. + + Returns: + A dictionary containing all information items. + """ + if os.path.isfile(self.os_release_file): + with open(self.os_release_file) as release_file: + return self._parse_os_release_content(release_file) + return {} + + @staticmethod + def _parse_os_release_content(lines): + """ + Parse the lines of an os-release file. + + Parameters: + + * lines: Iterable through the lines in the os-release file. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + lexer = shlex.shlex(lines, posix=True) + lexer.whitespace_split = True + + # The shlex module defines its `wordchars` variable using literals, + # making it dependent on the encoding of the Python source file. + # In Python 2.6 and 2.7, the shlex source file is encoded in + # 'iso-8859-1', and the `wordchars` variable is defined as a byte + # string. This causes a UnicodeDecodeError to be raised when the + # parsed content is a unicode object. The following fix resolves that + # (... but it should be fixed in shlex...): + if sys.version_info[0] == 2 and isinstance(lexer.wordchars, bytes): + lexer.wordchars = lexer.wordchars.decode('iso-8859-1') + + tokens = list(lexer) + for token in tokens: + # At this point, all shell-like parsing has been done (i.e. + # comments processed, quotes and backslash escape sequences + # processed, multi-line values assembled, trailing newlines + # stripped, etc.), so the tokens are now either: + # * variable assignments: var=value + # * commands or their arguments (not allowed in os-release) + if '=' in token: + k, v = token.split('=', 1) + if isinstance(v, bytes): + v = v.decode('utf-8') + props[k.lower()] = v + if k == 'VERSION': + # this handles cases in which the codename is in + # the `(CODENAME)` (rhel, centos, fedora) format + # or in the `, CODENAME` format (Ubuntu). + codename = re.search(r'(\(\D+\))|,(\s+)?\D+', v) + if codename: + codename = codename.group() + codename = codename.strip('()') + codename = codename.strip(',') + codename = codename.strip() + # codename appears within paranthese. + props['codename'] = codename + else: + props['codename'] = '' + else: + # Ignore any tokens that are not variable assignments + pass + return props + + @cached_property + def _lsb_release_info(self): + """ + Get the information items from the lsb_release command output. + + Returns: + A dictionary containing all information items. + """ + if not self.include_lsb: + return {} + with open(os.devnull, 'w') as devnull: + try: + cmd = ('lsb_release', '-a') + stdout = subprocess.check_output(cmd, stderr=devnull) + except OSError: # Command not found + return {} + content = stdout.decode(sys.getfilesystemencoding()).splitlines() + return self._parse_lsb_release_content(content) + + @staticmethod + def _parse_lsb_release_content(lines): + """ + Parse the output of the lsb_release command. + + Parameters: + + * lines: Iterable through the lines of the lsb_release output. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + for line in lines: + kv = line.strip('\n').split(':', 1) + if len(kv) != 2: + # Ignore lines without colon. + continue + k, v = kv + props.update({k.replace(' ', '_').lower(): v.strip()}) + return props + + @cached_property + def _distro_release_info(self): + """ + Get the information items from the specified distro release file. + + Returns: + A dictionary containing all information items. + """ + if self.distro_release_file: + # If it was specified, we use it and parse what we can, even if + # its file name or content does not match the expected pattern. + distro_info = self._parse_distro_release_file( + self.distro_release_file) + basename = os.path.basename(self.distro_release_file) + # The file name pattern for user-specified distro release files + # is somewhat more tolerant (compared to when searching for the + # file), because we want to use what was specified as best as + # possible. + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match: + distro_info['id'] = match.group(1) + return distro_info + else: + try: + basenames = os.listdir(_UNIXCONFDIR) + # We sort for repeatability in cases where there are multiple + # distro specific files; e.g. CentOS, Oracle, Enterprise all + # containing `redhat-release` on top of their own. + basenames.sort() + except OSError: + # This may occur when /etc is not readable but we can't be + # sure about the *-release files. Check common entries of + # /etc for information. If they turn out to not be there the + # error is handled in `_parse_distro_release_file()`. + basenames = ['SuSE-release', + 'arch-release', + 'base-release', + 'centos-release', + 'fedora-release', + 'gentoo-release', + 'mageia-release', + 'mandrake-release', + 'mandriva-release', + 'mandrivalinux-release', + 'manjaro-release', + 'oracle-release', + 'redhat-release', + 'sl-release', + 'slackware-version'] + for basename in basenames: + if basename in _DISTRO_RELEASE_IGNORE_BASENAMES: + continue + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match: + filepath = os.path.join(_UNIXCONFDIR, basename) + distro_info = self._parse_distro_release_file(filepath) + if 'name' in distro_info: + # The name is always present if the pattern matches + self.distro_release_file = filepath + distro_info['id'] = match.group(1) + return distro_info + return {} + + def _parse_distro_release_file(self, filepath): + """ + Parse a distro release file. + + Parameters: + + * filepath: Path name of the distro release file. + + Returns: + A dictionary containing all information items. + """ + try: + with open(filepath) as fp: + # Only parse the first line. For instance, on SLES there + # are multiple lines. We don't want them... + return self._parse_distro_release_content(fp.readline()) + except (OSError, IOError): + # Ignore not being able to read a specific, seemingly version + # related file. + # See https://github.com/nir0s/distro/issues/162 + return {} + + @staticmethod + def _parse_distro_release_content(line): + """ + Parse a line from a distro release file. + + Parameters: + * line: Line from the distro release file. Must be a unicode string + or a UTF-8 encoded byte string. + + Returns: + A dictionary containing all information items. + """ + if isinstance(line, bytes): + line = line.decode('utf-8') + matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match( + line.strip()[::-1]) + distro_info = {} + if matches: + # regexp ensures non-None + distro_info['name'] = matches.group(3)[::-1] + if matches.group(2): + distro_info['version_id'] = matches.group(2)[::-1] + if matches.group(1): + distro_info['codename'] = matches.group(1)[::-1] + elif line: + distro_info['name'] = line.strip() + return distro_info + + +_distro = LinuxDistribution() + + +def main(): + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + parser = argparse.ArgumentParser(description="Linux distro info tool") + parser.add_argument( + '--json', + '-j', + help="Output in machine readable format", + action="store_true") + args = parser.parse_args() + + if args.json: + logger.info(json.dumps(info(), indent=4, sort_keys=True)) + else: + logger.info('Name: %s', name(pretty=True)) + distribution_version = version(pretty=True) + logger.info('Version: %s', distribution_version) + distribution_codename = codename() + logger.info('Codename: %s', distribution_codename) + + +if __name__ == '__main__': + main() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py new file mode 100755 index 0000000..0b54002 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py @@ -0,0 +1,35 @@ +""" +HTML parsing library based on the `WHATWG HTML specification +<https://whatwg.org/html>`_. The parser is designed to be compatible with +existing HTML found in the wild and implements well-defined error recovery that +is largely compatible with modern desktop web browsers. + +Example usage:: + + from pip._vendor import html5lib + with open("my_document.html", "rb") as f: + tree = html5lib.parse(f) + +For convenience, this module re-exports the following names: + +* :func:`~.html5parser.parse` +* :func:`~.html5parser.parseFragment` +* :class:`~.html5parser.HTMLParser` +* :func:`~.treebuilders.getTreeBuilder` +* :func:`~.treewalkers.getTreeWalker` +* :func:`~.serializer.serialize` +""" + +from __future__ import absolute_import, division, unicode_literals + +from .html5parser import HTMLParser, parse, parseFragment +from .treebuilders import getTreeBuilder +from .treewalkers import getTreeWalker +from .serializer import serialize + +__all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder", + "getTreeWalker", "serialize"] + +# this has to be at the top level, see how setup.py parses this +#: Distribution version number. +__version__ = "1.0.1" diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py new file mode 100755 index 0000000..68f9b1e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py @@ -0,0 +1,288 @@ +from __future__ import absolute_import, division, unicode_literals + +import re +import warnings + +from .constants import DataLossWarning + +baseChar = """ +[#x0041-#x005A] | [#x0061-#x007A] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | +[#x00F8-#x00FF] | [#x0100-#x0131] | [#x0134-#x013E] | [#x0141-#x0148] | +[#x014A-#x017E] | [#x0180-#x01C3] | [#x01CD-#x01F0] | [#x01F4-#x01F5] | +[#x01FA-#x0217] | [#x0250-#x02A8] | [#x02BB-#x02C1] | #x0386 | +[#x0388-#x038A] | #x038C | [#x038E-#x03A1] | [#x03A3-#x03CE] | +[#x03D0-#x03D6] | #x03DA | #x03DC | #x03DE | #x03E0 | [#x03E2-#x03F3] | +[#x0401-#x040C] | [#x040E-#x044F] | [#x0451-#x045C] | [#x045E-#x0481] | +[#x0490-#x04C4] | [#x04C7-#x04C8] | [#x04CB-#x04CC] | [#x04D0-#x04EB] | +[#x04EE-#x04F5] | [#x04F8-#x04F9] | [#x0531-#x0556] | #x0559 | +[#x0561-#x0586] | [#x05D0-#x05EA] | [#x05F0-#x05F2] | [#x0621-#x063A] | +[#x0641-#x064A] | [#x0671-#x06B7] | [#x06BA-#x06BE] | [#x06C0-#x06CE] | +[#x06D0-#x06D3] | #x06D5 | [#x06E5-#x06E6] | [#x0905-#x0939] | #x093D | +[#x0958-#x0961] | [#x0985-#x098C] | [#x098F-#x0990] | [#x0993-#x09A8] | +[#x09AA-#x09B0] | #x09B2 | [#x09B6-#x09B9] | [#x09DC-#x09DD] | +[#x09DF-#x09E1] | [#x09F0-#x09F1] | [#x0A05-#x0A0A] | [#x0A0F-#x0A10] | +[#x0A13-#x0A28] | [#x0A2A-#x0A30] | [#x0A32-#x0A33] | [#x0A35-#x0A36] | +[#x0A38-#x0A39] | [#x0A59-#x0A5C] | #x0A5E | [#x0A72-#x0A74] | +[#x0A85-#x0A8B] | #x0A8D | [#x0A8F-#x0A91] | [#x0A93-#x0AA8] | +[#x0AAA-#x0AB0] | [#x0AB2-#x0AB3] | [#x0AB5-#x0AB9] | #x0ABD | #x0AE0 | +[#x0B05-#x0B0C] | [#x0B0F-#x0B10] | [#x0B13-#x0B28] | [#x0B2A-#x0B30] | +[#x0B32-#x0B33] | [#x0B36-#x0B39] | #x0B3D | [#x0B5C-#x0B5D] | +[#x0B5F-#x0B61] | [#x0B85-#x0B8A] | [#x0B8E-#x0B90] | [#x0B92-#x0B95] | +[#x0B99-#x0B9A] | #x0B9C | [#x0B9E-#x0B9F] | [#x0BA3-#x0BA4] | +[#x0BA8-#x0BAA] | [#x0BAE-#x0BB5] | [#x0BB7-#x0BB9] | [#x0C05-#x0C0C] | +[#x0C0E-#x0C10] | [#x0C12-#x0C28] | [#x0C2A-#x0C33] | [#x0C35-#x0C39] | +[#x0C60-#x0C61] | [#x0C85-#x0C8C] | [#x0C8E-#x0C90] | [#x0C92-#x0CA8] | +[#x0CAA-#x0CB3] | [#x0CB5-#x0CB9] | #x0CDE | [#x0CE0-#x0CE1] | +[#x0D05-#x0D0C] | [#x0D0E-#x0D10] | [#x0D12-#x0D28] | [#x0D2A-#x0D39] | +[#x0D60-#x0D61] | [#x0E01-#x0E2E] | #x0E30 | [#x0E32-#x0E33] | +[#x0E40-#x0E45] | [#x0E81-#x0E82] | #x0E84 | [#x0E87-#x0E88] | #x0E8A | +#x0E8D | [#x0E94-#x0E97] | [#x0E99-#x0E9F] | [#x0EA1-#x0EA3] | #x0EA5 | +#x0EA7 | [#x0EAA-#x0EAB] | [#x0EAD-#x0EAE] | #x0EB0 | [#x0EB2-#x0EB3] | +#x0EBD | [#x0EC0-#x0EC4] | [#x0F40-#x0F47] | [#x0F49-#x0F69] | +[#x10A0-#x10C5] | [#x10D0-#x10F6] | #x1100 | [#x1102-#x1103] | +[#x1105-#x1107] | #x1109 | [#x110B-#x110C] | [#x110E-#x1112] | #x113C | +#x113E | #x1140 | #x114C | #x114E | #x1150 | [#x1154-#x1155] | #x1159 | +[#x115F-#x1161] | #x1163 | #x1165 | #x1167 | #x1169 | [#x116D-#x116E] | +[#x1172-#x1173] | #x1175 | #x119E | #x11A8 | #x11AB | [#x11AE-#x11AF] | +[#x11B7-#x11B8] | #x11BA | [#x11BC-#x11C2] | #x11EB | #x11F0 | #x11F9 | +[#x1E00-#x1E9B] | [#x1EA0-#x1EF9] | [#x1F00-#x1F15] | [#x1F18-#x1F1D] | +[#x1F20-#x1F45] | [#x1F48-#x1F4D] | [#x1F50-#x1F57] | #x1F59 | #x1F5B | +#x1F5D | [#x1F5F-#x1F7D] | [#x1F80-#x1FB4] | [#x1FB6-#x1FBC] | #x1FBE | +[#x1FC2-#x1FC4] | [#x1FC6-#x1FCC] | [#x1FD0-#x1FD3] | [#x1FD6-#x1FDB] | +[#x1FE0-#x1FEC] | [#x1FF2-#x1FF4] | [#x1FF6-#x1FFC] | #x2126 | +[#x212A-#x212B] | #x212E | [#x2180-#x2182] | [#x3041-#x3094] | +[#x30A1-#x30FA] | [#x3105-#x312C] | [#xAC00-#xD7A3]""" + +ideographic = """[#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]""" + +combiningCharacter = """ +[#x0300-#x0345] | [#x0360-#x0361] | [#x0483-#x0486] | [#x0591-#x05A1] | +[#x05A3-#x05B9] | [#x05BB-#x05BD] | #x05BF | [#x05C1-#x05C2] | #x05C4 | +[#x064B-#x0652] | #x0670 | [#x06D6-#x06DC] | [#x06DD-#x06DF] | +[#x06E0-#x06E4] | [#x06E7-#x06E8] | [#x06EA-#x06ED] | [#x0901-#x0903] | +#x093C | [#x093E-#x094C] | #x094D | [#x0951-#x0954] | [#x0962-#x0963] | +[#x0981-#x0983] | #x09BC | #x09BE | #x09BF | [#x09C0-#x09C4] | +[#x09C7-#x09C8] | [#x09CB-#x09CD] | #x09D7 | [#x09E2-#x09E3] | #x0A02 | +#x0A3C | #x0A3E | #x0A3F | [#x0A40-#x0A42] | [#x0A47-#x0A48] | +[#x0A4B-#x0A4D] | [#x0A70-#x0A71] | [#x0A81-#x0A83] | #x0ABC | +[#x0ABE-#x0AC5] | [#x0AC7-#x0AC9] | [#x0ACB-#x0ACD] | [#x0B01-#x0B03] | +#x0B3C | [#x0B3E-#x0B43] | [#x0B47-#x0B48] | [#x0B4B-#x0B4D] | +[#x0B56-#x0B57] | [#x0B82-#x0B83] | [#x0BBE-#x0BC2] | [#x0BC6-#x0BC8] | +[#x0BCA-#x0BCD] | #x0BD7 | [#x0C01-#x0C03] | [#x0C3E-#x0C44] | +[#x0C46-#x0C48] | [#x0C4A-#x0C4D] | [#x0C55-#x0C56] | [#x0C82-#x0C83] | +[#x0CBE-#x0CC4] | [#x0CC6-#x0CC8] | [#x0CCA-#x0CCD] | [#x0CD5-#x0CD6] | +[#x0D02-#x0D03] | [#x0D3E-#x0D43] | [#x0D46-#x0D48] | [#x0D4A-#x0D4D] | +#x0D57 | #x0E31 | [#x0E34-#x0E3A] | [#x0E47-#x0E4E] | #x0EB1 | +[#x0EB4-#x0EB9] | [#x0EBB-#x0EBC] | [#x0EC8-#x0ECD] | [#x0F18-#x0F19] | +#x0F35 | #x0F37 | #x0F39 | #x0F3E | #x0F3F | [#x0F71-#x0F84] | +[#x0F86-#x0F8B] | [#x0F90-#x0F95] | #x0F97 | [#x0F99-#x0FAD] | +[#x0FB1-#x0FB7] | #x0FB9 | [#x20D0-#x20DC] | #x20E1 | [#x302A-#x302F] | +#x3099 | #x309A""" + +digit = """ +[#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] | +[#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] | +[#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] | +[#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29]""" + +extender = """ +#x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 | +#[#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE]""" + +letter = " | ".join([baseChar, ideographic]) + +# Without the +name = " | ".join([letter, digit, ".", "-", "_", combiningCharacter, + extender]) +nameFirst = " | ".join([letter, "_"]) + +reChar = re.compile(r"#x([\d|A-F]{4,4})") +reCharRange = re.compile(r"\[#x([\d|A-F]{4,4})-#x([\d|A-F]{4,4})\]") + + +def charStringToList(chars): + charRanges = [item.strip() for item in chars.split(" | ")] + rv = [] + for item in charRanges: + foundMatch = False + for regexp in (reChar, reCharRange): + match = regexp.match(item) + if match is not None: + rv.append([hexToInt(item) for item in match.groups()]) + if len(rv[-1]) == 1: + rv[-1] = rv[-1] * 2 + foundMatch = True + break + if not foundMatch: + assert len(item) == 1 + + rv.append([ord(item)] * 2) + rv = normaliseCharList(rv) + return rv + + +def normaliseCharList(charList): + charList = sorted(charList) + for item in charList: + assert item[1] >= item[0] + rv = [] + i = 0 + while i < len(charList): + j = 1 + rv.append(charList[i]) + while i + j < len(charList) and charList[i + j][0] <= rv[-1][1] + 1: + rv[-1][1] = charList[i + j][1] + j += 1 + i += j + return rv + +# We don't really support characters above the BMP :( +max_unicode = int("FFFF", 16) + + +def missingRanges(charList): + rv = [] + if charList[0] != 0: + rv.append([0, charList[0][0] - 1]) + for i, item in enumerate(charList[:-1]): + rv.append([item[1] + 1, charList[i + 1][0] - 1]) + if charList[-1][1] != max_unicode: + rv.append([charList[-1][1] + 1, max_unicode]) + return rv + + +def listToRegexpStr(charList): + rv = [] + for item in charList: + if item[0] == item[1]: + rv.append(escapeRegexp(chr(item[0]))) + else: + rv.append(escapeRegexp(chr(item[0])) + "-" + + escapeRegexp(chr(item[1]))) + return "[%s]" % "".join(rv) + + +def hexToInt(hex_str): + return int(hex_str, 16) + + +def escapeRegexp(string): + specialCharacters = (".", "^", "$", "*", "+", "?", "{", "}", + "[", "]", "|", "(", ")", "-") + for char in specialCharacters: + string = string.replace(char, "\\" + char) + + return string + +# output from the above +nonXmlNameBMPRegexp = re.compile('[\x00-,/:-@\\[-\\^`\\{-\xb6\xb8-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u02cf\u02d2-\u02ff\u0346-\u035f\u0362-\u0385\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482\u0487-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u0590\u05a2\u05ba\u05be\u05c0\u05c3\u05c5-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u063f\u0653-\u065f\u066a-\u066f\u06b8-\u06b9\u06bf\u06cf\u06d4\u06e9\u06ee-\u06ef\u06fa-\u0900\u0904\u093a-\u093b\u094e-\u0950\u0955-\u0957\u0964-\u0965\u0970-\u0980\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09bb\u09bd\u09c5-\u09c6\u09c9-\u09ca\u09ce-\u09d6\u09d8-\u09db\u09de\u09e4-\u09e5\u09f2-\u0a01\u0a03-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a3b\u0a3d\u0a43-\u0a46\u0a49-\u0a4a\u0a4e-\u0a58\u0a5d\u0a5f-\u0a65\u0a75-\u0a80\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abb\u0ac6\u0aca\u0ace-\u0adf\u0ae1-\u0ae5\u0af0-\u0b00\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3b\u0b44-\u0b46\u0b49-\u0b4a\u0b4e-\u0b55\u0b58-\u0b5b\u0b5e\u0b62-\u0b65\u0b70-\u0b81\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0bbd\u0bc3-\u0bc5\u0bc9\u0bce-\u0bd6\u0bd8-\u0be6\u0bf0-\u0c00\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c3d\u0c45\u0c49\u0c4e-\u0c54\u0c57-\u0c5f\u0c62-\u0c65\u0c70-\u0c81\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cbd\u0cc5\u0cc9\u0cce-\u0cd4\u0cd7-\u0cdd\u0cdf\u0ce2-\u0ce5\u0cf0-\u0d01\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d3d\u0d44-\u0d45\u0d49\u0d4e-\u0d56\u0d58-\u0d5f\u0d62-\u0d65\u0d70-\u0e00\u0e2f\u0e3b-\u0e3f\u0e4f\u0e5a-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eba\u0ebe-\u0ebf\u0ec5\u0ec7\u0ece-\u0ecf\u0eda-\u0f17\u0f1a-\u0f1f\u0f2a-\u0f34\u0f36\u0f38\u0f3a-\u0f3d\u0f48\u0f6a-\u0f70\u0f85\u0f8c-\u0f8f\u0f96\u0f98\u0fae-\u0fb0\u0fb8\u0fba-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u20cf\u20dd-\u20e0\u20e2-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3004\u3006\u3008-\u3020\u3030\u3036-\u3040\u3095-\u3098\u309b-\u309c\u309f-\u30a0\u30fb\u30ff-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa + +nonXmlNameFirstBMPRegexp = re.compile('[\x00-@\\[-\\^`\\{-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u0385\u0387\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u0640\u064b-\u0670\u06b8-\u06b9\u06bf\u06cf\u06d4\u06d6-\u06e4\u06e7-\u0904\u093a-\u093c\u093e-\u0957\u0962-\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09db\u09de\u09e2-\u09ef\u09f2-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a58\u0a5d\u0a5f-\u0a71\u0a75-\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abc\u0abe-\u0adf\u0ae1-\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3c\u0b3e-\u0b5b\u0b5e\u0b62-\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c5f\u0c62-\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cdd\u0cdf\u0ce2-\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d5f\u0d62-\u0e00\u0e2f\u0e31\u0e34-\u0e3f\u0e46-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eb1\u0eb4-\u0ebc\u0ebe-\u0ebf\u0ec5-\u0f3f\u0f48\u0f6a-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3006\u3008-\u3020\u302a-\u3040\u3095-\u30a0\u30fb-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa + +# Simpler things +nonPubidCharRegexp = re.compile("[^\x20\x0D\x0Aa-zA-Z0-9\\-'()+,./:=?;!*#@$_%]") + + +class InfosetFilter(object): + replacementRegexp = re.compile(r"U[\dA-F]{5,5}") + + def __init__(self, + dropXmlnsLocalName=False, + dropXmlnsAttrNs=False, + preventDoubleDashComments=False, + preventDashAtCommentEnd=False, + replaceFormFeedCharacters=True, + preventSingleQuotePubid=False): + + self.dropXmlnsLocalName = dropXmlnsLocalName + self.dropXmlnsAttrNs = dropXmlnsAttrNs + + self.preventDoubleDashComments = preventDoubleDashComments + self.preventDashAtCommentEnd = preventDashAtCommentEnd + + self.replaceFormFeedCharacters = replaceFormFeedCharacters + + self.preventSingleQuotePubid = preventSingleQuotePubid + + self.replaceCache = {} + + def coerceAttribute(self, name, namespace=None): + if self.dropXmlnsLocalName and name.startswith("xmlns:"): + warnings.warn("Attributes cannot begin with xmlns", DataLossWarning) + return None + elif (self.dropXmlnsAttrNs and + namespace == "http://www.w3.org/2000/xmlns/"): + warnings.warn("Attributes cannot be in the xml namespace", DataLossWarning) + return None + else: + return self.toXmlName(name) + + def coerceElement(self, name): + return self.toXmlName(name) + + def coerceComment(self, data): + if self.preventDoubleDashComments: + while "--" in data: + warnings.warn("Comments cannot contain adjacent dashes", DataLossWarning) + data = data.replace("--", "- -") + if data.endswith("-"): + warnings.warn("Comments cannot end in a dash", DataLossWarning) + data += " " + return data + + def coerceCharacters(self, data): + if self.replaceFormFeedCharacters: + for _ in range(data.count("\x0C")): + warnings.warn("Text cannot contain U+000C", DataLossWarning) + data = data.replace("\x0C", " ") + # Other non-xml characters + return data + + def coercePubid(self, data): + dataOutput = data + for char in nonPubidCharRegexp.findall(data): + warnings.warn("Coercing non-XML pubid", DataLossWarning) + replacement = self.getReplacementCharacter(char) + dataOutput = dataOutput.replace(char, replacement) + if self.preventSingleQuotePubid and dataOutput.find("'") >= 0: + warnings.warn("Pubid cannot contain single quote", DataLossWarning) + dataOutput = dataOutput.replace("'", self.getReplacementCharacter("'")) + return dataOutput + + def toXmlName(self, name): + nameFirst = name[0] + nameRest = name[1:] + m = nonXmlNameFirstBMPRegexp.match(nameFirst) + if m: + warnings.warn("Coercing non-XML name", DataLossWarning) + nameFirstOutput = self.getReplacementCharacter(nameFirst) + else: + nameFirstOutput = nameFirst + + nameRestOutput = nameRest + replaceChars = set(nonXmlNameBMPRegexp.findall(nameRest)) + for char in replaceChars: + warnings.warn("Coercing non-XML name", DataLossWarning) + replacement = self.getReplacementCharacter(char) + nameRestOutput = nameRestOutput.replace(char, replacement) + return nameFirstOutput + nameRestOutput + + def getReplacementCharacter(self, char): + if char in self.replaceCache: + replacement = self.replaceCache[char] + else: + replacement = self.escapeChar(char) + return replacement + + def fromXmlName(self, name): + for item in set(self.replacementRegexp.findall(name)): + name = name.replace(item, self.unescapeChar(item)) + return name + + def escapeChar(self, char): + replacement = "U%05X" % ord(char) + self.replaceCache[char] = replacement + return replacement + + def unescapeChar(self, charcode): + return chr(int(charcode[1:], 16)) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py new file mode 100755 index 0000000..21c6bbc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py @@ -0,0 +1,923 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import text_type, binary_type +from pip._vendor.six.moves import http_client, urllib + +import codecs +import re + +from pip._vendor import webencodings + +from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase +from .constants import _ReparseException +from . import _utils + +from io import StringIO + +try: + from io import BytesIO +except ImportError: + BytesIO = StringIO + +# Non-unicode versions of constants for use in the pre-parser +spaceCharactersBytes = frozenset([item.encode("ascii") for item in spaceCharacters]) +asciiLettersBytes = frozenset([item.encode("ascii") for item in asciiLetters]) +asciiUppercaseBytes = frozenset([item.encode("ascii") for item in asciiUppercase]) +spacesAngleBrackets = spaceCharactersBytes | frozenset([b">", b"<"]) + + +invalid_unicode_no_surrogate = "[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]" # noqa + +if _utils.supports_lone_surrogates: + # Use one extra step of indirection and create surrogates with + # eval. Not using this indirection would introduce an illegal + # unicode literal on platforms not supporting such lone + # surrogates. + assert invalid_unicode_no_surrogate[-1] == "]" and invalid_unicode_no_surrogate.count("]") == 1 + invalid_unicode_re = re.compile(invalid_unicode_no_surrogate[:-1] + + eval('"\\uD800-\\uDFFF"') + # pylint:disable=eval-used + "]") +else: + invalid_unicode_re = re.compile(invalid_unicode_no_surrogate) + +non_bmp_invalid_codepoints = set([0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, + 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, + 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE, + 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, + 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, + 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, + 0x10FFFE, 0x10FFFF]) + +ascii_punctuation_re = re.compile("[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005C\u005B-\u0060\u007B-\u007E]") + +# Cache for charsUntil() +charsUntilRegEx = {} + + +class BufferedStream(object): + """Buffering for streams that do not have buffering of their own + + The buffer is implemented as a list of chunks on the assumption that + joining many strings will be slow since it is O(n**2) + """ + + def __init__(self, stream): + self.stream = stream + self.buffer = [] + self.position = [-1, 0] # chunk number, offset + + def tell(self): + pos = 0 + for chunk in self.buffer[:self.position[0]]: + pos += len(chunk) + pos += self.position[1] + return pos + + def seek(self, pos): + assert pos <= self._bufferedBytes() + offset = pos + i = 0 + while len(self.buffer[i]) < offset: + offset -= len(self.buffer[i]) + i += 1 + self.position = [i, offset] + + def read(self, bytes): + if not self.buffer: + return self._readStream(bytes) + elif (self.position[0] == len(self.buffer) and + self.position[1] == len(self.buffer[-1])): + return self._readStream(bytes) + else: + return self._readFromBuffer(bytes) + + def _bufferedBytes(self): + return sum([len(item) for item in self.buffer]) + + def _readStream(self, bytes): + data = self.stream.read(bytes) + self.buffer.append(data) + self.position[0] += 1 + self.position[1] = len(data) + return data + + def _readFromBuffer(self, bytes): + remainingBytes = bytes + rv = [] + bufferIndex = self.position[0] + bufferOffset = self.position[1] + while bufferIndex < len(self.buffer) and remainingBytes != 0: + assert remainingBytes > 0 + bufferedData = self.buffer[bufferIndex] + + if remainingBytes <= len(bufferedData) - bufferOffset: + bytesToRead = remainingBytes + self.position = [bufferIndex, bufferOffset + bytesToRead] + else: + bytesToRead = len(bufferedData) - bufferOffset + self.position = [bufferIndex, len(bufferedData)] + bufferIndex += 1 + rv.append(bufferedData[bufferOffset:bufferOffset + bytesToRead]) + remainingBytes -= bytesToRead + + bufferOffset = 0 + + if remainingBytes: + rv.append(self._readStream(remainingBytes)) + + return b"".join(rv) + + +def HTMLInputStream(source, **kwargs): + # Work around Python bug #20007: read(0) closes the connection. + # http://bugs.python.org/issue20007 + if (isinstance(source, http_client.HTTPResponse) or + # Also check for addinfourl wrapping HTTPResponse + (isinstance(source, urllib.response.addbase) and + isinstance(source.fp, http_client.HTTPResponse))): + isUnicode = False + elif hasattr(source, "read"): + isUnicode = isinstance(source.read(0), text_type) + else: + isUnicode = isinstance(source, text_type) + + if isUnicode: + encodings = [x for x in kwargs if x.endswith("_encoding")] + if encodings: + raise TypeError("Cannot set an encoding with a unicode input, set %r" % encodings) + + return HTMLUnicodeInputStream(source, **kwargs) + else: + return HTMLBinaryInputStream(source, **kwargs) + + +class HTMLUnicodeInputStream(object): + """Provides a unicode stream of characters to the HTMLTokenizer. + + This class takes care of character encoding and removing or replacing + incorrect byte-sequences and also provides column and line tracking. + + """ + + _defaultChunkSize = 10240 + + def __init__(self, source): + """Initialises the HTMLInputStream. + + HTMLInputStream(source, [encoding]) -> Normalized stream from source + for use by html5lib. + + source can be either a file-object, local filename or a string. + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + """ + + if not _utils.supports_lone_surrogates: + # Such platforms will have already checked for such + # surrogate errors, so no need to do this checking. + self.reportCharacterErrors = None + elif len("\U0010FFFF") == 1: + self.reportCharacterErrors = self.characterErrorsUCS4 + else: + self.reportCharacterErrors = self.characterErrorsUCS2 + + # List of where new lines occur + self.newLines = [0] + + self.charEncoding = (lookupEncoding("utf-8"), "certain") + self.dataStream = self.openStream(source) + + self.reset() + + def reset(self): + self.chunk = "" + self.chunkSize = 0 + self.chunkOffset = 0 + self.errors = [] + + # number of (complete) lines in previous chunks + self.prevNumLines = 0 + # number of columns in the last line of the previous chunk + self.prevNumCols = 0 + + # Deal with CR LF and surrogates split over chunk boundaries + self._bufferedCharacter = None + + def openStream(self, source): + """Produces a file object from source. + + source can be either a file object, local filename or a string. + + """ + # Already a file object + if hasattr(source, 'read'): + stream = source + else: + stream = StringIO(source) + + return stream + + def _position(self, offset): + chunk = self.chunk + nLines = chunk.count('\n', 0, offset) + positionLine = self.prevNumLines + nLines + lastLinePos = chunk.rfind('\n', 0, offset) + if lastLinePos == -1: + positionColumn = self.prevNumCols + offset + else: + positionColumn = offset - (lastLinePos + 1) + return (positionLine, positionColumn) + + def position(self): + """Returns (line, col) of the current position in the stream.""" + line, col = self._position(self.chunkOffset) + return (line + 1, col) + + def char(self): + """ Read one character from the stream or queue if available. Return + EOF when EOF is reached. + """ + # Read a new chunk from the input stream if necessary + if self.chunkOffset >= self.chunkSize: + if not self.readChunk(): + return EOF + + chunkOffset = self.chunkOffset + char = self.chunk[chunkOffset] + self.chunkOffset = chunkOffset + 1 + + return char + + def readChunk(self, chunkSize=None): + if chunkSize is None: + chunkSize = self._defaultChunkSize + + self.prevNumLines, self.prevNumCols = self._position(self.chunkSize) + + self.chunk = "" + self.chunkSize = 0 + self.chunkOffset = 0 + + data = self.dataStream.read(chunkSize) + + # Deal with CR LF and surrogates broken across chunks + if self._bufferedCharacter: + data = self._bufferedCharacter + data + self._bufferedCharacter = None + elif not data: + # We have no more data, bye-bye stream + return False + + if len(data) > 1: + lastv = ord(data[-1]) + if lastv == 0x0D or 0xD800 <= lastv <= 0xDBFF: + self._bufferedCharacter = data[-1] + data = data[:-1] + + if self.reportCharacterErrors: + self.reportCharacterErrors(data) + + # Replace invalid characters + data = data.replace("\r\n", "\n") + data = data.replace("\r", "\n") + + self.chunk = data + self.chunkSize = len(data) + + return True + + def characterErrorsUCS4(self, data): + for _ in range(len(invalid_unicode_re.findall(data))): + self.errors.append("invalid-codepoint") + + def characterErrorsUCS2(self, data): + # Someone picked the wrong compile option + # You lose + skip = False + for match in invalid_unicode_re.finditer(data): + if skip: + continue + codepoint = ord(match.group()) + pos = match.start() + # Pretty sure there should be endianness issues here + if _utils.isSurrogatePair(data[pos:pos + 2]): + # We have a surrogate pair! + char_val = _utils.surrogatePairToCodepoint(data[pos:pos + 2]) + if char_val in non_bmp_invalid_codepoints: + self.errors.append("invalid-codepoint") + skip = True + elif (codepoint >= 0xD800 and codepoint <= 0xDFFF and + pos == len(data) - 1): + self.errors.append("invalid-codepoint") + else: + skip = False + self.errors.append("invalid-codepoint") + + def charsUntil(self, characters, opposite=False): + """ Returns a string of characters from the stream up to but not + including any character in 'characters' or EOF. 'characters' must be + a container that supports the 'in' method and iteration over its + characters. + """ + + # Use a cache of regexps to find the required characters + try: + chars = charsUntilRegEx[(characters, opposite)] + except KeyError: + if __debug__: + for c in characters: + assert(ord(c) < 128) + regex = "".join(["\\x%02x" % ord(c) for c in characters]) + if not opposite: + regex = "^%s" % regex + chars = charsUntilRegEx[(characters, opposite)] = re.compile("[%s]+" % regex) + + rv = [] + + while True: + # Find the longest matching prefix + m = chars.match(self.chunk, self.chunkOffset) + if m is None: + # If nothing matched, and it wasn't because we ran out of chunk, + # then stop + if self.chunkOffset != self.chunkSize: + break + else: + end = m.end() + # If not the whole chunk matched, return everything + # up to the part that didn't match + if end != self.chunkSize: + rv.append(self.chunk[self.chunkOffset:end]) + self.chunkOffset = end + break + # If the whole remainder of the chunk matched, + # use it all and read the next chunk + rv.append(self.chunk[self.chunkOffset:]) + if not self.readChunk(): + # Reached EOF + break + + r = "".join(rv) + return r + + def unget(self, char): + # Only one character is allowed to be ungotten at once - it must + # be consumed again before any further call to unget + if char is not None: + if self.chunkOffset == 0: + # unget is called quite rarely, so it's a good idea to do + # more work here if it saves a bit of work in the frequently + # called char and charsUntil. + # So, just prepend the ungotten character onto the current + # chunk: + self.chunk = char + self.chunk + self.chunkSize += 1 + else: + self.chunkOffset -= 1 + assert self.chunk[self.chunkOffset] == char + + +class HTMLBinaryInputStream(HTMLUnicodeInputStream): + """Provides a unicode stream of characters to the HTMLTokenizer. + + This class takes care of character encoding and removing or replacing + incorrect byte-sequences and also provides column and line tracking. + + """ + + def __init__(self, source, override_encoding=None, transport_encoding=None, + same_origin_parent_encoding=None, likely_encoding=None, + default_encoding="windows-1252", useChardet=True): + """Initialises the HTMLInputStream. + + HTMLInputStream(source, [encoding]) -> Normalized stream from source + for use by html5lib. + + source can be either a file-object, local filename or a string. + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + """ + # Raw Stream - for unicode objects this will encode to utf-8 and set + # self.charEncoding as appropriate + self.rawStream = self.openStream(source) + + HTMLUnicodeInputStream.__init__(self, self.rawStream) + + # Encoding Information + # Number of bytes to use when looking for a meta element with + # encoding information + self.numBytesMeta = 1024 + # Number of bytes to use when using detecting encoding using chardet + self.numBytesChardet = 100 + # Things from args + self.override_encoding = override_encoding + self.transport_encoding = transport_encoding + self.same_origin_parent_encoding = same_origin_parent_encoding + self.likely_encoding = likely_encoding + self.default_encoding = default_encoding + + # Determine encoding + self.charEncoding = self.determineEncoding(useChardet) + assert self.charEncoding[0] is not None + + # Call superclass + self.reset() + + def reset(self): + self.dataStream = self.charEncoding[0].codec_info.streamreader(self.rawStream, 'replace') + HTMLUnicodeInputStream.reset(self) + + def openStream(self, source): + """Produces a file object from source. + + source can be either a file object, local filename or a string. + + """ + # Already a file object + if hasattr(source, 'read'): + stream = source + else: + stream = BytesIO(source) + + try: + stream.seek(stream.tell()) + except: # pylint:disable=bare-except + stream = BufferedStream(stream) + + return stream + + def determineEncoding(self, chardet=True): + # BOMs take precedence over everything + # This will also read past the BOM if present + charEncoding = self.detectBOM(), "certain" + if charEncoding[0] is not None: + return charEncoding + + # If we've been overriden, we've been overriden + charEncoding = lookupEncoding(self.override_encoding), "certain" + if charEncoding[0] is not None: + return charEncoding + + # Now check the transport layer + charEncoding = lookupEncoding(self.transport_encoding), "certain" + if charEncoding[0] is not None: + return charEncoding + + # Look for meta elements with encoding information + charEncoding = self.detectEncodingMeta(), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Parent document encoding + charEncoding = lookupEncoding(self.same_origin_parent_encoding), "tentative" + if charEncoding[0] is not None and not charEncoding[0].name.startswith("utf-16"): + return charEncoding + + # "likely" encoding + charEncoding = lookupEncoding(self.likely_encoding), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Guess with chardet, if available + if chardet: + try: + from pip._vendor.chardet.universaldetector import UniversalDetector + except ImportError: + pass + else: + buffers = [] + detector = UniversalDetector() + while not detector.done: + buffer = self.rawStream.read(self.numBytesChardet) + assert isinstance(buffer, bytes) + if not buffer: + break + buffers.append(buffer) + detector.feed(buffer) + detector.close() + encoding = lookupEncoding(detector.result['encoding']) + self.rawStream.seek(0) + if encoding is not None: + return encoding, "tentative" + + # Try the default encoding + charEncoding = lookupEncoding(self.default_encoding), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Fallback to html5lib's default if even that hasn't worked + return lookupEncoding("windows-1252"), "tentative" + + def changeEncoding(self, newEncoding): + assert self.charEncoding[1] != "certain" + newEncoding = lookupEncoding(newEncoding) + if newEncoding is None: + return + if newEncoding.name in ("utf-16be", "utf-16le"): + newEncoding = lookupEncoding("utf-8") + assert newEncoding is not None + elif newEncoding == self.charEncoding[0]: + self.charEncoding = (self.charEncoding[0], "certain") + else: + self.rawStream.seek(0) + self.charEncoding = (newEncoding, "certain") + self.reset() + raise _ReparseException("Encoding changed from %s to %s" % (self.charEncoding[0], newEncoding)) + + def detectBOM(self): + """Attempts to detect at BOM at the start of the stream. If + an encoding can be determined from the BOM return the name of the + encoding otherwise return None""" + bomDict = { + codecs.BOM_UTF8: 'utf-8', + codecs.BOM_UTF16_LE: 'utf-16le', codecs.BOM_UTF16_BE: 'utf-16be', + codecs.BOM_UTF32_LE: 'utf-32le', codecs.BOM_UTF32_BE: 'utf-32be' + } + + # Go to beginning of file and read in 4 bytes + string = self.rawStream.read(4) + assert isinstance(string, bytes) + + # Try detecting the BOM using bytes from the string + encoding = bomDict.get(string[:3]) # UTF-8 + seek = 3 + if not encoding: + # Need to detect UTF-32 before UTF-16 + encoding = bomDict.get(string) # UTF-32 + seek = 4 + if not encoding: + encoding = bomDict.get(string[:2]) # UTF-16 + seek = 2 + + # Set the read position past the BOM if one was found, otherwise + # set it to the start of the stream + if encoding: + self.rawStream.seek(seek) + return lookupEncoding(encoding) + else: + self.rawStream.seek(0) + return None + + def detectEncodingMeta(self): + """Report the encoding declared by the meta element + """ + buffer = self.rawStream.read(self.numBytesMeta) + assert isinstance(buffer, bytes) + parser = EncodingParser(buffer) + self.rawStream.seek(0) + encoding = parser.getEncoding() + + if encoding is not None and encoding.name in ("utf-16be", "utf-16le"): + encoding = lookupEncoding("utf-8") + + return encoding + + +class EncodingBytes(bytes): + """String-like object with an associated position and various extra methods + If the position is ever greater than the string length then an exception is + raised""" + def __new__(self, value): + assert isinstance(value, bytes) + return bytes.__new__(self, value.lower()) + + def __init__(self, value): + # pylint:disable=unused-argument + self._position = -1 + + def __iter__(self): + return self + + def __next__(self): + p = self._position = self._position + 1 + if p >= len(self): + raise StopIteration + elif p < 0: + raise TypeError + return self[p:p + 1] + + def next(self): + # Py2 compat + return self.__next__() + + def previous(self): + p = self._position + if p >= len(self): + raise StopIteration + elif p < 0: + raise TypeError + self._position = p = p - 1 + return self[p:p + 1] + + def setPosition(self, position): + if self._position >= len(self): + raise StopIteration + self._position = position + + def getPosition(self): + if self._position >= len(self): + raise StopIteration + if self._position >= 0: + return self._position + else: + return None + + position = property(getPosition, setPosition) + + def getCurrentByte(self): + return self[self.position:self.position + 1] + + currentByte = property(getCurrentByte) + + def skip(self, chars=spaceCharactersBytes): + """Skip past a list of characters""" + p = self.position # use property for the error-checking + while p < len(self): + c = self[p:p + 1] + if c not in chars: + self._position = p + return c + p += 1 + self._position = p + return None + + def skipUntil(self, chars): + p = self.position + while p < len(self): + c = self[p:p + 1] + if c in chars: + self._position = p + return c + p += 1 + self._position = p + return None + + def matchBytes(self, bytes): + """Look for a sequence of bytes at the start of a string. If the bytes + are found return True and advance the position to the byte after the + match. Otherwise return False and leave the position alone""" + p = self.position + data = self[p:p + len(bytes)] + rv = data.startswith(bytes) + if rv: + self.position += len(bytes) + return rv + + def jumpTo(self, bytes): + """Look for the next sequence of bytes matching a given sequence. If + a match is found advance the position to the last byte of the match""" + newPosition = self[self.position:].find(bytes) + if newPosition > -1: + # XXX: This is ugly, but I can't see a nicer way to fix this. + if self._position == -1: + self._position = 0 + self._position += (newPosition + len(bytes) - 1) + return True + else: + raise StopIteration + + +class EncodingParser(object): + """Mini parser for detecting character encoding from meta elements""" + + def __init__(self, data): + """string - the data to work on for encoding detection""" + self.data = EncodingBytes(data) + self.encoding = None + + def getEncoding(self): + methodDispatch = ( + (b"<!--", self.handleComment), + (b"<meta", self.handleMeta), + (b"</", self.handlePossibleEndTag), + (b"<!", self.handleOther), + (b"<?", self.handleOther), + (b"<", self.handlePossibleStartTag)) + for _ in self.data: + keepParsing = True + for key, method in methodDispatch: + if self.data.matchBytes(key): + try: + keepParsing = method() + break + except StopIteration: + keepParsing = False + break + if not keepParsing: + break + + return self.encoding + + def handleComment(self): + """Skip over comments""" + return self.data.jumpTo(b"-->") + + def handleMeta(self): + if self.data.currentByte not in spaceCharactersBytes: + # if we have <meta not followed by a space so just keep going + return True + # We have a valid meta element we want to search for attributes + hasPragma = False + pendingEncoding = None + while True: + # Try to find the next attribute after the current position + attr = self.getAttribute() + if attr is None: + return True + else: + if attr[0] == b"http-equiv": + hasPragma = attr[1] == b"content-type" + if hasPragma and pendingEncoding is not None: + self.encoding = pendingEncoding + return False + elif attr[0] == b"charset": + tentativeEncoding = attr[1] + codec = lookupEncoding(tentativeEncoding) + if codec is not None: + self.encoding = codec + return False + elif attr[0] == b"content": + contentParser = ContentAttrParser(EncodingBytes(attr[1])) + tentativeEncoding = contentParser.parse() + if tentativeEncoding is not None: + codec = lookupEncoding(tentativeEncoding) + if codec is not None: + if hasPragma: + self.encoding = codec + return False + else: + pendingEncoding = codec + + def handlePossibleStartTag(self): + return self.handlePossibleTag(False) + + def handlePossibleEndTag(self): + next(self.data) + return self.handlePossibleTag(True) + + def handlePossibleTag(self, endTag): + data = self.data + if data.currentByte not in asciiLettersBytes: + # If the next byte is not an ascii letter either ignore this + # fragment (possible start tag case) or treat it according to + # handleOther + if endTag: + data.previous() + self.handleOther() + return True + + c = data.skipUntil(spacesAngleBrackets) + if c == b"<": + # return to the first step in the overall "two step" algorithm + # reprocessing the < byte + data.previous() + else: + # Read all attributes + attr = self.getAttribute() + while attr is not None: + attr = self.getAttribute() + return True + + def handleOther(self): + return self.data.jumpTo(b">") + + def getAttribute(self): + """Return a name,value pair for the next attribute in the stream, + if one is found, or None""" + data = self.data + # Step 1 (skip chars) + c = data.skip(spaceCharactersBytes | frozenset([b"/"])) + assert c is None or len(c) == 1 + # Step 2 + if c in (b">", None): + return None + # Step 3 + attrName = [] + attrValue = [] + # Step 4 attribute name + while True: + if c == b"=" and attrName: + break + elif c in spaceCharactersBytes: + # Step 6! + c = data.skip() + break + elif c in (b"/", b">"): + return b"".join(attrName), b"" + elif c in asciiUppercaseBytes: + attrName.append(c.lower()) + elif c is None: + return None + else: + attrName.append(c) + # Step 5 + c = next(data) + # Step 7 + if c != b"=": + data.previous() + return b"".join(attrName), b"" + # Step 8 + next(data) + # Step 9 + c = data.skip() + # Step 10 + if c in (b"'", b'"'): + # 10.1 + quoteChar = c + while True: + # 10.2 + c = next(data) + # 10.3 + if c == quoteChar: + next(data) + return b"".join(attrName), b"".join(attrValue) + # 10.4 + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + # 10.5 + else: + attrValue.append(c) + elif c == b">": + return b"".join(attrName), b"" + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + elif c is None: + return None + else: + attrValue.append(c) + # Step 11 + while True: + c = next(data) + if c in spacesAngleBrackets: + return b"".join(attrName), b"".join(attrValue) + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + elif c is None: + return None + else: + attrValue.append(c) + + +class ContentAttrParser(object): + def __init__(self, data): + assert isinstance(data, bytes) + self.data = data + + def parse(self): + try: + # Check if the attr name is charset + # otherwise return + self.data.jumpTo(b"charset") + self.data.position += 1 + self.data.skip() + if not self.data.currentByte == b"=": + # If there is no = sign keep looking for attrs + return None + self.data.position += 1 + self.data.skip() + # Look for an encoding between matching quote marks + if self.data.currentByte in (b'"', b"'"): + quoteMark = self.data.currentByte + self.data.position += 1 + oldPosition = self.data.position + if self.data.jumpTo(quoteMark): + return self.data[oldPosition:self.data.position] + else: + return None + else: + # Unquoted value + oldPosition = self.data.position + try: + self.data.skipUntil(spaceCharactersBytes) + return self.data[oldPosition:self.data.position] + except StopIteration: + # Return the whole remaining value + return self.data[oldPosition:] + except StopIteration: + return None + + +def lookupEncoding(encoding): + """Return the python codec name corresponding to an encoding or None if the + string doesn't correspond to a valid encoding.""" + if isinstance(encoding, binary_type): + try: + encoding = encoding.decode("ascii") + except UnicodeDecodeError: + return None + + if encoding is not None: + try: + return webencodings.lookup(encoding) + except AttributeError: + return None + else: + return None diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py new file mode 100755 index 0000000..ef1ccf8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py @@ -0,0 +1,1721 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import unichr as chr + +from collections import deque + +from .constants import spaceCharacters +from .constants import entities +from .constants import asciiLetters, asciiUpper2Lower +from .constants import digits, hexDigits, EOF +from .constants import tokenTypes, tagTokenTypes +from .constants import replacementCharacters + +from ._inputstream import HTMLInputStream + +from ._trie import Trie + +entitiesTrie = Trie(entities) + + +class HTMLTokenizer(object): + """ This class takes care of tokenizing HTML. + + * self.currentToken + Holds the token that is currently being processed. + + * self.state + Holds a reference to the method to be invoked... XXX + + * self.stream + Points to HTMLInputStream object. + """ + + def __init__(self, stream, parser=None, **kwargs): + + self.stream = HTMLInputStream(stream, **kwargs) + self.parser = parser + + # Setup the initial tokenizer state + self.escapeFlag = False + self.lastFourChars = [] + self.state = self.dataState + self.escape = False + + # The current token being created + self.currentToken = None + super(HTMLTokenizer, self).__init__() + + def __iter__(self): + """ This is where the magic happens. + + We do our usually processing through the states and when we have a token + to return we yield the token which pauses processing until the next token + is requested. + """ + self.tokenQueue = deque([]) + # Start processing. When EOF is reached self.state will return False + # instead of True and the loop will terminate. + while self.state(): + while self.stream.errors: + yield {"type": tokenTypes["ParseError"], "data": self.stream.errors.pop(0)} + while self.tokenQueue: + yield self.tokenQueue.popleft() + + def consumeNumberEntity(self, isHex): + """This function returns either U+FFFD or the character based on the + decimal or hexadecimal representation. It also discards ";" if present. + If not present self.tokenQueue.append({"type": tokenTypes["ParseError"]}) is invoked. + """ + + allowed = digits + radix = 10 + if isHex: + allowed = hexDigits + radix = 16 + + charStack = [] + + # Consume all the characters that are in range while making sure we + # don't hit an EOF. + c = self.stream.char() + while c in allowed and c is not EOF: + charStack.append(c) + c = self.stream.char() + + # Convert the set of characters consumed to an int. + charAsInt = int("".join(charStack), radix) + + # Certain characters get replaced with others + if charAsInt in replacementCharacters: + char = replacementCharacters[charAsInt] + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + elif ((0xD800 <= charAsInt <= 0xDFFF) or + (charAsInt > 0x10FFFF)): + char = "\uFFFD" + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + else: + # Should speed up this check somehow (e.g. move the set to a constant) + if ((0x0001 <= charAsInt <= 0x0008) or + (0x000E <= charAsInt <= 0x001F) or + (0x007F <= charAsInt <= 0x009F) or + (0xFDD0 <= charAsInt <= 0xFDEF) or + charAsInt in frozenset([0x000B, 0xFFFE, 0xFFFF, 0x1FFFE, + 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, + 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, + 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, + 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, + 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE, + 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, + 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, + 0xFFFFF, 0x10FFFE, 0x10FFFF])): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + try: + # Try/except needed as UCS-2 Python builds' unichar only works + # within the BMP. + char = chr(charAsInt) + except ValueError: + v = charAsInt - 0x10000 + char = chr(0xD800 | (v >> 10)) + chr(0xDC00 | (v & 0x3FF)) + + # Discard the ; if present. Otherwise, put it back on the queue and + # invoke parseError on parser. + if c != ";": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "numeric-entity-without-semicolon"}) + self.stream.unget(c) + + return char + + def consumeEntity(self, allowedChar=None, fromAttribute=False): + # Initialise to the default output for when no entity is matched + output = "&" + + charStack = [self.stream.char()] + if (charStack[0] in spaceCharacters or charStack[0] in (EOF, "<", "&") or + (allowedChar is not None and allowedChar == charStack[0])): + self.stream.unget(charStack[0]) + + elif charStack[0] == "#": + # Read the next character to see if it's hex or decimal + hex = False + charStack.append(self.stream.char()) + if charStack[-1] in ("x", "X"): + hex = True + charStack.append(self.stream.char()) + + # charStack[-1] should be the first digit + if (hex and charStack[-1] in hexDigits) \ + or (not hex and charStack[-1] in digits): + # At least one digit found, so consume the whole number + self.stream.unget(charStack[-1]) + output = self.consumeNumberEntity(hex) + else: + # No digits found + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "expected-numeric-entity"}) + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + + else: + # At this point in the process might have named entity. Entities + # are stored in the global variable "entities". + # + # Consume characters and compare to these to a substring of the + # entity names in the list until the substring no longer matches. + while (charStack[-1] is not EOF): + if not entitiesTrie.has_keys_with_prefix("".join(charStack)): + break + charStack.append(self.stream.char()) + + # At this point we have a string that starts with some characters + # that may match an entity + # Try to find the longest entity the string will match to take care + # of ¬i for instance. + try: + entityName = entitiesTrie.longest_prefix("".join(charStack[:-1])) + entityLength = len(entityName) + except KeyError: + entityName = None + + if entityName is not None: + if entityName[-1] != ";": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "named-entity-without-semicolon"}) + if (entityName[-1] != ";" and fromAttribute and + (charStack[entityLength] in asciiLetters or + charStack[entityLength] in digits or + charStack[entityLength] == "=")): + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + else: + output = entities[entityName] + self.stream.unget(charStack.pop()) + output += "".join(charStack[entityLength:]) + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-named-entity"}) + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + + if fromAttribute: + self.currentToken["data"][-1][1] += output + else: + if output in spaceCharacters: + tokenType = "SpaceCharacters" + else: + tokenType = "Characters" + self.tokenQueue.append({"type": tokenTypes[tokenType], "data": output}) + + def processEntityInAttribute(self, allowedChar): + """This method replaces the need for "entityInAttributeValueState". + """ + self.consumeEntity(allowedChar=allowedChar, fromAttribute=True) + + def emitCurrentToken(self): + """This method is a generic handler for emitting the tags. It also sets + the state to "data" because that's what's needed after a token has been + emitted. + """ + token = self.currentToken + # Add token to the queue to be yielded + if (token["type"] in tagTokenTypes): + token["name"] = token["name"].translate(asciiUpper2Lower) + if token["type"] == tokenTypes["EndTag"]: + if token["data"]: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "attributes-in-end-tag"}) + if token["selfClosing"]: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "self-closing-flag-on-end-tag"}) + self.tokenQueue.append(token) + self.state = self.dataState + + # Below are the various tokenizer states worked out. + def dataState(self): + data = self.stream.char() + if data == "&": + self.state = self.entityDataState + elif data == "<": + self.state = self.tagOpenState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\u0000"}) + elif data is EOF: + # Tokenization ends. + return False + elif data in spaceCharacters: + # Directly after emitting a token you switch back to the "data + # state". At that point spaceCharacters are important so they are + # emitted separately. + self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": + data + self.stream.charsUntil(spaceCharacters, True)}) + # No need to update lastFourChars here, since the first space will + # have already been appended to lastFourChars and will have broken + # any <!-- or --> sequences + else: + chars = self.stream.charsUntil(("&", "<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def entityDataState(self): + self.consumeEntity() + self.state = self.dataState + return True + + def rcdataState(self): + data = self.stream.char() + if data == "&": + self.state = self.characterReferenceInRcdata + elif data == "<": + self.state = self.rcdataLessThanSignState + elif data == EOF: + # Tokenization ends. + return False + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data in spaceCharacters: + # Directly after emitting a token you switch back to the "data + # state". At that point spaceCharacters are important so they are + # emitted separately. + self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": + data + self.stream.charsUntil(spaceCharacters, True)}) + # No need to update lastFourChars here, since the first space will + # have already been appended to lastFourChars and will have broken + # any <!-- or --> sequences + else: + chars = self.stream.charsUntil(("&", "<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def characterReferenceInRcdata(self): + self.consumeEntity() + self.state = self.rcdataState + return True + + def rawtextState(self): + data = self.stream.char() + if data == "<": + self.state = self.rawtextLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + # Tokenization ends. + return False + else: + chars = self.stream.charsUntil(("<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def scriptDataState(self): + data = self.stream.char() + if data == "<": + self.state = self.scriptDataLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + # Tokenization ends. + return False + else: + chars = self.stream.charsUntil(("<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def plaintextState(self): + data = self.stream.char() + if data == EOF: + # Tokenization ends. + return False + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + self.stream.charsUntil("\u0000")}) + return True + + def tagOpenState(self): + data = self.stream.char() + if data == "!": + self.state = self.markupDeclarationOpenState + elif data == "/": + self.state = self.closeTagOpenState + elif data in asciiLetters: + self.currentToken = {"type": tokenTypes["StartTag"], + "name": data, "data": [], + "selfClosing": False, + "selfClosingAcknowledged": False} + self.state = self.tagNameState + elif data == ">": + # XXX In theory it could be something besides a tag name. But + # do we really care? + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name-but-got-right-bracket"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<>"}) + self.state = self.dataState + elif data == "?": + # XXX In theory it could be something besides a tag name. But + # do we really care? + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name-but-got-question-mark"}) + self.stream.unget(data) + self.state = self.bogusCommentState + else: + # XXX + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.dataState + return True + + def closeTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.currentToken = {"type": tokenTypes["EndTag"], "name": data, + "data": [], "selfClosing": False} + self.state = self.tagNameState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-right-bracket"}) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-eof"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.state = self.dataState + else: + # XXX data can be _'_... + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-char", + "datavars": {"data": data}}) + self.stream.unget(data) + self.state = self.bogusCommentState + return True + + def tagNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == ">": + self.emitCurrentToken() + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-tag-name"}) + self.state = self.dataState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] += "\uFFFD" + else: + self.currentToken["name"] += data + # (Don't use charsUntil here, because tag names are + # very short and it's faster to not do anything fancy) + return True + + def rcdataLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.rcdataEndTagOpenState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rcdataEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.rcdataEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rcdataEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rawtextLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.rawtextEndTagOpenState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def rawtextEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.rawtextEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def rawtextEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def scriptDataLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.scriptDataEndTagOpenState + elif data == "!": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<!"}) + self.state = self.scriptDataEscapeStartState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.scriptDataEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapeStartState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapeStartDashState + else: + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapeStartDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashDashState + else: + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapedState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashState + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + self.state = self.dataState + else: + chars = self.stream.charsUntil(("<", "-", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def scriptDataEscapedDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashDashState + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataEscapedState + elif data == EOF: + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedDashDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) + self.state = self.scriptDataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataEscapedState + elif data == EOF: + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.scriptDataEscapedEndTagOpenState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<" + data}) + self.temporaryBuffer = data + self.state = self.scriptDataDoubleEscapeStartState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer = data + self.state = self.scriptDataEscapedEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataDoubleEscapeStartState(self): + data = self.stream.char() + if data in (spaceCharacters | frozenset(("/", ">"))): + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + if self.temporaryBuffer.lower() == "script": + self.state = self.scriptDataDoubleEscapedState + else: + self.state = self.scriptDataEscapedState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.temporaryBuffer += data + else: + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataDoubleEscapedState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataDoubleEscapedDashState + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + return True + + def scriptDataDoubleEscapedDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataDoubleEscapedDashDashState + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataDoubleEscapedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapedDashDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) + self.state = self.scriptDataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataDoubleEscapedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapedLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "/"}) + self.temporaryBuffer = "" + self.state = self.scriptDataDoubleEscapeEndState + else: + self.stream.unget(data) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapeEndState(self): + data = self.stream.char() + if data in (spaceCharacters | frozenset(("/", ">"))): + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + if self.temporaryBuffer.lower() == "script": + self.state = self.scriptDataEscapedState + else: + self.state = self.scriptDataDoubleEscapedState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.temporaryBuffer += data + else: + self.stream.unget(data) + self.state = self.scriptDataDoubleEscapedState + return True + + def beforeAttributeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data in asciiLetters: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == ">": + self.emitCurrentToken() + elif data == "/": + self.state = self.selfClosingStartTagState + elif data in ("'", '"', "=", "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "invalid-character-in-attribute-name"}) + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"].append(["\uFFFD", ""]) + self.state = self.attributeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-name-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + return True + + def attributeNameState(self): + data = self.stream.char() + leavingThisState = True + emitToken = False + if data == "=": + self.state = self.beforeAttributeValueState + elif data in asciiLetters: + self.currentToken["data"][-1][0] += data +\ + self.stream.charsUntil(asciiLetters, True) + leavingThisState = False + elif data == ">": + # XXX If we emit here the attributes are converted to a dict + # without being checked and when the code below runs we error + # because data is a dict not a list + emitToken = True + elif data in spaceCharacters: + self.state = self.afterAttributeNameState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][0] += "\uFFFD" + leavingThisState = False + elif data in ("'", '"', "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "invalid-character-in-attribute-name"}) + self.currentToken["data"][-1][0] += data + leavingThisState = False + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "eof-in-attribute-name"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][0] += data + leavingThisState = False + + if leavingThisState: + # Attributes are not dropped at this stage. That happens when the + # start tag token is emitted so values can still be safely appended + # to attributes, but we do want to report the parse error in time. + self.currentToken["data"][-1][0] = ( + self.currentToken["data"][-1][0].translate(asciiUpper2Lower)) + for name, _ in self.currentToken["data"][:-1]: + if self.currentToken["data"][-1][0] == name: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "duplicate-attribute"}) + break + # XXX Fix for above XXX + if emitToken: + self.emitCurrentToken() + return True + + def afterAttributeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data == "=": + self.state = self.beforeAttributeValueState + elif data == ">": + self.emitCurrentToken() + elif data in asciiLetters: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"].append(["\uFFFD", ""]) + self.state = self.attributeNameState + elif data in ("'", '"', "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "invalid-character-after-attribute-name"}) + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-end-of-tag-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + return True + + def beforeAttributeValueState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data == "\"": + self.state = self.attributeValueDoubleQuotedState + elif data == "&": + self.state = self.attributeValueUnQuotedState + self.stream.unget(data) + elif data == "'": + self.state = self.attributeValueSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-value-but-got-right-bracket"}) + self.emitCurrentToken() + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + self.state = self.attributeValueUnQuotedState + elif data in ("=", "<", "`"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "equals-in-unquoted-attribute-value"}) + self.currentToken["data"][-1][1] += data + self.state = self.attributeValueUnQuotedState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-value-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data + self.state = self.attributeValueUnQuotedState + return True + + def attributeValueDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterAttributeValueState + elif data == "&": + self.processEntityInAttribute('"') + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-double-quote"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data +\ + self.stream.charsUntil(("\"", "&", "\u0000")) + return True + + def attributeValueSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterAttributeValueState + elif data == "&": + self.processEntityInAttribute("'") + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-single-quote"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data +\ + self.stream.charsUntil(("'", "&", "\u0000")) + return True + + def attributeValueUnQuotedState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == "&": + self.processEntityInAttribute(">") + elif data == ">": + self.emitCurrentToken() + elif data in ('"', "'", "=", "<", "`"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-in-unquoted-attribute-value"}) + self.currentToken["data"][-1][1] += data + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-no-quotes"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data + self.stream.charsUntil( + frozenset(("&", ">", '"', "'", "=", "<", "`", "\u0000")) | spaceCharacters) + return True + + def afterAttributeValueState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == ">": + self.emitCurrentToken() + elif data == "/": + self.state = self.selfClosingStartTagState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-EOF-after-attribute-value"}) + self.stream.unget(data) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-after-attribute-value"}) + self.stream.unget(data) + self.state = self.beforeAttributeNameState + return True + + def selfClosingStartTagState(self): + data = self.stream.char() + if data == ">": + self.currentToken["selfClosing"] = True + self.emitCurrentToken() + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "unexpected-EOF-after-solidus-in-tag"}) + self.stream.unget(data) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-after-solidus-in-tag"}) + self.stream.unget(data) + self.state = self.beforeAttributeNameState + return True + + def bogusCommentState(self): + # Make a new comment token and give it as value all the characters + # until the first > or EOF (charsUntil checks for EOF automatically) + # and emit it. + data = self.stream.charsUntil(">") + data = data.replace("\u0000", "\uFFFD") + self.tokenQueue.append( + {"type": tokenTypes["Comment"], "data": data}) + + # Eat the character directly after the bogus comment which is either a + # ">" or an EOF. + self.stream.char() + self.state = self.dataState + return True + + def markupDeclarationOpenState(self): + charStack = [self.stream.char()] + if charStack[-1] == "-": + charStack.append(self.stream.char()) + if charStack[-1] == "-": + self.currentToken = {"type": tokenTypes["Comment"], "data": ""} + self.state = self.commentStartState + return True + elif charStack[-1] in ('d', 'D'): + matched = True + for expected in (('o', 'O'), ('c', 'C'), ('t', 'T'), + ('y', 'Y'), ('p', 'P'), ('e', 'E')): + charStack.append(self.stream.char()) + if charStack[-1] not in expected: + matched = False + break + if matched: + self.currentToken = {"type": tokenTypes["Doctype"], + "name": "", + "publicId": None, "systemId": None, + "correct": True} + self.state = self.doctypeState + return True + elif (charStack[-1] == "[" and + self.parser is not None and + self.parser.tree.openElements and + self.parser.tree.openElements[-1].namespace != self.parser.tree.defaultNamespace): + matched = True + for expected in ["C", "D", "A", "T", "A", "["]: + charStack.append(self.stream.char()) + if charStack[-1] != expected: + matched = False + break + if matched: + self.state = self.cdataSectionState + return True + + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-dashes-or-doctype"}) + + while charStack: + self.stream.unget(charStack.pop()) + self.state = self.bogusCommentState + return True + + def commentStartState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentStartDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "incorrect-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += data + self.state = self.commentState + return True + + def commentStartDashState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "-\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "incorrect-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "-" + data + self.state = self.commentState + return True + + def commentState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += data + \ + self.stream.charsUntil(("-", "\u0000")) + return True + + def commentEndDashState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "-\uFFFD" + self.state = self.commentState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-end-dash"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "-" + data + self.state = self.commentState + return True + + def commentEndState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "--\uFFFD" + self.state = self.commentState + elif data == "!": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-bang-after-double-dash-in-comment"}) + self.state = self.commentEndBangState + elif data == "-": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-dash-after-double-dash-in-comment"}) + self.currentToken["data"] += data + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-double-dash"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + # XXX + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-comment"}) + self.currentToken["data"] += "--" + data + self.state = self.commentState + return True + + def commentEndBangState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "-": + self.currentToken["data"] += "--!" + self.state = self.commentEndDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "--!\uFFFD" + self.state = self.commentState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-end-bang-state"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "--!" + data + self.state = self.commentState + return True + + def doctypeState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-eof"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "need-space-after-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypeNameState + return True + + def beforeDoctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-right-bracket"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] = "\uFFFD" + self.state = self.doctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-eof"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["name"] = data + self.state = self.doctypeNameState + return True + + def doctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.state = self.afterDoctypeNameState + elif data == ">": + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] += "\uFFFD" + self.state = self.doctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype-name"}) + self.currentToken["correct"] = False + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["name"] += data + return True + + def afterDoctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.currentToken["correct"] = False + self.stream.unget(data) + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + if data in ("p", "P"): + matched = True + for expected in (("u", "U"), ("b", "B"), ("l", "L"), + ("i", "I"), ("c", "C")): + data = self.stream.char() + if data not in expected: + matched = False + break + if matched: + self.state = self.afterDoctypePublicKeywordState + return True + elif data in ("s", "S"): + matched = True + for expected in (("y", "Y"), ("s", "S"), ("t", "T"), + ("e", "E"), ("m", "M")): + data = self.stream.char() + if data not in expected: + matched = False + break + if matched: + self.state = self.afterDoctypeSystemKeywordState + return True + + # All the characters read before the current 'data' will be + # [a-zA-Z], so they're garbage in the bogus doctype and can be + # discarded; only the latest character might be '>' or EOF + # and needs to be ungetted + self.stream.unget(data) + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-space-or-right-bracket-in-doctype", "datavars": + {"data": data}}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + + return True + + def afterDoctypePublicKeywordState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypePublicIdentifierState + elif data in ("'", '"'): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypePublicIdentifierState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.stream.unget(data) + self.state = self.beforeDoctypePublicIdentifierState + return True + + def beforeDoctypePublicIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == "\"": + self.currentToken["publicId"] = "" + self.state = self.doctypePublicIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["publicId"] = "" + self.state = self.doctypePublicIdentifierSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def doctypePublicIdentifierDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterDoctypePublicIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["publicId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["publicId"] += data + return True + + def doctypePublicIdentifierSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterDoctypePublicIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["publicId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["publicId"] += data + return True + + def afterDoctypePublicIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.betweenDoctypePublicAndSystemIdentifiersState + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == '"': + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def betweenDoctypePublicAndSystemIdentifiersState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == '"': + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def afterDoctypeSystemKeywordState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypeSystemIdentifierState + elif data in ("'", '"'): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypeSystemIdentifierState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.stream.unget(data) + self.state = self.beforeDoctypeSystemIdentifierState + return True + + def beforeDoctypeSystemIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == "\"": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def doctypeSystemIdentifierDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterDoctypeSystemIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["systemId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["systemId"] += data + return True + + def doctypeSystemIdentifierSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterDoctypeSystemIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["systemId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["systemId"] += data + return True + + def afterDoctypeSystemIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.state = self.bogusDoctypeState + return True + + def bogusDoctypeState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + # XXX EMIT + self.stream.unget(data) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + pass + return True + + def cdataSectionState(self): + data = [] + while True: + data.append(self.stream.charsUntil("]")) + data.append(self.stream.charsUntil(">")) + char = self.stream.char() + if char == EOF: + break + else: + assert char == ">" + if data[-1][-2:] == "]]": + data[-1] = data[-1][:-2] + break + else: + data.append(char) + + data = "".join(data) # pylint:disable=redefined-variable-type + # Deal with null here rather than in the parser + nullCount = data.count("\u0000") + if nullCount > 0: + for _ in range(nullCount): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + data = data.replace("\u0000", "\uFFFD") + if data: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": data}) + self.state = self.dataState + return True diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py new file mode 100755 index 0000000..ccc70bd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, unicode_literals + +from .py import Trie as PyTrie + +Trie = PyTrie + +# pylint:disable=wrong-import-position +try: + from .datrie import Trie as DATrie +except ImportError: + pass +else: + Trie = DATrie +# pylint:enable=wrong-import-position diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py new file mode 100755 index 0000000..ecfff32 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py @@ -0,0 +1,37 @@ +from __future__ import absolute_import, division, unicode_literals + +from collections import Mapping + + +class Trie(Mapping): + """Abstract base class for tries""" + + def keys(self, prefix=None): + # pylint:disable=arguments-differ + keys = super(Trie, self).keys() + + if prefix is None: + return set(keys) + + return {x for x in keys if x.startswith(prefix)} + + def has_keys_with_prefix(self, prefix): + for key in self.keys(): + if key.startswith(prefix): + return True + + return False + + def longest_prefix(self, prefix): + if prefix in self: + return prefix + + for i in range(1, len(prefix) + 1): + if prefix[:-i] in self: + return prefix[:-i] + + raise KeyError(prefix) + + def longest_prefix_item(self, prefix): + lprefix = self.longest_prefix(prefix) + return (lprefix, self[lprefix]) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py new file mode 100755 index 0000000..cb1af60 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import, division, unicode_literals + +from datrie import Trie as DATrie +from pip._vendor.six import text_type + +from ._base import Trie as ABCTrie + + +class Trie(ABCTrie): + def __init__(self, data): + chars = set() + for key in data.keys(): + if not isinstance(key, text_type): + raise TypeError("All keys must be strings") + for char in key: + chars.add(char) + + self._data = DATrie("".join(chars)) + for key, value in data.items(): + self._data[key] = value + + def __contains__(self, key): + return key in self._data + + def __len__(self): + return len(self._data) + + def __iter__(self): + raise NotImplementedError() + + def __getitem__(self, key): + return self._data[key] + + def keys(self, prefix=None): + return self._data.keys(prefix) + + def has_keys_with_prefix(self, prefix): + return self._data.has_keys_with_prefix(prefix) + + def longest_prefix(self, prefix): + return self._data.longest_prefix(prefix) + + def longest_prefix_item(self, prefix): + return self._data.longest_prefix_item(prefix) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py new file mode 100755 index 0000000..5531263 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py @@ -0,0 +1,67 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from bisect import bisect_left + +from ._base import Trie as ABCTrie + + +class Trie(ABCTrie): + def __init__(self, data): + if not all(isinstance(x, text_type) for x in data.keys()): + raise TypeError("All keys must be strings") + + self._data = data + self._keys = sorted(data.keys()) + self._cachestr = "" + self._cachepoints = (0, len(data)) + + def __contains__(self, key): + return key in self._data + + def __len__(self): + return len(self._data) + + def __iter__(self): + return iter(self._data) + + def __getitem__(self, key): + return self._data[key] + + def keys(self, prefix=None): + if prefix is None or prefix == "" or not self._keys: + return set(self._keys) + + if prefix.startswith(self._cachestr): + lo, hi = self._cachepoints + start = i = bisect_left(self._keys, prefix, lo, hi) + else: + start = i = bisect_left(self._keys, prefix) + + keys = set() + if start == len(self._keys): + return keys + + while self._keys[i].startswith(prefix): + keys.add(self._keys[i]) + i += 1 + + self._cachestr = prefix + self._cachepoints = (start, i) + + return keys + + def has_keys_with_prefix(self, prefix): + if prefix in self._data: + return True + + if prefix.startswith(self._cachestr): + lo, hi = self._cachepoints + i = bisect_left(self._keys, prefix, lo, hi) + else: + i = bisect_left(self._keys, prefix) + + if i == len(self._keys): + return False + + return self._keys[i].startswith(prefix) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py new file mode 100755 index 0000000..a559fa0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py @@ -0,0 +1,124 @@ +from __future__ import absolute_import, division, unicode_literals + +from types import ModuleType + +from pip._vendor.six import text_type + +try: + import xml.etree.cElementTree as default_etree +except ImportError: + import xml.etree.ElementTree as default_etree + + +__all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair", + "surrogatePairToCodepoint", "moduleFactoryFactory", + "supports_lone_surrogates"] + + +# Platforms not supporting lone surrogates (\uD800-\uDFFF) should be +# caught by the below test. In general this would be any platform +# using UTF-16 as its encoding of unicode strings, such as +# Jython. This is because UTF-16 itself is based on the use of such +# surrogates, and there is no mechanism to further escape such +# escapes. +try: + _x = eval('"\\uD800"') # pylint:disable=eval-used + if not isinstance(_x, text_type): + # We need this with u"" because of http://bugs.jython.org/issue2039 + _x = eval('u"\\uD800"') # pylint:disable=eval-used + assert isinstance(_x, text_type) +except: # pylint:disable=bare-except + supports_lone_surrogates = False +else: + supports_lone_surrogates = True + + +class MethodDispatcher(dict): + """Dict with 2 special properties: + + On initiation, keys that are lists, sets or tuples are converted to + multiple keys so accessing any one of the items in the original + list-like object returns the matching value + + md = MethodDispatcher({("foo", "bar"):"baz"}) + md["foo"] == "baz" + + A default value which can be set through the default attribute. + """ + + def __init__(self, items=()): + # Using _dictEntries instead of directly assigning to self is about + # twice as fast. Please do careful performance testing before changing + # anything here. + _dictEntries = [] + for name, value in items: + if isinstance(name, (list, tuple, frozenset, set)): + for item in name: + _dictEntries.append((item, value)) + else: + _dictEntries.append((name, value)) + dict.__init__(self, _dictEntries) + assert len(self) == len(_dictEntries) + self.default = None + + def __getitem__(self, key): + return dict.get(self, key, self.default) + + +# Some utility functions to deal with weirdness around UCS2 vs UCS4 +# python builds + +def isSurrogatePair(data): + return (len(data) == 2 and + ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and + ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF) + + +def surrogatePairToCodepoint(data): + char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 + + (ord(data[1]) - 0xDC00)) + return char_val + +# Module Factory Factory (no, this isn't Java, I know) +# Here to stop this being duplicated all over the place. + + +def moduleFactoryFactory(factory): + moduleCache = {} + + def moduleFactory(baseModule, *args, **kwargs): + if isinstance(ModuleType.__name__, type("")): + name = "_%s_factory" % baseModule.__name__ + else: + name = b"_%s_factory" % baseModule.__name__ + + kwargs_tuple = tuple(kwargs.items()) + + try: + return moduleCache[name][args][kwargs_tuple] + except KeyError: + mod = ModuleType(name) + objs = factory(baseModule, *args, **kwargs) + mod.__dict__.update(objs) + if "name" not in moduleCache: + moduleCache[name] = {} + if "args" not in moduleCache[name]: + moduleCache[name][args] = {} + if "kwargs" not in moduleCache[name][args]: + moduleCache[name][args][kwargs_tuple] = {} + moduleCache[name][args][kwargs_tuple] = mod + return mod + + return moduleFactory + + +def memoize(func): + cache = {} + + def wrapped(*args, **kwargs): + key = (tuple(args), tuple(kwargs.items())) + if key not in cache: + cache[key] = func(*args, **kwargs) + return cache[key] + + return wrapped diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py new file mode 100755 index 0000000..bca155e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py @@ -0,0 +1,2947 @@ +from __future__ import absolute_import, division, unicode_literals + +import string + +EOF = None + +E = { + "null-character": + "Null character in input stream, replaced with U+FFFD.", + "invalid-codepoint": + "Invalid codepoint in stream.", + "incorrectly-placed-solidus": + "Solidus (/) incorrectly placed in tag.", + "incorrect-cr-newline-entity": + "Incorrect CR newline entity, replaced with LF.", + "illegal-windows-1252-entity": + "Entity used with illegal number (windows-1252 reference).", + "cant-convert-numeric-entity": + "Numeric entity couldn't be converted to character " + "(codepoint U+%(charAsInt)08x).", + "illegal-codepoint-for-numeric-entity": + "Numeric entity represents an illegal codepoint: " + "U+%(charAsInt)08x.", + "numeric-entity-without-semicolon": + "Numeric entity didn't end with ';'.", + "expected-numeric-entity-but-got-eof": + "Numeric entity expected. Got end of file instead.", + "expected-numeric-entity": + "Numeric entity expected but none found.", + "named-entity-without-semicolon": + "Named entity didn't end with ';'.", + "expected-named-entity": + "Named entity expected. Got none.", + "attributes-in-end-tag": + "End tag contains unexpected attributes.", + 'self-closing-flag-on-end-tag': + "End tag contains unexpected self-closing flag.", + "expected-tag-name-but-got-right-bracket": + "Expected tag name. Got '>' instead.", + "expected-tag-name-but-got-question-mark": + "Expected tag name. Got '?' instead. (HTML doesn't " + "support processing instructions.)", + "expected-tag-name": + "Expected tag name. Got something else instead", + "expected-closing-tag-but-got-right-bracket": + "Expected closing tag. Got '>' instead. Ignoring '</>'.", + "expected-closing-tag-but-got-eof": + "Expected closing tag. Unexpected end of file.", + "expected-closing-tag-but-got-char": + "Expected closing tag. Unexpected character '%(data)s' found.", + "eof-in-tag-name": + "Unexpected end of file in the tag name.", + "expected-attribute-name-but-got-eof": + "Unexpected end of file. Expected attribute name instead.", + "eof-in-attribute-name": + "Unexpected end of file in attribute name.", + "invalid-character-in-attribute-name": + "Invalid character in attribute name", + "duplicate-attribute": + "Dropped duplicate attribute on tag.", + "expected-end-of-tag-name-but-got-eof": + "Unexpected end of file. Expected = or end of tag.", + "expected-attribute-value-but-got-eof": + "Unexpected end of file. Expected attribute value.", + "expected-attribute-value-but-got-right-bracket": + "Expected attribute value. Got '>' instead.", + 'equals-in-unquoted-attribute-value': + "Unexpected = in unquoted attribute", + 'unexpected-character-in-unquoted-attribute-value': + "Unexpected character in unquoted attribute", + "invalid-character-after-attribute-name": + "Unexpected character after attribute name.", + "unexpected-character-after-attribute-value": + "Unexpected character after attribute value.", + "eof-in-attribute-value-double-quote": + "Unexpected end of file in attribute value (\").", + "eof-in-attribute-value-single-quote": + "Unexpected end of file in attribute value (').", + "eof-in-attribute-value-no-quotes": + "Unexpected end of file in attribute value.", + "unexpected-EOF-after-solidus-in-tag": + "Unexpected end of file in tag. Expected >", + "unexpected-character-after-solidus-in-tag": + "Unexpected character after / in tag. Expected >", + "expected-dashes-or-doctype": + "Expected '--' or 'DOCTYPE'. Not found.", + "unexpected-bang-after-double-dash-in-comment": + "Unexpected ! after -- in comment", + "unexpected-space-after-double-dash-in-comment": + "Unexpected space after -- in comment", + "incorrect-comment": + "Incorrect comment.", + "eof-in-comment": + "Unexpected end of file in comment.", + "eof-in-comment-end-dash": + "Unexpected end of file in comment (-)", + "unexpected-dash-after-double-dash-in-comment": + "Unexpected '-' after '--' found in comment.", + "eof-in-comment-double-dash": + "Unexpected end of file in comment (--).", + "eof-in-comment-end-space-state": + "Unexpected end of file in comment.", + "eof-in-comment-end-bang-state": + "Unexpected end of file in comment.", + "unexpected-char-in-comment": + "Unexpected character in comment found.", + "need-space-after-doctype": + "No space after literal string 'DOCTYPE'.", + "expected-doctype-name-but-got-right-bracket": + "Unexpected > character. Expected DOCTYPE name.", + "expected-doctype-name-but-got-eof": + "Unexpected end of file. Expected DOCTYPE name.", + "eof-in-doctype-name": + "Unexpected end of file in DOCTYPE name.", + "eof-in-doctype": + "Unexpected end of file in DOCTYPE.", + "expected-space-or-right-bracket-in-doctype": + "Expected space or '>'. Got '%(data)s'", + "unexpected-end-of-doctype": + "Unexpected end of DOCTYPE.", + "unexpected-char-in-doctype": + "Unexpected character in DOCTYPE.", + "eof-in-innerhtml": + "XXX innerHTML EOF", + "unexpected-doctype": + "Unexpected DOCTYPE. Ignored.", + "non-html-root": + "html needs to be the first start tag.", + "expected-doctype-but-got-eof": + "Unexpected End of file. Expected DOCTYPE.", + "unknown-doctype": + "Erroneous DOCTYPE.", + "expected-doctype-but-got-chars": + "Unexpected non-space characters. Expected DOCTYPE.", + "expected-doctype-but-got-start-tag": + "Unexpected start tag (%(name)s). Expected DOCTYPE.", + "expected-doctype-but-got-end-tag": + "Unexpected end tag (%(name)s). Expected DOCTYPE.", + "end-tag-after-implied-root": + "Unexpected end tag (%(name)s) after the (implied) root element.", + "expected-named-closing-tag-but-got-eof": + "Unexpected end of file. Expected end tag (%(name)s).", + "two-heads-are-not-better-than-one": + "Unexpected start tag head in existing head. Ignored.", + "unexpected-end-tag": + "Unexpected end tag (%(name)s). Ignored.", + "unexpected-start-tag-out-of-my-head": + "Unexpected start tag (%(name)s) that can be in head. Moved.", + "unexpected-start-tag": + "Unexpected start tag (%(name)s).", + "missing-end-tag": + "Missing end tag (%(name)s).", + "missing-end-tags": + "Missing end tags (%(name)s).", + "unexpected-start-tag-implies-end-tag": + "Unexpected start tag (%(startName)s) " + "implies end tag (%(endName)s).", + "unexpected-start-tag-treated-as": + "Unexpected start tag (%(originalName)s). Treated as %(newName)s.", + "deprecated-tag": + "Unexpected start tag %(name)s. Don't use it!", + "unexpected-start-tag-ignored": + "Unexpected start tag %(name)s. Ignored.", + "expected-one-end-tag-but-got-another": + "Unexpected end tag (%(gotName)s). " + "Missing end tag (%(expectedName)s).", + "end-tag-too-early": + "End tag (%(name)s) seen too early. Expected other end tag.", + "end-tag-too-early-named": + "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).", + "end-tag-too-early-ignored": + "End tag (%(name)s) seen too early. Ignored.", + "adoption-agency-1.1": + "End tag (%(name)s) violates step 1, " + "paragraph 1 of the adoption agency algorithm.", + "adoption-agency-1.2": + "End tag (%(name)s) violates step 1, " + "paragraph 2 of the adoption agency algorithm.", + "adoption-agency-1.3": + "End tag (%(name)s) violates step 1, " + "paragraph 3 of the adoption agency algorithm.", + "adoption-agency-4.4": + "End tag (%(name)s) violates step 4, " + "paragraph 4 of the adoption agency algorithm.", + "unexpected-end-tag-treated-as": + "Unexpected end tag (%(originalName)s). Treated as %(newName)s.", + "no-end-tag": + "This element (%(name)s) has no end tag.", + "unexpected-implied-end-tag-in-table": + "Unexpected implied end tag (%(name)s) in the table phase.", + "unexpected-implied-end-tag-in-table-body": + "Unexpected implied end tag (%(name)s) in the table body phase.", + "unexpected-char-implies-table-voodoo": + "Unexpected non-space characters in " + "table context caused voodoo mode.", + "unexpected-hidden-input-in-table": + "Unexpected input with type hidden in table context.", + "unexpected-form-in-table": + "Unexpected form in table context.", + "unexpected-start-tag-implies-table-voodoo": + "Unexpected start tag (%(name)s) in " + "table context caused voodoo mode.", + "unexpected-end-tag-implies-table-voodoo": + "Unexpected end tag (%(name)s) in " + "table context caused voodoo mode.", + "unexpected-cell-in-table-body": + "Unexpected table cell start tag (%(name)s) " + "in the table body phase.", + "unexpected-cell-end-tag": + "Got table cell end tag (%(name)s) " + "while required end tags are missing.", + "unexpected-end-tag-in-table-body": + "Unexpected end tag (%(name)s) in the table body phase. Ignored.", + "unexpected-implied-end-tag-in-table-row": + "Unexpected implied end tag (%(name)s) in the table row phase.", + "unexpected-end-tag-in-table-row": + "Unexpected end tag (%(name)s) in the table row phase. Ignored.", + "unexpected-select-in-select": + "Unexpected select start tag in the select phase " + "treated as select end tag.", + "unexpected-input-in-select": + "Unexpected input start tag in the select phase.", + "unexpected-start-tag-in-select": + "Unexpected start tag token (%(name)s in the select phase. " + "Ignored.", + "unexpected-end-tag-in-select": + "Unexpected end tag (%(name)s) in the select phase. Ignored.", + "unexpected-table-element-start-tag-in-select-in-table": + "Unexpected table element start tag (%(name)s) in the select in table phase.", + "unexpected-table-element-end-tag-in-select-in-table": + "Unexpected table element end tag (%(name)s) in the select in table phase.", + "unexpected-char-after-body": + "Unexpected non-space characters in the after body phase.", + "unexpected-start-tag-after-body": + "Unexpected start tag token (%(name)s)" + " in the after body phase.", + "unexpected-end-tag-after-body": + "Unexpected end tag token (%(name)s)" + " in the after body phase.", + "unexpected-char-in-frameset": + "Unexpected characters in the frameset phase. Characters ignored.", + "unexpected-start-tag-in-frameset": + "Unexpected start tag token (%(name)s)" + " in the frameset phase. Ignored.", + "unexpected-frameset-in-frameset-innerhtml": + "Unexpected end tag token (frameset) " + "in the frameset phase (innerHTML).", + "unexpected-end-tag-in-frameset": + "Unexpected end tag token (%(name)s)" + " in the frameset phase. Ignored.", + "unexpected-char-after-frameset": + "Unexpected non-space characters in the " + "after frameset phase. Ignored.", + "unexpected-start-tag-after-frameset": + "Unexpected start tag (%(name)s)" + " in the after frameset phase. Ignored.", + "unexpected-end-tag-after-frameset": + "Unexpected end tag (%(name)s)" + " in the after frameset phase. Ignored.", + "unexpected-end-tag-after-body-innerhtml": + "Unexpected end tag after body(innerHtml)", + "expected-eof-but-got-char": + "Unexpected non-space characters. Expected end of file.", + "expected-eof-but-got-start-tag": + "Unexpected start tag (%(name)s)" + ". Expected end of file.", + "expected-eof-but-got-end-tag": + "Unexpected end tag (%(name)s)" + ". Expected end of file.", + "eof-in-table": + "Unexpected end of file. Expected table content.", + "eof-in-select": + "Unexpected end of file. Expected select content.", + "eof-in-frameset": + "Unexpected end of file. Expected frameset content.", + "eof-in-script-in-script": + "Unexpected end of file. Expected script content.", + "eof-in-foreign-lands": + "Unexpected end of file. Expected foreign content", + "non-void-element-with-trailing-solidus": + "Trailing solidus not allowed on element %(name)s", + "unexpected-html-element-in-foreign-content": + "Element %(name)s not allowed in a non-html context", + "unexpected-end-tag-before-html": + "Unexpected end tag (%(name)s) before html.", + "unexpected-inhead-noscript-tag": + "Element %(name)s not allowed in a inhead-noscript context", + "eof-in-head-noscript": + "Unexpected end of file. Expected inhead-noscript content", + "char-in-head-noscript": + "Unexpected non-space character. Expected inhead-noscript content", + "XXX-undefined-error": + "Undefined error (this sucks and should be fixed)", +} + +namespaces = { + "html": "http://www.w3.org/1999/xhtml", + "mathml": "http://www.w3.org/1998/Math/MathML", + "svg": "http://www.w3.org/2000/svg", + "xlink": "http://www.w3.org/1999/xlink", + "xml": "http://www.w3.org/XML/1998/namespace", + "xmlns": "http://www.w3.org/2000/xmlns/" +} + +scopingElements = frozenset([ + (namespaces["html"], "applet"), + (namespaces["html"], "caption"), + (namespaces["html"], "html"), + (namespaces["html"], "marquee"), + (namespaces["html"], "object"), + (namespaces["html"], "table"), + (namespaces["html"], "td"), + (namespaces["html"], "th"), + (namespaces["mathml"], "mi"), + (namespaces["mathml"], "mo"), + (namespaces["mathml"], "mn"), + (namespaces["mathml"], "ms"), + (namespaces["mathml"], "mtext"), + (namespaces["mathml"], "annotation-xml"), + (namespaces["svg"], "foreignObject"), + (namespaces["svg"], "desc"), + (namespaces["svg"], "title"), +]) + +formattingElements = frozenset([ + (namespaces["html"], "a"), + (namespaces["html"], "b"), + (namespaces["html"], "big"), + (namespaces["html"], "code"), + (namespaces["html"], "em"), + (namespaces["html"], "font"), + (namespaces["html"], "i"), + (namespaces["html"], "nobr"), + (namespaces["html"], "s"), + (namespaces["html"], "small"), + (namespaces["html"], "strike"), + (namespaces["html"], "strong"), + (namespaces["html"], "tt"), + (namespaces["html"], "u") +]) + +specialElements = frozenset([ + (namespaces["html"], "address"), + (namespaces["html"], "applet"), + (namespaces["html"], "area"), + (namespaces["html"], "article"), + (namespaces["html"], "aside"), + (namespaces["html"], "base"), + (namespaces["html"], "basefont"), + (namespaces["html"], "bgsound"), + (namespaces["html"], "blockquote"), + (namespaces["html"], "body"), + (namespaces["html"], "br"), + (namespaces["html"], "button"), + (namespaces["html"], "caption"), + (namespaces["html"], "center"), + (namespaces["html"], "col"), + (namespaces["html"], "colgroup"), + (namespaces["html"], "command"), + (namespaces["html"], "dd"), + (namespaces["html"], "details"), + (namespaces["html"], "dir"), + (namespaces["html"], "div"), + (namespaces["html"], "dl"), + (namespaces["html"], "dt"), + (namespaces["html"], "embed"), + (namespaces["html"], "fieldset"), + (namespaces["html"], "figure"), + (namespaces["html"], "footer"), + (namespaces["html"], "form"), + (namespaces["html"], "frame"), + (namespaces["html"], "frameset"), + (namespaces["html"], "h1"), + (namespaces["html"], "h2"), + (namespaces["html"], "h3"), + (namespaces["html"], "h4"), + (namespaces["html"], "h5"), + (namespaces["html"], "h6"), + (namespaces["html"], "head"), + (namespaces["html"], "header"), + (namespaces["html"], "hr"), + (namespaces["html"], "html"), + (namespaces["html"], "iframe"), + # Note that image is commented out in the spec as "this isn't an + # element that can end up on the stack, so it doesn't matter," + (namespaces["html"], "image"), + (namespaces["html"], "img"), + (namespaces["html"], "input"), + (namespaces["html"], "isindex"), + (namespaces["html"], "li"), + (namespaces["html"], "link"), + (namespaces["html"], "listing"), + (namespaces["html"], "marquee"), + (namespaces["html"], "menu"), + (namespaces["html"], "meta"), + (namespaces["html"], "nav"), + (namespaces["html"], "noembed"), + (namespaces["html"], "noframes"), + (namespaces["html"], "noscript"), + (namespaces["html"], "object"), + (namespaces["html"], "ol"), + (namespaces["html"], "p"), + (namespaces["html"], "param"), + (namespaces["html"], "plaintext"), + (namespaces["html"], "pre"), + (namespaces["html"], "script"), + (namespaces["html"], "section"), + (namespaces["html"], "select"), + (namespaces["html"], "style"), + (namespaces["html"], "table"), + (namespaces["html"], "tbody"), + (namespaces["html"], "td"), + (namespaces["html"], "textarea"), + (namespaces["html"], "tfoot"), + (namespaces["html"], "th"), + (namespaces["html"], "thead"), + (namespaces["html"], "title"), + (namespaces["html"], "tr"), + (namespaces["html"], "ul"), + (namespaces["html"], "wbr"), + (namespaces["html"], "xmp"), + (namespaces["svg"], "foreignObject") +]) + +htmlIntegrationPointElements = frozenset([ + (namespaces["mathml"], "annotation-xml"), + (namespaces["svg"], "foreignObject"), + (namespaces["svg"], "desc"), + (namespaces["svg"], "title") +]) + +mathmlTextIntegrationPointElements = frozenset([ + (namespaces["mathml"], "mi"), + (namespaces["mathml"], "mo"), + (namespaces["mathml"], "mn"), + (namespaces["mathml"], "ms"), + (namespaces["mathml"], "mtext") +]) + +adjustSVGAttributes = { + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "contentscripttype": "contentScriptType", + "contentstyletype": "contentStyleType", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "externalresourcesrequired": "externalResourcesRequired", + "filterres": "filterRes", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan" +} + +adjustMathMLAttributes = {"definitionurl": "definitionURL"} + +adjustForeignAttributes = { + "xlink:actuate": ("xlink", "actuate", namespaces["xlink"]), + "xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]), + "xlink:href": ("xlink", "href", namespaces["xlink"]), + "xlink:role": ("xlink", "role", namespaces["xlink"]), + "xlink:show": ("xlink", "show", namespaces["xlink"]), + "xlink:title": ("xlink", "title", namespaces["xlink"]), + "xlink:type": ("xlink", "type", namespaces["xlink"]), + "xml:base": ("xml", "base", namespaces["xml"]), + "xml:lang": ("xml", "lang", namespaces["xml"]), + "xml:space": ("xml", "space", namespaces["xml"]), + "xmlns": (None, "xmlns", namespaces["xmlns"]), + "xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"]) +} + +unadjustForeignAttributes = dict([((ns, local), qname) for qname, (prefix, local, ns) in + adjustForeignAttributes.items()]) + +spaceCharacters = frozenset([ + "\t", + "\n", + "\u000C", + " ", + "\r" +]) + +tableInsertModeElements = frozenset([ + "table", + "tbody", + "tfoot", + "thead", + "tr" +]) + +asciiLowercase = frozenset(string.ascii_lowercase) +asciiUppercase = frozenset(string.ascii_uppercase) +asciiLetters = frozenset(string.ascii_letters) +digits = frozenset(string.digits) +hexDigits = frozenset(string.hexdigits) + +asciiUpper2Lower = dict([(ord(c), ord(c.lower())) + for c in string.ascii_uppercase]) + +# Heading elements need to be ordered +headingElements = ( + "h1", + "h2", + "h3", + "h4", + "h5", + "h6" +) + +voidElements = frozenset([ + "base", + "command", + "event-source", + "link", + "meta", + "hr", + "br", + "img", + "embed", + "param", + "area", + "col", + "input", + "source", + "track" +]) + +cdataElements = frozenset(['title', 'textarea']) + +rcdataElements = frozenset([ + 'style', + 'script', + 'xmp', + 'iframe', + 'noembed', + 'noframes', + 'noscript' +]) + +booleanAttributes = { + "": frozenset(["irrelevant", "itemscope"]), + "style": frozenset(["scoped"]), + "img": frozenset(["ismap"]), + "audio": frozenset(["autoplay", "controls"]), + "video": frozenset(["autoplay", "controls"]), + "script": frozenset(["defer", "async"]), + "details": frozenset(["open"]), + "datagrid": frozenset(["multiple", "disabled"]), + "command": frozenset(["hidden", "disabled", "checked", "default"]), + "hr": frozenset(["noshade"]), + "menu": frozenset(["autosubmit"]), + "fieldset": frozenset(["disabled", "readonly"]), + "option": frozenset(["disabled", "readonly", "selected"]), + "optgroup": frozenset(["disabled", "readonly"]), + "button": frozenset(["disabled", "autofocus"]), + "input": frozenset(["disabled", "readonly", "required", "autofocus", "checked", "ismap"]), + "select": frozenset(["disabled", "readonly", "autofocus", "multiple"]), + "output": frozenset(["disabled", "readonly"]), + "iframe": frozenset(["seamless"]), +} + +# entitiesWindows1252 has to be _ordered_ and needs to have an index. It +# therefore can't be a frozenset. +entitiesWindows1252 = ( + 8364, # 0x80 0x20AC EURO SIGN + 65533, # 0x81 UNDEFINED + 8218, # 0x82 0x201A SINGLE LOW-9 QUOTATION MARK + 402, # 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK + 8222, # 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK + 8230, # 0x85 0x2026 HORIZONTAL ELLIPSIS + 8224, # 0x86 0x2020 DAGGER + 8225, # 0x87 0x2021 DOUBLE DAGGER + 710, # 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT + 8240, # 0x89 0x2030 PER MILLE SIGN + 352, # 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON + 8249, # 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 338, # 0x8C 0x0152 LATIN CAPITAL LIGATURE OE + 65533, # 0x8D UNDEFINED + 381, # 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON + 65533, # 0x8F UNDEFINED + 65533, # 0x90 UNDEFINED + 8216, # 0x91 0x2018 LEFT SINGLE QUOTATION MARK + 8217, # 0x92 0x2019 RIGHT SINGLE QUOTATION MARK + 8220, # 0x93 0x201C LEFT DOUBLE QUOTATION MARK + 8221, # 0x94 0x201D RIGHT DOUBLE QUOTATION MARK + 8226, # 0x95 0x2022 BULLET + 8211, # 0x96 0x2013 EN DASH + 8212, # 0x97 0x2014 EM DASH + 732, # 0x98 0x02DC SMALL TILDE + 8482, # 0x99 0x2122 TRADE MARK SIGN + 353, # 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON + 8250, # 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 339, # 0x9C 0x0153 LATIN SMALL LIGATURE OE + 65533, # 0x9D UNDEFINED + 382, # 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON + 376 # 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS +) + +xmlEntities = frozenset(['lt;', 'gt;', 'amp;', 'apos;', 'quot;']) + +entities = { + "AElig": "\xc6", + "AElig;": "\xc6", + "AMP": "&", + "AMP;": "&", + "Aacute": "\xc1", + "Aacute;": "\xc1", + "Abreve;": "\u0102", + "Acirc": "\xc2", + "Acirc;": "\xc2", + "Acy;": "\u0410", + "Afr;": "\U0001d504", + "Agrave": "\xc0", + "Agrave;": "\xc0", + "Alpha;": "\u0391", + "Amacr;": "\u0100", + "And;": "\u2a53", + "Aogon;": "\u0104", + "Aopf;": "\U0001d538", + "ApplyFunction;": "\u2061", + "Aring": "\xc5", + "Aring;": "\xc5", + "Ascr;": "\U0001d49c", + "Assign;": "\u2254", + "Atilde": "\xc3", + "Atilde;": "\xc3", + "Auml": "\xc4", + "Auml;": "\xc4", + "Backslash;": "\u2216", + "Barv;": "\u2ae7", + "Barwed;": "\u2306", + "Bcy;": "\u0411", + "Because;": "\u2235", + "Bernoullis;": "\u212c", + "Beta;": "\u0392", + "Bfr;": "\U0001d505", + "Bopf;": "\U0001d539", + "Breve;": "\u02d8", + "Bscr;": "\u212c", + "Bumpeq;": "\u224e", + "CHcy;": "\u0427", + "COPY": "\xa9", + "COPY;": "\xa9", + "Cacute;": "\u0106", + "Cap;": "\u22d2", + "CapitalDifferentialD;": "\u2145", + "Cayleys;": "\u212d", + "Ccaron;": "\u010c", + "Ccedil": "\xc7", + "Ccedil;": "\xc7", + "Ccirc;": "\u0108", + "Cconint;": "\u2230", + "Cdot;": "\u010a", + "Cedilla;": "\xb8", + "CenterDot;": "\xb7", + "Cfr;": "\u212d", + "Chi;": "\u03a7", + "CircleDot;": "\u2299", + "CircleMinus;": "\u2296", + "CirclePlus;": "\u2295", + "CircleTimes;": "\u2297", + "ClockwiseContourIntegral;": "\u2232", + "CloseCurlyDoubleQuote;": "\u201d", + "CloseCurlyQuote;": "\u2019", + "Colon;": "\u2237", + "Colone;": "\u2a74", + "Congruent;": "\u2261", + "Conint;": "\u222f", + "ContourIntegral;": "\u222e", + "Copf;": "\u2102", + "Coproduct;": "\u2210", + "CounterClockwiseContourIntegral;": "\u2233", + "Cross;": "\u2a2f", + "Cscr;": "\U0001d49e", + "Cup;": "\u22d3", + "CupCap;": "\u224d", + "DD;": "\u2145", + "DDotrahd;": "\u2911", + "DJcy;": "\u0402", + "DScy;": "\u0405", + "DZcy;": "\u040f", + "Dagger;": "\u2021", + "Darr;": "\u21a1", + "Dashv;": "\u2ae4", + "Dcaron;": "\u010e", + "Dcy;": "\u0414", + "Del;": "\u2207", + "Delta;": "\u0394", + "Dfr;": "\U0001d507", + "DiacriticalAcute;": "\xb4", + "DiacriticalDot;": "\u02d9", + "DiacriticalDoubleAcute;": "\u02dd", + "DiacriticalGrave;": "`", + "DiacriticalTilde;": "\u02dc", + "Diamond;": "\u22c4", + "DifferentialD;": "\u2146", + "Dopf;": "\U0001d53b", + "Dot;": "\xa8", + "DotDot;": "\u20dc", + "DotEqual;": "\u2250", + "DoubleContourIntegral;": "\u222f", + "DoubleDot;": "\xa8", + "DoubleDownArrow;": "\u21d3", + "DoubleLeftArrow;": "\u21d0", + "DoubleLeftRightArrow;": "\u21d4", + "DoubleLeftTee;": "\u2ae4", + "DoubleLongLeftArrow;": "\u27f8", + "DoubleLongLeftRightArrow;": "\u27fa", + "DoubleLongRightArrow;": "\u27f9", + "DoubleRightArrow;": "\u21d2", + "DoubleRightTee;": "\u22a8", + "DoubleUpArrow;": "\u21d1", + "DoubleUpDownArrow;": "\u21d5", + "DoubleVerticalBar;": "\u2225", + "DownArrow;": "\u2193", + "DownArrowBar;": "\u2913", + "DownArrowUpArrow;": "\u21f5", + "DownBreve;": "\u0311", + "DownLeftRightVector;": "\u2950", + "DownLeftTeeVector;": "\u295e", + "DownLeftVector;": "\u21bd", + "DownLeftVectorBar;": "\u2956", + "DownRightTeeVector;": "\u295f", + "DownRightVector;": "\u21c1", + "DownRightVectorBar;": "\u2957", + "DownTee;": "\u22a4", + "DownTeeArrow;": "\u21a7", + "Downarrow;": "\u21d3", + "Dscr;": "\U0001d49f", + "Dstrok;": "\u0110", + "ENG;": "\u014a", + "ETH": "\xd0", + "ETH;": "\xd0", + "Eacute": "\xc9", + "Eacute;": "\xc9", + "Ecaron;": "\u011a", + "Ecirc": "\xca", + "Ecirc;": "\xca", + "Ecy;": "\u042d", + "Edot;": "\u0116", + "Efr;": "\U0001d508", + "Egrave": "\xc8", + "Egrave;": "\xc8", + "Element;": "\u2208", + "Emacr;": "\u0112", + "EmptySmallSquare;": "\u25fb", + "EmptyVerySmallSquare;": "\u25ab", + "Eogon;": "\u0118", + "Eopf;": "\U0001d53c", + "Epsilon;": "\u0395", + "Equal;": "\u2a75", + "EqualTilde;": "\u2242", + "Equilibrium;": "\u21cc", + "Escr;": "\u2130", + "Esim;": "\u2a73", + "Eta;": "\u0397", + "Euml": "\xcb", + "Euml;": "\xcb", + "Exists;": "\u2203", + "ExponentialE;": "\u2147", + "Fcy;": "\u0424", + "Ffr;": "\U0001d509", + "FilledSmallSquare;": "\u25fc", + "FilledVerySmallSquare;": "\u25aa", + "Fopf;": "\U0001d53d", + "ForAll;": "\u2200", + "Fouriertrf;": "\u2131", + "Fscr;": "\u2131", + "GJcy;": "\u0403", + "GT": ">", + "GT;": ">", + "Gamma;": "\u0393", + "Gammad;": "\u03dc", + "Gbreve;": "\u011e", + "Gcedil;": "\u0122", + "Gcirc;": "\u011c", + "Gcy;": "\u0413", + "Gdot;": "\u0120", + "Gfr;": "\U0001d50a", + "Gg;": "\u22d9", + "Gopf;": "\U0001d53e", + "GreaterEqual;": "\u2265", + "GreaterEqualLess;": "\u22db", + "GreaterFullEqual;": "\u2267", + "GreaterGreater;": "\u2aa2", + "GreaterLess;": "\u2277", + "GreaterSlantEqual;": "\u2a7e", + "GreaterTilde;": "\u2273", + "Gscr;": "\U0001d4a2", + "Gt;": "\u226b", + "HARDcy;": "\u042a", + "Hacek;": "\u02c7", + "Hat;": "^", + "Hcirc;": "\u0124", + "Hfr;": "\u210c", + "HilbertSpace;": "\u210b", + "Hopf;": "\u210d", + "HorizontalLine;": "\u2500", + "Hscr;": "\u210b", + "Hstrok;": "\u0126", + "HumpDownHump;": "\u224e", + "HumpEqual;": "\u224f", + "IEcy;": "\u0415", + "IJlig;": "\u0132", + "IOcy;": "\u0401", + "Iacute": "\xcd", + "Iacute;": "\xcd", + "Icirc": "\xce", + "Icirc;": "\xce", + "Icy;": "\u0418", + "Idot;": "\u0130", + "Ifr;": "\u2111", + "Igrave": "\xcc", + "Igrave;": "\xcc", + "Im;": "\u2111", + "Imacr;": "\u012a", + "ImaginaryI;": "\u2148", + "Implies;": "\u21d2", + "Int;": "\u222c", + "Integral;": "\u222b", + "Intersection;": "\u22c2", + "InvisibleComma;": "\u2063", + "InvisibleTimes;": "\u2062", + "Iogon;": "\u012e", + "Iopf;": "\U0001d540", + "Iota;": "\u0399", + "Iscr;": "\u2110", + "Itilde;": "\u0128", + "Iukcy;": "\u0406", + "Iuml": "\xcf", + "Iuml;": "\xcf", + "Jcirc;": "\u0134", + "Jcy;": "\u0419", + "Jfr;": "\U0001d50d", + "Jopf;": "\U0001d541", + "Jscr;": "\U0001d4a5", + "Jsercy;": "\u0408", + "Jukcy;": "\u0404", + "KHcy;": "\u0425", + "KJcy;": "\u040c", + "Kappa;": "\u039a", + "Kcedil;": "\u0136", + "Kcy;": "\u041a", + "Kfr;": "\U0001d50e", + "Kopf;": "\U0001d542", + "Kscr;": "\U0001d4a6", + "LJcy;": "\u0409", + "LT": "<", + "LT;": "<", + "Lacute;": "\u0139", + "Lambda;": "\u039b", + "Lang;": "\u27ea", + "Laplacetrf;": "\u2112", + "Larr;": "\u219e", + "Lcaron;": "\u013d", + "Lcedil;": "\u013b", + "Lcy;": "\u041b", + "LeftAngleBracket;": "\u27e8", + "LeftArrow;": "\u2190", + "LeftArrowBar;": "\u21e4", + "LeftArrowRightArrow;": "\u21c6", + "LeftCeiling;": "\u2308", + "LeftDoubleBracket;": "\u27e6", + "LeftDownTeeVector;": "\u2961", + "LeftDownVector;": "\u21c3", + "LeftDownVectorBar;": "\u2959", + "LeftFloor;": "\u230a", + "LeftRightArrow;": "\u2194", + "LeftRightVector;": "\u294e", + "LeftTee;": "\u22a3", + "LeftTeeArrow;": "\u21a4", + "LeftTeeVector;": "\u295a", + "LeftTriangle;": "\u22b2", + "LeftTriangleBar;": "\u29cf", + "LeftTriangleEqual;": "\u22b4", + "LeftUpDownVector;": "\u2951", + "LeftUpTeeVector;": "\u2960", + "LeftUpVector;": "\u21bf", + "LeftUpVectorBar;": "\u2958", + "LeftVector;": "\u21bc", + "LeftVectorBar;": "\u2952", + "Leftarrow;": "\u21d0", + "Leftrightarrow;": "\u21d4", + "LessEqualGreater;": "\u22da", + "LessFullEqual;": "\u2266", + "LessGreater;": "\u2276", + "LessLess;": "\u2aa1", + "LessSlantEqual;": "\u2a7d", + "LessTilde;": "\u2272", + "Lfr;": "\U0001d50f", + "Ll;": "\u22d8", + "Lleftarrow;": "\u21da", + "Lmidot;": "\u013f", + "LongLeftArrow;": "\u27f5", + "LongLeftRightArrow;": "\u27f7", + "LongRightArrow;": "\u27f6", + "Longleftarrow;": "\u27f8", + "Longleftrightarrow;": "\u27fa", + "Longrightarrow;": "\u27f9", + "Lopf;": "\U0001d543", + "LowerLeftArrow;": "\u2199", + "LowerRightArrow;": "\u2198", + "Lscr;": "\u2112", + "Lsh;": "\u21b0", + "Lstrok;": "\u0141", + "Lt;": "\u226a", + "Map;": "\u2905", + "Mcy;": "\u041c", + "MediumSpace;": "\u205f", + "Mellintrf;": "\u2133", + "Mfr;": "\U0001d510", + "MinusPlus;": "\u2213", + "Mopf;": "\U0001d544", + "Mscr;": "\u2133", + "Mu;": "\u039c", + "NJcy;": "\u040a", + "Nacute;": "\u0143", + "Ncaron;": "\u0147", + "Ncedil;": "\u0145", + "Ncy;": "\u041d", + "NegativeMediumSpace;": "\u200b", + "NegativeThickSpace;": "\u200b", + "NegativeThinSpace;": "\u200b", + "NegativeVeryThinSpace;": "\u200b", + "NestedGreaterGreater;": "\u226b", + "NestedLessLess;": "\u226a", + "NewLine;": "\n", + "Nfr;": "\U0001d511", + "NoBreak;": "\u2060", + "NonBreakingSpace;": "\xa0", + "Nopf;": "\u2115", + "Not;": "\u2aec", + "NotCongruent;": "\u2262", + "NotCupCap;": "\u226d", + "NotDoubleVerticalBar;": "\u2226", + "NotElement;": "\u2209", + "NotEqual;": "\u2260", + "NotEqualTilde;": "\u2242\u0338", + "NotExists;": "\u2204", + "NotGreater;": "\u226f", + "NotGreaterEqual;": "\u2271", + "NotGreaterFullEqual;": "\u2267\u0338", + "NotGreaterGreater;": "\u226b\u0338", + "NotGreaterLess;": "\u2279", + "NotGreaterSlantEqual;": "\u2a7e\u0338", + "NotGreaterTilde;": "\u2275", + "NotHumpDownHump;": "\u224e\u0338", + "NotHumpEqual;": "\u224f\u0338", + "NotLeftTriangle;": "\u22ea", + "NotLeftTriangleBar;": "\u29cf\u0338", + "NotLeftTriangleEqual;": "\u22ec", + "NotLess;": "\u226e", + "NotLessEqual;": "\u2270", + "NotLessGreater;": "\u2278", + "NotLessLess;": "\u226a\u0338", + "NotLessSlantEqual;": "\u2a7d\u0338", + "NotLessTilde;": "\u2274", + "NotNestedGreaterGreater;": "\u2aa2\u0338", + "NotNestedLessLess;": "\u2aa1\u0338", + "NotPrecedes;": "\u2280", + "NotPrecedesEqual;": "\u2aaf\u0338", + "NotPrecedesSlantEqual;": "\u22e0", + "NotReverseElement;": "\u220c", + "NotRightTriangle;": "\u22eb", + "NotRightTriangleBar;": "\u29d0\u0338", + "NotRightTriangleEqual;": "\u22ed", + "NotSquareSubset;": "\u228f\u0338", + "NotSquareSubsetEqual;": "\u22e2", + "NotSquareSuperset;": "\u2290\u0338", + "NotSquareSupersetEqual;": "\u22e3", + "NotSubset;": "\u2282\u20d2", + "NotSubsetEqual;": "\u2288", + "NotSucceeds;": "\u2281", + "NotSucceedsEqual;": "\u2ab0\u0338", + "NotSucceedsSlantEqual;": "\u22e1", + "NotSucceedsTilde;": "\u227f\u0338", + "NotSuperset;": "\u2283\u20d2", + "NotSupersetEqual;": "\u2289", + "NotTilde;": "\u2241", + "NotTildeEqual;": "\u2244", + "NotTildeFullEqual;": "\u2247", + "NotTildeTilde;": "\u2249", + "NotVerticalBar;": "\u2224", + "Nscr;": "\U0001d4a9", + "Ntilde": "\xd1", + "Ntilde;": "\xd1", + "Nu;": "\u039d", + "OElig;": "\u0152", + "Oacute": "\xd3", + "Oacute;": "\xd3", + "Ocirc": "\xd4", + "Ocirc;": "\xd4", + "Ocy;": "\u041e", + "Odblac;": "\u0150", + "Ofr;": "\U0001d512", + "Ograve": "\xd2", + "Ograve;": "\xd2", + "Omacr;": "\u014c", + "Omega;": "\u03a9", + "Omicron;": "\u039f", + "Oopf;": "\U0001d546", + "OpenCurlyDoubleQuote;": "\u201c", + "OpenCurlyQuote;": "\u2018", + "Or;": "\u2a54", + "Oscr;": "\U0001d4aa", + "Oslash": "\xd8", + "Oslash;": "\xd8", + "Otilde": "\xd5", + "Otilde;": "\xd5", + "Otimes;": "\u2a37", + "Ouml": "\xd6", + "Ouml;": "\xd6", + "OverBar;": "\u203e", + "OverBrace;": "\u23de", + "OverBracket;": "\u23b4", + "OverParenthesis;": "\u23dc", + "PartialD;": "\u2202", + "Pcy;": "\u041f", + "Pfr;": "\U0001d513", + "Phi;": "\u03a6", + "Pi;": "\u03a0", + "PlusMinus;": "\xb1", + "Poincareplane;": "\u210c", + "Popf;": "\u2119", + "Pr;": "\u2abb", + "Precedes;": "\u227a", + "PrecedesEqual;": "\u2aaf", + "PrecedesSlantEqual;": "\u227c", + "PrecedesTilde;": "\u227e", + "Prime;": "\u2033", + "Product;": "\u220f", + "Proportion;": "\u2237", + "Proportional;": "\u221d", + "Pscr;": "\U0001d4ab", + "Psi;": "\u03a8", + "QUOT": "\"", + "QUOT;": "\"", + "Qfr;": "\U0001d514", + "Qopf;": "\u211a", + "Qscr;": "\U0001d4ac", + "RBarr;": "\u2910", + "REG": "\xae", + "REG;": "\xae", + "Racute;": "\u0154", + "Rang;": "\u27eb", + "Rarr;": "\u21a0", + "Rarrtl;": "\u2916", + "Rcaron;": "\u0158", + "Rcedil;": "\u0156", + "Rcy;": "\u0420", + "Re;": "\u211c", + "ReverseElement;": "\u220b", + "ReverseEquilibrium;": "\u21cb", + "ReverseUpEquilibrium;": "\u296f", + "Rfr;": "\u211c", + "Rho;": "\u03a1", + "RightAngleBracket;": "\u27e9", + "RightArrow;": "\u2192", + "RightArrowBar;": "\u21e5", + "RightArrowLeftArrow;": "\u21c4", + "RightCeiling;": "\u2309", + "RightDoubleBracket;": "\u27e7", + "RightDownTeeVector;": "\u295d", + "RightDownVector;": "\u21c2", + "RightDownVectorBar;": "\u2955", + "RightFloor;": "\u230b", + "RightTee;": "\u22a2", + "RightTeeArrow;": "\u21a6", + "RightTeeVector;": "\u295b", + "RightTriangle;": "\u22b3", + "RightTriangleBar;": "\u29d0", + "RightTriangleEqual;": "\u22b5", + "RightUpDownVector;": "\u294f", + "RightUpTeeVector;": "\u295c", + "RightUpVector;": "\u21be", + "RightUpVectorBar;": "\u2954", + "RightVector;": "\u21c0", + "RightVectorBar;": "\u2953", + "Rightarrow;": "\u21d2", + "Ropf;": "\u211d", + "RoundImplies;": "\u2970", + "Rrightarrow;": "\u21db", + "Rscr;": "\u211b", + "Rsh;": "\u21b1", + "RuleDelayed;": "\u29f4", + "SHCHcy;": "\u0429", + "SHcy;": "\u0428", + "SOFTcy;": "\u042c", + "Sacute;": "\u015a", + "Sc;": "\u2abc", + "Scaron;": "\u0160", + "Scedil;": "\u015e", + "Scirc;": "\u015c", + "Scy;": "\u0421", + "Sfr;": "\U0001d516", + "ShortDownArrow;": "\u2193", + "ShortLeftArrow;": "\u2190", + "ShortRightArrow;": "\u2192", + "ShortUpArrow;": "\u2191", + "Sigma;": "\u03a3", + "SmallCircle;": "\u2218", + "Sopf;": "\U0001d54a", + "Sqrt;": "\u221a", + "Square;": "\u25a1", + "SquareIntersection;": "\u2293", + "SquareSubset;": "\u228f", + "SquareSubsetEqual;": "\u2291", + "SquareSuperset;": "\u2290", + "SquareSupersetEqual;": "\u2292", + "SquareUnion;": "\u2294", + "Sscr;": "\U0001d4ae", + "Star;": "\u22c6", + "Sub;": "\u22d0", + "Subset;": "\u22d0", + "SubsetEqual;": "\u2286", + "Succeeds;": "\u227b", + "SucceedsEqual;": "\u2ab0", + "SucceedsSlantEqual;": "\u227d", + "SucceedsTilde;": "\u227f", + "SuchThat;": "\u220b", + "Sum;": "\u2211", + "Sup;": "\u22d1", + "Superset;": "\u2283", + "SupersetEqual;": "\u2287", + "Supset;": "\u22d1", + "THORN": "\xde", + "THORN;": "\xde", + "TRADE;": "\u2122", + "TSHcy;": "\u040b", + "TScy;": "\u0426", + "Tab;": "\t", + "Tau;": "\u03a4", + "Tcaron;": "\u0164", + "Tcedil;": "\u0162", + "Tcy;": "\u0422", + "Tfr;": "\U0001d517", + "Therefore;": "\u2234", + "Theta;": "\u0398", + "ThickSpace;": "\u205f\u200a", + "ThinSpace;": "\u2009", + "Tilde;": "\u223c", + "TildeEqual;": "\u2243", + "TildeFullEqual;": "\u2245", + "TildeTilde;": "\u2248", + "Topf;": "\U0001d54b", + "TripleDot;": "\u20db", + "Tscr;": "\U0001d4af", + "Tstrok;": "\u0166", + "Uacute": "\xda", + "Uacute;": "\xda", + "Uarr;": "\u219f", + "Uarrocir;": "\u2949", + "Ubrcy;": "\u040e", + "Ubreve;": "\u016c", + "Ucirc": "\xdb", + "Ucirc;": "\xdb", + "Ucy;": "\u0423", + "Udblac;": "\u0170", + "Ufr;": "\U0001d518", + "Ugrave": "\xd9", + "Ugrave;": "\xd9", + "Umacr;": "\u016a", + "UnderBar;": "_", + "UnderBrace;": "\u23df", + "UnderBracket;": "\u23b5", + "UnderParenthesis;": "\u23dd", + "Union;": "\u22c3", + "UnionPlus;": "\u228e", + "Uogon;": "\u0172", + "Uopf;": "\U0001d54c", + "UpArrow;": "\u2191", + "UpArrowBar;": "\u2912", + "UpArrowDownArrow;": "\u21c5", + "UpDownArrow;": "\u2195", + "UpEquilibrium;": "\u296e", + "UpTee;": "\u22a5", + "UpTeeArrow;": "\u21a5", + "Uparrow;": "\u21d1", + "Updownarrow;": "\u21d5", + "UpperLeftArrow;": "\u2196", + "UpperRightArrow;": "\u2197", + "Upsi;": "\u03d2", + "Upsilon;": "\u03a5", + "Uring;": "\u016e", + "Uscr;": "\U0001d4b0", + "Utilde;": "\u0168", + "Uuml": "\xdc", + "Uuml;": "\xdc", + "VDash;": "\u22ab", + "Vbar;": "\u2aeb", + "Vcy;": "\u0412", + "Vdash;": "\u22a9", + "Vdashl;": "\u2ae6", + "Vee;": "\u22c1", + "Verbar;": "\u2016", + "Vert;": "\u2016", + "VerticalBar;": "\u2223", + "VerticalLine;": "|", + "VerticalSeparator;": "\u2758", + "VerticalTilde;": "\u2240", + "VeryThinSpace;": "\u200a", + "Vfr;": "\U0001d519", + "Vopf;": "\U0001d54d", + "Vscr;": "\U0001d4b1", + "Vvdash;": "\u22aa", + "Wcirc;": "\u0174", + "Wedge;": "\u22c0", + "Wfr;": "\U0001d51a", + "Wopf;": "\U0001d54e", + "Wscr;": "\U0001d4b2", + "Xfr;": "\U0001d51b", + "Xi;": "\u039e", + "Xopf;": "\U0001d54f", + "Xscr;": "\U0001d4b3", + "YAcy;": "\u042f", + "YIcy;": "\u0407", + "YUcy;": "\u042e", + "Yacute": "\xdd", + "Yacute;": "\xdd", + "Ycirc;": "\u0176", + "Ycy;": "\u042b", + "Yfr;": "\U0001d51c", + "Yopf;": "\U0001d550", + "Yscr;": "\U0001d4b4", + "Yuml;": "\u0178", + "ZHcy;": "\u0416", + "Zacute;": "\u0179", + "Zcaron;": "\u017d", + "Zcy;": "\u0417", + "Zdot;": "\u017b", + "ZeroWidthSpace;": "\u200b", + "Zeta;": "\u0396", + "Zfr;": "\u2128", + "Zopf;": "\u2124", + "Zscr;": "\U0001d4b5", + "aacute": "\xe1", + "aacute;": "\xe1", + "abreve;": "\u0103", + "ac;": "\u223e", + "acE;": "\u223e\u0333", + "acd;": "\u223f", + "acirc": "\xe2", + "acirc;": "\xe2", + "acute": "\xb4", + "acute;": "\xb4", + "acy;": "\u0430", + "aelig": "\xe6", + "aelig;": "\xe6", + "af;": "\u2061", + "afr;": "\U0001d51e", + "agrave": "\xe0", + "agrave;": "\xe0", + "alefsym;": "\u2135", + "aleph;": "\u2135", + "alpha;": "\u03b1", + "amacr;": "\u0101", + "amalg;": "\u2a3f", + "amp": "&", + "amp;": "&", + "and;": "\u2227", + "andand;": "\u2a55", + "andd;": "\u2a5c", + "andslope;": "\u2a58", + "andv;": "\u2a5a", + "ang;": "\u2220", + "ange;": "\u29a4", + "angle;": "\u2220", + "angmsd;": "\u2221", + "angmsdaa;": "\u29a8", + "angmsdab;": "\u29a9", + "angmsdac;": "\u29aa", + "angmsdad;": "\u29ab", + "angmsdae;": "\u29ac", + "angmsdaf;": "\u29ad", + "angmsdag;": "\u29ae", + "angmsdah;": "\u29af", + "angrt;": "\u221f", + "angrtvb;": "\u22be", + "angrtvbd;": "\u299d", + "angsph;": "\u2222", + "angst;": "\xc5", + "angzarr;": "\u237c", + "aogon;": "\u0105", + "aopf;": "\U0001d552", + "ap;": "\u2248", + "apE;": "\u2a70", + "apacir;": "\u2a6f", + "ape;": "\u224a", + "apid;": "\u224b", + "apos;": "'", + "approx;": "\u2248", + "approxeq;": "\u224a", + "aring": "\xe5", + "aring;": "\xe5", + "ascr;": "\U0001d4b6", + "ast;": "*", + "asymp;": "\u2248", + "asympeq;": "\u224d", + "atilde": "\xe3", + "atilde;": "\xe3", + "auml": "\xe4", + "auml;": "\xe4", + "awconint;": "\u2233", + "awint;": "\u2a11", + "bNot;": "\u2aed", + "backcong;": "\u224c", + "backepsilon;": "\u03f6", + "backprime;": "\u2035", + "backsim;": "\u223d", + "backsimeq;": "\u22cd", + "barvee;": "\u22bd", + "barwed;": "\u2305", + "barwedge;": "\u2305", + "bbrk;": "\u23b5", + "bbrktbrk;": "\u23b6", + "bcong;": "\u224c", + "bcy;": "\u0431", + "bdquo;": "\u201e", + "becaus;": "\u2235", + "because;": "\u2235", + "bemptyv;": "\u29b0", + "bepsi;": "\u03f6", + "bernou;": "\u212c", + "beta;": "\u03b2", + "beth;": "\u2136", + "between;": "\u226c", + "bfr;": "\U0001d51f", + "bigcap;": "\u22c2", + "bigcirc;": "\u25ef", + "bigcup;": "\u22c3", + "bigodot;": "\u2a00", + "bigoplus;": "\u2a01", + "bigotimes;": "\u2a02", + "bigsqcup;": "\u2a06", + "bigstar;": "\u2605", + "bigtriangledown;": "\u25bd", + "bigtriangleup;": "\u25b3", + "biguplus;": "\u2a04", + "bigvee;": "\u22c1", + "bigwedge;": "\u22c0", + "bkarow;": "\u290d", + "blacklozenge;": "\u29eb", + "blacksquare;": "\u25aa", + "blacktriangle;": "\u25b4", + "blacktriangledown;": "\u25be", + "blacktriangleleft;": "\u25c2", + "blacktriangleright;": "\u25b8", + "blank;": "\u2423", + "blk12;": "\u2592", + "blk14;": "\u2591", + "blk34;": "\u2593", + "block;": "\u2588", + "bne;": "=\u20e5", + "bnequiv;": "\u2261\u20e5", + "bnot;": "\u2310", + "bopf;": "\U0001d553", + "bot;": "\u22a5", + "bottom;": "\u22a5", + "bowtie;": "\u22c8", + "boxDL;": "\u2557", + "boxDR;": "\u2554", + "boxDl;": "\u2556", + "boxDr;": "\u2553", + "boxH;": "\u2550", + "boxHD;": "\u2566", + "boxHU;": "\u2569", + "boxHd;": "\u2564", + "boxHu;": "\u2567", + "boxUL;": "\u255d", + "boxUR;": "\u255a", + "boxUl;": "\u255c", + "boxUr;": "\u2559", + "boxV;": "\u2551", + "boxVH;": "\u256c", + "boxVL;": "\u2563", + "boxVR;": "\u2560", + "boxVh;": "\u256b", + "boxVl;": "\u2562", + "boxVr;": "\u255f", + "boxbox;": "\u29c9", + "boxdL;": "\u2555", + "boxdR;": "\u2552", + "boxdl;": "\u2510", + "boxdr;": "\u250c", + "boxh;": "\u2500", + "boxhD;": "\u2565", + "boxhU;": "\u2568", + "boxhd;": "\u252c", + "boxhu;": "\u2534", + "boxminus;": "\u229f", + "boxplus;": "\u229e", + "boxtimes;": "\u22a0", + "boxuL;": "\u255b", + "boxuR;": "\u2558", + "boxul;": "\u2518", + "boxur;": "\u2514", + "boxv;": "\u2502", + "boxvH;": "\u256a", + "boxvL;": "\u2561", + "boxvR;": "\u255e", + "boxvh;": "\u253c", + "boxvl;": "\u2524", + "boxvr;": "\u251c", + "bprime;": "\u2035", + "breve;": "\u02d8", + "brvbar": "\xa6", + "brvbar;": "\xa6", + "bscr;": "\U0001d4b7", + "bsemi;": "\u204f", + "bsim;": "\u223d", + "bsime;": "\u22cd", + "bsol;": "\\", + "bsolb;": "\u29c5", + "bsolhsub;": "\u27c8", + "bull;": "\u2022", + "bullet;": "\u2022", + "bump;": "\u224e", + "bumpE;": "\u2aae", + "bumpe;": "\u224f", + "bumpeq;": "\u224f", + "cacute;": "\u0107", + "cap;": "\u2229", + "capand;": "\u2a44", + "capbrcup;": "\u2a49", + "capcap;": "\u2a4b", + "capcup;": "\u2a47", + "capdot;": "\u2a40", + "caps;": "\u2229\ufe00", + "caret;": "\u2041", + "caron;": "\u02c7", + "ccaps;": "\u2a4d", + "ccaron;": "\u010d", + "ccedil": "\xe7", + "ccedil;": "\xe7", + "ccirc;": "\u0109", + "ccups;": "\u2a4c", + "ccupssm;": "\u2a50", + "cdot;": "\u010b", + "cedil": "\xb8", + "cedil;": "\xb8", + "cemptyv;": "\u29b2", + "cent": "\xa2", + "cent;": "\xa2", + "centerdot;": "\xb7", + "cfr;": "\U0001d520", + "chcy;": "\u0447", + "check;": "\u2713", + "checkmark;": "\u2713", + "chi;": "\u03c7", + "cir;": "\u25cb", + "cirE;": "\u29c3", + "circ;": "\u02c6", + "circeq;": "\u2257", + "circlearrowleft;": "\u21ba", + "circlearrowright;": "\u21bb", + "circledR;": "\xae", + "circledS;": "\u24c8", + "circledast;": "\u229b", + "circledcirc;": "\u229a", + "circleddash;": "\u229d", + "cire;": "\u2257", + "cirfnint;": "\u2a10", + "cirmid;": "\u2aef", + "cirscir;": "\u29c2", + "clubs;": "\u2663", + "clubsuit;": "\u2663", + "colon;": ":", + "colone;": "\u2254", + "coloneq;": "\u2254", + "comma;": ",", + "commat;": "@", + "comp;": "\u2201", + "compfn;": "\u2218", + "complement;": "\u2201", + "complexes;": "\u2102", + "cong;": "\u2245", + "congdot;": "\u2a6d", + "conint;": "\u222e", + "copf;": "\U0001d554", + "coprod;": "\u2210", + "copy": "\xa9", + "copy;": "\xa9", + "copysr;": "\u2117", + "crarr;": "\u21b5", + "cross;": "\u2717", + "cscr;": "\U0001d4b8", + "csub;": "\u2acf", + "csube;": "\u2ad1", + "csup;": "\u2ad0", + "csupe;": "\u2ad2", + "ctdot;": "\u22ef", + "cudarrl;": "\u2938", + "cudarrr;": "\u2935", + "cuepr;": "\u22de", + "cuesc;": "\u22df", + "cularr;": "\u21b6", + "cularrp;": "\u293d", + "cup;": "\u222a", + "cupbrcap;": "\u2a48", + "cupcap;": "\u2a46", + "cupcup;": "\u2a4a", + "cupdot;": "\u228d", + "cupor;": "\u2a45", + "cups;": "\u222a\ufe00", + "curarr;": "\u21b7", + "curarrm;": "\u293c", + "curlyeqprec;": "\u22de", + "curlyeqsucc;": "\u22df", + "curlyvee;": "\u22ce", + "curlywedge;": "\u22cf", + "curren": "\xa4", + "curren;": "\xa4", + "curvearrowleft;": "\u21b6", + "curvearrowright;": "\u21b7", + "cuvee;": "\u22ce", + "cuwed;": "\u22cf", + "cwconint;": "\u2232", + "cwint;": "\u2231", + "cylcty;": "\u232d", + "dArr;": "\u21d3", + "dHar;": "\u2965", + "dagger;": "\u2020", + "daleth;": "\u2138", + "darr;": "\u2193", + "dash;": "\u2010", + "dashv;": "\u22a3", + "dbkarow;": "\u290f", + "dblac;": "\u02dd", + "dcaron;": "\u010f", + "dcy;": "\u0434", + "dd;": "\u2146", + "ddagger;": "\u2021", + "ddarr;": "\u21ca", + "ddotseq;": "\u2a77", + "deg": "\xb0", + "deg;": "\xb0", + "delta;": "\u03b4", + "demptyv;": "\u29b1", + "dfisht;": "\u297f", + "dfr;": "\U0001d521", + "dharl;": "\u21c3", + "dharr;": "\u21c2", + "diam;": "\u22c4", + "diamond;": "\u22c4", + "diamondsuit;": "\u2666", + "diams;": "\u2666", + "die;": "\xa8", + "digamma;": "\u03dd", + "disin;": "\u22f2", + "div;": "\xf7", + "divide": "\xf7", + "divide;": "\xf7", + "divideontimes;": "\u22c7", + "divonx;": "\u22c7", + "djcy;": "\u0452", + "dlcorn;": "\u231e", + "dlcrop;": "\u230d", + "dollar;": "$", + "dopf;": "\U0001d555", + "dot;": "\u02d9", + "doteq;": "\u2250", + "doteqdot;": "\u2251", + "dotminus;": "\u2238", + "dotplus;": "\u2214", + "dotsquare;": "\u22a1", + "doublebarwedge;": "\u2306", + "downarrow;": "\u2193", + "downdownarrows;": "\u21ca", + "downharpoonleft;": "\u21c3", + "downharpoonright;": "\u21c2", + "drbkarow;": "\u2910", + "drcorn;": "\u231f", + "drcrop;": "\u230c", + "dscr;": "\U0001d4b9", + "dscy;": "\u0455", + "dsol;": "\u29f6", + "dstrok;": "\u0111", + "dtdot;": "\u22f1", + "dtri;": "\u25bf", + "dtrif;": "\u25be", + "duarr;": "\u21f5", + "duhar;": "\u296f", + "dwangle;": "\u29a6", + "dzcy;": "\u045f", + "dzigrarr;": "\u27ff", + "eDDot;": "\u2a77", + "eDot;": "\u2251", + "eacute": "\xe9", + "eacute;": "\xe9", + "easter;": "\u2a6e", + "ecaron;": "\u011b", + "ecir;": "\u2256", + "ecirc": "\xea", + "ecirc;": "\xea", + "ecolon;": "\u2255", + "ecy;": "\u044d", + "edot;": "\u0117", + "ee;": "\u2147", + "efDot;": "\u2252", + "efr;": "\U0001d522", + "eg;": "\u2a9a", + "egrave": "\xe8", + "egrave;": "\xe8", + "egs;": "\u2a96", + "egsdot;": "\u2a98", + "el;": "\u2a99", + "elinters;": "\u23e7", + "ell;": "\u2113", + "els;": "\u2a95", + "elsdot;": "\u2a97", + "emacr;": "\u0113", + "empty;": "\u2205", + "emptyset;": "\u2205", + "emptyv;": "\u2205", + "emsp13;": "\u2004", + "emsp14;": "\u2005", + "emsp;": "\u2003", + "eng;": "\u014b", + "ensp;": "\u2002", + "eogon;": "\u0119", + "eopf;": "\U0001d556", + "epar;": "\u22d5", + "eparsl;": "\u29e3", + "eplus;": "\u2a71", + "epsi;": "\u03b5", + "epsilon;": "\u03b5", + "epsiv;": "\u03f5", + "eqcirc;": "\u2256", + "eqcolon;": "\u2255", + "eqsim;": "\u2242", + "eqslantgtr;": "\u2a96", + "eqslantless;": "\u2a95", + "equals;": "=", + "equest;": "\u225f", + "equiv;": "\u2261", + "equivDD;": "\u2a78", + "eqvparsl;": "\u29e5", + "erDot;": "\u2253", + "erarr;": "\u2971", + "escr;": "\u212f", + "esdot;": "\u2250", + "esim;": "\u2242", + "eta;": "\u03b7", + "eth": "\xf0", + "eth;": "\xf0", + "euml": "\xeb", + "euml;": "\xeb", + "euro;": "\u20ac", + "excl;": "!", + "exist;": "\u2203", + "expectation;": "\u2130", + "exponentiale;": "\u2147", + "fallingdotseq;": "\u2252", + "fcy;": "\u0444", + "female;": "\u2640", + "ffilig;": "\ufb03", + "fflig;": "\ufb00", + "ffllig;": "\ufb04", + "ffr;": "\U0001d523", + "filig;": "\ufb01", + "fjlig;": "fj", + "flat;": "\u266d", + "fllig;": "\ufb02", + "fltns;": "\u25b1", + "fnof;": "\u0192", + "fopf;": "\U0001d557", + "forall;": "\u2200", + "fork;": "\u22d4", + "forkv;": "\u2ad9", + "fpartint;": "\u2a0d", + "frac12": "\xbd", + "frac12;": "\xbd", + "frac13;": "\u2153", + "frac14": "\xbc", + "frac14;": "\xbc", + "frac15;": "\u2155", + "frac16;": "\u2159", + "frac18;": "\u215b", + "frac23;": "\u2154", + "frac25;": "\u2156", + "frac34": "\xbe", + "frac34;": "\xbe", + "frac35;": "\u2157", + "frac38;": "\u215c", + "frac45;": "\u2158", + "frac56;": "\u215a", + "frac58;": "\u215d", + "frac78;": "\u215e", + "frasl;": "\u2044", + "frown;": "\u2322", + "fscr;": "\U0001d4bb", + "gE;": "\u2267", + "gEl;": "\u2a8c", + "gacute;": "\u01f5", + "gamma;": "\u03b3", + "gammad;": "\u03dd", + "gap;": "\u2a86", + "gbreve;": "\u011f", + "gcirc;": "\u011d", + "gcy;": "\u0433", + "gdot;": "\u0121", + "ge;": "\u2265", + "gel;": "\u22db", + "geq;": "\u2265", + "geqq;": "\u2267", + "geqslant;": "\u2a7e", + "ges;": "\u2a7e", + "gescc;": "\u2aa9", + "gesdot;": "\u2a80", + "gesdoto;": "\u2a82", + "gesdotol;": "\u2a84", + "gesl;": "\u22db\ufe00", + "gesles;": "\u2a94", + "gfr;": "\U0001d524", + "gg;": "\u226b", + "ggg;": "\u22d9", + "gimel;": "\u2137", + "gjcy;": "\u0453", + "gl;": "\u2277", + "glE;": "\u2a92", + "gla;": "\u2aa5", + "glj;": "\u2aa4", + "gnE;": "\u2269", + "gnap;": "\u2a8a", + "gnapprox;": "\u2a8a", + "gne;": "\u2a88", + "gneq;": "\u2a88", + "gneqq;": "\u2269", + "gnsim;": "\u22e7", + "gopf;": "\U0001d558", + "grave;": "`", + "gscr;": "\u210a", + "gsim;": "\u2273", + "gsime;": "\u2a8e", + "gsiml;": "\u2a90", + "gt": ">", + "gt;": ">", + "gtcc;": "\u2aa7", + "gtcir;": "\u2a7a", + "gtdot;": "\u22d7", + "gtlPar;": "\u2995", + "gtquest;": "\u2a7c", + "gtrapprox;": "\u2a86", + "gtrarr;": "\u2978", + "gtrdot;": "\u22d7", + "gtreqless;": "\u22db", + "gtreqqless;": "\u2a8c", + "gtrless;": "\u2277", + "gtrsim;": "\u2273", + "gvertneqq;": "\u2269\ufe00", + "gvnE;": "\u2269\ufe00", + "hArr;": "\u21d4", + "hairsp;": "\u200a", + "half;": "\xbd", + "hamilt;": "\u210b", + "hardcy;": "\u044a", + "harr;": "\u2194", + "harrcir;": "\u2948", + "harrw;": "\u21ad", + "hbar;": "\u210f", + "hcirc;": "\u0125", + "hearts;": "\u2665", + "heartsuit;": "\u2665", + "hellip;": "\u2026", + "hercon;": "\u22b9", + "hfr;": "\U0001d525", + "hksearow;": "\u2925", + "hkswarow;": "\u2926", + "hoarr;": "\u21ff", + "homtht;": "\u223b", + "hookleftarrow;": "\u21a9", + "hookrightarrow;": "\u21aa", + "hopf;": "\U0001d559", + "horbar;": "\u2015", + "hscr;": "\U0001d4bd", + "hslash;": "\u210f", + "hstrok;": "\u0127", + "hybull;": "\u2043", + "hyphen;": "\u2010", + "iacute": "\xed", + "iacute;": "\xed", + "ic;": "\u2063", + "icirc": "\xee", + "icirc;": "\xee", + "icy;": "\u0438", + "iecy;": "\u0435", + "iexcl": "\xa1", + "iexcl;": "\xa1", + "iff;": "\u21d4", + "ifr;": "\U0001d526", + "igrave": "\xec", + "igrave;": "\xec", + "ii;": "\u2148", + "iiiint;": "\u2a0c", + "iiint;": "\u222d", + "iinfin;": "\u29dc", + "iiota;": "\u2129", + "ijlig;": "\u0133", + "imacr;": "\u012b", + "image;": "\u2111", + "imagline;": "\u2110", + "imagpart;": "\u2111", + "imath;": "\u0131", + "imof;": "\u22b7", + "imped;": "\u01b5", + "in;": "\u2208", + "incare;": "\u2105", + "infin;": "\u221e", + "infintie;": "\u29dd", + "inodot;": "\u0131", + "int;": "\u222b", + "intcal;": "\u22ba", + "integers;": "\u2124", + "intercal;": "\u22ba", + "intlarhk;": "\u2a17", + "intprod;": "\u2a3c", + "iocy;": "\u0451", + "iogon;": "\u012f", + "iopf;": "\U0001d55a", + "iota;": "\u03b9", + "iprod;": "\u2a3c", + "iquest": "\xbf", + "iquest;": "\xbf", + "iscr;": "\U0001d4be", + "isin;": "\u2208", + "isinE;": "\u22f9", + "isindot;": "\u22f5", + "isins;": "\u22f4", + "isinsv;": "\u22f3", + "isinv;": "\u2208", + "it;": "\u2062", + "itilde;": "\u0129", + "iukcy;": "\u0456", + "iuml": "\xef", + "iuml;": "\xef", + "jcirc;": "\u0135", + "jcy;": "\u0439", + "jfr;": "\U0001d527", + "jmath;": "\u0237", + "jopf;": "\U0001d55b", + "jscr;": "\U0001d4bf", + "jsercy;": "\u0458", + "jukcy;": "\u0454", + "kappa;": "\u03ba", + "kappav;": "\u03f0", + "kcedil;": "\u0137", + "kcy;": "\u043a", + "kfr;": "\U0001d528", + "kgreen;": "\u0138", + "khcy;": "\u0445", + "kjcy;": "\u045c", + "kopf;": "\U0001d55c", + "kscr;": "\U0001d4c0", + "lAarr;": "\u21da", + "lArr;": "\u21d0", + "lAtail;": "\u291b", + "lBarr;": "\u290e", + "lE;": "\u2266", + "lEg;": "\u2a8b", + "lHar;": "\u2962", + "lacute;": "\u013a", + "laemptyv;": "\u29b4", + "lagran;": "\u2112", + "lambda;": "\u03bb", + "lang;": "\u27e8", + "langd;": "\u2991", + "langle;": "\u27e8", + "lap;": "\u2a85", + "laquo": "\xab", + "laquo;": "\xab", + "larr;": "\u2190", + "larrb;": "\u21e4", + "larrbfs;": "\u291f", + "larrfs;": "\u291d", + "larrhk;": "\u21a9", + "larrlp;": "\u21ab", + "larrpl;": "\u2939", + "larrsim;": "\u2973", + "larrtl;": "\u21a2", + "lat;": "\u2aab", + "latail;": "\u2919", + "late;": "\u2aad", + "lates;": "\u2aad\ufe00", + "lbarr;": "\u290c", + "lbbrk;": "\u2772", + "lbrace;": "{", + "lbrack;": "[", + "lbrke;": "\u298b", + "lbrksld;": "\u298f", + "lbrkslu;": "\u298d", + "lcaron;": "\u013e", + "lcedil;": "\u013c", + "lceil;": "\u2308", + "lcub;": "{", + "lcy;": "\u043b", + "ldca;": "\u2936", + "ldquo;": "\u201c", + "ldquor;": "\u201e", + "ldrdhar;": "\u2967", + "ldrushar;": "\u294b", + "ldsh;": "\u21b2", + "le;": "\u2264", + "leftarrow;": "\u2190", + "leftarrowtail;": "\u21a2", + "leftharpoondown;": "\u21bd", + "leftharpoonup;": "\u21bc", + "leftleftarrows;": "\u21c7", + "leftrightarrow;": "\u2194", + "leftrightarrows;": "\u21c6", + "leftrightharpoons;": "\u21cb", + "leftrightsquigarrow;": "\u21ad", + "leftthreetimes;": "\u22cb", + "leg;": "\u22da", + "leq;": "\u2264", + "leqq;": "\u2266", + "leqslant;": "\u2a7d", + "les;": "\u2a7d", + "lescc;": "\u2aa8", + "lesdot;": "\u2a7f", + "lesdoto;": "\u2a81", + "lesdotor;": "\u2a83", + "lesg;": "\u22da\ufe00", + "lesges;": "\u2a93", + "lessapprox;": "\u2a85", + "lessdot;": "\u22d6", + "lesseqgtr;": "\u22da", + "lesseqqgtr;": "\u2a8b", + "lessgtr;": "\u2276", + "lesssim;": "\u2272", + "lfisht;": "\u297c", + "lfloor;": "\u230a", + "lfr;": "\U0001d529", + "lg;": "\u2276", + "lgE;": "\u2a91", + "lhard;": "\u21bd", + "lharu;": "\u21bc", + "lharul;": "\u296a", + "lhblk;": "\u2584", + "ljcy;": "\u0459", + "ll;": "\u226a", + "llarr;": "\u21c7", + "llcorner;": "\u231e", + "llhard;": "\u296b", + "lltri;": "\u25fa", + "lmidot;": "\u0140", + "lmoust;": "\u23b0", + "lmoustache;": "\u23b0", + "lnE;": "\u2268", + "lnap;": "\u2a89", + "lnapprox;": "\u2a89", + "lne;": "\u2a87", + "lneq;": "\u2a87", + "lneqq;": "\u2268", + "lnsim;": "\u22e6", + "loang;": "\u27ec", + "loarr;": "\u21fd", + "lobrk;": "\u27e6", + "longleftarrow;": "\u27f5", + "longleftrightarrow;": "\u27f7", + "longmapsto;": "\u27fc", + "longrightarrow;": "\u27f6", + "looparrowleft;": "\u21ab", + "looparrowright;": "\u21ac", + "lopar;": "\u2985", + "lopf;": "\U0001d55d", + "loplus;": "\u2a2d", + "lotimes;": "\u2a34", + "lowast;": "\u2217", + "lowbar;": "_", + "loz;": "\u25ca", + "lozenge;": "\u25ca", + "lozf;": "\u29eb", + "lpar;": "(", + "lparlt;": "\u2993", + "lrarr;": "\u21c6", + "lrcorner;": "\u231f", + "lrhar;": "\u21cb", + "lrhard;": "\u296d", + "lrm;": "\u200e", + "lrtri;": "\u22bf", + "lsaquo;": "\u2039", + "lscr;": "\U0001d4c1", + "lsh;": "\u21b0", + "lsim;": "\u2272", + "lsime;": "\u2a8d", + "lsimg;": "\u2a8f", + "lsqb;": "[", + "lsquo;": "\u2018", + "lsquor;": "\u201a", + "lstrok;": "\u0142", + "lt": "<", + "lt;": "<", + "ltcc;": "\u2aa6", + "ltcir;": "\u2a79", + "ltdot;": "\u22d6", + "lthree;": "\u22cb", + "ltimes;": "\u22c9", + "ltlarr;": "\u2976", + "ltquest;": "\u2a7b", + "ltrPar;": "\u2996", + "ltri;": "\u25c3", + "ltrie;": "\u22b4", + "ltrif;": "\u25c2", + "lurdshar;": "\u294a", + "luruhar;": "\u2966", + "lvertneqq;": "\u2268\ufe00", + "lvnE;": "\u2268\ufe00", + "mDDot;": "\u223a", + "macr": "\xaf", + "macr;": "\xaf", + "male;": "\u2642", + "malt;": "\u2720", + "maltese;": "\u2720", + "map;": "\u21a6", + "mapsto;": "\u21a6", + "mapstodown;": "\u21a7", + "mapstoleft;": "\u21a4", + "mapstoup;": "\u21a5", + "marker;": "\u25ae", + "mcomma;": "\u2a29", + "mcy;": "\u043c", + "mdash;": "\u2014", + "measuredangle;": "\u2221", + "mfr;": "\U0001d52a", + "mho;": "\u2127", + "micro": "\xb5", + "micro;": "\xb5", + "mid;": "\u2223", + "midast;": "*", + "midcir;": "\u2af0", + "middot": "\xb7", + "middot;": "\xb7", + "minus;": "\u2212", + "minusb;": "\u229f", + "minusd;": "\u2238", + "minusdu;": "\u2a2a", + "mlcp;": "\u2adb", + "mldr;": "\u2026", + "mnplus;": "\u2213", + "models;": "\u22a7", + "mopf;": "\U0001d55e", + "mp;": "\u2213", + "mscr;": "\U0001d4c2", + "mstpos;": "\u223e", + "mu;": "\u03bc", + "multimap;": "\u22b8", + "mumap;": "\u22b8", + "nGg;": "\u22d9\u0338", + "nGt;": "\u226b\u20d2", + "nGtv;": "\u226b\u0338", + "nLeftarrow;": "\u21cd", + "nLeftrightarrow;": "\u21ce", + "nLl;": "\u22d8\u0338", + "nLt;": "\u226a\u20d2", + "nLtv;": "\u226a\u0338", + "nRightarrow;": "\u21cf", + "nVDash;": "\u22af", + "nVdash;": "\u22ae", + "nabla;": "\u2207", + "nacute;": "\u0144", + "nang;": "\u2220\u20d2", + "nap;": "\u2249", + "napE;": "\u2a70\u0338", + "napid;": "\u224b\u0338", + "napos;": "\u0149", + "napprox;": "\u2249", + "natur;": "\u266e", + "natural;": "\u266e", + "naturals;": "\u2115", + "nbsp": "\xa0", + "nbsp;": "\xa0", + "nbump;": "\u224e\u0338", + "nbumpe;": "\u224f\u0338", + "ncap;": "\u2a43", + "ncaron;": "\u0148", + "ncedil;": "\u0146", + "ncong;": "\u2247", + "ncongdot;": "\u2a6d\u0338", + "ncup;": "\u2a42", + "ncy;": "\u043d", + "ndash;": "\u2013", + "ne;": "\u2260", + "neArr;": "\u21d7", + "nearhk;": "\u2924", + "nearr;": "\u2197", + "nearrow;": "\u2197", + "nedot;": "\u2250\u0338", + "nequiv;": "\u2262", + "nesear;": "\u2928", + "nesim;": "\u2242\u0338", + "nexist;": "\u2204", + "nexists;": "\u2204", + "nfr;": "\U0001d52b", + "ngE;": "\u2267\u0338", + "nge;": "\u2271", + "ngeq;": "\u2271", + "ngeqq;": "\u2267\u0338", + "ngeqslant;": "\u2a7e\u0338", + "nges;": "\u2a7e\u0338", + "ngsim;": "\u2275", + "ngt;": "\u226f", + "ngtr;": "\u226f", + "nhArr;": "\u21ce", + "nharr;": "\u21ae", + "nhpar;": "\u2af2", + "ni;": "\u220b", + "nis;": "\u22fc", + "nisd;": "\u22fa", + "niv;": "\u220b", + "njcy;": "\u045a", + "nlArr;": "\u21cd", + "nlE;": "\u2266\u0338", + "nlarr;": "\u219a", + "nldr;": "\u2025", + "nle;": "\u2270", + "nleftarrow;": "\u219a", + "nleftrightarrow;": "\u21ae", + "nleq;": "\u2270", + "nleqq;": "\u2266\u0338", + "nleqslant;": "\u2a7d\u0338", + "nles;": "\u2a7d\u0338", + "nless;": "\u226e", + "nlsim;": "\u2274", + "nlt;": "\u226e", + "nltri;": "\u22ea", + "nltrie;": "\u22ec", + "nmid;": "\u2224", + "nopf;": "\U0001d55f", + "not": "\xac", + "not;": "\xac", + "notin;": "\u2209", + "notinE;": "\u22f9\u0338", + "notindot;": "\u22f5\u0338", + "notinva;": "\u2209", + "notinvb;": "\u22f7", + "notinvc;": "\u22f6", + "notni;": "\u220c", + "notniva;": "\u220c", + "notnivb;": "\u22fe", + "notnivc;": "\u22fd", + "npar;": "\u2226", + "nparallel;": "\u2226", + "nparsl;": "\u2afd\u20e5", + "npart;": "\u2202\u0338", + "npolint;": "\u2a14", + "npr;": "\u2280", + "nprcue;": "\u22e0", + "npre;": "\u2aaf\u0338", + "nprec;": "\u2280", + "npreceq;": "\u2aaf\u0338", + "nrArr;": "\u21cf", + "nrarr;": "\u219b", + "nrarrc;": "\u2933\u0338", + "nrarrw;": "\u219d\u0338", + "nrightarrow;": "\u219b", + "nrtri;": "\u22eb", + "nrtrie;": "\u22ed", + "nsc;": "\u2281", + "nsccue;": "\u22e1", + "nsce;": "\u2ab0\u0338", + "nscr;": "\U0001d4c3", + "nshortmid;": "\u2224", + "nshortparallel;": "\u2226", + "nsim;": "\u2241", + "nsime;": "\u2244", + "nsimeq;": "\u2244", + "nsmid;": "\u2224", + "nspar;": "\u2226", + "nsqsube;": "\u22e2", + "nsqsupe;": "\u22e3", + "nsub;": "\u2284", + "nsubE;": "\u2ac5\u0338", + "nsube;": "\u2288", + "nsubset;": "\u2282\u20d2", + "nsubseteq;": "\u2288", + "nsubseteqq;": "\u2ac5\u0338", + "nsucc;": "\u2281", + "nsucceq;": "\u2ab0\u0338", + "nsup;": "\u2285", + "nsupE;": "\u2ac6\u0338", + "nsupe;": "\u2289", + "nsupset;": "\u2283\u20d2", + "nsupseteq;": "\u2289", + "nsupseteqq;": "\u2ac6\u0338", + "ntgl;": "\u2279", + "ntilde": "\xf1", + "ntilde;": "\xf1", + "ntlg;": "\u2278", + "ntriangleleft;": "\u22ea", + "ntrianglelefteq;": "\u22ec", + "ntriangleright;": "\u22eb", + "ntrianglerighteq;": "\u22ed", + "nu;": "\u03bd", + "num;": "#", + "numero;": "\u2116", + "numsp;": "\u2007", + "nvDash;": "\u22ad", + "nvHarr;": "\u2904", + "nvap;": "\u224d\u20d2", + "nvdash;": "\u22ac", + "nvge;": "\u2265\u20d2", + "nvgt;": ">\u20d2", + "nvinfin;": "\u29de", + "nvlArr;": "\u2902", + "nvle;": "\u2264\u20d2", + "nvlt;": "<\u20d2", + "nvltrie;": "\u22b4\u20d2", + "nvrArr;": "\u2903", + "nvrtrie;": "\u22b5\u20d2", + "nvsim;": "\u223c\u20d2", + "nwArr;": "\u21d6", + "nwarhk;": "\u2923", + "nwarr;": "\u2196", + "nwarrow;": "\u2196", + "nwnear;": "\u2927", + "oS;": "\u24c8", + "oacute": "\xf3", + "oacute;": "\xf3", + "oast;": "\u229b", + "ocir;": "\u229a", + "ocirc": "\xf4", + "ocirc;": "\xf4", + "ocy;": "\u043e", + "odash;": "\u229d", + "odblac;": "\u0151", + "odiv;": "\u2a38", + "odot;": "\u2299", + "odsold;": "\u29bc", + "oelig;": "\u0153", + "ofcir;": "\u29bf", + "ofr;": "\U0001d52c", + "ogon;": "\u02db", + "ograve": "\xf2", + "ograve;": "\xf2", + "ogt;": "\u29c1", + "ohbar;": "\u29b5", + "ohm;": "\u03a9", + "oint;": "\u222e", + "olarr;": "\u21ba", + "olcir;": "\u29be", + "olcross;": "\u29bb", + "oline;": "\u203e", + "olt;": "\u29c0", + "omacr;": "\u014d", + "omega;": "\u03c9", + "omicron;": "\u03bf", + "omid;": "\u29b6", + "ominus;": "\u2296", + "oopf;": "\U0001d560", + "opar;": "\u29b7", + "operp;": "\u29b9", + "oplus;": "\u2295", + "or;": "\u2228", + "orarr;": "\u21bb", + "ord;": "\u2a5d", + "order;": "\u2134", + "orderof;": "\u2134", + "ordf": "\xaa", + "ordf;": "\xaa", + "ordm": "\xba", + "ordm;": "\xba", + "origof;": "\u22b6", + "oror;": "\u2a56", + "orslope;": "\u2a57", + "orv;": "\u2a5b", + "oscr;": "\u2134", + "oslash": "\xf8", + "oslash;": "\xf8", + "osol;": "\u2298", + "otilde": "\xf5", + "otilde;": "\xf5", + "otimes;": "\u2297", + "otimesas;": "\u2a36", + "ouml": "\xf6", + "ouml;": "\xf6", + "ovbar;": "\u233d", + "par;": "\u2225", + "para": "\xb6", + "para;": "\xb6", + "parallel;": "\u2225", + "parsim;": "\u2af3", + "parsl;": "\u2afd", + "part;": "\u2202", + "pcy;": "\u043f", + "percnt;": "%", + "period;": ".", + "permil;": "\u2030", + "perp;": "\u22a5", + "pertenk;": "\u2031", + "pfr;": "\U0001d52d", + "phi;": "\u03c6", + "phiv;": "\u03d5", + "phmmat;": "\u2133", + "phone;": "\u260e", + "pi;": "\u03c0", + "pitchfork;": "\u22d4", + "piv;": "\u03d6", + "planck;": "\u210f", + "planckh;": "\u210e", + "plankv;": "\u210f", + "plus;": "+", + "plusacir;": "\u2a23", + "plusb;": "\u229e", + "pluscir;": "\u2a22", + "plusdo;": "\u2214", + "plusdu;": "\u2a25", + "pluse;": "\u2a72", + "plusmn": "\xb1", + "plusmn;": "\xb1", + "plussim;": "\u2a26", + "plustwo;": "\u2a27", + "pm;": "\xb1", + "pointint;": "\u2a15", + "popf;": "\U0001d561", + "pound": "\xa3", + "pound;": "\xa3", + "pr;": "\u227a", + "prE;": "\u2ab3", + "prap;": "\u2ab7", + "prcue;": "\u227c", + "pre;": "\u2aaf", + "prec;": "\u227a", + "precapprox;": "\u2ab7", + "preccurlyeq;": "\u227c", + "preceq;": "\u2aaf", + "precnapprox;": "\u2ab9", + "precneqq;": "\u2ab5", + "precnsim;": "\u22e8", + "precsim;": "\u227e", + "prime;": "\u2032", + "primes;": "\u2119", + "prnE;": "\u2ab5", + "prnap;": "\u2ab9", + "prnsim;": "\u22e8", + "prod;": "\u220f", + "profalar;": "\u232e", + "profline;": "\u2312", + "profsurf;": "\u2313", + "prop;": "\u221d", + "propto;": "\u221d", + "prsim;": "\u227e", + "prurel;": "\u22b0", + "pscr;": "\U0001d4c5", + "psi;": "\u03c8", + "puncsp;": "\u2008", + "qfr;": "\U0001d52e", + "qint;": "\u2a0c", + "qopf;": "\U0001d562", + "qprime;": "\u2057", + "qscr;": "\U0001d4c6", + "quaternions;": "\u210d", + "quatint;": "\u2a16", + "quest;": "?", + "questeq;": "\u225f", + "quot": "\"", + "quot;": "\"", + "rAarr;": "\u21db", + "rArr;": "\u21d2", + "rAtail;": "\u291c", + "rBarr;": "\u290f", + "rHar;": "\u2964", + "race;": "\u223d\u0331", + "racute;": "\u0155", + "radic;": "\u221a", + "raemptyv;": "\u29b3", + "rang;": "\u27e9", + "rangd;": "\u2992", + "range;": "\u29a5", + "rangle;": "\u27e9", + "raquo": "\xbb", + "raquo;": "\xbb", + "rarr;": "\u2192", + "rarrap;": "\u2975", + "rarrb;": "\u21e5", + "rarrbfs;": "\u2920", + "rarrc;": "\u2933", + "rarrfs;": "\u291e", + "rarrhk;": "\u21aa", + "rarrlp;": "\u21ac", + "rarrpl;": "\u2945", + "rarrsim;": "\u2974", + "rarrtl;": "\u21a3", + "rarrw;": "\u219d", + "ratail;": "\u291a", + "ratio;": "\u2236", + "rationals;": "\u211a", + "rbarr;": "\u290d", + "rbbrk;": "\u2773", + "rbrace;": "}", + "rbrack;": "]", + "rbrke;": "\u298c", + "rbrksld;": "\u298e", + "rbrkslu;": "\u2990", + "rcaron;": "\u0159", + "rcedil;": "\u0157", + "rceil;": "\u2309", + "rcub;": "}", + "rcy;": "\u0440", + "rdca;": "\u2937", + "rdldhar;": "\u2969", + "rdquo;": "\u201d", + "rdquor;": "\u201d", + "rdsh;": "\u21b3", + "real;": "\u211c", + "realine;": "\u211b", + "realpart;": "\u211c", + "reals;": "\u211d", + "rect;": "\u25ad", + "reg": "\xae", + "reg;": "\xae", + "rfisht;": "\u297d", + "rfloor;": "\u230b", + "rfr;": "\U0001d52f", + "rhard;": "\u21c1", + "rharu;": "\u21c0", + "rharul;": "\u296c", + "rho;": "\u03c1", + "rhov;": "\u03f1", + "rightarrow;": "\u2192", + "rightarrowtail;": "\u21a3", + "rightharpoondown;": "\u21c1", + "rightharpoonup;": "\u21c0", + "rightleftarrows;": "\u21c4", + "rightleftharpoons;": "\u21cc", + "rightrightarrows;": "\u21c9", + "rightsquigarrow;": "\u219d", + "rightthreetimes;": "\u22cc", + "ring;": "\u02da", + "risingdotseq;": "\u2253", + "rlarr;": "\u21c4", + "rlhar;": "\u21cc", + "rlm;": "\u200f", + "rmoust;": "\u23b1", + "rmoustache;": "\u23b1", + "rnmid;": "\u2aee", + "roang;": "\u27ed", + "roarr;": "\u21fe", + "robrk;": "\u27e7", + "ropar;": "\u2986", + "ropf;": "\U0001d563", + "roplus;": "\u2a2e", + "rotimes;": "\u2a35", + "rpar;": ")", + "rpargt;": "\u2994", + "rppolint;": "\u2a12", + "rrarr;": "\u21c9", + "rsaquo;": "\u203a", + "rscr;": "\U0001d4c7", + "rsh;": "\u21b1", + "rsqb;": "]", + "rsquo;": "\u2019", + "rsquor;": "\u2019", + "rthree;": "\u22cc", + "rtimes;": "\u22ca", + "rtri;": "\u25b9", + "rtrie;": "\u22b5", + "rtrif;": "\u25b8", + "rtriltri;": "\u29ce", + "ruluhar;": "\u2968", + "rx;": "\u211e", + "sacute;": "\u015b", + "sbquo;": "\u201a", + "sc;": "\u227b", + "scE;": "\u2ab4", + "scap;": "\u2ab8", + "scaron;": "\u0161", + "sccue;": "\u227d", + "sce;": "\u2ab0", + "scedil;": "\u015f", + "scirc;": "\u015d", + "scnE;": "\u2ab6", + "scnap;": "\u2aba", + "scnsim;": "\u22e9", + "scpolint;": "\u2a13", + "scsim;": "\u227f", + "scy;": "\u0441", + "sdot;": "\u22c5", + "sdotb;": "\u22a1", + "sdote;": "\u2a66", + "seArr;": "\u21d8", + "searhk;": "\u2925", + "searr;": "\u2198", + "searrow;": "\u2198", + "sect": "\xa7", + "sect;": "\xa7", + "semi;": ";", + "seswar;": "\u2929", + "setminus;": "\u2216", + "setmn;": "\u2216", + "sext;": "\u2736", + "sfr;": "\U0001d530", + "sfrown;": "\u2322", + "sharp;": "\u266f", + "shchcy;": "\u0449", + "shcy;": "\u0448", + "shortmid;": "\u2223", + "shortparallel;": "\u2225", + "shy": "\xad", + "shy;": "\xad", + "sigma;": "\u03c3", + "sigmaf;": "\u03c2", + "sigmav;": "\u03c2", + "sim;": "\u223c", + "simdot;": "\u2a6a", + "sime;": "\u2243", + "simeq;": "\u2243", + "simg;": "\u2a9e", + "simgE;": "\u2aa0", + "siml;": "\u2a9d", + "simlE;": "\u2a9f", + "simne;": "\u2246", + "simplus;": "\u2a24", + "simrarr;": "\u2972", + "slarr;": "\u2190", + "smallsetminus;": "\u2216", + "smashp;": "\u2a33", + "smeparsl;": "\u29e4", + "smid;": "\u2223", + "smile;": "\u2323", + "smt;": "\u2aaa", + "smte;": "\u2aac", + "smtes;": "\u2aac\ufe00", + "softcy;": "\u044c", + "sol;": "/", + "solb;": "\u29c4", + "solbar;": "\u233f", + "sopf;": "\U0001d564", + "spades;": "\u2660", + "spadesuit;": "\u2660", + "spar;": "\u2225", + "sqcap;": "\u2293", + "sqcaps;": "\u2293\ufe00", + "sqcup;": "\u2294", + "sqcups;": "\u2294\ufe00", + "sqsub;": "\u228f", + "sqsube;": "\u2291", + "sqsubset;": "\u228f", + "sqsubseteq;": "\u2291", + "sqsup;": "\u2290", + "sqsupe;": "\u2292", + "sqsupset;": "\u2290", + "sqsupseteq;": "\u2292", + "squ;": "\u25a1", + "square;": "\u25a1", + "squarf;": "\u25aa", + "squf;": "\u25aa", + "srarr;": "\u2192", + "sscr;": "\U0001d4c8", + "ssetmn;": "\u2216", + "ssmile;": "\u2323", + "sstarf;": "\u22c6", + "star;": "\u2606", + "starf;": "\u2605", + "straightepsilon;": "\u03f5", + "straightphi;": "\u03d5", + "strns;": "\xaf", + "sub;": "\u2282", + "subE;": "\u2ac5", + "subdot;": "\u2abd", + "sube;": "\u2286", + "subedot;": "\u2ac3", + "submult;": "\u2ac1", + "subnE;": "\u2acb", + "subne;": "\u228a", + "subplus;": "\u2abf", + "subrarr;": "\u2979", + "subset;": "\u2282", + "subseteq;": "\u2286", + "subseteqq;": "\u2ac5", + "subsetneq;": "\u228a", + "subsetneqq;": "\u2acb", + "subsim;": "\u2ac7", + "subsub;": "\u2ad5", + "subsup;": "\u2ad3", + "succ;": "\u227b", + "succapprox;": "\u2ab8", + "succcurlyeq;": "\u227d", + "succeq;": "\u2ab0", + "succnapprox;": "\u2aba", + "succneqq;": "\u2ab6", + "succnsim;": "\u22e9", + "succsim;": "\u227f", + "sum;": "\u2211", + "sung;": "\u266a", + "sup1": "\xb9", + "sup1;": "\xb9", + "sup2": "\xb2", + "sup2;": "\xb2", + "sup3": "\xb3", + "sup3;": "\xb3", + "sup;": "\u2283", + "supE;": "\u2ac6", + "supdot;": "\u2abe", + "supdsub;": "\u2ad8", + "supe;": "\u2287", + "supedot;": "\u2ac4", + "suphsol;": "\u27c9", + "suphsub;": "\u2ad7", + "suplarr;": "\u297b", + "supmult;": "\u2ac2", + "supnE;": "\u2acc", + "supne;": "\u228b", + "supplus;": "\u2ac0", + "supset;": "\u2283", + "supseteq;": "\u2287", + "supseteqq;": "\u2ac6", + "supsetneq;": "\u228b", + "supsetneqq;": "\u2acc", + "supsim;": "\u2ac8", + "supsub;": "\u2ad4", + "supsup;": "\u2ad6", + "swArr;": "\u21d9", + "swarhk;": "\u2926", + "swarr;": "\u2199", + "swarrow;": "\u2199", + "swnwar;": "\u292a", + "szlig": "\xdf", + "szlig;": "\xdf", + "target;": "\u2316", + "tau;": "\u03c4", + "tbrk;": "\u23b4", + "tcaron;": "\u0165", + "tcedil;": "\u0163", + "tcy;": "\u0442", + "tdot;": "\u20db", + "telrec;": "\u2315", + "tfr;": "\U0001d531", + "there4;": "\u2234", + "therefore;": "\u2234", + "theta;": "\u03b8", + "thetasym;": "\u03d1", + "thetav;": "\u03d1", + "thickapprox;": "\u2248", + "thicksim;": "\u223c", + "thinsp;": "\u2009", + "thkap;": "\u2248", + "thksim;": "\u223c", + "thorn": "\xfe", + "thorn;": "\xfe", + "tilde;": "\u02dc", + "times": "\xd7", + "times;": "\xd7", + "timesb;": "\u22a0", + "timesbar;": "\u2a31", + "timesd;": "\u2a30", + "tint;": "\u222d", + "toea;": "\u2928", + "top;": "\u22a4", + "topbot;": "\u2336", + "topcir;": "\u2af1", + "topf;": "\U0001d565", + "topfork;": "\u2ada", + "tosa;": "\u2929", + "tprime;": "\u2034", + "trade;": "\u2122", + "triangle;": "\u25b5", + "triangledown;": "\u25bf", + "triangleleft;": "\u25c3", + "trianglelefteq;": "\u22b4", + "triangleq;": "\u225c", + "triangleright;": "\u25b9", + "trianglerighteq;": "\u22b5", + "tridot;": "\u25ec", + "trie;": "\u225c", + "triminus;": "\u2a3a", + "triplus;": "\u2a39", + "trisb;": "\u29cd", + "tritime;": "\u2a3b", + "trpezium;": "\u23e2", + "tscr;": "\U0001d4c9", + "tscy;": "\u0446", + "tshcy;": "\u045b", + "tstrok;": "\u0167", + "twixt;": "\u226c", + "twoheadleftarrow;": "\u219e", + "twoheadrightarrow;": "\u21a0", + "uArr;": "\u21d1", + "uHar;": "\u2963", + "uacute": "\xfa", + "uacute;": "\xfa", + "uarr;": "\u2191", + "ubrcy;": "\u045e", + "ubreve;": "\u016d", + "ucirc": "\xfb", + "ucirc;": "\xfb", + "ucy;": "\u0443", + "udarr;": "\u21c5", + "udblac;": "\u0171", + "udhar;": "\u296e", + "ufisht;": "\u297e", + "ufr;": "\U0001d532", + "ugrave": "\xf9", + "ugrave;": "\xf9", + "uharl;": "\u21bf", + "uharr;": "\u21be", + "uhblk;": "\u2580", + "ulcorn;": "\u231c", + "ulcorner;": "\u231c", + "ulcrop;": "\u230f", + "ultri;": "\u25f8", + "umacr;": "\u016b", + "uml": "\xa8", + "uml;": "\xa8", + "uogon;": "\u0173", + "uopf;": "\U0001d566", + "uparrow;": "\u2191", + "updownarrow;": "\u2195", + "upharpoonleft;": "\u21bf", + "upharpoonright;": "\u21be", + "uplus;": "\u228e", + "upsi;": "\u03c5", + "upsih;": "\u03d2", + "upsilon;": "\u03c5", + "upuparrows;": "\u21c8", + "urcorn;": "\u231d", + "urcorner;": "\u231d", + "urcrop;": "\u230e", + "uring;": "\u016f", + "urtri;": "\u25f9", + "uscr;": "\U0001d4ca", + "utdot;": "\u22f0", + "utilde;": "\u0169", + "utri;": "\u25b5", + "utrif;": "\u25b4", + "uuarr;": "\u21c8", + "uuml": "\xfc", + "uuml;": "\xfc", + "uwangle;": "\u29a7", + "vArr;": "\u21d5", + "vBar;": "\u2ae8", + "vBarv;": "\u2ae9", + "vDash;": "\u22a8", + "vangrt;": "\u299c", + "varepsilon;": "\u03f5", + "varkappa;": "\u03f0", + "varnothing;": "\u2205", + "varphi;": "\u03d5", + "varpi;": "\u03d6", + "varpropto;": "\u221d", + "varr;": "\u2195", + "varrho;": "\u03f1", + "varsigma;": "\u03c2", + "varsubsetneq;": "\u228a\ufe00", + "varsubsetneqq;": "\u2acb\ufe00", + "varsupsetneq;": "\u228b\ufe00", + "varsupsetneqq;": "\u2acc\ufe00", + "vartheta;": "\u03d1", + "vartriangleleft;": "\u22b2", + "vartriangleright;": "\u22b3", + "vcy;": "\u0432", + "vdash;": "\u22a2", + "vee;": "\u2228", + "veebar;": "\u22bb", + "veeeq;": "\u225a", + "vellip;": "\u22ee", + "verbar;": "|", + "vert;": "|", + "vfr;": "\U0001d533", + "vltri;": "\u22b2", + "vnsub;": "\u2282\u20d2", + "vnsup;": "\u2283\u20d2", + "vopf;": "\U0001d567", + "vprop;": "\u221d", + "vrtri;": "\u22b3", + "vscr;": "\U0001d4cb", + "vsubnE;": "\u2acb\ufe00", + "vsubne;": "\u228a\ufe00", + "vsupnE;": "\u2acc\ufe00", + "vsupne;": "\u228b\ufe00", + "vzigzag;": "\u299a", + "wcirc;": "\u0175", + "wedbar;": "\u2a5f", + "wedge;": "\u2227", + "wedgeq;": "\u2259", + "weierp;": "\u2118", + "wfr;": "\U0001d534", + "wopf;": "\U0001d568", + "wp;": "\u2118", + "wr;": "\u2240", + "wreath;": "\u2240", + "wscr;": "\U0001d4cc", + "xcap;": "\u22c2", + "xcirc;": "\u25ef", + "xcup;": "\u22c3", + "xdtri;": "\u25bd", + "xfr;": "\U0001d535", + "xhArr;": "\u27fa", + "xharr;": "\u27f7", + "xi;": "\u03be", + "xlArr;": "\u27f8", + "xlarr;": "\u27f5", + "xmap;": "\u27fc", + "xnis;": "\u22fb", + "xodot;": "\u2a00", + "xopf;": "\U0001d569", + "xoplus;": "\u2a01", + "xotime;": "\u2a02", + "xrArr;": "\u27f9", + "xrarr;": "\u27f6", + "xscr;": "\U0001d4cd", + "xsqcup;": "\u2a06", + "xuplus;": "\u2a04", + "xutri;": "\u25b3", + "xvee;": "\u22c1", + "xwedge;": "\u22c0", + "yacute": "\xfd", + "yacute;": "\xfd", + "yacy;": "\u044f", + "ycirc;": "\u0177", + "ycy;": "\u044b", + "yen": "\xa5", + "yen;": "\xa5", + "yfr;": "\U0001d536", + "yicy;": "\u0457", + "yopf;": "\U0001d56a", + "yscr;": "\U0001d4ce", + "yucy;": "\u044e", + "yuml": "\xff", + "yuml;": "\xff", + "zacute;": "\u017a", + "zcaron;": "\u017e", + "zcy;": "\u0437", + "zdot;": "\u017c", + "zeetrf;": "\u2128", + "zeta;": "\u03b6", + "zfr;": "\U0001d537", + "zhcy;": "\u0436", + "zigrarr;": "\u21dd", + "zopf;": "\U0001d56b", + "zscr;": "\U0001d4cf", + "zwj;": "\u200d", + "zwnj;": "\u200c", +} + +replacementCharacters = { + 0x0: "\uFFFD", + 0x0d: "\u000D", + 0x80: "\u20AC", + 0x81: "\u0081", + 0x82: "\u201A", + 0x83: "\u0192", + 0x84: "\u201E", + 0x85: "\u2026", + 0x86: "\u2020", + 0x87: "\u2021", + 0x88: "\u02C6", + 0x89: "\u2030", + 0x8A: "\u0160", + 0x8B: "\u2039", + 0x8C: "\u0152", + 0x8D: "\u008D", + 0x8E: "\u017D", + 0x8F: "\u008F", + 0x90: "\u0090", + 0x91: "\u2018", + 0x92: "\u2019", + 0x93: "\u201C", + 0x94: "\u201D", + 0x95: "\u2022", + 0x96: "\u2013", + 0x97: "\u2014", + 0x98: "\u02DC", + 0x99: "\u2122", + 0x9A: "\u0161", + 0x9B: "\u203A", + 0x9C: "\u0153", + 0x9D: "\u009D", + 0x9E: "\u017E", + 0x9F: "\u0178", +} + +tokenTypes = { + "Doctype": 0, + "Characters": 1, + "SpaceCharacters": 2, + "StartTag": 3, + "EndTag": 4, + "EmptyTag": 5, + "Comment": 6, + "ParseError": 7 +} + +tagTokenTypes = frozenset([tokenTypes["StartTag"], tokenTypes["EndTag"], + tokenTypes["EmptyTag"]]) + + +prefixes = dict([(v, k) for k, v in namespaces.items()]) +prefixes["http://www.w3.org/1998/Math/MathML"] = "math" + + +class DataLossWarning(UserWarning): + """Raised when the current tree is unable to represent the input data""" + pass + + +class _ReparseException(Exception): + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py new file mode 100755 index 0000000..d9e234a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py @@ -0,0 +1,29 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + +from collections import OrderedDict + + +def _attr_key(attr): + """Return an appropriate key for an attribute for sorting + + Attributes have a namespace that can be either ``None`` or a string. We + can't compare the two because they're different types, so we convert + ``None`` to an empty string first. + + """ + return (attr[0][0] or ''), attr[0][1] + + +class Filter(base.Filter): + """Alphabetizes attributes for elements""" + def __iter__(self): + for token in base.Filter.__iter__(self): + if token["type"] in ("StartTag", "EmptyTag"): + attrs = OrderedDict() + for name, value in sorted(token["data"].items(), + key=_attr_key): + attrs[name] = value + token["data"] = attrs + yield token diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py new file mode 100755 index 0000000..f5aa523 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, unicode_literals + + +class Filter(object): + def __init__(self, source): + self.source = source + + def __iter__(self): + return iter(self.source) + + def __getattr__(self, name): + return getattr(self.source, name) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py new file mode 100755 index 0000000..2f8ec4f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + + +class Filter(base.Filter): + """Injects ``<meta charset=ENCODING>`` tag into head of document""" + def __init__(self, source, encoding): + """Creates a Filter + + :arg source: the source token stream + + :arg encoding: the encoding to set + + """ + base.Filter.__init__(self, source) + self.encoding = encoding + + def __iter__(self): + state = "pre_head" + meta_found = (self.encoding is None) + pending = [] + + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag": + if token["name"].lower() == "head": + state = "in_head" + + elif type == "EmptyTag": + if token["name"].lower() == "meta": + # replace charset with actual encoding + has_http_equiv_content_type = False + for (namespace, name), value in token["data"].items(): + if namespace is not None: + continue + elif name.lower() == 'charset': + token["data"][(namespace, name)] = self.encoding + meta_found = True + break + elif name == 'http-equiv' and value.lower() == 'content-type': + has_http_equiv_content_type = True + else: + if has_http_equiv_content_type and (None, "content") in token["data"]: + token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding + meta_found = True + + elif token["name"].lower() == "head" and not meta_found: + # insert meta into empty head + yield {"type": "StartTag", "name": "head", + "data": token["data"]} + yield {"type": "EmptyTag", "name": "meta", + "data": {(None, "charset"): self.encoding}} + yield {"type": "EndTag", "name": "head"} + meta_found = True + continue + + elif type == "EndTag": + if token["name"].lower() == "head" and pending: + # insert meta into head (if necessary) and flush pending queue + yield pending.pop(0) + if not meta_found: + yield {"type": "EmptyTag", "name": "meta", + "data": {(None, "charset"): self.encoding}} + while pending: + yield pending.pop(0) + meta_found = True + state = "post_head" + + if state == "in_head": + pending.append(token) + else: + yield token diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py new file mode 100755 index 0000000..b5bbd97 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py @@ -0,0 +1,93 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import text_type + +from . import base +from ..constants import namespaces, voidElements + +from ..constants import spaceCharacters +spaceCharacters = "".join(spaceCharacters) + + +class Filter(base.Filter): + """Lints the token stream for errors + + If it finds any errors, it'll raise an ``AssertionError``. + + """ + def __init__(self, source, require_matching_tags=True): + """Creates a Filter + + :arg source: the source token stream + + :arg require_matching_tags: whether or not to require matching tags + + """ + super(Filter, self).__init__(source) + self.require_matching_tags = require_matching_tags + + def __iter__(self): + open_elements = [] + for token in base.Filter.__iter__(self): + type = token["type"] + if type in ("StartTag", "EmptyTag"): + namespace = token["namespace"] + name = token["name"] + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + assert isinstance(token["data"], dict) + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + assert type == "EmptyTag" + else: + assert type == "StartTag" + if type == "StartTag" and self.require_matching_tags: + open_elements.append((namespace, name)) + for (namespace, name), value in token["data"].items(): + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + assert isinstance(value, text_type) + + elif type == "EndTag": + namespace = token["namespace"] + name = token["name"] + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + assert False, "Void element reported as EndTag token: %(tag)s" % {"tag": name} + elif self.require_matching_tags: + start = open_elements.pop() + assert start == (namespace, name) + + elif type == "Comment": + data = token["data"] + assert isinstance(data, text_type) + + elif type in ("Characters", "SpaceCharacters"): + data = token["data"] + assert isinstance(data, text_type) + assert data != "" + if type == "SpaceCharacters": + assert data.strip(spaceCharacters) == "" + + elif type == "Doctype": + name = token["name"] + assert name is None or isinstance(name, text_type) + assert token["publicId"] is None or isinstance(name, text_type) + assert token["systemId"] is None or isinstance(name, text_type) + + elif type == "Entity": + assert isinstance(token["name"], text_type) + + elif type == "SerializerError": + assert isinstance(token["data"], text_type) + + else: + assert False, "Unknown token type: %(type)s" % {"type": type} + + yield token diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py new file mode 100755 index 0000000..c8d5e54 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py @@ -0,0 +1,207 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + + +class Filter(base.Filter): + """Removes optional tags from the token stream""" + def slider(self): + previous1 = previous2 = None + for token in self.source: + if previous1 is not None: + yield previous2, previous1, token + previous2 = previous1 + previous1 = token + if previous1 is not None: + yield previous2, previous1, None + + def __iter__(self): + for previous, token, next in self.slider(): + type = token["type"] + if type == "StartTag": + if (token["data"] or + not self.is_optional_start(token["name"], previous, next)): + yield token + elif type == "EndTag": + if not self.is_optional_end(token["name"], next): + yield token + else: + yield token + + def is_optional_start(self, tagname, previous, next): + type = next and next["type"] or None + if tagname in 'html': + # An html element's start tag may be omitted if the first thing + # inside the html element is not a space character or a comment. + return type not in ("Comment", "SpaceCharacters") + elif tagname == 'head': + # A head element's start tag may be omitted if the first thing + # inside the head element is an element. + # XXX: we also omit the start tag if the head element is empty + if type in ("StartTag", "EmptyTag"): + return True + elif type == "EndTag": + return next["name"] == "head" + elif tagname == 'body': + # A body element's start tag may be omitted if the first thing + # inside the body element is not a space character or a comment, + # except if the first thing inside the body element is a script + # or style element and the node immediately preceding the body + # element is a head element whose end tag has been omitted. + if type in ("Comment", "SpaceCharacters"): + return False + elif type == "StartTag": + # XXX: we do not look at the preceding event, so we never omit + # the body element's start tag if it's followed by a script or + # a style element. + return next["name"] not in ('script', 'style') + else: + return True + elif tagname == 'colgroup': + # A colgroup element's start tag may be omitted if the first thing + # inside the colgroup element is a col element, and if the element + # is not immediately preceded by another colgroup element whose + # end tag has been omitted. + if type in ("StartTag", "EmptyTag"): + # XXX: we do not look at the preceding event, so instead we never + # omit the colgroup element's end tag when it is immediately + # followed by another colgroup element. See is_optional_end. + return next["name"] == "col" + else: + return False + elif tagname == 'tbody': + # A tbody element's start tag may be omitted if the first thing + # inside the tbody element is a tr element, and if the element is + # not immediately preceded by a tbody, thead, or tfoot element + # whose end tag has been omitted. + if type == "StartTag": + # omit the thead and tfoot elements' end tag when they are + # immediately followed by a tbody element. See is_optional_end. + if previous and previous['type'] == 'EndTag' and \ + previous['name'] in ('tbody', 'thead', 'tfoot'): + return False + return next["name"] == 'tr' + else: + return False + return False + + def is_optional_end(self, tagname, next): + type = next and next["type"] or None + if tagname in ('html', 'head', 'body'): + # An html element's end tag may be omitted if the html element + # is not immediately followed by a space character or a comment. + return type not in ("Comment", "SpaceCharacters") + elif tagname in ('li', 'optgroup', 'tr'): + # A li element's end tag may be omitted if the li element is + # immediately followed by another li element or if there is + # no more content in the parent element. + # An optgroup element's end tag may be omitted if the optgroup + # element is immediately followed by another optgroup element, + # or if there is no more content in the parent element. + # A tr element's end tag may be omitted if the tr element is + # immediately followed by another tr element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] == tagname + else: + return type == "EndTag" or type is None + elif tagname in ('dt', 'dd'): + # A dt element's end tag may be omitted if the dt element is + # immediately followed by another dt element or a dd element. + # A dd element's end tag may be omitted if the dd element is + # immediately followed by another dd element or a dt element, + # or if there is no more content in the parent element. + if type == "StartTag": + return next["name"] in ('dt', 'dd') + elif tagname == 'dd': + return type == "EndTag" or type is None + else: + return False + elif tagname == 'p': + # A p element's end tag may be omitted if the p element is + # immediately followed by an address, article, aside, + # blockquote, datagrid, dialog, dir, div, dl, fieldset, + # footer, form, h1, h2, h3, h4, h5, h6, header, hr, menu, + # nav, ol, p, pre, section, table, or ul, element, or if + # there is no more content in the parent element. + if type in ("StartTag", "EmptyTag"): + return next["name"] in ('address', 'article', 'aside', + 'blockquote', 'datagrid', 'dialog', + 'dir', 'div', 'dl', 'fieldset', 'footer', + 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'header', 'hr', 'menu', 'nav', 'ol', + 'p', 'pre', 'section', 'table', 'ul') + else: + return type == "EndTag" or type is None + elif tagname == 'option': + # An option element's end tag may be omitted if the option + # element is immediately followed by another option element, + # or if it is immediately followed by an <code>optgroup</code> + # element, or if there is no more content in the parent + # element. + if type == "StartTag": + return next["name"] in ('option', 'optgroup') + else: + return type == "EndTag" or type is None + elif tagname in ('rt', 'rp'): + # An rt element's end tag may be omitted if the rt element is + # immediately followed by an rt or rp element, or if there is + # no more content in the parent element. + # An rp element's end tag may be omitted if the rp element is + # immediately followed by an rt or rp element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] in ('rt', 'rp') + else: + return type == "EndTag" or type is None + elif tagname == 'colgroup': + # A colgroup element's end tag may be omitted if the colgroup + # element is not immediately followed by a space character or + # a comment. + if type in ("Comment", "SpaceCharacters"): + return False + elif type == "StartTag": + # XXX: we also look for an immediately following colgroup + # element. See is_optional_start. + return next["name"] != 'colgroup' + else: + return True + elif tagname in ('thead', 'tbody'): + # A thead element's end tag may be omitted if the thead element + # is immediately followed by a tbody or tfoot element. + # A tbody element's end tag may be omitted if the tbody element + # is immediately followed by a tbody or tfoot element, or if + # there is no more content in the parent element. + # A tfoot element's end tag may be omitted if the tfoot element + # is immediately followed by a tbody element, or if there is no + # more content in the parent element. + # XXX: we never omit the end tag when the following element is + # a tbody. See is_optional_start. + if type == "StartTag": + return next["name"] in ['tbody', 'tfoot'] + elif tagname == 'tbody': + return type == "EndTag" or type is None + else: + return False + elif tagname == 'tfoot': + # A tfoot element's end tag may be omitted if the tfoot element + # is immediately followed by a tbody element, or if there is no + # more content in the parent element. + # XXX: we never omit the end tag when the following element is + # a tbody. See is_optional_start. + if type == "StartTag": + return next["name"] == 'tbody' + else: + return type == "EndTag" or type is None + elif tagname in ('td', 'th'): + # A td element's end tag may be omitted if the td element is + # immediately followed by a td or th element, or if there is + # no more content in the parent element. + # A th element's end tag may be omitted if the th element is + # immediately followed by a td or th element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] in ('td', 'th') + else: + return type == "EndTag" or type is None + return False diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py new file mode 100755 index 0000000..c3199a5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py @@ -0,0 +1,896 @@ +from __future__ import absolute_import, division, unicode_literals + +import re +from xml.sax.saxutils import escape, unescape + +from pip._vendor.six.moves import urllib_parse as urlparse + +from . import base +from ..constants import namespaces, prefixes + +__all__ = ["Filter"] + + +allowed_elements = frozenset(( + (namespaces['html'], 'a'), + (namespaces['html'], 'abbr'), + (namespaces['html'], 'acronym'), + (namespaces['html'], 'address'), + (namespaces['html'], 'area'), + (namespaces['html'], 'article'), + (namespaces['html'], 'aside'), + (namespaces['html'], 'audio'), + (namespaces['html'], 'b'), + (namespaces['html'], 'big'), + (namespaces['html'], 'blockquote'), + (namespaces['html'], 'br'), + (namespaces['html'], 'button'), + (namespaces['html'], 'canvas'), + (namespaces['html'], 'caption'), + (namespaces['html'], 'center'), + (namespaces['html'], 'cite'), + (namespaces['html'], 'code'), + (namespaces['html'], 'col'), + (namespaces['html'], 'colgroup'), + (namespaces['html'], 'command'), + (namespaces['html'], 'datagrid'), + (namespaces['html'], 'datalist'), + (namespaces['html'], 'dd'), + (namespaces['html'], 'del'), + (namespaces['html'], 'details'), + (namespaces['html'], 'dfn'), + (namespaces['html'], 'dialog'), + (namespaces['html'], 'dir'), + (namespaces['html'], 'div'), + (namespaces['html'], 'dl'), + (namespaces['html'], 'dt'), + (namespaces['html'], 'em'), + (namespaces['html'], 'event-source'), + (namespaces['html'], 'fieldset'), + (namespaces['html'], 'figcaption'), + (namespaces['html'], 'figure'), + (namespaces['html'], 'footer'), + (namespaces['html'], 'font'), + (namespaces['html'], 'form'), + (namespaces['html'], 'header'), + (namespaces['html'], 'h1'), + (namespaces['html'], 'h2'), + (namespaces['html'], 'h3'), + (namespaces['html'], 'h4'), + (namespaces['html'], 'h5'), + (namespaces['html'], 'h6'), + (namespaces['html'], 'hr'), + (namespaces['html'], 'i'), + (namespaces['html'], 'img'), + (namespaces['html'], 'input'), + (namespaces['html'], 'ins'), + (namespaces['html'], 'keygen'), + (namespaces['html'], 'kbd'), + (namespaces['html'], 'label'), + (namespaces['html'], 'legend'), + (namespaces['html'], 'li'), + (namespaces['html'], 'm'), + (namespaces['html'], 'map'), + (namespaces['html'], 'menu'), + (namespaces['html'], 'meter'), + (namespaces['html'], 'multicol'), + (namespaces['html'], 'nav'), + (namespaces['html'], 'nextid'), + (namespaces['html'], 'ol'), + (namespaces['html'], 'output'), + (namespaces['html'], 'optgroup'), + (namespaces['html'], 'option'), + (namespaces['html'], 'p'), + (namespaces['html'], 'pre'), + (namespaces['html'], 'progress'), + (namespaces['html'], 'q'), + (namespaces['html'], 's'), + (namespaces['html'], 'samp'), + (namespaces['html'], 'section'), + (namespaces['html'], 'select'), + (namespaces['html'], 'small'), + (namespaces['html'], 'sound'), + (namespaces['html'], 'source'), + (namespaces['html'], 'spacer'), + (namespaces['html'], 'span'), + (namespaces['html'], 'strike'), + (namespaces['html'], 'strong'), + (namespaces['html'], 'sub'), + (namespaces['html'], 'sup'), + (namespaces['html'], 'table'), + (namespaces['html'], 'tbody'), + (namespaces['html'], 'td'), + (namespaces['html'], 'textarea'), + (namespaces['html'], 'time'), + (namespaces['html'], 'tfoot'), + (namespaces['html'], 'th'), + (namespaces['html'], 'thead'), + (namespaces['html'], 'tr'), + (namespaces['html'], 'tt'), + (namespaces['html'], 'u'), + (namespaces['html'], 'ul'), + (namespaces['html'], 'var'), + (namespaces['html'], 'video'), + (namespaces['mathml'], 'maction'), + (namespaces['mathml'], 'math'), + (namespaces['mathml'], 'merror'), + (namespaces['mathml'], 'mfrac'), + (namespaces['mathml'], 'mi'), + (namespaces['mathml'], 'mmultiscripts'), + (namespaces['mathml'], 'mn'), + (namespaces['mathml'], 'mo'), + (namespaces['mathml'], 'mover'), + (namespaces['mathml'], 'mpadded'), + (namespaces['mathml'], 'mphantom'), + (namespaces['mathml'], 'mprescripts'), + (namespaces['mathml'], 'mroot'), + (namespaces['mathml'], 'mrow'), + (namespaces['mathml'], 'mspace'), + (namespaces['mathml'], 'msqrt'), + (namespaces['mathml'], 'mstyle'), + (namespaces['mathml'], 'msub'), + (namespaces['mathml'], 'msubsup'), + (namespaces['mathml'], 'msup'), + (namespaces['mathml'], 'mtable'), + (namespaces['mathml'], 'mtd'), + (namespaces['mathml'], 'mtext'), + (namespaces['mathml'], 'mtr'), + (namespaces['mathml'], 'munder'), + (namespaces['mathml'], 'munderover'), + (namespaces['mathml'], 'none'), + (namespaces['svg'], 'a'), + (namespaces['svg'], 'animate'), + (namespaces['svg'], 'animateColor'), + (namespaces['svg'], 'animateMotion'), + (namespaces['svg'], 'animateTransform'), + (namespaces['svg'], 'clipPath'), + (namespaces['svg'], 'circle'), + (namespaces['svg'], 'defs'), + (namespaces['svg'], 'desc'), + (namespaces['svg'], 'ellipse'), + (namespaces['svg'], 'font-face'), + (namespaces['svg'], 'font-face-name'), + (namespaces['svg'], 'font-face-src'), + (namespaces['svg'], 'g'), + (namespaces['svg'], 'glyph'), + (namespaces['svg'], 'hkern'), + (namespaces['svg'], 'linearGradient'), + (namespaces['svg'], 'line'), + (namespaces['svg'], 'marker'), + (namespaces['svg'], 'metadata'), + (namespaces['svg'], 'missing-glyph'), + (namespaces['svg'], 'mpath'), + (namespaces['svg'], 'path'), + (namespaces['svg'], 'polygon'), + (namespaces['svg'], 'polyline'), + (namespaces['svg'], 'radialGradient'), + (namespaces['svg'], 'rect'), + (namespaces['svg'], 'set'), + (namespaces['svg'], 'stop'), + (namespaces['svg'], 'svg'), + (namespaces['svg'], 'switch'), + (namespaces['svg'], 'text'), + (namespaces['svg'], 'title'), + (namespaces['svg'], 'tspan'), + (namespaces['svg'], 'use'), +)) + +allowed_attributes = frozenset(( + # HTML attributes + (None, 'abbr'), + (None, 'accept'), + (None, 'accept-charset'), + (None, 'accesskey'), + (None, 'action'), + (None, 'align'), + (None, 'alt'), + (None, 'autocomplete'), + (None, 'autofocus'), + (None, 'axis'), + (None, 'background'), + (None, 'balance'), + (None, 'bgcolor'), + (None, 'bgproperties'), + (None, 'border'), + (None, 'bordercolor'), + (None, 'bordercolordark'), + (None, 'bordercolorlight'), + (None, 'bottompadding'), + (None, 'cellpadding'), + (None, 'cellspacing'), + (None, 'ch'), + (None, 'challenge'), + (None, 'char'), + (None, 'charoff'), + (None, 'choff'), + (None, 'charset'), + (None, 'checked'), + (None, 'cite'), + (None, 'class'), + (None, 'clear'), + (None, 'color'), + (None, 'cols'), + (None, 'colspan'), + (None, 'compact'), + (None, 'contenteditable'), + (None, 'controls'), + (None, 'coords'), + (None, 'data'), + (None, 'datafld'), + (None, 'datapagesize'), + (None, 'datasrc'), + (None, 'datetime'), + (None, 'default'), + (None, 'delay'), + (None, 'dir'), + (None, 'disabled'), + (None, 'draggable'), + (None, 'dynsrc'), + (None, 'enctype'), + (None, 'end'), + (None, 'face'), + (None, 'for'), + (None, 'form'), + (None, 'frame'), + (None, 'galleryimg'), + (None, 'gutter'), + (None, 'headers'), + (None, 'height'), + (None, 'hidefocus'), + (None, 'hidden'), + (None, 'high'), + (None, 'href'), + (None, 'hreflang'), + (None, 'hspace'), + (None, 'icon'), + (None, 'id'), + (None, 'inputmode'), + (None, 'ismap'), + (None, 'keytype'), + (None, 'label'), + (None, 'leftspacing'), + (None, 'lang'), + (None, 'list'), + (None, 'longdesc'), + (None, 'loop'), + (None, 'loopcount'), + (None, 'loopend'), + (None, 'loopstart'), + (None, 'low'), + (None, 'lowsrc'), + (None, 'max'), + (None, 'maxlength'), + (None, 'media'), + (None, 'method'), + (None, 'min'), + (None, 'multiple'), + (None, 'name'), + (None, 'nohref'), + (None, 'noshade'), + (None, 'nowrap'), + (None, 'open'), + (None, 'optimum'), + (None, 'pattern'), + (None, 'ping'), + (None, 'point-size'), + (None, 'poster'), + (None, 'pqg'), + (None, 'preload'), + (None, 'prompt'), + (None, 'radiogroup'), + (None, 'readonly'), + (None, 'rel'), + (None, 'repeat-max'), + (None, 'repeat-min'), + (None, 'replace'), + (None, 'required'), + (None, 'rev'), + (None, 'rightspacing'), + (None, 'rows'), + (None, 'rowspan'), + (None, 'rules'), + (None, 'scope'), + (None, 'selected'), + (None, 'shape'), + (None, 'size'), + (None, 'span'), + (None, 'src'), + (None, 'start'), + (None, 'step'), + (None, 'style'), + (None, 'summary'), + (None, 'suppress'), + (None, 'tabindex'), + (None, 'target'), + (None, 'template'), + (None, 'title'), + (None, 'toppadding'), + (None, 'type'), + (None, 'unselectable'), + (None, 'usemap'), + (None, 'urn'), + (None, 'valign'), + (None, 'value'), + (None, 'variable'), + (None, 'volume'), + (None, 'vspace'), + (None, 'vrml'), + (None, 'width'), + (None, 'wrap'), + (namespaces['xml'], 'lang'), + # MathML attributes + (None, 'actiontype'), + (None, 'align'), + (None, 'columnalign'), + (None, 'columnalign'), + (None, 'columnalign'), + (None, 'columnlines'), + (None, 'columnspacing'), + (None, 'columnspan'), + (None, 'depth'), + (None, 'display'), + (None, 'displaystyle'), + (None, 'equalcolumns'), + (None, 'equalrows'), + (None, 'fence'), + (None, 'fontstyle'), + (None, 'fontweight'), + (None, 'frame'), + (None, 'height'), + (None, 'linethickness'), + (None, 'lspace'), + (None, 'mathbackground'), + (None, 'mathcolor'), + (None, 'mathvariant'), + (None, 'mathvariant'), + (None, 'maxsize'), + (None, 'minsize'), + (None, 'other'), + (None, 'rowalign'), + (None, 'rowalign'), + (None, 'rowalign'), + (None, 'rowlines'), + (None, 'rowspacing'), + (None, 'rowspan'), + (None, 'rspace'), + (None, 'scriptlevel'), + (None, 'selection'), + (None, 'separator'), + (None, 'stretchy'), + (None, 'width'), + (None, 'width'), + (namespaces['xlink'], 'href'), + (namespaces['xlink'], 'show'), + (namespaces['xlink'], 'type'), + # SVG attributes + (None, 'accent-height'), + (None, 'accumulate'), + (None, 'additive'), + (None, 'alphabetic'), + (None, 'arabic-form'), + (None, 'ascent'), + (None, 'attributeName'), + (None, 'attributeType'), + (None, 'baseProfile'), + (None, 'bbox'), + (None, 'begin'), + (None, 'by'), + (None, 'calcMode'), + (None, 'cap-height'), + (None, 'class'), + (None, 'clip-path'), + (None, 'color'), + (None, 'color-rendering'), + (None, 'content'), + (None, 'cx'), + (None, 'cy'), + (None, 'd'), + (None, 'dx'), + (None, 'dy'), + (None, 'descent'), + (None, 'display'), + (None, 'dur'), + (None, 'end'), + (None, 'fill'), + (None, 'fill-opacity'), + (None, 'fill-rule'), + (None, 'font-family'), + (None, 'font-size'), + (None, 'font-stretch'), + (None, 'font-style'), + (None, 'font-variant'), + (None, 'font-weight'), + (None, 'from'), + (None, 'fx'), + (None, 'fy'), + (None, 'g1'), + (None, 'g2'), + (None, 'glyph-name'), + (None, 'gradientUnits'), + (None, 'hanging'), + (None, 'height'), + (None, 'horiz-adv-x'), + (None, 'horiz-origin-x'), + (None, 'id'), + (None, 'ideographic'), + (None, 'k'), + (None, 'keyPoints'), + (None, 'keySplines'), + (None, 'keyTimes'), + (None, 'lang'), + (None, 'marker-end'), + (None, 'marker-mid'), + (None, 'marker-start'), + (None, 'markerHeight'), + (None, 'markerUnits'), + (None, 'markerWidth'), + (None, 'mathematical'), + (None, 'max'), + (None, 'min'), + (None, 'name'), + (None, 'offset'), + (None, 'opacity'), + (None, 'orient'), + (None, 'origin'), + (None, 'overline-position'), + (None, 'overline-thickness'), + (None, 'panose-1'), + (None, 'path'), + (None, 'pathLength'), + (None, 'points'), + (None, 'preserveAspectRatio'), + (None, 'r'), + (None, 'refX'), + (None, 'refY'), + (None, 'repeatCount'), + (None, 'repeatDur'), + (None, 'requiredExtensions'), + (None, 'requiredFeatures'), + (None, 'restart'), + (None, 'rotate'), + (None, 'rx'), + (None, 'ry'), + (None, 'slope'), + (None, 'stemh'), + (None, 'stemv'), + (None, 'stop-color'), + (None, 'stop-opacity'), + (None, 'strikethrough-position'), + (None, 'strikethrough-thickness'), + (None, 'stroke'), + (None, 'stroke-dasharray'), + (None, 'stroke-dashoffset'), + (None, 'stroke-linecap'), + (None, 'stroke-linejoin'), + (None, 'stroke-miterlimit'), + (None, 'stroke-opacity'), + (None, 'stroke-width'), + (None, 'systemLanguage'), + (None, 'target'), + (None, 'text-anchor'), + (None, 'to'), + (None, 'transform'), + (None, 'type'), + (None, 'u1'), + (None, 'u2'), + (None, 'underline-position'), + (None, 'underline-thickness'), + (None, 'unicode'), + (None, 'unicode-range'), + (None, 'units-per-em'), + (None, 'values'), + (None, 'version'), + (None, 'viewBox'), + (None, 'visibility'), + (None, 'width'), + (None, 'widths'), + (None, 'x'), + (None, 'x-height'), + (None, 'x1'), + (None, 'x2'), + (namespaces['xlink'], 'actuate'), + (namespaces['xlink'], 'arcrole'), + (namespaces['xlink'], 'href'), + (namespaces['xlink'], 'role'), + (namespaces['xlink'], 'show'), + (namespaces['xlink'], 'title'), + (namespaces['xlink'], 'type'), + (namespaces['xml'], 'base'), + (namespaces['xml'], 'lang'), + (namespaces['xml'], 'space'), + (None, 'y'), + (None, 'y1'), + (None, 'y2'), + (None, 'zoomAndPan'), +)) + +attr_val_is_uri = frozenset(( + (None, 'href'), + (None, 'src'), + (None, 'cite'), + (None, 'action'), + (None, 'longdesc'), + (None, 'poster'), + (None, 'background'), + (None, 'datasrc'), + (None, 'dynsrc'), + (None, 'lowsrc'), + (None, 'ping'), + (namespaces['xlink'], 'href'), + (namespaces['xml'], 'base'), +)) + +svg_attr_val_allows_ref = frozenset(( + (None, 'clip-path'), + (None, 'color-profile'), + (None, 'cursor'), + (None, 'fill'), + (None, 'filter'), + (None, 'marker'), + (None, 'marker-start'), + (None, 'marker-mid'), + (None, 'marker-end'), + (None, 'mask'), + (None, 'stroke'), +)) + +svg_allow_local_href = frozenset(( + (None, 'altGlyph'), + (None, 'animate'), + (None, 'animateColor'), + (None, 'animateMotion'), + (None, 'animateTransform'), + (None, 'cursor'), + (None, 'feImage'), + (None, 'filter'), + (None, 'linearGradient'), + (None, 'pattern'), + (None, 'radialGradient'), + (None, 'textpath'), + (None, 'tref'), + (None, 'set'), + (None, 'use') +)) + +allowed_css_properties = frozenset(( + 'azimuth', + 'background-color', + 'border-bottom-color', + 'border-collapse', + 'border-color', + 'border-left-color', + 'border-right-color', + 'border-top-color', + 'clear', + 'color', + 'cursor', + 'direction', + 'display', + 'elevation', + 'float', + 'font', + 'font-family', + 'font-size', + 'font-style', + 'font-variant', + 'font-weight', + 'height', + 'letter-spacing', + 'line-height', + 'overflow', + 'pause', + 'pause-after', + 'pause-before', + 'pitch', + 'pitch-range', + 'richness', + 'speak', + 'speak-header', + 'speak-numeral', + 'speak-punctuation', + 'speech-rate', + 'stress', + 'text-align', + 'text-decoration', + 'text-indent', + 'unicode-bidi', + 'vertical-align', + 'voice-family', + 'volume', + 'white-space', + 'width', +)) + +allowed_css_keywords = frozenset(( + 'auto', + 'aqua', + 'black', + 'block', + 'blue', + 'bold', + 'both', + 'bottom', + 'brown', + 'center', + 'collapse', + 'dashed', + 'dotted', + 'fuchsia', + 'gray', + 'green', + '!important', + 'italic', + 'left', + 'lime', + 'maroon', + 'medium', + 'none', + 'navy', + 'normal', + 'nowrap', + 'olive', + 'pointer', + 'purple', + 'red', + 'right', + 'solid', + 'silver', + 'teal', + 'top', + 'transparent', + 'underline', + 'white', + 'yellow', +)) + +allowed_svg_properties = frozenset(( + 'fill', + 'fill-opacity', + 'fill-rule', + 'stroke', + 'stroke-width', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-opacity', +)) + +allowed_protocols = frozenset(( + 'ed2k', + 'ftp', + 'http', + 'https', + 'irc', + 'mailto', + 'news', + 'gopher', + 'nntp', + 'telnet', + 'webcal', + 'xmpp', + 'callto', + 'feed', + 'urn', + 'aim', + 'rsync', + 'tag', + 'ssh', + 'sftp', + 'rtsp', + 'afs', + 'data', +)) + +allowed_content_types = frozenset(( + 'image/png', + 'image/jpeg', + 'image/gif', + 'image/webp', + 'image/bmp', + 'text/plain', +)) + + +data_content_type = re.compile(r''' + ^ + # Match a content type <application>/<type> + (?P<content_type>[-a-zA-Z0-9.]+/[-a-zA-Z0-9.]+) + # Match any character set and encoding + (?:(?:;charset=(?:[-a-zA-Z0-9]+)(?:;(?:base64))?) + |(?:;(?:base64))?(?:;charset=(?:[-a-zA-Z0-9]+))?) + # Assume the rest is data + ,.* + $ + ''', + re.VERBOSE) + + +class Filter(base.Filter): + """Sanitizes token stream of XHTML+MathML+SVG and of inline style attributes""" + def __init__(self, + source, + allowed_elements=allowed_elements, + allowed_attributes=allowed_attributes, + allowed_css_properties=allowed_css_properties, + allowed_css_keywords=allowed_css_keywords, + allowed_svg_properties=allowed_svg_properties, + allowed_protocols=allowed_protocols, + allowed_content_types=allowed_content_types, + attr_val_is_uri=attr_val_is_uri, + svg_attr_val_allows_ref=svg_attr_val_allows_ref, + svg_allow_local_href=svg_allow_local_href): + """Creates a Filter + + :arg allowed_elements: set of elements to allow--everything else will + be escaped + + :arg allowed_attributes: set of attributes to allow in + elements--everything else will be stripped + + :arg allowed_css_properties: set of CSS properties to allow--everything + else will be stripped + + :arg allowed_css_keywords: set of CSS keywords to allow--everything + else will be stripped + + :arg allowed_svg_properties: set of SVG properties to allow--everything + else will be removed + + :arg allowed_protocols: set of allowed protocols for URIs + + :arg allowed_content_types: set of allowed content types for ``data`` URIs. + + :arg attr_val_is_uri: set of attributes that have URI values--values + that have a scheme not listed in ``allowed_protocols`` are removed + + :arg svg_attr_val_allows_ref: set of SVG attributes that can have + references + + :arg svg_allow_local_href: set of SVG elements that can have local + hrefs--these are removed + + """ + super(Filter, self).__init__(source) + self.allowed_elements = allowed_elements + self.allowed_attributes = allowed_attributes + self.allowed_css_properties = allowed_css_properties + self.allowed_css_keywords = allowed_css_keywords + self.allowed_svg_properties = allowed_svg_properties + self.allowed_protocols = allowed_protocols + self.allowed_content_types = allowed_content_types + self.attr_val_is_uri = attr_val_is_uri + self.svg_attr_val_allows_ref = svg_attr_val_allows_ref + self.svg_allow_local_href = svg_allow_local_href + + def __iter__(self): + for token in base.Filter.__iter__(self): + token = self.sanitize_token(token) + if token: + yield token + + # Sanitize the +html+, escaping all elements not in ALLOWED_ELEMENTS, and + # stripping out all attributes not in ALLOWED_ATTRIBUTES. Style attributes + # are parsed, and a restricted set, specified by ALLOWED_CSS_PROPERTIES and + # ALLOWED_CSS_KEYWORDS, are allowed through. attributes in ATTR_VAL_IS_URI + # are scanned, and only URI schemes specified in ALLOWED_PROTOCOLS are + # allowed. + # + # sanitize_html('<script> do_nasty_stuff() </script>') + # => <script> do_nasty_stuff() </script> + # sanitize_html('<a href="javascript: sucker();">Click here for $100</a>') + # => <a>Click here for $100</a> + def sanitize_token(self, token): + + # accommodate filters which use token_type differently + token_type = token["type"] + if token_type in ("StartTag", "EndTag", "EmptyTag"): + name = token["name"] + namespace = token["namespace"] + if ((namespace, name) in self.allowed_elements or + (namespace is None and + (namespaces["html"], name) in self.allowed_elements)): + return self.allowed_token(token) + else: + return self.disallowed_token(token) + elif token_type == "Comment": + pass + else: + return token + + def allowed_token(self, token): + if "data" in token: + attrs = token["data"] + attr_names = set(attrs.keys()) + + # Remove forbidden attributes + for to_remove in (attr_names - self.allowed_attributes): + del token["data"][to_remove] + attr_names.remove(to_remove) + + # Remove attributes with disallowed URL values + for attr in (attr_names & self.attr_val_is_uri): + assert attr in attrs + # I don't have a clue where this regexp comes from or why it matches those + # characters, nor why we call unescape. I just know it's always been here. + # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all + # this will do is remove *more* than it otherwise would. + val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\\s]+", '', + unescape(attrs[attr])).lower() + # remove replacement characters from unescaped characters + val_unescaped = val_unescaped.replace("\ufffd", "") + try: + uri = urlparse.urlparse(val_unescaped) + except ValueError: + uri = None + del attrs[attr] + if uri and uri.scheme: + if uri.scheme not in self.allowed_protocols: + del attrs[attr] + if uri.scheme == 'data': + m = data_content_type.match(uri.path) + if not m: + del attrs[attr] + elif m.group('content_type') not in self.allowed_content_types: + del attrs[attr] + + for attr in self.svg_attr_val_allows_ref: + if attr in attrs: + attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', + ' ', + unescape(attrs[attr])) + if (token["name"] in self.svg_allow_local_href and + (namespaces['xlink'], 'href') in attrs and re.search(r'^\s*[^#\s].*', + attrs[(namespaces['xlink'], 'href')])): + del attrs[(namespaces['xlink'], 'href')] + if (None, 'style') in attrs: + attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) + token["data"] = attrs + return token + + def disallowed_token(self, token): + token_type = token["type"] + if token_type == "EndTag": + token["data"] = "</%s>" % token["name"] + elif token["data"]: + assert token_type in ("StartTag", "EmptyTag") + attrs = [] + for (ns, name), v in token["data"].items(): + attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) + token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) + else: + token["data"] = "<%s>" % token["name"] + if token.get("selfClosing"): + token["data"] = token["data"][:-1] + "/>" + + token["type"] = "Characters" + + del token["name"] + return token + + def sanitize_css(self, style): + # disallow urls + style = re.compile(r'url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) + + # gauntlet + if not re.match(r"""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): + return '' + if not re.match(r"^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): + return '' + + clean = [] + for prop, value in re.findall(r"([-\w]+)\s*:\s*([^:;]*)", style): + if not value: + continue + if prop.lower() in self.allowed_css_properties: + clean.append(prop + ': ' + value + ';') + elif prop.split('-')[0].lower() in ['background', 'border', 'margin', + 'padding']: + for keyword in value.split(): + if keyword not in self.allowed_css_keywords and \ + not re.match(r"^(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa + break + else: + clean.append(prop + ': ' + value + ';') + elif prop.lower() in self.allowed_svg_properties: + clean.append(prop + ': ' + value + ';') + + return ' '.join(clean) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py new file mode 100755 index 0000000..24bb0de --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py @@ -0,0 +1,38 @@ +from __future__ import absolute_import, division, unicode_literals + +import re + +from . import base +from ..constants import rcdataElements, spaceCharacters +spaceCharacters = "".join(spaceCharacters) + +SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) + + +class Filter(base.Filter): + """Collapses whitespace except in pre, textarea, and script elements""" + spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) + + def __iter__(self): + preserve = 0 + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag" \ + and (preserve or token["name"] in self.spacePreserveElements): + preserve += 1 + + elif type == "EndTag" and preserve: + preserve -= 1 + + elif not preserve and type == "SpaceCharacters" and token["data"]: + # Test on token["data"] above to not introduce spaces where there were not + token["data"] = " " + + elif not preserve and type == "Characters": + token["data"] = collapse_spaces(token["data"]) + + yield token + + +def collapse_spaces(text): + return SPACES_REGEX.sub(' ', text) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py new file mode 100755 index 0000000..b185971 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py @@ -0,0 +1,2791 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import with_metaclass, viewkeys + +import types +from collections import OrderedDict + +from . import _inputstream +from . import _tokenizer + +from . import treebuilders +from .treebuilders.base import Marker + +from . import _utils +from .constants import ( + spaceCharacters, asciiUpper2Lower, + specialElements, headingElements, cdataElements, rcdataElements, + tokenTypes, tagTokenTypes, + namespaces, + htmlIntegrationPointElements, mathmlTextIntegrationPointElements, + adjustForeignAttributes as adjustForeignAttributesMap, + adjustMathMLAttributes, adjustSVGAttributes, + E, + _ReparseException +) + + +def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML document as a string or file-like object into a tree + + :arg doc: the document to parse as a string or file-like object + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import parse + >>> parse('<html><body><p>This is a doc</p></body></html>') + <Element u'{http://www.w3.org/1999/xhtml}html' at 0x7feac4909db0> + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parse(doc, **kwargs) + + +def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML fragment as a string or file-like object into a tree + + :arg doc: the fragment to parse as a string or file-like object + + :arg container: the container context to parse the fragment in + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import parseFragment + >>> parseFragment('<b>this is a fragment</b>') + <Element u'DOCUMENT_FRAGMENT' at 0x7feac484b090> + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parseFragment(doc, container=container, **kwargs) + + +def method_decorator_metaclass(function): + class Decorated(type): + def __new__(meta, classname, bases, classDict): + for attributeName, attribute in classDict.items(): + if isinstance(attribute, types.FunctionType): + attribute = function(attribute) + + classDict[attributeName] = attribute + return type.__new__(meta, classname, bases, classDict) + return Decorated + + +class HTMLParser(object): + """HTML parser + + Generates a tree structure from a stream of (possibly malformed) HTML. + + """ + + def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): + """ + :arg tree: a treebuilder class controlling the type of tree that will be + returned. Built in treebuilders can be accessed through + html5lib.treebuilders.getTreeBuilder(treeType) + + :arg strict: raise an exception when a parse error is encountered + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :arg debug: whether or not to enable debug mode which logs things + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() # generates parser with etree builder + >>> parser = HTMLParser('lxml', strict=True) # generates parser with lxml builder which is strict + + """ + + # Raise an exception on the first error encountered + self.strict = strict + + if tree is None: + tree = treebuilders.getTreeBuilder("etree") + self.tree = tree(namespaceHTMLElements) + self.errors = [] + + self.phases = dict([(name, cls(self, self.tree)) for name, cls in + getPhases(debug).items()]) + + def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): + + self.innerHTMLMode = innerHTML + self.container = container + self.scripting = scripting + self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) + self.reset() + + try: + self.mainLoop() + except _ReparseException: + self.reset() + self.mainLoop() + + def reset(self): + self.tree.reset() + self.firstStartTag = False + self.errors = [] + self.log = [] # only used with debug mode + # "quirks" / "limited quirks" / "no quirks" + self.compatMode = "no quirks" + + if self.innerHTMLMode: + self.innerHTML = self.container.lower() + + if self.innerHTML in cdataElements: + self.tokenizer.state = self.tokenizer.rcdataState + elif self.innerHTML in rcdataElements: + self.tokenizer.state = self.tokenizer.rawtextState + elif self.innerHTML == 'plaintext': + self.tokenizer.state = self.tokenizer.plaintextState + else: + # state already is data state + # self.tokenizer.state = self.tokenizer.dataState + pass + self.phase = self.phases["beforeHtml"] + self.phase.insertHtmlElement() + self.resetInsertionMode() + else: + self.innerHTML = False # pylint:disable=redefined-variable-type + self.phase = self.phases["initial"] + + self.lastPhase = None + + self.beforeRCDataPhase = None + + self.framesetOK = True + + @property + def documentEncoding(self): + """Name of the character encoding that was used to decode the input stream, or + :obj:`None` if that is not determined yet + + """ + if not hasattr(self, 'tokenizer'): + return None + return self.tokenizer.stream.charEncoding[0].name + + def isHTMLIntegrationPoint(self, element): + if (element.name == "annotation-xml" and + element.namespace == namespaces["mathml"]): + return ("encoding" in element.attributes and + element.attributes["encoding"].translate( + asciiUpper2Lower) in + ("text/html", "application/xhtml+xml")) + else: + return (element.namespace, element.name) in htmlIntegrationPointElements + + def isMathMLTextIntegrationPoint(self, element): + return (element.namespace, element.name) in mathmlTextIntegrationPointElements + + def mainLoop(self): + CharactersToken = tokenTypes["Characters"] + SpaceCharactersToken = tokenTypes["SpaceCharacters"] + StartTagToken = tokenTypes["StartTag"] + EndTagToken = tokenTypes["EndTag"] + CommentToken = tokenTypes["Comment"] + DoctypeToken = tokenTypes["Doctype"] + ParseErrorToken = tokenTypes["ParseError"] + + for token in self.normalizedTokens(): + prev_token = None + new_token = token + while new_token is not None: + prev_token = new_token + currentNode = self.tree.openElements[-1] if self.tree.openElements else None + currentNodeNamespace = currentNode.namespace if currentNode else None + currentNodeName = currentNode.name if currentNode else None + + type = new_token["type"] + + if type == ParseErrorToken: + self.parseError(new_token["data"], new_token.get("datavars", {})) + new_token = None + else: + if (len(self.tree.openElements) == 0 or + currentNodeNamespace == self.tree.defaultNamespace or + (self.isMathMLTextIntegrationPoint(currentNode) and + ((type == StartTagToken and + token["name"] not in frozenset(["mglyph", "malignmark"])) or + type in (CharactersToken, SpaceCharactersToken))) or + (currentNodeNamespace == namespaces["mathml"] and + currentNodeName == "annotation-xml" and + type == StartTagToken and + token["name"] == "svg") or + (self.isHTMLIntegrationPoint(currentNode) and + type in (StartTagToken, CharactersToken, SpaceCharactersToken))): + phase = self.phase + else: + phase = self.phases["inForeignContent"] + + if type == CharactersToken: + new_token = phase.processCharacters(new_token) + elif type == SpaceCharactersToken: + new_token = phase.processSpaceCharacters(new_token) + elif type == StartTagToken: + new_token = phase.processStartTag(new_token) + elif type == EndTagToken: + new_token = phase.processEndTag(new_token) + elif type == CommentToken: + new_token = phase.processComment(new_token) + elif type == DoctypeToken: + new_token = phase.processDoctype(new_token) + + if (type == StartTagToken and prev_token["selfClosing"] and + not prev_token["selfClosingAcknowledged"]): + self.parseError("non-void-element-with-trailing-solidus", + {"name": prev_token["name"]}) + + # When the loop finishes it's EOF + reprocess = True + phases = [] + while reprocess: + phases.append(self.phase) + reprocess = self.phase.processEOF() + if reprocess: + assert self.phase not in phases + + def normalizedTokens(self): + for token in self.tokenizer: + yield self.normalizeToken(token) + + def parse(self, stream, *args, **kwargs): + """Parse a HTML document into a well-formed tree + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element). + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parse('<html><body><p>This is a doc</p></body></html>') + <Element u'{http://www.w3.org/1999/xhtml}html' at 0x7feac4909db0> + + """ + self._parse(stream, False, None, *args, **kwargs) + return self.tree.getDocument() + + def parseFragment(self, stream, *args, **kwargs): + """Parse a HTML fragment into a well-formed tree fragment + + :arg container: name of the element we're setting the innerHTML + property if set to None, default to 'div' + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parseFragment('<b>this is a fragment</b>') + <Element u'DOCUMENT_FRAGMENT' at 0x7feac484b090> + + """ + self._parse(stream, True, *args, **kwargs) + return self.tree.getFragment() + + def parseError(self, errorcode="XXX-undefined-error", datavars=None): + # XXX The idea is to make errorcode mandatory. + if datavars is None: + datavars = {} + self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) + if self.strict: + raise ParseError(E[errorcode] % datavars) + + def normalizeToken(self, token): + # HTML5 specific normalizations to the token stream + if token["type"] == tokenTypes["StartTag"]: + raw = token["data"] + token["data"] = OrderedDict(raw) + if len(raw) > len(token["data"]): + # we had some duplicated attribute, fix so first wins + token["data"].update(raw[::-1]) + + return token + + def adjustMathMLAttributes(self, token): + adjust_attributes(token, adjustMathMLAttributes) + + def adjustSVGAttributes(self, token): + adjust_attributes(token, adjustSVGAttributes) + + def adjustForeignAttributes(self, token): + adjust_attributes(token, adjustForeignAttributesMap) + + def reparseTokenNormal(self, token): + # pylint:disable=unused-argument + self.parser.phase() + + def resetInsertionMode(self): + # The name of this method is mostly historical. (It's also used in the + # specification.) + last = False + newModes = { + "select": "inSelect", + "td": "inCell", + "th": "inCell", + "tr": "inRow", + "tbody": "inTableBody", + "thead": "inTableBody", + "tfoot": "inTableBody", + "caption": "inCaption", + "colgroup": "inColumnGroup", + "table": "inTable", + "head": "inBody", + "body": "inBody", + "frameset": "inFrameset", + "html": "beforeHead" + } + for node in self.tree.openElements[::-1]: + nodeName = node.name + new_phase = None + if node == self.tree.openElements[0]: + assert self.innerHTML + last = True + nodeName = self.innerHTML + # Check for conditions that should only happen in the innerHTML + # case + if nodeName in ("select", "colgroup", "head", "html"): + assert self.innerHTML + + if not last and node.namespace != self.tree.defaultNamespace: + continue + + if nodeName in newModes: + new_phase = self.phases[newModes[nodeName]] + break + elif last: + new_phase = self.phases["inBody"] + break + + self.phase = new_phase + + def parseRCDataRawtext(self, token, contentType): + # Generic RCDATA/RAWTEXT Parsing algorithm + assert contentType in ("RAWTEXT", "RCDATA") + + self.tree.insertElement(token) + + if contentType == "RAWTEXT": + self.tokenizer.state = self.tokenizer.rawtextState + else: + self.tokenizer.state = self.tokenizer.rcdataState + + self.originalPhase = self.phase + + self.phase = self.phases["text"] + + +@_utils.memoize +def getPhases(debug): + def log(function): + """Logger that records which phase processes each token""" + type_names = dict((value, key) for key, value in + tokenTypes.items()) + + def wrapped(self, *args, **kwargs): + if function.__name__.startswith("process") and len(args) > 0: + token = args[0] + try: + info = {"type": type_names[token['type']]} + except: + raise + if token['type'] in tagTokenTypes: + info["name"] = token['name'] + + self.parser.log.append((self.parser.tokenizer.state.__name__, + self.parser.phase.__class__.__name__, + self.__class__.__name__, + function.__name__, + info)) + return function(self, *args, **kwargs) + else: + return function(self, *args, **kwargs) + return wrapped + + def getMetaclass(use_metaclass, metaclass_func): + if use_metaclass: + return method_decorator_metaclass(metaclass_func) + else: + return type + + # pylint:disable=unused-argument + class Phase(with_metaclass(getMetaclass(debug, log))): + """Base class for helper object that implements each phase of processing + """ + + def __init__(self, parser, tree): + self.parser = parser + self.tree = tree + + def processEOF(self): + raise NotImplementedError + + def processComment(self, token): + # For most phases the following is correct. Where it's not it will be + # overridden. + self.tree.insertComment(token, self.tree.openElements[-1]) + + def processDoctype(self, token): + self.parser.parseError("unexpected-doctype") + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processSpaceCharacters(self, token): + self.tree.insertText(token["data"]) + + def processStartTag(self, token): + return self.startTagHandler[token["name"]](token) + + def startTagHtml(self, token): + if not self.parser.firstStartTag and token["name"] == "html": + self.parser.parseError("non-html-root") + # XXX Need a check here to see if the first start tag token emitted is + # this token... If it's not, invoke self.parser.parseError(). + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[0].attributes: + self.tree.openElements[0].attributes[attr] = value + self.parser.firstStartTag = False + + def processEndTag(self, token): + return self.endTagHandler[token["name"]](token) + + class InitialPhase(Phase): + def processSpaceCharacters(self, token): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + correct = token["correct"] + + if (name != "html" or publicId is not None or + systemId is not None and systemId != "about:legacy-compat"): + self.parser.parseError("unknown-doctype") + + if publicId is None: + publicId = "" + + self.tree.insertDoctype(token) + + if publicId != "": + publicId = publicId.translate(asciiUpper2Lower) + + if (not correct or token["name"] != "html" or + publicId.startswith( + ("+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//")) or + publicId in ("-//w3o//dtd w3 html strict 3.0//en//", + "-/w3c/dtd html 4.0 transitional/en", + "html") or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is None or + systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): + self.parser.compatMode = "quirks" + elif (publicId.startswith( + ("-//w3c//dtd xhtml 1.0 frameset//", + "-//w3c//dtd xhtml 1.0 transitional//")) or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is not None): + self.parser.compatMode = "limited quirks" + + self.parser.phase = self.parser.phases["beforeHtml"] + + def anythingElse(self): + self.parser.compatMode = "quirks" + self.parser.phase = self.parser.phases["beforeHtml"] + + def processCharacters(self, token): + self.parser.parseError("expected-doctype-but-got-chars") + self.anythingElse() + return token + + def processStartTag(self, token): + self.parser.parseError("expected-doctype-but-got-start-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEndTag(self, token): + self.parser.parseError("expected-doctype-but-got-end-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEOF(self): + self.parser.parseError("expected-doctype-but-got-eof") + self.anythingElse() + return True + + class BeforeHtmlPhase(Phase): + # helper methods + def insertHtmlElement(self): + self.tree.insertRoot(impliedTagToken("html", "StartTag")) + self.parser.phase = self.parser.phases["beforeHead"] + + # other + def processEOF(self): + self.insertHtmlElement() + return True + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.insertHtmlElement() + return token + + def processStartTag(self, token): + if token["name"] == "html": + self.parser.firstStartTag = True + self.insertHtmlElement() + return token + + def processEndTag(self, token): + if token["name"] not in ("head", "body", "html", "br"): + self.parser.parseError("unexpected-end-tag-before-html", + {"name": token["name"]}) + else: + self.insertHtmlElement() + return token + + class BeforeHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("head", "body", "html", "br"), self.endTagImplyHead) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.startTagHead(impliedTagToken("head", "StartTag")) + return True + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.tree.insertElement(token) + self.tree.headPointer = self.tree.openElements[-1] + self.parser.phase = self.parser.phases["inHead"] + + def startTagOther(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagImplyHead(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagOther(self, token): + self.parser.parseError("end-tag-after-implied-root", + {"name": token["name"]}) + + class InHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("title", self.startTagTitle), + (("noframes", "style"), self.startTagNoFramesStyle), + ("noscript", self.startTagNoscript), + ("script", self.startTagScript), + (("base", "basefont", "bgsound", "command", "link"), + self.startTagBaseLinkCommand), + ("meta", self.startTagMeta), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("head", self.endTagHead), + (("br", "html", "body"), self.endTagHtmlBodyBr) + ]) + self.endTagHandler.default = self.endTagOther + + # the real thing + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.parser.parseError("two-heads-are-not-better-than-one") + + def startTagBaseLinkCommand(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMeta(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + attributes = token["data"] + if self.parser.tokenizer.stream.charEncoding[1] == "tentative": + if "charset" in attributes: + self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) + elif ("content" in attributes and + "http-equiv" in attributes and + attributes["http-equiv"].lower() == "content-type"): + # Encoding it as UTF-8 here is a hack, as really we should pass + # the abstract Unicode string, and just use the + # ContentAttrParser on that, but using UTF-8 allows all chars + # to be encoded and as a ASCII-superset works. + data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) + parser = _inputstream.ContentAttrParser(data) + codec = parser.parse() + self.parser.tokenizer.stream.changeEncoding(codec) + + def startTagTitle(self, token): + self.parser.parseRCDataRawtext(token, "RCDATA") + + def startTagNoFramesStyle(self, token): + # Need to decide whether to implement the scripting-disabled case + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagNoscript(self, token): + if self.parser.scripting: + self.parser.parseRCDataRawtext(token, "RAWTEXT") + else: + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inHeadNoscript"] + + def startTagScript(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState + self.parser.originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["text"] + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHead(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "head", "Expected head got %s" % node.name + self.parser.phase = self.parser.phases["afterHead"] + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.endTagHead(impliedTagToken("head")) + + class InHeadNoscriptPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("basefont", "bgsound", "link", "meta", "noframes", "style"), self.startTagBaseLinkCommand), + (("head", "noscript"), self.startTagHeadNoscript), + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("noscript", self.endTagNoscript), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.parser.parseError("eof-in-head-noscript") + self.anythingElse() + return True + + def processComment(self, token): + return self.parser.phases["inHead"].processComment(token) + + def processCharacters(self, token): + self.parser.parseError("char-in-head-noscript") + self.anythingElse() + return token + + def processSpaceCharacters(self, token): + return self.parser.phases["inHead"].processSpaceCharacters(token) + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBaseLinkCommand(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagHeadNoscript(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagNoscript(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "noscript", "Expected noscript got %s" % node.name + self.parser.phase = self.parser.phases["inHead"] + + def endTagBr(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + # Caller must raise parse error first! + self.endTagNoscript(impliedTagToken("noscript")) + + class AfterHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", + "style", "title"), + self.startTagFromHead), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + self.endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), + self.endTagHtmlBodyBr)]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBody(self, token): + self.parser.framesetOK = False + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inBody"] + + def startTagFrameset(self, token): + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagFromHead(self, token): + self.parser.parseError("unexpected-start-tag-out-of-my-head", + {"name": token["name"]}) + self.tree.openElements.append(self.tree.headPointer) + self.parser.phases["inHead"].processStartTag(token) + for node in self.tree.openElements[::-1]: + if node.name == "head": + self.tree.openElements.remove(node) + break + + def startTagHead(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.tree.insertElement(impliedTagToken("body", "StartTag")) + self.parser.phase = self.parser.phases["inBody"] + self.parser.framesetOK = True + + class InBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody + # the really-really-really-very crazy mode + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + # Set this to the default handler + self.processSpaceCharacters = self.processSpaceCharactersNonPre + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("base", "basefont", "bgsound", "command", "link", "meta", + "script", "style", "title"), + self.startTagProcessInHead), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("address", "article", "aside", "blockquote", "center", "details", + "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p", + "section", "summary", "ul"), + self.startTagCloseP), + (headingElements, self.startTagHeading), + (("pre", "listing"), self.startTagPreListing), + ("form", self.startTagForm), + (("li", "dd", "dt"), self.startTagListItem), + ("plaintext", self.startTagPlaintext), + ("a", self.startTagA), + (("b", "big", "code", "em", "font", "i", "s", "small", "strike", + "strong", "tt", "u"), self.startTagFormatting), + ("nobr", self.startTagNobr), + ("button", self.startTagButton), + (("applet", "marquee", "object"), self.startTagAppletMarqueeObject), + ("xmp", self.startTagXmp), + ("table", self.startTagTable), + (("area", "br", "embed", "img", "keygen", "wbr"), + self.startTagVoidFormatting), + (("param", "source", "track"), self.startTagParamSource), + ("input", self.startTagInput), + ("hr", self.startTagHr), + ("image", self.startTagImage), + ("isindex", self.startTagIsIndex), + ("textarea", self.startTagTextarea), + ("iframe", self.startTagIFrame), + ("noscript", self.startTagNoscript), + (("noembed", "noframes"), self.startTagRawtext), + ("select", self.startTagSelect), + (("rp", "rt"), self.startTagRpRt), + (("option", "optgroup"), self.startTagOpt), + (("math"), self.startTagMath), + (("svg"), self.startTagSvg), + (("caption", "col", "colgroup", "frame", "head", + "tbody", "td", "tfoot", "th", "thead", + "tr"), self.startTagMisplaced) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("body", self.endTagBody), + ("html", self.endTagHtml), + (("address", "article", "aside", "blockquote", "button", "center", + "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre", + "section", "summary", "ul"), self.endTagBlock), + ("form", self.endTagForm), + ("p", self.endTagP), + (("dd", "dt", "li"), self.endTagListItem), + (headingElements, self.endTagHeading), + (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", + "strike", "strong", "tt", "u"), self.endTagFormatting), + (("applet", "marquee", "object"), self.endTagAppletMarqueeObject), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def isMatchingFormattingElement(self, node1, node2): + return (node1.name == node2.name and + node1.namespace == node2.namespace and + node1.attributes == node2.attributes) + + # helper + def addFormattingElement(self, token): + self.tree.insertElement(token) + element = self.tree.openElements[-1] + + matchingElements = [] + for node in self.tree.activeFormattingElements[::-1]: + if node is Marker: + break + elif self.isMatchingFormattingElement(node, element): + matchingElements.append(node) + + assert len(matchingElements) <= 3 + if len(matchingElements) == 3: + self.tree.activeFormattingElements.remove(matchingElements[-1]) + self.tree.activeFormattingElements.append(element) + + # the real deal + def processEOF(self): + allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", + "tfoot", "th", "thead", "tr", "body", + "html")) + for node in self.tree.openElements[::-1]: + if node.name not in allowed_elements: + self.parser.parseError("expected-closing-tag-but-got-eof") + break + # Stop parsing + + def processSpaceCharactersDropNewline(self, token): + # Sometimes (start of <pre>, <listing>, and <textarea> blocks) we + # want to drop leading newlines + data = token["data"] + self.processSpaceCharacters = self.processSpaceCharactersNonPre + if (data.startswith("\n") and + self.tree.openElements[-1].name in ("pre", "listing", "textarea") and + not self.tree.openElements[-1].hasContent()): + data = data[1:] + if data: + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(data) + + def processCharacters(self, token): + if token["data"] == "\u0000": + # The tokenizer should always emit null on its own + return + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(token["data"]) + # This must be bad for performance + if (self.parser.framesetOK and + any([char not in spaceCharacters + for char in token["data"]])): + self.parser.framesetOK = False + + def processSpaceCharactersNonPre(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(token["data"]) + + def startTagProcessInHead(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagBody(self, token): + self.parser.parseError("unexpected-start-tag", {"name": "body"}) + if (len(self.tree.openElements) == 1 or + self.tree.openElements[1].name != "body"): + assert self.parser.innerHTML + else: + self.parser.framesetOK = False + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[1].attributes: + self.tree.openElements[1].attributes[attr] = value + + def startTagFrameset(self, token): + self.parser.parseError("unexpected-start-tag", {"name": "frameset"}) + if (len(self.tree.openElements) == 1 or self.tree.openElements[1].name != "body"): + assert self.parser.innerHTML + elif not self.parser.framesetOK: + pass + else: + if self.tree.openElements[1].parent: + self.tree.openElements[1].parent.removeChild(self.tree.openElements[1]) + while self.tree.openElements[-1].name != "html": + self.tree.openElements.pop() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagCloseP(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + + def startTagPreListing(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.framesetOK = False + self.processSpaceCharacters = self.processSpaceCharactersDropNewline + + def startTagForm(self, token): + if self.tree.formPointer: + self.parser.parseError("unexpected-start-tag", {"name": "form"}) + else: + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.tree.formPointer = self.tree.openElements[-1] + + def startTagListItem(self, token): + self.parser.framesetOK = False + + stopNamesMap = {"li": ["li"], + "dt": ["dt", "dd"], + "dd": ["dt", "dd"]} + stopNames = stopNamesMap[token["name"]] + for node in reversed(self.tree.openElements): + if node.name in stopNames: + self.parser.phase.processEndTag( + impliedTagToken(node.name, "EndTag")) + break + if (node.nameTuple in specialElements and + node.name not in ("address", "div", "p")): + break + + if self.tree.elementInScope("p", variant="button"): + self.parser.phase.processEndTag( + impliedTagToken("p", "EndTag")) + + self.tree.insertElement(token) + + def startTagPlaintext(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.plaintextState + + def startTagHeading(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + if self.tree.openElements[-1].name in headingElements: + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagA(self, token): + afeAElement = self.tree.elementInActiveFormattingElements("a") + if afeAElement: + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "a", "endName": "a"}) + self.endTagFormatting(impliedTagToken("a")) + if afeAElement in self.tree.openElements: + self.tree.openElements.remove(afeAElement) + if afeAElement in self.tree.activeFormattingElements: + self.tree.activeFormattingElements.remove(afeAElement) + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagFormatting(self, token): + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagNobr(self, token): + self.tree.reconstructActiveFormattingElements() + if self.tree.elementInScope("nobr"): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "nobr", "endName": "nobr"}) + self.processEndTag(impliedTagToken("nobr")) + # XXX Need tests that trigger the following + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagButton(self, token): + if self.tree.elementInScope("button"): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "button", "endName": "button"}) + self.processEndTag(impliedTagToken("button")) + return token + else: + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.parser.framesetOK = False + + def startTagAppletMarqueeObject(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.tree.activeFormattingElements.append(Marker) + self.parser.framesetOK = False + + def startTagXmp(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.reconstructActiveFormattingElements() + self.parser.framesetOK = False + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagTable(self, token): + if self.parser.compatMode != "quirks": + if self.tree.elementInScope("p", variant="button"): + self.processEndTag(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.framesetOK = False + self.parser.phase = self.parser.phases["inTable"] + + def startTagVoidFormatting(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + self.parser.framesetOK = False + + def startTagInput(self, token): + framesetOK = self.parser.framesetOK + self.startTagVoidFormatting(token) + if ("type" in token["data"] and + token["data"]["type"].translate(asciiUpper2Lower) == "hidden"): + # input type=hidden doesn't change framesetOK + self.parser.framesetOK = framesetOK + + def startTagParamSource(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagHr(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + self.parser.framesetOK = False + + def startTagImage(self, token): + # No really... + self.parser.parseError("unexpected-start-tag-treated-as", + {"originalName": "image", "newName": "img"}) + self.processStartTag(impliedTagToken("img", "StartTag", + attributes=token["data"], + selfClosing=token["selfClosing"])) + + def startTagIsIndex(self, token): + self.parser.parseError("deprecated-tag", {"name": "isindex"}) + if self.tree.formPointer: + return + form_attrs = {} + if "action" in token["data"]: + form_attrs["action"] = token["data"]["action"] + self.processStartTag(impliedTagToken("form", "StartTag", + attributes=form_attrs)) + self.processStartTag(impliedTagToken("hr", "StartTag")) + self.processStartTag(impliedTagToken("label", "StartTag")) + # XXX Localization ... + if "prompt" in token["data"]: + prompt = token["data"]["prompt"] + else: + prompt = "This is a searchable index. Enter search keywords: " + self.processCharacters( + {"type": tokenTypes["Characters"], "data": prompt}) + attributes = token["data"].copy() + if "action" in attributes: + del attributes["action"] + if "prompt" in attributes: + del attributes["prompt"] + attributes["name"] = "isindex" + self.processStartTag(impliedTagToken("input", "StartTag", + attributes=attributes, + selfClosing=token["selfClosing"])) + self.processEndTag(impliedTagToken("label")) + self.processStartTag(impliedTagToken("hr", "StartTag")) + self.processEndTag(impliedTagToken("form")) + + def startTagTextarea(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.rcdataState + self.processSpaceCharacters = self.processSpaceCharactersDropNewline + self.parser.framesetOK = False + + def startTagIFrame(self, token): + self.parser.framesetOK = False + self.startTagRawtext(token) + + def startTagNoscript(self, token): + if self.parser.scripting: + self.startTagRawtext(token) + else: + self.startTagOther(token) + + def startTagRawtext(self, token): + """iframe, noembed noframes, noscript(if scripting enabled)""" + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagOpt(self, token): + if self.tree.openElements[-1].name == "option": + self.parser.phase.processEndTag(impliedTagToken("option")) + self.tree.reconstructActiveFormattingElements() + self.parser.tree.insertElement(token) + + def startTagSelect(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.parser.framesetOK = False + if self.parser.phase in (self.parser.phases["inTable"], + self.parser.phases["inCaption"], + self.parser.phases["inColumnGroup"], + self.parser.phases["inTableBody"], + self.parser.phases["inRow"], + self.parser.phases["inCell"]): + self.parser.phase = self.parser.phases["inSelectInTable"] + else: + self.parser.phase = self.parser.phases["inSelect"] + + def startTagRpRt(self, token): + if self.tree.elementInScope("ruby"): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "ruby": + self.parser.parseError() + self.tree.insertElement(token) + + def startTagMath(self, token): + self.tree.reconstructActiveFormattingElements() + self.parser.adjustMathMLAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = namespaces["mathml"] + self.tree.insertElement(token) + # Need to get the parse error right for the case where the token + # has a namespace not equal to the xmlns attribute + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagSvg(self, token): + self.tree.reconstructActiveFormattingElements() + self.parser.adjustSVGAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = namespaces["svg"] + self.tree.insertElement(token) + # Need to get the parse error right for the case where the token + # has a namespace not equal to the xmlns attribute + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMisplaced(self, token): + """ Elements that should be children of other elements that have a + different insertion mode; here they are ignored + "caption", "col", "colgroup", "frame", "frameset", "head", + "option", "optgroup", "tbody", "td", "tfoot", "th", "thead", + "tr", "noscript" + """ + self.parser.parseError("unexpected-start-tag-ignored", {"name": token["name"]}) + + def startTagOther(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + + def endTagP(self, token): + if not self.tree.elementInScope("p", variant="button"): + self.startTagCloseP(impliedTagToken("p", "StartTag")) + self.parser.parseError("unexpected-end-tag", {"name": "p"}) + self.endTagP(impliedTagToken("p", "EndTag")) + else: + self.tree.generateImpliedEndTags("p") + if self.tree.openElements[-1].name != "p": + self.parser.parseError("unexpected-end-tag", {"name": "p"}) + node = self.tree.openElements.pop() + while node.name != "p": + node = self.tree.openElements.pop() + + def endTagBody(self, token): + if not self.tree.elementInScope("body"): + self.parser.parseError() + return + elif self.tree.openElements[-1].name != "body": + for node in self.tree.openElements[2:]: + if node.name not in frozenset(("dd", "dt", "li", "optgroup", + "option", "p", "rp", "rt", + "tbody", "td", "tfoot", + "th", "thead", "tr", "body", + "html")): + # Not sure this is the correct name for the parse error + self.parser.parseError( + "expected-one-end-tag-but-got-another", + {"gotName": "body", "expectedName": node.name}) + break + self.parser.phase = self.parser.phases["afterBody"] + + def endTagHtml(self, token): + # We repeat the test for the body end tag token being ignored here + if self.tree.elementInScope("body"): + self.endTagBody(impliedTagToken("body")) + return token + + def endTagBlock(self, token): + # Put us back in the right whitespace handling mode + if token["name"] == "pre": + self.processSpaceCharacters = self.processSpaceCharactersNonPre + inScope = self.tree.elementInScope(token["name"]) + if inScope: + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + if inScope: + node = self.tree.openElements.pop() + while node.name != token["name"]: + node = self.tree.openElements.pop() + + def endTagForm(self, token): + node = self.tree.formPointer + self.tree.formPointer = None + if node is None or not self.tree.elementInScope(node): + self.parser.parseError("unexpected-end-tag", + {"name": "form"}) + else: + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1] != node: + self.parser.parseError("end-tag-too-early-ignored", + {"name": "form"}) + self.tree.openElements.remove(node) + + def endTagListItem(self, token): + if token["name"] == "li": + variant = "list" + else: + variant = None + if not self.tree.elementInScope(token["name"], variant=variant): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + else: + self.tree.generateImpliedEndTags(exclude=token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError( + "end-tag-too-early", + {"name": token["name"]}) + node = self.tree.openElements.pop() + while node.name != token["name"]: + node = self.tree.openElements.pop() + + def endTagHeading(self, token): + for item in headingElements: + if self.tree.elementInScope(item): + self.tree.generateImpliedEndTags() + break + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + + for item in headingElements: + if self.tree.elementInScope(item): + item = self.tree.openElements.pop() + while item.name not in headingElements: + item = self.tree.openElements.pop() + break + + def endTagFormatting(self, token): + """The much-feared adoption agency algorithm""" + # http://svn.whatwg.org/webapps/complete.html#adoptionAgency revision 7867 + # XXX Better parseError messages appreciated. + + # Step 1 + outerLoopCounter = 0 + + # Step 2 + while outerLoopCounter < 8: + + # Step 3 + outerLoopCounter += 1 + + # Step 4: + + # Let the formatting element be the last element in + # the list of active formatting elements that: + # - is between the end of the list and the last scope + # marker in the list, if any, or the start of the list + # otherwise, and + # - has the same tag name as the token. + formattingElement = self.tree.elementInActiveFormattingElements( + token["name"]) + if (not formattingElement or + (formattingElement in self.tree.openElements and + not self.tree.elementInScope(formattingElement.name))): + # If there is no such node, then abort these steps + # and instead act as described in the "any other + # end tag" entry below. + self.endTagOther(token) + return + + # Otherwise, if there is such a node, but that node is + # not in the stack of open elements, then this is a + # parse error; remove the element from the list, and + # abort these steps. + elif formattingElement not in self.tree.openElements: + self.parser.parseError("adoption-agency-1.2", {"name": token["name"]}) + self.tree.activeFormattingElements.remove(formattingElement) + return + + # Otherwise, if there is such a node, and that node is + # also in the stack of open elements, but the element + # is not in scope, then this is a parse error; ignore + # the token, and abort these steps. + elif not self.tree.elementInScope(formattingElement.name): + self.parser.parseError("adoption-agency-4.4", {"name": token["name"]}) + return + + # Otherwise, there is a formatting element and that + # element is in the stack and is in scope. If the + # element is not the current node, this is a parse + # error. In any case, proceed with the algorithm as + # written in the following steps. + else: + if formattingElement != self.tree.openElements[-1]: + self.parser.parseError("adoption-agency-1.3", {"name": token["name"]}) + + # Step 5: + + # Let the furthest block be the topmost node in the + # stack of open elements that is lower in the stack + # than the formatting element, and is an element in + # the special category. There might not be one. + afeIndex = self.tree.openElements.index(formattingElement) + furthestBlock = None + for element in self.tree.openElements[afeIndex:]: + if element.nameTuple in specialElements: + furthestBlock = element + break + + # Step 6: + + # If there is no furthest block, then the UA must + # first pop all the nodes from the bottom of the stack + # of open elements, from the current node up to and + # including the formatting element, then remove the + # formatting element from the list of active + # formatting elements, and finally abort these steps. + if furthestBlock is None: + element = self.tree.openElements.pop() + while element != formattingElement: + element = self.tree.openElements.pop() + self.tree.activeFormattingElements.remove(element) + return + + # Step 7 + commonAncestor = self.tree.openElements[afeIndex - 1] + + # Step 8: + # The bookmark is supposed to help us identify where to reinsert + # nodes in step 15. We have to ensure that we reinsert nodes after + # the node before the active formatting element. Note the bookmark + # can move in step 9.7 + bookmark = self.tree.activeFormattingElements.index(formattingElement) + + # Step 9 + lastNode = node = furthestBlock + innerLoopCounter = 0 + + index = self.tree.openElements.index(node) + while innerLoopCounter < 3: + innerLoopCounter += 1 + # Node is element before node in open elements + index -= 1 + node = self.tree.openElements[index] + if node not in self.tree.activeFormattingElements: + self.tree.openElements.remove(node) + continue + # Step 9.6 + if node == formattingElement: + break + # Step 9.7 + if lastNode == furthestBlock: + bookmark = self.tree.activeFormattingElements.index(node) + 1 + # Step 9.8 + clone = node.cloneNode() + # Replace node with clone + self.tree.activeFormattingElements[ + self.tree.activeFormattingElements.index(node)] = clone + self.tree.openElements[ + self.tree.openElements.index(node)] = clone + node = clone + # Step 9.9 + # Remove lastNode from its parents, if any + if lastNode.parent: + lastNode.parent.removeChild(lastNode) + node.appendChild(lastNode) + # Step 9.10 + lastNode = node + + # Step 10 + # Foster parent lastNode if commonAncestor is a + # table, tbody, tfoot, thead, or tr we need to foster + # parent the lastNode + if lastNode.parent: + lastNode.parent.removeChild(lastNode) + + if commonAncestor.name in frozenset(("table", "tbody", "tfoot", "thead", "tr")): + parent, insertBefore = self.tree.getTableMisnestedNodePosition() + parent.insertBefore(lastNode, insertBefore) + else: + commonAncestor.appendChild(lastNode) + + # Step 11 + clone = formattingElement.cloneNode() + + # Step 12 + furthestBlock.reparentChildren(clone) + + # Step 13 + furthestBlock.appendChild(clone) + + # Step 14 + self.tree.activeFormattingElements.remove(formattingElement) + self.tree.activeFormattingElements.insert(bookmark, clone) + + # Step 15 + self.tree.openElements.remove(formattingElement) + self.tree.openElements.insert( + self.tree.openElements.index(furthestBlock) + 1, clone) + + def endTagAppletMarqueeObject(self, token): + if self.tree.elementInScope(token["name"]): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + + if self.tree.elementInScope(token["name"]): + element = self.tree.openElements.pop() + while element.name != token["name"]: + element = self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + + def endTagBr(self, token): + self.parser.parseError("unexpected-end-tag-treated-as", + {"originalName": "br", "newName": "br element"}) + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(impliedTagToken("br", "StartTag")) + self.tree.openElements.pop() + + def endTagOther(self, token): + for node in self.tree.openElements[::-1]: + if node.name == token["name"]: + self.tree.generateImpliedEndTags(exclude=token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + while self.tree.openElements.pop() != node: + pass + break + else: + if node.nameTuple in specialElements: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + break + + class TextPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([]) + self.startTagHandler.default = self.startTagOther + self.endTagHandler = _utils.MethodDispatcher([ + ("script", self.endTagScript)]) + self.endTagHandler.default = self.endTagOther + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processEOF(self): + self.parser.parseError("expected-named-closing-tag-but-got-eof", + {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + self.parser.phase = self.parser.originalPhase + return True + + def startTagOther(self, token): + assert False, "Tried to process start tag %s in RCDATA/RAWTEXT mode" % token['name'] + + def endTagScript(self, token): + node = self.tree.openElements.pop() + assert node.name == "script" + self.parser.phase = self.parser.originalPhase + # The rest of this method is all stuff that only happens if + # document.write works + + def endTagOther(self, token): + self.tree.openElements.pop() + self.parser.phase = self.parser.originalPhase + + class InTablePhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-table + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("caption", self.startTagCaption), + ("colgroup", self.startTagColgroup), + ("col", self.startTagCol), + (("tbody", "tfoot", "thead"), self.startTagRowGroup), + (("td", "th", "tr"), self.startTagImplyTbody), + ("table", self.startTagTable), + (("style", "script"), self.startTagStyleScript), + ("input", self.startTagInput), + ("form", self.startTagForm) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("table", self.endTagTable), + (("body", "caption", "col", "colgroup", "html", "tbody", "td", + "tfoot", "th", "thead", "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods + def clearStackToTableContext(self): + # "clear the stack back to a table context" + while self.tree.openElements[-1].name not in ("table", "html"): + # self.parser.parseError("unexpected-implied-end-tag-in-table", + # {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + # When the current node is <html> it's an innerHTML case + + # processing methods + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-table") + else: + assert self.parser.innerHTML + # Stop parsing + + def processSpaceCharacters(self, token): + originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["inTableText"] + self.parser.phase.originalPhase = originalPhase + self.parser.phase.processSpaceCharacters(token) + + def processCharacters(self, token): + originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["inTableText"] + self.parser.phase.originalPhase = originalPhase + self.parser.phase.processCharacters(token) + + def insertText(self, token): + # If we get here there must be at least one non-whitespace character + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processCharacters(token) + self.tree.insertFromTable = False + + def startTagCaption(self, token): + self.clearStackToTableContext() + self.tree.activeFormattingElements.append(Marker) + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inCaption"] + + def startTagColgroup(self, token): + self.clearStackToTableContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inColumnGroup"] + + def startTagCol(self, token): + self.startTagColgroup(impliedTagToken("colgroup", "StartTag")) + return token + + def startTagRowGroup(self, token): + self.clearStackToTableContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inTableBody"] + + def startTagImplyTbody(self, token): + self.startTagRowGroup(impliedTagToken("tbody", "StartTag")) + return token + + def startTagTable(self, token): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "table", "endName": "table"}) + self.parser.phase.processEndTag(impliedTagToken("table")) + if not self.parser.innerHTML: + return token + + def startTagStyleScript(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagInput(self, token): + if ("type" in token["data"] and + token["data"]["type"].translate(asciiUpper2Lower) == "hidden"): + self.parser.parseError("unexpected-hidden-input-in-table") + self.tree.insertElement(token) + # XXX associate with form + self.tree.openElements.pop() + else: + self.startTagOther(token) + + def startTagForm(self, token): + self.parser.parseError("unexpected-form-in-table") + if self.tree.formPointer is None: + self.tree.insertElement(token) + self.tree.formPointer = self.tree.openElements[-1] + self.tree.openElements.pop() + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-implies-table-voodoo", {"name": token["name"]}) + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processStartTag(token) + self.tree.insertFromTable = False + + def endTagTable(self, token): + if self.tree.elementInScope("table", variant="table"): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "table": + self.parser.parseError("end-tag-too-early-named", + {"gotName": "table", + "expectedName": self.tree.openElements[-1].name}) + while self.tree.openElements[-1].name != "table": + self.tree.openElements.pop() + self.tree.openElements.pop() + self.parser.resetInsertionMode() + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-implies-table-voodoo", {"name": token["name"]}) + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processEndTag(token) + self.tree.insertFromTable = False + + class InTableTextPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.originalPhase = None + self.characterTokens = [] + + def flushCharacters(self): + data = "".join([item["data"] for item in self.characterTokens]) + if any([item not in spaceCharacters for item in data]): + token = {"type": tokenTypes["Characters"], "data": data} + self.parser.phases["inTable"].insertText(token) + elif data: + self.tree.insertText(data) + self.characterTokens = [] + + def processComment(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + def processEOF(self): + self.flushCharacters() + self.parser.phase = self.originalPhase + return True + + def processCharacters(self, token): + if token["data"] == "\u0000": + return + self.characterTokens.append(token) + + def processSpaceCharacters(self, token): + # pretty sure we should never reach here + self.characterTokens.append(token) + # assert False + + def processStartTag(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + def processEndTag(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + class InCaptionPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-caption + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.startTagTableElement) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("caption", self.endTagCaption), + ("table", self.endTagTable), + (("body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + def ignoreEndTagCaption(self): + return not self.tree.elementInScope("caption", variant="table") + + def processEOF(self): + self.parser.phases["inBody"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inBody"].processCharacters(token) + + def startTagTableElement(self, token): + self.parser.parseError() + # XXX Have to duplicate logic here to find out if the tag is ignored + ignoreEndTag = self.ignoreEndTagCaption() + self.parser.phase.processEndTag(impliedTagToken("caption")) + if not ignoreEndTag: + return token + + def startTagOther(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def endTagCaption(self, token): + if not self.ignoreEndTagCaption(): + # AT this code is quite similar to endTagTable in "InTable" + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "caption": + self.parser.parseError("expected-one-end-tag-but-got-another", + {"gotName": "caption", + "expectedName": self.tree.openElements[-1].name}) + while self.tree.openElements[-1].name != "caption": + self.tree.openElements.pop() + self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + self.parser.phase = self.parser.phases["inTable"] + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagTable(self, token): + self.parser.parseError() + ignoreEndTag = self.ignoreEndTagCaption() + self.parser.phase.processEndTag(impliedTagToken("caption")) + if not ignoreEndTag: + return token + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inBody"].processEndTag(token) + + class InColumnGroupPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-column + + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("col", self.startTagCol) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("colgroup", self.endTagColgroup), + ("col", self.endTagCol) + ]) + self.endTagHandler.default = self.endTagOther + + def ignoreEndTagColgroup(self): + return self.tree.openElements[-1].name == "html" + + def processEOF(self): + if self.tree.openElements[-1].name == "html": + assert self.parser.innerHTML + return + else: + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return True + + def processCharacters(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + def startTagCol(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagOther(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + def endTagColgroup(self, token): + if self.ignoreEndTagColgroup(): + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + else: + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTable"] + + def endTagCol(self, token): + self.parser.parseError("no-end-tag", {"name": "col"}) + + def endTagOther(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + class InTableBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-table0 + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("tr", self.startTagTr), + (("td", "th"), self.startTagTableCell), + (("caption", "col", "colgroup", "tbody", "tfoot", "thead"), + self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("tbody", "tfoot", "thead"), self.endTagTableRowGroup), + ("table", self.endTagTable), + (("body", "caption", "col", "colgroup", "html", "td", "th", + "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods + def clearStackToTableBodyContext(self): + while self.tree.openElements[-1].name not in ("tbody", "tfoot", + "thead", "html"): + # self.parser.parseError("unexpected-implied-end-tag-in-table", + # {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + if self.tree.openElements[-1].name == "html": + assert self.parser.innerHTML + + # the rest + def processEOF(self): + self.parser.phases["inTable"].processEOF() + + def processSpaceCharacters(self, token): + return self.parser.phases["inTable"].processSpaceCharacters(token) + + def processCharacters(self, token): + return self.parser.phases["inTable"].processCharacters(token) + + def startTagTr(self, token): + self.clearStackToTableBodyContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inRow"] + + def startTagTableCell(self, token): + self.parser.parseError("unexpected-cell-in-table-body", + {"name": token["name"]}) + self.startTagTr(impliedTagToken("tr", "StartTag")) + return token + + def startTagTableOther(self, token): + # XXX AT Any ideas on how to share this with endTagTable? + if (self.tree.elementInScope("tbody", variant="table") or + self.tree.elementInScope("thead", variant="table") or + self.tree.elementInScope("tfoot", variant="table")): + self.clearStackToTableBodyContext() + self.endTagTableRowGroup( + impliedTagToken(self.tree.openElements[-1].name)) + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def startTagOther(self, token): + return self.parser.phases["inTable"].processStartTag(token) + + def endTagTableRowGroup(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.clearStackToTableBodyContext() + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTable"] + else: + self.parser.parseError("unexpected-end-tag-in-table-body", + {"name": token["name"]}) + + def endTagTable(self, token): + if (self.tree.elementInScope("tbody", variant="table") or + self.tree.elementInScope("thead", variant="table") or + self.tree.elementInScope("tfoot", variant="table")): + self.clearStackToTableBodyContext() + self.endTagTableRowGroup( + impliedTagToken(self.tree.openElements[-1].name)) + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag-in-table-body", + {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inTable"].processEndTag(token) + + class InRowPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-row + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("td", "th"), self.startTagTableCell), + (("caption", "col", "colgroup", "tbody", "tfoot", "thead", + "tr"), self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("tr", self.endTagTr), + ("table", self.endTagTable), + (("tbody", "tfoot", "thead"), self.endTagTableRowGroup), + (("body", "caption", "col", "colgroup", "html", "td", "th"), + self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods (XXX unify this with other table helper methods) + def clearStackToTableRowContext(self): + while self.tree.openElements[-1].name not in ("tr", "html"): + self.parser.parseError("unexpected-implied-end-tag-in-table-row", + {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + + def ignoreEndTagTr(self): + return not self.tree.elementInScope("tr", variant="table") + + # the rest + def processEOF(self): + self.parser.phases["inTable"].processEOF() + + def processSpaceCharacters(self, token): + return self.parser.phases["inTable"].processSpaceCharacters(token) + + def processCharacters(self, token): + return self.parser.phases["inTable"].processCharacters(token) + + def startTagTableCell(self, token): + self.clearStackToTableRowContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inCell"] + self.tree.activeFormattingElements.append(Marker) + + def startTagTableOther(self, token): + ignoreEndTag = self.ignoreEndTagTr() + self.endTagTr(impliedTagToken("tr")) + # XXX how are we sure it's always ignored in the innerHTML case? + if not ignoreEndTag: + return token + + def startTagOther(self, token): + return self.parser.phases["inTable"].processStartTag(token) + + def endTagTr(self, token): + if not self.ignoreEndTagTr(): + self.clearStackToTableRowContext() + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTableBody"] + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagTable(self, token): + ignoreEndTag = self.ignoreEndTagTr() + self.endTagTr(impliedTagToken("tr")) + # Reprocess the current tag if the tr end tag was not ignored + # XXX how are we sure it's always ignored in the innerHTML case? + if not ignoreEndTag: + return token + + def endTagTableRowGroup(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.endTagTr(impliedTagToken("tr")) + return token + else: + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag-in-table-row", + {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inTable"].processEndTag(token) + + class InCellPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-cell + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("td", "th"), self.endTagTableCell), + (("body", "caption", "col", "colgroup", "html"), self.endTagIgnore), + (("table", "tbody", "tfoot", "thead", "tr"), self.endTagImply) + ]) + self.endTagHandler.default = self.endTagOther + + # helper + def closeCell(self): + if self.tree.elementInScope("td", variant="table"): + self.endTagTableCell(impliedTagToken("td")) + elif self.tree.elementInScope("th", variant="table"): + self.endTagTableCell(impliedTagToken("th")) + + # the rest + def processEOF(self): + self.parser.phases["inBody"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inBody"].processCharacters(token) + + def startTagTableOther(self, token): + if (self.tree.elementInScope("td", variant="table") or + self.tree.elementInScope("th", variant="table")): + self.closeCell() + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def startTagOther(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def endTagTableCell(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.tree.generateImpliedEndTags(token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("unexpected-cell-end-tag", + {"name": token["name"]}) + while True: + node = self.tree.openElements.pop() + if node.name == token["name"]: + break + else: + self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + self.parser.phase = self.parser.phases["inRow"] + else: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagImply(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.closeCell() + return token + else: + # sometimes innerHTML case + self.parser.parseError() + + def endTagOther(self, token): + return self.parser.phases["inBody"].processEndTag(token) + + class InSelectPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("option", self.startTagOption), + ("optgroup", self.startTagOptgroup), + ("select", self.startTagSelect), + (("input", "keygen", "textarea"), self.startTagInput), + ("script", self.startTagScript) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("option", self.endTagOption), + ("optgroup", self.endTagOptgroup), + ("select", self.endTagSelect) + ]) + self.endTagHandler.default = self.endTagOther + + # http://www.whatwg.org/specs/web-apps/current-work/#in-select + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-select") + else: + assert self.parser.innerHTML + + def processCharacters(self, token): + if token["data"] == "\u0000": + return + self.tree.insertText(token["data"]) + + def startTagOption(self, token): + # We need to imply </option> if <option> is the current node. + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagOptgroup(self, token): + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + if self.tree.openElements[-1].name == "optgroup": + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagSelect(self, token): + self.parser.parseError("unexpected-select-in-select") + self.endTagSelect(impliedTagToken("select")) + + def startTagInput(self, token): + self.parser.parseError("unexpected-input-in-select") + if self.tree.elementInScope("select", variant="select"): + self.endTagSelect(impliedTagToken("select")) + return token + else: + assert self.parser.innerHTML + + def startTagScript(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-in-select", + {"name": token["name"]}) + + def endTagOption(self, token): + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + else: + self.parser.parseError("unexpected-end-tag-in-select", + {"name": "option"}) + + def endTagOptgroup(self, token): + # </optgroup> implicitly closes <option> + if (self.tree.openElements[-1].name == "option" and + self.tree.openElements[-2].name == "optgroup"): + self.tree.openElements.pop() + # It also closes </optgroup> + if self.tree.openElements[-1].name == "optgroup": + self.tree.openElements.pop() + # But nothing else + else: + self.parser.parseError("unexpected-end-tag-in-select", + {"name": "optgroup"}) + + def endTagSelect(self, token): + if self.tree.elementInScope("select", variant="select"): + node = self.tree.openElements.pop() + while node.name != "select": + node = self.tree.openElements.pop() + self.parser.resetInsertionMode() + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-in-select", + {"name": token["name"]}) + + class InSelectInTablePhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"), + self.startTagTable) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"), + self.endTagTable) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.parser.phases["inSelect"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inSelect"].processCharacters(token) + + def startTagTable(self, token): + self.parser.parseError("unexpected-table-element-start-tag-in-select-in-table", {"name": token["name"]}) + self.endTagOther(impliedTagToken("select")) + return token + + def startTagOther(self, token): + return self.parser.phases["inSelect"].processStartTag(token) + + def endTagTable(self, token): + self.parser.parseError("unexpected-table-element-end-tag-in-select-in-table", {"name": token["name"]}) + if self.tree.elementInScope(token["name"], variant="table"): + self.endTagOther(impliedTagToken("select")) + return token + + def endTagOther(self, token): + return self.parser.phases["inSelect"].processEndTag(token) + + class InForeignContentPhase(Phase): + breakoutElements = frozenset(["b", "big", "blockquote", "body", "br", + "center", "code", "dd", "div", "dl", "dt", + "em", "embed", "h1", "h2", "h3", + "h4", "h5", "h6", "head", "hr", "i", "img", + "li", "listing", "menu", "meta", "nobr", + "ol", "p", "pre", "ruby", "s", "small", + "span", "strong", "strike", "sub", "sup", + "table", "tt", "u", "ul", "var"]) + + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + def adjustSVGTagNames(self, token): + replacements = {"altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath"} + + if token["name"] in replacements: + token["name"] = replacements[token["name"]] + + def processCharacters(self, token): + if token["data"] == "\u0000": + token["data"] = "\uFFFD" + elif (self.parser.framesetOK and + any(char not in spaceCharacters for char in token["data"])): + self.parser.framesetOK = False + Phase.processCharacters(self, token) + + def processStartTag(self, token): + currentNode = self.tree.openElements[-1] + if (token["name"] in self.breakoutElements or + (token["name"] == "font" and + set(token["data"].keys()) & set(["color", "face", "size"]))): + self.parser.parseError("unexpected-html-element-in-foreign-content", + {"name": token["name"]}) + while (self.tree.openElements[-1].namespace != + self.tree.defaultNamespace and + not self.parser.isHTMLIntegrationPoint(self.tree.openElements[-1]) and + not self.parser.isMathMLTextIntegrationPoint(self.tree.openElements[-1])): + self.tree.openElements.pop() + return token + + else: + if currentNode.namespace == namespaces["mathml"]: + self.parser.adjustMathMLAttributes(token) + elif currentNode.namespace == namespaces["svg"]: + self.adjustSVGTagNames(token) + self.parser.adjustSVGAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = currentNode.namespace + self.tree.insertElement(token) + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def processEndTag(self, token): + nodeIndex = len(self.tree.openElements) - 1 + node = self.tree.openElements[-1] + if node.name.translate(asciiUpper2Lower) != token["name"]: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + while True: + if node.name.translate(asciiUpper2Lower) == token["name"]: + # XXX this isn't in the spec but it seems necessary + if self.parser.phase == self.parser.phases["inTableText"]: + self.parser.phase.flushCharacters() + self.parser.phase = self.parser.phase.originalPhase + while self.tree.openElements.pop() != node: + assert self.tree.openElements + new_token = None + break + nodeIndex -= 1 + + node = self.tree.openElements[nodeIndex] + if node.namespace != self.tree.defaultNamespace: + continue + else: + new_token = self.parser.phase.processEndTag(token) + break + return new_token + + class AfterBodyPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([("html", self.endTagHtml)]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + # Stop parsing + pass + + def processComment(self, token): + # This is needed because data is to be appended to the <html> element + # here and not to whatever is currently open. + self.tree.insertComment(token, self.tree.openElements[0]) + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-after-body") + self.parser.phase = self.parser.phases["inBody"] + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-after-body", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + def endTagHtml(self, name): + if self.parser.innerHTML: + self.parser.parseError("unexpected-end-tag-after-body-innerhtml") + else: + self.parser.phase = self.parser.phases["afterAfterBody"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-after-body", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + class InFramesetPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-frameset + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("frameset", self.startTagFrameset), + ("frame", self.startTagFrame), + ("noframes", self.startTagNoframes) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("frameset", self.endTagFrameset) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-frameset") + else: + assert self.parser.innerHTML + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-in-frameset") + + def startTagFrameset(self, token): + self.tree.insertElement(token) + + def startTagFrame(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + + def startTagNoframes(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-in-frameset", + {"name": token["name"]}) + + def endTagFrameset(self, token): + if self.tree.openElements[-1].name == "html": + # innerHTML case + self.parser.parseError("unexpected-frameset-in-frameset-innerhtml") + else: + self.tree.openElements.pop() + if (not self.parser.innerHTML and + self.tree.openElements[-1].name != "frameset"): + # If we're not in innerHTML mode and the current node is not a + # "frameset" element (anymore) then switch. + self.parser.phase = self.parser.phases["afterFrameset"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-in-frameset", + {"name": token["name"]}) + + class AfterFramesetPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#after3 + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("noframes", self.startTagNoframes) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("html", self.endTagHtml) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + # Stop parsing + pass + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-after-frameset") + + def startTagNoframes(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-after-frameset", + {"name": token["name"]}) + + def endTagHtml(self, token): + self.parser.phase = self.parser.phases["afterAfterFrameset"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-after-frameset", + {"name": token["name"]}) + + class AfterAfterBodyPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml) + ]) + self.startTagHandler.default = self.startTagOther + + def processEOF(self): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + return self.parser.phases["inBody"].processSpaceCharacters(token) + + def processCharacters(self, token): + self.parser.parseError("expected-eof-but-got-char") + self.parser.phase = self.parser.phases["inBody"] + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("expected-eof-but-got-start-tag", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + def processEndTag(self, token): + self.parser.parseError("expected-eof-but-got-end-tag", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + class AfterAfterFramesetPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("noframes", self.startTagNoFrames) + ]) + self.startTagHandler.default = self.startTagOther + + def processEOF(self): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + return self.parser.phases["inBody"].processSpaceCharacters(token) + + def processCharacters(self, token): + self.parser.parseError("expected-eof-but-got-char") + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagNoFrames(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("expected-eof-but-got-start-tag", + {"name": token["name"]}) + + def processEndTag(self, token): + self.parser.parseError("expected-eof-but-got-end-tag", + {"name": token["name"]}) + # pylint:enable=unused-argument + + return { + "initial": InitialPhase, + "beforeHtml": BeforeHtmlPhase, + "beforeHead": BeforeHeadPhase, + "inHead": InHeadPhase, + "inHeadNoscript": InHeadNoscriptPhase, + "afterHead": AfterHeadPhase, + "inBody": InBodyPhase, + "text": TextPhase, + "inTable": InTablePhase, + "inTableText": InTableTextPhase, + "inCaption": InCaptionPhase, + "inColumnGroup": InColumnGroupPhase, + "inTableBody": InTableBodyPhase, + "inRow": InRowPhase, + "inCell": InCellPhase, + "inSelect": InSelectPhase, + "inSelectInTable": InSelectInTablePhase, + "inForeignContent": InForeignContentPhase, + "afterBody": AfterBodyPhase, + "inFrameset": InFramesetPhase, + "afterFrameset": AfterFramesetPhase, + "afterAfterBody": AfterAfterBodyPhase, + "afterAfterFrameset": AfterAfterFramesetPhase, + # XXX after after frameset + } + + +def adjust_attributes(token, replacements): + needs_adjustment = viewkeys(token['data']) & viewkeys(replacements) + if needs_adjustment: + token['data'] = OrderedDict((replacements.get(k, k), v) + for k, v in token['data'].items()) + + +def impliedTagToken(name, type="EndTag", attributes=None, + selfClosing=False): + if attributes is None: + attributes = {} + return {"type": tokenTypes[type], "name": name, "data": attributes, + "selfClosing": selfClosing} + + +class ParseError(Exception): + """Error in parsed document""" + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py new file mode 100755 index 0000000..641323e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py @@ -0,0 +1,409 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +import re + +from codecs import register_error, xmlcharrefreplace_errors + +from .constants import voidElements, booleanAttributes, spaceCharacters +from .constants import rcdataElements, entities, xmlEntities +from . import treewalkers, _utils +from xml.sax.saxutils import escape + +_quoteAttributeSpecChars = "".join(spaceCharacters) + "\"'=<>`" +_quoteAttributeSpec = re.compile("[" + _quoteAttributeSpecChars + "]") +_quoteAttributeLegacy = re.compile("[" + _quoteAttributeSpecChars + + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n" + "\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15" + "\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x2f\x60\xa0\u1680\u180e\u180f\u2000" + "\u2001\u2002\u2003\u2004\u2005\u2006\u2007" + "\u2008\u2009\u200a\u2028\u2029\u202f\u205f" + "\u3000]") + + +_encode_entity_map = {} +_is_ucs4 = len("\U0010FFFF") == 1 +for k, v in list(entities.items()): + # skip multi-character entities + if ((_is_ucs4 and len(v) > 1) or + (not _is_ucs4 and len(v) > 2)): + continue + if v != "&": + if len(v) == 2: + v = _utils.surrogatePairToCodepoint(v) + else: + v = ord(v) + if v not in _encode_entity_map or k.islower(): + # prefer < over < and similarly for &, >, etc. + _encode_entity_map[v] = k + + +def htmlentityreplace_errors(exc): + if isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)): + res = [] + codepoints = [] + skip = False + for i, c in enumerate(exc.object[exc.start:exc.end]): + if skip: + skip = False + continue + index = i + exc.start + if _utils.isSurrogatePair(exc.object[index:min([exc.end, index + 2])]): + codepoint = _utils.surrogatePairToCodepoint(exc.object[index:index + 2]) + skip = True + else: + codepoint = ord(c) + codepoints.append(codepoint) + for cp in codepoints: + e = _encode_entity_map.get(cp) + if e: + res.append("&") + res.append(e) + if not e.endswith(";"): + res.append(";") + else: + res.append("&#x%s;" % (hex(cp)[2:])) + return ("".join(res), exc.end) + else: + return xmlcharrefreplace_errors(exc) + + +register_error("htmlentityreplace", htmlentityreplace_errors) + + +def serialize(input, tree="etree", encoding=None, **serializer_opts): + """Serializes the input token stream using the specified treewalker + + :arg input: the token stream to serialize + + :arg tree: the treewalker to use + + :arg encoding: the encoding to use + + :arg serializer_opts: any options to pass to the + :py:class:`html5lib.serializer.HTMLSerializer` that gets created + + :returns: the tree serialized as a string + + Example: + + >>> from html5lib.html5parser import parse + >>> from html5lib.serializer import serialize + >>> token_stream = parse('<html><body><p>Hi!</p></body></html>') + >>> serialize(token_stream, omit_optional_tags=False) + '<html><head></head><body><p>Hi!</p></body></html>' + + """ + # XXX: Should we cache this? + walker = treewalkers.getTreeWalker(tree) + s = HTMLSerializer(**serializer_opts) + return s.render(walker(input), encoding) + + +class HTMLSerializer(object): + + # attribute quoting options + quote_attr_values = "legacy" # be secure by default + quote_char = '"' + use_best_quote_char = True + + # tag syntax options + omit_optional_tags = True + minimize_boolean_attributes = True + use_trailing_solidus = False + space_before_trailing_solidus = True + + # escaping options + escape_lt_in_attrs = False + escape_rcdata = False + resolve_entities = True + + # miscellaneous options + alphabetical_attributes = False + inject_meta_charset = True + strip_whitespace = False + sanitize = False + + options = ("quote_attr_values", "quote_char", "use_best_quote_char", + "omit_optional_tags", "minimize_boolean_attributes", + "use_trailing_solidus", "space_before_trailing_solidus", + "escape_lt_in_attrs", "escape_rcdata", "resolve_entities", + "alphabetical_attributes", "inject_meta_charset", + "strip_whitespace", "sanitize") + + def __init__(self, **kwargs): + """Initialize HTMLSerializer + + :arg inject_meta_charset: Whether or not to inject the meta charset. + + Defaults to ``True``. + + :arg quote_attr_values: Whether to quote attribute values that don't + require quoting per legacy browser behavior (``"legacy"``), when + required by the standard (``"spec"``), or always (``"always"``). + + Defaults to ``"legacy"``. + + :arg quote_char: Use given quote character for attribute quoting. + + Defaults to ``"`` which will use double quotes unless attribute + value contains a double quote, in which case single quotes are + used. + + :arg escape_lt_in_attrs: Whether or not to escape ``<`` in attribute + values. + + Defaults to ``False``. + + :arg escape_rcdata: Whether to escape characters that need to be + escaped within normal elements within rcdata elements such as + style. + + Defaults to ``False``. + + :arg resolve_entities: Whether to resolve named character entities that + appear in the source tree. The XML predefined entities < > + & " ' are unaffected by this setting. + + Defaults to ``True``. + + :arg strip_whitespace: Whether to remove semantically meaningless + whitespace. (This compresses all whitespace to a single space + except within ``pre``.) + + Defaults to ``False``. + + :arg minimize_boolean_attributes: Shortens boolean attributes to give + just the attribute value, for example:: + + <input disabled="disabled"> + + becomes:: + + <input disabled> + + Defaults to ``True``. + + :arg use_trailing_solidus: Includes a close-tag slash at the end of the + start tag of void elements (empty elements whose end tag is + forbidden). E.g. ``<hr/>``. + + Defaults to ``False``. + + :arg space_before_trailing_solidus: Places a space immediately before + the closing slash in a tag using a trailing solidus. E.g. + ``<hr />``. Requires ``use_trailing_solidus=True``. + + Defaults to ``True``. + + :arg sanitize: Strip all unsafe or unknown constructs from output. + See :py:class:`html5lib.filters.sanitizer.Filter`. + + Defaults to ``False``. + + :arg omit_optional_tags: Omit start/end tags that are optional. + + Defaults to ``True``. + + :arg alphabetical_attributes: Reorder attributes to be in alphabetical order. + + Defaults to ``False``. + + """ + unexpected_args = frozenset(kwargs) - frozenset(self.options) + if len(unexpected_args) > 0: + raise TypeError("__init__() got an unexpected keyword argument '%s'" % next(iter(unexpected_args))) + if 'quote_char' in kwargs: + self.use_best_quote_char = False + for attr in self.options: + setattr(self, attr, kwargs.get(attr, getattr(self, attr))) + self.errors = [] + self.strict = False + + def encode(self, string): + assert(isinstance(string, text_type)) + if self.encoding: + return string.encode(self.encoding, "htmlentityreplace") + else: + return string + + def encodeStrict(self, string): + assert(isinstance(string, text_type)) + if self.encoding: + return string.encode(self.encoding, "strict") + else: + return string + + def serialize(self, treewalker, encoding=None): + # pylint:disable=too-many-nested-blocks + self.encoding = encoding + in_cdata = False + self.errors = [] + + if encoding and self.inject_meta_charset: + from .filters.inject_meta_charset import Filter + treewalker = Filter(treewalker, encoding) + # Alphabetical attributes is here under the assumption that none of + # the later filters add or change order of attributes; it needs to be + # before the sanitizer so escaped elements come out correctly + if self.alphabetical_attributes: + from .filters.alphabeticalattributes import Filter + treewalker = Filter(treewalker) + # WhitespaceFilter should be used before OptionalTagFilter + # for maximum efficiently of this latter filter + if self.strip_whitespace: + from .filters.whitespace import Filter + treewalker = Filter(treewalker) + if self.sanitize: + from .filters.sanitizer import Filter + treewalker = Filter(treewalker) + if self.omit_optional_tags: + from .filters.optionaltags import Filter + treewalker = Filter(treewalker) + + for token in treewalker: + type = token["type"] + if type == "Doctype": + doctype = "<!DOCTYPE %s" % token["name"] + + if token["publicId"]: + doctype += ' PUBLIC "%s"' % token["publicId"] + elif token["systemId"]: + doctype += " SYSTEM" + if token["systemId"]: + if token["systemId"].find('"') >= 0: + if token["systemId"].find("'") >= 0: + self.serializeError("System identifer contains both single and double quote characters") + quote_char = "'" + else: + quote_char = '"' + doctype += " %s%s%s" % (quote_char, token["systemId"], quote_char) + + doctype += ">" + yield self.encodeStrict(doctype) + + elif type in ("Characters", "SpaceCharacters"): + if type == "SpaceCharacters" or in_cdata: + if in_cdata and token["data"].find("</") >= 0: + self.serializeError("Unexpected </ in CDATA") + yield self.encode(token["data"]) + else: + yield self.encode(escape(token["data"])) + + elif type in ("StartTag", "EmptyTag"): + name = token["name"] + yield self.encodeStrict("<%s" % name) + if name in rcdataElements and not self.escape_rcdata: + in_cdata = True + elif in_cdata: + self.serializeError("Unexpected child element of a CDATA element") + for (_, attr_name), attr_value in token["data"].items(): + # TODO: Add namespace support here + k = attr_name + v = attr_value + yield self.encodeStrict(' ') + + yield self.encodeStrict(k) + if not self.minimize_boolean_attributes or \ + (k not in booleanAttributes.get(name, tuple()) and + k not in booleanAttributes.get("", tuple())): + yield self.encodeStrict("=") + if self.quote_attr_values == "always" or len(v) == 0: + quote_attr = True + elif self.quote_attr_values == "spec": + quote_attr = _quoteAttributeSpec.search(v) is not None + elif self.quote_attr_values == "legacy": + quote_attr = _quoteAttributeLegacy.search(v) is not None + else: + raise ValueError("quote_attr_values must be one of: " + "'always', 'spec', or 'legacy'") + v = v.replace("&", "&") + if self.escape_lt_in_attrs: + v = v.replace("<", "<") + if quote_attr: + quote_char = self.quote_char + if self.use_best_quote_char: + if "'" in v and '"' not in v: + quote_char = '"' + elif '"' in v and "'" not in v: + quote_char = "'" + if quote_char == "'": + v = v.replace("'", "'") + else: + v = v.replace('"', """) + yield self.encodeStrict(quote_char) + yield self.encode(v) + yield self.encodeStrict(quote_char) + else: + yield self.encode(v) + if name in voidElements and self.use_trailing_solidus: + if self.space_before_trailing_solidus: + yield self.encodeStrict(" /") + else: + yield self.encodeStrict("/") + yield self.encode(">") + + elif type == "EndTag": + name = token["name"] + if name in rcdataElements: + in_cdata = False + elif in_cdata: + self.serializeError("Unexpected child element of a CDATA element") + yield self.encodeStrict("</%s>" % name) + + elif type == "Comment": + data = token["data"] + if data.find("--") >= 0: + self.serializeError("Comment contains --") + yield self.encodeStrict("<!--%s-->" % token["data"]) + + elif type == "Entity": + name = token["name"] + key = name + ";" + if key not in entities: + self.serializeError("Entity %s not recognized" % name) + if self.resolve_entities and key not in xmlEntities: + data = entities[key] + else: + data = "&%s;" % name + yield self.encodeStrict(data) + + else: + self.serializeError(token["data"]) + + def render(self, treewalker, encoding=None): + """Serializes the stream from the treewalker into a string + + :arg treewalker: the treewalker to serialize + + :arg encoding: the string encoding to use + + :returns: the serialized tree + + Example: + + >>> from html5lib import parse, getTreeWalker + >>> from html5lib.serializer import HTMLSerializer + >>> token_stream = parse('<html><body>Hi!</body></html>') + >>> walker = getTreeWalker('etree') + >>> serializer = HTMLSerializer(omit_optional_tags=False) + >>> serializer.render(walker(token_stream)) + '<html><head></head><body>Hi!</body></html>' + + """ + if encoding: + return b"".join(list(self.serialize(treewalker, encoding))) + else: + return "".join(list(self.serialize(treewalker))) + + def serializeError(self, data="XXX ERROR MESSAGE NEEDED"): + # XXX The idea is to make data mandatory. + self.errors.append(data) + if self.strict: + raise SerializeError + + +class SerializeError(Exception): + """Error in serialized tree""" + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py new file mode 100755 index 0000000..8767fb0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py @@ -0,0 +1,30 @@ +"""Tree adapters let you convert from one tree structure to another + +Example: + +.. code-block:: python + + from pip._vendor import html5lib + from pip._vendor.html5lib.treeadapters import genshi + + doc = '<html><body>Hi!</body></html>' + treebuilder = html5lib.getTreeBuilder('etree') + parser = html5lib.HTMLParser(tree=treebuilder) + tree = parser.parse(doc) + TreeWalker = html5lib.getTreeWalker('etree') + + genshi_tree = genshi.to_genshi(TreeWalker(tree)) + +""" +from __future__ import absolute_import, division, unicode_literals + +from . import sax + +__all__ = ["sax"] + +try: + from . import genshi # noqa +except ImportError: + pass +else: + __all__.append("genshi") diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py new file mode 100755 index 0000000..73c70c6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import, division, unicode_literals + +from genshi.core import QName, Attrs +from genshi.core import START, END, TEXT, COMMENT, DOCTYPE + + +def to_genshi(walker): + """Convert a tree to a genshi tree + + :arg walker: the treewalker to use to walk the tree to convert it + + :returns: generator of genshi nodes + + """ + text = [] + for token in walker: + type = token["type"] + if type in ("Characters", "SpaceCharacters"): + text.append(token["data"]) + elif text: + yield TEXT, "".join(text), (None, -1, -1) + text = [] + + if type in ("StartTag", "EmptyTag"): + if token["namespace"]: + name = "{%s}%s" % (token["namespace"], token["name"]) + else: + name = token["name"] + attrs = Attrs([(QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value) + for attr, value in token["data"].items()]) + yield (START, (QName(name), attrs), (None, -1, -1)) + if type == "EmptyTag": + type = "EndTag" + + if type == "EndTag": + if token["namespace"]: + name = "{%s}%s" % (token["namespace"], token["name"]) + else: + name = token["name"] + + yield END, QName(name), (None, -1, -1) + + elif type == "Comment": + yield COMMENT, token["data"], (None, -1, -1) + + elif type == "Doctype": + yield DOCTYPE, (token["name"], token["publicId"], + token["systemId"]), (None, -1, -1) + + else: + pass # FIXME: What to do? + + if text: + yield TEXT, "".join(text), (None, -1, -1) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py new file mode 100755 index 0000000..1f06d13 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.sax.xmlreader import AttributesNSImpl + +from ..constants import adjustForeignAttributes, unadjustForeignAttributes + +prefix_mapping = {} +for prefix, localName, namespace in adjustForeignAttributes.values(): + if prefix is not None: + prefix_mapping[prefix] = namespace + + +def to_sax(walker, handler): + """Call SAX-like content handler based on treewalker walker + + :arg walker: the treewalker to use to walk the tree to convert it + + :arg handler: SAX handler to use + + """ + handler.startDocument() + for prefix, namespace in prefix_mapping.items(): + handler.startPrefixMapping(prefix, namespace) + + for token in walker: + type = token["type"] + if type == "Doctype": + continue + elif type in ("StartTag", "EmptyTag"): + attrs = AttributesNSImpl(token["data"], + unadjustForeignAttributes) + handler.startElementNS((token["namespace"], token["name"]), + token["name"], + attrs) + if type == "EmptyTag": + handler.endElementNS((token["namespace"], token["name"]), + token["name"]) + elif type == "EndTag": + handler.endElementNS((token["namespace"], token["name"]), + token["name"]) + elif type in ("Characters", "SpaceCharacters"): + handler.characters(token["data"]) + elif type == "Comment": + pass + else: + assert False, "Unknown token type" + + for prefix, namespace in prefix_mapping.items(): + handler.endPrefixMapping(prefix) + handler.endDocument() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py new file mode 100755 index 0000000..2ce5c87 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py @@ -0,0 +1,88 @@ +"""A collection of modules for building different kinds of trees from HTML +documents. + +To create a treebuilder for a new type of tree, you need to do +implement several things: + +1. A set of classes for various types of elements: Document, Doctype, Comment, + Element. These must implement the interface of ``base.treebuilders.Node`` + (although comment nodes have a different signature for their constructor, + see ``treebuilders.etree.Comment``) Textual content may also be implemented + as another node type, or not, as your tree implementation requires. + +2. A treebuilder object (called ``TreeBuilder`` by convention) that inherits + from ``treebuilders.base.TreeBuilder``. This has 4 required attributes: + + * ``documentClass`` - the class to use for the bottommost node of a document + * ``elementClass`` - the class to use for HTML Elements + * ``commentClass`` - the class to use for comments + * ``doctypeClass`` - the class to use for doctypes + + It also has one required method: + + * ``getDocument`` - Returns the root node of the complete document tree + +3. If you wish to run the unit tests, you must also create a ``testSerializer`` + method on your treebuilder which accepts a node and returns a string + containing Node and its children serialized according to the format used in + the unittests + +""" + +from __future__ import absolute_import, division, unicode_literals + +from .._utils import default_etree + +treeBuilderCache = {} + + +def getTreeBuilder(treeType, implementation=None, **kwargs): + """Get a TreeBuilder class for various types of trees with built-in support + + :arg treeType: the name of the tree type required (case-insensitive). Supported + values are: + + * "dom" - A generic builder for DOM implementations, defaulting to a + xml.dom.minidom based implementation. + * "etree" - A generic builder for tree implementations exposing an + ElementTree-like interface, defaulting to xml.etree.cElementTree if + available and xml.etree.ElementTree if not. + * "lxml" - A etree-based builder for lxml.etree, handling limitations + of lxml's implementation. + + :arg implementation: (Currently applies to the "etree" and "dom" tree + types). A module implementing the tree type e.g. xml.etree.ElementTree + or xml.etree.cElementTree. + + :arg kwargs: Any additional options to pass to the TreeBuilder when + creating it. + + Example: + + >>> from html5lib.treebuilders import getTreeBuilder + >>> builder = getTreeBuilder('etree') + + """ + + treeType = treeType.lower() + if treeType not in treeBuilderCache: + if treeType == "dom": + from . import dom + # Come up with a sane default (pref. from the stdlib) + if implementation is None: + from xml.dom import minidom + implementation = minidom + # NEVER cache here, caching is done in the dom submodule + return dom.getDomModule(implementation, **kwargs).TreeBuilder + elif treeType == "lxml": + from . import etree_lxml + treeBuilderCache[treeType] = etree_lxml.TreeBuilder + elif treeType == "etree": + from . import etree + if implementation is None: + implementation = default_etree + # NEVER cache here, caching is done in the etree submodule + return etree.getETreeModule(implementation, **kwargs).TreeBuilder + else: + raise ValueError("""Unrecognised treebuilder "%s" """ % treeType) + return treeBuilderCache.get(treeType) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py new file mode 100755 index 0000000..ed32fcb --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py @@ -0,0 +1,417 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from ..constants import scopingElements, tableInsertModeElements, namespaces + +# The scope markers are inserted when entering object elements, +# marquees, table cells, and table captions, and are used to prevent formatting +# from "leaking" into tables, object elements, and marquees. +Marker = None + +listElementsMap = { + None: (frozenset(scopingElements), False), + "button": (frozenset(scopingElements | set([(namespaces["html"], "button")])), False), + "list": (frozenset(scopingElements | set([(namespaces["html"], "ol"), + (namespaces["html"], "ul")])), False), + "table": (frozenset([(namespaces["html"], "html"), + (namespaces["html"], "table")]), False), + "select": (frozenset([(namespaces["html"], "optgroup"), + (namespaces["html"], "option")]), True) +} + + +class Node(object): + """Represents an item in the tree""" + def __init__(self, name): + """Creates a Node + + :arg name: The tag name associated with the node + + """ + # The tag name assocaited with the node + self.name = name + # The parent of the current node (or None for the document node) + self.parent = None + # The value of the current node (applies to text nodes and comments) + self.value = None + # A dict holding name -> value pairs for attributes of the node + self.attributes = {} + # A list of child nodes of the current node. This must include all + # elements but not necessarily other node types. + self.childNodes = [] + # A list of miscellaneous flags that can be set on the node. + self._flags = [] + + def __str__(self): + attributesStr = " ".join(["%s=\"%s\"" % (name, value) + for name, value in + self.attributes.items()]) + if attributesStr: + return "<%s %s>" % (self.name, attributesStr) + else: + return "<%s>" % (self.name) + + def __repr__(self): + return "<%s>" % (self.name) + + def appendChild(self, node): + """Insert node as a child of the current node + + :arg node: the node to insert + + """ + raise NotImplementedError + + def insertText(self, data, insertBefore=None): + """Insert data as text in the current node, positioned before the + start of node insertBefore or to the end of the node's text. + + :arg data: the data to insert + + :arg insertBefore: True if you want to insert the text before the node + and False if you want to insert it after the node + + """ + raise NotImplementedError + + def insertBefore(self, node, refNode): + """Insert node as a child of the current node, before refNode in the + list of child nodes. Raises ValueError if refNode is not a child of + the current node + + :arg node: the node to insert + + :arg refNode: the child node to insert the node before + + """ + raise NotImplementedError + + def removeChild(self, node): + """Remove node from the children of the current node + + :arg node: the child node to remove + + """ + raise NotImplementedError + + def reparentChildren(self, newParent): + """Move all the children of the current node to newParent. + This is needed so that trees that don't store text as nodes move the + text in the correct way + + :arg newParent: the node to move all this node's children to + + """ + # XXX - should this method be made more general? + for child in self.childNodes: + newParent.appendChild(child) + self.childNodes = [] + + def cloneNode(self): + """Return a shallow copy of the current node i.e. a node with the same + name and attributes but with no parent or child nodes + """ + raise NotImplementedError + + def hasContent(self): + """Return true if the node has children or text, false otherwise + """ + raise NotImplementedError + + +class ActiveFormattingElements(list): + def append(self, node): + equalCount = 0 + if node != Marker: + for element in self[::-1]: + if element == Marker: + break + if self.nodesEqual(element, node): + equalCount += 1 + if equalCount == 3: + self.remove(element) + break + list.append(self, node) + + def nodesEqual(self, node1, node2): + if not node1.nameTuple == node2.nameTuple: + return False + + if not node1.attributes == node2.attributes: + return False + + return True + + +class TreeBuilder(object): + """Base treebuilder implementation + + * documentClass - the class to use for the bottommost node of a document + * elementClass - the class to use for HTML Elements + * commentClass - the class to use for comments + * doctypeClass - the class to use for doctypes + + """ + # pylint:disable=not-callable + + # Document class + documentClass = None + + # The class to use for creating a node + elementClass = None + + # The class to use for creating comments + commentClass = None + + # The class to use for creating doctypes + doctypeClass = None + + # Fragment class + fragmentClass = None + + def __init__(self, namespaceHTMLElements): + """Create a TreeBuilder + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + """ + if namespaceHTMLElements: + self.defaultNamespace = "http://www.w3.org/1999/xhtml" + else: + self.defaultNamespace = None + self.reset() + + def reset(self): + self.openElements = [] + self.activeFormattingElements = ActiveFormattingElements() + + # XXX - rename these to headElement, formElement + self.headPointer = None + self.formPointer = None + + self.insertFromTable = False + + self.document = self.documentClass() + + def elementInScope(self, target, variant=None): + + # If we pass a node in we match that. if we pass a string + # match any node with that name + exactNode = hasattr(target, "nameTuple") + if not exactNode: + if isinstance(target, text_type): + target = (namespaces["html"], target) + assert isinstance(target, tuple) + + listElements, invert = listElementsMap[variant] + + for node in reversed(self.openElements): + if exactNode and node == target: + return True + elif not exactNode and node.nameTuple == target: + return True + elif (invert ^ (node.nameTuple in listElements)): + return False + + assert False # We should never reach this point + + def reconstructActiveFormattingElements(self): + # Within this algorithm the order of steps described in the + # specification is not quite the same as the order of steps in the + # code. It should still do the same though. + + # Step 1: stop the algorithm when there's nothing to do. + if not self.activeFormattingElements: + return + + # Step 2 and step 3: we start with the last element. So i is -1. + i = len(self.activeFormattingElements) - 1 + entry = self.activeFormattingElements[i] + if entry == Marker or entry in self.openElements: + return + + # Step 6 + while entry != Marker and entry not in self.openElements: + if i == 0: + # This will be reset to 0 below + i = -1 + break + i -= 1 + # Step 5: let entry be one earlier in the list. + entry = self.activeFormattingElements[i] + + while True: + # Step 7 + i += 1 + + # Step 8 + entry = self.activeFormattingElements[i] + clone = entry.cloneNode() # Mainly to get a new copy of the attributes + + # Step 9 + element = self.insertElement({"type": "StartTag", + "name": clone.name, + "namespace": clone.namespace, + "data": clone.attributes}) + + # Step 10 + self.activeFormattingElements[i] = element + + # Step 11 + if element == self.activeFormattingElements[-1]: + break + + def clearActiveFormattingElements(self): + entry = self.activeFormattingElements.pop() + while self.activeFormattingElements and entry != Marker: + entry = self.activeFormattingElements.pop() + + def elementInActiveFormattingElements(self, name): + """Check if an element exists between the end of the active + formatting elements and the last marker. If it does, return it, else + return false""" + + for item in self.activeFormattingElements[::-1]: + # Check for Marker first because if it's a Marker it doesn't have a + # name attribute. + if item == Marker: + break + elif item.name == name: + return item + return False + + def insertRoot(self, token): + element = self.createElement(token) + self.openElements.append(element) + self.document.appendChild(element) + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + doctype = self.doctypeClass(name, publicId, systemId) + self.document.appendChild(doctype) + + def insertComment(self, token, parent=None): + if parent is None: + parent = self.openElements[-1] + parent.appendChild(self.commentClass(token["data"])) + + def createElement(self, token): + """Create an element but don't insert it anywhere""" + name = token["name"] + namespace = token.get("namespace", self.defaultNamespace) + element = self.elementClass(name, namespace) + element.attributes = token["data"] + return element + + def _getInsertFromTable(self): + return self._insertFromTable + + def _setInsertFromTable(self, value): + """Switch the function used to insert an element from the + normal one to the misnested table one and back again""" + self._insertFromTable = value + if value: + self.insertElement = self.insertElementTable + else: + self.insertElement = self.insertElementNormal + + insertFromTable = property(_getInsertFromTable, _setInsertFromTable) + + def insertElementNormal(self, token): + name = token["name"] + assert isinstance(name, text_type), "Element %s not unicode" % name + namespace = token.get("namespace", self.defaultNamespace) + element = self.elementClass(name, namespace) + element.attributes = token["data"] + self.openElements[-1].appendChild(element) + self.openElements.append(element) + return element + + def insertElementTable(self, token): + """Create an element and insert it into the tree""" + element = self.createElement(token) + if self.openElements[-1].name not in tableInsertModeElements: + return self.insertElementNormal(token) + else: + # We should be in the InTable mode. This means we want to do + # special magic element rearranging + parent, insertBefore = self.getTableMisnestedNodePosition() + if insertBefore is None: + parent.appendChild(element) + else: + parent.insertBefore(element, insertBefore) + self.openElements.append(element) + return element + + def insertText(self, data, parent=None): + """Insert text data.""" + if parent is None: + parent = self.openElements[-1] + + if (not self.insertFromTable or (self.insertFromTable and + self.openElements[-1].name + not in tableInsertModeElements)): + parent.insertText(data) + else: + # We should be in the InTable mode. This means we want to do + # special magic element rearranging + parent, insertBefore = self.getTableMisnestedNodePosition() + parent.insertText(data, insertBefore) + + def getTableMisnestedNodePosition(self): + """Get the foster parent element, and sibling to insert before + (or None) when inserting a misnested table node""" + # The foster parent element is the one which comes before the most + # recently opened table element + # XXX - this is really inelegant + lastTable = None + fosterParent = None + insertBefore = None + for elm in self.openElements[::-1]: + if elm.name == "table": + lastTable = elm + break + if lastTable: + # XXX - we should really check that this parent is actually a + # node here + if lastTable.parent: + fosterParent = lastTable.parent + insertBefore = lastTable + else: + fosterParent = self.openElements[ + self.openElements.index(lastTable) - 1] + else: + fosterParent = self.openElements[0] + return fosterParent, insertBefore + + def generateImpliedEndTags(self, exclude=None): + name = self.openElements[-1].name + # XXX td, th and tr are not actually needed + if (name in frozenset(("dd", "dt", "li", "option", "optgroup", "p", "rp", "rt")) and + name != exclude): + self.openElements.pop() + # XXX This is not entirely what the specification says. We should + # investigate it more closely. + self.generateImpliedEndTags(exclude) + + def getDocument(self): + """Return the final tree""" + return self.document + + def getFragment(self): + """Return the final fragment""" + # assert self.innerHTML + fragment = self.fragmentClass() + self.openElements[0].reparentChildren(fragment) + return fragment + + def testSerializer(self, node): + """Serialize the subtree of node in the format required by unit tests + + :arg node: the node from which to start serializing + + """ + raise NotImplementedError diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py new file mode 100755 index 0000000..8117b2d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py @@ -0,0 +1,236 @@ +from __future__ import absolute_import, division, unicode_literals + + +from collections import MutableMapping +from xml.dom import minidom, Node +import weakref + +from . import base +from .. import constants +from ..constants import namespaces +from .._utils import moduleFactoryFactory + + +def getDomBuilder(DomImplementation): + Dom = DomImplementation + + class AttrList(MutableMapping): + def __init__(self, element): + self.element = element + + def __iter__(self): + return iter(self.element.attributes.keys()) + + def __setitem__(self, name, value): + if isinstance(name, tuple): + raise NotImplementedError + else: + attr = self.element.ownerDocument.createAttribute(name) + attr.value = value + self.element.attributes[name] = attr + + def __len__(self): + return len(self.element.attributes) + + def items(self): + return list(self.element.attributes.items()) + + def values(self): + return list(self.element.attributes.values()) + + def __getitem__(self, name): + if isinstance(name, tuple): + raise NotImplementedError + else: + return self.element.attributes[name].value + + def __delitem__(self, name): + if isinstance(name, tuple): + raise NotImplementedError + else: + del self.element.attributes[name] + + class NodeBuilder(base.Node): + def __init__(self, element): + base.Node.__init__(self, element.nodeName) + self.element = element + + namespace = property(lambda self: hasattr(self.element, "namespaceURI") and + self.element.namespaceURI or None) + + def appendChild(self, node): + node.parent = self + self.element.appendChild(node.element) + + def insertText(self, data, insertBefore=None): + text = self.element.ownerDocument.createTextNode(data) + if insertBefore: + self.element.insertBefore(text, insertBefore.element) + else: + self.element.appendChild(text) + + def insertBefore(self, node, refNode): + self.element.insertBefore(node.element, refNode.element) + node.parent = self + + def removeChild(self, node): + if node.element.parentNode == self.element: + self.element.removeChild(node.element) + node.parent = None + + def reparentChildren(self, newParent): + while self.element.hasChildNodes(): + child = self.element.firstChild + self.element.removeChild(child) + newParent.element.appendChild(child) + self.childNodes = [] + + def getAttributes(self): + return AttrList(self.element) + + def setAttributes(self, attributes): + if attributes: + for name, value in list(attributes.items()): + if isinstance(name, tuple): + if name[0] is not None: + qualifiedName = (name[0] + ":" + name[1]) + else: + qualifiedName = name[1] + self.element.setAttributeNS(name[2], qualifiedName, + value) + else: + self.element.setAttribute( + name, value) + attributes = property(getAttributes, setAttributes) + + def cloneNode(self): + return NodeBuilder(self.element.cloneNode(False)) + + def hasContent(self): + return self.element.hasChildNodes() + + def getNameTuple(self): + if self.namespace is None: + return namespaces["html"], self.name + else: + return self.namespace, self.name + + nameTuple = property(getNameTuple) + + class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable + def documentClass(self): + self.dom = Dom.getDOMImplementation().createDocument(None, None, None) + return weakref.proxy(self) + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + domimpl = Dom.getDOMImplementation() + doctype = domimpl.createDocumentType(name, publicId, systemId) + self.document.appendChild(NodeBuilder(doctype)) + if Dom == minidom: + doctype.ownerDocument = self.dom + + def elementClass(self, name, namespace=None): + if namespace is None and self.defaultNamespace is None: + node = self.dom.createElement(name) + else: + node = self.dom.createElementNS(namespace, name) + + return NodeBuilder(node) + + def commentClass(self, data): + return NodeBuilder(self.dom.createComment(data)) + + def fragmentClass(self): + return NodeBuilder(self.dom.createDocumentFragment()) + + def appendChild(self, node): + self.dom.appendChild(node.element) + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + return self.dom + + def getFragment(self): + return base.TreeBuilder.getFragment(self).element + + def insertText(self, data, parent=None): + data = data + if parent != self: + base.TreeBuilder.insertText(self, data, parent) + else: + # HACK: allow text nodes as children of the document node + if hasattr(self.dom, '_child_node_types'): + # pylint:disable=protected-access + if Node.TEXT_NODE not in self.dom._child_node_types: + self.dom._child_node_types = list(self.dom._child_node_types) + self.dom._child_node_types.append(Node.TEXT_NODE) + self.dom.appendChild(self.dom.createTextNode(data)) + + implementation = DomImplementation + name = None + + def testSerializer(element): + element.normalize() + rv = [] + + def serializeElement(element, indent=0): + if element.nodeType == Node.DOCUMENT_TYPE_NODE: + if element.name: + if element.publicId or element.systemId: + publicId = element.publicId or "" + systemId = element.systemId or "" + rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" % + (' ' * indent, element.name, publicId, systemId)) + else: + rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name)) + else: + rv.append("|%s<!DOCTYPE >" % (' ' * indent,)) + elif element.nodeType == Node.DOCUMENT_NODE: + rv.append("#document") + elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE: + rv.append("#document-fragment") + elif element.nodeType == Node.COMMENT_NODE: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue)) + elif element.nodeType == Node.TEXT_NODE: + rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue)) + else: + if (hasattr(element, "namespaceURI") and + element.namespaceURI is not None): + name = "%s %s" % (constants.prefixes[element.namespaceURI], + element.nodeName) + else: + name = element.nodeName + rv.append("|%s<%s>" % (' ' * indent, name)) + if element.hasAttributes(): + attributes = [] + for i in range(len(element.attributes)): + attr = element.attributes.item(i) + name = attr.nodeName + value = attr.value + ns = attr.namespaceURI + if ns: + name = "%s %s" % (constants.prefixes[ns], attr.localName) + else: + name = attr.nodeName + attributes.append((name, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + indent += 2 + for child in element.childNodes: + serializeElement(child, indent) + serializeElement(element, 0) + + return "\n".join(rv) + + return locals() + + +# The actual means to get a module! +getDomModule = moduleFactoryFactory(getDomBuilder) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py new file mode 100755 index 0000000..9a4aa95 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py @@ -0,0 +1,340 @@ +from __future__ import absolute_import, division, unicode_literals +# pylint:disable=protected-access + +from pip._vendor.six import text_type + +import re + +from . import base +from .. import _ihatexml +from .. import constants +from ..constants import namespaces +from .._utils import moduleFactoryFactory + +tag_regexp = re.compile("{([^}]*)}(.*)") + + +def getETreeBuilder(ElementTreeImplementation, fullTree=False): + ElementTree = ElementTreeImplementation + ElementTreeCommentType = ElementTree.Comment("asd").tag + + class Element(base.Node): + def __init__(self, name, namespace=None): + self._name = name + self._namespace = namespace + self._element = ElementTree.Element(self._getETreeTag(name, + namespace)) + if namespace is None: + self.nameTuple = namespaces["html"], self._name + else: + self.nameTuple = self._namespace, self._name + self.parent = None + self._childNodes = [] + self._flags = [] + + def _getETreeTag(self, name, namespace): + if namespace is None: + etree_tag = name + else: + etree_tag = "{%s}%s" % (namespace, name) + return etree_tag + + def _setName(self, name): + self._name = name + self._element.tag = self._getETreeTag(self._name, self._namespace) + + def _getName(self): + return self._name + + name = property(_getName, _setName) + + def _setNamespace(self, namespace): + self._namespace = namespace + self._element.tag = self._getETreeTag(self._name, self._namespace) + + def _getNamespace(self): + return self._namespace + + namespace = property(_getNamespace, _setNamespace) + + def _getAttributes(self): + return self._element.attrib + + def _setAttributes(self, attributes): + # Delete existing attributes first + # XXX - there may be a better way to do this... + for key in list(self._element.attrib.keys()): + del self._element.attrib[key] + for key, value in attributes.items(): + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], key[1]) + else: + name = key + self._element.set(name, value) + + attributes = property(_getAttributes, _setAttributes) + + def _getChildNodes(self): + return self._childNodes + + def _setChildNodes(self, value): + del self._element[:] + self._childNodes = [] + for element in value: + self.insertChild(element) + + childNodes = property(_getChildNodes, _setChildNodes) + + def hasContent(self): + """Return true if the node has children or text""" + return bool(self._element.text or len(self._element)) + + def appendChild(self, node): + self._childNodes.append(node) + self._element.append(node._element) + node.parent = self + + def insertBefore(self, node, refNode): + index = list(self._element).index(refNode._element) + self._element.insert(index, node._element) + node.parent = self + + def removeChild(self, node): + self._childNodes.remove(node) + self._element.remove(node._element) + node.parent = None + + def insertText(self, data, insertBefore=None): + if not(len(self._element)): + if not self._element.text: + self._element.text = "" + self._element.text += data + elif insertBefore is None: + # Insert the text as the tail of the last child element + if not self._element[-1].tail: + self._element[-1].tail = "" + self._element[-1].tail += data + else: + # Insert the text before the specified node + children = list(self._element) + index = children.index(insertBefore._element) + if index > 0: + if not self._element[index - 1].tail: + self._element[index - 1].tail = "" + self._element[index - 1].tail += data + else: + if not self._element.text: + self._element.text = "" + self._element.text += data + + def cloneNode(self): + element = type(self)(self.name, self.namespace) + for name, value in self.attributes.items(): + element.attributes[name] = value + return element + + def reparentChildren(self, newParent): + if newParent.childNodes: + newParent.childNodes[-1]._element.tail += self._element.text + else: + if not newParent._element.text: + newParent._element.text = "" + if self._element.text is not None: + newParent._element.text += self._element.text + self._element.text = "" + base.Node.reparentChildren(self, newParent) + + class Comment(Element): + def __init__(self, data): + # Use the superclass constructor to set all properties on the + # wrapper element + self._element = ElementTree.Comment(data) + self.parent = None + self._childNodes = [] + self._flags = [] + + def _getData(self): + return self._element.text + + def _setData(self, value): + self._element.text = value + + data = property(_getData, _setData) + + class DocumentType(Element): + def __init__(self, name, publicId, systemId): + Element.__init__(self, "<!DOCTYPE>") + self._element.text = name + self.publicId = publicId + self.systemId = systemId + + def _getPublicId(self): + return self._element.get("publicId", "") + + def _setPublicId(self, value): + if value is not None: + self._element.set("publicId", value) + + publicId = property(_getPublicId, _setPublicId) + + def _getSystemId(self): + return self._element.get("systemId", "") + + def _setSystemId(self, value): + if value is not None: + self._element.set("systemId", value) + + systemId = property(_getSystemId, _setSystemId) + + class Document(Element): + def __init__(self): + Element.__init__(self, "DOCUMENT_ROOT") + + class DocumentFragment(Element): + def __init__(self): + Element.__init__(self, "DOCUMENT_FRAGMENT") + + def testSerializer(element): + rv = [] + + def serializeElement(element, indent=0): + if not(hasattr(element, "tag")): + element = element.getroot() + if element.tag == "<!DOCTYPE>": + if element.get("publicId") or element.get("systemId"): + publicId = element.get("publicId") or "" + systemId = element.get("systemId") or "" + rv.append("""<!DOCTYPE %s "%s" "%s">""" % + (element.text, publicId, systemId)) + else: + rv.append("<!DOCTYPE %s>" % (element.text,)) + elif element.tag == "DOCUMENT_ROOT": + rv.append("#document") + if element.text is not None: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + if element.tail is not None: + raise TypeError("Document node cannot have tail") + if hasattr(element, "attrib") and len(element.attrib): + raise TypeError("Document node cannot have attributes") + elif element.tag == ElementTreeCommentType: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.text)) + else: + assert isinstance(element.tag, text_type), \ + "Expected unicode, got %s, %s" % (type(element.tag), element.tag) + nsmatch = tag_regexp.match(element.tag) + + if nsmatch is None: + name = element.tag + else: + ns, name = nsmatch.groups() + prefix = constants.prefixes[ns] + name = "%s %s" % (prefix, name) + rv.append("|%s<%s>" % (' ' * indent, name)) + + if hasattr(element, "attrib"): + attributes = [] + for name, value in element.attrib.items(): + nsmatch = tag_regexp.match(name) + if nsmatch is not None: + ns, name = nsmatch.groups() + prefix = constants.prefixes[ns] + attr_string = "%s %s" % (prefix, name) + else: + attr_string = name + attributes.append((attr_string, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + if element.text: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + indent += 2 + for child in element: + serializeElement(child, indent) + if element.tail: + rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail)) + serializeElement(element, 0) + + return "\n".join(rv) + + def tostring(element): # pylint:disable=unused-variable + """Serialize an element and its child nodes to a string""" + rv = [] + filter = _ihatexml.InfosetFilter() + + def serializeElement(element): + if isinstance(element, ElementTree.ElementTree): + element = element.getroot() + + if element.tag == "<!DOCTYPE>": + if element.get("publicId") or element.get("systemId"): + publicId = element.get("publicId") or "" + systemId = element.get("systemId") or "" + rv.append("""<!DOCTYPE %s PUBLIC "%s" "%s">""" % + (element.text, publicId, systemId)) + else: + rv.append("<!DOCTYPE %s>" % (element.text,)) + elif element.tag == "DOCUMENT_ROOT": + if element.text is not None: + rv.append(element.text) + if element.tail is not None: + raise TypeError("Document node cannot have tail") + if hasattr(element, "attrib") and len(element.attrib): + raise TypeError("Document node cannot have attributes") + + for child in element: + serializeElement(child) + + elif element.tag == ElementTreeCommentType: + rv.append("<!--%s-->" % (element.text,)) + else: + # This is assumed to be an ordinary element + if not element.attrib: + rv.append("<%s>" % (filter.fromXmlName(element.tag),)) + else: + attr = " ".join(["%s=\"%s\"" % ( + filter.fromXmlName(name), value) + for name, value in element.attrib.items()]) + rv.append("<%s %s>" % (element.tag, attr)) + if element.text: + rv.append(element.text) + + for child in element: + serializeElement(child) + + rv.append("</%s>" % (element.tag,)) + + if element.tail: + rv.append(element.tail) + + serializeElement(element) + + return "".join(rv) + + class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable + documentClass = Document + doctypeClass = DocumentType + elementClass = Element + commentClass = Comment + fragmentClass = DocumentFragment + implementation = ElementTreeImplementation + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + if fullTree: + return self.document._element + else: + if self.defaultNamespace is not None: + return self.document._element.find( + "{%s}html" % self.defaultNamespace) + else: + return self.document._element.find("html") + + def getFragment(self): + return base.TreeBuilder.getFragment(self)._element + + return locals() + + +getETreeModule = moduleFactoryFactory(getETreeBuilder) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py new file mode 100755 index 0000000..66a9ba3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py @@ -0,0 +1,366 @@ +"""Module for supporting the lxml.etree library. The idea here is to use as much +of the native library as possible, without using fragile hacks like custom element +names that break between releases. The downside of this is that we cannot represent +all possible trees; specifically the following are known to cause problems: + +Text or comments as siblings of the root element +Docypes with no name + +When any of these things occur, we emit a DataLossWarning +""" + +from __future__ import absolute_import, division, unicode_literals +# pylint:disable=protected-access + +import warnings +import re +import sys + +from . import base +from ..constants import DataLossWarning +from .. import constants +from . import etree as etree_builders +from .. import _ihatexml + +import lxml.etree as etree + + +fullTree = True +tag_regexp = re.compile("{([^}]*)}(.*)") + +comment_type = etree.Comment("asd").tag + + +class DocumentType(object): + def __init__(self, name, publicId, systemId): + self.name = name + self.publicId = publicId + self.systemId = systemId + + +class Document(object): + def __init__(self): + self._elementTree = None + self._childNodes = [] + + def appendChild(self, element): + self._elementTree.getroot().addnext(element._element) + + def _getChildNodes(self): + return self._childNodes + + childNodes = property(_getChildNodes) + + +def testSerializer(element): + rv = [] + infosetFilter = _ihatexml.InfosetFilter(preventDoubleDashComments=True) + + def serializeElement(element, indent=0): + if not hasattr(element, "tag"): + if hasattr(element, "getroot"): + # Full tree case + rv.append("#document") + if element.docinfo.internalDTD: + if not (element.docinfo.public_id or + element.docinfo.system_url): + dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name + else: + dtd_str = """<!DOCTYPE %s "%s" "%s">""" % ( + element.docinfo.root_name, + element.docinfo.public_id, + element.docinfo.system_url) + rv.append("|%s%s" % (' ' * (indent + 2), dtd_str)) + next_element = element.getroot() + while next_element.getprevious() is not None: + next_element = next_element.getprevious() + while next_element is not None: + serializeElement(next_element, indent + 2) + next_element = next_element.getnext() + elif isinstance(element, str) or isinstance(element, bytes): + # Text in a fragment + assert isinstance(element, str) or sys.version_info[0] == 2 + rv.append("|%s\"%s\"" % (' ' * indent, element)) + else: + # Fragment case + rv.append("#document-fragment") + for next_element in element: + serializeElement(next_element, indent + 2) + elif element.tag == comment_type: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.text)) + if hasattr(element, "tail") and element.tail: + rv.append("|%s\"%s\"" % (' ' * indent, element.tail)) + else: + assert isinstance(element, etree._Element) + nsmatch = etree_builders.tag_regexp.match(element.tag) + if nsmatch is not None: + ns = nsmatch.group(1) + tag = nsmatch.group(2) + prefix = constants.prefixes[ns] + rv.append("|%s<%s %s>" % (' ' * indent, prefix, + infosetFilter.fromXmlName(tag))) + else: + rv.append("|%s<%s>" % (' ' * indent, + infosetFilter.fromXmlName(element.tag))) + + if hasattr(element, "attrib"): + attributes = [] + for name, value in element.attrib.items(): + nsmatch = tag_regexp.match(name) + if nsmatch is not None: + ns, name = nsmatch.groups() + name = infosetFilter.fromXmlName(name) + prefix = constants.prefixes[ns] + attr_string = "%s %s" % (prefix, name) + else: + attr_string = infosetFilter.fromXmlName(name) + attributes.append((attr_string, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + + if element.text: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + indent += 2 + for child in element: + serializeElement(child, indent) + if hasattr(element, "tail") and element.tail: + rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail)) + serializeElement(element, 0) + + return "\n".join(rv) + + +def tostring(element): + """Serialize an element and its child nodes to a string""" + rv = [] + + def serializeElement(element): + if not hasattr(element, "tag"): + if element.docinfo.internalDTD: + if element.docinfo.doctype: + dtd_str = element.docinfo.doctype + else: + dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name + rv.append(dtd_str) + serializeElement(element.getroot()) + + elif element.tag == comment_type: + rv.append("<!--%s-->" % (element.text,)) + + else: + # This is assumed to be an ordinary element + if not element.attrib: + rv.append("<%s>" % (element.tag,)) + else: + attr = " ".join(["%s=\"%s\"" % (name, value) + for name, value in element.attrib.items()]) + rv.append("<%s %s>" % (element.tag, attr)) + if element.text: + rv.append(element.text) + + for child in element: + serializeElement(child) + + rv.append("</%s>" % (element.tag,)) + + if hasattr(element, "tail") and element.tail: + rv.append(element.tail) + + serializeElement(element) + + return "".join(rv) + + +class TreeBuilder(base.TreeBuilder): + documentClass = Document + doctypeClass = DocumentType + elementClass = None + commentClass = None + fragmentClass = Document + implementation = etree + + def __init__(self, namespaceHTMLElements, fullTree=False): + builder = etree_builders.getETreeModule(etree, fullTree=fullTree) + infosetFilter = self.infosetFilter = _ihatexml.InfosetFilter(preventDoubleDashComments=True) + self.namespaceHTMLElements = namespaceHTMLElements + + class Attributes(dict): + def __init__(self, element, value=None): + if value is None: + value = {} + self._element = element + dict.__init__(self, value) # pylint:disable=non-parent-init-called + for key, value in self.items(): + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1])) + else: + name = infosetFilter.coerceAttribute(key) + self._element._element.attrib[name] = value + + def __setitem__(self, key, value): + dict.__setitem__(self, key, value) + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1])) + else: + name = infosetFilter.coerceAttribute(key) + self._element._element.attrib[name] = value + + class Element(builder.Element): + def __init__(self, name, namespace): + name = infosetFilter.coerceElement(name) + builder.Element.__init__(self, name, namespace=namespace) + self._attributes = Attributes(self) + + def _setName(self, name): + self._name = infosetFilter.coerceElement(name) + self._element.tag = self._getETreeTag( + self._name, self._namespace) + + def _getName(self): + return infosetFilter.fromXmlName(self._name) + + name = property(_getName, _setName) + + def _getAttributes(self): + return self._attributes + + def _setAttributes(self, attributes): + self._attributes = Attributes(self, attributes) + + attributes = property(_getAttributes, _setAttributes) + + def insertText(self, data, insertBefore=None): + data = infosetFilter.coerceCharacters(data) + builder.Element.insertText(self, data, insertBefore) + + def appendChild(self, child): + builder.Element.appendChild(self, child) + + class Comment(builder.Comment): + def __init__(self, data): + data = infosetFilter.coerceComment(data) + builder.Comment.__init__(self, data) + + def _setData(self, data): + data = infosetFilter.coerceComment(data) + self._element.text = data + + def _getData(self): + return self._element.text + + data = property(_getData, _setData) + + self.elementClass = Element + self.commentClass = Comment + # self.fragmentClass = builder.DocumentFragment + base.TreeBuilder.__init__(self, namespaceHTMLElements) + + def reset(self): + base.TreeBuilder.reset(self) + self.insertComment = self.insertCommentInitial + self.initial_comments = [] + self.doctype = None + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + if fullTree: + return self.document._elementTree + else: + return self.document._elementTree.getroot() + + def getFragment(self): + fragment = [] + element = self.openElements[0]._element + if element.text: + fragment.append(element.text) + fragment.extend(list(element)) + if element.tail: + fragment.append(element.tail) + return fragment + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + if not name: + warnings.warn("lxml cannot represent empty doctype", DataLossWarning) + self.doctype = None + else: + coercedName = self.infosetFilter.coerceElement(name) + if coercedName != name: + warnings.warn("lxml cannot represent non-xml doctype", DataLossWarning) + + doctype = self.doctypeClass(coercedName, publicId, systemId) + self.doctype = doctype + + def insertCommentInitial(self, data, parent=None): + assert parent is None or parent is self.document + assert self.document._elementTree is None + self.initial_comments.append(data) + + def insertCommentMain(self, data, parent=None): + if (parent == self.document and + self.document._elementTree.getroot()[-1].tag == comment_type): + warnings.warn("lxml cannot represent adjacent comments beyond the root elements", DataLossWarning) + super(TreeBuilder, self).insertComment(data, parent) + + def insertRoot(self, token): + # Because of the way libxml2 works, it doesn't seem to be possible to + # alter information like the doctype after the tree has been parsed. + # Therefore we need to use the built-in parser to create our initial + # tree, after which we can add elements like normal + docStr = "" + if self.doctype: + assert self.doctype.name + docStr += "<!DOCTYPE %s" % self.doctype.name + if (self.doctype.publicId is not None or + self.doctype.systemId is not None): + docStr += (' PUBLIC "%s" ' % + (self.infosetFilter.coercePubid(self.doctype.publicId or ""))) + if self.doctype.systemId: + sysid = self.doctype.systemId + if sysid.find("'") >= 0 and sysid.find('"') >= 0: + warnings.warn("DOCTYPE system cannot contain single and double quotes", DataLossWarning) + sysid = sysid.replace("'", 'U00027') + if sysid.find("'") >= 0: + docStr += '"%s"' % sysid + else: + docStr += "'%s'" % sysid + else: + docStr += "''" + docStr += ">" + if self.doctype.name != token["name"]: + warnings.warn("lxml cannot represent doctype with a different name to the root element", DataLossWarning) + docStr += "<THIS_SHOULD_NEVER_APPEAR_PUBLICLY/>" + root = etree.fromstring(docStr) + + # Append the initial comments: + for comment_token in self.initial_comments: + comment = self.commentClass(comment_token["data"]) + root.addprevious(comment._element) + + # Create the root document and add the ElementTree to it + self.document = self.documentClass() + self.document._elementTree = root.getroottree() + + # Give the root element the right name + name = token["name"] + namespace = token.get("namespace", self.defaultNamespace) + if namespace is None: + etree_tag = name + else: + etree_tag = "{%s}%s" % (namespace, name) + root.tag = etree_tag + + # Add the root element to the internal child/open data structures + root_element = self.elementClass(name, namespace) + root_element._element = root + self.document._childNodes.append(root_element) + self.openElements.append(root_element) + + # Reset to the default insert comment function + self.insertComment = self.insertCommentMain diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py new file mode 100755 index 0000000..31a173d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py @@ -0,0 +1,154 @@ +"""A collection of modules for iterating through different kinds of +tree, generating tokens identical to those produced by the tokenizer +module. + +To create a tree walker for a new type of tree, you need to do +implement a tree walker object (called TreeWalker by convention) that +implements a 'serialize' method taking a tree as sole argument and +returning an iterator generating tokens. +""" + +from __future__ import absolute_import, division, unicode_literals + +from .. import constants +from .._utils import default_etree + +__all__ = ["getTreeWalker", "pprint"] + +treeWalkerCache = {} + + +def getTreeWalker(treeType, implementation=None, **kwargs): + """Get a TreeWalker class for various types of tree with built-in support + + :arg str treeType: the name of the tree type required (case-insensitive). + Supported values are: + + * "dom": The xml.dom.minidom DOM implementation + * "etree": A generic walker for tree implementations exposing an + elementtree-like interface (known to work with ElementTree, + cElementTree and lxml.etree). + * "lxml": Optimized walker for lxml.etree + * "genshi": a Genshi stream + + :arg implementation: A module implementing the tree type e.g. + xml.etree.ElementTree or cElementTree (Currently applies to the "etree" + tree type only). + + :arg kwargs: keyword arguments passed to the etree walker--for other + walkers, this has no effect + + :returns: a TreeWalker class + + """ + + treeType = treeType.lower() + if treeType not in treeWalkerCache: + if treeType == "dom": + from . import dom + treeWalkerCache[treeType] = dom.TreeWalker + elif treeType == "genshi": + from . import genshi + treeWalkerCache[treeType] = genshi.TreeWalker + elif treeType == "lxml": + from . import etree_lxml + treeWalkerCache[treeType] = etree_lxml.TreeWalker + elif treeType == "etree": + from . import etree + if implementation is None: + implementation = default_etree + # XXX: NEVER cache here, caching is done in the etree submodule + return etree.getETreeModule(implementation, **kwargs).TreeWalker + return treeWalkerCache.get(treeType) + + +def concatenateCharacterTokens(tokens): + pendingCharacters = [] + for token in tokens: + type = token["type"] + if type in ("Characters", "SpaceCharacters"): + pendingCharacters.append(token["data"]) + else: + if pendingCharacters: + yield {"type": "Characters", "data": "".join(pendingCharacters)} + pendingCharacters = [] + yield token + if pendingCharacters: + yield {"type": "Characters", "data": "".join(pendingCharacters)} + + +def pprint(walker): + """Pretty printer for tree walkers + + Takes a TreeWalker instance and pretty prints the output of walking the tree. + + :arg walker: a TreeWalker instance + + """ + output = [] + indent = 0 + for token in concatenateCharacterTokens(walker): + type = token["type"] + if type in ("StartTag", "EmptyTag"): + # tag name + if token["namespace"] and token["namespace"] != constants.namespaces["html"]: + if token["namespace"] in constants.prefixes: + ns = constants.prefixes[token["namespace"]] + else: + ns = token["namespace"] + name = "%s %s" % (ns, token["name"]) + else: + name = token["name"] + output.append("%s<%s>" % (" " * indent, name)) + indent += 2 + # attributes (sorted for consistent ordering) + attrs = token["data"] + for (namespace, localname), value in sorted(attrs.items()): + if namespace: + if namespace in constants.prefixes: + ns = constants.prefixes[namespace] + else: + ns = namespace + name = "%s %s" % (ns, localname) + else: + name = localname + output.append("%s%s=\"%s\"" % (" " * indent, name, value)) + # self-closing + if type == "EmptyTag": + indent -= 2 + + elif type == "EndTag": + indent -= 2 + + elif type == "Comment": + output.append("%s<!-- %s -->" % (" " * indent, token["data"])) + + elif type == "Doctype": + if token["name"]: + if token["publicId"]: + output.append("""%s<!DOCTYPE %s "%s" "%s">""" % + (" " * indent, + token["name"], + token["publicId"], + token["systemId"] if token["systemId"] else "")) + elif token["systemId"]: + output.append("""%s<!DOCTYPE %s "" "%s">""" % + (" " * indent, + token["name"], + token["systemId"])) + else: + output.append("%s<!DOCTYPE %s>" % (" " * indent, + token["name"])) + else: + output.append("%s<!DOCTYPE >" % (" " * indent,)) + + elif type == "Characters": + output.append("%s\"%s\"" % (" " * indent, token["data"])) + + elif type == "SpaceCharacters": + assert False, "concatenateCharacterTokens should have got rid of all Space tokens" + + else: + raise ValueError("Unknown token type, %s" % type) + + return "\n".join(output) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py new file mode 100755 index 0000000..f82984b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py @@ -0,0 +1,252 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.dom import Node +from ..constants import namespaces, voidElements, spaceCharacters + +__all__ = ["DOCUMENT", "DOCTYPE", "TEXT", "ELEMENT", "COMMENT", "ENTITY", "UNKNOWN", + "TreeWalker", "NonRecursiveTreeWalker"] + +DOCUMENT = Node.DOCUMENT_NODE +DOCTYPE = Node.DOCUMENT_TYPE_NODE +TEXT = Node.TEXT_NODE +ELEMENT = Node.ELEMENT_NODE +COMMENT = Node.COMMENT_NODE +ENTITY = Node.ENTITY_NODE +UNKNOWN = "<#UNKNOWN#>" + +spaceCharacters = "".join(spaceCharacters) + + +class TreeWalker(object): + """Walks a tree yielding tokens + + Tokens are dicts that all have a ``type`` field specifying the type of the + token. + + """ + def __init__(self, tree): + """Creates a TreeWalker + + :arg tree: the tree to walk + + """ + self.tree = tree + + def __iter__(self): + raise NotImplementedError + + def error(self, msg): + """Generates an error token with the given message + + :arg msg: the error message + + :returns: SerializeError token + + """ + return {"type": "SerializeError", "data": msg} + + def emptyTag(self, namespace, name, attrs, hasChildren=False): + """Generates an EmptyTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :arg attrs: the attributes of the element as a dict + + :arg hasChildren: whether or not to yield a SerializationError because + this tag shouldn't have children + + :returns: EmptyTag token + + """ + yield {"type": "EmptyTag", "name": name, + "namespace": namespace, + "data": attrs} + if hasChildren: + yield self.error("Void element has children") + + def startTag(self, namespace, name, attrs): + """Generates a StartTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :arg attrs: the attributes of the element as a dict + + :returns: StartTag token + + """ + return {"type": "StartTag", + "name": name, + "namespace": namespace, + "data": attrs} + + def endTag(self, namespace, name): + """Generates an EndTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :returns: EndTag token + + """ + return {"type": "EndTag", + "name": name, + "namespace": namespace} + + def text(self, data): + """Generates SpaceCharacters and Characters tokens + + Depending on what's in the data, this generates one or more + ``SpaceCharacters`` and ``Characters`` tokens. + + For example: + + >>> from html5lib.treewalkers.base import TreeWalker + >>> # Give it an empty tree just so it instantiates + >>> walker = TreeWalker([]) + >>> list(walker.text('')) + [] + >>> list(walker.text(' ')) + [{u'data': ' ', u'type': u'SpaceCharacters'}] + >>> list(walker.text(' abc ')) # doctest: +NORMALIZE_WHITESPACE + [{u'data': ' ', u'type': u'SpaceCharacters'}, + {u'data': u'abc', u'type': u'Characters'}, + {u'data': u' ', u'type': u'SpaceCharacters'}] + + :arg data: the text data + + :returns: one or more ``SpaceCharacters`` and ``Characters`` tokens + + """ + data = data + middle = data.lstrip(spaceCharacters) + left = data[:len(data) - len(middle)] + if left: + yield {"type": "SpaceCharacters", "data": left} + data = middle + middle = data.rstrip(spaceCharacters) + right = data[len(middle):] + if middle: + yield {"type": "Characters", "data": middle} + if right: + yield {"type": "SpaceCharacters", "data": right} + + def comment(self, data): + """Generates a Comment token + + :arg data: the comment + + :returns: Comment token + + """ + return {"type": "Comment", "data": data} + + def doctype(self, name, publicId=None, systemId=None): + """Generates a Doctype token + + :arg name: + + :arg publicId: + + :arg systemId: + + :returns: the Doctype token + + """ + return {"type": "Doctype", + "name": name, + "publicId": publicId, + "systemId": systemId} + + def entity(self, name): + """Generates an Entity token + + :arg name: the entity name + + :returns: an Entity token + + """ + return {"type": "Entity", "name": name} + + def unknown(self, nodeType): + """Handles unknown node types""" + return self.error("Unknown node type: " + nodeType) + + +class NonRecursiveTreeWalker(TreeWalker): + def getNodeDetails(self, node): + raise NotImplementedError + + def getFirstChild(self, node): + raise NotImplementedError + + def getNextSibling(self, node): + raise NotImplementedError + + def getParentNode(self, node): + raise NotImplementedError + + def __iter__(self): + currentNode = self.tree + while currentNode is not None: + details = self.getNodeDetails(currentNode) + type, details = details[0], details[1:] + hasChildren = False + + if type == DOCTYPE: + yield self.doctype(*details) + + elif type == TEXT: + for token in self.text(*details): + yield token + + elif type == ELEMENT: + namespace, name, attributes, hasChildren = details + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + for token in self.emptyTag(namespace, name, attributes, + hasChildren): + yield token + hasChildren = False + else: + yield self.startTag(namespace, name, attributes) + + elif type == COMMENT: + yield self.comment(details[0]) + + elif type == ENTITY: + yield self.entity(details[0]) + + elif type == DOCUMENT: + hasChildren = True + + else: + yield self.unknown(details[0]) + + if hasChildren: + firstChild = self.getFirstChild(currentNode) + else: + firstChild = None + + if firstChild is not None: + currentNode = firstChild + else: + while currentNode is not None: + details = self.getNodeDetails(currentNode) + type, details = details[0], details[1:] + if type == ELEMENT: + namespace, name, attributes, hasChildren = details + if (namespace and namespace != namespaces["html"]) or name not in voidElements: + yield self.endTag(namespace, name) + if self.tree is currentNode: + currentNode = None + break + nextSibling = self.getNextSibling(currentNode) + if nextSibling is not None: + currentNode = nextSibling + break + else: + currentNode = self.getParentNode(currentNode) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py new file mode 100755 index 0000000..b3e2753 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.dom import Node + +from . import base + + +class TreeWalker(base.NonRecursiveTreeWalker): + def getNodeDetails(self, node): + if node.nodeType == Node.DOCUMENT_TYPE_NODE: + return base.DOCTYPE, node.name, node.publicId, node.systemId + + elif node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): + return base.TEXT, node.nodeValue + + elif node.nodeType == Node.ELEMENT_NODE: + attrs = {} + for attr in list(node.attributes.keys()): + attr = node.getAttributeNode(attr) + if attr.namespaceURI: + attrs[(attr.namespaceURI, attr.localName)] = attr.value + else: + attrs[(None, attr.name)] = attr.value + return (base.ELEMENT, node.namespaceURI, node.nodeName, + attrs, node.hasChildNodes()) + + elif node.nodeType == Node.COMMENT_NODE: + return base.COMMENT, node.nodeValue + + elif node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE): + return (base.DOCUMENT,) + + else: + return base.UNKNOWN, node.nodeType + + def getFirstChild(self, node): + return node.firstChild + + def getNextSibling(self, node): + return node.nextSibling + + def getParentNode(self, node): + return node.parentNode diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py new file mode 100755 index 0000000..1a35add --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import, division, unicode_literals + +from collections import OrderedDict +import re + +from pip._vendor.six import string_types + +from . import base +from .._utils import moduleFactoryFactory + +tag_regexp = re.compile("{([^}]*)}(.*)") + + +def getETreeBuilder(ElementTreeImplementation): + ElementTree = ElementTreeImplementation + ElementTreeCommentType = ElementTree.Comment("asd").tag + + class TreeWalker(base.NonRecursiveTreeWalker): # pylint:disable=unused-variable + """Given the particular ElementTree representation, this implementation, + to avoid using recursion, returns "nodes" as tuples with the following + content: + + 1. The current element + + 2. The index of the element relative to its parent + + 3. A stack of ancestor elements + + 4. A flag "text", "tail" or None to indicate if the current node is a + text node; either the text or tail of the current element (1) + """ + def getNodeDetails(self, node): + if isinstance(node, tuple): # It might be the root Element + elt, _, _, flag = node + if flag in ("text", "tail"): + return base.TEXT, getattr(elt, flag) + else: + node = elt + + if not(hasattr(node, "tag")): + node = node.getroot() + + if node.tag in ("DOCUMENT_ROOT", "DOCUMENT_FRAGMENT"): + return (base.DOCUMENT,) + + elif node.tag == "<!DOCTYPE>": + return (base.DOCTYPE, node.text, + node.get("publicId"), node.get("systemId")) + + elif node.tag == ElementTreeCommentType: + return base.COMMENT, node.text + + else: + assert isinstance(node.tag, string_types), type(node.tag) + # This is assumed to be an ordinary element + match = tag_regexp.match(node.tag) + if match: + namespace, tag = match.groups() + else: + namespace = None + tag = node.tag + attrs = OrderedDict() + for name, value in list(node.attrib.items()): + match = tag_regexp.match(name) + if match: + attrs[(match.group(1), match.group(2))] = value + else: + attrs[(None, name)] = value + return (base.ELEMENT, namespace, tag, + attrs, len(node) or node.text) + + def getFirstChild(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + element, key, parents, flag = node, None, [], None + + if flag in ("text", "tail"): + return None + else: + if element.text: + return element, key, parents, "text" + elif len(element): + parents.append(element) + return element[0], 0, parents, None + else: + return None + + def getNextSibling(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + return None + + if flag == "text": + if len(element): + parents.append(element) + return element[0], 0, parents, None + else: + return None + else: + if element.tail and flag != "tail": + return element, key, parents, "tail" + elif key < len(parents[-1]) - 1: + return parents[-1][key + 1], key + 1, parents, None + else: + return None + + def getParentNode(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + return None + + if flag == "text": + if not parents: + return element + else: + return element, key, parents, None + else: + parent = parents.pop() + if not parents: + return parent + else: + assert list(parents[-1]).count(parent) == 1 + return parent, list(parents[-1]).index(parent), parents, None + + return locals() + +getETreeModule = moduleFactoryFactory(getETreeBuilder) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py new file mode 100755 index 0000000..f6f395a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py @@ -0,0 +1,213 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from lxml import etree +from ..treebuilders.etree import tag_regexp + +from . import base + +from .. import _ihatexml + + +def ensure_str(s): + if s is None: + return None + elif isinstance(s, text_type): + return s + else: + return s.decode("ascii", "strict") + + +class Root(object): + def __init__(self, et): + self.elementtree = et + self.children = [] + + try: + if et.docinfo.internalDTD: + self.children.append(Doctype(self, + ensure_str(et.docinfo.root_name), + ensure_str(et.docinfo.public_id), + ensure_str(et.docinfo.system_url))) + except AttributeError: + pass + + try: + node = et.getroot() + except AttributeError: + node = et + + while node.getprevious() is not None: + node = node.getprevious() + while node is not None: + self.children.append(node) + node = node.getnext() + + self.text = None + self.tail = None + + def __getitem__(self, key): + return self.children[key] + + def getnext(self): + return None + + def __len__(self): + return 1 + + +class Doctype(object): + def __init__(self, root_node, name, public_id, system_id): + self.root_node = root_node + self.name = name + self.public_id = public_id + self.system_id = system_id + + self.text = None + self.tail = None + + def getnext(self): + return self.root_node.children[1] + + +class FragmentRoot(Root): + def __init__(self, children): + self.children = [FragmentWrapper(self, child) for child in children] + self.text = self.tail = None + + def getnext(self): + return None + + +class FragmentWrapper(object): + def __init__(self, fragment_root, obj): + self.root_node = fragment_root + self.obj = obj + if hasattr(self.obj, 'text'): + self.text = ensure_str(self.obj.text) + else: + self.text = None + if hasattr(self.obj, 'tail'): + self.tail = ensure_str(self.obj.tail) + else: + self.tail = None + + def __getattr__(self, name): + return getattr(self.obj, name) + + def getnext(self): + siblings = self.root_node.children + idx = siblings.index(self) + if idx < len(siblings) - 1: + return siblings[idx + 1] + else: + return None + + def __getitem__(self, key): + return self.obj[key] + + def __bool__(self): + return bool(self.obj) + + def getparent(self): + return None + + def __str__(self): + return str(self.obj) + + def __unicode__(self): + return str(self.obj) + + def __len__(self): + return len(self.obj) + + +class TreeWalker(base.NonRecursiveTreeWalker): + def __init__(self, tree): + # pylint:disable=redefined-variable-type + if isinstance(tree, list): + self.fragmentChildren = set(tree) + tree = FragmentRoot(tree) + else: + self.fragmentChildren = set() + tree = Root(tree) + base.NonRecursiveTreeWalker.__init__(self, tree) + self.filter = _ihatexml.InfosetFilter() + + def getNodeDetails(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + return base.TEXT, ensure_str(getattr(node, key)) + + elif isinstance(node, Root): + return (base.DOCUMENT,) + + elif isinstance(node, Doctype): + return base.DOCTYPE, node.name, node.public_id, node.system_id + + elif isinstance(node, FragmentWrapper) and not hasattr(node, "tag"): + return base.TEXT, ensure_str(node.obj) + + elif node.tag == etree.Comment: + return base.COMMENT, ensure_str(node.text) + + elif node.tag == etree.Entity: + return base.ENTITY, ensure_str(node.text)[1:-1] # strip &; + + else: + # This is assumed to be an ordinary element + match = tag_regexp.match(ensure_str(node.tag)) + if match: + namespace, tag = match.groups() + else: + namespace = None + tag = ensure_str(node.tag) + attrs = {} + for name, value in list(node.attrib.items()): + name = ensure_str(name) + value = ensure_str(value) + match = tag_regexp.match(name) + if match: + attrs[(match.group(1), match.group(2))] = value + else: + attrs[(None, name)] = value + return (base.ELEMENT, namespace, self.filter.fromXmlName(tag), + attrs, len(node) > 0 or node.text) + + def getFirstChild(self, node): + assert not isinstance(node, tuple), "Text nodes have no children" + + assert len(node) or node.text, "Node has no children" + if node.text: + return (node, "text") + else: + return node[0] + + def getNextSibling(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + if key == "text": + # XXX: we cannot use a "bool(node) and node[0] or None" construct here + # because node[0] might evaluate to False if it has no child element + if len(node): + return node[0] + else: + return None + else: # tail + return node.getnext() + + return (node, "tail") if node.tail else node.getnext() + + def getParentNode(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + if key == "text": + return node + # else: fallback to "normal" processing + elif node in self.fragmentChildren: + return None + + return node.getparent() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py new file mode 100755 index 0000000..42cd559 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py @@ -0,0 +1,69 @@ +from __future__ import absolute_import, division, unicode_literals + +from genshi.core import QName +from genshi.core import START, END, XML_NAMESPACE, DOCTYPE, TEXT +from genshi.core import START_NS, END_NS, START_CDATA, END_CDATA, PI, COMMENT + +from . import base + +from ..constants import voidElements, namespaces + + +class TreeWalker(base.TreeWalker): + def __iter__(self): + # Buffer the events so we can pass in the following one + previous = None + for event in self.tree: + if previous is not None: + for token in self.tokens(previous, event): + yield token + previous = event + + # Don't forget the final event! + if previous is not None: + for token in self.tokens(previous, None): + yield token + + def tokens(self, event, next): + kind, data, _ = event + if kind == START: + tag, attribs = data + name = tag.localname + namespace = tag.namespace + converted_attribs = {} + for k, v in attribs: + if isinstance(k, QName): + converted_attribs[(k.namespace, k.localname)] = v + else: + converted_attribs[(None, k)] = v + + if namespace == namespaces["html"] and name in voidElements: + for token in self.emptyTag(namespace, name, converted_attribs, + not next or next[0] != END or + next[1] != tag): + yield token + else: + yield self.startTag(namespace, name, converted_attribs) + + elif kind == END: + name = data.localname + namespace = data.namespace + if namespace != namespaces["html"] or name not in voidElements: + yield self.endTag(namespace, name) + + elif kind == COMMENT: + yield self.comment(data) + + elif kind == TEXT: + for token in self.text(data): + yield token + + elif kind == DOCTYPE: + yield self.doctype(*data) + + elif kind in (XML_NAMESPACE, DOCTYPE, START_NS, END_NS, + START_CDATA, END_CDATA, PI): + pass + + else: + yield self.unknown(kind) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py new file mode 100755 index 0000000..4ed56a1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py @@ -0,0 +1,2 @@ +from .package_data import __version__ +from .core import * diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/codec.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/codec.py new file mode 100755 index 0000000..65b06e2 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/compat.py new file mode 100755 index 0000000..f4d3f6d --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py new file mode 100755 index 0000000..944ff98 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py @@ -0,0 +1,387 @@ +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): + return unicodedata.combining(unichr(cp)) + +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 + break + 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']): + 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))) + 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') + try: + ulabel(label) + except IDNAError: + raise IDNAError('The label {0} is not a valid A-label'.format(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):] + 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 std3_rules and replacement is None)): + output += char + elif replacement is not None and (status == "M" or + (status == "3" and 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) + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if labels[-1] == '': + del labels[-1] + trailing_dot = True + for label in labels: + result.append(alabel(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'.') + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + result.append(ulabel(label)) + if trailing_dot: + result.append(u'') + return u'.'.join(result) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py new file mode 100755 index 0000000..c197a69 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py @@ -0,0 +1,1585 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "6.3.0" +scripts = { + 'Greek': ( + 0x37000000374, + 0x37500000378, + 0x37a0000037e, + 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, + 0x101400001018b, + 0x1d2000001d246, + ), + 'Han': ( + 0x2e8000002e9a, + 0x2e9b00002ef4, + 0x2f0000002fd6, + 0x300500003006, + 0x300700003008, + 0x30210000302a, + 0x30380000303c, + 0x340000004db6, + 0x4e0000009fcd, + 0xf9000000fa6e, + 0xfa700000fada, + 0x200000002a6d7, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2f8000002fa1e, + ), + 'Hebrew': ( + 0x591000005c8, + 0x5d0000005eb, + 0x5f0000005f5, + 0xfb1d0000fb37, + 0xfb380000fb3d, + 0xfb3e0000fb3f, + 0xfb400000fb42, + 0xfb430000fb45, + 0xfb460000fb50, + ), + 'Hiragana': ( + 0x304100003097, + 0x309d000030a0, + 0x1b0010001b002, + 0x1f2000001f201, + ), + 'Katakana': ( + 0x30a1000030fb, + 0x30fd00003100, + 0x31f000003200, + 0x32d0000032ff, + 0x330000003358, + 0xff660000ff70, + 0xff710000ff9e, + 0x1b0000001b001, + ), +} +joining_types = { + 0x600: 85, + 0x601: 85, + 0x602: 85, + 0x603: 85, + 0x604: 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, + 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: 68, + 0x848: 68, + 0x849: 82, + 0x84a: 68, + 0x84b: 68, + 0x84c: 68, + 0x84d: 68, + 0x84e: 68, + 0x84f: 82, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 85, + 0x857: 85, + 0x858: 85, + 0x8a0: 68, + 0x8a2: 68, + 0x8a3: 68, + 0x8a4: 68, + 0x8a5: 68, + 0x8a6: 68, + 0x8a7: 68, + 0x8a8: 68, + 0x8a9: 68, + 0x8aa: 82, + 0x8ab: 82, + 0x8ac: 82, + 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, + 0x1880: 85, + 0x1881: 85, + 0x1882: 85, + 0x1883: 85, + 0x1884: 85, + 0x1885: 85, + 0x1886: 85, + 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, + 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, +} +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, + 0x5590000055a, + 0x56100000587, + 0x591000005be, + 0x5bf000005c0, + 0x5c1000005c3, + 0x5c4000005c6, + 0x5c7000005c8, + 0x5d0000005eb, + 0x5f0000005f3, + 0x6100000061b, + 0x62000000640, + 0x64100000660, + 0x66e00000675, + 0x679000006d4, + 0x6d5000006dd, + 0x6df000006e9, + 0x6ea000006f0, + 0x6fa00000700, + 0x7100000074b, + 0x74d000007b2, + 0x7c0000007f6, + 0x8000000082e, + 0x8400000085c, + 0x8a0000008a1, + 0x8a2000008ad, + 0x8e4000008ff, + 0x90000000958, + 0x96000000964, + 0x96600000970, + 0x97100000978, + 0x97900000980, + 0x98100000984, + 0x9850000098d, + 0x98f00000991, + 0x993000009a9, + 0x9aa000009b1, + 0x9b2000009b3, + 0x9b6000009ba, + 0x9bc000009c5, + 0x9c7000009c9, + 0x9cb000009cf, + 0x9d7000009d8, + 0x9e0000009e4, + 0x9e6000009f2, + 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, + 0xb0100000b04, + 0xb0500000b0d, + 0xb0f00000b11, + 0xb1300000b29, + 0xb2a00000b31, + 0xb3200000b34, + 0xb3500000b3a, + 0xb3c00000b45, + 0xb4700000b49, + 0xb4b00000b4e, + 0xb5600000b58, + 0xb5f00000b64, + 0xb6600000b70, + 0xb7100000b72, + 0xb8200000b84, + 0xb8500000b8b, + 0xb8e00000b91, + 0xb9200000b96, + 0xb9900000b9b, + 0xb9c00000b9d, + 0xb9e00000ba0, + 0xba300000ba5, + 0xba800000bab, + 0xbae00000bba, + 0xbbe00000bc3, + 0xbc600000bc9, + 0xbca00000bce, + 0xbd000000bd1, + 0xbd700000bd8, + 0xbe600000bf0, + 0xc0100000c04, + 0xc0500000c0d, + 0xc0e00000c11, + 0xc1200000c29, + 0xc2a00000c34, + 0xc3500000c3a, + 0xc3d00000c45, + 0xc4600000c49, + 0xc4a00000c4e, + 0xc5500000c57, + 0xc5800000c5a, + 0xc6000000c64, + 0xc6600000c70, + 0xc8200000c84, + 0xc8500000c8d, + 0xc8e00000c91, + 0xc9200000ca9, + 0xcaa00000cb4, + 0xcb500000cba, + 0xcbc00000cc5, + 0xcc600000cc9, + 0xcca00000cce, + 0xcd500000cd7, + 0xcde00000cdf, + 0xce000000ce4, + 0xce600000cf0, + 0xcf100000cf3, + 0xd0200000d04, + 0xd0500000d0d, + 0xd0e00000d11, + 0xd1200000d3b, + 0xd3d00000d45, + 0xd4600000d49, + 0xd4a00000d4f, + 0xd5700000d58, + 0xd6000000d64, + 0xd6600000d70, + 0xd7a00000d80, + 0xd8200000d84, + 0xd8500000d97, + 0xd9a00000db2, + 0xdb300000dbc, + 0xdbd00000dbe, + 0xdc000000dc7, + 0xdca00000dcb, + 0xdcf00000dd5, + 0xdd600000dd7, + 0xdd800000de0, + 0xdf200000df4, + 0xe0100000e33, + 0xe3400000e3b, + 0xe4000000e4f, + 0xe5000000e5a, + 0xe8100000e83, + 0xe8400000e85, + 0xe8700000e89, + 0xe8a00000e8b, + 0xe8d00000e8e, + 0xe9400000e98, + 0xe9900000ea0, + 0xea100000ea4, + 0xea500000ea6, + 0xea700000ea8, + 0xeaa00000eac, + 0xead00000eb3, + 0xeb400000eba, + 0xebb00000ebe, + 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, + 0x13a0000013f5, + 0x14010000166d, + 0x166f00001680, + 0x16810000169b, + 0x16a0000016eb, + 0x17000000170d, + 0x170e00001715, + 0x172000001735, + 0x174000001754, + 0x17600000176d, + 0x176e00001771, + 0x177200001774, + 0x1780000017b4, + 0x17b6000017d4, + 0x17d7000017d8, + 0x17dc000017de, + 0x17e0000017ea, + 0x18100000181a, + 0x182000001878, + 0x1880000018ab, + 0x18b0000018f6, + 0x19000000191d, + 0x19200000192c, + 0x19300000193c, + 0x19460000196e, + 0x197000001975, + 0x1980000019ac, + 0x19b0000019ca, + 0x19d0000019da, + 0x1a0000001a1c, + 0x1a2000001a5f, + 0x1a6000001a7d, + 0x1a7f00001a8a, + 0x1a9000001a9a, + 0x1aa700001aa8, + 0x1b0000001b4c, + 0x1b5000001b5a, + 0x1b6b00001b74, + 0x1b8000001bf4, + 0x1c0000001c38, + 0x1c4000001c4a, + 0x1c4d00001c7e, + 0x1cd000001cd3, + 0x1cd400001cf7, + 0x1d0000001d2c, + 0x1d2f00001d30, + 0x1d3b00001d3c, + 0x1d4e00001d4f, + 0x1d6b00001d78, + 0x1d7900001d9b, + 0x1dc000001de7, + 0x1dfc00001e00, + 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, + 0x31050000312e, + 0x31a0000031bb, + 0x31f000003200, + 0x340000004db6, + 0x4e0000009fcd, + 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, + 0xa69f0000a6e6, + 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, + 0xa78e0000a78f, + 0xa7910000a792, + 0xa7930000a794, + 0xa7a10000a7a2, + 0xa7a30000a7a4, + 0xa7a50000a7a6, + 0xa7a70000a7a8, + 0xa7a90000a7aa, + 0xa7fa0000a828, + 0xa8400000a874, + 0xa8800000a8c5, + 0xa8d00000a8da, + 0xa8e00000a8f8, + 0xa8fb0000a8fc, + 0xa9000000a92e, + 0xa9300000a954, + 0xa9800000a9c1, + 0xa9cf0000a9da, + 0xaa000000aa37, + 0xaa400000aa4e, + 0xaa500000aa5a, + 0xaa600000aa77, + 0xaa7a0000aa7c, + 0xaa800000aac3, + 0xaadb0000aade, + 0xaae00000aaf0, + 0xaaf20000aaf7, + 0xab010000ab07, + 0xab090000ab0f, + 0xab110000ab17, + 0xab200000ab27, + 0xab280000ab2f, + 0xabc00000abeb, + 0xabec0000abee, + 0xabf00000abfa, + 0xac000000d7a4, + 0xfa0e0000fa10, + 0xfa110000fa12, + 0xfa130000fa15, + 0xfa1f0000fa20, + 0xfa210000fa22, + 0xfa230000fa25, + 0xfa270000fa2a, + 0xfb1e0000fb1f, + 0xfe200000fe27, + 0xfe730000fe74, + 0x100000001000c, + 0x1000d00010027, + 0x100280001003b, + 0x1003c0001003e, + 0x1003f0001004e, + 0x100500001005e, + 0x10080000100fb, + 0x101fd000101fe, + 0x102800001029d, + 0x102a0000102d1, + 0x103000001031f, + 0x1033000010341, + 0x103420001034a, + 0x103800001039e, + 0x103a0000103c4, + 0x103c8000103d0, + 0x104280001049e, + 0x104a0000104aa, + 0x1080000010806, + 0x1080800010809, + 0x1080a00010836, + 0x1083700010839, + 0x1083c0001083d, + 0x1083f00010856, + 0x1090000010916, + 0x109200001093a, + 0x10980000109b8, + 0x109be000109c0, + 0x10a0000010a04, + 0x10a0500010a07, + 0x10a0c00010a14, + 0x10a1500010a18, + 0x10a1900010a34, + 0x10a3800010a3b, + 0x10a3f00010a40, + 0x10a6000010a7d, + 0x10b0000010b36, + 0x10b4000010b56, + 0x10b6000010b73, + 0x10c0000010c49, + 0x1100000011047, + 0x1106600011070, + 0x11080000110bb, + 0x110d0000110e9, + 0x110f0000110fa, + 0x1110000011135, + 0x1113600011140, + 0x11180000111c5, + 0x111d0000111da, + 0x11680000116b8, + 0x116c0000116ca, + 0x120000001236f, + 0x130000001342f, + 0x1680000016a39, + 0x16f0000016f45, + 0x16f5000016f7f, + 0x16f8f00016fa0, + 0x1b0000001b002, + 0x200000002a6d7, + 0x2a7000002b735, + 0x2b7400002b81e, + ), + 'CONTEXTJ': ( + 0x200c0000200e, + ), + 'CONTEXTO': ( + 0xb7000000b8, + 0x37500000376, + 0x5f3000005f5, + 0x6600000066a, + 0x6f0000006fa, + 0x30fb000030fc, + ), +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/intranges.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/intranges.py new file mode 100755 index 0000000..8202be8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py new file mode 100755 index 0000000..3073271 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py @@ -0,0 +1,2 @@ +__version__ = '2.6' + diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py new file mode 100755 index 0000000..fa1d66a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py @@ -0,0 +1,7634 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "6.3.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, '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'ђ'), + (0x403, 'M', u'ѓ'), + ] + +def _seg_7(): + return [ + (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'), + (0x49E, 'M', u'ҟ'), + ] + +def _seg_8(): + return [ + (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'ԃ'), + (0x503, 'V'), + ] + +def _seg_9(): + return [ + (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, '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'), + (0x560, 'X'), + (0x561, 'V'), + (0x587, 'M', u'եւ'), + (0x588, 'X'), + (0x589, 'V'), + (0x58B, 'X'), + (0x58F, 'V'), + (0x590, 'X'), + (0x591, 'V'), + (0x5C8, 'X'), + (0x5D0, 'V'), + (0x5EB, 'X'), + (0x5F0, 'V'), + (0x5F5, 'X'), + (0x606, 'V'), + (0x61C, 'X'), + (0x61E, 'V'), + (0x675, 'M', u'اٴ'), + (0x676, 'M', u'وٴ'), + (0x677, 'M', u'ۇٴ'), + (0x678, 'M', u'يٴ'), + (0x679, 'V'), + (0x6DD, 'X'), + ] + +def _seg_10(): + return [ + (0x6DE, 'V'), + (0x70E, 'X'), + (0x710, 'V'), + (0x74B, 'X'), + (0x74D, 'V'), + (0x7B2, 'X'), + (0x7C0, 'V'), + (0x7FB, 'X'), + (0x800, 'V'), + (0x82E, 'X'), + (0x830, 'V'), + (0x83F, 'X'), + (0x840, 'V'), + (0x85C, 'X'), + (0x85E, 'V'), + (0x85F, 'X'), + (0x8A0, 'V'), + (0x8A1, 'X'), + (0x8A2, 'V'), + (0x8AD, 'X'), + (0x8E4, 'V'), + (0x8FF, 'X'), + (0x900, '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'), + (0x978, 'X'), + (0x979, 'V'), + (0x980, 'X'), + (0x981, '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'), + (0x9FC, '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'ਜ਼'), + (0xA5C, 'V'), + (0xA5D, 'X'), + (0xA5E, 'M', u'ਫ਼'), + (0xA5F, 'X'), + ] + +def _seg_11(): + return [ + (0xA66, 'V'), + (0xA76, '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'), + (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'), + (0xB56, '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'), + (0xC01, 'V'), + (0xC04, 'X'), + (0xC05, 'V'), + (0xC0D, 'X'), + (0xC0E, 'V'), + (0xC11, 'X'), + (0xC12, 'V'), + (0xC29, 'X'), + (0xC2A, 'V'), + (0xC34, 'X'), + (0xC35, 'V'), + ] + +def _seg_12(): + return [ + (0xC3A, 'X'), + (0xC3D, 'V'), + (0xC45, 'X'), + (0xC46, 'V'), + (0xC49, 'X'), + (0xC4A, 'V'), + (0xC4E, 'X'), + (0xC55, 'V'), + (0xC57, 'X'), + (0xC58, 'V'), + (0xC5A, 'X'), + (0xC60, 'V'), + (0xC64, 'X'), + (0xC66, 'V'), + (0xC70, 'X'), + (0xC78, 'V'), + (0xC80, 'X'), + (0xC82, 'V'), + (0xC84, 'X'), + (0xC85, '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'), + (0xD02, 'V'), + (0xD04, 'X'), + (0xD05, 'V'), + (0xD0D, 'X'), + (0xD0E, 'V'), + (0xD11, 'X'), + (0xD12, 'V'), + (0xD3B, 'X'), + (0xD3D, 'V'), + (0xD45, 'X'), + (0xD46, 'V'), + (0xD49, 'X'), + (0xD4A, 'V'), + (0xD4F, 'X'), + (0xD57, 'V'), + (0xD58, 'X'), + (0xD60, 'V'), + (0xD64, 'X'), + (0xD66, 'V'), + (0xD76, 'X'), + (0xD79, 'V'), + (0xD80, 'X'), + (0xD82, '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'), + (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'), + (0xE87, 'V'), + ] + +def _seg_13(): + return [ + (0xE89, 'X'), + (0xE8A, 'V'), + (0xE8B, 'X'), + (0xE8D, 'V'), + (0xE8E, 'X'), + (0xE94, 'V'), + (0xE98, 'X'), + (0xE99, 'V'), + (0xEA0, 'X'), + (0xEA1, 'V'), + (0xEA4, 'X'), + (0xEA5, 'V'), + (0xEA6, 'X'), + (0xEA7, 'V'), + (0xEA8, 'X'), + (0xEAA, 'V'), + (0xEAC, 'X'), + (0xEAD, 'V'), + (0xEB3, 'M', u'ໍາ'), + (0xEB4, 'V'), + (0xEBA, 'X'), + (0xEBB, 'V'), + (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'), + ] + +def _seg_14(): + return [ + (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'), + (0x1316, 'X'), + (0x1318, 'V'), + (0x135B, 'X'), + (0x135D, 'V'), + (0x137D, 'X'), + (0x1380, 'V'), + (0x139A, 'X'), + (0x13A0, 'V'), + (0x13F5, 'X'), + (0x1400, 'V'), + (0x1680, 'X'), + (0x1681, 'V'), + (0x169D, 'X'), + (0x16A0, 'V'), + (0x16F1, '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'), + (0x1878, 'X'), + (0x1880, 'V'), + (0x18AB, 'X'), + (0x18B0, 'V'), + (0x18F6, 'X'), + (0x1900, 'V'), + (0x191D, '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'), + ] + +def _seg_15(): + return [ + (0x1AA0, 'V'), + (0x1AAE, 'X'), + (0x1B00, 'V'), + (0x1B4C, 'X'), + (0x1B50, 'V'), + (0x1B7D, 'X'), + (0x1B80, 'V'), + (0x1BF4, 'X'), + (0x1BFC, 'V'), + (0x1C38, 'X'), + (0x1C3B, 'V'), + (0x1C4A, 'X'), + (0x1C4D, 'V'), + (0x1C80, 'X'), + (0x1CC0, 'V'), + (0x1CC8, 'X'), + (0x1CD0, 'V'), + (0x1CF7, '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'), + (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'ɭ'), + ] + +def _seg_16(): + return [ + (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'), + (0x1DE7, 'X'), + (0x1DFC, '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'ḡ'), + (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'ṋ'), + ] + +def _seg_17(): + return [ + (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'ẅ'), + (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'), + ] + +def _seg_18(): + return [ + (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'), + (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'ἥ'), + ] + +def _seg_19(): + return [ + (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'ἄι'), + (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'ὦι'), + ] + +def _seg_20(): + return [ + (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'ωι'), + (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'), + ] + +def _seg_21(): + return [ + (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'), + (0x20BB, 'X'), + (0x20D0, 'V'), + (0x20F1, 'X'), + (0x2100, '3', u'a/c'), + (0x2101, '3', u'a/s'), + (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'א'), + ] + +def _seg_22(): + return [ + (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'), + (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, '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'), + (0x23F4, 'X'), + (0x2400, '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'), + ] + +def _seg_23(): + return [ + (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'), + (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'), + ] + +def _seg_24(): + return [ + (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'), + (0x2700, 'X'), + (0x2701, 'V'), + (0x2A0C, 'M', u'∫∫∫∫'), + (0x2A0D, 'V'), + (0x2A74, '3', u'::='), + (0x2A75, '3', u'=='), + (0x2A76, '3', u'==='), + (0x2A77, 'V'), + (0x2ADC, 'M', u'⫝̸'), + (0x2ADD, 'V'), + (0x2B4D, 'X'), + (0x2B50, 'V'), + (0x2B5A, 'X'), + (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'ⱕ'), + (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'ⲃ'), + ] + +def _seg_25(): + return [ + (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'ⲿ'), + (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'ⳮ'), + ] + +def _seg_26(): + return [ + (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'), + (0x2E3C, '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'刀'), + (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'彐'), + ] + +def _seg_27(): + return [ + (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'竹'), + (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'身'), + ] + +def _seg_28(): + return [ + (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'.'), + (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'), + (0x312E, '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'ᄡ'), + ] + +def _seg_29(): + return [ + (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'ᅇ'), + (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'), + (0x31BB, 'X'), + (0x31C0, 'V'), + (0x31E4, 'X'), + (0x31F0, 'V'), + (0x3200, '3', u'(ᄀ)'), + (0x3201, '3', u'(ᄂ)'), + (0x3202, '3', u'(ᄃ)'), + (0x3203, '3', u'(ᄅ)'), + (0x3204, '3', u'(ᄆ)'), + ] + +def _seg_30(): + return [ + (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'(自)'), + (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'나'), + ] + +def _seg_31(): + return [ + (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'企'), + (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'エ'), + ] + +def _seg_32(): + return [ + (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, 'X'), + (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'ギニー'), + (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'ペソ'), + ] + +def _seg_33(): + return [ + (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'), + (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'), + ] + +def _seg_34(): + return [ + (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'), + (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'), + ] + +def _seg_35(): + return [ + (0x3400, 'V'), + (0x4DB6, 'X'), + (0x4DC0, 'V'), + (0x9FCD, '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'), + (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, 'X'), + (0xA69F, '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'), + ] + +def _seg_36(): + return [ + (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'ꝯ'), + (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'), + (0xA78F, 'X'), + (0xA790, 'M', u'ꞑ'), + (0xA791, 'V'), + (0xA792, 'M', u'ꞓ'), + (0xA793, 'V'), + (0xA794, 'X'), + (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, 'X'), + (0xA7F8, 'M', u'ħ'), + ] + +def _seg_37(): + return [ + (0xA7F9, 'M', u'œ'), + (0xA7FA, 'V'), + (0xA82C, 'X'), + (0xA830, 'V'), + (0xA83A, 'X'), + (0xA840, 'V'), + (0xA878, 'X'), + (0xA880, 'V'), + (0xA8C5, 'X'), + (0xA8CE, 'V'), + (0xA8DA, 'X'), + (0xA8E0, 'V'), + (0xA8FC, 'X'), + (0xA900, 'V'), + (0xA954, 'X'), + (0xA95F, 'V'), + (0xA97D, 'X'), + (0xA980, 'V'), + (0xA9CE, 'X'), + (0xA9CF, 'V'), + (0xA9DA, 'X'), + (0xA9DE, 'V'), + (0xA9E0, 'X'), + (0xAA00, 'V'), + (0xAA37, 'X'), + (0xAA40, 'V'), + (0xAA4E, 'X'), + (0xAA50, 'V'), + (0xAA5A, 'X'), + (0xAA5C, 'V'), + (0xAA7C, 'X'), + (0xAA80, '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'), + (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'來'), + ] + +def _seg_38(): + return [ + (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'漏'), + (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'撚'), + ] + +def _seg_39(): + return [ + (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'零'), + (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'淋'), + ] + +def _seg_40(): + return [ + (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'礼'), + (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'著'), + ] + +def _seg_41(): + return [ + (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'嬨'), + (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'醙'), + ] + +def _seg_42(): + return [ + (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'վն'), + (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'ڍ'), + ] + +def _seg_43(): + return [ + (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'ئۆ'), + (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'كي'), + ] + +def _seg_44(): + return [ + (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' ٍّ'), + (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'تح'), + ] + +def _seg_45(): + return [ + (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'قم'), + (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'صي'), + ] + +def _seg_46(): + return [ + (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'شخ'), + (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'محم'), + ] + +def _seg_47(): + return [ + (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'يحي'), + (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'), + (0xFE27, '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'》'), + ] + +def _seg_48(): + return [ + (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'='), + (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'"'), + ] + +def _seg_49(): + return [ + (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'), + (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'ヲ'), + ] + +def _seg_50(): + return [ + (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'ヌ'), + (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'ᅪ'), + ] + +def _seg_51(): + return [ + (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'), + (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'), + (0x1018B, 'X'), + (0x10190, 'V'), + (0x1019C, 'X'), + (0x101D0, 'V'), + (0x101FE, 'X'), + (0x10280, 'V'), + (0x1029D, 'X'), + (0x102A0, 'V'), + (0x102D1, 'X'), + (0x10300, 'V'), + (0x1031F, 'X'), + (0x10320, 'V'), + (0x10324, 'X'), + (0x10330, 'V'), + (0x1034B, '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'𐑅'), + ] + +def _seg_52(): + return [ + (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'), + (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'), + (0x10860, 'X'), + (0x10900, 'V'), + (0x1091C, 'X'), + (0x1091F, 'V'), + (0x1093A, 'X'), + (0x1093F, 'V'), + (0x10940, 'X'), + (0x10980, 'V'), + (0x109B8, 'X'), + (0x109BE, 'V'), + (0x109C0, 'X'), + (0x10A00, 'V'), + (0x10A04, 'X'), + (0x10A05, 'V'), + (0x10A07, 'X'), + (0x10A0C, 'V'), + (0x10A14, 'X'), + (0x10A15, 'V'), + (0x10A18, 'X'), + (0x10A19, 'V'), + (0x10A34, 'X'), + (0x10A38, 'V'), + (0x10A3B, 'X'), + (0x10A3F, 'V'), + (0x10A48, 'X'), + (0x10A50, 'V'), + (0x10A59, 'X'), + (0x10A60, 'V'), + (0x10A80, 'X'), + (0x10B00, 'V'), + (0x10B36, 'X'), + (0x10B39, 'V'), + (0x10B56, 'X'), + (0x10B58, 'V'), + (0x10B73, 'X'), + (0x10B78, 'V'), + (0x10B80, 'X'), + (0x10C00, 'V'), + (0x10C49, 'X'), + (0x10E60, 'V'), + (0x10E7F, 'X'), + (0x11000, 'V'), + (0x1104E, 'X'), + (0x11052, 'V'), + (0x11070, 'X'), + (0x11080, 'V'), + (0x110BD, 'X'), + (0x110BE, 'V'), + (0x110C2, 'X'), + (0x110D0, 'V'), + (0x110E9, 'X'), + (0x110F0, 'V'), + (0x110FA, 'X'), + (0x11100, 'V'), + (0x11135, 'X'), + (0x11136, 'V'), + (0x11144, 'X'), + (0x11180, 'V'), + (0x111C9, 'X'), + (0x111D0, 'V'), + (0x111DA, 'X'), + (0x11680, 'V'), + (0x116B8, 'X'), + (0x116C0, 'V'), + (0x116CA, 'X'), + (0x12000, 'V'), + (0x1236F, 'X'), + (0x12400, 'V'), + (0x12463, 'X'), + (0x12470, 'V'), + (0x12474, 'X'), + (0x13000, 'V'), + (0x1342F, 'X'), + ] + +def _seg_53(): + return [ + (0x16800, 'V'), + (0x16A39, 'X'), + (0x16F00, 'V'), + (0x16F45, 'X'), + (0x16F50, 'V'), + (0x16F7F, 'X'), + (0x16F8F, 'V'), + (0x16FA0, 'X'), + (0x1B000, 'V'), + (0x1B002, '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'), + (0x1D173, 'X'), + (0x1D17B, 'V'), + (0x1D1BB, 'M', u'𝆹𝅥'), + (0x1D1BC, 'M', u'𝆺𝅥'), + (0x1D1BD, 'M', u'𝆹𝅥𝅮'), + (0x1D1BE, 'M', u'𝆺𝅥𝅮'), + (0x1D1BF, 'M', u'𝆹𝅥𝅯'), + (0x1D1C0, 'M', u'𝆺𝅥𝅯'), + (0x1D1C1, 'V'), + (0x1D1DE, 'X'), + (0x1D200, 'V'), + (0x1D246, 'X'), + (0x1D300, 'V'), + (0x1D357, 'X'), + (0x1D360, 'V'), + (0x1D372, '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'), + ] + +def _seg_54(): + return [ + (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'), + (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'), + ] + +def _seg_55(): + return [ + (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'), + (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'), + ] + +def _seg_56(): + return [ + (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'), + (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'), + ] + +def _seg_57(): + return [ + (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'), + (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'), + ] + +def _seg_58(): + return [ + (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'), + (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'), + ] + +def _seg_59(): + return [ + (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'), + (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'), + ] + +def _seg_60(): + return [ + (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'ι'), + (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'ε'), + ] + +def _seg_61(): + return [ + (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'ε'), + (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'ρ'), + ] + +def _seg_62(): + return [ + (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'μ'), + (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'), + ] + +def _seg_63(): + return [ + (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'), + (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, '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'ق'), + ] + +def _seg_64(): + return [ + (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'ك'), + (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'), + ] + +def _seg_65(): + return [ + (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'), + (0x1F0BF, 'X'), + (0x1F0C1, 'V'), + (0x1F0D0, 'X'), + (0x1F0D1, 'V'), + (0x1F0E0, '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,'), + (0x1F109, '3', u'8,'), + (0x1F10A, '3', u'9,'), + (0x1F10B, 'X'), + (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, 'X'), + (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'), + ] + +def _seg_66(): + return [ + (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, 'X'), + (0x1F170, 'V'), + (0x1F190, 'M', u'dj'), + (0x1F191, 'V'), + (0x1F19B, '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'販'), + (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, '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'), + (0x1F300, 'V'), + (0x1F321, 'X'), + (0x1F330, 'V'), + (0x1F336, 'X'), + (0x1F337, 'V'), + (0x1F37D, 'X'), + (0x1F380, 'V'), + (0x1F394, 'X'), + (0x1F3A0, 'V'), + (0x1F3C5, 'X'), + (0x1F3C6, 'V'), + (0x1F3CB, 'X'), + (0x1F3E0, 'V'), + (0x1F3F1, 'X'), + (0x1F400, 'V'), + (0x1F43F, 'X'), + (0x1F440, 'V'), + ] + +def _seg_67(): + return [ + (0x1F441, 'X'), + (0x1F442, 'V'), + (0x1F4F8, 'X'), + (0x1F4F9, 'V'), + (0x1F4FD, 'X'), + (0x1F500, 'V'), + (0x1F53E, 'X'), + (0x1F540, 'V'), + (0x1F544, 'X'), + (0x1F550, 'V'), + (0x1F568, 'X'), + (0x1F5FB, 'V'), + (0x1F641, 'X'), + (0x1F645, 'V'), + (0x1F650, 'X'), + (0x1F680, 'V'), + (0x1F6C6, 'X'), + (0x1F700, 'V'), + (0x1F774, 'X'), + (0x20000, 'V'), + (0x2A6D7, 'X'), + (0x2A700, 'V'), + (0x2B735, 'X'), + (0x2B740, 'V'), + (0x2B81E, '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'圗'), + ] + +def _seg_68(): + return [ + (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'壷'), + (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'扝'), + ] + +def _seg_69(): + return [ + (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'㨮'), + (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'災'), + ] + +def _seg_70(): + return [ + (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'𤜵'), + (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'聰'), + ] + +def _seg_71(): + return [ + (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'辞'), + (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'郱'), + ] + +def _seg_72(): + return [ + (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'𨵷'), + (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'), + (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() +) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py new file mode 100755 index 0000000..6da8d93 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py @@ -0,0 +1,2419 @@ +# Copyright 2007 Google Inc. +# Licensed to PSF under a Contributor Agreement. + +"""A fast, lightweight IPv4/IPv6 manipulation library in Python. + +This library is used to create/poke/manipulate IPv4 and IPv6 addresses +and networks. + +""" + +from __future__ import unicode_literals + + +import itertools +import struct + +__version__ = '1.0.19' + +# Compatibility functions +_compat_int_types = (int,) +try: + _compat_int_types = (int, long) +except NameError: + pass +try: + _compat_str = unicode +except NameError: + _compat_str = str + assert bytes != str +if b'\0'[0] == 0: # Python 3 semantics + def _compat_bytes_to_byte_vals(byt): + return byt +else: + def _compat_bytes_to_byte_vals(byt): + return [struct.unpack(b'!B', b)[0] for b in byt] +try: + _compat_int_from_byte_vals = int.from_bytes +except AttributeError: + def _compat_int_from_byte_vals(bytvals, endianess): + assert endianess == 'big' + res = 0 + for bv in bytvals: + assert isinstance(bv, _compat_int_types) + res = (res << 8) + bv + return res + + +def _compat_to_bytes(intval, length, endianess): + assert isinstance(intval, _compat_int_types) + assert endianess == 'big' + if length == 4: + if intval < 0 or intval >= 2 ** 32: + raise struct.error("integer out of range for 'I' format code") + return struct.pack(b'!I', intval) + elif length == 16: + if intval < 0 or intval >= 2 ** 128: + raise struct.error("integer out of range for 'QQ' format code") + return struct.pack(b'!QQ', intval >> 64, intval & 0xffffffffffffffff) + else: + raise NotImplementedError() + + +if hasattr(int, 'bit_length'): + # Not int.bit_length , since that won't work in 2.7 where long exists + def _compat_bit_length(i): + return i.bit_length() +else: + def _compat_bit_length(i): + for res in itertools.count(): + if i >> res == 0: + return res + + +def _compat_range(start, end, step=1): + assert step > 0 + i = start + while i < end: + yield i + i += step + + +class _TotalOrderingMixin(object): + __slots__ = () + + # Helper that derives the other comparison operations from + # __lt__ and __eq__ + # We avoid functools.total_ordering because it doesn't handle + # NotImplemented correctly yet (http://bugs.python.org/issue10042) + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not equal + + def __lt__(self, other): + raise NotImplementedError + + def __le__(self, other): + less = self.__lt__(other) + if less is NotImplemented or not less: + return self.__eq__(other) + return less + + def __gt__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not (less or equal) + + def __ge__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + return not less + + +IPV4LENGTH = 32 +IPV6LENGTH = 128 + + +class AddressValueError(ValueError): + """A Value Error related to the address.""" + + +class NetmaskValueError(ValueError): + """A Value Error related to the netmask.""" + + +def ip_address(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Address or IPv6Address object. + + Raises: + ValueError: if the *address* passed isn't either a v4 or a v6 + address + + """ + try: + return IPv4Address(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Address(address) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % + address) + + +def ip_network(address, strict=True): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP network. Either IPv4 or + IPv6 networks may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Network or IPv6Network object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. Or if the network has host bits set. + + """ + try: + return IPv4Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 network. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % + address) + + +def ip_interface(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Interface or IPv6Interface object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. + + Notes: + The IPv?Interface classes describe an Address on a particular + Network, so they're basically a combination of both the Address + and Network classes. + + """ + try: + return IPv4Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + raise ValueError('%r does not appear to be an IPv4 or IPv6 interface' % + address) + + +def v4_int_to_packed(address): + """Represent an address as 4 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv4 IP address. + + Returns: + The integer address packed as 4 bytes in network (big-endian) order. + + Raises: + ValueError: If the integer is negative or too large to be an + IPv4 IP address. + + """ + try: + return _compat_to_bytes(address, 4, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv4") + + +def v6_int_to_packed(address): + """Represent an address as 16 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv6 IP address. + + Returns: + The integer address packed as 16 bytes in network (big-endian) order. + + """ + try: + return _compat_to_bytes(address, 16, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv6") + + +def _split_optional_netmask(address): + """Helper to split the netmask and raise AddressValueError if needed""" + addr = _compat_str(address).split('/') + if len(addr) > 2: + raise AddressValueError("Only one '/' permitted in %r" % address) + return addr + + +def _find_address_range(addresses): + """Find a sequence of sorted deduplicated IPv#Address. + + Args: + addresses: a list of IPv#Address objects. + + Yields: + A tuple containing the first and last IP addresses in the sequence. + + """ + it = iter(addresses) + first = last = next(it) + for ip in it: + if ip._ip != last._ip + 1: + yield first, last + first = ip + last = ip + yield first, last + + +def _count_righthand_zero_bits(number, bits): + """Count the number of zero bits on the right hand side. + + Args: + number: an integer. + bits: maximum number of bits to count. + + Returns: + The number of zero bits on the right hand side of the number. + + """ + if number == 0: + return bits + return min(bits, _compat_bit_length(~number & (number - 1))) + + +def summarize_address_range(first, last): + """Summarize a network range given the first and last IP addresses. + + Example: + >>> list(summarize_address_range(IPv4Address('192.0.2.0'), + ... IPv4Address('192.0.2.130'))) + ... #doctest: +NORMALIZE_WHITESPACE + [IPv4Network('192.0.2.0/25'), IPv4Network('192.0.2.128/31'), + IPv4Network('192.0.2.130/32')] + + Args: + first: the first IPv4Address or IPv6Address in the range. + last: the last IPv4Address or IPv6Address in the range. + + Returns: + An iterator of the summarized IPv(4|6) network objects. + + Raise: + TypeError: + If the first and last objects are not IP addresses. + If the first and last objects are not the same version. + ValueError: + If the last object is not greater than the first. + If the version of the first address is not 4 or 6. + + """ + if (not (isinstance(first, _BaseAddress) and + isinstance(last, _BaseAddress))): + raise TypeError('first and last must be IP addresses, not networks') + if first.version != last.version: + raise TypeError("%s and %s are not of the same version" % ( + first, last)) + if first > last: + raise ValueError('last IP address must be greater than first') + + if first.version == 4: + ip = IPv4Network + elif first.version == 6: + ip = IPv6Network + else: + raise ValueError('unknown IP version') + + ip_bits = first._max_prefixlen + first_int = first._ip + last_int = last._ip + while first_int <= last_int: + nbits = min(_count_righthand_zero_bits(first_int, ip_bits), + _compat_bit_length(last_int - first_int + 1) - 1) + net = ip((first_int, ip_bits - nbits)) + yield net + first_int += 1 << nbits + if first_int - 1 == ip._ALL_ONES: + break + + +def _collapse_addresses_internal(addresses): + """Loops through the addresses, collapsing concurrent netblocks. + + Example: + + ip1 = IPv4Network('192.0.2.0/26') + ip2 = IPv4Network('192.0.2.64/26') + ip3 = IPv4Network('192.0.2.128/26') + ip4 = IPv4Network('192.0.2.192/26') + + _collapse_addresses_internal([ip1, ip2, ip3, ip4]) -> + [IPv4Network('192.0.2.0/24')] + + This shouldn't be called directly; it is called via + collapse_addresses([]). + + Args: + addresses: A list of IPv4Network's or IPv6Network's + + Returns: + A list of IPv4Network's or IPv6Network's depending on what we were + passed. + + """ + # First merge + to_merge = list(addresses) + subnets = {} + while to_merge: + net = to_merge.pop() + supernet = net.supernet() + existing = subnets.get(supernet) + if existing is None: + subnets[supernet] = net + elif existing != net: + # Merge consecutive subnets + del subnets[supernet] + to_merge.append(supernet) + # Then iterate over resulting networks, skipping subsumed subnets + last = None + for net in sorted(subnets.values()): + if last is not None: + # Since they are sorted, + # last.network_address <= net.network_address is a given. + if last.broadcast_address >= net.broadcast_address: + continue + yield net + last = net + + +def collapse_addresses(addresses): + """Collapse a list of IP objects. + + Example: + collapse_addresses([IPv4Network('192.0.2.0/25'), + IPv4Network('192.0.2.128/25')]) -> + [IPv4Network('192.0.2.0/24')] + + Args: + addresses: An iterator of IPv4Network or IPv6Network objects. + + Returns: + An iterator of the collapsed IPv(4|6)Network objects. + + Raises: + TypeError: If passed a list of mixed version objects. + + """ + addrs = [] + ips = [] + nets = [] + + # split IP addresses and networks + for ip in addresses: + if isinstance(ip, _BaseAddress): + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + ips.append(ip) + elif ip._prefixlen == ip._max_prefixlen: + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + try: + ips.append(ip.ip) + except AttributeError: + ips.append(ip.network_address) + else: + if nets and nets[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, nets[-1])) + nets.append(ip) + + # sort and dedup + ips = sorted(set(ips)) + + # find consecutive address ranges in the sorted sequence and summarize them + if ips: + for first, last in _find_address_range(ips): + addrs.extend(summarize_address_range(first, last)) + + return _collapse_addresses_internal(addrs + nets) + + +def get_mixed_type_key(obj): + """Return a key suitable for sorting between networks and addresses. + + Address and Network objects are not sortable by default; they're + fundamentally different so the expression + + IPv4Address('192.0.2.0') <= IPv4Network('192.0.2.0/24') + + doesn't make any sense. There are some times however, where you may wish + to have ipaddress sort these for you anyway. If you need to do this, you + can use this function as the key= argument to sorted(). + + Args: + obj: either a Network or Address object. + Returns: + appropriate key. + + """ + if isinstance(obj, _BaseNetwork): + return obj._get_networks_key() + elif isinstance(obj, _BaseAddress): + return obj._get_address_key() + return NotImplemented + + +class _IPAddressBase(_TotalOrderingMixin): + + """The mother class.""" + + __slots__ = () + + @property + def exploded(self): + """Return the longhand version of the IP address as a string.""" + return self._explode_shorthand_ip_string() + + @property + def compressed(self): + """Return the shorthand version of the IP address as a string.""" + return _compat_str(self) + + @property + def reverse_pointer(self): + """The name of the reverse DNS pointer for the IP address, e.g.: + >>> ipaddress.ip_address("127.0.0.1").reverse_pointer + '1.0.0.127.in-addr.arpa' + >>> ipaddress.ip_address("2001:db8::1").reverse_pointer + '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa' + + """ + return self._reverse_pointer() + + @property + def version(self): + msg = '%200s has no version specified' % (type(self),) + raise NotImplementedError(msg) + + def _check_int_address(self, address): + if address < 0: + msg = "%d (< 0) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._version)) + if address > self._ALL_ONES: + msg = "%d (>= 2**%d) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._max_prefixlen, + self._version)) + + def _check_packed_address(self, address, expected_len): + address_len = len(address) + if address_len != expected_len: + msg = ( + '%r (len %d != %d) is not permitted as an IPv%d address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?') + raise AddressValueError(msg % (address, address_len, + expected_len, self._version)) + + @classmethod + def _ip_int_from_prefix(cls, prefixlen): + """Turn the prefix length into a bitwise netmask + + Args: + prefixlen: An integer, the prefix length. + + Returns: + An integer. + + """ + return cls._ALL_ONES ^ (cls._ALL_ONES >> prefixlen) + + @classmethod + def _prefix_from_ip_int(cls, ip_int): + """Return prefix length from the bitwise netmask. + + Args: + ip_int: An integer, the netmask in expanded bitwise format + + Returns: + An integer, the prefix length. + + Raises: + ValueError: If the input intermingles zeroes & ones + """ + trailing_zeroes = _count_righthand_zero_bits(ip_int, + cls._max_prefixlen) + prefixlen = cls._max_prefixlen - trailing_zeroes + leading_ones = ip_int >> trailing_zeroes + all_ones = (1 << prefixlen) - 1 + if leading_ones != all_ones: + byteslen = cls._max_prefixlen // 8 + details = _compat_to_bytes(ip_int, byteslen, 'big') + msg = 'Netmask pattern %r mixes zeroes & ones' + raise ValueError(msg % details) + return prefixlen + + @classmethod + def _report_invalid_netmask(cls, netmask_str): + msg = '%r is not a valid netmask' % netmask_str + raise NetmaskValueError(msg) + + @classmethod + def _prefix_from_prefix_string(cls, prefixlen_str): + """Return prefix length from a numeric string + + Args: + prefixlen_str: The string to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask + """ + # int allows a leading +/- as well as surrounding whitespace, + # so we ensure that isn't the case + if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str): + cls._report_invalid_netmask(prefixlen_str) + try: + prefixlen = int(prefixlen_str) + except ValueError: + cls._report_invalid_netmask(prefixlen_str) + if not (0 <= prefixlen <= cls._max_prefixlen): + cls._report_invalid_netmask(prefixlen_str) + return prefixlen + + @classmethod + def _prefix_from_ip_string(cls, ip_str): + """Turn a netmask/hostmask string into a prefix length + + Args: + ip_str: The netmask/hostmask to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask/hostmask + """ + # Parse the netmask/hostmask like an IP address. + try: + ip_int = cls._ip_int_from_string(ip_str) + except AddressValueError: + cls._report_invalid_netmask(ip_str) + + # Try matching a netmask (this would be /1*0*/ as a bitwise regexp). + # Note that the two ambiguous cases (all-ones and all-zeroes) are + # treated as netmasks. + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + pass + + # Invert the bits, and try matching a /0+1+/ hostmask instead. + ip_int ^= cls._ALL_ONES + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + cls._report_invalid_netmask(ip_str) + + def __reduce__(self): + return self.__class__, (_compat_str(self),) + + +class _BaseAddress(_IPAddressBase): + + """A generic IP object. + + This IP class contains the version independent methods which are + used by single IP addresses. + """ + + __slots__ = () + + def __int__(self): + return self._ip + + def __eq__(self, other): + try: + return (self._ip == other._ip and + self._version == other._version) + except AttributeError: + return NotImplemented + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseAddress): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self._ip != other._ip: + return self._ip < other._ip + return False + + # Shorthand for Integer addition and subtraction. This is not + # meant to ever support addition/subtraction of addresses. + def __add__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) + other) + + def __sub__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) - other) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return _compat_str(self._string_from_ip_int(self._ip)) + + def __hash__(self): + return hash(hex(int(self._ip))) + + def _get_address_key(self): + return (self._version, self) + + def __reduce__(self): + return self.__class__, (self._ip,) + + +class _BaseNetwork(_IPAddressBase): + + """A generic IP network object. + + This IP class contains the version independent methods which are + used by networks. + + """ + def __init__(self, address): + self._cache = {} + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return '%s/%d' % (self.network_address, self.prefixlen) + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the network + or broadcast addresses. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast): + yield self._address_class(x) + + def __iter__(self): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network, broadcast + 1): + yield self._address_class(x) + + def __getitem__(self, n): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + if n >= 0: + if network + n > broadcast: + raise IndexError('address out of range') + return self._address_class(network + n) + else: + n += 1 + if broadcast + n < network: + raise IndexError('address out of range') + return self._address_class(broadcast + n) + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseNetwork): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self.network_address != other.network_address: + return self.network_address < other.network_address + if self.netmask != other.netmask: + return self.netmask < other.netmask + return False + + def __eq__(self, other): + try: + return (self._version == other._version and + self.network_address == other.network_address and + int(self.netmask) == int(other.netmask)) + except AttributeError: + return NotImplemented + + def __hash__(self): + return hash(int(self.network_address) ^ int(self.netmask)) + + def __contains__(self, other): + # always false if one is v4 and the other is v6. + if self._version != other._version: + return False + # dealing with another network. + if isinstance(other, _BaseNetwork): + return False + # dealing with another address + else: + # address + return (int(self.network_address) <= int(other._ip) <= + int(self.broadcast_address)) + + def overlaps(self, other): + """Tell if self is partly contained in other.""" + return self.network_address in other or ( + self.broadcast_address in other or ( + other.network_address in self or ( + other.broadcast_address in self))) + + @property + def broadcast_address(self): + x = self._cache.get('broadcast_address') + if x is None: + x = self._address_class(int(self.network_address) | + int(self.hostmask)) + self._cache['broadcast_address'] = x + return x + + @property + def hostmask(self): + x = self._cache.get('hostmask') + if x is None: + x = self._address_class(int(self.netmask) ^ self._ALL_ONES) + self._cache['hostmask'] = x + return x + + @property + def with_prefixlen(self): + return '%s/%d' % (self.network_address, self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self.network_address, self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self.network_address, self.hostmask) + + @property + def num_addresses(self): + """Number of hosts in the current subnet.""" + return int(self.broadcast_address) - int(self.network_address) + 1 + + @property + def _address_class(self): + # Returning bare address objects (rather than interfaces) allows for + # more consistent behaviour across the network address, broadcast + # address and individual host addresses. + msg = '%200s has no associated address class' % (type(self),) + raise NotImplementedError(msg) + + @property + def prefixlen(self): + return self._prefixlen + + def address_exclude(self, other): + """Remove an address from a larger block. + + For example: + + addr1 = ip_network('192.0.2.0/28') + addr2 = ip_network('192.0.2.1/32') + list(addr1.address_exclude(addr2)) = + [IPv4Network('192.0.2.0/32'), IPv4Network('192.0.2.2/31'), + IPv4Network('192.0.2.4/30'), IPv4Network('192.0.2.8/29')] + + or IPv6: + + addr1 = ip_network('2001:db8::1/32') + addr2 = ip_network('2001:db8::1/128') + list(addr1.address_exclude(addr2)) = + [ip_network('2001:db8::1/128'), + ip_network('2001:db8::2/127'), + ip_network('2001:db8::4/126'), + ip_network('2001:db8::8/125'), + ... + ip_network('2001:db8:8000::/33')] + + Args: + other: An IPv4Network or IPv6Network object of the same type. + + Returns: + An iterator of the IPv(4|6)Network objects which is self + minus other. + + Raises: + TypeError: If self and other are of differing address + versions, or if other is not a network object. + ValueError: If other is not completely contained by self. + + """ + if not self._version == other._version: + raise TypeError("%s and %s are not of the same version" % ( + self, other)) + + if not isinstance(other, _BaseNetwork): + raise TypeError("%s is not a network object" % other) + + if not other.subnet_of(self): + raise ValueError('%s not contained in %s' % (other, self)) + if other == self: + return + + # Make sure we're comparing the network of other. + other = other.__class__('%s/%s' % (other.network_address, + other.prefixlen)) + + s1, s2 = self.subnets() + while s1 != other and s2 != other: + if other.subnet_of(s1): + yield s2 + s1, s2 = s1.subnets() + elif other.subnet_of(s2): + yield s1 + s1, s2 = s2.subnets() + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + if s1 == other: + yield s2 + elif s2 == other: + yield s1 + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + + def compare_networks(self, other): + """Compare two IP objects. + + This is only concerned about the comparison of the integer + representation of the network addresses. This means that the + host bits aren't considered at all in this method. If you want + to compare host bits, you can easily enough do a + 'HostA._ip < HostB._ip' + + Args: + other: An IP object. + + Returns: + If the IP versions of self and other are the same, returns: + + -1 if self < other: + eg: IPv4Network('192.0.2.0/25') < IPv4Network('192.0.2.128/25') + IPv6Network('2001:db8::1000/124') < + IPv6Network('2001:db8::2000/124') + 0 if self == other + eg: IPv4Network('192.0.2.0/24') == IPv4Network('192.0.2.0/24') + IPv6Network('2001:db8::1000/124') == + IPv6Network('2001:db8::1000/124') + 1 if self > other + eg: IPv4Network('192.0.2.128/25') > IPv4Network('192.0.2.0/25') + IPv6Network('2001:db8::2000/124') > + IPv6Network('2001:db8::1000/124') + + Raises: + TypeError if the IP versions are different. + + """ + # does this need to raise a ValueError? + if self._version != other._version: + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + # self._version == other._version below here: + if self.network_address < other.network_address: + return -1 + if self.network_address > other.network_address: + return 1 + # self.network_address == other.network_address below here: + if self.netmask < other.netmask: + return -1 + if self.netmask > other.netmask: + return 1 + return 0 + + def _get_networks_key(self): + """Network-only key function. + + Returns an object that identifies this address' network and + netmask. This function is a suitable "key" argument for sorted() + and list.sort(). + + """ + return (self._version, self.network_address, self.netmask) + + def subnets(self, prefixlen_diff=1, new_prefix=None): + """The subnets which join to make the current subnet. + + In the case that self contains only one IP + (self._prefixlen == 32 for IPv4 or self._prefixlen == 128 + for IPv6), yield an iterator with just ourself. + + Args: + prefixlen_diff: An integer, the amount the prefix length + should be increased by. This should not be set if + new_prefix is also set. + new_prefix: The desired new prefix length. This must be a + larger number (smaller prefix) than the existing prefix. + This should not be set if prefixlen_diff is also set. + + Returns: + An iterator of IPv(4|6) objects. + + Raises: + ValueError: The prefixlen_diff is too small or too large. + OR + prefixlen_diff and new_prefix are both set or new_prefix + is a smaller number than the current prefix (smaller + number means a larger network) + + """ + if self._prefixlen == self._max_prefixlen: + yield self + return + + if new_prefix is not None: + if new_prefix < self._prefixlen: + raise ValueError('new prefix must be longer') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = new_prefix - self._prefixlen + + if prefixlen_diff < 0: + raise ValueError('prefix length diff must be > 0') + new_prefixlen = self._prefixlen + prefixlen_diff + + if new_prefixlen > self._max_prefixlen: + raise ValueError( + 'prefix length diff %d is invalid for netblock %s' % ( + new_prefixlen, self)) + + start = int(self.network_address) + end = int(self.broadcast_address) + 1 + step = (int(self.hostmask) + 1) >> prefixlen_diff + for new_addr in _compat_range(start, end, step): + current = self.__class__((new_addr, new_prefixlen)) + yield current + + def supernet(self, prefixlen_diff=1, new_prefix=None): + """The supernet containing the current network. + + Args: + prefixlen_diff: An integer, the amount the prefix length of + the network should be decreased by. For example, given a + /24 network and a prefixlen_diff of 3, a supernet with a + /21 netmask is returned. + + Returns: + An IPv4 network object. + + Raises: + ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have + a negative prefix length. + OR + If prefixlen_diff and new_prefix are both set or new_prefix is a + larger number than the current prefix (larger number means a + smaller network) + + """ + if self._prefixlen == 0: + return self + + if new_prefix is not None: + if new_prefix > self._prefixlen: + raise ValueError('new prefix must be shorter') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = self._prefixlen - new_prefix + + new_prefixlen = self.prefixlen - prefixlen_diff + if new_prefixlen < 0: + raise ValueError( + 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % + (self.prefixlen, prefixlen_diff)) + return self.__class__(( + int(self.network_address) & (int(self.netmask) << prefixlen_diff), + new_prefixlen)) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return (self.network_address.is_multicast and + self.broadcast_address.is_multicast) + + @staticmethod + def _is_subnet_of(a, b): + try: + # Always false if one is v4 and the other is v6. + if a._version != b._version: + raise TypeError("%s and %s are not of the same version" (a, b)) + return (b.network_address <= a.network_address and + b.broadcast_address >= a.broadcast_address) + except AttributeError: + raise TypeError("Unable to test subnet containment " + "between %s and %s" % (a, b)) + + def subnet_of(self, other): + """Return True if this network is a subnet of other.""" + return self._is_subnet_of(self, other) + + def supernet_of(self, other): + """Return True if this network is a supernet of other.""" + return self._is_subnet_of(other, self) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return (self.network_address.is_reserved and + self.broadcast_address.is_reserved) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return (self.network_address.is_link_local and + self.broadcast_address.is_link_local) + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return (self.network_address.is_private and + self.broadcast_address.is_private) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return (self.network_address.is_unspecified and + self.broadcast_address.is_unspecified) + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return (self.network_address.is_loopback and + self.broadcast_address.is_loopback) + + +class _BaseV4(object): + + """Base IPv4 object. + + The following methods are used by IPv4 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 4 + # Equivalent to 255.255.255.255 or 32 bits of 1's. + _ALL_ONES = (2 ** IPV4LENGTH) - 1 + _DECIMAL_DIGITS = frozenset('0123456789') + + # the valid octets for host and netmasks. only useful for IPv4. + _valid_mask_octets = frozenset([255, 254, 252, 248, 240, 224, 192, 128, 0]) + + _max_prefixlen = IPV4LENGTH + # There are only a handful of valid v4 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + def _explode_shorthand_ip_string(self): + return _compat_str(self) + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + try: + # Check for a netmask in prefix length form + prefixlen = cls._prefix_from_prefix_string(arg) + except NetmaskValueError: + # Check for a netmask or hostmask in dotted-quad form. + # This may raise NetmaskValueError. + prefixlen = cls._prefix_from_ip_string(arg) + netmask = IPv4Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn the given IP string into an integer for comparison. + + Args: + ip_str: A string, the IP ip_str. + + Returns: + The IP ip_str as an integer. + + Raises: + AddressValueError: if ip_str isn't a valid IPv4 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + octets = ip_str.split('.') + if len(octets) != 4: + raise AddressValueError("Expected 4 octets in %r" % ip_str) + + try: + return _compat_int_from_byte_vals( + map(cls._parse_octet, octets), 'big') + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_octet(cls, octet_str): + """Convert a decimal octet into an integer. + + Args: + octet_str: A string, the number to parse. + + Returns: + The octet as an integer. + + Raises: + ValueError: if the octet isn't strictly a decimal from [0..255]. + + """ + if not octet_str: + raise ValueError("Empty octet not permitted") + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._DECIMAL_DIGITS.issuperset(octet_str): + msg = "Only decimal digits permitted in %r" + raise ValueError(msg % octet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(octet_str) > 3: + msg = "At most 3 characters permitted in %r" + raise ValueError(msg % octet_str) + # Convert to integer (we know digits are legal) + octet_int = int(octet_str, 10) + # Any octets that look like they *might* be written in octal, + # and which don't look exactly the same in both octal and + # decimal are rejected as ambiguous + if octet_int > 7 and octet_str[0] == '0': + msg = "Ambiguous (octal/decimal) value in %r not permitted" + raise ValueError(msg % octet_str) + if octet_int > 255: + raise ValueError("Octet %d (> 255) not permitted" % octet_int) + return octet_int + + @classmethod + def _string_from_ip_int(cls, ip_int): + """Turns a 32-bit integer into dotted decimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + The IP address as a string in dotted decimal notation. + + """ + return '.'.join(_compat_str(struct.unpack(b'!B', b)[0] + if isinstance(b, bytes) + else b) + for b in _compat_to_bytes(ip_int, 4, 'big')) + + def _is_hostmask(self, ip_str): + """Test if the IP string is a hostmask (rather than a netmask). + + Args: + ip_str: A string, the potential hostmask. + + Returns: + A boolean, True if the IP string is a hostmask. + + """ + bits = ip_str.split('.') + try: + parts = [x for x in map(int, bits) if x in self._valid_mask_octets] + except ValueError: + return False + if len(parts) != len(bits): + return False + if parts[0] < parts[-1]: + return True + return False + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv4 address. + + This implements the method described in RFC1035 3.5. + + """ + reverse_octets = _compat_str(self).split('.')[::-1] + return '.'.join(reverse_octets) + '.in-addr.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv4Address(_BaseV4, _BaseAddress): + + """Represent and manipulate single IPv4 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + + """ + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv4Address('192.0.2.1') == IPv4Address(3221225985). + or, more generally + IPv4Address(int(IPv4Address('192.0.2.1'))) == + IPv4Address('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 4) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v4_int_to_packed(self._ip) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within the + reserved IPv4 Network range. + + """ + return self in self._constants._reserved_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + return ( + self not in self._constants._public_network and + not self.is_private) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is multicast. + See RFC 3171 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 5735 3. + + """ + return self == self._constants._unspecified_address + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback per RFC 3330. + + """ + return self in self._constants._loopback_network + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is link-local per RFC 3927. + + """ + return self in self._constants._linklocal_network + + +class IPv4Interface(IPv4Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv4Address.__init__(self, address) + self.network = IPv4Network(self._ip) + self._prefixlen = self._max_prefixlen + return + + if isinstance(address, tuple): + IPv4Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + + self.network = IPv4Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv4Address.__init__(self, addr[0]) + + self.network = IPv4Network(address, strict=False) + self._prefixlen = self.network._prefixlen + + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv4Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv4Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv4Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + +class IPv4Network(_BaseV4, _BaseNetwork): + + """This class represents and manipulates 32-bit IPv4 network + addresses.. + + Attributes: [examples for IPv4Network('192.0.2.0/27')] + .network_address: IPv4Address('192.0.2.0') + .hostmask: IPv4Address('0.0.0.31') + .broadcast_address: IPv4Address('192.0.2.32') + .netmask: IPv4Address('255.255.255.224') + .prefixlen: 27 + + """ + # Class to use when creating address objects + _address_class = IPv4Address + + def __init__(self, address, strict=True): + + """Instantiate a new IPv4 network object. + + Args: + address: A string or integer representing the IP [& network]. + '192.0.2.0/24' + '192.0.2.0/255.255.255.0' + '192.0.0.2/0.0.0.255' + are all functionally the same in IPv4. Similarly, + '192.0.2.1' + '192.0.2.1/255.255.255.255' + '192.0.2.1/32' + are also functionally equivalent. That is to say, failing to + provide a subnetmask will create an object with a mask of /32. + + If the mask (portion after the / in the argument) is given in + dotted quad form, it is treated as a netmask if it starts with a + non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it + starts with a zero field (e.g. 0.255.255.255 == /8), with the + single exception of an all-zero mask which is treated as a + netmask == /0. If no mask is given, a default of /32 is used. + + Additionally, an integer can be passed, so + IPv4Network('192.0.2.1') == IPv4Network(3221225985) + or, more generally + IPv4Interface(int(IPv4Interface('192.0.2.1'))) == + IPv4Interface('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + NetmaskValueError: If the netmask isn't valid for + an IPv4 address. + ValueError: If strict is True and a network address is not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Constructing from a packed address or integer + if isinstance(address, (_compat_int_types, bytes)): + self.network_address = IPv4Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + # fixme: address/network test here. + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + # We weren't given an address[1] + arg = self._max_prefixlen + self.network_address = IPv4Address(address[0]) + self.netmask, self._prefixlen = self._make_netmask(arg) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv4Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + self.network_address = IPv4Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv4Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv4Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry. + + """ + return (not (self.network_address in IPv4Network('100.64.0.0/10') and + self.broadcast_address in IPv4Network('100.64.0.0/10')) and + not self.is_private) + + +class _IPv4Constants(object): + + _linklocal_network = IPv4Network('169.254.0.0/16') + + _loopback_network = IPv4Network('127.0.0.0/8') + + _multicast_network = IPv4Network('224.0.0.0/4') + + _public_network = IPv4Network('100.64.0.0/10') + + _private_networks = [ + IPv4Network('0.0.0.0/8'), + IPv4Network('10.0.0.0/8'), + IPv4Network('127.0.0.0/8'), + IPv4Network('169.254.0.0/16'), + IPv4Network('172.16.0.0/12'), + IPv4Network('192.0.0.0/29'), + IPv4Network('192.0.0.170/31'), + IPv4Network('192.0.2.0/24'), + IPv4Network('192.168.0.0/16'), + IPv4Network('198.18.0.0/15'), + IPv4Network('198.51.100.0/24'), + IPv4Network('203.0.113.0/24'), + IPv4Network('240.0.0.0/4'), + IPv4Network('255.255.255.255/32'), + ] + + _reserved_network = IPv4Network('240.0.0.0/4') + + _unspecified_address = IPv4Address('0.0.0.0') + + +IPv4Address._constants = _IPv4Constants + + +class _BaseV6(object): + + """Base IPv6 object. + + The following methods are used by IPv6 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 6 + _ALL_ONES = (2 ** IPV6LENGTH) - 1 + _HEXTET_COUNT = 8 + _HEX_DIGITS = frozenset('0123456789ABCDEFabcdef') + _max_prefixlen = IPV6LENGTH + + # There are only a bunch of valid v6 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + prefixlen = cls._prefix_from_prefix_string(arg) + netmask = IPv6Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn an IPv6 ip_str into an integer. + + Args: + ip_str: A string, the IPv6 ip_str. + + Returns: + An int, the IPv6 address + + Raises: + AddressValueError: if ip_str isn't a valid IPv6 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + parts = ip_str.split(':') + + # An IPv6 address needs at least 2 colons (3 parts). + _min_parts = 3 + if len(parts) < _min_parts: + msg = "At least %d parts expected in %r" % (_min_parts, ip_str) + raise AddressValueError(msg) + + # If the address has an IPv4-style suffix, convert it to hexadecimal. + if '.' in parts[-1]: + try: + ipv4_int = IPv4Address(parts.pop())._ip + except AddressValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) + parts.append('%x' % (ipv4_int & 0xFFFF)) + + # An IPv6 address can't have more than 8 colons (9 parts). + # The extra colon comes from using the "::" notation for a single + # leading or trailing zero part. + _max_parts = cls._HEXTET_COUNT + 1 + if len(parts) > _max_parts: + msg = "At most %d colons permitted in %r" % ( + _max_parts - 1, ip_str) + raise AddressValueError(msg) + + # Disregarding the endpoints, find '::' with nothing in between. + # This indicates that a run of zeroes has been skipped. + skip_index = None + for i in _compat_range(1, len(parts) - 1): + if not parts[i]: + if skip_index is not None: + # Can't have more than one '::' + msg = "At most one '::' permitted in %r" % ip_str + raise AddressValueError(msg) + skip_index = i + + # parts_hi is the number of parts to copy from above/before the '::' + # parts_lo is the number of parts to copy from below/after the '::' + if skip_index is not None: + # If we found a '::', then check if it also covers the endpoints. + parts_hi = skip_index + parts_lo = len(parts) - skip_index - 1 + if not parts[0]: + parts_hi -= 1 + if parts_hi: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + parts_lo -= 1 + if parts_lo: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_skipped = cls._HEXTET_COUNT - (parts_hi + parts_lo) + if parts_skipped < 1: + msg = "Expected at most %d other parts with '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT - 1, ip_str)) + else: + # Otherwise, allocate the entire address to parts_hi. The + # endpoints could still be empty, but _parse_hextet() will check + # for that. + if len(parts) != cls._HEXTET_COUNT: + msg = "Exactly %d parts expected without '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT, ip_str)) + if not parts[0]: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_hi = len(parts) + parts_lo = 0 + parts_skipped = 0 + + try: + # Now, parse the hextets into a 128-bit integer. + ip_int = 0 + for i in range(parts_hi): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + ip_int <<= 16 * parts_skipped + for i in range(-parts_lo, 0): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + return ip_int + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_hextet(cls, hextet_str): + """Convert an IPv6 hextet string into an integer. + + Args: + hextet_str: A string, the number to parse. + + Returns: + The hextet as an integer. + + Raises: + ValueError: if the input isn't strictly a hex number from + [0..FFFF]. + + """ + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._HEX_DIGITS.issuperset(hextet_str): + raise ValueError("Only hex digits permitted in %r" % hextet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(hextet_str) > 4: + msg = "At most 4 characters permitted in %r" + raise ValueError(msg % hextet_str) + # Length check means we can skip checking the integer value + return int(hextet_str, 16) + + @classmethod + def _compress_hextets(cls, hextets): + """Compresses a list of hextets. + + Compresses a list of strings, replacing the longest continuous + sequence of "0" in the list with "" and adding empty strings at + the beginning or at the end of the string such that subsequently + calling ":".join(hextets) will produce the compressed version of + the IPv6 address. + + Args: + hextets: A list of strings, the hextets to compress. + + Returns: + A list of strings. + + """ + best_doublecolon_start = -1 + best_doublecolon_len = 0 + doublecolon_start = -1 + doublecolon_len = 0 + for index, hextet in enumerate(hextets): + if hextet == '0': + doublecolon_len += 1 + if doublecolon_start == -1: + # Start of a sequence of zeros. + doublecolon_start = index + if doublecolon_len > best_doublecolon_len: + # This is the longest sequence of zeros so far. + best_doublecolon_len = doublecolon_len + best_doublecolon_start = doublecolon_start + else: + doublecolon_len = 0 + doublecolon_start = -1 + + if best_doublecolon_len > 1: + best_doublecolon_end = (best_doublecolon_start + + best_doublecolon_len) + # For zeros at the end of the address. + if best_doublecolon_end == len(hextets): + hextets += [''] + hextets[best_doublecolon_start:best_doublecolon_end] = [''] + # For zeros at the beginning of the address. + if best_doublecolon_start == 0: + hextets = [''] + hextets + + return hextets + + @classmethod + def _string_from_ip_int(cls, ip_int=None): + """Turns a 128-bit integer into hexadecimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + A string, the hexadecimal representation of the address. + + Raises: + ValueError: The address is bigger than 128 bits of all ones. + + """ + if ip_int is None: + ip_int = int(cls._ip) + + if ip_int > cls._ALL_ONES: + raise ValueError('IPv6 address is too large') + + hex_str = '%032x' % ip_int + hextets = ['%x' % int(hex_str[x:x + 4], 16) for x in range(0, 32, 4)] + + hextets = cls._compress_hextets(hextets) + return ':'.join(hextets) + + def _explode_shorthand_ip_string(self): + """Expand a shortened IPv6 address. + + Args: + ip_str: A string, the IPv6 address. + + Returns: + A string, the expanded IPv6 address. + + """ + if isinstance(self, IPv6Network): + ip_str = _compat_str(self.network_address) + elif isinstance(self, IPv6Interface): + ip_str = _compat_str(self.ip) + else: + ip_str = _compat_str(self) + + ip_int = self._ip_int_from_string(ip_str) + hex_str = '%032x' % ip_int + parts = [hex_str[x:x + 4] for x in range(0, 32, 4)] + if isinstance(self, (_BaseNetwork, IPv6Interface)): + return '%s/%d' % (':'.join(parts), self._prefixlen) + return ':'.join(parts) + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv6 address. + + This implements the method described in RFC3596 2.5. + + """ + reverse_chars = self.exploded[::-1].replace(':', '') + return '.'.join(reverse_chars) + '.ip6.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv6Address(_BaseV6, _BaseAddress): + + """Represent and manipulate single IPv6 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + """Instantiate a new IPv6 address object. + + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv6Address('2001:db8::') == + IPv6Address(42540766411282592856903984951653826560) + or, more generally + IPv6Address(int(IPv6Address('2001:db8::'))) == + IPv6Address('2001:db8::') + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 16) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v6_int_to_packed(self._ip) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return any(self in x for x in self._constants._reserved_networks) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return self in self._constants._linklocal_network + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return self in self._constants._sitelocal_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv6-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, true if the address is not reserved per + iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return self._ip == 0 + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return self._ip == 1 + + @property + def ipv4_mapped(self): + """Return the IPv4 mapped address. + + Returns: + If the IPv6 address is a v4 mapped address, return the + IPv4 mapped address. Return None otherwise. + + """ + if (self._ip >> 32) != 0xFFFF: + return None + return IPv4Address(self._ip & 0xFFFFFFFF) + + @property + def teredo(self): + """Tuple of embedded teredo IPs. + + Returns: + Tuple of the (server, client) IPs or None if the address + doesn't appear to be a teredo address (doesn't start with + 2001::/32) + + """ + if (self._ip >> 96) != 0x20010000: + return None + return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF), + IPv4Address(~self._ip & 0xFFFFFFFF)) + + @property + def sixtofour(self): + """Return the IPv4 6to4 embedded address. + + Returns: + The IPv4 6to4-embedded address if present or None if the + address doesn't appear to contain a 6to4 embedded address. + + """ + if (self._ip >> 112) != 0x2002: + return None + return IPv4Address((self._ip >> 80) & 0xFFFFFFFF) + + +class IPv6Interface(IPv6Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv6Address.__init__(self, address) + self.network = IPv6Network(self._ip) + self._prefixlen = self._max_prefixlen + return + if isinstance(address, tuple): + IPv6Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv6Address.__init__(self, addr[0]) + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self._prefixlen = self.network._prefixlen + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv6Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv6Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv6Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + @property + def is_unspecified(self): + return self._ip == 0 and self.network.is_unspecified + + @property + def is_loopback(self): + return self._ip == 1 and self.network.is_loopback + + +class IPv6Network(_BaseV6, _BaseNetwork): + + """This class represents and manipulates 128-bit IPv6 networks. + + Attributes: [examples for IPv6('2001:db8::1000/124')] + .network_address: IPv6Address('2001:db8::1000') + .hostmask: IPv6Address('::f') + .broadcast_address: IPv6Address('2001:db8::100f') + .netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0') + .prefixlen: 124 + + """ + + # Class to use when creating address objects + _address_class = IPv6Address + + def __init__(self, address, strict=True): + """Instantiate a new IPv6 Network object. + + Args: + address: A string or integer representing the IPv6 network or the + IP and prefix/netmask. + '2001:db8::/128' + '2001:db8:0000:0000:0000:0000:0000:0000/128' + '2001:db8::' + are all functionally the same in IPv6. That is to say, + failing to provide a subnetmask will create an object with + a mask of /128. + + Additionally, an integer can be passed, so + IPv6Network('2001:db8::') == + IPv6Network(42540766411282592856903984951653826560) + or, more generally + IPv6Network(int(IPv6Network('2001:db8::'))) == + IPv6Network('2001:db8::') + + strict: A boolean. If true, ensure that we have been passed + A true network address, eg, 2001:db8::1000/124 and not an + IP address on a network, eg, 2001:db8::1/124. + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + NetmaskValueError: If the netmask isn't valid for + an IPv6 address. + ValueError: If strict was True and a network address was not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Efficient constructor from integer or packed address + if isinstance(address, (bytes, _compat_int_types)): + self.network_address = IPv6Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + self.network_address = IPv6Address(address[0]) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv6Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + + self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv6Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv6Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the + Subnet-Router anycast address. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast + 1): + yield self._address_class(x) + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return (self.network_address.is_site_local and + self.broadcast_address.is_site_local) + + +class _IPv6Constants(object): + + _linklocal_network = IPv6Network('fe80::/10') + + _multicast_network = IPv6Network('ff00::/8') + + _private_networks = [ + IPv6Network('::1/128'), + IPv6Network('::/128'), + IPv6Network('::ffff:0:0/96'), + IPv6Network('100::/64'), + IPv6Network('2001::/23'), + IPv6Network('2001:2::/48'), + IPv6Network('2001:db8::/32'), + IPv6Network('2001:10::/28'), + IPv6Network('fc00::/7'), + IPv6Network('fe80::/10'), + ] + + _reserved_networks = [ + IPv6Network('::/8'), IPv6Network('100::/8'), + IPv6Network('200::/7'), IPv6Network('400::/6'), + IPv6Network('800::/5'), IPv6Network('1000::/4'), + IPv6Network('4000::/3'), IPv6Network('6000::/3'), + IPv6Network('8000::/3'), IPv6Network('A000::/3'), + IPv6Network('C000::/3'), IPv6Network('E000::/4'), + IPv6Network('F000::/5'), IPv6Network('F800::/6'), + IPv6Network('FE00::/9'), + ] + + _sitelocal_network = IPv6Network('fec0::/10') + + +IPv6Address._constants = _IPv6Constants diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py new file mode 100755 index 0000000..228e051 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- + +""" +lockfile.py - Platform-independent advisory file locks. + +Requires Python 2.5 unless you apply 2.4.diff +Locking is done on a per-thread basis instead of a per-process basis. + +Usage: + +>>> lock = LockFile('somefile') +>>> try: +... lock.acquire() +... except AlreadyLocked: +... print 'somefile', 'is locked already.' +... except LockFailed: +... print 'somefile', 'can\\'t be locked.' +... else: +... print 'got lock' +got lock +>>> print lock.is_locked() +True +>>> lock.release() + +>>> lock = LockFile('somefile') +>>> print lock.is_locked() +False +>>> with lock: +... print lock.is_locked() +True +>>> print lock.is_locked() +False + +>>> lock = LockFile('somefile') +>>> # It is okay to lock twice from the same thread... +>>> with lock: +... lock.acquire() +... +>>> # Though no counter is kept, so you can't unlock multiple times... +>>> print lock.is_locked() +False + +Exceptions: + + Error - base class for other exceptions + LockError - base class for all locking exceptions + AlreadyLocked - Another thread or process already holds the lock + LockFailed - Lock failed for some other reason + UnlockError - base class for all unlocking exceptions + AlreadyUnlocked - File was not locked. + NotMyLock - File was locked but not by the current thread/process +""" + +from __future__ import absolute_import + +import functools +import os +import socket +import threading +import warnings + +# Work with PEP8 and non-PEP8 versions of threading module. +if not hasattr(threading, "current_thread"): + threading.current_thread = threading.currentThread +if not hasattr(threading.Thread, "get_name"): + threading.Thread.get_name = threading.Thread.getName + +__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked', + 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock', + 'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock', + 'LockBase', 'locked'] + + +class Error(Exception): + """ + Base class for other exceptions. + + >>> try: + ... raise Error + ... except Exception: + ... pass + """ + pass + + +class LockError(Error): + """ + Base class for error arising from attempts to acquire the lock. + + >>> try: + ... raise LockError + ... except Error: + ... pass + """ + pass + + +class LockTimeout(LockError): + """Raised when lock creation fails within a user-defined period of time. + + >>> try: + ... raise LockTimeout + ... except LockError: + ... pass + """ + pass + + +class AlreadyLocked(LockError): + """Some other thread/process is locking the file. + + >>> try: + ... raise AlreadyLocked + ... except LockError: + ... pass + """ + pass + + +class LockFailed(LockError): + """Lock file creation failed for some other reason. + + >>> try: + ... raise LockFailed + ... except LockError: + ... pass + """ + pass + + +class UnlockError(Error): + """ + Base class for errors arising from attempts to release the lock. + + >>> try: + ... raise UnlockError + ... except Error: + ... pass + """ + pass + + +class NotLocked(UnlockError): + """Raised when an attempt is made to unlock an unlocked file. + + >>> try: + ... raise NotLocked + ... except UnlockError: + ... pass + """ + pass + + +class NotMyLock(UnlockError): + """Raised when an attempt is made to unlock a file someone else locked. + + >>> try: + ... raise NotMyLock + ... except UnlockError: + ... pass + """ + pass + + +class _SharedBase(object): + def __init__(self, path): + self.path = path + + def acquire(self, timeout=None): + """ + Acquire the lock. + + * If timeout is omitted (or None), wait forever trying to lock the + file. + + * If timeout > 0, try to acquire the lock for that many seconds. If + the lock period expires and the file is still locked, raise + LockTimeout. + + * If timeout <= 0, raise AlreadyLocked immediately if the file is + already locked. + """ + raise NotImplemented("implement in subclass") + + def release(self): + """ + Release the lock. + + If the file is not locked, raise NotLocked. + """ + raise NotImplemented("implement in subclass") + + def __enter__(self): + """ + Context manager support. + """ + self.acquire() + return self + + def __exit__(self, *_exc): + """ + Context manager support. + """ + self.release() + + def __repr__(self): + return "<%s: %r>" % (self.__class__.__name__, self.path) + + +class LockBase(_SharedBase): + """Base class for platform-specific lock classes.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = LockBase('somefile') + >>> lock = LockBase('somefile', threaded=False) + """ + super(LockBase, self).__init__(path) + self.lock_file = os.path.abspath(path) + ".lock" + self.hostname = socket.gethostname() + self.pid = os.getpid() + if threaded: + t = threading.current_thread() + # Thread objects in Python 2.4 and earlier do not have ident + # attrs. Worm around that. + ident = getattr(t, "ident", hash(t)) + self.tname = "-%x" % (ident & 0xffffffff) + else: + self.tname = "" + dirname = os.path.dirname(self.lock_file) + + # unique name is mostly about the current process, but must + # also contain the path -- otherwise, two adjacent locked + # files conflict (one file gets locked, creating lock-file and + # unique file, the other one gets locked, creating lock-file + # and overwriting the already existing lock-file, then one + # gets unlocked, deleting both lock-file and unique file, + # finally the last lock errors out upon releasing. + self.unique_name = os.path.join(dirname, + "%s%s.%s%s" % (self.hostname, + self.tname, + self.pid, + hash(self.path))) + self.timeout = timeout + + def is_locked(self): + """ + Tell whether or not the file is locked. + """ + raise NotImplemented("implement in subclass") + + def i_am_locking(self): + """ + Return True if this object is locking the file. + """ + raise NotImplemented("implement in subclass") + + def break_lock(self): + """ + Remove a lock. Useful if a locking thread failed to unlock. + """ + raise NotImplemented("implement in subclass") + + def __repr__(self): + return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, + self.path) + + +def _fl_helper(cls, mod, *args, **kwds): + warnings.warn("Import from %s module instead of lockfile package" % mod, + DeprecationWarning, stacklevel=2) + # This is a bit funky, but it's only for awhile. The way the unit tests + # are constructed this function winds up as an unbound method, so it + # actually takes three args, not two. We want to toss out self. + if not isinstance(args[0], str): + # We are testing, avoid the first arg + args = args[1:] + if len(args) == 1 and not kwds: + kwds["threaded"] = True + return cls(*args, **kwds) + + +def LinkFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import LinkLockFile from the + lockfile.linklockfile module. + """ + from . import linklockfile + return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", + *args, **kwds) + + +def MkdirFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import MkdirLockFile from the + lockfile.mkdirlockfile module. + """ + from . import mkdirlockfile + return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", + *args, **kwds) + + +def SQLiteFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import SQLiteLockFile from the + lockfile.mkdirlockfile module. + """ + from . import sqlitelockfile + return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", + *args, **kwds) + + +def locked(path, timeout=None): + """Decorator which enables locks for decorated function. + + Arguments: + - path: path for lockfile. + - timeout (optional): Timeout for acquiring lock. + + Usage: + @locked('/var/run/myname', timeout=0) + def myname(...): + ... + """ + def decor(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + lock = FileLock(path, timeout=timeout) + lock.acquire() + try: + return func(*args, **kwargs) + finally: + lock.release() + return wrapper + return decor + + +if hasattr(os, "link"): + from . import linklockfile as _llf + LockFile = _llf.LinkLockFile +else: + from . import mkdirlockfile as _mlf + LockFile = _mlf.MkdirLockFile + +FileLock = LockFile diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py new file mode 100755 index 0000000..11af0f3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import + +import time +import os + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class LinkLockFile(LockBase): + """Lock access to a file using atomic property of link(2). + + >>> lock = LinkLockFile('somefile') + >>> lock = LinkLockFile('somefile', threaded=False) + """ + + def acquire(self, timeout=None): + try: + open(self.unique_name, "wb").close() + except IOError: + raise LockFailed("failed to create %s" % self.unique_name) + + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a hard link to it. + try: + os.link(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + nlinks = os.stat(self.unique_name).st_nlink + if nlinks == 2: + # The original link plus the one I created == 2. We're + # good to go. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + os.unlink(self.unique_name) + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout / 10 or 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name) and + os.stat(self.unique_name).st_nlink == 2) + + def break_lock(self): + if os.path.exists(self.lock_file): + os.unlink(self.lock_file) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py new file mode 100755 index 0000000..bd5a51e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py @@ -0,0 +1,84 @@ +from __future__ import absolute_import, division + +import time +import os +import sys +import errno + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class MkdirLockFile(LockBase): + """Lock file by creating a directory.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = MkdirLockFile('somefile') + >>> lock = MkdirLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + # Lock file itself is a directory. Place the unique file name into + # it. + self.unique_name = os.path.join(self.lock_file, + "%s.%s%s" % (self.hostname, + self.tname, + self.pid)) + + def acquire(self, timeout=None): + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + else: + wait = max(0, timeout / 10) + + while True: + try: + os.mkdir(self.lock_file) + except OSError: + err = sys.exc_info()[1] + if err.errno == errno.EEXIST: + # Already locked. + if os.path.exists(self.unique_name): + # Already locked by me. + return + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock. + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(wait) + else: + # Couldn't create the lock for some other reason + raise LockFailed("failed to create %s" % self.lock_file) + else: + open(self.unique_name, "wb").close() + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.rmdir(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name)) + + def break_lock(self): + if os.path.exists(self.lock_file): + for name in os.listdir(self.lock_file): + os.unlink(os.path.join(self.lock_file, name)) + os.rmdir(self.lock_file) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py new file mode 100755 index 0000000..d776de5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +# pidlockfile.py +# +# Copyright © 2008–2009 Ben Finney <ben+python@benfinney.id.au> +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the Python Software Foundation License, version 2 or +# later as published by the Python Software Foundation. +# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. + +""" Lockfile behaviour implemented via Unix PID files. + """ + +from __future__ import absolute_import + +import errno +import os +import time + +from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, + LockTimeout) + + +class PIDLockFile(LockBase): + """ Lockfile implemented as a Unix PID file. + + The lock file is a normal file named by the attribute `path`. + A lock's PID file contains a single line of text, containing + the process ID (PID) of the process that acquired the lock. + + >>> lock = PIDLockFile('somefile') + >>> lock = PIDLockFile('somefile') + """ + + def __init__(self, path, threaded=False, timeout=None): + # pid lockfiles don't support threaded operation, so always force + # False as the threaded arg. + LockBase.__init__(self, path, False, timeout) + self.unique_name = self.path + + def read_pid(self): + """ Get the PID from the lock file. + """ + return read_pid_from_pidfile(self.path) + + def is_locked(self): + """ Test if the lock is currently held. + + The lock is held if the PID file for this lock exists. + + """ + return os.path.exists(self.path) + + def i_am_locking(self): + """ Test if the lock is held by the current process. + + Returns ``True`` if the current process ID matches the + number stored in the PID file. + """ + return self.is_locked() and os.getpid() == self.read_pid() + + def acquire(self, timeout=None): + """ Acquire the lock. + + Creates the PID file for this lock, or raises an error if + the lock could not be acquired. + """ + + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + try: + write_pid_to_pidfile(self.path) + except OSError as exc: + if exc.errno == errno.EEXIST: + # The lock creation failed. Maybe sleep a bit. + if time.time() > end_time: + if timeout is not None and timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout / 10 or 0.1) + else: + raise LockFailed("failed to create %s" % self.path) + else: + return + + def release(self): + """ Release the lock. + + Removes the PID file to release the lock, or raises an + error if the current process does not hold the lock. + + """ + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + remove_existing_pidfile(self.path) + + def break_lock(self): + """ Break an existing lock. + + Removes the PID file if it already exists, otherwise does + nothing. + + """ + remove_existing_pidfile(self.path) + + +def read_pid_from_pidfile(pidfile_path): + """ Read the PID recorded in the named PID file. + + Read and return the numeric PID recorded as text in the named + PID file. If the PID file cannot be read, or if the content is + not a valid PID, return ``None``. + + """ + pid = None + try: + pidfile = open(pidfile_path, 'r') + except IOError: + pass + else: + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. + # + # Programs that read PID files should be somewhat flexible + # in what they accept; i.e., they should ignore extra + # whitespace, leading zeroes, absence of the trailing + # newline, or additional lines in the PID file. + + line = pidfile.readline().strip() + try: + pid = int(line) + except ValueError: + pass + pidfile.close() + + return pid + + +def write_pid_to_pidfile(pidfile_path): + """ Write the PID in the named PID file. + + Get the numeric process ID (“PID”) of the current process + and write it to the named file as a line of text. + + """ + open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) + open_mode = 0o644 + pidfile_fd = os.open(pidfile_path, open_flags, open_mode) + pidfile = os.fdopen(pidfile_fd, 'w') + + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. For + # example, if crond was process number 25, /var/run/crond.pid + # would contain three characters: two, five, and newline. + + pid = os.getpid() + pidfile.write("%s\n" % pid) + pidfile.close() + + +def remove_existing_pidfile(pidfile_path): + """ Remove the named PID file if it exists. + + Removing a PID file that doesn't already exist puts us in the + desired state, so we ignore the condition if the file does not + exist. + + """ + try: + os.remove(pidfile_path) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + raise diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py new file mode 100755 index 0000000..278dff4 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py @@ -0,0 +1,156 @@ +from __future__ import absolute_import, division + +import time +import os + +try: + unicode +except NameError: + unicode = str + +from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked + + +class SQLiteLockFile(LockBase): + "Demonstrate SQL-based locking." + + testdb = None + + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = SQLiteLockFile('somefile') + >>> lock = SQLiteLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + self.lock_file = unicode(self.lock_file) + self.unique_name = unicode(self.unique_name) + + if SQLiteLockFile.testdb is None: + import tempfile + _fd, testdb = tempfile.mkstemp() + os.close(_fd) + os.unlink(testdb) + del _fd, tempfile + SQLiteLockFile.testdb = testdb + + import sqlite3 + self.connection = sqlite3.connect(SQLiteLockFile.testdb) + + c = self.connection.cursor() + try: + c.execute("create table locks" + "(" + " lock_file varchar(32)," + " unique_name varchar(32)" + ")") + except sqlite3.OperationalError: + pass + else: + self.connection.commit() + import atexit + atexit.register(os.unlink, SQLiteLockFile.testdb) + + def acquire(self, timeout=None): + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + elif timeout <= 0: + wait = 0 + else: + wait = timeout / 10 + + cursor = self.connection.cursor() + + while True: + if not self.is_locked(): + # Not locked. Try to lock it. + cursor.execute("insert into locks" + " (lock_file, unique_name)" + " values" + " (?, ?)", + (self.lock_file, self.unique_name)) + self.connection.commit() + + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) > 1: + # Nope. Someone else got there. Remove our lock. + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + else: + # Yup. We're done, so go home. + return + else: + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) == 1: + # We're the locker, so go home. + return + + # Maybe we should wait a bit longer. + if timeout is not None and time.time() > end_time: + if timeout > 0: + # No more waiting. + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock and we are impatient.. + raise AlreadyLocked("%s is already locked" % self.path) + + # Well, okay. We'll give it a bit longer. + time.sleep(wait) + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me (by %s)" % + (self.unique_name, self._who_is_locking())) + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + + def _who_is_locking(self): + cursor = self.connection.cursor() + cursor.execute("select unique_name from locks" + " where lock_file = ?", + (self.lock_file,)) + return cursor.fetchone()[0] + + def is_locked(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?", + (self.lock_file,)) + rows = cursor.fetchall() + return not not rows + + def i_am_locking(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?" + " and unique_name = ?", + (self.lock_file, self.unique_name)) + return not not cursor.fetchall() + + def break_lock(self): + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where lock_file = ?", + (self.lock_file,)) + self.connection.commit() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py new file mode 100755 index 0000000..93ff2b5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import + +import os +import time + +from . import (LockBase, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class SymlinkLockFile(LockBase): + """Lock access to a file using symlink(2).""" + + def __init__(self, path, threaded=True, timeout=None): + # super(SymlinkLockFile).__init(...) + LockBase.__init__(self, path, threaded, timeout) + # split it back! + self.unique_name = os.path.split(self.unique_name)[1] + + def acquire(self, timeout=None): + # Hopefully unnecessary for symlink. + # try: + # open(self.unique_name, "wb").close() + # except IOError: + # raise LockFailed("failed to create %s" % self.unique_name) + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a symbolic link to it. + try: + os.symlink(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + if self.i_am_locking(): + # Linked to out unique name. Proceed. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout / 10 if timeout is not None else 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.islink(self.lock_file) + + def i_am_locking(self): + return (os.path.islink(self.lock_file) + and os.readlink(self.lock_file) == self.unique_name) + + def break_lock(self): + if os.path.islink(self.lock_file): # exists && link + os.unlink(self.lock_file) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py new file mode 100755 index 0000000..dda626a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py @@ -0,0 +1,66 @@ +# coding: utf-8 +from pip._vendor.msgpack._version import version +from pip._vendor.msgpack.exceptions import * + +from collections import namedtuple + + +class ExtType(namedtuple('ExtType', 'code data')): + """ExtType represents ext type in msgpack.""" + def __new__(cls, code, data): + if not isinstance(code, int): + raise TypeError("code must be int") + if not isinstance(data, bytes): + raise TypeError("data must be bytes") + if not 0 <= code <= 127: + raise ValueError("code must be 0~127") + return super(ExtType, cls).__new__(cls, code, data) + + +import os +if os.environ.get('MSGPACK_PUREPYTHON'): + from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker +else: + try: + from pip._vendor.msgpack._packer import Packer + from pip._vendor.msgpack._unpacker import unpackb, Unpacker + except ImportError: + from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker + + +def pack(o, stream, **kwargs): + """ + Pack object `o` and write it to `stream` + + See :class:`Packer` for options. + """ + packer = Packer(**kwargs) + stream.write(packer.pack(o)) + + +def packb(o, **kwargs): + """ + Pack object `o` and return packed bytes + + See :class:`Packer` for options. + """ + return Packer(**kwargs).pack(o) + + +def unpack(stream, **kwargs): + """ + Unpack an object from `stream`. + + Raises `ExtraData` when `stream` contains extra bytes. + See :class:`Unpacker` for options. + """ + data = stream.read() + return unpackb(data, **kwargs) + + +# alias for compatibility to simplejson/marshal/pickle. +load = unpack +loads = unpackb + +dump = pack +dumps = packb diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py new file mode 100755 index 0000000..91d97cd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py @@ -0,0 +1 @@ +version = (0, 5, 6) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py new file mode 100755 index 0000000..e0b5133 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py @@ -0,0 +1,41 @@ +class UnpackException(Exception): + """Deprecated. Use Exception instead to catch all exception during unpacking.""" + + +class BufferFull(UnpackException): + pass + + +class OutOfData(UnpackException): + pass + + +class UnpackValueError(UnpackException, ValueError): + """Deprecated. Use ValueError instead.""" + + +class ExtraData(UnpackValueError): + def __init__(self, unpacked, extra): + self.unpacked = unpacked + self.extra = extra + + def __str__(self): + return "unpack(b) received extra data." + + +class PackException(Exception): + """Deprecated. Use Exception instead to catch all exception during packing.""" + + +class PackValueError(PackException, ValueError): + """PackValueError is raised when type of input data is supported but it's value is unsupported. + + Deprecated. Use ValueError instead. + """ + + +class PackOverflowError(PackValueError, OverflowError): + """PackOverflowError is raised when integer value is out of range of msgpack support [-2**31, 2**32). + + Deprecated. Use ValueError instead. + """ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py new file mode 100755 index 0000000..a1a9712 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py @@ -0,0 +1,977 @@ +"""Fallback pure Python implementation of msgpack""" + +import sys +import struct +import warnings + +if sys.version_info[0] == 3: + PY3 = True + int_types = int + Unicode = str + xrange = range + def dict_iteritems(d): + return d.items() +else: + PY3 = False + int_types = (int, long) + Unicode = unicode + def dict_iteritems(d): + return d.iteritems() + + +if hasattr(sys, 'pypy_version_info'): + # cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own + # StringBuilder is fastest. + from __pypy__ import newlist_hint + try: + from __pypy__.builders import BytesBuilder as StringBuilder + except ImportError: + from __pypy__.builders import StringBuilder + USING_STRINGBUILDER = True + class StringIO(object): + def __init__(self, s=b''): + if s: + self.builder = StringBuilder(len(s)) + self.builder.append(s) + else: + self.builder = StringBuilder() + def write(self, s): + if isinstance(s, memoryview): + s = s.tobytes() + elif isinstance(s, bytearray): + s = bytes(s) + self.builder.append(s) + def getvalue(self): + return self.builder.build() +else: + USING_STRINGBUILDER = False + from io import BytesIO as StringIO + newlist_hint = lambda size: [] + + +from pip._vendor.msgpack.exceptions import ( + BufferFull, + OutOfData, + UnpackValueError, + PackValueError, + PackOverflowError, + ExtraData) + +from pip._vendor.msgpack import ExtType + + +EX_SKIP = 0 +EX_CONSTRUCT = 1 +EX_READ_ARRAY_HEADER = 2 +EX_READ_MAP_HEADER = 3 + +TYPE_IMMEDIATE = 0 +TYPE_ARRAY = 1 +TYPE_MAP = 2 +TYPE_RAW = 3 +TYPE_BIN = 4 +TYPE_EXT = 5 + +DEFAULT_RECURSE_LIMIT = 511 + + +def _check_type_strict(obj, t, type=type, tuple=tuple): + if type(t) is tuple: + return type(obj) in t + else: + return type(obj) is t + + +def _get_data_from_buffer(obj): + try: + view = memoryview(obj) + except TypeError: + # try to use legacy buffer protocol if 2.7, otherwise re-raise + if not PY3: + view = memoryview(buffer(obj)) + warnings.warn("using old buffer interface to unpack %s; " + "this leads to unpacking errors if slicing is used and " + "will be removed in a future version" % type(obj), + RuntimeWarning) + else: + raise + if view.itemsize != 1: + raise ValueError("cannot unpack from multi-byte object") + return view + + +def unpack(stream, **kwargs): + warnings.warn( + "Direct calling implementation's unpack() is deprecated, Use msgpack.unpack() or unpackb() instead.", + PendingDeprecationWarning) + data = stream.read() + return unpackb(data, **kwargs) + + +def unpackb(packed, **kwargs): + """ + Unpack an object from `packed`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(None, **kwargs) + unpacker.feed(packed) + try: + ret = unpacker._unpack() + except OutOfData: + raise UnpackValueError("Data is not enough.") + if unpacker._got_extradata(): + raise ExtraData(ret, unpacker._get_extradata()) + return ret + + +class Unpacker(object): + """Streaming unpacker. + + arguments: + + :param file_like: + File-like object having `.read(n)` method. + If specified, unpacker reads serialized data from it and :meth:`feed()` is not usable. + + :param int read_size: + Used as `file_like.read(read_size)`. (default: `min(16*1024, max_buffer_size)`) + + :param bool use_list: + If true, unpack msgpack array to Python list. + Otherwise, unpack to Python tuple. (default: True) + + :param bool raw: + If true, unpack msgpack raw to Python bytes (default). + Otherwise, unpack to Python str (or unicode on Python 2) by decoding + with UTF-8 encoding (recommended). + Currently, the default is true, but it will be changed to false in + near future. So you must specify it explicitly for keeping backward + compatibility. + + *encoding* option which is deprecated overrides this option. + + :param callable object_hook: + When specified, it should be callable. + Unpacker calls it with a dict argument after unpacking msgpack map. + (See also simplejson) + + :param callable object_pairs_hook: + When specified, it should be callable. + Unpacker calls it with a list of key-value pairs after unpacking msgpack map. + (See also simplejson) + + :param str encoding: + Encoding used for decoding msgpack raw. + If it is None (default), msgpack raw is deserialized to Python bytes. + + :param str unicode_errors: + (deprecated) Used for decoding msgpack raw with *encoding*. + (default: `'strict'`) + + :param int max_buffer_size: + Limits size of data waiting unpacked. 0 means system's INT_MAX (default). + Raises `BufferFull` exception when it is insufficient. + You should set this parameter when unpacking data from untrusted source. + + :param int max_str_len: + Limits max length of str. (default: 2**31-1) + + :param int max_bin_len: + Limits max length of bin. (default: 2**31-1) + + :param int max_array_len: + Limits max length of array. (default: 2**31-1) + + :param int max_map_len: + Limits max length of map. (default: 2**31-1) + + + example of streaming deserialize from file-like object:: + + unpacker = Unpacker(file_like, raw=False) + for o in unpacker: + process(o) + + example of streaming deserialize from socket:: + + unpacker = Unpacker(raw=False) + while True: + buf = sock.recv(1024**2) + if not buf: + break + unpacker.feed(buf) + for o in unpacker: + process(o) + """ + + def __init__(self, file_like=None, read_size=0, use_list=True, raw=True, + object_hook=None, object_pairs_hook=None, list_hook=None, + encoding=None, unicode_errors=None, max_buffer_size=0, + ext_hook=ExtType, + max_str_len=2147483647, # 2**32-1 + max_bin_len=2147483647, + max_array_len=2147483647, + max_map_len=2147483647, + max_ext_len=2147483647): + + if encoding is not None: + warnings.warn( + "encoding is deprecated, Use raw=False instead.", + PendingDeprecationWarning) + + if unicode_errors is None: + unicode_errors = 'strict' + + if file_like is None: + self._feeding = True + else: + if not callable(file_like.read): + raise TypeError("`file_like.read` must be callable") + self.file_like = file_like + self._feeding = False + + #: array of bytes fed. + self._buffer = bytearray() + # Some very old pythons don't support `struct.unpack_from()` with a + # `bytearray`. So we wrap it in a `buffer()` there. + if sys.version_info < (2, 7, 6): + self._buffer_view = buffer(self._buffer) + else: + self._buffer_view = self._buffer + #: Which position we currently reads + self._buff_i = 0 + + # When Unpacker is used as an iterable, between the calls to next(), + # the buffer is not "consumed" completely, for efficiency sake. + # Instead, it is done sloppily. To make sure we raise BufferFull at + # the correct moments, we have to keep track of how sloppy we were. + # Furthermore, when the buffer is incomplete (that is: in the case + # we raise an OutOfData) we need to rollback the buffer to the correct + # state, which _buf_checkpoint records. + self._buf_checkpoint = 0 + + self._max_buffer_size = max_buffer_size or 2**31-1 + if read_size > self._max_buffer_size: + raise ValueError("read_size must be smaller than max_buffer_size") + self._read_size = read_size or min(self._max_buffer_size, 16*1024) + self._raw = bool(raw) + self._encoding = encoding + self._unicode_errors = unicode_errors + self._use_list = use_list + self._list_hook = list_hook + self._object_hook = object_hook + self._object_pairs_hook = object_pairs_hook + self._ext_hook = ext_hook + self._max_str_len = max_str_len + self._max_bin_len = max_bin_len + self._max_array_len = max_array_len + self._max_map_len = max_map_len + self._max_ext_len = max_ext_len + self._stream_offset = 0 + + if list_hook is not None and not callable(list_hook): + raise TypeError('`list_hook` is not callable') + if object_hook is not None and not callable(object_hook): + raise TypeError('`object_hook` is not callable') + if object_pairs_hook is not None and not callable(object_pairs_hook): + raise TypeError('`object_pairs_hook` is not callable') + if object_hook is not None and object_pairs_hook is not None: + raise TypeError("object_pairs_hook and object_hook are mutually " + "exclusive") + if not callable(ext_hook): + raise TypeError("`ext_hook` is not callable") + + def feed(self, next_bytes): + assert self._feeding + view = _get_data_from_buffer(next_bytes) + if (len(self._buffer) - self._buff_i + len(view) > self._max_buffer_size): + raise BufferFull + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[:self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + self._buffer += view + + def _consume(self): + """ Gets rid of the used parts of the buffer. """ + self._stream_offset += self._buff_i - self._buf_checkpoint + self._buf_checkpoint = self._buff_i + + def _got_extradata(self): + return self._buff_i < len(self._buffer) + + def _get_extradata(self): + return self._buffer[self._buff_i:] + + def read_bytes(self, n): + return self._read(n) + + def _read(self, n): + # (int) -> bytearray + self._reserve(n) + i = self._buff_i + self._buff_i = i+n + return self._buffer[i:i+n] + + def _reserve(self, n): + remain_bytes = len(self._buffer) - self._buff_i - n + + # Fast path: buffer has n bytes already + if remain_bytes >= 0: + return + + if self._feeding: + self._buff_i = self._buf_checkpoint + raise OutOfData + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[:self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + # Read from file + remain_bytes = -remain_bytes + while remain_bytes > 0: + to_read_bytes = max(self._read_size, remain_bytes) + read_data = self.file_like.read(to_read_bytes) + if not read_data: + break + assert isinstance(read_data, bytes) + self._buffer += read_data + remain_bytes -= len(read_data) + + if len(self._buffer) < n + self._buff_i: + self._buff_i = 0 # rollback + raise OutOfData + + def _read_header(self, execute=EX_CONSTRUCT): + typ = TYPE_IMMEDIATE + n = 0 + obj = None + self._reserve(1) + b = self._buffer[self._buff_i] + self._buff_i += 1 + if b & 0b10000000 == 0: + obj = b + elif b & 0b11100000 == 0b11100000: + obj = -1 - (b ^ 0xff) + elif b & 0b11100000 == 0b10100000: + n = b & 0b00011111 + typ = TYPE_RAW + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b & 0b11110000 == 0b10010000: + n = b & 0b00001111 + typ = TYPE_ARRAY + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b & 0b11110000 == 0b10000000: + n = b & 0b00001111 + typ = TYPE_MAP + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + elif b == 0xc0: + obj = None + elif b == 0xc2: + obj = False + elif b == 0xc3: + obj = True + elif b == 0xc4: + typ = TYPE_BIN + self._reserve(1) + n = self._buffer[self._buff_i] + self._buff_i += 1 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc5: + typ = TYPE_BIN + self._reserve(2) + n = struct.unpack_from(">H", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc6: + typ = TYPE_BIN + self._reserve(4) + n = struct.unpack_from(">I", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc7: # ext 8 + typ = TYPE_EXT + self._reserve(2) + L, n = struct.unpack_from('Bb', self._buffer_view, self._buff_i) + self._buff_i += 2 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xc8: # ext 16 + typ = TYPE_EXT + self._reserve(3) + L, n = struct.unpack_from('>Hb', self._buffer_view, self._buff_i) + self._buff_i += 3 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xc9: # ext 32 + typ = TYPE_EXT + self._reserve(5) + L, n = struct.unpack_from('>Ib', self._buffer_view, self._buff_i) + self._buff_i += 5 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xca: + self._reserve(4) + obj = struct.unpack_from(">f", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xcb: + self._reserve(8) + obj = struct.unpack_from(">d", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xcc: + self._reserve(1) + obj = self._buffer[self._buff_i] + self._buff_i += 1 + elif b == 0xcd: + self._reserve(2) + obj = struct.unpack_from(">H", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + elif b == 0xce: + self._reserve(4) + obj = struct.unpack_from(">I", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xcf: + self._reserve(8) + obj = struct.unpack_from(">Q", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xd0: + self._reserve(1) + obj = struct.unpack_from("b", self._buffer_view, self._buff_i)[0] + self._buff_i += 1 + elif b == 0xd1: + self._reserve(2) + obj = struct.unpack_from(">h", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + elif b == 0xd2: + self._reserve(4) + obj = struct.unpack_from(">i", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xd3: + self._reserve(8) + obj = struct.unpack_from(">q", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xd4: # fixext 1 + typ = TYPE_EXT + if self._max_ext_len < 1: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (1, self._max_ext_len)) + self._reserve(2) + n, obj = struct.unpack_from("b1s", self._buffer_view, self._buff_i) + self._buff_i += 2 + elif b == 0xd5: # fixext 2 + typ = TYPE_EXT + if self._max_ext_len < 2: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (2, self._max_ext_len)) + self._reserve(3) + n, obj = struct.unpack_from("b2s", self._buffer_view, self._buff_i) + self._buff_i += 3 + elif b == 0xd6: # fixext 4 + typ = TYPE_EXT + if self._max_ext_len < 4: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (4, self._max_ext_len)) + self._reserve(5) + n, obj = struct.unpack_from("b4s", self._buffer_view, self._buff_i) + self._buff_i += 5 + elif b == 0xd7: # fixext 8 + typ = TYPE_EXT + if self._max_ext_len < 8: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (8, self._max_ext_len)) + self._reserve(9) + n, obj = struct.unpack_from("b8s", self._buffer_view, self._buff_i) + self._buff_i += 9 + elif b == 0xd8: # fixext 16 + typ = TYPE_EXT + if self._max_ext_len < 16: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (16, self._max_ext_len)) + self._reserve(17) + n, obj = struct.unpack_from("b16s", self._buffer_view, self._buff_i) + self._buff_i += 17 + elif b == 0xd9: + typ = TYPE_RAW + self._reserve(1) + n = self._buffer[self._buff_i] + self._buff_i += 1 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xda: + typ = TYPE_RAW + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xdb: + typ = TYPE_RAW + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xdc: + typ = TYPE_ARRAY + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b == 0xdd: + typ = TYPE_ARRAY + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b == 0xde: + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + typ = TYPE_MAP + elif b == 0xdf: + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + typ = TYPE_MAP + else: + raise UnpackValueError("Unknown header: 0x%x" % b) + return typ, n, obj + + def _unpack(self, execute=EX_CONSTRUCT): + typ, n, obj = self._read_header(execute) + + if execute == EX_READ_ARRAY_HEADER: + if typ != TYPE_ARRAY: + raise UnpackValueError("Expected array") + return n + if execute == EX_READ_MAP_HEADER: + if typ != TYPE_MAP: + raise UnpackValueError("Expected map") + return n + # TODO should we eliminate the recursion? + if typ == TYPE_ARRAY: + if execute == EX_SKIP: + for i in xrange(n): + # TODO check whether we need to call `list_hook` + self._unpack(EX_SKIP) + return + ret = newlist_hint(n) + for i in xrange(n): + ret.append(self._unpack(EX_CONSTRUCT)) + if self._list_hook is not None: + ret = self._list_hook(ret) + # TODO is the interaction between `list_hook` and `use_list` ok? + return ret if self._use_list else tuple(ret) + if typ == TYPE_MAP: + if execute == EX_SKIP: + for i in xrange(n): + # TODO check whether we need to call hooks + self._unpack(EX_SKIP) + self._unpack(EX_SKIP) + return + if self._object_pairs_hook is not None: + ret = self._object_pairs_hook( + (self._unpack(EX_CONSTRUCT), + self._unpack(EX_CONSTRUCT)) + for _ in xrange(n)) + else: + ret = {} + for _ in xrange(n): + key = self._unpack(EX_CONSTRUCT) + ret[key] = self._unpack(EX_CONSTRUCT) + if self._object_hook is not None: + ret = self._object_hook(ret) + return ret + if execute == EX_SKIP: + return + if typ == TYPE_RAW: + if self._encoding is not None: + obj = obj.decode(self._encoding, self._unicode_errors) + elif self._raw: + obj = bytes(obj) + else: + obj = obj.decode('utf_8') + return obj + if typ == TYPE_EXT: + return self._ext_hook(n, bytes(obj)) + if typ == TYPE_BIN: + return bytes(obj) + assert typ == TYPE_IMMEDIATE + return obj + + def __iter__(self): + return self + + def __next__(self): + try: + ret = self._unpack(EX_CONSTRUCT) + self._consume() + return ret + except OutOfData: + self._consume() + raise StopIteration + + next = __next__ + + def skip(self, write_bytes=None): + self._unpack(EX_SKIP) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + + def unpack(self, write_bytes=None): + ret = self._unpack(EX_CONSTRUCT) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def read_array_header(self, write_bytes=None): + ret = self._unpack(EX_READ_ARRAY_HEADER) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def read_map_header(self, write_bytes=None): + ret = self._unpack(EX_READ_MAP_HEADER) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def tell(self): + return self._stream_offset + + +class Packer(object): + """ + MessagePack Packer + + usage: + + packer = Packer() + astream.write(packer.pack(a)) + astream.write(packer.pack(b)) + + Packer's constructor has some keyword arguments: + + :param callable default: + Convert user type to builtin type that Packer supports. + See also simplejson's document. + + :param bool use_single_float: + Use single precision float type for float. (default: False) + + :param bool autoreset: + Reset buffer after each pack and return its content as `bytes`. (default: True). + If set this to false, use `bytes()` to get content and `.reset()` to clear buffer. + + :param bool use_bin_type: + Use bin type introduced in msgpack spec 2.0 for bytes. + It also enables str8 type for unicode. + + :param bool strict_types: + If set to true, types will be checked to be exact. Derived classes + from serializeable types will not be serialized and will be + treated as unsupported type and forwarded to default. + Additionally tuples will not be serialized as lists. + This is useful when trying to implement accurate serialization + for python types. + + :param str encoding: + (deprecated) Convert unicode to bytes with this encoding. (default: 'utf-8') + + :param str unicode_errors: + Error handler for encoding unicode. (default: 'strict') + """ + def __init__(self, default=None, encoding=None, unicode_errors=None, + use_single_float=False, autoreset=True, use_bin_type=False, + strict_types=False): + if encoding is None: + encoding = 'utf_8' + else: + warnings.warn( + "encoding is deprecated, Use raw=False instead.", + PendingDeprecationWarning) + + if unicode_errors is None: + unicode_errors = 'strict' + + self._strict_types = strict_types + self._use_float = use_single_float + self._autoreset = autoreset + self._use_bin_type = use_bin_type + self._encoding = encoding + self._unicode_errors = unicode_errors + self._buffer = StringIO() + if default is not None: + if not callable(default): + raise TypeError("default must be callable") + self._default = default + + def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, + check=isinstance, check_type_strict=_check_type_strict): + default_used = False + if self._strict_types: + check = check_type_strict + list_types = list + else: + list_types = (list, tuple) + while True: + if nest_limit < 0: + raise PackValueError("recursion limit exceeded") + if obj is None: + return self._buffer.write(b"\xc0") + if check(obj, bool): + if obj: + return self._buffer.write(b"\xc3") + return self._buffer.write(b"\xc2") + if check(obj, int_types): + if 0 <= obj < 0x80: + return self._buffer.write(struct.pack("B", obj)) + if -0x20 <= obj < 0: + return self._buffer.write(struct.pack("b", obj)) + if 0x80 <= obj <= 0xff: + return self._buffer.write(struct.pack("BB", 0xcc, obj)) + if -0x80 <= obj < 0: + return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) + if 0xff < obj <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xcd, obj)) + if -0x8000 <= obj < -0x80: + return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) + if 0xffff < obj <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xce, obj)) + if -0x80000000 <= obj < -0x8000: + return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) + if 0xffffffff < obj <= 0xffffffffffffffff: + return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) + if -0x8000000000000000 <= obj < -0x80000000: + return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = True + continue + raise PackOverflowError("Integer value out of range") + if check(obj, (bytes, bytearray)): + n = len(obj) + if n >= 2**32: + raise PackValueError("%s is too large" % type(obj).__name__) + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, Unicode): + if self._encoding is None: + raise TypeError( + "Can't encode unicode string: " + "no encoding is specified") + obj = obj.encode(self._encoding, self._unicode_errors) + n = len(obj) + if n >= 2**32: + raise PackValueError("String is too large") + self._pack_raw_header(n) + return self._buffer.write(obj) + if check(obj, memoryview): + n = len(obj) * obj.itemsize + if n >= 2**32: + raise PackValueError("Memoryview is too large") + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, float): + if self._use_float: + return self._buffer.write(struct.pack(">Bf", 0xca, obj)) + return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) + if check(obj, ExtType): + code = obj.code + data = obj.data + assert isinstance(code, int) + assert isinstance(data, bytes) + L = len(data) + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(struct.pack(">BB", 0xc7, L)) + elif L <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xc8, L)) + else: + self._buffer.write(struct.pack(">BI", 0xc9, L)) + self._buffer.write(struct.pack("b", code)) + self._buffer.write(data) + return + if check(obj, list_types): + n = len(obj) + self._pack_array_header(n) + for i in xrange(n): + self._pack(obj[i], nest_limit - 1) + return + if check(obj, dict): + return self._pack_map_pairs(len(obj), dict_iteritems(obj), + nest_limit - 1) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = 1 + continue + raise TypeError("Cannot serialize %r" % (obj, )) + + def pack(self, obj): + try: + self._pack(obj) + except: + self._buffer = StringIO() # force reset + raise + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_map_pairs(self, pairs): + self._pack_map_pairs(len(pairs), pairs) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_array_header(self, n): + if n >= 2**32: + raise PackValueError + self._pack_array_header(n) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_map_header(self, n): + if n >= 2**32: + raise PackValueError + self._pack_map_header(n) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_ext_type(self, typecode, data): + if not isinstance(typecode, int): + raise TypeError("typecode must have int type.") + if not 0 <= typecode <= 127: + raise ValueError("typecode should be 0-127") + if not isinstance(data, bytes): + raise TypeError("data must have bytes type") + L = len(data) + if L > 0xffffffff: + raise PackValueError("Too large data") + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(b'\xc7' + struct.pack('B', L)) + elif L <= 0xffff: + self._buffer.write(b'\xc8' + struct.pack('>H', L)) + else: + self._buffer.write(b'\xc9' + struct.pack('>I', L)) + self._buffer.write(struct.pack('B', typecode)) + self._buffer.write(data) + + def _pack_array_header(self, n): + if n <= 0x0f: + return self._buffer.write(struct.pack('B', 0x90 + n)) + if n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xdc, n)) + if n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xdd, n)) + raise PackValueError("Array is too large") + + def _pack_map_header(self, n): + if n <= 0x0f: + return self._buffer.write(struct.pack('B', 0x80 + n)) + if n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xde, n)) + if n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xdf, n)) + raise PackValueError("Dict is too large") + + def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT): + self._pack_map_header(n) + for (k, v) in pairs: + self._pack(k, nest_limit - 1) + self._pack(v, nest_limit - 1) + + def _pack_raw_header(self, n): + if n <= 0x1f: + self._buffer.write(struct.pack('B', 0xa0 + n)) + elif self._use_bin_type and n <= 0xff: + self._buffer.write(struct.pack('>BB', 0xd9, n)) + elif n <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xda, n)) + elif n <= 0xffffffff: + self._buffer.write(struct.pack(">BI", 0xdb, n)) + else: + raise PackValueError('Raw is too large') + + def _pack_bin_header(self, n): + if not self._use_bin_type: + return self._pack_raw_header(n) + elif n <= 0xff: + return self._buffer.write(struct.pack('>BB', 0xc4, n)) + elif n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xc5, n)) + elif n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xc6, n)) + else: + raise PackValueError('Bin is too large') + + def bytes(self): + return self._buffer.getvalue() + + def reset(self): + self._buffer = StringIO() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py new file mode 100755 index 0000000..bb79fb7 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "17.1" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2014-2016 %s" % __author__ diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py new file mode 100755 index 0000000..e520d35 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py new file mode 100755 index 0000000..6daa860 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py @@ -0,0 +1,30 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import sys + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = str, +else: + string_types = basestring, + + +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(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py new file mode 100755 index 0000000..3f0c27f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py @@ -0,0 +1,70 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + + +class Infinity(object): + + def __repr__(self): + return "Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return False + + def __le__(self, other): + return False + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return True + + def __ge__(self, other): + return True + + def __neg__(self): + return NegativeInfinity + + +Infinity = Infinity() + + +class NegativeInfinity(object): + + def __repr__(self): + return "-Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return True + + def __le__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return False + + def __ge__(self, other): + return False + + def __neg__(self): + return Infinity + + +NegativeInfinity = NegativeInfinity() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py new file mode 100755 index 0000000..b4dc0b9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py @@ -0,0 +1,301 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import operator +import os +import platform +import sys + +from pip._vendor.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from pip._vendor.pyparsing import ZeroOrMore, Group, Forward, QuotedString +from pip._vendor.pyparsing import Literal as L # noqa + +from ._compat import string_types +from .specifiers import Specifier, InvalidSpecifier + + +__all__ = [ + "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName", + "Marker", "default_environment", +] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Node(object): + + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + def __repr__(self): + return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) + + def serialize(self): + raise NotImplementedError + + +class Variable(Node): + + def serialize(self): + return str(self) + + +class Value(Node): + + def serialize(self): + return '"{0}"'.format(self) + + +class Op(Node): + + def serialize(self): + return str(self) + + +VARIABLE = ( + L("implementation_version") | + L("platform_python_implementation") | + L("implementation_name") | + L("python_full_version") | + L("platform_release") | + L("platform_version") | + L("platform_machine") | + L("platform_system") | + L("python_version") | + L("sys_platform") | + L("os_name") | + L("os.name") | # PEP-345 + L("sys.platform") | # PEP-345 + L("platform.version") | # PEP-345 + L("platform.machine") | # PEP-345 + L("platform.python_implementation") | # PEP-345 + L("python_implementation") | # undocumented setuptools legacy + L("extra") +) +ALIASES = { + 'os.name': 'os_name', + 'sys.platform': 'sys_platform', + 'platform.version': 'platform_version', + 'platform.machine': 'platform_machine', + 'platform.python_implementation': 'platform_python_implementation', + 'python_implementation': 'platform_python_implementation' +} +VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) + +VERSION_CMP = ( + L("===") | + L("==") | + L(">=") | + L("<=") | + L("!=") | + L("~=") | + L(">") | + L("<") +) + +MARKER_OP = VERSION_CMP | L("not in") | L("in") +MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) + +MARKER_VALUE = QuotedString("'") | QuotedString('"') +MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) + +BOOLOP = L("and") | L("or") + +MARKER_VAR = VARIABLE | MARKER_VALUE + +MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) +MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) + +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() + +MARKER_EXPR = Forward() +MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) +MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) + +MARKER = stringStart + MARKER_EXPR + stringEnd + + +def _coerce_parse_result(results): + if isinstance(results, ParseResults): + return [_coerce_parse_result(i) for i in results] + else: + return results + + +def _format_marker(marker, first=True): + assert isinstance(marker, (list, tuple, string_types)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if (isinstance(marker, list) and len(marker) == 1 and + isinstance(marker[0], (list, tuple))): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs, op, rhs): + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs) + + oper = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison( + "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) + ) + + return oper(lhs, rhs) + + +_undefined = object() + + +def _get_env(environment, name): + value = environment.get(name, _undefined) + + if value is _undefined: + raise UndefinedEnvironmentName( + "{0!r} does not exist in evaluation environment.".format(name) + ) + + return value + + +def _evaluate_markers(markers, environment): + groups = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, string_types)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + lhs_value = _get_env(environment, lhs.value) + rhs_value = rhs.value + else: + lhs_value = lhs.value + rhs_value = _get_env(environment, rhs.value) + + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info): + version = '{0.major}.{0.minor}.{0.micro}'.format(info) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + +def default_environment(): + if hasattr(sys, 'implementation'): + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + iver = '0' + implementation_name = '' + + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": platform.python_version()[:3], + "sys_platform": sys.platform, + } + + +class Marker(object): + + def __init__(self, marker): + try: + self._markers = _coerce_parse_result(MARKER.parseString(marker)) + except ParseException as e: + err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( + marker, marker[e.loc:e.loc + 8]) + raise InvalidMarker(err_str) + + def __str__(self): + return _format_marker(self._markers) + + def __repr__(self): + return "<Marker({0!r})>".format(str(self)) + + def evaluate(self, environment=None): + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = default_environment() + if environment is not None: + current_environment.update(environment) + + return _evaluate_markers(self._markers, current_environment) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py new file mode 100755 index 0000000..98bc507 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py @@ -0,0 +1,130 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import string +import re + +from pip._vendor.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from pip._vendor.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from pip._vendor.pyparsing import Literal as L # noqa +from pip._vendor.six.moves.urllib import parse as urlparse + +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r'[^ ]+')("url") +URL = (AT + URI) + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY +VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), + joinString=",", adjacent=False)("_raw_spec") +_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) +_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '') + +VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") +VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start:t._original_end]) +) +MARKER_SEPARATOR = SEMICOLON +MARKER = MARKER_SEPARATOR + MARKER_EXPR + +VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = \ + NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd +# pyparsing isn't thread safe during initialization, so we do it eagerly, see +# issue #104 +REQUIREMENT.parseString("x[]") + + +class Requirement(object): + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException as e: + raise InvalidRequirement( + "Invalid requirement, parse error at \"{0!r}\"".format( + requirement_string[e.loc:e.loc + 8])) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc): + raise InvalidRequirement("Invalid URL given") + self.url = req.url + else: + self.url = None + self.extras = set(req.extras.asList() if req.extras else []) + self.specifier = SpecifierSet(req.specifier) + self.marker = req.marker if req.marker else None + + def __str__(self): + parts = [self.name] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + return "<Requirement({0!r})>".format(str(self)) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py new file mode 100755 index 0000000..7d2fe4c --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py @@ -0,0 +1,774 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from .version import Version, LegacyVersion, parse + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): + + @abc.abstractmethod + def __str__(self): + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} + + def __init__(self, spec="", prereleases=None): + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format( + self.__class__.__name__, + str(self), + pre, + ) + + def __str__(self): + return "{0}{1}".format(*self._spec) + + def __hash__(self): + return hash(self._spec) + + def __eq__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec == other._spec + + def __ne__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + return getattr(self, "_compare_{0}".format(self._operators[op])) + + def _coerce_version(self, version): + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + return self._spec[0] + + @property + def version(self): + return self._spec[1] + + @property + def prereleases(self): + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + return self._get_operator(self.operator)(item, self.version) + + def filter(self, iterable, prereleases=None): + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if (parsed_version.is_prerelease and not + (prereleases or self.prereleases)): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P<operator>(==|!=|<=|>=|<|>)) + \s* + (?P<version> + [^,;\s)]* # Since this is a "legacy" specifier, and the version + # string can be just about anything, we match everything + # except for whitespace, a semi-colon for marker support, + # a closing paren since versions can be enclosed in + # them, and a comma since it's a version separator. + ) + """ + ) + + _regex = re.compile( + r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + return prospective > self._coerce_version(spec) + + +def _require_version_compare(fn): + @functools.wraps(fn) + def wrapped(self, prospective, spec): + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P<operator>(~=|==|!=|<=|>=|<|>|===)) + (?P<version> + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?<!==|!=|~=) # We have special cases for these + # operators so we want to make sure they + # don't match here. + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + ) + """ + ) + + _regex = re.compile( + r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "~=": "compatible", + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") and not + x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return (self._get_operator(">=")(prospective, spec) and + self._get_operator("==")(prospective, prefix)) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + prospective = Version(prospective.public) + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + prospective = prospective[:len(spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + spec, prospective = _pad_version(spec, prospective) + else: + # Convert our spec string into a Version + spec = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec.local: + prospective = Version(prospective.public) + + return prospective == spec + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + return prospective <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is techincally greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + result = [] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]):]) + right_split.append(right[len(right_split[0]):]) + + # Insert our padding + left_split.insert( + 1, + ["0"] * max(0, len(right_split[0]) - len(left_split[0])), + ) + right_split.insert( + 1, + ["0"] * max(0, len(left_split[0]) - len(right_split[0])), + ) + + return ( + list(itertools.chain(*left_split)), + list(itertools.chain(*right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + + def __init__(self, specifiers="", prereleases=None): + # Split on , to break each indidivual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<SpecifierSet({0!r}{1})>".format(str(self), pre) + + def __str__(self): + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + return hash(self._specs) + + def __and__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + return len(self._specs) + + def __iter__(self): + return iter(self._specs) + + @property + def prereleases(self): + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all( + s.contains(item, prereleases=prereleases) + for s in self._specs + ) + + def filter(self, iterable, prereleases=None): + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] + found_prereleases = [] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py new file mode 100755 index 0000000..5151f9f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py @@ -0,0 +1,63 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import re + +from .version import InvalidVersion, Version + + +_canonicalize_regex = re.compile(r"[-_.]+") + + +def canonicalize_name(name): + # This is taken from PEP 503. + return _canonicalize_regex.sub("-", name).lower() + + +def canonicalize_version(version): + """ + This is very similar to Version.__str__, but has one subtle differences + with the way it handles the release segment. + """ + + try: + version = Version(version) + except InvalidVersion: + # Legacy versions cannot be normalized + return version + + parts = [] + + # Epoch + if version.epoch != 0: + parts.append("{0}!".format(version.epoch)) + + # Release segment + # NB: This strips trailing '.0's to normalize + parts.append( + re.sub( + r'(\.0)+$', + '', + ".".join(str(x) for x in version.release) + ) + ) + + # Pre-release + if version.pre is not None: + parts.append("".join(str(x) for x in version.pre)) + + # Post-release + if version.post is not None: + parts.append(".post{0}".format(version.post)) + + # Development release + if version.dev is not None: + parts.append(".dev{0}".format(version.dev)) + + # Local version segment + if version.local is not None: + parts.append("+{0}".format(version.local)) + + return "".join(parts) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py new file mode 100755 index 0000000..a8affbd --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py @@ -0,0 +1,441 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity + + +__all__ = [ + "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN" +] + + +_Version = collections.namedtuple( + "_Version", + ["epoch", "release", "dev", "pre", "post", "local"], +) + + +def parse(version): + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + + def __init__(self, version): + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + return self._version + + def __repr__(self): + return "<LegacyVersion({0})>".format(repr(str(self))) + + @property + def public(self): + return self._version + + @property + def base_version(self): + return self._version + + @property + def epoch(self): + return -1 + + @property + def release(self): + return None + + @property + def pre(self): + return None + + @property + def post(self): + return None + + @property + def dev(self): + return None + + @property + def local(self): + return None + + @property + def is_prerelease(self): + return False + + @property + def is_postrelease(self): + return False + + @property + def is_devrelease(self): + return False + + +_legacy_version_component_re = re.compile( + r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE, +) + +_legacy_version_replacement_map = { + "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@", +} + + +def _parse_version_parts(s): + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + while parts and parts[-1] == "*final-": + parts.pop() + + # remove trailing zeros from each series of numeric parts + while parts and parts[-1] == "00000000": + parts.pop() + + parts.append(part) + parts = tuple(parts) + + return epoch, parts + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P<epoch>[0-9]+)!)? # epoch + (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment + (?P<pre> # pre-release + [-_\.]? + (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) + [-_\.]? + (?P<pre_n>[0-9]+)? + )? + (?P<post> # post release + (?:-(?P<post_n1>[0-9]+)) + | + (?: + [-_\.]? + (?P<post_l>post|rev|r) + [-_\.]? + (?P<post_n2>[0-9]+)? + ) + )? + (?P<dev> # dev release + [-_\.]? + (?P<dev_l>dev) + [-_\.]? + (?P<dev_n>[0-9]+)? + )? + ) + (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version +""" + + +class Version(_BaseVersion): + + _regex = re.compile( + r"^\s*" + VERSION_PATTERN + r"\s*$", + re.VERBOSE | re.IGNORECASE, + ) + + def __init__(self, version): + # Validate the version and parse it into pieces + match = self._regex.search(version) + if not match: + raise InvalidVersion("Invalid version: '{0}'".format(version)) + + # Store the parsed out pieces of the version + self._version = _Version( + epoch=int(match.group("epoch")) if match.group("epoch") else 0, + release=tuple(int(i) for i in match.group("release").split(".")), + pre=_parse_letter_version( + match.group("pre_l"), + match.group("pre_n"), + ), + post=_parse_letter_version( + match.group("post_l"), + match.group("post_n1") or match.group("post_n2"), + ), + dev=_parse_letter_version( + match.group("dev_l"), + match.group("dev_n"), + ), + local=_parse_local_version(match.group("local")), + ) + + # Generate a key which will be used for sorting + self._key = _cmpkey( + self._version.epoch, + self._version.release, + self._version.pre, + self._version.post, + self._version.dev, + self._version.local, + ) + + def __repr__(self): + return "<Version({0})>".format(repr(str(self))) + + def __str__(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + # Pre-release + if self.pre is not None: + parts.append("".join(str(x) for x in self.pre)) + + # Post-release + if self.post is not None: + parts.append(".post{0}".format(self.post)) + + # Development release + if self.dev is not None: + parts.append(".dev{0}".format(self.dev)) + + # Local version segment + if self.local is not None: + parts.append("+{0}".format(self.local)) + + return "".join(parts) + + @property + def epoch(self): + return self._version.epoch + + @property + def release(self): + return self._version.release + + @property + def pre(self): + return self._version.pre + + @property + def post(self): + return self._version.post[1] if self._version.post else None + + @property + def dev(self): + return self._version.dev[1] if self._version.dev else None + + @property + def local(self): + if self._version.local: + return ".".join(str(x) for x in self._version.local) + else: + return None + + @property + def public(self): + return str(self).split("+", 1)[0] + + @property + def base_version(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + return "".join(parts) + + @property + def is_prerelease(self): + return self.dev is not None or self.pre is not None + + @property + def is_postrelease(self): + return self.post is not None + + @property + def is_devrelease(self): + return self.dev is not None + + +def _parse_letter_version(letter, number): + if letter: + # We consider there to be an implicit 0 in a pre-release if there is + # not a numeral associated with it. + if number is None: + number = 0 + + # We normalize any letters to their lower case form + letter = letter.lower() + + # We consider some words to be alternate spellings of other words and + # in those cases we want to normalize the spellings to our preferred + # spelling. + if letter == "alpha": + letter = "a" + elif letter == "beta": + letter = "b" + elif letter in ["c", "pre", "preview"]: + letter = "rc" + elif letter in ["rev", "r"]: + letter = "post" + + return letter, int(number) + if not letter and number: + # We assume if we are given a number, but we are not given a letter + # then this is using the implicit post release syntax (e.g. 1.0-1) + letter = "post" + + return letter, int(number) + + +_local_version_separators = re.compile(r"[\._-]") + + +def _parse_local_version(local): + """ + Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). + """ + if local is not None: + return tuple( + part.lower() if not part.isdigit() else int(part) + for part in _local_version_separators.split(local) + ) + + +def _cmpkey(epoch, release, pre, post, dev, local): + # When we compare a release version, we want to compare it with all of the + # trailing zeros removed. So we'll use a reverse the list, drop all the now + # leading zeros until we come to something non zero, then take the rest + # re-reverse it back into the correct order and make it a tuple and use + # that for our sorting key. + release = tuple( + reversed(list( + itertools.dropwhile( + lambda x: x == 0, + reversed(release), + ) + )) + ) + + # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. + # We'll do this by abusing the pre segment, but we _only_ want to do this + # if there is not a pre or a post segment. If we have one of those then + # the normal sorting rules will handle this case correctly. + if pre is None and post is None and dev is not None: + pre = -Infinity + # Versions without a pre-release (except as noted above) should sort after + # those with one. + elif pre is None: + pre = Infinity + + # Versions without a post segment should sort before those with one. + if post is None: + post = -Infinity + + # Versions without a development segment should sort after those with one. + if dev is None: + dev = Infinity + + if local is None: + # Versions without a local segment should sort before those with one. + local = -Infinity + else: + # Versions with a local segment need that segment parsed to implement + # the sorting rules in PEP440. + # - Alpha numeric segments sort before numeric segments + # - Alpha numeric segments sort lexicographically + # - Numeric segments sort numerically + # - Shorter versions sort before longer versions when the prefixes + # match exactly + local = tuple( + (i, "") if isinstance(i, int) else (-Infinity, i) + for i in local + ) + + return epoch, release, pre, post, dev, local diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py new file mode 100755 index 0000000..6e1fb52 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py @@ -0,0 +1,3125 @@ +# coding: utf-8 +""" +Package resource API +-------------------- + +A resource is a logical file contained within a package, or a logical +subdirectory thereof. The package resource API expects resource names +to have their path parts separated with ``/``, *not* whatever the local +path separator is. Do not use os.path operations to manipulate resource +names being passed into the API. + +The package resource API is designed to work with normal filesystem packages, +.egg files, and unpacked .egg files. It can also work in a limited way with +.zip files and with custom PEP 302 loaders that support the ``get_data()`` +method. +""" + +from __future__ import absolute_import + +import sys +import os +import io +import time +import re +import types +import zipfile +import zipimport +import warnings +import stat +import functools +import pkgutil +import operator +import platform +import collections +import plistlib +import email.parser +import errno +import tempfile +import textwrap +import itertools +import inspect +from pkgutil import get_importer + +try: + import _imp +except ImportError: + # Python 3.2 compatibility + import imp as _imp + +from pip._vendor import six +from pip._vendor.six.moves import urllib, map, filter + +# capture these to bypass sandboxing +from os import utime +try: + from os import mkdir, rename, unlink + WRITE_SUPPORT = True +except ImportError: + # no write support, probably under GAE + WRITE_SUPPORT = False + +from os import open as os_open +from os.path import isdir, split + +try: + import importlib.machinery as importlib_machinery + # access attribute to force import under delayed import mechanisms. + importlib_machinery.__name__ +except ImportError: + importlib_machinery = None + +from . import py31compat +from pip._vendor import appdirs +from pip._vendor import packaging +__import__('pip._vendor.packaging.version') +__import__('pip._vendor.packaging.specifiers') +__import__('pip._vendor.packaging.requirements') +__import__('pip._vendor.packaging.markers') + + +if (3, 0) < sys.version_info < (3, 3): + raise RuntimeError("Python 3.3 or later is required") + +if six.PY2: + # Those builtin exceptions are only defined in Python 3 + PermissionError = None + NotADirectoryError = None + +# declare some globals that will be defined later to +# satisfy the linters. +require = None +working_set = None +add_activation_listener = None +resources_stream = None +cleanup_resources = None +resource_dir = None +resource_stream = None +set_extraction_path = None +resource_isdir = None +resource_string = None +iter_entry_points = None +resource_listdir = None +resource_filename = None +resource_exists = None +_distribution_finders = None +_namespace_handlers = None +_namespace_packages = None + + +class PEP440Warning(RuntimeWarning): + """ + Used when there is an issue with a version or specifier not complying with + PEP 440. + """ + + +def parse_version(v): + try: + return packaging.version.Version(v) + except packaging.version.InvalidVersion: + return packaging.version.LegacyVersion(v) + + +_state_vars = {} + + +def _declare_state(vartype, **kw): + globals().update(kw) + _state_vars.update(dict.fromkeys(kw, vartype)) + + +def __getstate__(): + state = {} + g = globals() + for k, v in _state_vars.items(): + state[k] = g['_sget_' + v](g[k]) + return state + + +def __setstate__(state): + g = globals() + for k, v in state.items(): + g['_sset_' + _state_vars[k]](k, g[k], v) + return state + + +def _sget_dict(val): + return val.copy() + + +def _sset_dict(key, ob, state): + ob.clear() + ob.update(state) + + +def _sget_object(val): + return val.__getstate__() + + +def _sset_object(key, ob, state): + ob.__setstate__(state) + + +_sget_none = _sset_none = lambda *args: None + + +def get_supported_platform(): + """Return this platform's maximum compatible version. + + distutils.util.get_platform() normally reports the minimum version + of Mac OS X that would be required to *use* extensions produced by + distutils. But what we want when checking compatibility is to know the + version of Mac OS X that we are *running*. To allow usage of packages that + explicitly require a newer version of Mac OS X, we must also know the + current version of the OS. + + If this condition occurs for any other platform with a version in its + platform strings, this function should be extended accordingly. + """ + plat = get_build_platform() + m = macosVersionString.match(plat) + if m is not None and sys.platform == "darwin": + try: + plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) + except ValueError: + # not Mac OS X + pass + return plat + + +__all__ = [ + # Basic resource access and distribution/entry point discovery + 'require', 'run_script', 'get_provider', 'get_distribution', + 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'iter_entry_points', + 'resource_string', 'resource_stream', 'resource_filename', + 'resource_listdir', 'resource_exists', 'resource_isdir', + + # Environmental control + 'declare_namespace', 'working_set', 'add_activation_listener', + 'find_distributions', 'set_extraction_path', 'cleanup_resources', + 'get_default_cache', + + # Primary implementation classes + 'Environment', 'WorkingSet', 'ResourceManager', + 'Distribution', 'Requirement', 'EntryPoint', + + # Exceptions + 'ResolutionError', 'VersionConflict', 'DistributionNotFound', + 'UnknownExtra', 'ExtractionError', + + # Warnings + 'PEP440Warning', + + # Parsing functions and string utilities + 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', + 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', + + # filesystem utilities + 'ensure_directory', 'normalize_path', + + # Distribution "precedence" constants + 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', + + # "Provider" interfaces, implementations, and registration/lookup APIs + 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', + 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', + 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', + 'register_finder', 'register_namespace_handler', 'register_loader_type', + 'fixup_namespace_packages', 'get_importer', + + # Deprecated/backward compatibility only + 'run_main', 'AvailableDistributions', +] + + +class ResolutionError(Exception): + """Abstract base for dependency resolution errors""" + + def __repr__(self): + return self.__class__.__name__ + repr(self.args) + + +class VersionConflict(ResolutionError): + """ + An already-installed version conflicts with the requested version. + + Should be initialized with the installed Distribution and the requested + Requirement. + """ + + _template = "{self.dist} is installed but {self.req} is required" + + @property + def dist(self): + return self.args[0] + + @property + def req(self): + return self.args[1] + + def report(self): + return self._template.format(**locals()) + + def with_context(self, required_by): + """ + If required_by is non-empty, return a version of self that is a + ContextualVersionConflict. + """ + if not required_by: + return self + args = self.args + (required_by,) + return ContextualVersionConflict(*args) + + +class ContextualVersionConflict(VersionConflict): + """ + A VersionConflict that accepts a third parameter, the set of the + requirements that required the installed Distribution. + """ + + _template = VersionConflict._template + ' by {self.required_by}' + + @property + def required_by(self): + return self.args[2] + + +class DistributionNotFound(ResolutionError): + """A requested distribution was not found""" + + _template = ("The '{self.req}' distribution was not found " + "and is required by {self.requirers_str}") + + @property + def req(self): + return self.args[0] + + @property + def requirers(self): + return self.args[1] + + @property + def requirers_str(self): + if not self.requirers: + return 'the application' + return ', '.join(self.requirers) + + def report(self): + return self._template.format(**locals()) + + def __str__(self): + return self.report() + + +class UnknownExtra(ResolutionError): + """Distribution doesn't have an "extra feature" of the given name""" + + +_provider_factories = {} + +PY_MAJOR = sys.version[:3] +EGG_DIST = 3 +BINARY_DIST = 2 +SOURCE_DIST = 1 +CHECKOUT_DIST = 0 +DEVELOP_DIST = -1 + + +def register_loader_type(loader_type, provider_factory): + """Register `provider_factory` to make providers for `loader_type` + + `loader_type` is the type or class of a PEP 302 ``module.__loader__``, + and `provider_factory` is a function that, passed a *module* object, + returns an ``IResourceProvider`` for that module. + """ + _provider_factories[loader_type] = provider_factory + + +def get_provider(moduleOrReq): + """Return an IResourceProvider for the named module or requirement""" + if isinstance(moduleOrReq, Requirement): + return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] + try: + module = sys.modules[moduleOrReq] + except KeyError: + __import__(moduleOrReq) + module = sys.modules[moduleOrReq] + loader = getattr(module, '__loader__', None) + return _find_adapter(_provider_factories, loader)(module) + + +def _macosx_vers(_cache=[]): + if not _cache: + version = platform.mac_ver()[0] + # fallback for MacPorts + if version == '': + plist = '/System/Library/CoreServices/SystemVersion.plist' + if os.path.exists(plist): + if hasattr(plistlib, 'readPlist'): + plist_content = plistlib.readPlist(plist) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] + + _cache.append(version.split('.')) + return _cache[0] + + +def _macosx_arch(machine): + return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) + + +def get_build_platform(): + """Return this platform's string for platform-specific distributions + + XXX Currently this is the same as ``distutils.util.get_platform()``, but it + needs some hacks for Linux and Mac OS X. + """ + try: + # Python 2.7 or >=3.2 + from sysconfig import get_platform + except ImportError: + from distutils.util import get_platform + + plat = get_platform() + if sys.platform == "darwin" and not plat.startswith('macosx-'): + try: + version = _macosx_vers() + machine = os.uname()[4].replace(" ", "_") + return "macosx-%d.%d-%s" % ( + int(version[0]), int(version[1]), + _macosx_arch(machine), + ) + except ValueError: + # if someone is running a non-Mac darwin system, this will fall + # through to the default implementation + pass + return plat + + +macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") +darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") +# XXX backward compat +get_platform = get_build_platform + + +def compatible_platforms(provided, required): + """Can code for the `provided` platform run on the `required` platform? + + Returns true if either platform is ``None``, or the platforms are equal. + + XXX Needs compatibility checks for Linux and other unixy OSes. + """ + if provided is None or required is None or provided == required: + # easy case + return True + + # Mac OS X special cases + reqMac = macosVersionString.match(required) + if reqMac: + provMac = macosVersionString.match(provided) + + # is this a Mac package? + if not provMac: + # this is backwards compatibility for packages built before + # setuptools 0.6. All packages built after this point will + # use the new macosx designation. + provDarwin = darwinVersionString.match(provided) + if provDarwin: + dversion = int(provDarwin.group(1)) + macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) + if dversion == 7 and macosversion >= "10.3" or \ + dversion == 8 and macosversion >= "10.4": + return True + # egg isn't macosx or legacy darwin + return False + + # are they the same major version and machine type? + if provMac.group(1) != reqMac.group(1) or \ + provMac.group(3) != reqMac.group(3): + return False + + # is the required OS major update >= the provided one? + if int(provMac.group(2)) > int(reqMac.group(2)): + return False + + return True + + # XXX Linux and other platforms' special cases should go here + return False + + +def run_script(dist_spec, script_name): + """Locate distribution `dist_spec` and run its `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + require(dist_spec)[0].run_script(script_name, ns) + + +# backward compatibility +run_main = run_script + + +def get_distribution(dist): + """Return a current distribution object for a Requirement or string""" + if isinstance(dist, six.string_types): + dist = Requirement.parse(dist) + if isinstance(dist, Requirement): + dist = get_provider(dist) + if not isinstance(dist, Distribution): + raise TypeError("Expected string, Requirement, or Distribution", dist) + return dist + + +def load_entry_point(dist, group, name): + """Return `name` entry point of `group` for `dist` or raise ImportError""" + return get_distribution(dist).load_entry_point(group, name) + + +def get_entry_map(dist, group=None): + """Return the entry point map for `group`, or the full entry map""" + return get_distribution(dist).get_entry_map(group) + + +def get_entry_info(dist, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return get_distribution(dist).get_entry_info(group, name) + + +class IMetadataProvider: + def has_metadata(name): + """Does the package's distribution contain the named metadata?""" + + def get_metadata(name): + """The named metadata resource as a string""" + + def get_metadata_lines(name): + """Yield named metadata resource as list of non-blank non-comment lines + + Leading and trailing whitespace is stripped from each line, and lines + with ``#`` as the first non-blank character are omitted.""" + + def metadata_isdir(name): + """Is the named metadata a directory? (like ``os.path.isdir()``)""" + + def metadata_listdir(name): + """List of metadata names in the directory (like ``os.listdir()``)""" + + def run_script(script_name, namespace): + """Execute the named script in the supplied namespace dictionary""" + + +class IResourceProvider(IMetadataProvider): + """An object that provides access to package resources""" + + def get_resource_filename(manager, resource_name): + """Return a true filesystem path for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_stream(manager, resource_name): + """Return a readable file-like object for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_string(manager, resource_name): + """Return a string containing the contents of `resource_name` + + `manager` must be an ``IResourceManager``""" + + def has_resource(resource_name): + """Does the package contain the named resource?""" + + def resource_isdir(resource_name): + """Is the named resource a directory? (like ``os.path.isdir()``)""" + + def resource_listdir(resource_name): + """List of resource names in the directory (like ``os.listdir()``)""" + + +class WorkingSet(object): + """A collection of active distributions on sys.path (or a similar list)""" + + def __init__(self, entries=None): + """Create working set from list of path entries (default=sys.path)""" + self.entries = [] + self.entry_keys = {} + self.by_key = {} + self.callbacks = [] + + if entries is None: + entries = sys.path + + for entry in entries: + self.add_entry(entry) + + @classmethod + def _build_master(cls): + """ + Prepare the master working set. + """ + ws = cls() + try: + from __main__ import __requires__ + except ImportError: + # The main program does not list any requirements + return ws + + # ensure the requirements are met + try: + ws.require(__requires__) + except VersionConflict: + return cls._build_from_requirements(__requires__) + + return ws + + @classmethod + def _build_from_requirements(cls, req_spec): + """ + Build a working set from a requirement spec. Rewrites sys.path. + """ + # try it without defaults already on sys.path + # by starting with an empty path + ws = cls([]) + reqs = parse_requirements(req_spec) + dists = ws.resolve(reqs, Environment()) + for dist in dists: + ws.add(dist) + + # add any missing entries from sys.path + for entry in sys.path: + if entry not in ws.entries: + ws.add_entry(entry) + + # then copy back to sys.path + sys.path[:] = ws.entries + return ws + + def add_entry(self, entry): + """Add a path item to ``.entries``, finding any distributions on it + + ``find_distributions(entry, True)`` is used to find distributions + corresponding to the path entry, and they are added. `entry` is + always appended to ``.entries``, even if it is already present. + (This is because ``sys.path`` can contain the same value more than + once, and the ``.entries`` of the ``sys.path`` WorkingSet should always + equal ``sys.path``.) + """ + self.entry_keys.setdefault(entry, []) + self.entries.append(entry) + for dist in find_distributions(entry, True): + self.add(dist, entry, False) + + def __contains__(self, dist): + """True if `dist` is the active distribution for its project""" + return self.by_key.get(dist.key) == dist + + def find(self, req): + """Find a distribution matching requirement `req` + + If there is an active distribution for the requested project, this + returns it as long as it meets the version requirement specified by + `req`. But, if there is an active distribution for the project and it + does *not* meet the `req` requirement, ``VersionConflict`` is raised. + If there is no active distribution for the requested project, ``None`` + is returned. + """ + dist = self.by_key.get(req.key) + if dist is not None and dist not in req: + # XXX add more info + raise VersionConflict(dist, req) + return dist + + def iter_entry_points(self, group, name=None): + """Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set, otherwise only ones matching + both `group` and `name` are yielded (in distribution order). + """ + for dist in self: + entries = dist.get_entry_map(group) + if name is None: + for ep in entries.values(): + yield ep + elif name in entries: + yield entries[name] + + def run_script(self, requires, script_name): + """Locate distribution for `requires` and run `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + self.require(requires)[0].run_script(script_name, ns) + + def __iter__(self): + """Yield distributions for non-duplicate projects in the working set + + The yield order is the order in which the items' path entries were + added to the working set. + """ + seen = {} + for item in self.entries: + if item not in self.entry_keys: + # workaround a cache issue + continue + + for key in self.entry_keys[item]: + if key not in seen: + seen[key] = 1 + yield self.by_key[key] + + def add(self, dist, entry=None, insert=True, replace=False): + """Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to the ``.location`` of `dist`. + On exit from this routine, `entry` is added to the end of the working + set's ``.entries`` (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution in the set, unless `replace=True`. + If it's added, any callbacks registered with the ``subscribe()`` method + will be called. + """ + if insert: + dist.insert_on(self.entries, entry, replace=replace) + + if entry is None: + entry = dist.location + keys = self.entry_keys.setdefault(entry, []) + keys2 = self.entry_keys.setdefault(dist.location, []) + if not replace and dist.key in self.by_key: + # ignore hidden distros + return + + self.by_key[dist.key] = dist + if dist.key not in keys: + keys.append(dist.key) + if dist.key not in keys2: + keys2.append(dist.key) + self._added_new(dist) + + def resolve(self, requirements, env=None, installer=None, + replace_conflicting=False, extras=None): + """List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, it defaults to all distributions available within any + entry or distribution in the working set. `installer`, if supplied, + will be invoked with each requirement that cannot be met by an + already-installed distribution; it should return a ``Distribution`` or + ``None``. + + Unless `replace_conflicting=True`, raises a VersionConflict exception + if + any requirements are found on the path that have the correct name but + the wrong version. Otherwise, if an `installer` is supplied it will be + invoked to obtain the correct version of the requirement and activate + it. + + `extras` is a list of the extras to be used with these requirements. + This is important because extra requirements may look like `my_req; + extra = "my_extra"`, which would otherwise be interpreted as a purely + optional requirement. Instead, we want to be able to assert that these + requirements are truly required. + """ + + # set up the stack + requirements = list(requirements)[::-1] + # set of processed requirements + processed = {} + # key -> dist + best = {} + to_activate = [] + + req_extras = _ReqExtras() + + # Mapping of requirement to set of distributions that required it; + # useful for reporting info about conflicts. + required_by = collections.defaultdict(set) + + while requirements: + # process dependencies breadth-first + req = requirements.pop(0) + if req in processed: + # Ignore cyclic or redundant dependencies + continue + + if not req_extras.markers_pass(req, extras): + continue + + dist = best.get(req.key) + if dist is None: + # Find the best distribution and add it to the map + dist = self.by_key.get(req.key) + if dist is None or (dist not in req and replace_conflicting): + ws = self + if env is None: + if dist is None: + env = Environment(self.entries) + else: + # Use an empty environment and workingset to avoid + # any further conflicts with the conflicting + # distribution + env = Environment([]) + ws = WorkingSet([]) + dist = best[req.key] = env.best_match( + req, ws, installer, + replace_conflicting=replace_conflicting + ) + if dist is None: + requirers = required_by.get(req, None) + raise DistributionNotFound(req, requirers) + to_activate.append(dist) + if dist not in req: + # Oops, the "best" so far conflicts with a dependency + dependent_req = required_by[req] + raise VersionConflict(dist, req).with_context(dependent_req) + + # push the new requirements onto the stack + new_requirements = dist.requires(req.extras)[::-1] + requirements.extend(new_requirements) + + # Register the new requirements needed by req + for new_requirement in new_requirements: + required_by[new_requirement].add(req.project_name) + req_extras[new_requirement] = req.extras + + processed[req] = True + + # return list of distros to activate + return to_activate + + def find_plugins( + self, plugin_env, full_env=None, installer=None, fallback=True): + """Find all activatable distributions in `plugin_env` + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + # add plugins+libs to sys.path + map(working_set.add, distributions) + # display errors + print('Could not load', errors) + + The `plugin_env` should be an ``Environment`` instance that contains + only distributions that are in the project's "plugin directory" or + directories. The `full_env`, if supplied, should be an ``Environment`` + contains all currently-available distributions. If `full_env` is not + supplied, one is created automatically from the ``WorkingSet`` this + method is called on, which will typically mean that every directory on + ``sys.path`` will be scanned for distributions. + + `installer` is a standard installer callback as used by the + ``resolve()`` method. The `fallback` flag indicates whether we should + attempt to resolve older versions of a plugin if the newest version + cannot be resolved. + + This method returns a 2-tuple: (`distributions`, `error_info`), where + `distributions` is a list of the distributions found in `plugin_env` + that were loadable, along with any other distributions that are needed + to resolve their dependencies. `error_info` is a dictionary mapping + unloadable plugin distributions to an exception instance describing the + error that occurred. Usually this will be a ``DistributionNotFound`` or + ``VersionConflict`` instance. + """ + + plugin_projects = list(plugin_env) + # scan project names in alphabetic order + plugin_projects.sort() + + error_info = {} + distributions = {} + + if full_env is None: + env = Environment(self.entries) + env += plugin_env + else: + env = full_env + plugin_env + + shadow_set = self.__class__([]) + # put all our entries in shadow_set + list(map(shadow_set.add, self)) + + for project_name in plugin_projects: + + for dist in plugin_env[project_name]: + + req = [dist.as_requirement()] + + try: + resolvees = shadow_set.resolve(req, env, installer) + + except ResolutionError as v: + # save error info + error_info[dist] = v + if fallback: + # try the next older version of project + continue + else: + # give up on this project, keep going + break + + else: + list(map(shadow_set.add, resolvees)) + distributions.update(dict.fromkeys(resolvees)) + + # success, no need to try any more versions of this project + break + + distributions = list(distributions) + distributions.sort() + + return distributions, error_info + + def require(self, *requirements): + """Ensure that distributions matching `requirements` are activated + + `requirements` must be a string or a (possibly-nested) sequence + thereof, specifying the distributions and versions required. The + return value is a sequence of the distributions that needed to be + activated to fulfill the requirements; all relevant distributions are + included, even if they were already activated in this working set. + """ + needed = self.resolve(parse_requirements(requirements)) + + for dist in needed: + self.add(dist) + + return needed + + def subscribe(self, callback, existing=True): + """Invoke `callback` for all distributions + + If `existing=True` (default), + call on all existing ones, as well. + """ + if callback in self.callbacks: + return + self.callbacks.append(callback) + if not existing: + return + for dist in self: + callback(dist) + + def _added_new(self, dist): + for callback in self.callbacks: + callback(dist) + + def __getstate__(self): + return ( + self.entries[:], self.entry_keys.copy(), self.by_key.copy(), + self.callbacks[:] + ) + + def __setstate__(self, e_k_b_c): + entries, keys, by_key, callbacks = e_k_b_c + self.entries = entries[:] + self.entry_keys = keys.copy() + self.by_key = by_key.copy() + self.callbacks = callbacks[:] + + +class _ReqExtras(dict): + """ + Map each requirement to the extras that demanded it. + """ + + def markers_pass(self, req, extras=None): + """ + Evaluate markers for req against each extra that + demanded it. + + Return False if the req has a marker and fails + evaluation. Otherwise, return True. + """ + extra_evals = ( + req.marker.evaluate({'extra': extra}) + for extra in self.get(req, ()) + (extras or (None,)) + ) + return not req.marker or any(extra_evals) + + +class Environment(object): + """Searchable snapshot of distributions on a search path""" + + def __init__( + self, search_path=None, platform=get_supported_platform(), + python=PY_MAJOR): + """Snapshot distributions available on a search path + + Any distributions found on `search_path` are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. + + `platform` is an optional string specifying the name of the platform + that platform-specific distributions must be compatible with. If + unspecified, it defaults to the current platform. `python` is an + optional string naming the desired version of Python (e.g. ``'3.3'``); + it defaults to the current version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to map *all* distributions, not just those compatible with the + running platform or Python version. + """ + self._distmap = {} + self.platform = platform + self.python = python + self.scan(search_path) + + def can_add(self, dist): + """Is distribution `dist` acceptable for this environment? + + The distribution must match the platform and python version + requirements specified when this environment was created, or False + is returned. + """ + py_compat = ( + self.python is None + or dist.py_version is None + or dist.py_version == self.python + ) + return py_compat and compatible_platforms(dist.platform, self.platform) + + def remove(self, dist): + """Remove `dist` from the environment""" + self._distmap[dist.key].remove(dist) + + def scan(self, search_path=None): + """Scan `search_path` for distributions usable in this environment + + Any distributions found are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. + """ + if search_path is None: + search_path = sys.path + + for item in search_path: + for dist in find_distributions(item): + self.add(dist) + + def __getitem__(self, project_name): + """Return a newest-to-oldest list of distributions for `project_name` + + Uses case-insensitive `project_name` comparison, assuming all the + project's distributions use their project's name converted to all + lowercase as their key. + + """ + distribution_key = project_name.lower() + return self._distmap.get(distribution_key, []) + + def add(self, dist): + """Add `dist` if we ``can_add()`` it and it has not already been added + """ + if self.can_add(dist) and dist.has_version(): + dists = self._distmap.setdefault(dist.key, []) + if dist not in dists: + dists.append(dist) + dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) + + def best_match( + self, req, working_set, installer=None, replace_conflicting=False): + """Find distribution best matching `req` and usable on `working_set` + + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution + isn't active, this method returns the newest distribution in the + environment that meets the ``Requirement`` in `req`. If no suitable + distribution is found, and `installer` is supplied, then the result of + calling the environment's ``obtain(req, installer)`` method will be + returned. + """ + try: + dist = working_set.find(req) + except VersionConflict: + if not replace_conflicting: + raise + dist = None + if dist is not None: + return dist + for dist in self[req.key]: + if dist in req: + return dist + # try to download/install + return self.obtain(req, installer) + + def obtain(self, requirement, installer=None): + """Obtain a distribution matching `requirement` (e.g. via download) + + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument.""" + if installer is not None: + return installer(requirement) + + def __iter__(self): + """Yield the unique project names of the available distributions""" + for key in self._distmap.keys(): + if self[key]: + yield key + + def __iadd__(self, other): + """In-place addition of a distribution or environment""" + if isinstance(other, Distribution): + self.add(other) + elif isinstance(other, Environment): + for project in other: + for dist in other[project]: + self.add(dist) + else: + raise TypeError("Can't add %r to environment" % (other,)) + return self + + def __add__(self, other): + """Add an environment or distribution to an environment""" + new = self.__class__([], platform=None, python=None) + for env in self, other: + new += env + return new + + +# XXX backward compatibility +AvailableDistributions = Environment + + +class ExtractionError(RuntimeError): + """An error occurred extracting a resource + + The following attributes are available from instances of this exception: + + manager + The resource manager that raised this exception + + cache_path + The base directory for resource extraction + + original_error + The exception instance that caused extraction to fail + """ + + +class ResourceManager: + """Manage resource extraction and packages""" + extraction_path = None + + def __init__(self): + self.cached_files = {} + + def resource_exists(self, package_or_requirement, resource_name): + """Does the named resource exist?""" + return get_provider(package_or_requirement).has_resource(resource_name) + + def resource_isdir(self, package_or_requirement, resource_name): + """Is the named resource an existing directory?""" + return get_provider(package_or_requirement).resource_isdir( + resource_name + ) + + def resource_filename(self, package_or_requirement, resource_name): + """Return a true filesystem path for specified resource""" + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name + ) + + def resource_stream(self, package_or_requirement, resource_name): + """Return a readable file-like object for specified resource""" + return get_provider(package_or_requirement).get_resource_stream( + self, resource_name + ) + + def resource_string(self, package_or_requirement, resource_name): + """Return specified resource as a string""" + return get_provider(package_or_requirement).get_resource_string( + self, resource_name + ) + + def resource_listdir(self, package_or_requirement, resource_name): + """List the contents of the named resource directory""" + return get_provider(package_or_requirement).resource_listdir( + resource_name + ) + + def extraction_error(self): + """Give an error message for problems extracting file(s)""" + + old_exc = sys.exc_info()[1] + cache_path = self.extraction_path or get_default_cache() + + tmpl = textwrap.dedent(""" + Can't extract file(s) to egg cache + + The following error occurred while trying to extract file(s) + to the Python egg cache: + + {old_exc} + + The Python egg cache directory is currently set to: + + {cache_path} + + Perhaps your account does not have write access to this directory? + You can change the cache directory by setting the PYTHON_EGG_CACHE + environment variable to point to an accessible directory. + """).lstrip() + err = ExtractionError(tmpl.format(**locals())) + err.manager = self + err.cache_path = cache_path + err.original_error = old_exc + raise err + + def get_cache_path(self, archive_name, names=()): + """Return absolute location in cache for `archive_name` and `names` + + The parent directory of the resulting path will be created if it does + not already exist. `archive_name` should be the base filename of the + enclosing egg (which may not be the name of the enclosing zipfile!), + including its ".egg" extension. `names`, if provided, should be a + sequence of path name parts "under" the egg's extraction location. + + This method should only be called by resource providers that need to + obtain an extraction location, and only for names they intend to + extract, as it tracks the generated names for possible cleanup later. + """ + extract_path = self.extraction_path or get_default_cache() + target_path = os.path.join(extract_path, archive_name + '-tmp', *names) + try: + _bypass_ensure_directory(target_path) + except Exception: + self.extraction_error() + + self._warn_unsafe_extraction_path(extract_path) + + self.cached_files[target_path] = 1 + return target_path + + @staticmethod + def _warn_unsafe_extraction_path(path): + """ + If the default extraction path is overridden and set to an insecure + location, such as /tmp, it opens up an opportunity for an attacker to + replace an extracted file with an unauthorized payload. Warn the user + if a known insecure location is used. + + See Distribute #375 for more details. + """ + if os.name == 'nt' and not path.startswith(os.environ['windir']): + # On Windows, permissions are generally restrictive by default + # and temp directories are not writable by other users, so + # bypass the warning. + return + mode = os.stat(path).st_mode + if mode & stat.S_IWOTH or mode & stat.S_IWGRP: + msg = ( + "%s is writable by group/others and vulnerable to attack " + "when " + "used with get_resource_filename. Consider a more secure " + "location (set with .set_extraction_path or the " + "PYTHON_EGG_CACHE environment variable)." % path + ) + warnings.warn(msg, UserWarning) + + def postprocess(self, tempname, filename): + """Perform any platform-specific postprocessing of `tempname` + + This is where Mac header rewrites should be done; other platforms don't + have anything special they should do. + + Resource providers should call this method ONLY after successfully + extracting a compressed resource. They must NOT call it on resources + that are already in the filesystem. + + `tempname` is the current (temporary) name of the file, and `filename` + is the name it will be renamed to by the caller after this routine + returns. + """ + + if os.name == 'posix': + # Make the resource executable + mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 + os.chmod(tempname, mode) + + def set_extraction_path(self, path): + """Set the base path where resources will be extracted to, if needed. + + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which + is based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + + Resources are extracted to subdirectories of this path based upon + information given by the ``IResourceProvider``. You may set this to a + temporary directory, but then you must call ``cleanup_resources()`` to + delete the extracted files when done. There is no guarantee that + ``cleanup_resources()`` will be able to remove all extracted files. + + (Note: you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``.) + """ + if self.cached_files: + raise ValueError( + "Can't change extraction path, files already extracted" + ) + + self.extraction_path = path + + def cleanup_resources(self, force=False): + """ + Delete all extracted resource files and directories, returning a list + of the file and directory names that could not be successfully removed. + This function does not have any concurrency protection, so it should + generally only be called when the extraction path is a temporary + directory exclusive to a single process. This method is not + automatically called; you must call it explicitly or register it as an + ``atexit`` function if you wish to ensure cleanup of a temporary + directory used for extractions. + """ + # XXX + + +def get_default_cache(): + """ + Return the ``PYTHON_EGG_CACHE`` environment variable + or a platform-relevant user cache dir for an app + named "Python-Eggs". + """ + return ( + os.environ.get('PYTHON_EGG_CACHE') + or appdirs.user_cache_dir(appname='Python-Eggs') + ) + + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """ + Convert an arbitrary string to a standard version string + """ + try: + # normalize the version + return str(packaging.version.Version(version)) + except packaging.version.InvalidVersion: + version = version.replace(' ', '.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def safe_extra(extra): + """Convert an arbitrary string to a standard 'extra' name + + Any runs of non-alphanumeric characters are replaced with a single '_', + and the result is always lowercased. + """ + return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower() + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-', '_') + + +def invalid_marker(text): + """ + Validate text as a PEP 508 environment marker; return an exception + if invalid or False otherwise. + """ + try: + evaluate_marker(text) + except SyntaxError as e: + e.filename = None + e.lineno = None + return e + return False + + +def evaluate_marker(text, extra=None): + """ + Evaluate a PEP 508 environment marker. + Return a boolean indicating the marker result in this environment. + Raise SyntaxError if marker is invalid. + + This implementation uses the 'pyparsing' module. + """ + try: + marker = packaging.markers.Marker(text) + return marker.evaluate() + except packaging.markers.InvalidMarker as e: + raise SyntaxError(e) + + +class NullProvider: + """Try to implement resources and metadata for arbitrary PEP 302 loaders""" + + egg_name = None + egg_info = None + loader = None + + def __init__(self, module): + self.loader = getattr(module, '__loader__', None) + self.module_path = os.path.dirname(getattr(module, '__file__', '')) + + def get_resource_filename(self, manager, resource_name): + return self._fn(self.module_path, resource_name) + + def get_resource_stream(self, manager, resource_name): + return io.BytesIO(self.get_resource_string(manager, resource_name)) + + def get_resource_string(self, manager, resource_name): + return self._get(self._fn(self.module_path, resource_name)) + + def has_resource(self, resource_name): + return self._has(self._fn(self.module_path, resource_name)) + + def has_metadata(self, name): + return self.egg_info and self._has(self._fn(self.egg_info, name)) + + def get_metadata(self, name): + if not self.egg_info: + return "" + value = self._get(self._fn(self.egg_info, name)) + return value.decode('utf-8') if six.PY3 else value + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + def resource_isdir(self, resource_name): + return self._isdir(self._fn(self.module_path, resource_name)) + + def metadata_isdir(self, name): + return self.egg_info and self._isdir(self._fn(self.egg_info, name)) + + def resource_listdir(self, resource_name): + return self._listdir(self._fn(self.module_path, resource_name)) + + def metadata_listdir(self, name): + if self.egg_info: + return self._listdir(self._fn(self.egg_info, name)) + return [] + + def run_script(self, script_name, namespace): + script = 'scripts/' + script_name + if not self.has_metadata(script): + raise ResolutionError( + "Script {script!r} not found in metadata at {self.egg_info!r}" + .format(**locals()), + ) + script_text = self.get_metadata(script).replace('\r\n', '\n') + script_text = script_text.replace('\r', '\n') + script_filename = self._fn(self.egg_info, script) + namespace['__file__'] = script_filename + if os.path.exists(script_filename): + source = open(script_filename).read() + code = compile(source, script_filename, 'exec') + exec(code, namespace, namespace) + else: + from linecache import cache + cache[script_filename] = ( + len(script_text), 0, script_text.split('\n'), script_filename + ) + script_code = compile(script_text, script_filename, 'exec') + exec(script_code, namespace, namespace) + + def _has(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _isdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _listdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _fn(self, base, resource_name): + if resource_name: + return os.path.join(base, *resource_name.split('/')) + return base + + def _get(self, path): + if hasattr(self.loader, 'get_data'): + return self.loader.get_data(path) + raise NotImplementedError( + "Can't perform this operation for loaders without 'get_data()'" + ) + + +register_loader_type(object, NullProvider) + + +class EggProvider(NullProvider): + """Provider based on a virtual filesystem""" + + def __init__(self, module): + NullProvider.__init__(self, module) + self._setup_prefix() + + def _setup_prefix(self): + # we assume here that our metadata may be nested inside a "basket" + # of multiple eggs; that's why we use module_path instead of .archive + path = self.module_path + old = None + while path != old: + if _is_egg_path(path): + self.egg_name = os.path.basename(path) + self.egg_info = os.path.join(path, 'EGG-INFO') + self.egg_root = path + break + old = path + path, base = os.path.split(path) + + +class DefaultProvider(EggProvider): + """Provides access to package resources in the filesystem""" + + def _has(self, path): + return os.path.exists(path) + + def _isdir(self, path): + return os.path.isdir(path) + + def _listdir(self, path): + return os.listdir(path) + + def get_resource_stream(self, manager, resource_name): + return open(self._fn(self.module_path, resource_name), 'rb') + + def _get(self, path): + with open(path, 'rb') as stream: + return stream.read() + + @classmethod + def _register(cls): + loader_cls = getattr( + importlib_machinery, + 'SourceFileLoader', + type(None), + ) + register_loader_type(loader_cls, cls) + + +DefaultProvider._register() + + +class EmptyProvider(NullProvider): + """Provider that returns nothing for all requests""" + + module_path = None + + _isdir = _has = lambda self, path: False + + def _get(self, path): + return '' + + def _listdir(self, path): + return [] + + def __init__(self): + pass + + +empty_provider = EmptyProvider() + + +class ZipManifests(dict): + """ + zip manifest builder + """ + + @classmethod + def build(cls, path): + """ + Build a dictionary similar to the zipimport directory + caches, except instead of tuples, store ZipInfo objects. + + Use a platform-specific path separator (os.sep) for the path keys + for compatibility with pypy on Windows. + """ + with zipfile.ZipFile(path) as zfile: + items = ( + ( + name.replace('/', os.sep), + zfile.getinfo(name), + ) + for name in zfile.namelist() + ) + return dict(items) + + load = build + + +class MemoizedZipManifests(ZipManifests): + """ + Memoized zipfile manifests. + """ + manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') + + def load(self, path): + """ + Load a manifest at path or return a suitable manifest already loaded. + """ + path = os.path.normpath(path) + mtime = os.stat(path).st_mtime + + if path not in self or self[path].mtime != mtime: + manifest = self.build(path) + self[path] = self.manifest_mod(manifest, mtime) + + return self[path].manifest + + +class ZipProvider(EggProvider): + """Resource support for zips and eggs""" + + eagers = None + _zip_manifests = MemoizedZipManifests() + + def __init__(self, module): + EggProvider.__init__(self, module) + self.zip_pre = self.loader.archive + os.sep + + def _zipinfo_name(self, fspath): + # Convert a virtual filename (full path to file) into a zipfile subpath + # usable with the zipimport directory cache for our target archive + fspath = fspath.rstrip(os.sep) + if fspath == self.loader.archive: + return '' + if fspath.startswith(self.zip_pre): + return fspath[len(self.zip_pre):] + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.zip_pre) + ) + + def _parts(self, zip_path): + # Convert a zipfile subpath into an egg-relative path part list. + # pseudo-fs path + fspath = self.zip_pre + zip_path + if fspath.startswith(self.egg_root + os.sep): + return fspath[len(self.egg_root) + 1:].split(os.sep) + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.egg_root) + ) + + @property + def zipinfo(self): + return self._zip_manifests.load(self.loader.archive) + + def get_resource_filename(self, manager, resource_name): + if not self.egg_name: + raise NotImplementedError( + "resource_filename() only supported for .egg, not .zip" + ) + # no need to lock for extraction, since we use temp names + zip_path = self._resource_to_zip(resource_name) + eagers = self._get_eager_resources() + if '/'.join(self._parts(zip_path)) in eagers: + for name in eagers: + self._extract_resource(manager, self._eager_to_zip(name)) + return self._extract_resource(manager, zip_path) + + @staticmethod + def _get_date_and_size(zip_stat): + size = zip_stat.file_size + # ymdhms+wday, yday, dst + date_time = zip_stat.date_time + (0, 0, -1) + # 1980 offset already done + timestamp = time.mktime(date_time) + return timestamp, size + + def _extract_resource(self, manager, zip_path): + + if zip_path in self._index(): + for name in self._index()[zip_path]: + last = self._extract_resource( + manager, os.path.join(zip_path, name) + ) + # return the extracted directory name + return os.path.dirname(last) + + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + + if not WRITE_SUPPORT: + raise IOError('"os.rename" and "os.unlink" are not supported ' + 'on this platform') + try: + + real_path = manager.get_cache_path( + self.egg_name, self._parts(zip_path) + ) + + if self._is_current(real_path, zip_path): + return real_path + + outf, tmpnam = _mkstemp( + ".$extract", + dir=os.path.dirname(real_path), + ) + os.write(outf, self.loader.get_data(zip_path)) + os.close(outf) + utime(tmpnam, (timestamp, timestamp)) + manager.postprocess(tmpnam, real_path) + + try: + rename(tmpnam, real_path) + + except os.error: + if os.path.isfile(real_path): + if self._is_current(real_path, zip_path): + # the file became current since it was checked above, + # so proceed. + return real_path + # Windows, del old file and retry + elif os.name == 'nt': + unlink(real_path) + rename(tmpnam, real_path) + return real_path + raise + + except os.error: + # report a user-friendly error + manager.extraction_error() + + return real_path + + def _is_current(self, file_path, zip_path): + """ + Return True if the file_path is current for this zip_path + """ + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + if not os.path.isfile(file_path): + return False + stat = os.stat(file_path) + if stat.st_size != size or stat.st_mtime != timestamp: + return False + # check that the contents match + zip_contents = self.loader.get_data(zip_path) + with open(file_path, 'rb') as f: + file_contents = f.read() + return zip_contents == file_contents + + def _get_eager_resources(self): + if self.eagers is None: + eagers = [] + for name in ('native_libs.txt', 'eager_resources.txt'): + if self.has_metadata(name): + eagers.extend(self.get_metadata_lines(name)) + self.eagers = eagers + return self.eagers + + def _index(self): + try: + return self._dirindex + except AttributeError: + ind = {} + for path in self.zipinfo: + parts = path.split(os.sep) + while parts: + parent = os.sep.join(parts[:-1]) + if parent in ind: + ind[parent].append(parts[-1]) + break + else: + ind[parent] = [parts.pop()] + self._dirindex = ind + return ind + + def _has(self, fspath): + zip_path = self._zipinfo_name(fspath) + return zip_path in self.zipinfo or zip_path in self._index() + + def _isdir(self, fspath): + return self._zipinfo_name(fspath) in self._index() + + def _listdir(self, fspath): + return list(self._index().get(self._zipinfo_name(fspath), ())) + + def _eager_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.egg_root, resource_name)) + + def _resource_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.module_path, resource_name)) + + +register_loader_type(zipimport.zipimporter, ZipProvider) + + +class FileMetadata(EmptyProvider): + """Metadata handler for standalone PKG-INFO files + + Usage:: + + metadata = FileMetadata("/path/to/PKG-INFO") + + This provider rejects all data and metadata requests except for PKG-INFO, + which is treated as existing, and will be the contents of the file at + the provided location. + """ + + def __init__(self, path): + self.path = path + + def has_metadata(self, name): + return name == 'PKG-INFO' and os.path.isfile(self.path) + + def get_metadata(self, name): + if name != 'PKG-INFO': + raise KeyError("No metadata except PKG-INFO is available") + + with io.open(self.path, encoding='utf-8', errors="replace") as f: + metadata = f.read() + self._warn_on_replacement(metadata) + return metadata + + def _warn_on_replacement(self, metadata): + # Python 2.7 compat for: replacement_char = '�' + replacement_char = b'\xef\xbf\xbd'.decode('utf-8') + if replacement_char in metadata: + tmpl = "{self.path} could not be properly decoded in UTF-8" + msg = tmpl.format(**locals()) + warnings.warn(msg) + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + +class PathMetadata(DefaultProvider): + """Metadata provider for egg directories + + Usage:: + + # Development eggs: + + egg_info = "/path/to/PackageName.egg-info" + base_dir = os.path.dirname(egg_info) + metadata = PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + dist = Distribution(basedir, project_name=dist_name, metadata=metadata) + + # Unpacked egg directories: + + egg_path = "/path/to/PackageName-ver-pyver-etc.egg" + metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) + dist = Distribution.from_filename(egg_path, metadata=metadata) + """ + + def __init__(self, path, egg_info): + self.module_path = path + self.egg_info = egg_info + + +class EggMetadata(ZipProvider): + """Metadata provider for .egg files""" + + def __init__(self, importer): + """Create a metadata provider from a zipimporter""" + + self.zip_pre = importer.archive + os.sep + self.loader = importer + if importer.prefix: + self.module_path = os.path.join(importer.archive, importer.prefix) + else: + self.module_path = importer.archive + self._setup_prefix() + + +_declare_state('dict', _distribution_finders={}) + + +def register_finder(importer_type, distribution_finder): + """Register `distribution_finder` to find distributions in sys.path items + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `distribution_finder` is a callable that, passed a path + item and the importer instance, yields ``Distribution`` instances found on + that path item. See ``pkg_resources.find_on_path`` for an example.""" + _distribution_finders[importer_type] = distribution_finder + + +def find_distributions(path_item, only=False): + """Yield distributions accessible via `path_item`""" + importer = get_importer(path_item) + finder = _find_adapter(_distribution_finders, importer) + return finder(importer, path_item, only) + + +def find_eggs_in_zip(importer, path_item, only=False): + """ + Find eggs in zip files; possibly multiple nested eggs. + """ + if importer.archive.endswith('.whl'): + # wheels are not supported with this finder + # they don't have PKG-INFO metadata, and won't ever contain eggs + return + metadata = EggMetadata(importer) + if metadata.has_metadata('PKG-INFO'): + yield Distribution.from_filename(path_item, metadata=metadata) + if only: + # don't yield nested distros + return + for subitem in metadata.resource_listdir('/'): + if _is_egg_path(subitem): + subpath = os.path.join(path_item, subitem) + dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath) + for dist in dists: + yield dist + elif subitem.lower().endswith('.dist-info'): + subpath = os.path.join(path_item, subitem) + submeta = EggMetadata(zipimport.zipimporter(subpath)) + submeta.egg_info = subpath + yield Distribution.from_location(path_item, subitem, submeta) + + +register_finder(zipimport.zipimporter, find_eggs_in_zip) + + +def find_nothing(importer, path_item, only=False): + return () + + +register_finder(object, find_nothing) + + +def _by_version_descending(names): + """ + Given a list of filenames, return them in descending order + by version number. + + >>> names = 'bar', 'foo', 'Python-2.7.10.egg', 'Python-2.7.2.egg' + >>> _by_version_descending(names) + ['Python-2.7.10.egg', 'Python-2.7.2.egg', 'foo', 'bar'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.egg', 'Setuptools-1.2.3b1.egg'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.post1.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg'] + """ + def _by_version(name): + """ + Parse each component of the filename + """ + name, ext = os.path.splitext(name) + parts = itertools.chain(name.split('-'), [ext]) + return [packaging.version.parse(part) for part in parts] + + return sorted(names, key=_by_version, reverse=True) + + +def find_on_path(importer, path_item, only=False): + """Yield distributions accessible on a sys.path directory""" + path_item = _normalize_cached(path_item) + + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item, 'EGG-INFO') + ) + ) + return + + entries = safe_listdir(path_item) + + # for performance, before sorting by version, + # screen entries for only those that will yield + # distributions + filtered = ( + entry + for entry in entries + if dist_factory(path_item, entry, only) + ) + + # scan for .egg and .egg-info in directory + path_item_entries = _by_version_descending(filtered) + for entry in path_item_entries: + fullpath = os.path.join(path_item, entry) + factory = dist_factory(path_item, entry, only) + for dist in factory(fullpath): + yield dist + + +def dist_factory(path_item, entry, only): + """ + Return a dist_factory for a path_item and entry + """ + lower = entry.lower() + is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info'))) + return ( + distributions_from_metadata + if is_meta else + find_distributions + if not only and _is_egg_path(entry) else + resolve_egg_link + if not only and lower.endswith('.egg-link') else + NoDists() + ) + + +class NoDists: + """ + >>> bool(NoDists()) + False + + >>> list(NoDists()('anything')) + [] + """ + def __bool__(self): + return False + if six.PY2: + __nonzero__ = __bool__ + + def __call__(self, fullpath): + return iter(()) + + +def safe_listdir(path): + """ + Attempt to list contents of path, but suppress some exceptions. + """ + try: + return os.listdir(path) + except (PermissionError, NotADirectoryError): + pass + except OSError as e: + # Ignore the directory if does not exist, not a directory or + # permission denied + ignorable = ( + e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) + # Python 2 on Windows needs to be handled this way :( + or getattr(e, "winerror", None) == 267 + ) + if not ignorable: + raise + return () + + +def distributions_from_metadata(path): + root = os.path.dirname(path) + if os.path.isdir(path): + if len(os.listdir(path)) == 0: + # empty metadata dir; skip + return + metadata = PathMetadata(root, path) + else: + metadata = FileMetadata(path) + entry = os.path.basename(path) + yield Distribution.from_location( + root, entry, metadata, precedence=DEVELOP_DIST, + ) + + +def non_empty_lines(path): + """ + Yield non-empty lines from file at path + """ + with open(path) as f: + for line in f: + line = line.strip() + if line: + yield line + + +def resolve_egg_link(path): + """ + Given a path to an .egg-link, resolve distributions + present in the referenced path. + """ + referenced_paths = non_empty_lines(path) + resolved_paths = ( + os.path.join(os.path.dirname(path), ref) + for ref in referenced_paths + ) + dist_groups = map(find_distributions, resolved_paths) + return next(dist_groups, ()) + + +register_finder(pkgutil.ImpImporter, find_on_path) + +if hasattr(importlib_machinery, 'FileFinder'): + register_finder(importlib_machinery.FileFinder, find_on_path) + +_declare_state('dict', _namespace_handlers={}) +_declare_state('dict', _namespace_packages={}) + + +def register_namespace_handler(importer_type, namespace_handler): + """Register `namespace_handler` to declare namespace packages + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `namespace_handler` is a callable like this:: + + def namespace_handler(importer, path_entry, moduleName, module): + # return a path_entry to use for child packages + + Namespace handlers are only called if the importer object has already + agreed that it can handle the relevant path item, and they should only + return a subpath if the module __path__ does not already contain an + equivalent subpath. For an example namespace handler, see + ``pkg_resources.file_ns_handler``. + """ + _namespace_handlers[importer_type] = namespace_handler + + +def _handle_ns(packageName, path_item): + """Ensure that named package includes a subpath of path_item (if needed)""" + + importer = get_importer(path_item) + if importer is None: + return None + loader = importer.find_module(packageName) + if loader is None: + return None + module = sys.modules.get(packageName) + if module is None: + module = sys.modules[packageName] = types.ModuleType(packageName) + module.__path__ = [] + _set_parent_ns(packageName) + elif not hasattr(module, '__path__'): + raise TypeError("Not a package:", packageName) + handler = _find_adapter(_namespace_handlers, importer) + subpath = handler(importer, path_item, packageName, module) + if subpath is not None: + path = module.__path__ + path.append(subpath) + loader.load_module(packageName) + _rebuild_mod_path(path, packageName, module) + return subpath + + +def _rebuild_mod_path(orig_path, package_name, module): + """ + Rebuild module.__path__ ensuring that all entries are ordered + corresponding to their sys.path order + """ + sys_path = [_normalize_cached(p) for p in sys.path] + + def safe_sys_path_index(entry): + """ + Workaround for #520 and #513. + """ + try: + return sys_path.index(entry) + except ValueError: + return float('inf') + + def position_in_sys_path(path): + """ + Return the ordinal of the path based on its position in sys.path + """ + path_parts = path.split(os.sep) + module_parts = package_name.count('.') + 1 + parts = path_parts[:-module_parts] + return safe_sys_path_index(_normalize_cached(os.sep.join(parts))) + + if not isinstance(orig_path, list): + # Is this behavior useful when module.__path__ is not a list? + return + + orig_path.sort(key=position_in_sys_path) + module.__path__[:] = [_normalize_cached(p) for p in orig_path] + + +def declare_namespace(packageName): + """Declare that package 'packageName' is a namespace package""" + + _imp.acquire_lock() + try: + if packageName in _namespace_packages: + return + + path, parent = sys.path, None + if '.' in packageName: + parent = '.'.join(packageName.split('.')[:-1]) + declare_namespace(parent) + if parent not in _namespace_packages: + __import__(parent) + try: + path = sys.modules[parent].__path__ + except AttributeError: + raise TypeError("Not a package:", parent) + + # Track what packages are namespaces, so when new path items are added, + # they can be updated + _namespace_packages.setdefault(parent, []).append(packageName) + _namespace_packages.setdefault(packageName, []) + + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + + finally: + _imp.release_lock() + + +def fixup_namespace_packages(path_item, parent=None): + """Ensure that previously-declared namespace packages include path_item""" + _imp.acquire_lock() + try: + for package in _namespace_packages.get(parent, ()): + subpath = _handle_ns(package, path_item) + if subpath: + fixup_namespace_packages(subpath, package) + finally: + _imp.release_lock() + + +def file_ns_handler(importer, path_item, packageName, module): + """Compute an ns-package subpath for a filesystem or zipfile importer""" + + subpath = os.path.join(path_item, packageName.split('.')[-1]) + normalized = _normalize_cached(subpath) + for item in module.__path__: + if _normalize_cached(item) == normalized: + break + else: + # Only return the path if it's not already there + return subpath + + +register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) +register_namespace_handler(zipimport.zipimporter, file_ns_handler) + +if hasattr(importlib_machinery, 'FileFinder'): + register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) + + +def null_ns_handler(importer, path_item, packageName, module): + return None + + +register_namespace_handler(object, null_ns_handler) + + +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(filename)) + + +def _normalize_cached(filename, _cache={}): + try: + return _cache[filename] + except KeyError: + _cache[filename] = result = normalize_path(filename) + return result + + +def _is_egg_path(path): + """ + Determine if given path appears to be an egg. + """ + return path.lower().endswith('.egg') + + +def _is_unpacked_egg(path): + """ + Determine if given path appears to be an unpacked egg. + """ + return ( + _is_egg_path(path) and + os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO')) + ) + + +def _set_parent_ns(packageName): + parts = packageName.split('.') + name = parts.pop() + if parts: + parent = '.'.join(parts) + setattr(sys.modules[parent], name, sys.modules[packageName]) + + +def yield_lines(strs): + """Yield non-empty/non-comment lines of a string or sequence""" + if isinstance(strs, six.string_types): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + + +MODULE = re.compile(r"\w+(\.\w+)*$").match +EGG_NAME = re.compile( + r""" + (?P<name>[^-]+) ( + -(?P<ver>[^-]+) ( + -py(?P<pyver>[^-]+) ( + -(?P<plat>.+) + )? + )? + )? + """, + re.VERBOSE | re.IGNORECASE, +).match + + +class EntryPoint(object): + """Object representing an advertised importable object""" + + def __init__(self, name, module_name, attrs=(), extras=(), dist=None): + if not MODULE(module_name): + raise ValueError("Invalid module name", module_name) + self.name = name + self.module_name = module_name + self.attrs = tuple(attrs) + self.extras = tuple(extras) + self.dist = dist + + def __str__(self): + s = "%s = %s" % (self.name, self.module_name) + if self.attrs: + s += ':' + '.'.join(self.attrs) + if self.extras: + s += ' [%s]' % ','.join(self.extras) + return s + + def __repr__(self): + return "EntryPoint.parse(%r)" % str(self) + + def load(self, require=True, *args, **kwargs): + """ + Require packages for this EntryPoint, then resolve it. + """ + if not require or args or kwargs: + warnings.warn( + "Parameters to load are deprecated. Call .resolve and " + ".require separately.", + DeprecationWarning, + stacklevel=2, + ) + if require: + self.require(*args, **kwargs) + return self.resolve() + + def resolve(self): + """ + Resolve the entry point from its module and attrs. + """ + module = __import__(self.module_name, fromlist=['__name__'], level=0) + try: + return functools.reduce(getattr, self.attrs, module) + except AttributeError as exc: + raise ImportError(str(exc)) + + def require(self, env=None, installer=None): + if self.extras and not self.dist: + raise UnknownExtra("Can't require() without a distribution", self) + + # Get the requirements for this entry point with all its extras and + # then resolve them. We have to pass `extras` along when resolving so + # that the working set knows what extras we want. Otherwise, for + # dist-info distributions, the working set will assume that the + # requirements for that extra are purely optional and skip over them. + reqs = self.dist.requires(self.extras) + items = working_set.resolve(reqs, env, installer, extras=self.extras) + list(map(working_set.add, items)) + + pattern = re.compile( + r'\s*' + r'(?P<name>.+?)\s*' + r'=\s*' + r'(?P<module>[\w.]+)\s*' + r'(:\s*(?P<attr>[\w.]+))?\s*' + r'(?P<extras>\[.*\])?\s*$' + ) + + @classmethod + def parse(cls, src, dist=None): + """Parse a single entry point from string `src` + + Entry point syntax follows the form:: + + name = some.module:some.attr [extra1, extra2] + + The entry name and module name are required, but the ``:attrs`` and + ``[extras]`` parts are optional + """ + m = cls.pattern.match(src) + if not m: + msg = "EntryPoint must be in 'name=module:attrs [extras]' format" + raise ValueError(msg, src) + res = m.groupdict() + extras = cls._parse_extras(res['extras']) + attrs = res['attr'].split('.') if res['attr'] else () + return cls(res['name'], res['module'], attrs, extras, dist) + + @classmethod + def _parse_extras(cls, extras_spec): + if not extras_spec: + return () + req = Requirement.parse('x' + extras_spec) + if req.specs: + raise ValueError() + return req.extras + + @classmethod + def parse_group(cls, group, lines, dist=None): + """Parse an entry point group""" + if not MODULE(group): + raise ValueError("Invalid group name", group) + this = {} + for line in yield_lines(lines): + ep = cls.parse(line, dist) + if ep.name in this: + raise ValueError("Duplicate entry point", group, ep.name) + this[ep.name] = ep + return this + + @classmethod + def parse_map(cls, data, dist=None): + """Parse a map of entry point groups""" + if isinstance(data, dict): + data = data.items() + else: + data = split_sections(data) + maps = {} + for group, lines in data: + if group is None: + if not lines: + continue + raise ValueError("Entry points must be listed in groups") + group = group.strip() + if group in maps: + raise ValueError("Duplicate group name", group) + maps[group] = cls.parse_group(group, lines, dist) + return maps + + +def _remove_md5_fragment(location): + if not location: + return '' + parsed = urllib.parse.urlparse(location) + if parsed[-1].startswith('md5='): + return urllib.parse.urlunparse(parsed[:-1] + ('',)) + return location + + +def _version_from_file(lines): + """ + Given an iterable of lines from a Metadata file, return + the value of the Version field, if present, or None otherwise. + """ + def is_version_line(line): + return line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) + line = next(iter(version_lines), '') + _, _, value = line.partition(':') + return safe_version(value.strip()) or None + + +class Distribution(object): + """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' + + def __init__( + self, location=None, metadata=None, project_name=None, + version=None, py_version=PY_MAJOR, platform=None, + precedence=EGG_DIST): + self.project_name = safe_name(project_name or 'Unknown') + if version is not None: + self._version = safe_version(version) + self.py_version = py_version + self.platform = platform + self.location = location + self.precedence = precedence + self._provider = metadata or empty_provider + + @classmethod + def from_location(cls, location, basename, metadata=None, **kw): + project_name, version, py_version, platform = [None] * 4 + basename, ext = os.path.splitext(basename) + if ext.lower() in _distributionImpl: + cls = _distributionImpl[ext.lower()] + + match = EGG_NAME(basename) + if match: + project_name, version, py_version, platform = match.group( + 'name', 'ver', 'pyver', 'plat' + ) + return cls( + location, metadata, project_name=project_name, version=version, + py_version=py_version, platform=platform, **kw + )._reload_version() + + def _reload_version(self): + return self + + @property + def hashcmp(self): + return ( + self.parsed_version, + self.precedence, + self.key, + _remove_md5_fragment(self.location), + self.py_version or '', + self.platform or '', + ) + + def __hash__(self): + return hash(self.hashcmp) + + def __lt__(self, other): + return self.hashcmp < other.hashcmp + + def __le__(self, other): + return self.hashcmp <= other.hashcmp + + def __gt__(self, other): + return self.hashcmp > other.hashcmp + + def __ge__(self, other): + return self.hashcmp >= other.hashcmp + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # It's not a Distribution, so they are not equal + return False + return self.hashcmp == other.hashcmp + + def __ne__(self, other): + return not self == other + + # These properties have to be lazy so that we don't have to load any + # metadata until/unless it's actually needed. (i.e., some distributions + # may not know their name or version without loading PKG-INFO) + + @property + def key(self): + try: + return self._key + except AttributeError: + self._key = key = self.project_name.lower() + return key + + @property + def parsed_version(self): + if not hasattr(self, "_parsed_version"): + self._parsed_version = parse_version(self.version) + + return self._parsed_version + + def _warn_legacy_version(self): + LV = packaging.version.LegacyVersion + is_legacy = isinstance(self._parsed_version, LV) + if not is_legacy: + return + + # While an empty version is technically a legacy version and + # is not a valid PEP 440 version, it's also unlikely to + # actually come from someone and instead it is more likely that + # it comes from setuptools attempting to parse a filename and + # including it in the list. So for that we'll gate this warning + # on if the version is anything at all or not. + if not self.version: + return + + tmpl = textwrap.dedent(""" + '{project_name} ({version})' is being parsed as a legacy, + non PEP 440, + version. You may find odd behavior and sort order. + In particular it will be sorted as less than 0.0. It + is recommended to migrate to PEP 440 compatible + versions. + """).strip().replace('\n', ' ') + + warnings.warn(tmpl.format(**vars(self)), PEP440Warning) + + @property + def version(self): + try: + return self._version + except AttributeError: + version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if version is None: + tmpl = "Missing 'Version:' header and/or %s file" + raise ValueError(tmpl % self.PKG_INFO, self) + return version + + @property + def _dep_map(self): + """ + A map of extra to its list of (direct) requirements + for this distribution, including the null extra. + """ + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._filter_extras(self._build_dep_map()) + return self.__dep_map + + @staticmethod + def _filter_extras(dm): + """ + Given a mapping of extras to dependencies, strip off + environment markers and filter out any dependencies + not matching the markers. + """ + for extra in list(filter(None, dm)): + new_extra = extra + reqs = dm.pop(extra) + new_extra, _, marker = extra.partition(':') + fails_marker = marker and ( + invalid_marker(marker) + or not evaluate_marker(marker) + ) + if fails_marker: + reqs = [] + new_extra = safe_extra(new_extra) or None + + dm.setdefault(new_extra, []).extend(reqs) + return dm + + def _build_dep_map(self): + dm = {} + for name in 'requires.txt', 'depends.txt': + for extra, reqs in split_sections(self._get_metadata(name)): + dm.setdefault(extra, []).extend(parse_requirements(reqs)) + return dm + + def requires(self, extras=()): + """List of Requirements needed for this distro if `extras` are used""" + dm = self._dep_map + deps = [] + deps.extend(dm.get(None, ())) + for ext in extras: + try: + deps.extend(dm[safe_extra(ext)]) + except KeyError: + raise UnknownExtra( + "%s has no such extra feature %r" % (self, ext) + ) + return deps + + def _get_metadata(self, name): + if self.has_metadata(name): + for line in self.get_metadata_lines(name): + yield line + + def activate(self, path=None, replace=False): + """Ensure distribution is importable on `path` (default=sys.path)""" + if path is None: + path = sys.path + self.insert_on(path, replace=replace) + if path is sys.path: + fixup_namespace_packages(self.location) + for pkg in self._get_metadata('namespace_packages.txt'): + if pkg in sys.modules: + declare_namespace(pkg) + + def egg_name(self): + """Return what this distribution's standard .egg filename should be""" + filename = "%s-%s-py%s" % ( + to_filename(self.project_name), to_filename(self.version), + self.py_version or PY_MAJOR + ) + + if self.platform: + filename += '-' + self.platform + return filename + + def __repr__(self): + if self.location: + return "%s (%s)" % (self, self.location) + else: + return str(self) + + def __str__(self): + try: + version = getattr(self, 'version', None) + except ValueError: + version = None + version = version or "[unknown version]" + return "%s %s" % (self.project_name, version) + + def __getattr__(self, attr): + """Delegate all unrecognized public attributes to .metadata provider""" + if attr.startswith('_'): + raise AttributeError(attr) + return getattr(self._provider, attr) + + @classmethod + def from_filename(cls, filename, metadata=None, **kw): + return cls.from_location( + _normalize_cached(filename), os.path.basename(filename), metadata, + **kw + ) + + def as_requirement(self): + """Return a ``Requirement`` that matches this distribution exactly""" + if isinstance(self.parsed_version, packaging.version.Version): + spec = "%s==%s" % (self.project_name, self.parsed_version) + else: + spec = "%s===%s" % (self.project_name, self.parsed_version) + + return Requirement.parse(spec) + + def load_entry_point(self, group, name): + """Return the `name` entry point of `group` or raise ImportError""" + ep = self.get_entry_info(group, name) + if ep is None: + raise ImportError("Entry point %r not found" % ((group, name),)) + return ep.load() + + def get_entry_map(self, group=None): + """Return the entry point map for `group`, or the full entry map""" + try: + ep_map = self._ep_map + except AttributeError: + ep_map = self._ep_map = EntryPoint.parse_map( + self._get_metadata('entry_points.txt'), self + ) + if group is not None: + return ep_map.get(group, {}) + return ep_map + + def get_entry_info(self, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return self.get_entry_map(group).get(name) + + def insert_on(self, path, loc=None, replace=False): + """Ensure self.location is on path + + If replace=False (default): + - If location is already in path anywhere, do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent. + - Else: add to the end of path. + If replace=True: + - If location is already on path anywhere (not eggs) + or higher priority than its parent (eggs) + do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent, + removing any lower-priority entries. + - Else: add it to the front of path. + """ + + loc = loc or self.location + if not loc: + return + + nloc = _normalize_cached(loc) + bdir = os.path.dirname(nloc) + npath = [(p and _normalize_cached(p) or p) for p in path] + + for p, item in enumerate(npath): + if item == nloc: + if replace: + break + else: + # don't modify path (even removing duplicates) if + # found and not replace + return + elif item == bdir and self.precedence == EGG_DIST: + # if it's an .egg, give it precedence over its directory + # UNLESS it's already been added to sys.path and replace=False + if (not replace) and nloc in npath[p:]: + return + if path is sys.path: + self.check_version_conflict() + path.insert(p, loc) + npath.insert(p, nloc) + break + else: + if path is sys.path: + self.check_version_conflict() + if replace: + path.insert(0, loc) + else: + path.append(loc) + return + + # p is the spot where we found or inserted loc; now remove duplicates + while True: + try: + np = npath.index(nloc, p + 1) + except ValueError: + break + else: + del npath[np], path[np] + # ha! + p = np + + return + + def check_version_conflict(self): + if self.key == 'setuptools': + # ignore the inevitable setuptools self-conflicts :( + return + + nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt')) + loc = normalize_path(self.location) + for modname in self._get_metadata('top_level.txt'): + if (modname not in sys.modules or modname in nsp + or modname in _namespace_packages): + continue + if modname in ('pkg_resources', 'setuptools', 'site'): + continue + fn = getattr(sys.modules[modname], '__file__', None) + if fn and (normalize_path(fn).startswith(loc) or + fn.startswith(self.location)): + continue + issue_warning( + "Module %s was already imported from %s, but %s is being added" + " to sys.path" % (modname, fn, self.location), + ) + + def has_version(self): + try: + self.version + except ValueError: + issue_warning("Unbuilt egg for " + repr(self)) + return False + return True + + def clone(self, **kw): + """Copy this distribution, substituting in any changed keyword args""" + names = 'project_name version py_version platform location precedence' + for attr in names.split(): + kw.setdefault(attr, getattr(self, attr, None)) + kw.setdefault('metadata', self._provider) + return self.__class__(**kw) + + @property + def extras(self): + return [dep for dep in self._dep_map if dep] + + +class EggInfoDistribution(Distribution): + def _reload_version(self): + """ + Packages installed by distutils (e.g. numpy or scipy), + which uses an old safe_version, and so + their version numbers can get mangled when + converted to filenames (e.g., 1.11.0.dev0+2329eae to + 1.11.0.dev0_2329eae). These distributions will not be + parsed properly + downstream by Distribution and safe_version, so + take an extra step and try to get the version number from + the metadata file itself instead of the filename. + """ + md_version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if md_version: + self._version = md_version + return self + + +class DistInfoDistribution(Distribution): + """ + Wrap an actual or potential sys.path entry + w/metadata, .dist-info style. + """ + PKG_INFO = 'METADATA' + EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") + + @property + def _parsed_pkg_info(self): + """Parse and cache metadata""" + try: + return self._pkg_info + except AttributeError: + metadata = self.get_metadata(self.PKG_INFO) + self._pkg_info = email.parser.Parser().parsestr(metadata) + return self._pkg_info + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._compute_dependencies() + return self.__dep_map + + def _compute_dependencies(self): + """Recompute this distribution's dependencies.""" + dm = self.__dep_map = {None: []} + + reqs = [] + # Including any condition expressions + for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: + reqs.extend(parse_requirements(req)) + + def reqs_for_extra(extra): + for req in reqs: + if not req.marker or req.marker.evaluate({'extra': extra}): + yield req + + common = frozenset(reqs_for_extra(None)) + dm[None].extend(common) + + for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: + s_extra = safe_extra(extra.strip()) + dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common) + + return dm + + +_distributionImpl = { + '.egg': Distribution, + '.egg-info': EggInfoDistribution, + '.dist-info': DistInfoDistribution, +} + + +def issue_warning(*args, **kw): + level = 1 + g = globals() + try: + # find the first stack frame that is *not* code in + # the pkg_resources module, to use for the warning + while sys._getframe(level).f_globals is g: + level += 1 + except ValueError: + pass + warnings.warn(stacklevel=level + 1, *args, **kw) + + +class RequirementParseError(ValueError): + def __str__(self): + return ' '.join(self.args) + + +def parse_requirements(strs): + """Yield ``Requirement`` objects for each specification in `strs` + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + # create a steppable iterator, so we can handle \-continuations + lines = iter(yield_lines(strs)) + + for line in lines: + # Drop comments -- a hash without a space may be in a URL. + if ' #' in line: + line = line[:line.find(' #')] + # If there is a line continuation, drop it, and append the next line. + if line.endswith('\\'): + line = line[:-2].strip() + try: + line += next(lines) + except StopIteration: + return + yield Requirement(line) + + +class Requirement(packaging.requirements.Requirement): + def __init__(self, requirement_string): + """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" + try: + super(Requirement, self).__init__(requirement_string) + except packaging.requirements.InvalidRequirement as e: + raise RequirementParseError(str(e)) + self.unsafe_name = self.name + project_name = safe_name(self.name) + self.project_name, self.key = project_name, project_name.lower() + self.specs = [ + (spec.operator, spec.version) for spec in self.specifier] + self.extras = tuple(map(safe_extra, self.extras)) + self.hashCmp = ( + self.key, + self.specifier, + frozenset(self.extras), + str(self.marker) if self.marker else None, + ) + self.__hash = hash(self.hashCmp) + + def __eq__(self, other): + return ( + isinstance(other, Requirement) and + self.hashCmp == other.hashCmp + ) + + def __ne__(self, other): + return not self == other + + def __contains__(self, item): + if isinstance(item, Distribution): + if item.key != self.key: + return False + + item = item.version + + # Allow prereleases always in order to match the previous behavior of + # this method. In the future this should be smarter and follow PEP 440 + # more accurately. + return self.specifier.contains(item, prereleases=True) + + def __hash__(self): + return self.__hash + + def __repr__(self): + return "Requirement.parse(%r)" % str(self) + + @staticmethod + def parse(s): + req, = parse_requirements(s) + return req + + +def _always_object(classes): + """ + Ensure object appears in the mro even + for old-style classes. + """ + if object not in classes: + return classes + (object,) + return classes + + +def _find_adapter(registry, ob): + """Return an adapter factory for `ob` from `registry`""" + types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob)))) + for t in types: + if t in registry: + return registry[t] + + +def ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + py31compat.makedirs(dirname, exist_ok=True) + + +def _bypass_ensure_directory(path): + """Sandbox-bypassing version of ensure_directory()""" + if not WRITE_SUPPORT: + raise IOError('"os.mkdir" not supported on this platform.') + dirname, filename = split(path) + if dirname and filename and not isdir(dirname): + _bypass_ensure_directory(dirname) + mkdir(dirname, 0o755) + + +def split_sections(s): + """Split a string or iterable thereof into (section, content) pairs + + Each ``section`` is a stripped version of the section header ("[section]") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any such lines before the first section + header, they're returned in a first ``section`` of ``None``. + """ + section = None + content = [] + for line in yield_lines(s): + if line.startswith("["): + if line.endswith("]"): + if section or content: + yield section, content + section = line[1:-1].strip() + content = [] + else: + raise ValueError("Invalid section heading", line) + else: + content.append(line) + + # wrap up last segment + yield section, content + + +def _mkstemp(*args, **kw): + old_open = os.open + try: + # temporarily bypass sandboxing + os.open = os_open + return tempfile.mkstemp(*args, **kw) + finally: + # and then put it back + os.open = old_open + + +# Silence the PEP440Warning by default, so that end users don't get hit by it +# randomly just because they use pkg_resources. We want to append the rule +# because we want earlier uses of filterwarnings to take precedence over this +# one. +warnings.filterwarnings("ignore", category=PEP440Warning, append=True) + + +# from jaraco.functools 1.3 +def _call_aside(f, *args, **kwargs): + f(*args, **kwargs) + return f + + +@_call_aside +def _initialize(g=globals()): + "Set up global resource manager (deliberately not state-saved)" + manager = ResourceManager() + g['_manager'] = manager + g.update( + (name, getattr(manager, name)) + for name in dir(manager) + if not name.startswith('_') + ) + + +@_call_aside +def _initialize_master_working_set(): + """ + Prepare the master working set and make the ``require()`` + API available. + + This function has explicit effects on the global state + of pkg_resources. It is intended to be invoked once at + the initialization of this module. + + Invocation by other packages is unsupported and done + at their own risk. + """ + working_set = WorkingSet._build_master() + _declare_state('object', working_set=working_set) + + require = working_set.require + iter_entry_points = working_set.iter_entry_points + add_activation_listener = working_set.subscribe + run_script = working_set.run_script + # backward compatibility + run_main = run_script + # Activate all distributions already on sys.path with replace=False and + # ensure that all distributions added to the working set in the future + # (e.g. by calling ``require()``) will get activated as well, + # with higher priority (replace=True). + tuple( + dist.activate(replace=False) + for dist in working_set + ) + add_activation_listener( + lambda dist: dist.activate(replace=True), + existing=False, + ) + working_set.entries = [] + # match order + list(map(working_set.add_entry, sys.path)) + globals().update(locals()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py new file mode 100755 index 0000000..3e1c152 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py @@ -0,0 +1,22 @@ +import os +import errno +import sys + + +def _makedirs_31(path, exist_ok=False): + try: + os.makedirs(path) + except OSError as exc: + if not exist_ok or exc.errno != errno.EEXIST: + raise + + +# rely on compatibility behavior until mode considerations +# and exists_ok considerations are disentangled. +# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663 +needs_makedirs = ( + sys.version_info < (3, 2, 5) or + (3, 3) <= sys.version_info < (3, 3, 6) or + (3, 4) <= sys.version_info < (3, 4, 1) +) +makedirs = _makedirs_31 if needs_makedirs else os.makedirs diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py new file mode 100755 index 0000000..4aa97fc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py @@ -0,0 +1,127 @@ +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import division + +from collections import deque +from datetime import timedelta +from math import ceil +from sys import stderr +from time import time + + +__version__ = '1.3' + + +class Infinite(object): + file = stderr + sma_window = 10 # Simple Moving Average window + + def __init__(self, *args, **kwargs): + self.index = 0 + self.start_ts = time() + self.avg = 0 + self._ts = self.start_ts + self._xput = deque(maxlen=self.sma_window) + for key, val in kwargs.items(): + setattr(self, key, val) + + def __getitem__(self, key): + if key.startswith('_'): + return None + return getattr(self, key, None) + + @property + def elapsed(self): + return int(time() - self.start_ts) + + @property + def elapsed_td(self): + return timedelta(seconds=self.elapsed) + + def update_avg(self, n, dt): + if n > 0: + self._xput.append(dt / n) + self.avg = sum(self._xput) / len(self._xput) + + def update(self): + pass + + def start(self): + pass + + def finish(self): + pass + + def next(self, n=1): + now = time() + dt = now - self._ts + self.update_avg(n, dt) + self._ts = now + self.index = self.index + n + self.update() + + def iter(self, it): + try: + for x in it: + yield x + self.next() + finally: + self.finish() + + +class Progress(Infinite): + def __init__(self, *args, **kwargs): + super(Progress, self).__init__(*args, **kwargs) + self.max = kwargs.get('max', 100) + + @property + def eta(self): + return int(ceil(self.avg * self.remaining)) + + @property + def eta_td(self): + return timedelta(seconds=self.eta) + + @property + def percent(self): + return self.progress * 100 + + @property + def progress(self): + return min(1, self.index / self.max) + + @property + def remaining(self): + return max(self.max - self.index, 0) + + def start(self): + self.update() + + def goto(self, index): + incr = index - self.index + self.next(incr) + + def iter(self, it): + try: + self.max = len(it) + except TypeError: + pass + + try: + for x in it: + yield x + self.next() + finally: + self.finish() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py new file mode 100755 index 0000000..3fdd703 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Progress +from .helpers import WritelnMixin + + +class Bar(WritelnMixin, Progress): + width = 32 + message = '' + suffix = '%(index)d/%(max)d' + bar_prefix = ' |' + bar_suffix = '| ' + empty_fill = ' ' + fill = '#' + hide_cursor = True + + def update(self): + filled_length = int(self.width * self.progress) + empty_length = self.width - filled_length + + message = self.message % self + bar = self.fill * filled_length + empty = self.empty_fill * empty_length + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, empty, self.bar_suffix, + suffix]) + self.writeln(line) + + +class ChargingBar(Bar): + suffix = '%(percent)d%%' + bar_prefix = ' ' + bar_suffix = ' ' + empty_fill = '∙' + fill = '█' + + +class FillingSquaresBar(ChargingBar): + empty_fill = '▢' + fill = '▣' + + +class FillingCirclesBar(ChargingBar): + empty_fill = '◯' + fill = '◉' + + +class IncrementalBar(Bar): + phases = (' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█') + + def update(self): + nphases = len(self.phases) + filled_len = self.width * self.progress + nfull = int(filled_len) # Number of full chars + phase = int((filled_len - nfull) * nphases) # Phase of last char + nempty = self.width - nfull # Number of empty chars + + message = self.message % self + bar = self.phases[-1] * nfull + current = self.phases[phase] if phase > 0 else '' + empty = self.empty_fill * max(0, nempty - len(current)) + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, current, empty, + self.bar_suffix, suffix]) + self.writeln(line) + + +class PixelBar(IncrementalBar): + phases = ('⡀', '⡄', '⡆', '⡇', '⣇', '⣧', '⣷', '⣿') + + +class ShadyBar(IncrementalBar): + phases = (' ', '░', '▒', '▓', '█') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py new file mode 100755 index 0000000..e993a51 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Infinite, Progress +from .helpers import WriteMixin + + +class Counter(WriteMixin, Infinite): + message = '' + hide_cursor = True + + def update(self): + self.write(str(self.index)) + + +class Countdown(WriteMixin, Progress): + hide_cursor = True + + def update(self): + self.write(str(self.remaining)) + + +class Stack(WriteMixin, Progress): + phases = (' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█') + hide_cursor = True + + def update(self): + nphases = len(self.phases) + i = min(nphases - 1, int(self.progress * nphases)) + self.write(self.phases[i]) + + +class Pie(Stack): + phases = ('○', '◔', '◑', '◕', '●') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py new file mode 100755 index 0000000..96c8800 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py @@ -0,0 +1,91 @@ +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import print_function + + +HIDE_CURSOR = '\x1b[?25l' +SHOW_CURSOR = '\x1b[?25h' + + +class WriteMixin(object): + hide_cursor = False + + def __init__(self, message=None, **kwargs): + super(WriteMixin, self).__init__(**kwargs) + self._width = 0 + if message: + self.message = message + + if self.file.isatty(): + if self.hide_cursor: + print(HIDE_CURSOR, end='', file=self.file) + print(self.message, end='', file=self.file) + self.file.flush() + + def write(self, s): + if self.file.isatty(): + b = '\b' * self._width + c = s.ljust(self._width) + print(b + c, end='', file=self.file) + self._width = max(self._width, len(s)) + self.file.flush() + + def finish(self): + if self.file.isatty() and self.hide_cursor: + print(SHOW_CURSOR, end='', file=self.file) + + +class WritelnMixin(object): + hide_cursor = False + + def __init__(self, message=None, **kwargs): + super(WritelnMixin, self).__init__(**kwargs) + if message: + self.message = message + + if self.file.isatty() and self.hide_cursor: + print(HIDE_CURSOR, end='', file=self.file) + + def clearln(self): + if self.file.isatty(): + print('\r\x1b[K', end='', file=self.file) + + def writeln(self, line): + if self.file.isatty(): + self.clearln() + print(line, end='', file=self.file) + self.file.flush() + + def finish(self): + if self.file.isatty(): + print(file=self.file) + if self.hide_cursor: + print(SHOW_CURSOR, end='', file=self.file) + + +from signal import signal, SIGINT +from sys import exit + + +class SigIntMixin(object): + """Registers a signal handler that calls finish on SIGINT""" + + def __init__(self, *args, **kwargs): + super(SigIntMixin, self).__init__(*args, **kwargs) + signal(SIGINT, self._sigint_handler) + + def _sigint_handler(self, signum, frame): + self.finish() + exit(0) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py new file mode 100755 index 0000000..d67c679 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Infinite +from .helpers import WriteMixin + + +class Spinner(WriteMixin, Infinite): + message = '' + phases = ('-', '\\', '|', '/') + hide_cursor = True + + def update(self): + i = self.index % len(self.phases) + self.write(self.phases[i]) + + +class PieSpinner(Spinner): + phases = ['◷', '◶', '◵', '◴'] + + +class MoonSpinner(Spinner): + phases = ['◑', '◒', '◐', '◓'] + + +class LineSpinner(Spinner): + phases = ['⎺', '⎻', '⎼', '⎽', '⎼', '⎻'] + +class PixelSpinner(Spinner): + phases = ['⣾','⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽'] diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py new file mode 100755 index 0000000..d362e08 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py @@ -0,0 +1,5720 @@ +# module pyparsing.py +# +# Copyright (c) 2003-2016 Paul T. McGuire +# +# 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. +# + +__doc__ = \ +""" +pyparsing module - Classes and methods to define and execute parsing grammars + +The pyparsing module is an alternative approach to creating and executing simple grammars, +vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you +don't need to learn a new syntax for defining grammars or matching expressions - the parsing module +provides a library of classes that you use to construct the grammar directly in Python. + +Here is a program to parse "Hello, World!" (or any greeting of the form +C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements +(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to +L{Literal} expressions):: + + from pip._vendor.pyparsing import Word, alphas + + # define grammar of a greeting + greet = Word(alphas) + "," + Word(alphas) + "!" + + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + +The program outputs the following:: + + Hello, World! -> ['Hello', ',', 'World', '!'] + +The Python representation of the grammar is quite readable, owing to the self-explanatory +class names, and the use of '+', '|' and '^' operators. + +The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an +object with named attributes. + +The pyparsing module handles some of the problems that are typically vexing when writing text parsers: + - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) + - quoted strings + - embedded comments +""" + +__version__ = "2.2.0" +__versionTime__ = "06 Mar 2017 02:06 UTC" +__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" + +import string +from weakref import ref as wkref +import copy +import sys +import warnings +import re +import sre_constants +import collections +import pprint +import traceback +import types +from datetime import datetime + +try: + from _thread import RLock +except ImportError: + from threading import RLock + +try: + from collections import OrderedDict as _OrderedDict +except ImportError: + try: + from ordereddict import OrderedDict as _OrderedDict + except ImportError: + _OrderedDict = None + +#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) + +__all__ = [ +'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', +'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', +'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', +'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', +'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', +'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', +'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', +'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', +'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', +'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', +'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', +'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', +'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', +'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', +'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', +'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', +'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', +'CloseMatch', 'tokenMap', 'pyparsing_common', +] + +system_version = tuple(sys.version_info)[:3] +PY_3 = system_version[0] == 3 +if PY_3: + _MAX_INT = sys.maxsize + basestring = str + unichr = chr + _ustr = str + + # build list of single arg builtins, that can be used as parse actions + singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] + +else: + _MAX_INT = sys.maxint + range = xrange + + def _ustr(obj): + """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries + str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It + then < returns the unicode object | encodes it with the default encoding | ... >. + """ + if isinstance(obj,unicode): + return obj + + try: + # If this works, then _ustr(obj) has the same behaviour as str(obj), so + # it won't break any existing code. + return str(obj) + + except UnicodeEncodeError: + # Else encode it + ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') + xmlcharref = Regex(r'&#\d+;') + xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) + return xmlcharref.transformString(ret) + + # build list of single arg builtins, tolerant of Python version, that can be used as parse actions + singleArgBuiltins = [] + import __builtin__ + for fname in "sum len sorted reversed list tuple set any all min max".split(): + try: + singleArgBuiltins.append(getattr(__builtin__,fname)) + except AttributeError: + continue + +_generatorType = type((y for y in range(1))) + +def _xml_escape(data): + """Escape &, <, >, ", ', etc. in a string of data.""" + + # ampersand must be replaced first + from_symbols = '&><"\'' + to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) + for from_,to_ in zip(from_symbols, to_symbols): + data = data.replace(from_, to_) + return data + +class _Constants(object): + pass + +alphas = string.ascii_uppercase + string.ascii_lowercase +nums = "0123456789" +hexnums = nums + "ABCDEFabcdef" +alphanums = alphas + nums +_bslash = chr(92) +printables = "".join(c for c in string.printable if c not in string.whitespace) + +class ParseBaseException(Exception): + """base exception class for all parsing runtime exceptions""" + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, pstr, loc=0, msg=None, elem=None ): + self.loc = loc + if msg is None: + self.msg = pstr + self.pstr = "" + else: + self.msg = msg + self.pstr = pstr + self.parserElement = elem + self.args = (pstr, loc, msg) + + @classmethod + def _from_exception(cls, pe): + """ + internal factory method to simplify creating one type of ParseException + from another - avoids having __init__ signature conflicts among subclasses + """ + return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) + + def __getattr__( self, aname ): + """supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + """ + if( aname == "lineno" ): + return lineno( self.loc, self.pstr ) + elif( aname in ("col", "column") ): + return col( self.loc, self.pstr ) + elif( aname == "line" ): + return line( self.loc, self.pstr ) + else: + raise AttributeError(aname) + + def __str__( self ): + return "%s (at char %d), (line:%d, col:%d)" % \ + ( self.msg, self.loc, self.lineno, self.column ) + def __repr__( self ): + return _ustr(self) + def markInputline( self, markerString = ">!<" ): + """Extracts the exception line from the input string, and marks + the location of the exception with a special symbol. + """ + line_str = self.line + line_column = self.column - 1 + if markerString: + line_str = "".join((line_str[:line_column], + markerString, line_str[line_column:])) + return line_str.strip() + def __dir__(self): + return "lineno col line".split() + dir(type(self)) + +class ParseException(ParseBaseException): + """ + Exception thrown when parse expressions don't match class; + supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + + Example:: + try: + Word(nums).setName("integer").parseString("ABC") + except ParseException as pe: + print(pe) + print("column: {}".format(pe.col)) + + prints:: + Expected integer (at char 0), (line:1, col:1) + column: 1 + """ + pass + +class ParseFatalException(ParseBaseException): + """user-throwable exception thrown when inconsistent parse content + is found; stops all parsing immediately""" + pass + +class ParseSyntaxException(ParseFatalException): + """just like L{ParseFatalException}, but thrown internally when an + L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop + immediately because an unbacktrackable syntax error has been found""" + pass + +#~ class ReparseException(ParseBaseException): + #~ """Experimental class - parse actions can raise this exception to cause + #~ pyparsing to reparse the input string: + #~ - with a modified input string, and/or + #~ - with a modified start location + #~ Set the values of the ReparseException in the constructor, and raise the + #~ exception in a parse action to cause pyparsing to use the new string/location. + #~ Setting the values as None causes no change to be made. + #~ """ + #~ def __init_( self, newstring, restartLoc ): + #~ self.newParseText = newstring + #~ self.reparseLoc = restartLoc + +class RecursiveGrammarException(Exception): + """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" + def __init__( self, parseElementList ): + self.parseElementTrace = parseElementList + + def __str__( self ): + return "RecursiveGrammarException: %s" % self.parseElementTrace + +class _ParseResultsWithOffset(object): + def __init__(self,p1,p2): + self.tup = (p1,p2) + def __getitem__(self,i): + return self.tup[i] + def __repr__(self): + return repr(self.tup[0]) + def setOffset(self,i): + self.tup = (self.tup[0],i) + +class ParseResults(object): + """ + Structured parse results, to provide multiple means of access to the parsed data: + - as a list (C{len(results)}) + - by list index (C{results[0], results[1]}, etc.) + - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName}) + + Example:: + integer = Word(nums) + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + # equivalent form: + # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + # parseString returns a ParseResults object + result = date_str.parseString("1999/12/31") + + def test(s, fn=repr): + print("%s -> %s" % (s, fn(eval(s)))) + test("list(result)") + test("result[0]") + test("result['month']") + test("result.day") + test("'month' in result") + test("'minutes' in result") + test("result.dump()", str) + prints:: + list(result) -> ['1999', '/', '12', '/', '31'] + result[0] -> '1999' + result['month'] -> '12' + result.day -> '31' + 'month' in result -> True + 'minutes' in result -> False + result.dump() -> ['1999', '/', '12', '/', '31'] + - day: 31 + - month: 12 + - year: 1999 + """ + def __new__(cls, toklist=None, name=None, asList=True, modal=True ): + if isinstance(toklist, cls): + return toklist + retobj = object.__new__(cls) + retobj.__doinit = True + return retobj + + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): + if self.__doinit: + self.__doinit = False + self.__name = None + self.__parent = None + self.__accumNames = {} + self.__asList = asList + self.__modal = modal + if toklist is None: + toklist = [] + if isinstance(toklist, list): + self.__toklist = toklist[:] + elif isinstance(toklist, _generatorType): + self.__toklist = list(toklist) + else: + self.__toklist = [toklist] + self.__tokdict = dict() + + if name is not None and name: + if not modal: + self.__accumNames[name] = 0 + if isinstance(name,int): + name = _ustr(name) # will always return a str, but use _ustr for consistency + self.__name = name + if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): + if isinstance(toklist,basestring): + toklist = [ toklist ] + if asList: + if isinstance(toklist,ParseResults): + self[name] = _ParseResultsWithOffset(toklist.copy(),0) + else: + self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) + self[name].__name = name + else: + try: + self[name] = toklist[0] + except (KeyError,TypeError,IndexError): + self[name] = toklist + + def __getitem__( self, i ): + if isinstance( i, (int,slice) ): + return self.__toklist[i] + else: + if i not in self.__accumNames: + return self.__tokdict[i][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[i] ]) + + def __setitem__( self, k, v, isinstance=isinstance ): + if isinstance(v,_ParseResultsWithOffset): + self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] + sub = v[0] + elif isinstance(k,(int,slice)): + self.__toklist[k] = v + sub = v + else: + self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] + sub = v + if isinstance(sub,ParseResults): + sub.__parent = wkref(self) + + def __delitem__( self, i ): + if isinstance(i,(int,slice)): + mylen = len( self.__toklist ) + del self.__toklist[i] + + # convert int to slice + if isinstance(i, int): + if i < 0: + i += mylen + i = slice(i, i+1) + # get removed indices + removed = list(range(*i.indices(mylen))) + removed.reverse() + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for j in removed: + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) + else: + del self.__tokdict[i] + + def __contains__( self, k ): + return k in self.__tokdict + + def __len__( self ): return len( self.__toklist ) + def __bool__(self): return ( not not self.__toklist ) + __nonzero__ = __bool__ + def __iter__( self ): return iter( self.__toklist ) + def __reversed__( self ): return iter( self.__toklist[::-1] ) + def _iterkeys( self ): + if hasattr(self.__tokdict, "iterkeys"): + return self.__tokdict.iterkeys() + else: + return iter(self.__tokdict) + + def _itervalues( self ): + return (self[k] for k in self._iterkeys()) + + def _iteritems( self ): + return ((k, self[k]) for k in self._iterkeys()) + + if PY_3: + keys = _iterkeys + """Returns an iterator of all named result keys (Python 3.x only).""" + + values = _itervalues + """Returns an iterator of all named result values (Python 3.x only).""" + + items = _iteritems + """Returns an iterator of all named result key-value tuples (Python 3.x only).""" + + else: + iterkeys = _iterkeys + """Returns an iterator of all named result keys (Python 2.x only).""" + + itervalues = _itervalues + """Returns an iterator of all named result values (Python 2.x only).""" + + iteritems = _iteritems + """Returns an iterator of all named result key-value tuples (Python 2.x only).""" + + def keys( self ): + """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iterkeys()) + + def values( self ): + """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.itervalues()) + + def items( self ): + """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iteritems()) + + def haskeys( self ): + """Since keys() returns an iterator, this method is helpful in bypassing + code that looks for the existence of any defined results names.""" + return bool(self.__tokdict) + + def pop( self, *args, **kwargs): + """ + Removes and returns item at specified index (default=C{last}). + Supports both C{list} and C{dict} semantics for C{pop()}. If passed no + argument or an integer argument, it will use C{list} semantics + and pop tokens from the list of parsed tokens. If passed a + non-integer argument (most likely a string), it will use C{dict} + semantics and pop the corresponding value from any defined + results names. A second default return value argument is + supported, just as in C{dict.pop()}. + + Example:: + def remove_first(tokens): + tokens.pop(0) + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] + + label = Word(alphas) + patt = label("LABEL") + OneOrMore(Word(nums)) + print(patt.parseString("AAB 123 321").dump()) + + # Use pop() in a parse action to remove named result (note that corresponding value is not + # removed from list form of results) + def remove_LABEL(tokens): + tokens.pop("LABEL") + return tokens + patt.addParseAction(remove_LABEL) + print(patt.parseString("AAB 123 321").dump()) + prints:: + ['AAB', '123', '321'] + - LABEL: AAB + + ['AAB', '123', '321'] + """ + if not args: + args = [-1] + for k,v in kwargs.items(): + if k == 'default': + args = (args[0], v) + else: + raise TypeError("pop() got an unexpected keyword argument '%s'" % k) + if (isinstance(args[0], int) or + len(args) == 1 or + args[0] in self): + index = args[0] + ret = self[index] + del self[index] + return ret + else: + defaultvalue = args[1] + return defaultvalue + + def get(self, key, defaultValue=None): + """ + Returns named result matching the given key, or if there is no + such name, then returns the given C{defaultValue} or C{None} if no + C{defaultValue} is specified. + + Similar to C{dict.get()}. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString("1999/12/31") + print(result.get("year")) # -> '1999' + print(result.get("hour", "not specified")) # -> 'not specified' + print(result.get("hour")) # -> None + """ + if key in self: + return self[key] + else: + return defaultValue + + def insert( self, index, insStr ): + """ + Inserts new element at location index in the list of parsed tokens. + + Similar to C{list.insert()}. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to insert the parse location in the front of the parsed results + def insert_locn(locn, tokens): + tokens.insert(0, locn) + print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] + """ + self.__toklist.insert(index, insStr) + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) + + def append( self, item ): + """ + Add single element to end of ParseResults list of elements. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to compute the sum of the parsed integers, and add it to the end + def append_sum(tokens): + tokens.append(sum(map(int, tokens))) + print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] + """ + self.__toklist.append(item) + + def extend( self, itemseq ): + """ + Add sequence of elements to end of ParseResults list of elements. + + Example:: + patt = OneOrMore(Word(alphas)) + + # use a parse action to append the reverse of the matched strings, to make a palindrome + def make_palindrome(tokens): + tokens.extend(reversed([t[::-1] for t in tokens])) + return ''.join(tokens) + print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' + """ + if isinstance(itemseq, ParseResults): + self += itemseq + else: + self.__toklist.extend(itemseq) + + def clear( self ): + """ + Clear all elements and results names. + """ + del self.__toklist[:] + self.__tokdict.clear() + + def __getattr__( self, name ): + try: + return self[name] + except KeyError: + return "" + + if name in self.__tokdict: + if name not in self.__accumNames: + return self.__tokdict[name][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[name] ]) + else: + return "" + + def __add__( self, other ): + ret = self.copy() + ret += other + return ret + + def __iadd__( self, other ): + if other.__tokdict: + offset = len(self.__toklist) + addoffset = lambda a: offset if a<0 else a+offset + otheritems = other.__tokdict.items() + otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) + for (k,vlist) in otheritems for v in vlist] + for k,v in otherdictitems: + self[k] = v + if isinstance(v[0],ParseResults): + v[0].__parent = wkref(self) + + self.__toklist += other.__toklist + self.__accumNames.update( other.__accumNames ) + return self + + def __radd__(self, other): + if isinstance(other,int) and other == 0: + # useful for merging many ParseResults using sum() builtin + return self.copy() + else: + # this may raise a TypeError - so be it + return other + self + + def __repr__( self ): + return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) + + def __str__( self ): + return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' + + def _asStringList( self, sep='' ): + out = [] + for item in self.__toklist: + if out and sep: + out.append(sep) + if isinstance( item, ParseResults ): + out += item._asStringList() + else: + out.append( _ustr(item) ) + return out + + def asList( self ): + """ + Returns the parse results as a nested list of matching tokens, all converted to strings. + + Example:: + patt = OneOrMore(Word(alphas)) + result = patt.parseString("sldkj lsdkj sldkj") + # even though the result prints in string-like form, it is actually a pyparsing ParseResults + print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] + + # Use asList() to create an actual list + result_list = result.asList() + print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] + """ + return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] + + def asDict( self ): + """ + Returns the named parse results as a nested dictionary. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) + + result_dict = result.asDict() + print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} + + # even though a ParseResults supports dict-like access, sometime you just need to have a dict + import json + print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable + print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} + """ + if PY_3: + item_fn = self.items + else: + item_fn = self.iteritems + + def toItem(obj): + if isinstance(obj, ParseResults): + if obj.haskeys(): + return obj.asDict() + else: + return [toItem(v) for v in obj] + else: + return obj + + return dict((k,toItem(v)) for k,v in item_fn()) + + def copy( self ): + """ + Returns a new copy of a C{ParseResults} object. + """ + ret = ParseResults( self.__toklist ) + ret.__tokdict = self.__tokdict.copy() + ret.__parent = self.__parent + ret.__accumNames.update( self.__accumNames ) + ret.__name = self.__name + return ret + + def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): + """ + (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. + """ + nl = "\n" + out = [] + namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() + for v in vlist) + nextLevelIndent = indent + " " + + # collapse out indents if formatting is not desired + if not formatted: + indent = "" + nextLevelIndent = "" + nl = "" + + selfTag = None + if doctag is not None: + selfTag = doctag + else: + if self.__name: + selfTag = self.__name + + if not selfTag: + if namedItemsOnly: + return "" + else: + selfTag = "ITEM" + + out += [ nl, indent, "<", selfTag, ">" ] + + for i,res in enumerate(self.__toklist): + if isinstance(res,ParseResults): + if i in namedItems: + out += [ res.asXML(namedItems[i], + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + out += [ res.asXML(None, + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + # individual token, see if there is a name for it + resTag = None + if i in namedItems: + resTag = namedItems[i] + if not resTag: + if namedItemsOnly: + continue + else: + resTag = "ITEM" + xmlBodyText = _xml_escape(_ustr(res)) + out += [ nl, nextLevelIndent, "<", resTag, ">", + xmlBodyText, + "</", resTag, ">" ] + + out += [ nl, indent, "</", selfTag, ">" ] + return "".join(out) + + def __lookup(self,sub): + for k,vlist in self.__tokdict.items(): + for v,loc in vlist: + if sub is v: + return k + return None + + def getName(self): + r""" + Returns the results name for this token expression. Useful when several + different expressions might match at a particular location. + + Example:: + integer = Word(nums) + ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") + house_number_expr = Suppress('#') + Word(nums, alphanums) + user_data = (Group(house_number_expr)("house_number") + | Group(ssn_expr)("ssn") + | Group(integer)("age")) + user_info = OneOrMore(user_data) + + result = user_info.parseString("22 111-22-3333 #221B") + for item in result: + print(item.getName(), ':', item[0]) + prints:: + age : 22 + ssn : 111-22-3333 + house_number : 221B + """ + if self.__name: + return self.__name + elif self.__parent: + par = self.__parent() + if par: + return par.__lookup(self) + else: + return None + elif (len(self) == 1 and + len(self.__tokdict) == 1 and + next(iter(self.__tokdict.values()))[0][1] in (0,-1)): + return next(iter(self.__tokdict.keys())) + else: + return None + + def dump(self, indent='', depth=0, full=True): + """ + Diagnostic method for listing out the contents of a C{ParseResults}. + Accepts an optional C{indent} argument so that this string can be embedded + in a nested display of other data. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(result.dump()) + prints:: + ['12', '/', '31', '/', '1999'] + - day: 1999 + - month: 31 + - year: 12 + """ + out = [] + NL = '\n' + out.append( indent+_ustr(self.asList()) ) + if full: + if self.haskeys(): + items = sorted((str(k), v) for k,v in self.items()) + for k,v in items: + if out: + out.append(NL) + out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) + if isinstance(v,ParseResults): + if v: + out.append( v.dump(indent,depth+1) ) + else: + out.append(_ustr(v)) + else: + out.append(repr(v)) + elif any(isinstance(vv,ParseResults) for vv in self): + v = self + for i,vv in enumerate(v): + if isinstance(vv,ParseResults): + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) + else: + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) + + return "".join(out) + + def pprint(self, *args, **kwargs): + """ + Pretty-printer for parsed results as a list, using the C{pprint} module. + Accepts additional positional or keyword args as defined for the + C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) + + Example:: + ident = Word(alphas, alphanums) + num = Word(nums) + func = Forward() + term = ident | num | Group('(' + func + ')') + func <<= ident + Group(Optional(delimitedList(term))) + result = func.parseString("fna a,b,(fnb c,d,200),100") + result.pprint(width=40) + prints:: + ['fna', + ['a', + 'b', + ['(', 'fnb', ['c', 'd', '200'], ')'], + '100']] + """ + pprint.pprint(self.asList(), *args, **kwargs) + + # add support for pickle protocol + def __getstate__(self): + return ( self.__toklist, + ( self.__tokdict.copy(), + self.__parent is not None and self.__parent() or None, + self.__accumNames, + self.__name ) ) + + def __setstate__(self,state): + self.__toklist = state[0] + (self.__tokdict, + par, + inAccumNames, + self.__name) = state[1] + self.__accumNames = {} + self.__accumNames.update(inAccumNames) + if par is not None: + self.__parent = wkref(par) + else: + self.__parent = None + + def __getnewargs__(self): + return self.__toklist, self.__name, self.__asList, self.__modal + + def __dir__(self): + return (dir(type(self)) + list(self.keys())) + +collections.MutableMapping.register(ParseResults) + +def col (loc,strg): + """Returns current column within a string, counting newlines as line separators. + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + s = strg + return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) + +def lineno(loc,strg): + """Returns current line number within a string, counting newlines as line separators. + The first line is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + return strg.count("\n",0,loc) + 1 + +def line( loc, strg ): + """Returns the line of text containing loc within a string, counting newlines as line separators. + """ + lastCR = strg.rfind("\n", 0, loc) + nextCR = strg.find("\n", loc) + if nextCR >= 0: + return strg[lastCR+1:nextCR] + else: + return strg[lastCR+1:] + +def _defaultStartDebugAction( instring, loc, expr ): + print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) + +def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): + print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) + +def _defaultExceptionDebugAction( instring, loc, expr, exc ): + print ("Exception raised:" + _ustr(exc)) + +def nullDebugAction(*args): + """'Do-nothing' debug action, to suppress debugging output during parsing.""" + pass + +# Only works on Python 3.x - nonlocal is toxic to Python 2 installs +#~ 'decorator to trim function calls to match the arity of the target' +#~ def _trim_arity(func, maxargs=3): + #~ if func in singleArgBuiltins: + #~ return lambda s,l,t: func(t) + #~ limit = 0 + #~ foundArity = False + #~ def wrapper(*args): + #~ nonlocal limit,foundArity + #~ while 1: + #~ try: + #~ ret = func(*args[limit:]) + #~ foundArity = True + #~ return ret + #~ except TypeError: + #~ if limit == maxargs or foundArity: + #~ raise + #~ limit += 1 + #~ continue + #~ return wrapper + +# this version is Python 2.x-3.x cross-compatible +'decorator to trim function calls to match the arity of the target' +def _trim_arity(func, maxargs=2): + if func in singleArgBuiltins: + return lambda s,l,t: func(t) + limit = [0] + foundArity = [False] + + # traceback return data structure changed in Py3.5 - normalize back to plain tuples + if system_version[:2] >= (3,5): + def extract_stack(limit=0): + # special handling for Python 3.5.0 - extra deep call stack by 1 + offset = -3 if system_version == (3,5,0) else -2 + frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] + return [(frame_summary.filename, frame_summary.lineno)] + def extract_tb(tb, limit=0): + frames = traceback.extract_tb(tb, limit=limit) + frame_summary = frames[-1] + return [(frame_summary.filename, frame_summary.lineno)] + else: + extract_stack = traceback.extract_stack + extract_tb = traceback.extract_tb + + # synthesize what would be returned by traceback.extract_stack at the call to + # user's parse action 'func', so that we don't incur call penalty at parse time + + LINE_DIFF = 6 + # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND + # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! + this_line = extract_stack(limit=2)[-1] + pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) + + def wrapper(*args): + while 1: + try: + ret = func(*args[limit[0]:]) + foundArity[0] = True + return ret + except TypeError: + # re-raise TypeErrors if they did not come from our arity testing + if foundArity[0]: + raise + else: + try: + tb = sys.exc_info()[-1] + if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth: + raise + finally: + del tb + + if limit[0] <= maxargs: + limit[0] += 1 + continue + raise + + # copy func name to wrapper for sensible debug output + func_name = "<parse action>" + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + wrapper.__name__ = func_name + + return wrapper + +class ParserElement(object): + """Abstract base level parser element class.""" + DEFAULT_WHITE_CHARS = " \n\t\r" + verbose_stacktrace = False + + @staticmethod + def setDefaultWhitespaceChars( chars ): + r""" + Overrides the default whitespace chars + + Example:: + # default whitespace chars are space, <TAB> and newline + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] + + # change to just treat newline as significant + ParserElement.setDefaultWhitespaceChars(" \t") + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] + """ + ParserElement.DEFAULT_WHITE_CHARS = chars + + @staticmethod + def inlineLiteralsUsing(cls): + """ + Set class to be used for inclusion of string literals into a parser. + + Example:: + # default literal class used is Literal + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + + # change to Suppress + ParserElement.inlineLiteralsUsing(Suppress) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] + """ + ParserElement._literalStringClass = cls + + def __init__( self, savelist=False ): + self.parseAction = list() + self.failAction = None + #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall + self.strRepr = None + self.resultsName = None + self.saveAsList = savelist + self.skipWhitespace = True + self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + self.copyDefaultWhiteChars = True + self.mayReturnEmpty = False # used when checking for left-recursion + self.keepTabs = False + self.ignoreExprs = list() + self.debug = False + self.streamlined = False + self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index + self.errmsg = "" + self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) + self.debugActions = ( None, None, None ) #custom debug actions + self.re = None + self.callPreparse = True # used to avoid redundant calls to preParse + self.callDuringTry = False + + def copy( self ): + """ + Make a copy of this C{ParserElement}. Useful for defining different parse actions + for the same parsing pattern, using copies of the original parse element. + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") + integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + + print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) + prints:: + [5120, 100, 655360, 268435456] + Equivalent form of C{expr.copy()} is just C{expr()}:: + integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + """ + cpy = copy.copy( self ) + cpy.parseAction = self.parseAction[:] + cpy.ignoreExprs = self.ignoreExprs[:] + if self.copyDefaultWhiteChars: + cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + return cpy + + def setName( self, name ): + """ + Define name for this expression, makes debugging and exception messages clearer. + + Example:: + Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) + Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) + """ + self.name = name + self.errmsg = "Expected " + self.name + if hasattr(self,"exception"): + self.exception.msg = self.errmsg + return self + + def setResultsName( self, name, listAllMatches=False ): + """ + Define name for referencing matching tokens as a nested attribute + of the returned parse results. + NOTE: this returns a *copy* of the original C{ParserElement} object; + this is so that the client can define a basic element, such as an + integer, and reference it in multiple places with different names. + + You can also set results names using the abbreviated syntax, + C{expr("name")} in place of C{expr.setResultsName("name")} - + see L{I{__call__}<__call__>}. + + Example:: + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + + # equivalent form: + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + """ + newself = self.copy() + if name.endswith("*"): + name = name[:-1] + listAllMatches=True + newself.resultsName = name + newself.modalResults = not listAllMatches + return newself + + def setBreak(self,breakFlag = True): + """Method to invoke the Python pdb debugger when this element is + about to be parsed. Set C{breakFlag} to True to enable, False to + disable. + """ + if breakFlag: + _parseMethod = self._parse + def breaker(instring, loc, doActions=True, callPreParse=True): + import pdb + pdb.set_trace() + return _parseMethod( instring, loc, doActions, callPreParse ) + breaker._originalParseMethod = _parseMethod + self._parse = breaker + else: + if hasattr(self._parse,"_originalParseMethod"): + self._parse = self._parse._originalParseMethod + return self + + def setParseAction( self, *fns, **kwargs ): + """ + Define one or more actions to perform when successfully matching parse element definition. + Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, + C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: + - s = the original string being parsed (see note below) + - loc = the location of the matching substring + - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object + If the functions in fns modify the tokens, they can return them as the return + value from fn, and the modified list of tokens will replace the original. + Otherwise, fn does not need to return any value. + + Optional keyword arguments: + - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{parseString}<parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + + Example:: + integer = Word(nums) + date_str = integer + '/' + integer + '/' + integer + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + # use parse action to convert to ints at parse time + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + date_str = integer + '/' + integer + '/' + integer + + # note that integer fields are now ints, not strings + date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] + """ + self.parseAction = list(map(_trim_arity, list(fns))) + self.callDuringTry = kwargs.get("callDuringTry", False) + return self + + def addParseAction( self, *fns, **kwargs ): + """ + Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}. + + See examples in L{I{copy}<copy>}. + """ + self.parseAction += list(map(_trim_arity, list(fns))) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def addCondition(self, *fns, **kwargs): + """Add a boolean predicate function to expression's list of parse actions. See + L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, + functions passed to C{addCondition} need to return boolean success/fail of the condition. + + Optional keyword arguments: + - message = define a custom message to be used in the raised exception + - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + year_int = integer.copy() + year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") + date_str = year_int + '/' + integer + '/' + integer + + result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) + """ + msg = kwargs.get("message", "failed user-defined condition") + exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException + for fn in fns: + def pa(s,l,t): + if not bool(_trim_arity(fn)(s,l,t)): + raise exc_type(s,l,msg) + self.parseAction.append(pa) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def setFailAction( self, fn ): + """Define action to perform if parsing fails at this expression. + Fail acton fn is a callable function that takes the arguments + C{fn(s,loc,expr,err)} where: + - s = string being parsed + - loc = location where expression match was attempted and failed + - expr = the parse expression that failed + - err = the exception thrown + The function returns no value. It may throw C{L{ParseFatalException}} + if it is desired to stop parsing immediately.""" + self.failAction = fn + return self + + def _skipIgnorables( self, instring, loc ): + exprsFound = True + while exprsFound: + exprsFound = False + for e in self.ignoreExprs: + try: + while 1: + loc,dummy = e._parse( instring, loc ) + exprsFound = True + except ParseException: + pass + return loc + + def preParse( self, instring, loc ): + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + + if self.skipWhitespace: + wt = self.whiteChars + instrlen = len(instring) + while loc < instrlen and instring[loc] in wt: + loc += 1 + + return loc + + def parseImpl( self, instring, loc, doActions=True ): + return loc, [] + + def postParse( self, instring, loc, tokenlist ): + return tokenlist + + #~ @profile + def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): + debugging = ( self.debug ) #and doActions ) + + if debugging or self.failAction: + #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) + if (self.debugActions[0] ): + self.debugActions[0]( instring, loc, self ) + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + try: + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + except ParseBaseException as err: + #~ print ("Exception raised:", err) + if self.debugActions[2]: + self.debugActions[2]( instring, tokensStart, self, err ) + if self.failAction: + self.failAction( instring, tokensStart, self, err ) + raise + else: + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + if self.mayIndexError or loc >= len(instring): + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + else: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + + tokens = self.postParse( instring, loc, tokens ) + + retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) + if self.parseAction and (doActions or self.callDuringTry): + if debugging: + try: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + except ParseBaseException as err: + #~ print "Exception raised in user parse action:", err + if (self.debugActions[2] ): + self.debugActions[2]( instring, tokensStart, self, err ) + raise + else: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + + if debugging: + #~ print ("Matched",self,"->",retTokens.asList()) + if (self.debugActions[1] ): + self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) + + return loc, retTokens + + def tryParse( self, instring, loc ): + try: + return self._parse( instring, loc, doActions=False )[0] + except ParseFatalException: + raise ParseException( instring, loc, self.errmsg, self) + + def canParseNext(self, instring, loc): + try: + self.tryParse(instring, loc) + except (ParseException, IndexError): + return False + else: + return True + + class _UnboundedCache(object): + def __init__(self): + cache = {} + self.not_in_cache = not_in_cache = object() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + if _OrderedDict is not None: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = _OrderedDict() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(cache) > size: + try: + cache.popitem(False) + except KeyError: + pass + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + else: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = {} + key_fifo = collections.deque([], size) + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(key_fifo) > size: + cache.pop(key_fifo.popleft(), None) + key_fifo.append(key) + + def clear(self): + cache.clear() + key_fifo.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + # argument cache for optimizing repeated calls when backtracking through recursive expressions + packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail + packrat_cache_lock = RLock() + packrat_cache_stats = [0, 0] + + # this method gets repeatedly called during backtracking with the same arguments - + # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression + def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): + HIT, MISS = 0, 1 + lookup = (self, instring, loc, callPreParse, doActions) + with ParserElement.packrat_cache_lock: + cache = ParserElement.packrat_cache + value = cache.get(lookup) + if value is cache.not_in_cache: + ParserElement.packrat_cache_stats[MISS] += 1 + try: + value = self._parseNoCache(instring, loc, doActions, callPreParse) + except ParseBaseException as pe: + # cache a copy of the exception, without the traceback + cache.set(lookup, pe.__class__(*pe.args)) + raise + else: + cache.set(lookup, (value[0], value[1].copy())) + return value + else: + ParserElement.packrat_cache_stats[HIT] += 1 + if isinstance(value, Exception): + raise value + return (value[0], value[1].copy()) + + _parse = _parseNoCache + + @staticmethod + def resetCache(): + ParserElement.packrat_cache.clear() + ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) + + _packratEnabled = False + @staticmethod + def enablePackrat(cache_size_limit=128): + """Enables "packrat" parsing, which adds memoizing to the parsing logic. + Repeated parse attempts at the same string location (which happens + often in many complex grammars) can immediately return a cached value, + instead of re-executing parsing/validating code. Memoizing is done of + both valid results and parsing exceptions. + + Parameters: + - cache_size_limit - (default=C{128}) - if an integer value is provided + will limit the size of the packrat cache; if None is passed, then + the cache size will be unbounded; if 0 is passed, the cache will + be effectively disabled. + + This speedup may break existing programs that use parse actions that + have side-effects. For this reason, packrat parsing is disabled when + you first import pyparsing. To activate the packrat feature, your + program must call the class method C{ParserElement.enablePackrat()}. If + your program uses C{psyco} to "compile as you go", you must call + C{enablePackrat} before calling C{psyco.full()}. If you do not do this, + Python will crash. For best results, call C{enablePackrat()} immediately + after importing pyparsing. + + Example:: + from pip._vendor import pyparsing + pyparsing.ParserElement.enablePackrat() + """ + if not ParserElement._packratEnabled: + ParserElement._packratEnabled = True + if cache_size_limit is None: + ParserElement.packrat_cache = ParserElement._UnboundedCache() + else: + ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) + ParserElement._parse = ParserElement._parseCache + + def parseString( self, instring, parseAll=False ): + """ + Execute the parse expression with the given string. + This is the main interface to the client code, once the complete + expression has been built. + + If you want the grammar to require that the entire input string be + successfully parsed, then set C{parseAll} to True (equivalent to ending + the grammar with C{L{StringEnd()}}). + + Note: C{parseString} implicitly calls C{expandtabs()} on the input string, + in order to report proper column numbers in parse actions. + If the input string contains tabs and + the grammar uses parse actions that use the C{loc} argument to index into the + string being parsed, you can ensure you have a consistent view of the input + string by: + - calling C{parseWithTabs} on your grammar before calling C{parseString} + (see L{I{parseWithTabs}<parseWithTabs>}) + - define your parse action using the full C{(s,loc,toks)} signature, and + reference the input string using the parse action's C{s} argument + - explictly expand the tabs in your input string before calling + C{parseString} + + Example:: + Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] + Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text + """ + ParserElement.resetCache() + if not self.streamlined: + self.streamline() + #~ self.saveAsList = True + for e in self.ignoreExprs: + e.streamline() + if not self.keepTabs: + instring = instring.expandtabs() + try: + loc, tokens = self._parse( instring, 0 ) + if parseAll: + loc = self.preParse( instring, loc ) + se = Empty() + StringEnd() + se._parse( instring, loc ) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + else: + return tokens + + def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): + """ + Scan the input string for expression matches. Each match will return the + matching tokens, start location, and end location. May be called with optional + C{maxMatches} argument, to clip scanning after 'n' matches are found. If + C{overlap} is specified, then overlapping matches will be reported. + + Note that the start and end locations are reported relative to the string + being parsed. See L{I{parseString}<parseString>} for more information on parsing + strings with embedded tabs. + + Example:: + source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" + print(source) + for tokens,start,end in Word(alphas).scanString(source): + print(' '*start + '^'*(end-start)) + print(' '*start + tokens[0]) + + prints:: + + sldjf123lsdjjkf345sldkjf879lkjsfd987 + ^^^^^ + sldjf + ^^^^^^^ + lsdjjkf + ^^^^^^ + sldkjf + ^^^^^^ + lkjsfd + """ + if not self.streamlined: + self.streamline() + for e in self.ignoreExprs: + e.streamline() + + if not self.keepTabs: + instring = _ustr(instring).expandtabs() + instrlen = len(instring) + loc = 0 + preparseFn = self.preParse + parseFn = self._parse + ParserElement.resetCache() + matches = 0 + try: + while loc <= instrlen and matches < maxMatches: + try: + preloc = preparseFn( instring, loc ) + nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) + except ParseException: + loc = preloc+1 + else: + if nextLoc > loc: + matches += 1 + yield tokens, preloc, nextLoc + if overlap: + nextloc = preparseFn( instring, loc ) + if nextloc > loc: + loc = nextLoc + else: + loc += 1 + else: + loc = nextLoc + else: + loc = preloc+1 + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def transformString( self, instring ): + """ + Extension to C{L{scanString}}, to modify matching text with modified tokens that may + be returned from a parse action. To use C{transformString}, define a grammar and + attach a parse action to it that modifies the returned token list. + Invoking C{transformString()} on a target string will then scan for matches, + and replace the matched text patterns according to the logic in the parse + action. C{transformString()} returns the resulting transformed string. + + Example:: + wd = Word(alphas) + wd.setParseAction(lambda toks: toks[0].title()) + + print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) + Prints:: + Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. + """ + out = [] + lastE = 0 + # force preservation of <TAB>s, to minimize unwanted transformation of string, and to + # keep string locs straight between transformString and scanString + self.keepTabs = True + try: + for t,s,e in self.scanString( instring ): + out.append( instring[lastE:s] ) + if t: + if isinstance(t,ParseResults): + out += t.asList() + elif isinstance(t,list): + out += t + else: + out.append(t) + lastE = e + out.append(instring[lastE:]) + out = [o for o in out if o] + return "".join(map(_ustr,_flatten(out))) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def searchString( self, instring, maxMatches=_MAX_INT ): + """ + Another extension to C{L{scanString}}, simplifying the access to the tokens found + to match the given parse expression. May be called with optional + C{maxMatches} argument, to clip searching after 'n' matches are found. + + Example:: + # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters + cap_word = Word(alphas.upper(), alphas.lower()) + + print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) + + # the sum() builtin can be used to merge results into a single ParseResults object + print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))) + prints:: + [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] + ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] + """ + try: + return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): + """ + Generator method to split a string using the given expression as a separator. + May be called with optional C{maxsplit} argument, to limit the number of splits; + and the optional C{includeSeparators} argument (default=C{False}), if the separating + matching text should be included in the split results. + + Example:: + punc = oneOf(list(".,;:/-!?")) + print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) + prints:: + ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] + """ + splits = 0 + last = 0 + for t,s,e in self.scanString(instring, maxMatches=maxsplit): + yield instring[last:s] + if includeSeparators: + yield t[0] + last = e + yield instring[last:] + + def __add__(self, other ): + """ + Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement + converts them to L{Literal}s by default. + + Example:: + greet = Word(alphas) + "," + Word(alphas) + "!" + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + Prints:: + Hello, World! -> ['Hello', ',', 'World', '!'] + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return And( [ self, other ] ) + + def __radd__(self, other ): + """ + Implementation of + operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other + self + + def __sub__(self, other): + """ + Implementation of - operator, returns C{L{And}} with error stop + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return self + And._ErrorStop() + other + + def __rsub__(self, other ): + """ + Implementation of - operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other - self + + def __mul__(self,other): + """ + Implementation of * operator, allows use of C{expr * 3} in place of + C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer + tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples + may also include C{None} as in: + - C{expr*(n,None)} or C{expr*(n,)} is equivalent + to C{expr*n + L{ZeroOrMore}(expr)} + (read as "at least n instances of C{expr}") + - C{expr*(None,n)} is equivalent to C{expr*(0,n)} + (read as "0 to n instances of C{expr}") + - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} + - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} + + Note that C{expr*(None,n)} does not raise an exception if + more than n exprs exist in the input stream; that is, + C{expr*(None,n)} does not enforce a maximum number of expr + occurrences. If this behavior is desired, then write + C{expr*(None,n) + ~expr} + """ + if isinstance(other,int): + minElements, optElements = other,0 + elif isinstance(other,tuple): + other = (other + (None, None))[:2] + if other[0] is None: + other = (0, other[1]) + if isinstance(other[0],int) and other[1] is None: + if other[0] == 0: + return ZeroOrMore(self) + if other[0] == 1: + return OneOrMore(self) + else: + return self*other[0] + ZeroOrMore(self) + elif isinstance(other[0],int) and isinstance(other[1],int): + minElements, optElements = other + optElements -= minElements + else: + raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) + else: + raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) + + if minElements < 0: + raise ValueError("cannot multiply ParserElement by negative value") + if optElements < 0: + raise ValueError("second tuple value must be greater or equal to first tuple value") + if minElements == optElements == 0: + raise ValueError("cannot multiply ParserElement by 0 or (0,0)") + + if (optElements): + def makeOptionalList(n): + if n>1: + return Optional(self + makeOptionalList(n-1)) + else: + return Optional(self) + if minElements: + if minElements == 1: + ret = self + makeOptionalList(optElements) + else: + ret = And([self]*minElements) + makeOptionalList(optElements) + else: + ret = makeOptionalList(optElements) + else: + if minElements == 1: + ret = self + else: + ret = And([self]*minElements) + return ret + + def __rmul__(self, other): + return self.__mul__(other) + + def __or__(self, other ): + """ + Implementation of | operator - returns C{L{MatchFirst}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return MatchFirst( [ self, other ] ) + + def __ror__(self, other ): + """ + Implementation of | operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other | self + + def __xor__(self, other ): + """ + Implementation of ^ operator - returns C{L{Or}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Or( [ self, other ] ) + + def __rxor__(self, other ): + """ + Implementation of ^ operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other ^ self + + def __and__(self, other ): + """ + Implementation of & operator - returns C{L{Each}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Each( [ self, other ] ) + + def __rand__(self, other ): + """ + Implementation of & operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other & self + + def __invert__( self ): + """ + Implementation of ~ operator - returns C{L{NotAny}} + """ + return NotAny( self ) + + def __call__(self, name=None): + """ + Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. + + If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be + passed as C{True}. + + If C{name} is omitted, same as calling C{L{copy}}. + + Example:: + # these are equivalent + userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") + userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") + """ + if name is not None: + return self.setResultsName(name) + else: + return self.copy() + + def suppress( self ): + """ + Suppresses the output of this C{ParserElement}; useful to keep punctuation from + cluttering up returned output. + """ + return Suppress( self ) + + def leaveWhitespace( self ): + """ + Disables the skipping of whitespace before matching the characters in the + C{ParserElement}'s defined pattern. This is normally only used internally by + the pyparsing module, but may be needed in some whitespace-sensitive grammars. + """ + self.skipWhitespace = False + return self + + def setWhitespaceChars( self, chars ): + """ + Overrides the default whitespace chars + """ + self.skipWhitespace = True + self.whiteChars = chars + self.copyDefaultWhiteChars = False + return self + + def parseWithTabs( self ): + """ + Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string. + Must be called before C{parseString} when the input grammar contains elements that + match C{<TAB>} characters. + """ + self.keepTabs = True + return self + + def ignore( self, other ): + """ + Define expression to be ignored (e.g., comments) while doing pattern + matching; may be called repeatedly, to define multiple comment or other + ignorable patterns. + + Example:: + patt = OneOrMore(Word(alphas)) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] + + patt.ignore(cStyleComment) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] + """ + if isinstance(other, basestring): + other = Suppress(other) + + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + self.ignoreExprs.append(other) + else: + self.ignoreExprs.append( Suppress( other.copy() ) ) + return self + + def setDebugActions( self, startAction, successAction, exceptionAction ): + """ + Enable display of debugging messages while doing pattern matching. + """ + self.debugActions = (startAction or _defaultStartDebugAction, + successAction or _defaultSuccessDebugAction, + exceptionAction or _defaultExceptionDebugAction) + self.debug = True + return self + + def setDebug( self, flag=True ): + """ + Enable display of debugging messages while doing pattern matching. + Set C{flag} to True to enable, False to disable. + + Example:: + wd = Word(alphas).setName("alphaword") + integer = Word(nums).setName("numword") + term = wd | integer + + # turn on debugging for wd + wd.setDebug() + + OneOrMore(term).parseString("abc 123 xyz 890") + + prints:: + Match alphaword at loc 0(1,1) + Matched alphaword -> ['abc'] + Match alphaword at loc 3(1,4) + Exception raised:Expected alphaword (at char 4), (line:1, col:5) + Match alphaword at loc 7(1,8) + Matched alphaword -> ['xyz'] + Match alphaword at loc 11(1,12) + Exception raised:Expected alphaword (at char 12), (line:1, col:13) + Match alphaword at loc 15(1,16) + Exception raised:Expected alphaword (at char 15), (line:1, col:16) + + The output shown is that produced by the default debug actions - custom debug actions can be + specified using L{setDebugActions}. Prior to attempting + to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"} + is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"} + message is shown. Also note the use of L{setName} to assign a human-readable name to the expression, + which makes debugging and exception messages easier to understand - for instance, the default + name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. + """ + if flag: + self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) + else: + self.debug = False + return self + + def __str__( self ): + return self.name + + def __repr__( self ): + return _ustr(self) + + def streamline( self ): + self.streamlined = True + self.strRepr = None + return self + + def checkRecursion( self, parseElementList ): + pass + + def validate( self, validateTrace=[] ): + """ + Check defined expressions for valid structure, check for infinite recursive definitions. + """ + self.checkRecursion( [] ) + + def parseFile( self, file_or_filename, parseAll=False ): + """ + Execute the parse expression on the given file or filename. + If a filename is specified (instead of a file object), + the entire file is opened, read, and closed before parsing. + """ + try: + file_contents = file_or_filename.read() + except AttributeError: + with open(file_or_filename, "r") as f: + file_contents = f.read() + try: + return self.parseString(file_contents, parseAll) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def __eq__(self,other): + if isinstance(other, ParserElement): + return self is other or vars(self) == vars(other) + elif isinstance(other, basestring): + return self.matches(other) + else: + return super(ParserElement,self)==other + + def __ne__(self,other): + return not (self == other) + + def __hash__(self): + return hash(id(self)) + + def __req__(self,other): + return self == other + + def __rne__(self,other): + return not (self == other) + + def matches(self, testString, parseAll=True): + """ + Method for quick testing of a parser against a test string. Good for simple + inline microtests of sub expressions while building up larger parser. + + Parameters: + - testString - to test against this expression for a match + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + + Example:: + expr = Word(nums) + assert expr.matches("100") + """ + try: + self.parseString(_ustr(testString), parseAll=parseAll) + return True + except ParseBaseException: + return False + + def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): + """ + Execute the parse expression on a series of test strings, showing each + test, the parsed results or where the parse failed. Quick and easy way to + run a parse expression against a list of sample strings. + + Parameters: + - tests - a list of separate test strings, or a multiline string of test strings + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + - comment - (default=C{'#'}) - expression for indicating embedded comments in the test + string; pass None to disable comment filtering + - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; + if False, only dump nested list + - printResults - (default=C{True}) prints test output to stdout + - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing + + Returns: a (success, results) tuple, where success indicates that all tests succeeded + (or failed if C{failureTests} is True), and the results contain a list of lines of each + test's output + + Example:: + number_expr = pyparsing_common.number.copy() + + result = number_expr.runTests(''' + # unsigned integer + 100 + # negative integer + -100 + # float with scientific notation + 6.02e23 + # integer with scientific notation + 1e-12 + ''') + print("Success" if result[0] else "Failed!") + + result = number_expr.runTests(''' + # stray character + 100Z + # missing leading digit before '.' + -.100 + # too many '.' + 3.14.159 + ''', failureTests=True) + print("Success" if result[0] else "Failed!") + prints:: + # unsigned integer + 100 + [100] + + # negative integer + -100 + [-100] + + # float with scientific notation + 6.02e23 + [6.02e+23] + + # integer with scientific notation + 1e-12 + [1e-12] + + Success + + # stray character + 100Z + ^ + FAIL: Expected end of text (at char 3), (line:1, col:4) + + # missing leading digit before '.' + -.100 + ^ + FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) + + # too many '.' + 3.14.159 + ^ + FAIL: Expected end of text (at char 4), (line:1, col:5) + + Success + + Each test string must be on a single line. If you want to test a string that spans multiple + lines, create a test like this:: + + expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") + + (Note that this is a raw string literal, you must include the leading 'r'.) + """ + if isinstance(tests, basestring): + tests = list(map(str.strip, tests.rstrip().splitlines())) + if isinstance(comment, basestring): + comment = Literal(comment) + allResults = [] + comments = [] + success = True + for t in tests: + if comment is not None and comment.matches(t, False) or comments and not t: + comments.append(t) + continue + if not t: + continue + out = ['\n'.join(comments), t] + comments = [] + try: + t = t.replace(r'\n','\n') + result = self.parseString(t, parseAll=parseAll) + out.append(result.dump(full=fullDump)) + success = success and not failureTests + except ParseBaseException as pe: + fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" + if '\n' in t: + out.append(line(pe.loc, t)) + out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) + else: + out.append(' '*pe.loc + '^' + fatal) + out.append("FAIL: " + str(pe)) + success = success and failureTests + result = pe + except Exception as exc: + out.append("FAIL-EXCEPTION: " + str(exc)) + success = success and failureTests + result = exc + + if printResults: + if fullDump: + out.append('') + print('\n'.join(out)) + + allResults.append((t, result)) + + return success, allResults + + +class Token(ParserElement): + """ + Abstract C{ParserElement} subclass, for defining atomic matching patterns. + """ + def __init__( self ): + super(Token,self).__init__( savelist=False ) + + +class Empty(Token): + """ + An empty token, will always match. + """ + def __init__( self ): + super(Empty,self).__init__() + self.name = "Empty" + self.mayReturnEmpty = True + self.mayIndexError = False + + +class NoMatch(Token): + """ + A token that will never match. + """ + def __init__( self ): + super(NoMatch,self).__init__() + self.name = "NoMatch" + self.mayReturnEmpty = True + self.mayIndexError = False + self.errmsg = "Unmatchable token" + + def parseImpl( self, instring, loc, doActions=True ): + raise ParseException(instring, loc, self.errmsg, self) + + +class Literal(Token): + """ + Token to exactly match a specified string. + + Example:: + Literal('blah').parseString('blah') # -> ['blah'] + Literal('blah').parseString('blahfooblah') # -> ['blah'] + Literal('blah').parseString('bla') # -> Exception: Expected "blah" + + For case-insensitive matching, use L{CaselessLiteral}. + + For keyword matching (force word break before and after the matched string), + use L{Keyword} or L{CaselessKeyword}. + """ + def __init__( self, matchString ): + super(Literal,self).__init__() + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Literal; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.__class__ = Empty + self.name = '"%s"' % _ustr(self.match) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + + # Performance tuning: this routine gets called a *lot* + # if this is a single character match string and the first character matches, + # short-circuit as quickly as possible, and avoid calling startswith + #~ @profile + def parseImpl( self, instring, loc, doActions=True ): + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) +_L = Literal +ParserElement._literalStringClass = Literal + +class Keyword(Token): + """ + Token to exactly match a specified string as a keyword, that is, it must be + immediately followed by a non-keyword character. Compare with C{L{Literal}}: + - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. + - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} + Accepts two optional constructor arguments in addition to the keyword string: + - C{identChars} is a string of characters that would be valid identifier characters, + defaulting to all alphanumerics + "_" and "$" + - C{caseless} allows case-insensitive matching, default is C{False}. + + Example:: + Keyword("start").parseString("start") # -> ['start'] + Keyword("start").parseString("starting") # -> Exception + + For case-insensitive matching, use L{CaselessKeyword}. + """ + DEFAULT_KEYWORD_CHARS = alphanums+"_$" + + def __init__( self, matchString, identChars=None, caseless=False ): + super(Keyword,self).__init__() + if identChars is None: + identChars = Keyword.DEFAULT_KEYWORD_CHARS + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Keyword; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.name = '"%s"' % self.match + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + self.caseless = caseless + if caseless: + self.caselessmatch = matchString.upper() + identChars = identChars.upper() + self.identChars = set(identChars) + + def parseImpl( self, instring, loc, doActions=True ): + if self.caseless: + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and + (loc == 0 or instring[loc-1].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + else: + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and + (loc == 0 or instring[loc-1] not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + + def copy(self): + c = super(Keyword,self).copy() + c.identChars = Keyword.DEFAULT_KEYWORD_CHARS + return c + + @staticmethod + def setDefaultKeywordChars( chars ): + """Overrides the default Keyword chars + """ + Keyword.DEFAULT_KEYWORD_CHARS = chars + +class CaselessLiteral(Literal): + """ + Token to match a specified string, ignoring case of letters. + Note: the matched results will always be in the case of the given + match string, NOT the case of the input text. + + Example:: + OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] + + (Contrast with example for L{CaselessKeyword}.) + """ + def __init__( self, matchString ): + super(CaselessLiteral,self).__init__( matchString.upper() ) + # Preserve the defining literal. + self.returnString = matchString + self.name = "'%s'" % self.returnString + self.errmsg = "Expected " + self.name + + def parseImpl( self, instring, loc, doActions=True ): + if instring[ loc:loc+self.matchLen ].upper() == self.match: + return loc+self.matchLen, self.returnString + raise ParseException(instring, loc, self.errmsg, self) + +class CaselessKeyword(Keyword): + """ + Caseless version of L{Keyword}. + + Example:: + OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] + + (Contrast with example for L{CaselessLiteral}.) + """ + def __init__( self, matchString, identChars=None ): + super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) + + def parseImpl( self, instring, loc, doActions=True ): + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + +class CloseMatch(Token): + """ + A variation on L{Literal} which matches "close" matches, that is, + strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: + - C{match_string} - string to be matched + - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match + + The results from a successful parse will contain the matched text from the input string and the following named results: + - C{mismatches} - a list of the positions within the match_string where mismatches were found + - C{original} - the original match_string used to compare against the input string + + If C{mismatches} is an empty list, then the match was an exact match. + + Example:: + patt = CloseMatch("ATCATCGAATGGA") + patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) + patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) + + # exact match + patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) + + # close match allowing up to 2 mismatches + patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) + patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) + """ + def __init__(self, match_string, maxMismatches=1): + super(CloseMatch,self).__init__() + self.name = match_string + self.match_string = match_string + self.maxMismatches = maxMismatches + self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) + self.mayIndexError = False + self.mayReturnEmpty = False + + def parseImpl( self, instring, loc, doActions=True ): + start = loc + instrlen = len(instring) + maxloc = start + len(self.match_string) + + if maxloc <= instrlen: + match_string = self.match_string + match_stringloc = 0 + mismatches = [] + maxMismatches = self.maxMismatches + + for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): + src,mat = s_m + if src != mat: + mismatches.append(match_stringloc) + if len(mismatches) > maxMismatches: + break + else: + loc = match_stringloc + 1 + results = ParseResults([instring[start:loc]]) + results['original'] = self.match_string + results['mismatches'] = mismatches + return loc, results + + raise ParseException(instring, loc, self.errmsg, self) + + +class Word(Token): + """ + Token for matching words composed of allowed character sets. + Defined with string containing all allowed initial characters, + an optional string containing allowed body characters (if omitted, + defaults to the initial character set), and an optional minimum, + maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. An optional + C{excludeChars} parameter can list characters that might be found in + the input C{bodyChars} string; useful to define a word of all printables + except for one or two characters, for instance. + + L{srange} is useful for defining custom character set strings for defining + C{Word} expressions, using range notation from regular expression character sets. + + A common mistake is to use C{Word} to match a specific literal string, as in + C{Word("Address")}. Remember that C{Word} uses the string argument to define + I{sets} of matchable characters. This expression would match "Add", "AAA", + "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. + To match an exact literal string, use L{Literal} or L{Keyword}. + + pyparsing includes helper strings for building Words: + - L{alphas} + - L{nums} + - L{alphanums} + - L{hexnums} + - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) + - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) + - L{printables} (any non-whitespace character) + + Example:: + # a word composed of digits + integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) + + # a word with a leading capital, and zero or more lowercase + capital_word = Word(alphas.upper(), alphas.lower()) + + # hostnames are alphanumeric, with leading alpha, and '-' + hostname = Word(alphas, alphanums+'-') + + # roman numeral (not a strict parser, accepts invalid mix of characters) + roman = Word("IVXLCDM") + + # any string of non-whitespace characters, except for ',' + csv_value = Word(printables, excludeChars=",") + """ + def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): + super(Word,self).__init__() + if excludeChars: + initChars = ''.join(c for c in initChars if c not in excludeChars) + if bodyChars: + bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) + self.initCharsOrig = initChars + self.initChars = set(initChars) + if bodyChars : + self.bodyCharsOrig = bodyChars + self.bodyChars = set(bodyChars) + else: + self.bodyCharsOrig = initChars + self.bodyChars = set(initChars) + + self.maxSpecified = max > 0 + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.asKeyword = asKeyword + + if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): + if self.bodyCharsOrig == self.initCharsOrig: + self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) + elif len(self.initCharsOrig) == 1: + self.reString = "%s[%s]*" % \ + (re.escape(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + else: + self.reString = "[%s][%s]*" % \ + (_escapeRegexRangeChars(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + if self.asKeyword: + self.reString = r"\b"+self.reString+r"\b" + try: + self.re = re.compile( self.reString ) + except Exception: + self.re = None + + def parseImpl( self, instring, loc, doActions=True ): + if self.re: + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + return loc, result.group() + + if not(instring[ loc ] in self.initChars): + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + instrlen = len(instring) + bodychars = self.bodyChars + maxloc = start + self.maxLen + maxloc = min( maxloc, instrlen ) + while loc < maxloc and instring[loc] in bodychars: + loc += 1 + + throwException = False + if loc - start < self.minLen: + throwException = True + if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: + throwException = True + if self.asKeyword: + if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars): + throwException = True + + if throwException: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(Word,self).__str__() + except Exception: + pass + + + if self.strRepr is None: + + def charsAsStr(s): + if len(s)>4: + return s[:4]+"..." + else: + return s + + if ( self.initCharsOrig != self.bodyCharsOrig ): + self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) + else: + self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) + + return self.strRepr + + +class Regex(Token): + r""" + Token for matching strings that match a given regular expression. + Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. + If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as + named parse results. + + Example:: + realnum = Regex(r"[+-]?\d+\.\d*") + date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)') + # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression + roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") + """ + compiledREtype = type(re.compile("[A-Z]")) + def __init__( self, pattern, flags=0): + """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" + super(Regex,self).__init__() + + if isinstance(pattern, basestring): + if not pattern: + warnings.warn("null string passed to Regex; use Empty() instead", + SyntaxWarning, stacklevel=2) + + self.pattern = pattern + self.flags = flags + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % pattern, + SyntaxWarning, stacklevel=2) + raise + + elif isinstance(pattern, Regex.compiledREtype): + self.re = pattern + self.pattern = \ + self.reString = str(pattern) + self.flags = flags + + else: + raise ValueError("Regex may only be constructed with a string or a compiled RE object") + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + d = result.groupdict() + ret = ParseResults(result.group()) + if d: + for k in d: + ret[k] = d[k] + return loc,ret + + def __str__( self ): + try: + return super(Regex,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "Re:(%s)" % repr(self.pattern) + + return self.strRepr + + +class QuotedString(Token): + r""" + Token for matching strings that are delimited by quoting characters. + + Defined with the following parameters: + - quoteChar - string of one or more characters defining the quote delimiting string + - escChar - character to escape quotes, typically backslash (default=C{None}) + - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) + - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) + - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) + - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) + - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) + + Example:: + qs = QuotedString('"') + print(qs.searchString('lsjdf "This is the quote" sldjf')) + complex_qs = QuotedString('{{', endQuoteChar='}}') + print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) + sql_qs = QuotedString('"', escQuote='""') + print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) + prints:: + [['This is the quote']] + [['This is the "quote"']] + [['This is the quote with "embedded" quotes']] + """ + def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): + super(QuotedString,self).__init__() + + # remove white space from quote chars - wont work anyway + quoteChar = quoteChar.strip() + if not quoteChar: + warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + if endQuoteChar is None: + endQuoteChar = quoteChar + else: + endQuoteChar = endQuoteChar.strip() + if not endQuoteChar: + warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + self.quoteChar = quoteChar + self.quoteCharLen = len(quoteChar) + self.firstQuoteChar = quoteChar[0] + self.endQuoteChar = endQuoteChar + self.endQuoteCharLen = len(endQuoteChar) + self.escChar = escChar + self.escQuote = escQuote + self.unquoteResults = unquoteResults + self.convertWhitespaceEscapes = convertWhitespaceEscapes + + if multiline: + self.flags = re.MULTILINE | re.DOTALL + self.pattern = r'%s(?:[^%s%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + else: + self.flags = 0 + self.pattern = r'%s(?:[^%s\n\r%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + if len(self.endQuoteChar) > 1: + self.pattern += ( + '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), + _escapeRegexRangeChars(self.endQuoteChar[i])) + for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' + ) + if escQuote: + self.pattern += (r'|(?:%s)' % re.escape(escQuote)) + if escChar: + self.pattern += (r'|(?:%s.)' % re.escape(escChar)) + self.escCharReplacePattern = re.escape(self.escChar)+"(.)" + self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, + SyntaxWarning, stacklevel=2) + raise + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + ret = result.group() + + if self.unquoteResults: + + # strip off quotes + ret = ret[self.quoteCharLen:-self.endQuoteCharLen] + + if isinstance(ret,basestring): + # replace escaped whitespace + if '\\' in ret and self.convertWhitespaceEscapes: + ws_map = { + r'\t' : '\t', + r'\n' : '\n', + r'\f' : '\f', + r'\r' : '\r', + } + for wslit,wschar in ws_map.items(): + ret = ret.replace(wslit, wschar) + + # replace escaped characters + if self.escChar: + ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) + + # replace escaped quotes + if self.escQuote: + ret = ret.replace(self.escQuote, self.endQuoteChar) + + return loc, ret + + def __str__( self ): + try: + return super(QuotedString,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) + + return self.strRepr + + +class CharsNotIn(Token): + """ + Token for matching words composed of characters I{not} in a given set (will + include whitespace in matched characters if not listed in the provided exclusion set - see example). + Defined with string containing all disallowed characters, and an optional + minimum, maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. + + Example:: + # define a comma-separated-value as anything that is not a ',' + csv_value = CharsNotIn(',') + print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) + prints:: + ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] + """ + def __init__( self, notChars, min=1, max=0, exact=0 ): + super(CharsNotIn,self).__init__() + self.skipWhitespace = False + self.notChars = notChars + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = ( self.minLen == 0 ) + self.mayIndexError = False + + def parseImpl( self, instring, loc, doActions=True ): + if instring[loc] in self.notChars: + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + notchars = self.notChars + maxlen = min( start+self.maxLen, len(instring) ) + while loc < maxlen and \ + (instring[loc] not in notchars): + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(CharsNotIn, self).__str__() + except Exception: + pass + + if self.strRepr is None: + if len(self.notChars) > 4: + self.strRepr = "!W:(%s...)" % self.notChars[:4] + else: + self.strRepr = "!W:(%s)" % self.notChars + + return self.strRepr + +class White(Token): + """ + Special matching class for matching whitespace. Normally, whitespace is ignored + by pyparsing grammars. This class is included when some whitespace structures + are significant. Define with a string containing the whitespace characters to be + matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, + as defined for the C{L{Word}} class. + """ + whiteStrs = { + " " : "<SPC>", + "\t": "<TAB>", + "\n": "<LF>", + "\r": "<CR>", + "\f": "<FF>", + } + def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): + super(White,self).__init__() + self.matchWhite = ws + self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) + #~ self.leaveWhitespace() + self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) + self.mayReturnEmpty = True + self.errmsg = "Expected " + self.name + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + def parseImpl( self, instring, loc, doActions=True ): + if not(instring[ loc ] in self.matchWhite): + raise ParseException(instring, loc, self.errmsg, self) + start = loc + loc += 1 + maxloc = start + self.maxLen + maxloc = min( maxloc, len(instring) ) + while loc < maxloc and instring[loc] in self.matchWhite: + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + +class _PositionToken(Token): + def __init__( self ): + super(_PositionToken,self).__init__() + self.name=self.__class__.__name__ + self.mayReturnEmpty = True + self.mayIndexError = False + +class GoToColumn(_PositionToken): + """ + Token to advance to a specific column of input text; useful for tabular report scraping. + """ + def __init__( self, colno ): + super(GoToColumn,self).__init__() + self.col = colno + + def preParse( self, instring, loc ): + if col(loc,instring) != self.col: + instrlen = len(instring) + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : + loc += 1 + return loc + + def parseImpl( self, instring, loc, doActions=True ): + thiscol = col( loc, instring ) + if thiscol > self.col: + raise ParseException( instring, loc, "Text not in expected column", self ) + newloc = loc + self.col - thiscol + ret = instring[ loc: newloc ] + return newloc, ret + + +class LineStart(_PositionToken): + """ + Matches if current position is at the beginning of a line within the parse string + + Example:: + + test = '''\ + AAA this line + AAA and this line + AAA but not this one + B AAA and definitely not this one + ''' + + for t in (LineStart() + 'AAA' + restOfLine).searchString(test): + print(t) + + Prints:: + ['AAA', ' this line'] + ['AAA', ' and this line'] + + """ + def __init__( self ): + super(LineStart,self).__init__() + self.errmsg = "Expected start of line" + + def parseImpl( self, instring, loc, doActions=True ): + if col(loc, instring) == 1: + return loc, [] + raise ParseException(instring, loc, self.errmsg, self) + +class LineEnd(_PositionToken): + """ + Matches if current position is at the end of a line within the parse string + """ + def __init__( self ): + super(LineEnd,self).__init__() + self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) + self.errmsg = "Expected end of line" + + def parseImpl( self, instring, loc, doActions=True ): + if loc<len(instring): + if instring[loc] == "\n": + return loc+1, "\n" + else: + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class StringStart(_PositionToken): + """ + Matches if current position is at the beginning of the parse string + """ + def __init__( self ): + super(StringStart,self).__init__() + self.errmsg = "Expected start of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc != 0: + # see if entire string up to here is just whitespace and ignoreables + if loc != self.preParse( instring, 0 ): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class StringEnd(_PositionToken): + """ + Matches if current position is at the end of the parse string + """ + def __init__( self ): + super(StringEnd,self).__init__() + self.errmsg = "Expected end of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc < len(instring): + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + elif loc > len(instring): + return loc, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class WordStart(_PositionToken): + """ + Matches if the current position is at the beginning of a Word, and + is not preceded by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of + the string being parsed, or at the beginning of a line. + """ + def __init__(self, wordChars = printables): + super(WordStart,self).__init__() + self.wordChars = set(wordChars) + self.errmsg = "Not at the start of a word" + + def parseImpl(self, instring, loc, doActions=True ): + if loc != 0: + if (instring[loc-1] in self.wordChars or + instring[loc] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class WordEnd(_PositionToken): + """ + Matches if the current position is at the end of a Word, and + is not followed by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of + the string being parsed, or at the end of a line. + """ + def __init__(self, wordChars = printables): + super(WordEnd,self).__init__() + self.wordChars = set(wordChars) + self.skipWhitespace = False + self.errmsg = "Not at the end of a word" + + def parseImpl(self, instring, loc, doActions=True ): + instrlen = len(instring) + if instrlen>0 and loc<instrlen: + if (instring[loc] in self.wordChars or + instring[loc-1] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + +class ParseExpression(ParserElement): + """ + Abstract subclass of ParserElement, for combining and post-processing parsed tokens. + """ + def __init__( self, exprs, savelist = False ): + super(ParseExpression,self).__init__(savelist) + if isinstance( exprs, _generatorType ): + exprs = list(exprs) + + if isinstance( exprs, basestring ): + self.exprs = [ ParserElement._literalStringClass( exprs ) ] + elif isinstance( exprs, collections.Iterable ): + exprs = list(exprs) + # if sequence of strings provided, wrap with Literal + if all(isinstance(expr, basestring) for expr in exprs): + exprs = map(ParserElement._literalStringClass, exprs) + self.exprs = list(exprs) + else: + try: + self.exprs = list( exprs ) + except TypeError: + self.exprs = [ exprs ] + self.callPreparse = False + + def __getitem__( self, i ): + return self.exprs[i] + + def append( self, other ): + self.exprs.append( other ) + self.strRepr = None + return self + + def leaveWhitespace( self ): + """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on + all contained expressions.""" + self.skipWhitespace = False + self.exprs = [ e.copy() for e in self.exprs ] + for e in self.exprs: + e.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + else: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + return self + + def __str__( self ): + try: + return super(ParseExpression,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) + return self.strRepr + + def streamline( self ): + super(ParseExpression,self).streamline() + + for e in self.exprs: + e.streamline() + + # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) + # but only if there are no parse actions or resultsNames on the nested And's + # (likewise for Or's and MatchFirst's) + if ( len(self.exprs) == 2 ): + other = self.exprs[0] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = other.exprs[:] + [ self.exprs[1] ] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + other = self.exprs[-1] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = self.exprs[:-1] + other.exprs[:] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + self.errmsg = "Expected " + _ustr(self) + + return self + + def setResultsName( self, name, listAllMatches=False ): + ret = super(ParseExpression,self).setResultsName(name,listAllMatches) + return ret + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + for e in self.exprs: + e.validate(tmp) + self.checkRecursion( [] ) + + def copy(self): + ret = super(ParseExpression,self).copy() + ret.exprs = [e.copy() for e in self.exprs] + return ret + +class And(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found in the given order. + Expressions may be separated by whitespace. + May be constructed using the C{'+'} operator. + May also be constructed using the C{'-'} operator, which will suppress backtracking. + + Example:: + integer = Word(nums) + name_expr = OneOrMore(Word(alphas)) + + expr = And([integer("id"),name_expr("name"),integer("age")]) + # more easily written as: + expr = integer("id") + name_expr("name") + integer("age") + """ + + class _ErrorStop(Empty): + def __init__(self, *args, **kwargs): + super(And._ErrorStop,self).__init__(*args, **kwargs) + self.name = '-' + self.leaveWhitespace() + + def __init__( self, exprs, savelist = True ): + super(And,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.setWhitespaceChars( self.exprs[0].whiteChars ) + self.skipWhitespace = self.exprs[0].skipWhitespace + self.callPreparse = True + + def parseImpl( self, instring, loc, doActions=True ): + # pass False as last arg to _parse for first element, since we already + # pre-parsed the string as part of our And pre-parsing + loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) + errorStop = False + for e in self.exprs[1:]: + if isinstance(e, And._ErrorStop): + errorStop = True + continue + if errorStop: + try: + loc, exprtokens = e._parse( instring, loc, doActions ) + except ParseSyntaxException: + raise + except ParseBaseException as pe: + pe.__traceback__ = None + raise ParseSyntaxException._from_exception(pe) + except IndexError: + raise ParseSyntaxException(instring, len(instring), self.errmsg, self) + else: + loc, exprtokens = e._parse( instring, loc, doActions ) + if exprtokens or exprtokens.haskeys(): + resultlist += exprtokens + return loc, resultlist + + def __iadd__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #And( [ self, other ] ) + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + if not e.mayReturnEmpty: + break + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + +class Or(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the expression that matches the longest string will be used. + May be constructed using the C{'^'} operator. + + Example:: + # construct Or using '^' operator + + number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) + prints:: + [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(Or,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + matches = [] + for e in self.exprs: + try: + loc2 = e.tryParse( instring, loc ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + else: + # save match among all matches, to retry longest to shortest + matches.append((loc2, e)) + + if matches: + matches.sort(key=lambda x: -x[0]) + for _,e in matches: + try: + return e._parse( instring, loc, doActions ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + + def __ixor__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #Or( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class MatchFirst(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the first one listed is the one that will match. + May be constructed using the C{'|'} operator. + + Example:: + # construct MatchFirst using '|' operator + + # watch the order of expressions to match + number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] + + # put more selective expression first + number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) + print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(MatchFirst,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + for e in self.exprs: + try: + ret = e._parse( instring, loc, doActions ) + return ret + except ParseException as err: + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + + # only got here if no expression matched, raise exception for match that made it the furthest + else: + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + def __ior__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #MatchFirst( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class Each(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found, but in any order. + Expressions may be separated by whitespace. + May be constructed using the C{'&'} operator. + + Example:: + color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") + shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") + integer = Word(nums) + shape_attr = "shape:" + shape_type("shape") + posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") + color_attr = "color:" + color("color") + size_attr = "size:" + integer("size") + + # use Each (using operator '&') to accept attributes in any order + # (shape and posn are required, color and size are optional) + shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) + + shape_spec.runTests(''' + shape: SQUARE color: BLACK posn: 100, 120 + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + color:GREEN size:20 shape:TRIANGLE posn:20,40 + ''' + ) + prints:: + shape: SQUARE color: BLACK posn: 100, 120 + ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] + - color: BLACK + - posn: ['100', ',', '120'] + - x: 100 + - y: 120 + - shape: SQUARE + + + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] + - color: BLUE + - posn: ['50', ',', '80'] + - x: 50 + - y: 80 + - shape: CIRCLE + - size: 50 + + + color: GREEN size: 20 shape: TRIANGLE posn: 20,40 + ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] + - color: GREEN + - posn: ['20', ',', '40'] + - x: 20 + - y: 40 + - shape: TRIANGLE + - size: 20 + """ + def __init__( self, exprs, savelist = True ): + super(Each,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.skipWhitespace = True + self.initExprGroups = True + + def parseImpl( self, instring, loc, doActions=True ): + if self.initExprGroups: + self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) + opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] + opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] + self.optionals = opt1 + opt2 + self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] + self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] + self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] + self.required += self.multirequired + self.initExprGroups = False + tmpLoc = loc + tmpReqd = self.required[:] + tmpOpt = self.optionals[:] + matchOrder = [] + + keepMatching = True + while keepMatching: + tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired + failed = [] + for e in tmpExprs: + try: + tmpLoc = e.tryParse( instring, tmpLoc ) + except ParseException: + failed.append(e) + else: + matchOrder.append(self.opt1map.get(id(e),e)) + if e in tmpReqd: + tmpReqd.remove(e) + elif e in tmpOpt: + tmpOpt.remove(e) + if len(failed) == len(tmpExprs): + keepMatching = False + + if tmpReqd: + missing = ", ".join(_ustr(e) for e in tmpReqd) + raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) + + # add any unmatched Optionals, in case they have default values defined + matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] + + resultlist = [] + for e in matchOrder: + loc,results = e._parse(instring,loc,doActions) + resultlist.append(results) + + finalResults = sum(resultlist, ParseResults([])) + return loc, finalResults + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class ParseElementEnhance(ParserElement): + """ + Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. + """ + def __init__( self, expr, savelist=False ): + super(ParseElementEnhance,self).__init__(savelist) + if isinstance( expr, basestring ): + if issubclass(ParserElement._literalStringClass, Token): + expr = ParserElement._literalStringClass(expr) + else: + expr = ParserElement._literalStringClass(Literal(expr)) + self.expr = expr + self.strRepr = None + if expr is not None: + self.mayIndexError = expr.mayIndexError + self.mayReturnEmpty = expr.mayReturnEmpty + self.setWhitespaceChars( expr.whiteChars ) + self.skipWhitespace = expr.skipWhitespace + self.saveAsList = expr.saveAsList + self.callPreparse = expr.callPreparse + self.ignoreExprs.extend(expr.ignoreExprs) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr is not None: + return self.expr._parse( instring, loc, doActions, callPreParse=False ) + else: + raise ParseException("",loc,self.errmsg,self) + + def leaveWhitespace( self ): + self.skipWhitespace = False + self.expr = self.expr.copy() + if self.expr is not None: + self.expr.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + else: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + return self + + def streamline( self ): + super(ParseElementEnhance,self).streamline() + if self.expr is not None: + self.expr.streamline() + return self + + def checkRecursion( self, parseElementList ): + if self in parseElementList: + raise RecursiveGrammarException( parseElementList+[self] ) + subRecCheckList = parseElementList[:] + [ self ] + if self.expr is not None: + self.expr.checkRecursion( subRecCheckList ) + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion( [] ) + + def __str__( self ): + try: + return super(ParseElementEnhance,self).__str__() + except Exception: + pass + + if self.strRepr is None and self.expr is not None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) + return self.strRepr + + +class FollowedBy(ParseElementEnhance): + """ + Lookahead matching of the given parse expression. C{FollowedBy} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression matches at the current + position. C{FollowedBy} always returns a null token list. + + Example:: + # use FollowedBy to match a label only if it is followed by a ':' + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() + prints:: + [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] + """ + def __init__( self, expr ): + super(FollowedBy,self).__init__(expr) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + self.expr.tryParse( instring, loc ) + return loc, [] + + +class NotAny(ParseElementEnhance): + """ + Lookahead to disallow matching with the given parse expression. C{NotAny} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression does I{not} match at the current + position. Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny} + always returns a null token list. May be constructed using the '~' operator. + + Example:: + + """ + def __init__( self, expr ): + super(NotAny,self).__init__(expr) + #~ self.leaveWhitespace() + self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + self.mayReturnEmpty = True + self.errmsg = "Found unwanted token, "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr.canParseNext(instring, loc): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "~{" + _ustr(self.expr) + "}" + + return self.strRepr + +class _MultipleMatch(ParseElementEnhance): + def __init__( self, expr, stopOn=None): + super(_MultipleMatch, self).__init__(expr) + self.saveAsList = True + ender = stopOn + if isinstance(ender, basestring): + ender = ParserElement._literalStringClass(ender) + self.not_ender = ~ender if ender is not None else None + + def parseImpl( self, instring, loc, doActions=True ): + self_expr_parse = self.expr._parse + self_skip_ignorables = self._skipIgnorables + check_ender = self.not_ender is not None + if check_ender: + try_not_ender = self.not_ender.tryParse + + # must be at least one (but first see if we are the stopOn sentinel; + # if so, fail) + if check_ender: + try_not_ender(instring, loc) + loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) + try: + hasIgnoreExprs = (not not self.ignoreExprs) + while 1: + if check_ender: + try_not_ender(instring, loc) + if hasIgnoreExprs: + preloc = self_skip_ignorables( instring, loc ) + else: + preloc = loc + loc, tmptokens = self_expr_parse( instring, preloc, doActions ) + if tmptokens or tmptokens.haskeys(): + tokens += tmptokens + except (ParseException,IndexError): + pass + + return loc, tokens + +class OneOrMore(_MultipleMatch): + """ + Repetition of one or more of the given expression. + + Parameters: + - expr - expression that must match one or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: BLACK" + OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] + + # use stopOn attribute for OneOrMore to avoid reading label string as part of the data + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] + + # could also be written as + (attr_expr * (1,)).parseString(text).pprint() + """ + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + _ustr(self.expr) + "}..." + + return self.strRepr + +class ZeroOrMore(_MultipleMatch): + """ + Optional repetition of zero or more of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example: similar to L{OneOrMore} + """ + def __init__( self, expr, stopOn=None): + super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) + except (ParseException,IndexError): + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]..." + + return self.strRepr + +class _NullToken(object): + def __bool__(self): + return False + __nonzero__ = __bool__ + def __str__(self): + return "" + +_optionalNotMatched = _NullToken() +class Optional(ParseElementEnhance): + """ + Optional matching of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - default (optional) - value to be returned if the optional expression is not found. + + Example:: + # US postal code can be a 5-digit zip, plus optional 4-digit qualifier + zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) + zip.runTests(''' + # traditional ZIP code + 12345 + + # ZIP+4 form + 12101-0001 + + # invalid ZIP + 98765- + ''') + prints:: + # traditional ZIP code + 12345 + ['12345'] + + # ZIP+4 form + 12101-0001 + ['12101-0001'] + + # invalid ZIP + 98765- + ^ + FAIL: Expected end of text (at char 5), (line:1, col:6) + """ + def __init__( self, expr, default=_optionalNotMatched ): + super(Optional,self).__init__( expr, savelist=False ) + self.saveAsList = self.expr.saveAsList + self.defaultValue = default + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) + except (ParseException,IndexError): + if self.defaultValue is not _optionalNotMatched: + if self.expr.resultsName: + tokens = ParseResults([ self.defaultValue ]) + tokens[self.expr.resultsName] = self.defaultValue + else: + tokens = [ self.defaultValue ] + else: + tokens = [] + return loc, tokens + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]" + + return self.strRepr + +class SkipTo(ParseElementEnhance): + """ + Token for skipping over all undefined text until the matched expression is found. + + Parameters: + - expr - target expression marking the end of the data to be skipped + - include - (default=C{False}) if True, the target expression is also parsed + (the skipped text and target expression are returned as a 2-element list). + - ignore - (default=C{None}) used to define grammars (typically quoted strings and + comments) that might contain false matches to the target expression + - failOn - (default=C{None}) define expressions that are not allowed to be + included in the skipped test; if found before the target expression is found, + the SkipTo is not a match + + Example:: + report = ''' + Outstanding Issues Report - 1 Jan 2000 + + # | Severity | Description | Days Open + -----+----------+-------------------------------------------+----------- + 101 | Critical | Intermittent system crash | 6 + 94 | Cosmetic | Spelling error on Login ('log|n') | 14 + 79 | Minor | System slow when running too many reports | 47 + ''' + integer = Word(nums) + SEP = Suppress('|') + # use SkipTo to simply match everything up until the next SEP + # - ignore quoted strings, so that a '|' character inside a quoted string does not match + # - parse action will call token.strip() for each matched token, i.e., the description body + string_data = SkipTo(SEP, ignore=quotedString) + string_data.setParseAction(tokenMap(str.strip)) + ticket_expr = (integer("issue_num") + SEP + + string_data("sev") + SEP + + string_data("desc") + SEP + + integer("days_open")) + + for tkt in ticket_expr.searchString(report): + print tkt.dump() + prints:: + ['101', 'Critical', 'Intermittent system crash', '6'] + - days_open: 6 + - desc: Intermittent system crash + - issue_num: 101 + - sev: Critical + ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] + - days_open: 14 + - desc: Spelling error on Login ('log|n') + - issue_num: 94 + - sev: Cosmetic + ['79', 'Minor', 'System slow when running too many reports', '47'] + - days_open: 47 + - desc: System slow when running too many reports + - issue_num: 79 + - sev: Minor + """ + def __init__( self, other, include=False, ignore=None, failOn=None ): + super( SkipTo, self ).__init__( other ) + self.ignoreExpr = ignore + self.mayReturnEmpty = True + self.mayIndexError = False + self.includeMatch = include + self.asList = False + if isinstance(failOn, basestring): + self.failOn = ParserElement._literalStringClass(failOn) + else: + self.failOn = failOn + self.errmsg = "No match found for "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + startloc = loc + instrlen = len(instring) + expr = self.expr + expr_parse = self.expr._parse + self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None + self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None + + tmploc = loc + while tmploc <= instrlen: + if self_failOn_canParseNext is not None: + # break if failOn expression matches + if self_failOn_canParseNext(instring, tmploc): + break + + if self_ignoreExpr_tryParse is not None: + # advance past ignore expressions + while 1: + try: + tmploc = self_ignoreExpr_tryParse(instring, tmploc) + except ParseBaseException: + break + + try: + expr_parse(instring, tmploc, doActions=False, callPreParse=False) + except (ParseException, IndexError): + # no match, advance loc in string + tmploc += 1 + else: + # matched skipto expr, done + break + + else: + # ran off the end of the input string without matching skipto expr, fail + raise ParseException(instring, loc, self.errmsg, self) + + # build up return values + loc = tmploc + skiptext = instring[startloc:loc] + skipresult = ParseResults(skiptext) + + if self.includeMatch: + loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) + skipresult += mat + + return loc, skipresult + +class Forward(ParseElementEnhance): + """ + Forward declaration of an expression to be defined later - + used for recursive grammars, such as algebraic infix notation. + When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. + + Note: take care when assigning to C{Forward} not to overlook precedence of operators. + Specifically, '|' has a lower precedence than '<<', so that:: + fwdExpr << a | b | c + will actually be evaluated as:: + (fwdExpr << a) | b | c + thereby leaving b and c out as parseable alternatives. It is recommended that you + explicitly group the values inserted into the C{Forward}:: + fwdExpr << (a | b | c) + Converting to use the '<<=' operator instead will avoid this problem. + + See L{ParseResults.pprint} for an example of a recursive parser created using + C{Forward}. + """ + def __init__( self, other=None ): + super(Forward,self).__init__( other, savelist=False ) + + def __lshift__( self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass(other) + self.expr = other + self.strRepr = None + self.mayIndexError = self.expr.mayIndexError + self.mayReturnEmpty = self.expr.mayReturnEmpty + self.setWhitespaceChars( self.expr.whiteChars ) + self.skipWhitespace = self.expr.skipWhitespace + self.saveAsList = self.expr.saveAsList + self.ignoreExprs.extend(self.expr.ignoreExprs) + return self + + def __ilshift__(self, other): + return self << other + + def leaveWhitespace( self ): + self.skipWhitespace = False + return self + + def streamline( self ): + if not self.streamlined: + self.streamlined = True + if self.expr is not None: + self.expr.streamline() + return self + + def validate( self, validateTrace=[] ): + if self not in validateTrace: + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion([]) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + return self.__class__.__name__ + ": ..." + + # stubbed out for now - creates awful memory and perf issues + self._revertClass = self.__class__ + self.__class__ = _ForwardNoRecurse + try: + if self.expr is not None: + retString = _ustr(self.expr) + else: + retString = "None" + finally: + self.__class__ = self._revertClass + return self.__class__.__name__ + ": " + retString + + def copy(self): + if self.expr is not None: + return super(Forward,self).copy() + else: + ret = Forward() + ret <<= self + return ret + +class _ForwardNoRecurse(Forward): + def __str__( self ): + return "..." + +class TokenConverter(ParseElementEnhance): + """ + Abstract subclass of C{ParseExpression}, for converting parsed results. + """ + def __init__( self, expr, savelist=False ): + super(TokenConverter,self).__init__( expr )#, savelist ) + self.saveAsList = False + +class Combine(TokenConverter): + """ + Converter to concatenate all matching tokens to a single string. + By default, the matching patterns must also be contiguous in the input string; + this can be disabled by specifying C{'adjacent=False'} in the constructor. + + Example:: + real = Word(nums) + '.' + Word(nums) + print(real.parseString('3.1416')) # -> ['3', '.', '1416'] + # will also erroneously match the following + print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] + + real = Combine(Word(nums) + '.' + Word(nums)) + print(real.parseString('3.1416')) # -> ['3.1416'] + # no match when there are internal spaces + print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) + """ + def __init__( self, expr, joinString="", adjacent=True ): + super(Combine,self).__init__( expr ) + # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself + if adjacent: + self.leaveWhitespace() + self.adjacent = adjacent + self.skipWhitespace = True + self.joinString = joinString + self.callPreparse = True + + def ignore( self, other ): + if self.adjacent: + ParserElement.ignore(self, other) + else: + super( Combine, self).ignore( other ) + return self + + def postParse( self, instring, loc, tokenlist ): + retToks = tokenlist.copy() + del retToks[:] + retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) + + if self.resultsName and retToks.haskeys(): + return [ retToks ] + else: + return retToks + +class Group(TokenConverter): + """ + Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. + + Example:: + ident = Word(alphas) + num = Word(nums) + term = ident | num + func = ident + Optional(delimitedList(term)) + print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] + + func = ident + Group(Optional(delimitedList(term))) + print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] + """ + def __init__( self, expr ): + super(Group,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + return [ tokenlist ] + +class Dict(TokenConverter): + """ + Converter to return a repetitive expression as a list, but also as a dictionary. + Each element can also be referenced using the first token in the expression as its key. + Useful for tabular report scraping when the first column can be used as a item key. + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + # print attributes as plain groups + print(OneOrMore(attr_expr).parseString(text).dump()) + + # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names + result = Dict(OneOrMore(Group(attr_expr))).parseString(text) + print(result.dump()) + + # access named fields as dict entries, or output as dict + print(result['shape']) + print(result.asDict()) + prints:: + ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] + + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} + See more examples at L{ParseResults} of accessing fields by results name. + """ + def __init__( self, expr ): + super(Dict,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + for i,tok in enumerate(tokenlist): + if len(tok) == 0: + continue + ikey = tok[0] + if isinstance(ikey,int): + ikey = _ustr(tok[0]).strip() + if len(tok)==1: + tokenlist[ikey] = _ParseResultsWithOffset("",i) + elif len(tok)==2 and not isinstance(tok[1],ParseResults): + tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) + else: + dictvalue = tok.copy() #ParseResults(i) + del dictvalue[0] + if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) + else: + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) + + if self.resultsName: + return [ tokenlist ] + else: + return tokenlist + + +class Suppress(TokenConverter): + """ + Converter for ignoring the results of a parsed expression. + + Example:: + source = "a, b, c,d" + wd = Word(alphas) + wd_list1 = wd + ZeroOrMore(',' + wd) + print(wd_list1.parseString(source)) + + # often, delimiters that are useful during parsing are just in the + # way afterward - use Suppress to keep them out of the parsed output + wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) + print(wd_list2.parseString(source)) + prints:: + ['a', ',', 'b', ',', 'c', ',', 'd'] + ['a', 'b', 'c', 'd'] + (See also L{delimitedList}.) + """ + def postParse( self, instring, loc, tokenlist ): + return [] + + def suppress( self ): + return self + + +class OnlyOnce(object): + """ + Wrapper for parse actions, to ensure they are only called once. + """ + def __init__(self, methodCall): + self.callable = _trim_arity(methodCall) + self.called = False + def __call__(self,s,l,t): + if not self.called: + results = self.callable(s,l,t) + self.called = True + return results + raise ParseException(s,l,"") + def reset(self): + self.called = False + +def traceParseAction(f): + """ + Decorator for debugging parse actions. + + When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} + When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. + + Example:: + wd = Word(alphas) + + @traceParseAction + def remove_duplicate_chars(tokens): + return ''.join(sorted(set(''.join(tokens))) + + wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) + print(wds.parseString("slkdjs sld sldd sdlf sdljf")) + prints:: + >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) + <<leaving remove_duplicate_chars (ret: 'dfjkls') + ['dfjkls'] + """ + f = _trim_arity(f) + def z(*paArgs): + thisFunc = f.__name__ + s,l,t = paArgs[-3:] + if len(paArgs)>3: + thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc + sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) + try: + ret = f(*paArgs) + except Exception as exc: + sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) ) + raise + sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) ) + return ret + try: + z.__name__ = f.__name__ + except AttributeError: + pass + return z + +# +# global helpers +# +def delimitedList( expr, delim=",", combine=False ): + """ + Helper to define a delimited list of expressions - the delimiter defaults to ','. + By default, the list elements and delimiters can have intervening whitespace, and + comments, but this can be overridden by passing C{combine=True} in the constructor. + If C{combine} is set to C{True}, the matching tokens are returned as a single token + string, with the delimiters included; otherwise, the matching tokens are returned + as a list of tokens, with the delimiters suppressed. + + Example:: + delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc'] + delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] + """ + dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." + if combine: + return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) + else: + return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) + +def countedArray( expr, intExpr=None ): + """ + Helper to define a counted list of expressions. + This helper defines a pattern of the form:: + integer expr expr expr... + where the leading integer tells how many expr expressions follow. + The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. + + If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. + + Example:: + countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] + + # in this parser, the leading integer value is given in binary, + # '10' indicating that 2 values are in the array + binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2)) + countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] + """ + arrayExpr = Forward() + def countFieldParseAction(s,l,t): + n = t[0] + arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) + return [] + if intExpr is None: + intExpr = Word(nums).setParseAction(lambda t:int(t[0])) + else: + intExpr = intExpr.copy() + intExpr.setName("arrayLen") + intExpr.addParseAction(countFieldParseAction, callDuringTry=True) + return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') + +def _flatten(L): + ret = [] + for i in L: + if isinstance(i,list): + ret.extend(_flatten(i)) + else: + ret.append(i) + return ret + +def matchPreviousLiteral(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousLiteral(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches a + previous literal, will also match the leading C{"1:1"} in C{"1:10"}. + If this is not desired, use C{matchPreviousExpr}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + def copyTokenToRepeater(s,l,t): + if t: + if len(t) == 1: + rep << t[0] + else: + # flatten t tokens + tflat = _flatten(t.asList()) + rep << And(Literal(tt) for tt in tflat) + else: + rep << Empty() + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def matchPreviousExpr(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousExpr(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches by + expressions, will I{not} match the leading C{"1:1"} in C{"1:10"}; + the expressions are evaluated first, and then compared, so + C{"1"} is compared with C{"10"}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + e2 = expr.copy() + rep <<= e2 + def copyTokenToRepeater(s,l,t): + matchTokens = _flatten(t.asList()) + def mustMatchTheseTokens(s,l,t): + theseTokens = _flatten(t.asList()) + if theseTokens != matchTokens: + raise ParseException("",0,"") + rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def _escapeRegexRangeChars(s): + #~ escape these chars: ^-] + for c in r"\^-]": + s = s.replace(c,_bslash+c) + s = s.replace("\n",r"\n") + s = s.replace("\t",r"\t") + return _ustr(s) + +def oneOf( strs, caseless=False, useRegex=True ): + """ + Helper to quickly define a set of alternative Literals, and makes sure to do + longest-first testing when there is a conflict, regardless of the input order, + but returns a C{L{MatchFirst}} for best performance. + + Parameters: + - strs - a string of space-delimited literals, or a collection of string literals + - caseless - (default=C{False}) - treat all literals as caseless + - useRegex - (default=C{True}) - as an optimization, will generate a Regex + object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or + if creating a C{Regex} raises an exception) + + Example:: + comp_oper = oneOf("< = > <= >= !=") + var = Word(alphas) + number = Word(nums) + term = var | number + comparison_expr = term + comp_oper + term + print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) + prints:: + [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] + """ + if caseless: + isequal = ( lambda a,b: a.upper() == b.upper() ) + masks = ( lambda a,b: b.upper().startswith(a.upper()) ) + parseElementClass = CaselessLiteral + else: + isequal = ( lambda a,b: a == b ) + masks = ( lambda a,b: b.startswith(a) ) + parseElementClass = Literal + + symbols = [] + if isinstance(strs,basestring): + symbols = strs.split() + elif isinstance(strs, collections.Iterable): + symbols = list(strs) + else: + warnings.warn("Invalid argument to oneOf, expected string or iterable", + SyntaxWarning, stacklevel=2) + if not symbols: + return NoMatch() + + i = 0 + while i < len(symbols)-1: + cur = symbols[i] + for j,other in enumerate(symbols[i+1:]): + if ( isequal(other, cur) ): + del symbols[i+j+1] + break + elif ( masks(cur, other) ): + del symbols[i+j+1] + symbols.insert(i,other) + cur = other + break + else: + i += 1 + + if not caseless and useRegex: + #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) + try: + if len(symbols)==len("".join(symbols)): + return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) + else: + return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) + except Exception: + warnings.warn("Exception creating Regex for oneOf, building MatchFirst", + SyntaxWarning, stacklevel=2) + + + # last resort, just use MatchFirst + return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) + +def dictOf( key, value ): + """ + Helper to easily and clearly define a dictionary by specifying the respective patterns + for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens + in the proper order. The key pattern can include delimiting markers or punctuation, + as long as they are suppressed, thereby leaving the significant key text. The value + pattern can include named results, so that the C{Dict} results can include named token + fields. + + Example:: + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + print(OneOrMore(attr_expr).parseString(text).dump()) + + attr_label = label + attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) + + # similar to Dict, but simpler call format + result = dictOf(attr_label, attr_value).parseString(text) + print(result.dump()) + print(result['shape']) + print(result.shape) # object attribute access works too + print(result.asDict()) + prints:: + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + SQUARE + {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} + """ + return Dict( ZeroOrMore( Group ( key + value ) ) ) + +def originalTextFor(expr, asString=True): + """ + Helper to return the original, untokenized text for a given expression. Useful to + restore the parsed fields of an HTML start tag into the raw tag text itself, or to + revert separate tokens with intervening whitespace back to the original matching + input text. By default, returns astring containing the original parsed text. + + If the optional C{asString} argument is passed as C{False}, then the return value is a + C{L{ParseResults}} containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if + the expression passed to C{L{originalTextFor}} contains expressions with defined + results names, you must set C{asString} to C{False} if you want to preserve those + results name values. + + Example:: + src = "this is test <b> bold <i>text</i> </b> normal text " + for tag in ("b","i"): + opener,closer = makeHTMLTags(tag) + patt = originalTextFor(opener + SkipTo(closer) + closer) + print(patt.searchString(src)[0]) + prints:: + ['<b> bold <i>text</i> </b>'] + ['<i>text</i>'] + """ + locMarker = Empty().setParseAction(lambda s,loc,t: loc) + endlocMarker = locMarker.copy() + endlocMarker.callPreparse = False + matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") + if asString: + extractText = lambda s,l,t: s[t._original_start:t._original_end] + else: + def extractText(s,l,t): + t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] + matchExpr.setParseAction(extractText) + matchExpr.ignoreExprs = expr.ignoreExprs + return matchExpr + +def ungroup(expr): + """ + Helper to undo pyparsing's default grouping of And expressions, even + if all but one are non-empty. + """ + return TokenConverter(expr).setParseAction(lambda t:t[0]) + +def locatedExpr(expr): + """ + Helper to decorate a returned token with its starting and ending locations in the input string. + This helper adds the following results names: + - locn_start = location where matched expression begins + - locn_end = location where matched expression ends + - value = the actual parsed results + + Be careful if the input text contains C{<TAB>} characters, you may want to call + C{L{ParserElement.parseWithTabs}} + + Example:: + wd = Word(alphas) + for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): + print(match) + prints:: + [[0, 'ljsdf', 5]] + [[8, 'lksdjjf', 15]] + [[18, 'lkkjj', 23]] + """ + locator = Empty().setParseAction(lambda s,l,t: l) + return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) + + +# convenience constants for positional expressions +empty = Empty().setName("empty") +lineStart = LineStart().setName("lineStart") +lineEnd = LineEnd().setName("lineEnd") +stringStart = StringStart().setName("stringStart") +stringEnd = StringEnd().setName("stringEnd") + +_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) +_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) +_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) +_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(printables, excludeChars=r'\]', exact=1) | Regex(r"\w", re.UNICODE) +_charRange = Group(_singleChar + Suppress("-") + _singleChar) +_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" + +def srange(s): + r""" + Helper to easily define string ranges for use in Word construction. Borrows + syntax from regexp '[]' string range definitions:: + srange("[0-9]") -> "0123456789" + srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" + srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" + The input string must be enclosed in []'s, and the returned string is the expanded + character set joined into a single string. + The values enclosed in the []'s may be: + - a single character + - an escaped character with a leading backslash (such as C{\-} or C{\]}) + - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) + (C{\0x##} is also supported for backwards compatibility) + - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) + - a range of any of the above, separated by a dash (C{'a-z'}, etc.) + - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) + """ + _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) + try: + return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) + except Exception: + return "" + +def matchOnlyAtCol(n): + """ + Helper method for defining parse actions that require matching at a specific + column in the input text. + """ + def verifyCol(strg,locn,toks): + if col(locn,strg) != n: + raise ParseException(strg,locn,"matched token not at column %d" % n) + return verifyCol + +def replaceWith(replStr): + """ + Helper method for common parse actions that simply return a literal value. Especially + useful when used with C{L{transformString<ParserElement.transformString>}()}. + + Example:: + num = Word(nums).setParseAction(lambda toks: int(toks[0])) + na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) + term = na | num + + OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] + """ + return lambda s,l,t: [replStr] + +def removeQuotes(s,l,t): + """ + Helper parse action for removing quotation marks from parsed quoted strings. + + Example:: + # by default, quotation marks are included in parsed results + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] + + # use removeQuotes to strip quotation marks from parsed results + quotedString.setParseAction(removeQuotes) + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] + """ + return t[0][1:-1] + +def tokenMap(func, *args): + """ + Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional + args are passed, they are forwarded to the given function as additional arguments after + the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the + parsed data to an integer using base 16. + + Example (compare the last to example in L{ParserElement.transformString}:: + hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) + hex_ints.runTests(''' + 00 11 22 aa FF 0a 0d 1a + ''') + + upperword = Word(alphas).setParseAction(tokenMap(str.upper)) + OneOrMore(upperword).runTests(''' + my kingdom for a horse + ''') + + wd = Word(alphas).setParseAction(tokenMap(str.title)) + OneOrMore(wd).setParseAction(' '.join).runTests(''' + now is the winter of our discontent made glorious summer by this sun of york + ''') + prints:: + 00 11 22 aa FF 0a 0d 1a + [0, 17, 34, 170, 255, 10, 13, 26] + + my kingdom for a horse + ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] + + now is the winter of our discontent made glorious summer by this sun of york + ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] + """ + def pa(s,l,t): + return [func(tokn, *args) for tokn in t] + + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + pa.__name__ = func_name + + return pa + +upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) +"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" + +downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) +"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" + +def _makeTags(tagStr, xml): + """Internal helper to construct opening and closing tag expressions, given a tag name""" + if isinstance(tagStr,basestring): + resname = tagStr + tagStr = Keyword(tagStr, caseless=not xml) + else: + resname = tagStr.name + + tagAttrName = Word(alphas,alphanums+"_-:") + if (xml): + tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + else: + printablesLessRAbrack = "".join(c for c in printables if c not in ">") + tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ + Optional( Suppress("=") + tagAttrValue ) ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + closeTag = Combine(_L("</") + tagStr + ">") + + openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) + closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname) + openTag.tag = resname + closeTag.tag = resname + return openTag, closeTag + +def makeHTMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches + tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. + + Example:: + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple + a,a_end = makeHTMLTags("A") + link_expr = a + SkipTo(a_end)("link_text") + a_end + + for link in link_expr.searchString(text): + # attributes in the <A> tag (like "href" shown here) are also accessible as named results + print(link.link_text, '->', link.href) + prints:: + pyparsing -> http://pyparsing.wikispaces.com + """ + return _makeTags( tagStr, False ) + +def makeXMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for XML, given a tag name. Matches + tags only in the given upper/lower case. + + Example: similar to L{makeHTMLTags} + """ + return _makeTags( tagStr, True ) + +def withAttribute(*args,**attrDict): + """ + Helper to create a validating parse action to be used with start tags created + with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag + with a required attribute value, to avoid false matches on common tags such as + C{<TD>} or C{<DIV>}. + + Call C{withAttribute} with a series of attribute names and values. Specify the list + of filter attributes names and values as: + - keyword arguments, as in C{(align="right")}, or + - as an explicit dict with C{**} operator, when an attribute name is also a Python + reserved word, as in C{**{"class":"Customer", "align":"right"}} + - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) + For attribute names with a namespace prefix, you must use the second form. Attribute + names are matched insensitive to upper/lower case. + + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. + + To verify that the attribute exists, but without specifying a value, pass + C{withAttribute.ANY_VALUE} as the value. + + Example:: + html = ''' + <div> + Some text + <div type="grid">1 4 0 1 0</div> + <div type="graph">1,3 2,3 1,1</div> + <div>this has no type</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + + # only match div tag having a type attribute with value "grid" + div_grid = div().setParseAction(withAttribute(type="grid")) + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + # construct a match with any div tag having a type attribute, regardless of the value + div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + if args: + attrs = args[:] + else: + attrs = attrDict.items() + attrs = [(k,v) for k,v in attrs] + def pa(s,l,tokens): + for attrName,attrValue in attrs: + if attrName not in tokens: + raise ParseException(s,l,"no matching attribute " + attrName) + if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: + raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % + (attrName, tokens[attrName], attrValue)) + return pa +withAttribute.ANY_VALUE = object() + +def withClass(classname, namespace=''): + """ + Simplified version of C{L{withAttribute}} when matching on a div class - made + difficult because C{class} is a reserved word in Python. + + Example:: + html = ''' + <div> + Some text + <div class="grid">1 4 0 1 0</div> + <div class="graph">1,3 2,3 1,1</div> + <div>this <div> has no class</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + div_grid = div().setParseAction(withClass("grid")) + + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + classattr = "%s:class" % namespace if namespace else "class" + return withAttribute(**{classattr : classname}) + +opAssoc = _Constants() +opAssoc.LEFT = object() +opAssoc.RIGHT = object() + +def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + """ + Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary or + binary, left- or right-associative. Parse actions can also be attached + to operator expressions. The generated parser will also recognize the use + of parentheses to override operator precedences (see example below). + + Note: if you define a deep operator list, you may see performance issues + when using infixNotation. See L{ParserElement.enablePackrat} for a + mechanism to potentially improve your parser performance. + + Parameters: + - baseExpr - expression representing the most basic element for the nested + - opList - list of tuples, one for each operator precedence level in the + expression grammar; each tuple is of the form + (opExpr, numTerms, rightLeftAssoc, parseAction), where: + - opExpr is the pyparsing expression for the operator; + may also be a string, which will be converted to a Literal; + if numTerms is 3, opExpr is a tuple of two expressions, for the + two operators separating the 3 terms + - numTerms is the number of terms for this operator (must + be 1, 2, or 3) + - rightLeftAssoc is the indicator whether the operator is + right or left associative, using the pyparsing-defined + constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. + - parseAction is the parse action to be associated with + expressions matching this operator expression (the + parse action tuple member may be omitted); if the parse action + is passed a tuple or list of functions, this is equivalent to + calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) + - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) + - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) + + Example:: + # simple example of four-function arithmetic with ints and variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infixNotation(integer | varname, + [ + ('-', 1, opAssoc.RIGHT), + (oneOf('* /'), 2, opAssoc.LEFT), + (oneOf('+ -'), 2, opAssoc.LEFT), + ]) + + arith_expr.runTests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', fullDump=False) + prints:: + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + ret = Forward() + lastExpr = baseExpr | ( lpar + ret + rpar ) + for i,operDef in enumerate(opList): + opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr + if arity == 3: + if opExpr is None or len(opExpr) != 2: + raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + opExpr1, opExpr2 = opExpr + thisExpr = Forward().setName(termName) + if rightLeftAssoc == opAssoc.LEFT: + if arity == 1: + matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + else: + matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ + Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + elif rightLeftAssoc == opAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Optional): + opExpr = Optional(opExpr) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + else: + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ + Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + else: + raise ValueError("operator must indicate right or left associativity") + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.setParseAction(*pa) + else: + matchExpr.setParseAction(pa) + thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + lastExpr = thisExpr + ret <<= lastExpr + return ret + +operatorPrecedence = infixNotation +"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" + +dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") +sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") +quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + +def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): + """ + Helper method for defining nested lists enclosed in opening and closing + delimiters ("(" and ")" are the default). + + Parameters: + - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression + - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression + - content - expression for items within the nested lists (default=C{None}) + - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) + + If an expression is not provided for the content argument, the nested + expression will capture all whitespace-delimited content between delimiters + as a list of separate values. + + Use the C{ignoreExpr} argument to define expressions that may contain + opening or closing characters that should not be treated as opening + or closing characters for nesting, such as quotedString or a comment + expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. + The default is L{quotedString}, but if no expressions are to be ignored, + then pass C{None} for this argument. + + Example:: + data_type = oneOf("void int short long char float double") + decl_data_type = Combine(data_type + Optional(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR,RPAR = map(Suppress, "()") + + code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(cStyleComment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.searchString(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + prints:: + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener,basestring) and isinstance(closer,basestring): + if len(opener) == 1 and len(closer)==1: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t:t[0].strip())) + else: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + ~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + raise ValueError("opening and closing arguments must be strings if no content expression is given") + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + else: + ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) + ret.setName('nested %s%s expression' % (opener,closer)) + return ret + +def indentedBlock(blockStatementExpr, indentStack, indent=True): + """ + Helper method for defining space-delimited indentation blocks, such as + those used to define block statements in Python source code. + + Parameters: + - blockStatementExpr - expression defining syntax of statement that + is repeated within the indented block + - indentStack - list created by caller to manage indentation stack + (multiple statementWithIndentedBlock expressions within a single grammar + should share a common indentStack) + - indent - boolean indicating whether block must be indented beyond the + the current level; set to False for block of left-most statements + (default=C{True}) + + A valid block must contain at least one C{blockStatement}. + + Example:: + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group( funcDecl + func_body ) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << ( funcDef | assignment | identifier ) + + module_body = OneOrMore(stmt) + + parseTree = module_body.parseString(data) + parseTree.pprint() + prints:: + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + def checkPeerIndent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseFatalException(s,l,"illegal nesting") + raise ParseException(s,l,"not a peer entry") + + def checkSubIndent(s,l,t): + curCol = col(l,s) + if curCol > indentStack[-1]: + indentStack.append( curCol ) + else: + raise ParseException(s,l,"not a subentry") + + def checkUnindent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s,l,"not an unindent") + indentStack.pop() + + NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) + INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') + PEER = Empty().setParseAction(checkPeerIndent).setName('') + UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') + if indent: + smExpr = Group( Optional(NL) + + #~ FollowedBy(blockStatementExpr) + + INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + else: + smExpr = Group( Optional(NL) + + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.setName('indented block') + +alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") +punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") + +anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) +commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +def replaceHTMLEntity(t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +"Comment of the form C{/* ... */}" + +htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment") +"Comment of the form C{<!-- ... -->}" + +restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") +dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") +"Comment of the form C{// ... (to end of line)}" + +cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" + +javaStyleComment = cppStyleComment +"Same as C{L{cppStyleComment}}" + +pythonStyleComment = Regex(r"#.*").setName("Python style comment") +"Comment of the form C{# ... (to end of line)}" + +_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + + Optional( Word(" \t") + + ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") +commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. + This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" + +# some other useful expressions - using lower-case class name since we are really using this as a namespace +class pyparsing_common: + """ + Here are some common low-level expressions that may be useful in jump-starting parser development: + - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>}) + - common L{programming identifiers<identifier>} + - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>}) + - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>} + - L{UUID<uuid>} + - L{comma-separated list<comma_separated_list>} + Parse actions: + - C{L{convertToInteger}} + - C{L{convertToFloat}} + - C{L{convertToDate}} + - C{L{convertToDatetime}} + - C{L{stripHTMLTags}} + - C{L{upcaseTokens}} + - C{L{downcaseTokens}} + + Example:: + pyparsing_common.number.runTests(''' + # any int or real number, returned as the appropriate type + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.fnumber.runTests(''' + # any int or real number, returned as float + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.hex_integer.runTests(''' + # hex numbers + 100 + FF + ''') + + pyparsing_common.fraction.runTests(''' + # fractions + 1/2 + -3/4 + ''') + + pyparsing_common.mixed_integer.runTests(''' + # mixed fractions + 1 + 1/2 + -3/4 + 1-3/4 + ''') + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(''' + # uuid + 12345678-1234-5678-1234-567812345678 + ''') + prints:: + # any int or real number, returned as the appropriate type + 100 + [100] + + -100 + [-100] + + +100 + [100] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # any int or real number, returned as float + 100 + [100.0] + + -100 + [-100.0] + + +100 + [100.0] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # hex numbers + 100 + [256] + + FF + [255] + + # fractions + 1/2 + [0.5] + + -3/4 + [-0.75] + + # mixed fractions + 1 + [1] + + 1/2 + [0.5] + + -3/4 + [-0.75] + + 1-3/4 + [1.75] + + # uuid + 12345678-1234-5678-1234-567812345678 + [UUID('12345678-1234-5678-1234-567812345678')] + """ + + convertToInteger = tokenMap(int) + """ + Parse action for converting parsed integers to Python int + """ + + convertToFloat = tokenMap(float) + """ + Parse action for converting parsed numbers to Python float + """ + + integer = Word(nums).setName("integer").setParseAction(convertToInteger) + """expression that parses an unsigned integer, returns an int""" + + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + """expression that parses a hexadecimal integer, returns an int""" + + signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + """expression that parses an integer with optional leading sign, returns an int""" + + fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + """fractional expression of an integer divided by an integer, returns a float""" + fraction.addParseAction(lambda t: t[0]/t[-1]) + + mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" + mixed_integer.addParseAction(sum) + + real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) + """expression that parses a floating point number and returns a float""" + + sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + """expression that parses a floating point number with optional scientific notation and returns a float""" + + # streamlining this expression makes the docs nicer-looking + number = (sci_real | real | signed_integer).streamline() + """any numeric expression, returns the corresponding Python type""" + + fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + """any int or real number, returned as float""" + + identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" + + ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + "IPv4 address (C{0.0.0.0 - 255.255.255.255})" + + _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") + _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") + _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") + ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + "IPv6 address (long, short, or mixed form)" + + mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" + + @staticmethod + def convertToDate(fmt="%Y-%m-%d"): + """ + Helper to create a parse action for converting parsed date string to Python datetime.date + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) + + Example:: + date_expr = pyparsing_common.iso8601_date.copy() + date_expr.setParseAction(pyparsing_common.convertToDate()) + print(date_expr.parseString("1999-12-31")) + prints:: + [datetime.date(1999, 12, 31)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt).date() + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + @staticmethod + def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): + """ + Helper to create a parse action for converting parsed datetime string to Python datetime.datetime + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) + + Example:: + dt_expr = pyparsing_common.iso8601_datetime.copy() + dt_expr.setParseAction(pyparsing_common.convertToDatetime()) + print(dt_expr.parseString("1999-12-31T23:59:59.999")) + prints:: + [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt) + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date") + "ISO8601 date (C{yyyy-mm-dd})" + + iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" + + uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") + "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" + + _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod + def stripHTMLTags(s, l, tokens): + """ + Parse action to remove HTML tags from web page HTML source + + Example:: + # strip HTML links from normal text + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + td,td_end = makeHTMLTags("TD") + table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end + + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' + """ + return pyparsing_common._html_stripper.transformString(tokens[0]) + + _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') + + Optional( White(" \t") ) ) ).streamline().setName("commaItem") + comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" + + upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) + """Parse action to convert tokens to upper case.""" + + downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) + """Parse action to convert tokens to lower case.""" + + +if __name__ == "__main__": + + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") + + ident = Word(alphas, alphanums + "_$") + + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnNameList = Group(delimitedList(columnName)).setName("columns") + columnSpec = ('*' | columnNameList) + + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + + # demo runTests method, including embedded comments in test string + simpleSQL.runTests(""" + # '*' as column list and dotted table name + select * from SYS.XYZZY + + # caseless match on "SELECT", and casts back to "select" + SELECT * from XYZZY, ABC + + # list of column names, and mixed case SELECT keyword + Select AA,BB,CC from Sys.dual + + # multiple tables + Select A, B, C from Sys.dual, Table2 + + # invalid SELECT keyword - should fail + Xelect A, B, C from Sys.dual + + # incomplete command - should fail + Select + + # invalid column name - should fail + Select ^^^ frox Sys.dual + + """) + + pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + # any int or real number, returned as float + pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + pyparsing_common.hex_integer.runTests(""" + 100 + FF + """) + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(""" + 12345678-1234-5678-1234-567812345678 + """) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py new file mode 100755 index 0000000..222a196 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py @@ -0,0 +1,3 @@ +from .core import TomlError +from .parser import load, loads +from .writer import dump, dumps diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py new file mode 100755 index 0000000..0fcada4 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py @@ -0,0 +1,13 @@ +class TomlError(RuntimeError): + def __init__(self, message, line, col, filename): + RuntimeError.__init__(self, message, line, col, filename) + self.message = message + self.line = line + self.col = col + self.filename = filename + + def __str__(self): + return '{}({}, {}): {}'.format(self.filename, self.line, self.col, self.message) + + def __repr__(self): + return 'TomlError({!r}, {!r}, {!r}, {!r})'.format(self.message, self.line, self.col, self.filename) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py new file mode 100755 index 0000000..c416ed5 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py @@ -0,0 +1,374 @@ +import string, re, sys, datetime +from .core import TomlError + +if sys.version_info[0] == 2: + _chr = unichr +else: + _chr = chr + +def load(fin, translate=lambda t, x, v: v): + return loads(fin.read(), translate=translate, filename=getattr(fin, 'name', repr(fin))) + +def loads(s, filename='<string>', translate=lambda t, x, v: v): + if isinstance(s, bytes): + s = s.decode('utf-8') + + s = s.replace('\r\n', '\n') + + root = {} + tables = {} + scope = root + + src = _Source(s, filename=filename) + ast = _p_toml(src) + + def error(msg): + raise TomlError(msg, pos[0], pos[1], filename) + + def process_value(v): + kind, text, value, pos = v + if kind == 'str' and value.startswith('\n'): + value = value[1:] + if kind == 'array': + if value and any(k != value[0][0] for k, t, v, p in value[1:]): + error('array-type-mismatch') + value = [process_value(item) for item in value] + elif kind == 'table': + value = dict([(k, process_value(value[k])) for k in value]) + return translate(kind, text, value) + + for kind, value, pos in ast: + if kind == 'kv': + k, v = value + if k in scope: + error('duplicate_keys. Key "{0}" was used more than once.'.format(k)) + scope[k] = process_value(v) + else: + is_table_array = (kind == 'table_array') + cur = tables + for name in value[:-1]: + if isinstance(cur.get(name), list): + d, cur = cur[name][-1] + else: + d, cur = cur.setdefault(name, (None, {})) + + scope = {} + name = value[-1] + if name not in cur: + if is_table_array: + cur[name] = [(scope, {})] + else: + cur[name] = (scope, {}) + elif isinstance(cur[name], list): + if not is_table_array: + error('table_type_mismatch') + cur[name].append((scope, {})) + else: + if is_table_array: + error('table_type_mismatch') + old_scope, next_table = cur[name] + if old_scope is not None: + error('duplicate_tables') + cur[name] = (scope, next_table) + + def merge_tables(scope, tables): + if scope is None: + scope = {} + for k in tables: + if k in scope: + error('key_table_conflict') + v = tables[k] + if isinstance(v, list): + scope[k] = [merge_tables(sc, tbl) for sc, tbl in v] + else: + scope[k] = merge_tables(v[0], v[1]) + return scope + + return merge_tables(root, tables) + +class _Source: + def __init__(self, s, filename=None): + self.s = s + self._pos = (1, 1) + self._last = None + self._filename = filename + self.backtrack_stack = [] + + def last(self): + return self._last + + def pos(self): + return self._pos + + def fail(self): + return self._expect(None) + + def consume_dot(self): + if self.s: + self._last = self.s[0] + self.s = self[1:] + self._advance(self._last) + return self._last + return None + + def expect_dot(self): + return self._expect(self.consume_dot()) + + def consume_eof(self): + if not self.s: + self._last = '' + return True + return False + + def expect_eof(self): + return self._expect(self.consume_eof()) + + def consume(self, s): + if self.s.startswith(s): + self.s = self.s[len(s):] + self._last = s + self._advance(s) + return True + return False + + def expect(self, s): + return self._expect(self.consume(s)) + + def consume_re(self, re): + m = re.match(self.s) + if m: + self.s = self.s[len(m.group(0)):] + self._last = m + self._advance(m.group(0)) + return m + return None + + def expect_re(self, re): + return self._expect(self.consume_re(re)) + + def __enter__(self): + self.backtrack_stack.append((self.s, self._pos)) + + def __exit__(self, type, value, traceback): + if type is None: + self.backtrack_stack.pop() + else: + self.s, self._pos = self.backtrack_stack.pop() + return type == TomlError + + def commit(self): + self.backtrack_stack[-1] = (self.s, self._pos) + + def _expect(self, r): + if not r: + raise TomlError('msg', self._pos[0], self._pos[1], self._filename) + return r + + def _advance(self, s): + suffix_pos = s.rfind('\n') + if suffix_pos == -1: + self._pos = (self._pos[0], self._pos[1] + len(s)) + else: + self._pos = (self._pos[0] + s.count('\n'), len(s) - suffix_pos) + +_ews_re = re.compile(r'(?:[ \t]|#[^\n]*\n|#[^\n]*\Z|\n)*') +def _p_ews(s): + s.expect_re(_ews_re) + +_ws_re = re.compile(r'[ \t]*') +def _p_ws(s): + s.expect_re(_ws_re) + +_escapes = { 'b': '\b', 'n': '\n', 'r': '\r', 't': '\t', '"': '"', '\'': '\'', + '\\': '\\', '/': '/', 'f': '\f' } + +_basicstr_re = re.compile(r'[^"\\\000-\037]*') +_short_uni_re = re.compile(r'u([0-9a-fA-F]{4})') +_long_uni_re = re.compile(r'U([0-9a-fA-F]{8})') +_escapes_re = re.compile('[bnrt"\'\\\\/f]') +_newline_esc_re = re.compile('\n[ \t\n]*') +def _p_basicstr_content(s, content=_basicstr_re): + res = [] + while True: + res.append(s.expect_re(content).group(0)) + if not s.consume('\\'): + break + if s.consume_re(_newline_esc_re): + pass + elif s.consume_re(_short_uni_re) or s.consume_re(_long_uni_re): + res.append(_chr(int(s.last().group(1), 16))) + else: + s.expect_re(_escapes_re) + res.append(_escapes[s.last().group(0)]) + return ''.join(res) + +_key_re = re.compile(r'[0-9a-zA-Z-_]+') +def _p_key(s): + with s: + s.expect('"') + r = _p_basicstr_content(s, _basicstr_re) + s.expect('"') + return r + if s.consume('\''): + if s.consume('\'\''): + r = s.expect_re(_litstr_ml_re).group(0) + s.expect('\'\'\'') + else: + r = s.expect_re(_litstr_re).group(0) + s.expect('\'') + return r + return s.expect_re(_key_re).group(0) + +_float_re = re.compile(r'[+-]?(?:0|[1-9](?:_?\d)*)(?:\.\d(?:_?\d)*)?(?:[eE][+-]?(?:\d(?:_?\d)*))?') +_datetime_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))') + +_basicstr_ml_re = re.compile(r'(?:(?:|"|"")[^"\\\000-\011\013-\037])*') +_litstr_re = re.compile(r"[^'\000-\037]*") +_litstr_ml_re = re.compile(r"(?:(?:|'|'')(?:[^'\000-\011\013-\037]))*") +def _p_value(s): + pos = s.pos() + + if s.consume('true'): + return 'bool', s.last(), True, pos + if s.consume('false'): + return 'bool', s.last(), False, pos + + if s.consume('"'): + if s.consume('""'): + r = _p_basicstr_content(s, _basicstr_ml_re) + s.expect('"""') + else: + r = _p_basicstr_content(s, _basicstr_re) + s.expect('"') + return 'str', r, r, pos + + if s.consume('\''): + if s.consume('\'\''): + r = s.expect_re(_litstr_ml_re).group(0) + s.expect('\'\'\'') + else: + r = s.expect_re(_litstr_re).group(0) + s.expect('\'') + return 'str', r, r, pos + + if s.consume_re(_datetime_re): + m = s.last() + s0 = m.group(0) + r = map(int, m.groups()[:6]) + if m.group(7): + micro = float(m.group(7)) + else: + micro = 0 + + if m.group(8): + g = int(m.group(8), 10) * 60 + int(m.group(9), 10) + tz = _TimeZone(datetime.timedelta(0, g * 60)) + else: + tz = _TimeZone(datetime.timedelta(0, 0)) + + y, m, d, H, M, S = r + dt = datetime.datetime(y, m, d, H, M, S, int(micro * 1000000), tz) + return 'datetime', s0, dt, pos + + if s.consume_re(_float_re): + m = s.last().group(0) + r = m.replace('_','') + if '.' in m or 'e' in m or 'E' in m: + return 'float', m, float(r), pos + else: + return 'int', m, int(r, 10), pos + + if s.consume('['): + items = [] + with s: + while True: + _p_ews(s) + items.append(_p_value(s)) + s.commit() + _p_ews(s) + s.expect(',') + s.commit() + _p_ews(s) + s.expect(']') + return 'array', None, items, pos + + if s.consume('{'): + _p_ws(s) + items = {} + if not s.consume('}'): + k = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + items[k] = _p_value(s) + _p_ws(s) + while s.consume(','): + _p_ws(s) + k = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + items[k] = _p_value(s) + _p_ws(s) + s.expect('}') + return 'table', None, items, pos + + s.fail() + +def _p_stmt(s): + pos = s.pos() + if s.consume( '['): + is_array = s.consume('[') + _p_ws(s) + keys = [_p_key(s)] + _p_ws(s) + while s.consume('.'): + _p_ws(s) + keys.append(_p_key(s)) + _p_ws(s) + s.expect(']') + if is_array: + s.expect(']') + return 'table_array' if is_array else 'table', keys, pos + + key = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + value = _p_value(s) + return 'kv', (key, value), pos + +_stmtsep_re = re.compile(r'(?:[ \t]*(?:#[^\n]*)?\n)+[ \t]*') +def _p_toml(s): + stmts = [] + _p_ews(s) + with s: + stmts.append(_p_stmt(s)) + while True: + s.commit() + s.expect_re(_stmtsep_re) + stmts.append(_p_stmt(s)) + _p_ews(s) + s.expect_eof() + return stmts + +class _TimeZone(datetime.tzinfo): + def __init__(self, offset): + self._offset = offset + + def utcoffset(self, dt): + return self._offset + + def dst(self, dt): + return None + + def tzname(self, dt): + m = self._offset.total_seconds() // 60 + if m < 0: + res = '-' + m = -m + else: + res = '+' + h = m // 60 + m = m - h * 60 + return '{}{:.02}{:.02}'.format(res, h, m) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py new file mode 100755 index 0000000..19a8c6e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py @@ -0,0 +1,127 @@ +from __future__ import unicode_literals +import io, datetime, math, sys + +if sys.version_info[0] == 3: + long = int + unicode = str + + +def dumps(obj, sort_keys=False): + fout = io.StringIO() + dump(obj, fout, sort_keys=sort_keys) + return fout.getvalue() + + +_escapes = {'\n': 'n', '\r': 'r', '\\': '\\', '\t': 't', '\b': 'b', '\f': 'f', '"': '"'} + + +def _escape_string(s): + res = [] + start = 0 + + def flush(): + if start != i: + res.append(s[start:i]) + return i + 1 + + i = 0 + while i < len(s): + c = s[i] + if c in '"\\\n\r\t\b\f': + start = flush() + res.append('\\' + _escapes[c]) + elif ord(c) < 0x20: + start = flush() + res.append('\\u%04x' % ord(c)) + i += 1 + + flush() + return '"' + ''.join(res) + '"' + + +def _escape_id(s): + if any(not c.isalnum() and c not in '-_' for c in s): + return _escape_string(s) + return s + + +def _format_list(v): + return '[{0}]'.format(', '.join(_format_value(obj) for obj in v)) + +# Formula from: +# https://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds +# Once support for py26 is dropped, this can be replaced by td.total_seconds() +def _total_seconds(td): + return ((td.microseconds + + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.0**6) + +def _format_value(v): + if isinstance(v, bool): + return 'true' if v else 'false' + if isinstance(v, int) or isinstance(v, long): + return unicode(v) + if isinstance(v, float): + if math.isnan(v) or math.isinf(v): + raise ValueError("{0} is not a valid TOML value".format(v)) + else: + return repr(v) + elif isinstance(v, unicode) or isinstance(v, bytes): + return _escape_string(v) + elif isinstance(v, datetime.datetime): + offs = v.utcoffset() + offs = _total_seconds(offs) // 60 if offs is not None else 0 + + if offs == 0: + suffix = 'Z' + else: + if offs > 0: + suffix = '+' + else: + suffix = '-' + offs = -offs + suffix = '{0}{1:.02}{2:.02}'.format(suffix, offs // 60, offs % 60) + + if v.microsecond: + return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix + else: + return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix + elif isinstance(v, list): + return _format_list(v) + else: + raise RuntimeError(v) + + +def dump(obj, fout, sort_keys=False): + tables = [((), obj, False)] + + while tables: + name, table, is_array = tables.pop() + if name: + section_name = '.'.join(_escape_id(c) for c in name) + if is_array: + fout.write('[[{0}]]\n'.format(section_name)) + else: + fout.write('[{0}]\n'.format(section_name)) + + table_keys = sorted(table.keys()) if sort_keys else table.keys() + new_tables = [] + has_kv = False + for k in table_keys: + v = table[k] + if isinstance(v, dict): + new_tables.append((name + (k,), v, False)) + elif isinstance(v, list) and v and all(isinstance(o, dict) for o in v): + new_tables.extend((name + (k,), d, True) for d in v) + elif v is None: + # based on mojombo's comment: https://github.com/toml-lang/toml/issues/146#issuecomment-25019344 + fout.write( + '#{} = null # To use: uncomment and replace null with value\n'.format(_escape_id(k))) + has_kv = True + else: + fout.write('{0} = {1}\n'.format(_escape_id(k), _format_value(v))) + has_kv = True + + tables.extend(reversed(new_tables)) + + if (name or has_kv) and tables: + fout.write('\n') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py new file mode 100755 index 0000000..f9565cb --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py @@ -0,0 +1,123 @@ +# -*- 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 + >>> 'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('http://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key2": "value2", + "key1": "value1" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at <http://python-requests.org>. + +:copyright: (c) 2017 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +from pip._vendor import urllib3 +from pip._vendor import chardet +import warnings +from .exceptions import RequestsDependencyWarning + + +def check_compatibility(urllib3_version, chardet_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.22 + assert major == 1 + assert minor >= 21 + assert minor <= 22 + + # Check chardet for compatibility. + major, minor, patch = chardet_version.split('.')[:3] + major, minor, patch = int(major), int(minor), int(patch) + # chardet >= 3.0.2, < 3.1.0 + assert major == 3 + assert minor < 1 + assert patch >= 2 + + +# Check imported dependencies for compatibility. +try: + check_compatibility(urllib3.__version__, chardet.__version__) +except (AssertionError, ValueError): + warnings.warn("urllib3 ({0}) or chardet ({1}) doesn't match a supported " + "version!".format(urllib3.__version__, chardet.__version__), + RequestsDependencyWarning) + +# Attempt to enable urllib3's SNI support, if possible +from pip._internal.compat import WINDOWS +if not WINDOWS: + try: + from pip._vendor.urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() + except ImportError: + pass + +# urllib3's DependencyWarnings should be silenced. +from pip._vendor.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 +) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py new file mode 100755 index 0000000..d380286 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py @@ -0,0 +1,14 @@ +# .-. .-. .-. . . .-. .-. .-. .-. +# |( |- |.| | | |- `-. | `-. +# ' ' `-' `-`.`-' `-' `-' ' `-' + +__title__ = 'requests' +__description__ = 'Python HTTP for Humans.' +__url__ = 'http://python-requests.org' +__version__ = '2.18.4' +__build__ = 0x021804 +__author__ = 'Kenneth Reitz' +__author_email__ = 'me@kennethreitz.org' +__license__ = 'Apache 2.0' +__copyright__ = 'Copyright 2017 Kenneth Reitz' +__cake__ = u'\u2728 \U0001f370 \u2728' diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/_internal_utils.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/_internal_utils.py new file mode 100755 index 0000000..405b025 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py new file mode 100755 index 0000000..c50585c --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py @@ -0,0 +1,525 @@ +# -*- 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 pip._vendor.urllib3.poolmanager import PoolManager, proxy_from_url +from pip._vendor.urllib3.response import HTTPResponse +from pip._vendor.urllib3.util import Timeout as TimeoutSauce +from pip._vendor.urllib3.util.retry import Retry +from pip._vendor.urllib3.exceptions import ClosedPoolError +from pip._vendor.urllib3.exceptions import ConnectTimeoutError +from pip._vendor.urllib3.exceptions import HTTPError as _HTTPError +from pip._vendor.urllib3.exceptions import MaxRetryError +from pip._vendor.urllib3.exceptions import NewConnectionError +from pip._vendor.urllib3.exceptions import ProxyError as _ProxyError +from pip._vendor.urllib3.exceptions import ProtocolError +from pip._vendor.urllib3.exceptions import ReadTimeoutError +from pip._vendor.urllib3.exceptions import SSLError as _SSLError +from pip._vendor.urllib3.exceptions import ResponseError + +from .models import Response +from .compat import urlparse, basestring +from .utils import (DEFAULT_CA_BUNDLE_PATH, 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) +from .auth import _basic_auth_str + +try: + from pip._vendor.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 <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) <timeouts>` 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 <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 dict((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 <requests.adapters.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 <requests.adapters.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 <requests.adapters.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 = 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: {0}".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: {0}".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: {0}".format(conn.key_file)) + + def build_response(self, req, resp): + """Builds a :class:`Response <requests.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 <requests.adapters.HTTPAdapter>` + + :param req: The :class:`PreparedRequest <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 <requests.adapters.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_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 <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <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 <requests.adapters.HTTPAdapter>`. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <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 <requests.adapters.HTTPAdapter>`. + + :param proxies: 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 <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) <timeouts>` 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 + """ + + conn = self.get_connection(request.url, proxies) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers(request) + + 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 {0}. 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: + low_conn.putrequest(request.method, + url, + skip_accept_encoding=True) + + 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+ versions, use buffering of HTTP + # responses + r = low_conn.getresponse(buffering=True) + except TypeError: + # For compatibility with Python 2.6 versions and back + 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) + else: + raise + + return self.build_response(request, resp) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py new file mode 100755 index 0000000..f9ffabf --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py @@ -0,0 +1,152 @@ +# -*- 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 <Request>`. + + :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 or list of tuples ``[(key, value)]`` (will be form-encoded), 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 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) <timeouts>` 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 <Response>` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'http://httpbin.org/get') + <Response [200]> + """ + + # 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 or bytes to be sent in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + 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 <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + 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. + :return: :class:`Response <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 (will be form-encoded), 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 <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 (will be form-encoded), 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 <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 (will be form-encoded), 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 <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 <Response>` object + :rtype: requests.Response + """ + + return request('delete', url, **kwargs) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py new file mode 100755 index 0000000..73e4534 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py @@ -0,0 +1,293 @@ +# -*- 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 ({0!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 ({0!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(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 + + 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/requests/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/certs.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/certs.py new file mode 100755 index 0000000..9742f6e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 pip._vendor.certifi import where + +if __name__ == '__main__': + print(where()) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py new file mode 100755 index 0000000..4cea25e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module handles import compatibility issues between Python 2 and +Python 3. +""" + +from pip._vendor import 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) + +# Note: We've patched out simplejson support in pip because it prevents +# upgrading simplejson on Windows. +# try: +# import simplejson as json +# except (ImportError, SyntaxError): +# # simplejson does not support Python 3.2, it throws a SyntaxError +# # because of u'...' Unicode literals. +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 + + from pip._vendor.urllib3.packages.ordered_dict import OrderedDict + + builtin_str = str + bytes = str + str = unicode + basestring = basestring + numeric_types = (int, long, float) + integer_types = (int, long) + +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 + from collections import OrderedDict + + builtin_str = str + str = str + bytes = bytes + basestring = (str, bytes) + numeric_types = (int, float) + integer_types = (int,) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py new file mode 100755 index 0000000..e69d22e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py @@ -0,0 +1,542 @@ +# -*- 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 +import collections + +from ._internal_utils import to_native_string +from .compat import cookielib, urlparse, urlunparse, Morsel + +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, collections.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.update(self) + return new_cj + + +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 = dict( + 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. + """ + 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. + """ + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py new file mode 100755 index 0000000..377c4c2 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from pip._vendor.urllib3.exceptions import HTTPError as BaseHTTPError + + +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 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 schema (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """See defaults.py for valid schemas.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow 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.""" + pass + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + pass + + +class RequestsDependencyWarning(RequestsWarning): + """An imported dependency doesn't match the expected version range.""" + pass diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py new file mode 100755 index 0000000..28385f8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py @@ -0,0 +1,120 @@ +"""Module containing bug report helper(s).""" +from __future__ import print_function + +import json +import platform +import sys +import ssl + +from pip._vendor import idna +from pip._vendor import urllib3 +from pip._vendor import chardet + +from . import __version__ as requests_version + +try: + from .packages.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__} + 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__', ''), + } + + # OPENSSL_VERSION_NUMBER doesn't exist in the Python 2.6 ssl module. + system_ssl = getattr(ssl, 'OPENSSL_VERSION_NUMBER', None) + 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, + 'pyOpenSSL': pyopenssl_info, + 'urllib3': urllib3_info, + 'chardet': chardet_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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/hooks.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/hooks.py new file mode 100755 index 0000000..14db0c8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 dict((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 dict() + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py new file mode 100755 index 0000000..6f5b0fb --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py @@ -0,0 +1,948 @@ +# -*- coding: utf-8 -*- + +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import collections +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/requests/requests/issues/3578. +import encodings.idna + +from pip._vendor.urllib3.fields import RequestField +from pip._vendor.urllib3.filepost import encode_multipart_formdata +from pip._vendor.urllib3.util import parse_url +from pip._vendor.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) +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 ( + cookielib, urlunparse, urlsplit, urlencode, str, bytes, + is_py2, chardet, builtin_str, basestring) +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 + else: + fdata = fp.read() + + 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, collections.Callable): + self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if isinstance(h, collections.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 <Request>` object. + + Used to prepare a :class:`PreparedRequest <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 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: dictionary of URL parameters to append to the URL. + :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', 'http://httpbin.org/get') + >>> req.prepare() + <PreparedRequest [GET]> + """ + + 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 '<Request [%s]>' % (self.method) + + def prepare(self): + """Constructs a :class:`PreparedRequest <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 <PreparedRequest>` object, + containing the exact bytes that will be sent to the server. + + Generated from either a :class:`Request <Request>` object or manually. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'http://httpbin.org/get') + >>> r = req.prepare() + <PreparedRequest [GET]> + + >>> s = requests.Session() + >>> s.send(r) + <Response [200]> + """ + + 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 '<PreparedRequest [%s]>' % (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): + from pip._vendor 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/requests/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 schema 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'*'): + 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' + body = complexjson.dumps(json) + if not isinstance(body, bytes): + body = body.encode('utf-8') + + is_stream = all([ + hasattr(data, '__iter__'), + not isinstance(data, (basestring, list, tuple, collections.Mapping)) + ]) + + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + if is_stream: + 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 <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 <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 <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 <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 dict( + (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 '<Response [%s]>' % (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. + + 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 chardet library.""" + 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=None, 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 = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes() + + 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 + ``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 ValueError: 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 chardet 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 + return complexjson.loads(self.text, **kwargs) + + @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 stored :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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py new file mode 100755 index 0000000..c91d9c7 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py @@ -0,0 +1,16 @@ +import sys + +# This code exists for backwards compatibility reasons. +# I don't like it either. Just look the other way. :) + +for package in ('urllib3', 'idna', 'chardet'): + vendored_package = "pip._vendor." + package + locals()[package] = __import__(vendored_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 == vendored_package or mod.startswith(vendored_package + '.'): + unprefixed_mod = mod[len("pip._vendor."):] + sys.modules['pip._vendor.requests.packages.' + unprefixed_mod] = sys.modules[mod] + +# Kinda cool, though, right? diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py new file mode 100755 index 0000000..d8eafa8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py @@ -0,0 +1,737 @@ +# -*- coding: utf-8 -*- + +""" +requests.session +~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +import platform +import time +from collections import Mapping +from datetime import timedelta + +from .auth import _basic_auth_str +from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse +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 +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 +) + +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 platform.system() == 'Windows': + try: # Python 3.3+ + 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 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) + 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 %s redirects.' % 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 = '%s:%s' % (to_native_string(parsed_rurl.scheme), url) + + # The scheme should be lower case... + parsed = urlparse(url) + 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/requests/requests/issues/1084 + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + # https://github.com/requests/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 + try: + del headers['Cookie'] + except KeyError: + pass + + # 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: + # If we get redirected to a new host, we should strip out any + # authentication headers. + original_parsed = urlparse(response.request.url) + redirect_parsed = urlparse(url) + + if (original_parsed.hostname != redirect_parsed.hostname): + 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) + + return + + 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 + """ + proxies = proxies if proxies is not None else {} + headers = prepared_request.headers + url = prepared_request.url + scheme = urlparse(url).scheme + new_proxies = proxies.copy() + no_proxy = proxies.get('no_proxy') + + bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy) + if self.trust_env and not bypass_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) + + 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 + + # http://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('http://httpbin.org/get') + <Response [200]> + + Or as a context manager:: + + >>> with requests.Session() as s: + >>> s.get('http://httpbin.org/get') + <Response [200]> + """ + + __attrs__ = [ + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', + 'cert', 'prefetch', 'adapters', 'stream', 'trust_env', + 'max_redirects', + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request <Request>` sent from this + #: :class:`Session <Session>`. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request <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 <Request>`. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request <Request>`. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + 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 <requests.cookies.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 <PreparedRequest>` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request <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 <Request>`, prepares it and sends it. + Returns :class:`Response <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, 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) <timeouts>` 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``. + :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, 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, 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, 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) + kwargs.setdefault('proxies', self.proxies) + + # 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) + + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + + # Resolve redirects if allowed. + history = [resp for resp in gen] if allow_redirects else [] + + # 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): + return adapter + + # Nothing matches :-/ + raise InvalidSchema("No connection adapters were found for '%s'" % 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 = dict((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. + + :rtype: Session + """ + + return Session() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py new file mode 100755 index 0000000..85d9bbc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +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') + +for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith(('\\', '/')): + setattr(codes, title.upper(), code) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py new file mode 100755 index 0000000..ce775ba --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +import collections + +from .compat import OrderedDict + + +class CaseInsensitiveDict(collections.MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``collections.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, collections.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 '<lookup \'%s\'>' % (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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py new file mode 100755 index 0000000..fc4f894 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py @@ -0,0 +1,904 @@ +# -*- coding: utf-8 -*- + +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import cgi +import codecs +import collections +import contextlib +import io +import os +import platform +import re +import socket +import struct +import warnings + +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, OrderedDict, unquote, getproxies, + proxy_bypass, urlunparse, basestring, integer_types, is_py3, + proxy_bypass_environment, getproxies_environment) +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() + + +if platform.system() == 'Windows': + # provide a proxy_bypass version on Windows without DNS lookups + + def proxy_bypass_registry(host): + if is_py3: + import winreg + else: + import _winreg as winreg + try: + internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + proxyEnable = winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0] + 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 + # '<local>' 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 == '<local>': + 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: + 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 useable 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.""" + + try: + from netrc import netrc, NetrcParseError + + netrc_path = None + + for f in NETRC_FILES: + try: + loc = os.path.expanduser('~/{0}'.format(f)) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See http://bugs.python.org/issue20164 & + # https://github.com/requests/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 + + # AppEngine 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 from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + ValueError: need more than 1 value to unpack + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :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') + 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, collections.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'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I) + pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return (charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content)) + + +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 = cgi.parse_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + if 'text' in content_type: + return 'ISO-8859-1' + + +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 + """ + 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') + netloc = urlparse(url).netloc + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the netloc, both with and without the port. + no_proxy = ( + host for host in no_proxy.replace(' ', '').split(',') if host + ) + + ip = netloc.split(':')[0] + if is_ipv4_address(ip): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(ip, proxy_ip): + return True + elif ip == 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: + for host in no_proxy: + if netloc.endswith(host) or netloc.split(':')[0].endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + # If the system proxy settings indicate that this URL should be bypassed, + # don't proxy. + # The proxy_bypass function is incredibly buggy on OS X in early versions + # of Python 2.6, so allow this call to fail. Only catch the specific + # exceptions we've seen, though: this call failing in other ways can reveal + # legitimate problems. + with set_environ('no_proxy', no_proxy_arg): + try: + bypass = proxy_bypass(netloc) + 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 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': ', '.join(('gzip', 'deflate')), + 'Accept': '*/*', + 'Connection': 'keep-alive', + }) + + +def parse_header_links(value): + """Return a dict of parsed link headers proxies. + + i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = ' \'"' + + 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 + """ + scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme) + + # urlparse is a finicky beast, and sometimes decides that there isn't a + # netloc present. Assume that it's being over-cautious, and switch netloc + # and path if urlparse decided there was no netloc. + if not netloc: + netloc, path = path, netloc + + return urlunparse((scheme, netloc, path, params, 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py new file mode 100755 index 0000000..f8d743b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py @@ -0,0 +1,267 @@ +## Copyright 2013-2014 Ray Holder +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. + +import random +from pip._vendor import six +import sys +import time +import traceback + + +# sys.maxint / 2, since Python 3.2 doesn't have a sys.maxint... +MAX_WAIT = 1073741823 + + +def retry(*dargs, **dkw): + """ + Decorator function that instantiates the Retrying object + @param *dargs: positional arguments passed to Retrying object + @param **dkw: keyword arguments passed to the Retrying object + """ + # support both @retry and @retry() as valid syntax + if len(dargs) == 1 and callable(dargs[0]): + def wrap_simple(f): + + @six.wraps(f) + def wrapped_f(*args, **kw): + return Retrying().call(f, *args, **kw) + + return wrapped_f + + return wrap_simple(dargs[0]) + + else: + def wrap(f): + + @six.wraps(f) + def wrapped_f(*args, **kw): + return Retrying(*dargs, **dkw).call(f, *args, **kw) + + return wrapped_f + + return wrap + + +class Retrying(object): + + def __init__(self, + stop=None, wait=None, + stop_max_attempt_number=None, + stop_max_delay=None, + wait_fixed=None, + wait_random_min=None, wait_random_max=None, + wait_incrementing_start=None, wait_incrementing_increment=None, + wait_exponential_multiplier=None, wait_exponential_max=None, + retry_on_exception=None, + retry_on_result=None, + wrap_exception=False, + stop_func=None, + wait_func=None, + wait_jitter_max=None): + + self._stop_max_attempt_number = 5 if stop_max_attempt_number is None else stop_max_attempt_number + self._stop_max_delay = 100 if stop_max_delay is None else stop_max_delay + self._wait_fixed = 1000 if wait_fixed is None else wait_fixed + self._wait_random_min = 0 if wait_random_min is None else wait_random_min + self._wait_random_max = 1000 if wait_random_max is None else wait_random_max + self._wait_incrementing_start = 0 if wait_incrementing_start is None else wait_incrementing_start + self._wait_incrementing_increment = 100 if wait_incrementing_increment is None else wait_incrementing_increment + self._wait_exponential_multiplier = 1 if wait_exponential_multiplier is None else wait_exponential_multiplier + self._wait_exponential_max = MAX_WAIT if wait_exponential_max is None else wait_exponential_max + self._wait_jitter_max = 0 if wait_jitter_max is None else wait_jitter_max + + # TODO add chaining of stop behaviors + # stop behavior + stop_funcs = [] + if stop_max_attempt_number is not None: + stop_funcs.append(self.stop_after_attempt) + + if stop_max_delay is not None: + stop_funcs.append(self.stop_after_delay) + + if stop_func is not None: + self.stop = stop_func + + elif stop is None: + self.stop = lambda attempts, delay: any(f(attempts, delay) for f in stop_funcs) + + else: + self.stop = getattr(self, stop) + + # TODO add chaining of wait behaviors + # wait behavior + wait_funcs = [lambda *args, **kwargs: 0] + if wait_fixed is not None: + wait_funcs.append(self.fixed_sleep) + + if wait_random_min is not None or wait_random_max is not None: + wait_funcs.append(self.random_sleep) + + if wait_incrementing_start is not None or wait_incrementing_increment is not None: + wait_funcs.append(self.incrementing_sleep) + + if wait_exponential_multiplier is not None or wait_exponential_max is not None: + wait_funcs.append(self.exponential_sleep) + + if wait_func is not None: + self.wait = wait_func + + elif wait is None: + self.wait = lambda attempts, delay: max(f(attempts, delay) for f in wait_funcs) + + else: + self.wait = getattr(self, wait) + + # retry on exception filter + if retry_on_exception is None: + self._retry_on_exception = self.always_reject + else: + self._retry_on_exception = retry_on_exception + + # TODO simplify retrying by Exception types + # retry on result filter + if retry_on_result is None: + self._retry_on_result = self.never_reject + else: + self._retry_on_result = retry_on_result + + self._wrap_exception = wrap_exception + + def stop_after_attempt(self, previous_attempt_number, delay_since_first_attempt_ms): + """Stop after the previous attempt >= stop_max_attempt_number.""" + return previous_attempt_number >= self._stop_max_attempt_number + + def stop_after_delay(self, previous_attempt_number, delay_since_first_attempt_ms): + """Stop after the time from the first attempt >= stop_max_delay.""" + return delay_since_first_attempt_ms >= self._stop_max_delay + + def no_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Don't sleep at all before retrying.""" + return 0 + + def fixed_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Sleep a fixed amount of time between each retry.""" + return self._wait_fixed + + def random_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Sleep a random amount of time between wait_random_min and wait_random_max""" + return random.randint(self._wait_random_min, self._wait_random_max) + + def incrementing_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """ + Sleep an incremental amount of time after each attempt, starting at + wait_incrementing_start and incrementing by wait_incrementing_increment + """ + result = self._wait_incrementing_start + (self._wait_incrementing_increment * (previous_attempt_number - 1)) + if result < 0: + result = 0 + return result + + def exponential_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + exp = 2 ** previous_attempt_number + result = self._wait_exponential_multiplier * exp + if result > self._wait_exponential_max: + result = self._wait_exponential_max + if result < 0: + result = 0 + return result + + def never_reject(self, result): + return False + + def always_reject(self, result): + return True + + def should_reject(self, attempt): + reject = False + if attempt.has_exception: + reject |= self._retry_on_exception(attempt.value[1]) + else: + reject |= self._retry_on_result(attempt.value) + + return reject + + def call(self, fn, *args, **kwargs): + start_time = int(round(time.time() * 1000)) + attempt_number = 1 + while True: + try: + attempt = Attempt(fn(*args, **kwargs), attempt_number, False) + except: + tb = sys.exc_info() + attempt = Attempt(tb, attempt_number, True) + + if not self.should_reject(attempt): + return attempt.get(self._wrap_exception) + + delay_since_first_attempt_ms = int(round(time.time() * 1000)) - start_time + if self.stop(attempt_number, delay_since_first_attempt_ms): + if not self._wrap_exception and attempt.has_exception: + # get() on an attempt with an exception should cause it to be raised, but raise just in case + raise attempt.get() + else: + raise RetryError(attempt) + else: + sleep = self.wait(attempt_number, delay_since_first_attempt_ms) + if self._wait_jitter_max: + jitter = random.random() * self._wait_jitter_max + sleep = sleep + max(0, jitter) + time.sleep(sleep / 1000.0) + + attempt_number += 1 + + +class Attempt(object): + """ + An Attempt encapsulates a call to a target function that may end as a + normal return value from the function or an Exception depending on what + occurred during the execution. + """ + + def __init__(self, value, attempt_number, has_exception): + self.value = value + self.attempt_number = attempt_number + self.has_exception = has_exception + + def get(self, wrap_exception=False): + """ + Return the return value of this Attempt instance or raise an Exception. + If wrap_exception is true, this Attempt is wrapped inside of a + RetryError before being raised. + """ + if self.has_exception: + if wrap_exception: + raise RetryError(self) + else: + six.reraise(self.value[0], self.value[1], self.value[2]) + else: + return self.value + + def __repr__(self): + if self.has_exception: + return "Attempts: {0}, Error:\n{1}".format(self.attempt_number, "".join(traceback.format_tb(self.value[2]))) + else: + return "Attempts: {0}, Value: {1}".format(self.attempt_number, self.value) + + +class RetryError(Exception): + """ + A RetryError encapsulates the last Attempt instance right before giving up. + """ + + def __init__(self, last_attempt): + self.last_attempt = last_attempt + + def __str__(self): + return "RetryError[{0}]".format(self.last_attempt) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py new file mode 100755 index 0000000..e36380b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py @@ -0,0 +1,891 @@ +# Copyright (c) 2010-2017 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 <benjamin@python.org>" +__version__ = "1.11.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 + + +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 __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 + +_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("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_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 + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +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" +_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) + + +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, 2): + exec_("""def raise_from(value, from_value): + try: + if from_value is None: + raise value + raise value from from_value + finally: + value = None +""") +elif sys.version_info[:2] > (3, 2): + 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): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +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): + return meta(name, 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) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py new file mode 100755 index 0000000..1bffade --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py @@ -0,0 +1,97 @@ +""" +urllib3 - Thread-safe connection pooling and re-using. +""" + +from __future__ import absolute_import +import warnings + +from .connectionpool import ( + HTTPConnectionPool, + HTTPSConnectionPool, + connection_from_url +) + +from . import exceptions +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.url import get_host +from .util.timeout import Timeout +from .util.retry import Retry + + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' +__license__ = 'MIT' +__version__ = '1.22' + +__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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py new file mode 100755 index 0000000..ecbf6b0 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py @@ -0,0 +1,319 @@ +from __future__ import absolute_import +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 + + +try: # Python 2.7+ + from collections import OrderedDict +except ImportError: + from .packages.ordered_dict import OrderedDict +from .packages.six import iterkeys, itervalues, PY3 + + +__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 not PY3: # 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. + headers = [] + + for line in message.headers: + if line.startswith((' ', '\t')): + key, value = headers[-1] + headers[-1] = (key, value + '\r\n' + line.rstrip()) + continue + + key, value = line.split(':', 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py new file mode 100755 index 0000000..67090e3 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py @@ -0,0 +1,373 @@ +from __future__ import absolute_import +import datetime +import logging +import os +import sys +import socket +from socket import error as SocketError, timeout as SocketTimeout +import warnings +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 + +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 + + +from .exceptions import ( + NewConnectionError, + ConnectTimeoutError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .packages.ssl_match_hostname import match_hostname, CertificateError + +from .util.ssl_ import ( + resolve_cert_reqs, + resolve_ssl_version, + assert_fingerprint, + create_urllib3_context, + ssl_wrap_socket +) + + +from .util import connection + +from ._collections import HTTPHeaderDict + +log = logging.getLogger(__name__) + +port_by_scheme = { + 'http': 80, + 'https': 443, +} + +# When updating RECENT_DATE, move it to +# within two years of the current date, and no +# earlier than 6 months ago. +RECENT_DATE = datetime.date(2016, 1, 1) + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + pass + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on httplib.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. + + .. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x + + - ``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:: + + 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 + + def __init__(self, *args, **kw): + if six.PY3: # Python 3 + kw.pop('strict', None) + + # Pre-set source_address in case we have an older Python like 2.6. + self.source_address = kw.get('source_address') + + if sys.version_info < (2, 7): # Python 2.6 + # _HTTPConnection on Python 2.6 will balk at this keyword arg, but + # not newer versions. We can still use it when creating a + # connection though, so we pop it *after* we have saved it as + # self.source_address. + kw.pop('source_address', None) + + #: 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) + + # Superclass also sets self.source_address in Python 2.7+. + _HTTPConnection.__init__(self, *args, **kw) + + 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.host, self.port), self.timeout, **extra_kw) + + except SocketTimeout as e: + 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 _prepare_conn(self, conn): + self.sock = conn + # the _tunnel_host attribute was added in python 2.6.3 (via + # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do + # not have them. + if getattr(self, '_tunnel_host', None): + # 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 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 = HTTPHeaderDict(headers if headers is not None else {}) + skip_accept_encoding = 'accept-encoding' in headers + skip_host = 'host' in headers + self.putrequest( + method, + url, + skip_accept_encoding=skip_accept_encoding, + skip_host=skip_host + ) + for header, value in headers.items(): + self.putheader(header, value) + if 'transfer-encoding' not in headers: + self.putheader('Transfer-Encoding', 'chunked') + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (six.binary_type,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, six.binary_type): + chunk = chunk.encode('utf8') + len_str = hex(len(chunk))[2:] + self.send(len_str.encode('utf-8')) + self.send(b'\r\n') + self.send(chunk) + self.send(b'\r\n') + + # After the if clause, to always have a closed body + self.send(b'0\r\n\r\n') + + +class HTTPSConnection(HTTPConnection): + default_port = port_by_scheme['https'] + + ssl_version = None + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, **kw): + + HTTPConnection.__init__(self, host, port, strict=strict, + timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.ssl_context = ssl_context + + # 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 connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(None), + cert_reqs=resolve_cert_reqs(None), + ) + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ssl_context=self.ssl_context, + ) + + +class VerifiedHTTPSConnection(HTTPSConnection): + """ + Based on httplib.HTTPSConnection but wraps the socket with + SSL certification. + """ + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ssl_version = None + assert_fingerprint = None + + def set_cert(self, key_file=None, cert_file=None, + cert_reqs=None, ca_certs=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided, we can try to guess. If the user gave + # us a cert database, we assume they want to use it: otherwise, if + # they gave us an SSL Context object we should use whatever is set for + # it. + if cert_reqs is None: + if ca_certs or ca_cert_dir: + cert_reqs = 'CERT_REQUIRED' + elif self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + 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) + + def connect(self): + # Add certificate verification + conn = self._new_conn() + + hostname = self.host + if getattr(self, '_tunnel_host', None): + # _tunnel_host was added in Python 2.6.3 + # (See: http://hg.python.org/cpython/rev/0f57b30a152f) + + self.sock = conn + # 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 + + 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 + if self.ssl_context is None: + 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) + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + server_hostname=hostname, + ssl_context=context) + + 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/shazow/urllib3/issues/497 ' + 'for details.)'.format(hostname)), + SubjectAltNameWarning + ) + _match_hostname(cert, self.assert_hostname or hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED or + self.assert_fingerprint is not None + ) + + +def _match_hostname(cert, asserted_hostname): + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.error( + '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 + + +if ssl: + # Make a copy for testing. + UnverifiedHTTPSConnection = HTTPSConnection + HTTPSConnection = VerifiedHTTPSConnection +else: + HTTPSConnection = DummyConnection diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py new file mode 100755 index 0000000..b099ca8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py @@ -0,0 +1,905 @@ +from __future__ import absolute_import +import errno +import logging +import sys +import warnings + +from socket import error as SocketError, timeout as SocketTimeout +import socket + + +from .exceptions import ( + ClosedPoolError, + ProtocolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + LocationValueError, + MaxRetryError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, + InsecureRequestWarning, + NewConnectionError, +) +from .packages.ssl_match_hostname import CertificateError +from .packages import six +from .packages.six.moves import queue +from .connection import ( + port_by_scheme, + DummyConnection, + HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, + HTTPException, BaseSSLError, +) +from .request import RequestMethods +from .response import HTTPResponse + +from .util.connection import is_connection_dropped +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host, Url + + +if six.PY2: + # Queue is imported for side effects on MS Windows + import Queue as _unused_module_Queue # noqa: F401 + +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`. + """ + + scheme = None + QueueCls = queue.LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _ipv6_host(host).lower() + 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 = set([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:`httplib.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`httplib.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:`httplib.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.connectionpool.ProxyManager`" + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.connectionpool.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, + **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 {} + + # 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', []) + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTP connection (%d): %s", + self.num_connections, self.host) + + 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 + # httplib._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", + self.host) + + # 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.6 + 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 httplib.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # 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 2.6 and older, Python 3 + try: + httplib_response = conn.getresponse() + except Exception as e: + # Remove the TypeError from the exception chain in Python 3; + # otherwise it looks like a programming error was the cause. + 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. + """ + # 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) + + host = _ipv6_host(host).lower() + + # 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 body: + Data to send in the request body (useful for creating + POST requests, see HTTPConnectionPool.post_url for + more convenience). + + :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` + """ + 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) + + 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] <https://github.com/shazow/urllib3/issues/651> + release_this_conn = release_conn + + # Merge the proxy headers. Only do this in HTTP. We have to copy the + # headers dict so we can safely change it without those changes being + # reflected in anyone else's copy. + if self.scheme == 'http': + 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: + 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 queue.Empty: + # Timed out by queue. + raise EmptyPoolError(self, "No pool connections are available.") + + 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 + if 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, body_pos=body_pos, + **response_kw) + + def drain_and_release_conn(response): + try: + # discard any remaining response body, the connection will be + # released back to the pool once the entire response is read + response.read() + except (TimeoutError, HTTPException, SocketError, ProtocolError, + BaseSSLError, SSLError) as e: + pass + + # 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: + # Drain and release the connection for this response, since + # we're not returning it to be released manually. + drain_and_release_conn(response) + raise + return response + + # drain and return the connection to the pool before recursing + drain_and_release_conn(response) + + 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, 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: + # Drain and release the connection for this response, since + # we're not returning it to be released manually. + drain_and_release_conn(response) + raise + return response + + # drain and return the connection to the pool before recursing + drain_and_release_conn(response) + + 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, + body_pos=body_pos, **response_kw) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + When Python is compiled with the :mod:`ssl` module, then + :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, + instead of :class:`.HTTPSConnection`. + + :class:`.VerifiedHTTPSConnection` 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``, and ``ssl_version`` 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, + 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) + + if ca_certs and cert_reqs is None: + cert_reqs = 'CERT_REQUIRED' + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + 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, + 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): + """ + Establish tunnel connection early, because otherwise httplib + would improperly set Host: header to proxy's IP:port. + """ + # Python 2.7+ + try: + set_tunnel = conn.set_tunnel + except AttributeError: # Platform-specific: Python 2.6 + set_tunnel = conn._set_tunnel + + if sys.version_info <= (2, 6, 4) and not self.proxy_headers: # Python 2.6.4 and older + set_tunnel(self._proxy_host, self.port) + else: + set_tunnel(self._proxy_host, self.port, self.proxy_headers) + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTPS connection (%d): %s", + self.num_connections, self.host) + + 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, **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. ' + 'Adding certificate verification is strongly advised. See: ' + 'https://urllib3.readthedocs.io/en/latest/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 _ipv6_host(host): + """ + Process IPv6 address literals + """ + + # 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 + # + # Also if an IPv6 address literal has a zone identifier, the + # percent sign might be URIencoded, convert it back into ASCII + if host.startswith('[') and host.endswith(']'): + host = host.replace('%25', '%').strip('[]') + return host diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py new file mode 100755 index 0000000..9787b02 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py @@ -0,0 +1,593 @@ +""" +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 <will@wbond.net> + + 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.util import find_library +from ctypes import ( + c_void_p, c_int32, c_char_p, c_size_t, c_byte, c_uint32, c_ulong, c_long, + c_bool +) +from ctypes import CDLL, POINTER, CFUNCTYPE + + +security_path = find_library('Security') +if not security_path: + raise ImportError('The library Security could not be found') + + +core_foundation_path = find_library('CoreFoundation') +if not core_foundation_path: + raise ImportError('The library CoreFoundation could not be found') + + +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] + ) + ) + +Security = CDLL(security_path, use_errno=True) +CoreFoundation = CDLL(core_foundation_path, use_errno=True) + +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 + + 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 + + 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. + 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_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2 + 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_DSS_WITH_AES_256_CBC_SHA256 = 0x006A + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038 + 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_DSS_WITH_AES_128_CBC_SHA256 = 0x0040 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032 + 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_CHACHA20_POLY1305_SHA256 = 0x1303 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py new file mode 100755 index 0000000..4e5c0db --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py @@ -0,0 +1,343 @@ +""" +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 re +import os +import ssl +import tempfile + +from .bindings import Security, CoreFoundation, CFConst + + +# 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 _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. + """ + 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) + + 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.b64encode(random_bytes[:8]).decode('utf-8') + password = base64.b64encode(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) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py new file mode 100755 index 0000000..fc00d17 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py @@ -0,0 +1,296 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + +Example usage:: + + from pip._vendor.urllib3 import PoolManager + from pip._vendor.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 <https://cloud.google.com/appengine/docs/python/\ +urlfetch/#Python_Quotas_and_limits>`_ 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 + <https://cloud.google.com/appengine/docs/python/sockets/\ + #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 +<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import +import logging +import os +import warnings +from ..packages.six.moves.urllib.parse import urljoin + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + TimeoutError, + SSLError +) + +from ..packages.six import BytesIO +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.timeout import Timeout +from ..util.retry import Retry + +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 + <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + + 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 megabtyes. + * 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.") + + if is_prod_appengine_mvms(): + raise AppEnginePlatformError( + "Use normal urllib3.PoolManager instead of AppEngineManager" + "on Managed VMs, as using URLFetch is not necessary 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/latest/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) + + return HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **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 + + +def is_appengine(): + return (is_local_appengine() or + is_prod_appengine() or + is_prod_appengine_mvms()) + + +def is_appengine_sandbox(): + return is_appengine() and not is_prod_appengine_mvms() + + +def is_local_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Development/' in os.environ['SERVER_SOFTWARE']) + + +def is_prod_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and + not is_prod_appengine_mvms()) + + +def is_prod_appengine_mvms(): + return os.environ.get('GAE_VM', False) == 'true' diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py new file mode 100755 index 0000000..888e0ad --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py @@ -0,0 +1,112 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +from logging import getLogger +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + + +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 = {} + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py new file mode 100755 index 0000000..f13e2bc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py @@ -0,0 +1,455 @@ +""" +SSL with SNI_-support for Python 2. Follow these instructions if you would +like to verify SSL 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: + + 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:: + + 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`_). + +If you want to configure the default list of supported cipher suites, you can +set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +""" +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 + +from socket import timeout, error as SocketError +from io import BytesIO + +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 +from ..packages import six +import sys + +from .. import util + +__all__ = ['inject_into_urllib3', 'extract_from_urllib3'] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_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 + +try: + _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD}) +except AttributeError: + pass + +_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.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.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). + """ + 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. + """ + from pip._vendor import idna + + for prefix in [u'*.', u'.']: + if name.startswith(prefix): + name = name[len(prefix):] + return prefix.encode('ascii') + idna.encode(name) + return idna.encode(name) + + name = idna_encode(name) + if 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, x509.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. + names = [ + ('DNS', _dnsname_to_stdlib(name)) + for name in ext.get_values_for_type(x509.DNSName) + ] + 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 as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b'' + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv(*args, **kwargs) + 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 as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv_into(*args, **kwargs) + + 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: + wr = util.wait_for_write(self.socket, self.socket.gettimeout()) + if not wr: + 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 _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') + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_file(certfile) + if password is not None: + self._ctx.set_passwd_cb(lambda max_length, prompt_twice, userdata: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + 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: + rd = util.wait_for_read(sock, sock.gettimeout()) + if not rd: + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py new file mode 100755 index 0000000..77cf861 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py @@ -0,0 +1,810 @@ +""" +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! +""" +from __future__ import absolute_import + +import contextlib +import ctypes +import errno +import os.path +import shutil +import socket +import ssl +import threading +import weakref + +from .. import util +from ._securetransport.bindings import ( + Security, SecurityConst, CoreFoundation +) +from ._securetransport.low_level import ( + _assert_no_error, _cert_array_from_pem, _temporary_keychain, + _load_client_cert_chain +) + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +try: + memoryview(b'') +except NameError: + raise ImportError("SecureTransport only works on Pythons with memoryview") + +__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 becuase this is how +# SecureTransport wants them. +CIPHER_SUITES = [ + SecurityConst.TLS_AES_256_GCM_SHA384, + SecurityConst.TLS_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_RSA_WITH_AES_128_GCM_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. +_protocol_to_min_max = { + ssl.PROTOCOL_SSLv23: (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 + ) +if hasattr(ssl, "PROTOCOL_TLS"): + _protocol_to_min_max[ssl.PROTOCOL_TLS] = _protocol_to_min_max[ssl.PROTOCOL_SSLv23] + + +def inject_into_urllib3(): + """ + Monkey-patch urllib3 with SecureTransport-backed SSL-support. + """ + 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.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 + buffer = (ctypes.c_char * requested_length).from_address(data_buffer) + buffer_view = memoryview(buffer) + + try: + while read_count < requested_length: + if timeout is None or timeout >= 0: + readables = util.wait_for_read([base_socket], timeout) + if not readables: + raise socket.error(errno.EAGAIN, 'timed out') + + # We need to tell ctypes that we have a buffer that can be + # written to. Upsettingly, we do that like this: + chunk_size = base_socket.recv_into( + buffer_view[read_count:requested_length] + ) + 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: + if error == errno.ECONNRESET: + 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: + writables = util.wait_for_write([base_socket], timeout) + if not writables: + 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: + if error == errno.ECONNRESET: + 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 _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. + """ + # If we disabled cert validation, just say: cool. + if not verify: + return + + # 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 None: + CoreFoundation.CFRelease(cert_array) + + # Ok, now we can look at what the result was. + successes = ( + SecurityConst.kSecTrustResultUnspecified, + SecurityConst.kSecTrustResultProceed + ) + if trust_result.value not in successes: + raise ssl.SSLError( + "certificate verify failed, error code: %d" % + trust_result.value + ) + + def handshake(self, + server_hostname, + verify, + trust_bundle, + min_version, + max_version, + client_cert, + client_key, + client_key_passphrase): + """ + 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() + + # 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 _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 + + @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" + ) + + 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 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 + ) + return wrapped_socket diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py new file mode 100755 index 0000000..6c99a75 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) 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: + +- SOCKS4 +- SOCKS4a +- SOCKS5 +- Usernames and passwords for the SOCKS proxy + +Known Limitations: + +- Currently PySocks does not support contacting remote websites via literal + IPv6 addresses. Any such connection attempt will fail. You must use a domain + name. +- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any + such connection attempt will fail. +""" +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/latest/contrib.html#socks-proxies' + ), + DependencyWarning + ) + raise + +from socket import error as SocketError, 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 as e: + 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 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py new file mode 100755 index 0000000..670a63e --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py @@ -0,0 +1,246 @@ +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." + pass + + +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 + <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. + """ + 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 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 perfoming 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 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 httplib.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 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 InvalidHeader(HTTPError): + "The header provided was somehow invalid." + pass + + +class ProxySchemeUnknown(AssertionError, ValueError): + "ProxyManager does not support the supplied scheme" + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + message = "Not supported proxy scheme %s" % scheme + super(ProxySchemeUnknown, self).__init__(message) + + +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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py new file mode 100755 index 0000000..8e15621 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +import email.utils +import mimetypes + +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(name, value): + """ + Helper function to format and quote a single header parameter. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows RFC 2231, as + suggested by 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 a unicode string. + """ + if not any(ch in value for ch in '"\\\r\n'): + result = '%s="%s"' % (name, value) + try: + result.encode('ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + if not six.PY3 and isinstance(value, six.text_type): # Python 2: + value = value.encode('utf-8') + value = email.utils.encode_rfc2231(value, 'utf-8') + value = '%s*=%s' % (name, value) + return value + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. + :param headers: + An optional dict-like object of headers to initially use for the field. + """ + def __init__(self, name, data, filename=None, headers=None): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + + @classmethod + def from_tuples(cls, fieldname, value): + """ + 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) + 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. + + :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 format_header_param(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) typles 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 '; '.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('%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('%s: %s' % (header_name, header_value)) + + lines.append('\r\n') + return '\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 'form-data' + self.headers['Content-Disposition'] += '; '.join([ + '', self._render_parts( + (('name', self._name), ('filename', self._filename)) + ) + ]) + self.headers['Content-Type'] = content_type + self.headers['Content-Location'] = content_location diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py new file mode 100755 index 0000000..e53dedc --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import +import codecs + +from uuid import uuid4 +from io import BytesIO + +from .packages import six +from .packages.six import b +from .fields import RequestField + +writer = codecs.lookup('utf-8')[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + return uuid4().hex + + +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:`mimetools.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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py new file mode 100755 index 0000000..324c551 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from . import ssl_match_hostname + +__all__ = ('ssl_match_hostname', ) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py new file mode 100755 index 0000000..00dee0b --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py @@ -0,0 +1,53 @@ +# -*- 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) <= set(["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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py new file mode 100755 index 0000000..62dcb42 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py @@ -0,0 +1,259 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger, released under the MIT License. +# http://code.activestate.com/recipes/576693/ +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py new file mode 100755 index 0000000..7bd9225 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 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. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.10.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 + + +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 __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 + +_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("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("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_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_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("email_mime_base", "email.MIMEBase", "email.mime.base"), + 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("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "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"), +] +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 + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +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" +_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) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +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): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +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): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +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(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + 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) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py new file mode 100755 index 0000000..accb927 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py @@ -0,0 +1,19 @@ +import sys + +try: + # Our match_hostname function is the same as 3.5's, so we only want to + # import the match_hostname function if it's at least that good. + if sys.version_info < (3, 5): + raise ImportError("Fallback to vendored code") + + from ssl import CertificateError, match_hostname +except ImportError: + try: + # Backport of the function from a pypi module + from backports.ssl_match_hostname import CertificateError, match_hostname + except ImportError: + # Our vendored copy + from ._implementation import CertificateError, match_hostname + +# Not needed, but documenting what we provide. +__all__ = ('CertificateError', 'match_hostname') diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py new file mode 100755 index 0000000..7272d86 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py @@ -0,0 +1,157 @@ +"""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 +# backports.ssl_match_hostname to continue to be used all the way back to +# python-2.4. +try: + from pip._vendor 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,): + obj = unicode(obj, encoding='ascii', errors='strict') + 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 ValueError: + # Not an IP address (common case) + host_ip = None + except 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: + 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py new file mode 100755 index 0000000..607ae0f --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py @@ -0,0 +1,440 @@ +from __future__ import absolute_import +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from .connectionpool import port_by_scheme +from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.url import parse_url +from .util.retry import Retry + + +__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') + +# 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_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_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 +) + +#: 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) + + +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 + + 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:`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:`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:`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[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:`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 urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.connectionpool.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) + 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 + + if self.proxy is not None and u.scheme == "http": + 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) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + raise + return response + + kw['retries'] = retries + kw['redirect'] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + 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 contaning 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. + + 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, **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 not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + + connection_pool_kw['_proxy'] = self.proxy + connection_pool_kw['_proxy_headers'] = self.proxy_headers + + 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 u.scheme == "http": + # For proxied HTTPS requests, httplib sets the necessary headers + # on the CONNECT to the proxy. For HTTP, 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py new file mode 100755 index 0000000..9d789d6 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py @@ -0,0 +1,148 @@ +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.connectionpool.HTTPConnectionPool` and + :class:`~urllib3.poolmanager.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 = set(['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 NotImplemented("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() + + 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 + :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :meth:`urllib.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 mimick 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py new file mode 100755 index 0000000..54799ba --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py @@ -0,0 +1,626 @@ +from __future__ import absolute_import +from contextlib import contextmanager +import zlib +import io +import logging +from socket import timeout as SocketTimeout +from socket import error as SocketError + +from ._collections import HTTPHeaderDict +from .exceptions import ( + BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError, + ResponseNotChunked, IncompleteRead, InvalidHeader +) +from .packages.six import string_types as basestring, binary_type, PY3 +from .packages.six.moves import http_client as httplib +from .connection import HTTPException, BaseSSLError +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 = binary_type() + 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 GzipDecoder(object): + + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + return self._obj.decompress(data) + + +def _get_decoder(mode): + if mode == 'gzip': + return GzipDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible to httplib's 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 httplib.HTTPResponse: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, attempts to decode specific content-encoding's based on headers + (like 'gzip' and 'deflate') will be skipped and raw data will be used + instead. + + :param original_response: + When this HTTPResponse wrapper is generated from an httplib.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'] + 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, + retries=None, enforce_content_length=False, request_method=None): + + 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._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + + if body and isinstance(body, (basestring, binary_type)): + 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 + + @property + def data(self): + # For backwords-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 tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``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 and 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 + + elif length is not 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 and content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + try: + if decode_content and self._decoder: + data = self._decoder.decompress(data) + except (IOError, zlib.error) 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 and decode_content: + 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): # Defensive: + # This shouldn't happen but just in case we're missing an edge + # case, let's avoid swallowing SSL errors. + raise + + 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:`httplib.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 + data = None + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) + 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:`httplib.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 PY3: # Python 3 + headers = HTTPHeaderDict(headers.items()) + else: # Python 2 + headers = HTTPHeaderDict.from_httplib(headers) + + # 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 httplib.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() + + @property + def closed(self): + if 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'): + 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 + httplib.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 httplib.IncompleteRead(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 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 httplib.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks.") + + # 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 + + with self._error_catcher(): + 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() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py new file mode 100755 index 0000000..a84b005 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import make_headers +from .response import is_fp_closed +from .ssl_ import ( + SSLContext, + HAS_SNI, + IS_PYOPENSSL, + IS_SECURETRANSPORT, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import ( + current_time, + Timeout, +) + +from .retry import Retry +from .url import ( + get_host, + parse_url, + split_first, + Url, +) +from .wait import ( + wait_for_read, + wait_for_write +) + +__all__ = ( + 'HAS_SNI', + 'IS_PYOPENSSL', + 'IS_SECURETRANSPORT', + 'SSLContext', + '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' +) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py new file mode 100755 index 0000000..31ecd83 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import +import socket +from .wait import wait_for_read +from .selectors import HAS_SELECT, SelectorError + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`httplib.HTTPConnection` object. + + Note: For platforms like AppEngine, this will always return ``False`` to + let the platform handle connection recycling transparently for us. + """ + sock = getattr(conn, 'sock', False) + if sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + + if not HAS_SELECT: + return False + + try: + return bool(wait_for_read(sock, timeout=0.0)) + except SelectorError: + return True + + +# 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:`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() + + 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 + + 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/shazow/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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py new file mode 100755 index 0000000..22882b8 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import +from base64 import b64encode + +from ..packages.six import b, integer_types +from ..exceptions import UnrewindableBodyError + +ACCEPT_ENCODING = 'gzip,deflate' +_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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py new file mode 100755 index 0000000..c2eb49c --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py @@ -0,0 +1,81 @@ +from __future__ import absolute_import +from ..packages.six.moves import http_client as httplib + +from ..exceptions import HeaderParsingError + + +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 headers: Headers to verify. + :type headers: `httplib.HTTPMessage`. + + :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: # Platform-specific: Python 3. + unparsed_data = get_payload() + + 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 conn: + :type conn: :class:`httplib.HTTPResponse` + """ + # 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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py new file mode 100755 index 0000000..2a7e8c1 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py @@ -0,0 +1,401 @@ +from __future__ import absolute_import +import time +import logging +from collections import namedtuple +from itertools import takewhile +import email +import re + +from ..exceptions import ( + ConnectTimeoutError, + MaxRetryError, + ProtocolError, + ReadTimeoutError, + ResponseError, + InvalidHeader, +) +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"]) + + +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. It's a good idea to set this to some sensibly-high value to + account for unexpected edge cases and avoid infinite retry loops. + + 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 iterable method_whitelist: + 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_METHOD_WHITELIST`. + + Set to a ``False`` value to retry on any verb. + + :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 ``method_whitelist`` + 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.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. + + """ + + DEFAULT_METHOD_WHITELIST = frozenset([ + 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) + + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 + + def __init__(self, total=10, connect=None, read=None, redirect=None, status=None, + method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, + backoff_factor=0, raise_on_redirect=True, raise_on_status=True, + history=None, respect_retry_after_header=True): + + self.total = total + self.connect = connect + self.read = read + self.status = status + + 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.method_whitelist = method_whitelist + 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 + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, read=self.read, redirect=self.redirect, status=self.status, + method_whitelist=self.method_whitelist, + 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, + ) + 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.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(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + retry_date = time.mktime(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 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. + """ + 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 on the method whitelist. + """ + if self.method_whitelist and method.upper() not in self.method_whitelist: + return False + + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """ Is this method/status code retryable? (Based on whitelists 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) + 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 + 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 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 a the given method is in the whitelist + 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, + 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) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py new file mode 100755 index 0000000..9f16c66 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py @@ -0,0 +1,581 @@ +# Backport of selectors.py from Python 3.5+ to support Python < 3.4 +# Also has the behavior specified in PEP 475 which is to retry syscalls +# in the case of an EINTR error. This module is required because selectors34 +# does not follow this behavior and instead returns that no dile descriptor +# events have occurred rather than retry the syscall. The decision to drop +# support for select.devpoll is made to maintain 100% test coverage. + +import errno +import math +import select +import socket +import sys +import time +from collections import namedtuple, Mapping + +try: + monotonic = time.monotonic +except (AttributeError, ImportError): # Python 3.3< + monotonic = time.time + +EVENT_READ = (1 << 0) +EVENT_WRITE = (1 << 1) + +HAS_SELECT = True # Variable that shows whether the platform has a selector. +_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. +_DEFAULT_SELECTOR = None + + +class SelectorError(Exception): + def __init__(self, errcode): + super(SelectorError, self).__init__() + self.errno = errcode + + def __repr__(self): + return "<SelectorError errno={0}>".format(self.errno) + + def __str__(self): + return self.__repr__() + + +def _fileobj_to_fd(fileobj): + """ Return a file descriptor from a file object. If + given an integer will simply return that integer back. """ + if isinstance(fileobj, int): + fd = fileobj + else: + try: + fd = int(fileobj.fileno()) + except (AttributeError, TypeError, ValueError): + raise ValueError("Invalid file object: {0!r}".format(fileobj)) + if fd < 0: + raise ValueError("Invalid file descriptor: {0}".format(fd)) + return fd + + +# Determine which function to use to wrap system calls because Python 3.5+ +# already handles the case when system calls are interrupted. +if sys.version_info >= (3, 5): + def _syscall_wrapper(func, _, *args, **kwargs): + """ This is the short-circuit version of the below logic + because in Python 3.5+ all system calls automatically restart + and recalculate their timeouts. """ + try: + return func(*args, **kwargs) + except (OSError, IOError, select.error) as e: + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + raise SelectorError(errcode) +else: + def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): + """ Wrapper function for syscalls that could fail due to EINTR. + All functions should be retried if there is time left in the timeout + in accordance with PEP 475. """ + timeout = kwargs.get("timeout", None) + if timeout is None: + expires = None + recalc_timeout = False + else: + timeout = float(timeout) + if timeout < 0.0: # Timeout less than 0 treated as no timeout. + expires = None + else: + expires = monotonic() + timeout + + args = list(args) + if recalc_timeout and "timeout" not in kwargs: + raise ValueError( + "Timeout must be in args or kwargs to be recalculated") + + result = _SYSCALL_SENTINEL + while result is _SYSCALL_SENTINEL: + try: + result = func(*args, **kwargs) + # OSError is thrown by select.select + # IOError is thrown by select.epoll.poll + # select.error is thrown by select.poll.poll + # Aren't we thankful for Python 3.x rework for exceptions? + except (OSError, IOError, select.error) as e: + # select.error wasn't a subclass of OSError in the past. + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + elif hasattr(e, "args"): + errcode = e.args[0] + + # Also test for the Windows equivalent of EINTR. + is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and + errcode == errno.WSAEINTR)) + + if is_interrupt: + if expires is not None: + current_time = monotonic() + if current_time > expires: + raise OSError(errno=errno.ETIMEDOUT) + if recalc_timeout: + if "timeout" in kwargs: + kwargs["timeout"] = expires - current_time + continue + if errcode: + raise SelectorError(errcode) + else: + raise + return result + + +SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) + + +class _SelectorMapping(Mapping): + """ Mapping of file objects to selector keys """ + + def __init__(self, selector): + self._selector = selector + + def __len__(self): + return len(self._selector._fd_to_key) + + def __getitem__(self, fileobj): + try: + fd = self._selector._fileobj_lookup(fileobj) + return self._selector._fd_to_key[fd] + except KeyError: + raise KeyError("{0!r} is not registered.".format(fileobj)) + + def __iter__(self): + return iter(self._selector._fd_to_key) + + +class BaseSelector(object): + """ Abstract Selector class + + A selector supports registering file objects to be monitored + for specific I/O events. + + A file object is a file descriptor or any object with a + `fileno()` method. An arbitrary object can be attached to the + file object which can be used for example to store context info, + a callback, etc. + + A selector can use various implementations (select(), poll(), epoll(), + and kqueue()) depending on the platform. The 'DefaultSelector' class uses + the most efficient implementation for the current platform. + """ + def __init__(self): + # Maps file descriptors to keys. + self._fd_to_key = {} + + # Read-only mapping returned by get_map() + self._map = _SelectorMapping(self) + + def _fileobj_lookup(self, fileobj): + """ Return a file descriptor from a file object. + This wraps _fileobj_to_fd() to do an exhaustive + search in case the object is invalid but we still + have it in our map. Used by unregister() so we can + unregister an object that was previously registered + even if it is closed. It is also used by _SelectorMapping + """ + try: + return _fileobj_to_fd(fileobj) + except ValueError: + + # Search through all our mapped keys. + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + return key.fd + + # Raise ValueError after all. + raise + + def register(self, fileobj, events, data=None): + """ Register a file object for a set of events to monitor. """ + if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): + raise ValueError("Invalid events: {0!r}".format(events)) + + key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) + + if key.fd in self._fd_to_key: + raise KeyError("{0!r} (FD {1}) is already registered" + .format(fileobj, key.fd)) + + self._fd_to_key[key.fd] = key + return key + + def unregister(self, fileobj): + """ Unregister a file object from being monitored. """ + try: + key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + # Getting the fileno of a closed socket on Windows errors with EBADF. + except socket.error as e: # Platform-specific: Windows. + if e.errno != errno.EBADF: + raise + else: + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + self._fd_to_key.pop(key.fd) + break + else: + raise KeyError("{0!r} is not registered".format(fileobj)) + return key + + def modify(self, fileobj, events, data=None): + """ Change a registered file object monitored events and data. """ + # NOTE: Some subclasses optimize this operation even further. + try: + key = self._fd_to_key[self._fileobj_lookup(fileobj)] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + if events != key.events: + self.unregister(fileobj) + key = self.register(fileobj, events, data) + + elif data != key.data: + # Use a shortcut to update the data. + key = key._replace(data=data) + self._fd_to_key[key.fd] = key + + return key + + def select(self, timeout=None): + """ Perform the actual selection until some monitored file objects + are ready or the timeout expires. """ + raise NotImplementedError() + + def close(self): + """ Close the selector. This must be called to ensure that all + underlying resources are freed. """ + self._fd_to_key.clear() + self._map = None + + def get_key(self, fileobj): + """ Return the key associated with a registered file object. """ + mapping = self.get_map() + if mapping is None: + raise RuntimeError("Selector is closed") + try: + return mapping[fileobj] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + def get_map(self): + """ Return a mapping of file objects to selector keys """ + return self._map + + def _key_from_fd(self, fd): + """ Return the key associated to a given file descriptor + Return None if it is not found. """ + try: + return self._fd_to_key[fd] + except KeyError: + return None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + +# Almost all platforms have select.select() +if hasattr(select, "select"): + class SelectSelector(BaseSelector): + """ Select-based selector. """ + def __init__(self): + super(SelectSelector, self).__init__() + self._readers = set() + self._writers = set() + + def register(self, fileobj, events, data=None): + key = super(SelectSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + self._readers.add(key.fd) + if events & EVENT_WRITE: + self._writers.add(key.fd) + return key + + def unregister(self, fileobj): + key = super(SelectSelector, self).unregister(fileobj) + self._readers.discard(key.fd) + self._writers.discard(key.fd) + return key + + def _select(self, r, w, timeout=None): + """ Wrapper for select.select because timeout is a positional arg """ + return select.select(r, w, [], timeout) + + def select(self, timeout=None): + # Selecting on empty lists on Windows errors out. + if not len(self._readers) and not len(self._writers): + return [] + + timeout = None if timeout is None else max(timeout, 0.0) + ready = [] + r, w, _ = _syscall_wrapper(self._select, True, self._readers, + self._writers, timeout) + r = set(r) + w = set(w) + for fd in r | w: + events = 0 + if fd in r: + events |= EVENT_READ + if fd in w: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + +if hasattr(select, "poll"): + class PollSelector(BaseSelector): + """ Poll-based selector """ + def __init__(self): + super(PollSelector, self).__init__() + self._poll = select.poll() + + def register(self, fileobj, events, data=None): + key = super(PollSelector, self).register(fileobj, events, data) + event_mask = 0 + if events & EVENT_READ: + event_mask |= select.POLLIN + if events & EVENT_WRITE: + event_mask |= select.POLLOUT + self._poll.register(key.fd, event_mask) + return key + + def unregister(self, fileobj): + key = super(PollSelector, self).unregister(fileobj) + self._poll.unregister(key.fd) + return key + + def _wrap_poll(self, timeout=None): + """ Wrapper function for select.poll.poll() so that + _syscall_wrapper can work with only seconds. """ + if timeout is not None: + if timeout <= 0: + timeout = 0 + else: + # select.poll.poll() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) + + result = self._poll.poll(timeout) + return result + + def select(self, timeout=None): + ready = [] + fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.POLLIN: + events |= EVENT_WRITE + if event_mask & ~select.POLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + + return ready + + +if hasattr(select, "epoll"): + class EpollSelector(BaseSelector): + """ Epoll-based selector """ + def __init__(self): + super(EpollSelector, self).__init__() + self._epoll = select.epoll() + + def fileno(self): + return self._epoll.fileno() + + def register(self, fileobj, events, data=None): + key = super(EpollSelector, self).register(fileobj, events, data) + events_mask = 0 + if events & EVENT_READ: + events_mask |= select.EPOLLIN + if events & EVENT_WRITE: + events_mask |= select.EPOLLOUT + _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) + return key + + def unregister(self, fileobj): + key = super(EpollSelector, self).unregister(fileobj) + try: + _syscall_wrapper(self._epoll.unregister, False, key.fd) + except SelectorError: + # This can occur when the fd was closed since registry. + pass + return key + + def select(self, timeout=None): + if timeout is not None: + if timeout <= 0: + timeout = 0.0 + else: + # select.epoll.poll() has a resolution of 1 millisecond + # but luckily takes seconds so we don't need a wrapper + # like PollSelector. Just for better rounding. + timeout = math.ceil(timeout * 1e3) * 1e-3 + timeout = float(timeout) + else: + timeout = -1.0 # epoll.poll() must have a float. + + # We always want at least 1 to ensure that select can be called + # with no file descriptors registered. Otherwise will fail. + max_events = max(len(self._fd_to_key), 1) + + ready = [] + fd_events = _syscall_wrapper(self._epoll.poll, True, + timeout=timeout, + maxevents=max_events) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.EPOLLIN: + events |= EVENT_WRITE + if event_mask & ~select.EPOLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + def close(self): + self._epoll.close() + super(EpollSelector, self).close() + + +if hasattr(select, "kqueue"): + class KqueueSelector(BaseSelector): + """ Kqueue / Kevent-based selector """ + def __init__(self): + super(KqueueSelector, self).__init__() + self._kqueue = select.kqueue() + + def fileno(self): + return self._kqueue.fileno() + + def register(self, fileobj, events, data=None): + key = super(KqueueSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + if events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + return key + + def unregister(self, fileobj): + key = super(KqueueSelector, self).unregister(fileobj) + if key.events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + if key.events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + + return key + + def select(self, timeout=None): + if timeout is not None: + timeout = max(timeout, 0) + + max_events = len(self._fd_to_key) * 2 + ready_fds = {} + + kevent_list = _syscall_wrapper(self._kqueue.control, True, + None, max_events, timeout) + + for kevent in kevent_list: + fd = kevent.ident + event_mask = kevent.filter + events = 0 + if event_mask == select.KQ_FILTER_READ: + events |= EVENT_READ + if event_mask == select.KQ_FILTER_WRITE: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + if key.fd not in ready_fds: + ready_fds[key.fd] = (key, events & key.events) + else: + old_events = ready_fds[key.fd][1] + ready_fds[key.fd] = (key, (events | old_events) & key.events) + + return list(ready_fds.values()) + + def close(self): + self._kqueue.close() + super(KqueueSelector, self).close() + + +if not hasattr(select, 'select'): # Platform-specific: AppEngine + HAS_SELECT = False + + +def _can_allocate(struct): + """ Checks that select structs can be allocated by the underlying + operating system, not just advertised by the select module. We don't + check select() because we'll be hopeful that most platforms that + don't have it available will not advertise it. (ie: GAE) """ + try: + # select.poll() objects won't fail until used. + if struct == 'poll': + p = select.poll() + p.poll(0) + + # All others will fail on allocation. + else: + getattr(select, struct)().close() + return True + except (OSError, AttributeError) as e: + return False + + +# Choose the best implementation, roughly: +# kqueue == epoll > poll > select. Devpoll not supported. (See above) +# select() also can't accept a FD > FD_SETSIZE (usually around 1024) +def DefaultSelector(): + """ This function serves as a first call for DefaultSelector to + detect if the select module is being monkey-patched incorrectly + by eventlet, greenlet, and preserve proper behavior. """ + global _DEFAULT_SELECTOR + if _DEFAULT_SELECTOR is None: + if _can_allocate('kqueue'): + _DEFAULT_SELECTOR = KqueueSelector + elif _can_allocate('epoll'): + _DEFAULT_SELECTOR = EpollSelector + elif _can_allocate('poll'): + _DEFAULT_SELECTOR = PollSelector + elif hasattr(select, 'select'): + _DEFAULT_SELECTOR = SelectSelector + else: # Platform-specific: AppEngine + raise ValueError('Platform does not have a selector') + return _DEFAULT_SELECTOR() diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py new file mode 100755 index 0000000..c11dff2 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py @@ -0,0 +1,341 @@ +from __future__ import absolute_import +import errno +import warnings +import hmac + +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning + + +SSLContext = None +HAS_SNI = False +IS_PYOPENSSL = False +IS_SECURETRANSPORT = False + +# 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 l, r in zip(bytearray(a), bytearray(b)): + result |= l ^ r + return result == 0 + + +_const_compare_digest = getattr(hmac, 'compare_digest', + _const_compare_digest_backport) + + +try: # Test for SSL features + import ssl + from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23 + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + + +try: + from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + +# 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 TLS 1.3 cipher suites +# - 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 and DSS for security reasons. +DEFAULT_CIPHERS = ':'.join([ + 'TLS13-AES-256-GCM-SHA384', + 'TLS13-CHACHA20-POLY1305-SHA256', + 'TLS13-AES-128-GCM-SHA256', + 'ECDH+AESGCM', + 'ECDH+CHACHA20', + 'DH+AESGCM', + 'DH+CHACHA20', + 'ECDH+AES256', + 'DH+AES256', + 'ECDH+AES128', + 'DH+AES', + 'RSA+AESGCM', + 'RSA+AES', + '!aNULL', + '!eNULL', + '!MD5', +]) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + import sys + + class SSLContext(object): # Platform-specific: Python 2 & 3.1 + supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or + (3, 2) <= sys.version_info) + + 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): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + if not self.supports_set_ciphers: + raise TypeError( + 'Your version of Python does not support setting ' + 'a custom cipher suite. Please upgrade to Python ' + '2.7, 3.2, or later if you need this functionality.' + ) + 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/latest/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, + } + if self.supports_set_ciphers: # Platform-specific: Python 2.7+ + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + else: # Platform-specific: Python 2.6 + return wrap_socket(socket, **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_NONE`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbrevation. + (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_NONE + + 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_SSLv23 + + 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 pip._vendor.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``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) + + # 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 + + context.options |= options + + if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6 + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + context.verify_mode = cert_reqs + 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 + 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): + """ + 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. This is not + supported on Python 2.6 as the ssl module does not support it. + :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(). + """ + 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: + try: + context.load_verify_locations(ca_certs, ca_cert_dir) + except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2 + raise SSLError(e) + # Py33 raises FileNotFoundError which subclasses OSError + # These are not equivalent unless we check the errno attribute + except OSError as e: # Platform-specific: Python 3.3 and beyond + if e.errno == errno.ENOENT: + raise SSLError(e) + raise + elif getattr(context, 'load_default_certs', None) is not None: + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + if certfile: + context.load_cert_chain(certfile, keyfile) + if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI + return context.wrap_socket(sock, server_hostname=server_hostname) + + warnings.warn( + 'An HTTPS request has been made, but the SNI (Subject 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/latest/advanced-usage.html' + '#ssl-warnings', + SNIMissingWarning + ) + return context.wrap_socket(sock) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py new file mode 100755 index 0000000..9c2e6ef --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py @@ -0,0 +1,242 @@ +from __future__ import absolute_import +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT +import time + +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:: + + 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):: + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``:: + + 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: integer, float, or None + + :param connect: + The maximum amount of time 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 + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout for connection attempts. + + :type connect: integer, float, or None + + :param read: + The maximum amount of time 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 + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout. + + :type read: integer, 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 __str__(self): + return '%s(connect=%r, read=%r, total=%r)' % ( + type(self).__name__, self._connect, self._read, self.total) + + @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. + :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/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py new file mode 100755 index 0000000..60f826a --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py @@ -0,0 +1,230 @@ +from __future__ import absolute_import +from collections import namedtuple + +from ..exceptions import LocationParseError + + +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) + + +class Url(namedtuple('Url', url_attrs)): + """ + Datastructure 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: + scheme = scheme.lower() + if host and scheme in NORMALIZABLE_SCHEMES: + host = host.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 = '' + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + '://' + if auth is not None: + url += auth + '@' + if host is not None: + url += host + if port is not None: + url += ':' + str(port) + if path is not None: + url += path + if query is not None: + url += '?' + query + if fragment is not None: + url += '#' + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, '', None + + return s[:min_idx], s[min_idx + 1:], min_delim + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/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', ...) + """ + + # While this code has overlap with stdlib's urlparse, it is much + # simplified for our needs and less annoying. + # Additionally, this implementations does silly things to be optimal + # on CPython. + + if not url: + # Empty + return Url() + + scheme = None + auth = None + host = None + port = None + path = None + fragment = None + query = None + + # Scheme + if '://' in url: + scheme, url = url.split('://', 1) + + # Find the earliest Authority Terminator + # (http://tools.ietf.org/html/rfc3986#section-3.2) + url, path_, delim = split_first(url, ['/', '?', '#']) + + if delim: + # Reassemble the path + path = delim + path_ + + # Auth + if '@' in url: + # Last '@' denotes end of auth part + auth, url = url.rsplit('@', 1) + + # IPv6 + if url and url[0] == '[': + host, url = url.split(']', 1) + host += ']' + + # Port + if ':' in url: + _host, port = url.split(':', 1) + + if not host: + host = _host + + if port: + # If given, ports must be integers. No whitespace, no plus or + # minus prefixes, no non-integer digits such as ^2 (superscript). + if not port.isdigit(): + raise LocationParseError(url) + try: + port = int(port) + except ValueError: + raise LocationParseError(url) + else: + # Blank ports are cool, too. (rfc3986#section-3.2.3) + port = None + + elif not host and url: + host = url + + if not path: + return Url(scheme, auth, host, port, path, query, fragment) + + # Fragment + if '#' in path: + path, fragment = path.split('#', 1) + + # Query + if '?' in path: + path, query = path.split('?', 1) + + return Url(scheme, auth, host, port, path, query, fragment) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or 'http', p.hostname, p.port diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py new file mode 100755 index 0000000..46392f2 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py @@ -0,0 +1,40 @@ +from .selectors import ( + HAS_SELECT, + DefaultSelector, + EVENT_READ, + EVENT_WRITE +) + + +def _wait_for_io_events(socks, events, timeout=None): + """ Waits for IO events to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be interacted with immediately. """ + if not HAS_SELECT: + raise ValueError('Platform does not have a selector') + if not isinstance(socks, list): + # Probably just a single socket. + if hasattr(socks, "fileno"): + socks = [socks] + # Otherwise it might be a non-list iterable. + else: + socks = list(socks) + with DefaultSelector() as selector: + for sock in socks: + selector.register(sock, events) + return [key[0].fileobj for key in + selector.select(timeout) if key[1] & events] + + +def wait_for_read(socks, timeout=None): + """ Waits for reading to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be read from immediately. """ + return _wait_for_io_events(socks, EVENT_READ, timeout) + + +def wait_for_write(socks, timeout=None): + """ Waits for writing to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be written to immediately. """ + return _wait_for_io_events(socks, EVENT_WRITE, timeout) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py new file mode 100755 index 0000000..16671ef --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py @@ -0,0 +1,342 @@ +# coding: utf-8 +""" + + webencodings + ~~~~~~~~~~~~ + + This is a Python implementation of the `WHATWG Encoding standard + <http://encoding.spec.whatwg.org/>`. See README for details. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +import codecs + +from .labels import LABELS + + +VERSION = '0.5.1' + + +# Some names in Encoding are not valid Python aliases. Remap these. +PYTHON_NAMES = { + 'iso-8859-8-i': 'iso-8859-8', + 'x-mac-cyrillic': 'mac-cyrillic', + 'macintosh': 'mac-roman', + 'windows-874': 'cp874'} + +CACHE = {} + + +def ascii_lower(string): + r"""Transform (only) ASCII letters to lower case: A-Z is mapped to a-z. + + :param string: An Unicode string. + :returns: A new Unicode string. + + This is used for `ASCII case-insensitive + <http://encoding.spec.whatwg.org/#ascii-case-insensitive>`_ + matching of encoding labels. + The same matching is also used, among other things, + for `CSS keywords <http://dev.w3.org/csswg/css-values/#keywords>`_. + + This is different from the :meth:`~py:str.lower` method of Unicode strings + which also affect non-ASCII characters, + sometimes mapping them into the ASCII range: + + >>> keyword = u'Bac\N{KELVIN SIGN}ground' + >>> assert keyword.lower() == u'background' + >>> assert ascii_lower(keyword) != keyword.lower() + >>> assert ascii_lower(keyword) == u'bac\N{KELVIN SIGN}ground' + + """ + # This turns out to be faster than unicode.translate() + return string.encode('utf8').lower().decode('utf8') + + +def lookup(label): + """ + Look for an encoding by its label. + This is the spec’s `get an encoding + <http://encoding.spec.whatwg.org/#concept-encoding-get>`_ algorithm. + Supported labels are listed there. + + :param label: A string. + :returns: + An :class:`Encoding` object, or :obj:`None` for an unknown label. + + """ + # Only strip ASCII whitespace: U+0009, U+000A, U+000C, U+000D, and U+0020. + label = ascii_lower(label.strip('\t\n\f\r ')) + name = LABELS.get(label) + if name is None: + return None + encoding = CACHE.get(name) + if encoding is None: + if name == 'x-user-defined': + from .x_user_defined import codec_info + else: + python_name = PYTHON_NAMES.get(name, name) + # Any python_name value that gets to here should be valid. + codec_info = codecs.lookup(python_name) + encoding = Encoding(name, codec_info) + CACHE[name] = encoding + return encoding + + +def _get_encoding(encoding_or_label): + """ + Accept either an encoding object or label. + + :param encoding: An :class:`Encoding` object or a label string. + :returns: An :class:`Encoding` object. + :raises: :exc:`~exceptions.LookupError` for an unknown label. + + """ + if hasattr(encoding_or_label, 'codec_info'): + return encoding_or_label + + encoding = lookup(encoding_or_label) + if encoding is None: + raise LookupError('Unknown encoding label: %r' % encoding_or_label) + return encoding + + +class Encoding(object): + """Reresents a character encoding such as UTF-8, + that can be used for decoding or encoding. + + .. attribute:: name + + Canonical name of the encoding + + .. attribute:: codec_info + + The actual implementation of the encoding, + a stdlib :class:`~codecs.CodecInfo` object. + See :func:`codecs.register`. + + """ + def __init__(self, name, codec_info): + self.name = name + self.codec_info = codec_info + + def __repr__(self): + return '<Encoding %s>' % self.name + + +#: The UTF-8 encoding. Should be used for new content and formats. +UTF8 = lookup('utf-8') + +_UTF16LE = lookup('utf-16le') +_UTF16BE = lookup('utf-16be') + + +def decode(input, fallback_encoding, errors='replace'): + """ + Decode a single string. + + :param input: A byte string + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :return: + A ``(output, encoding)`` tuple of an Unicode string + and an :obj:`Encoding`. + + """ + # Fail early if `encoding` is an invalid label. + fallback_encoding = _get_encoding(fallback_encoding) + bom_encoding, input = _detect_bom(input) + encoding = bom_encoding or fallback_encoding + return encoding.codec_info.decode(input, errors)[0], encoding + + +def _detect_bom(input): + """Return (bom_encoding, input), with any BOM removed from the input.""" + if input.startswith(b'\xFF\xFE'): + return _UTF16LE, input[2:] + if input.startswith(b'\xFE\xFF'): + return _UTF16BE, input[2:] + if input.startswith(b'\xEF\xBB\xBF'): + return UTF8, input[3:] + return None, input + + +def encode(input, encoding=UTF8, errors='strict'): + """ + Encode a single string. + + :param input: An Unicode string. + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :return: A byte string. + + """ + return _get_encoding(encoding).codec_info.encode(input, errors)[0] + + +def iter_decode(input, fallback_encoding, errors='replace'): + """ + "Pull"-based decoder. + + :param input: + An iterable of byte strings. + + The input is first consumed just enough to determine the encoding + based on the precense of a BOM, + then consumed on demand when the return value is. + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :returns: + An ``(output, encoding)`` tuple. + :obj:`output` is an iterable of Unicode strings, + :obj:`encoding` is the :obj:`Encoding` that is being used. + + """ + + decoder = IncrementalDecoder(fallback_encoding, errors) + generator = _iter_decode_generator(input, decoder) + encoding = next(generator) + return generator, encoding + + +def _iter_decode_generator(input, decoder): + """Return a generator that first yields the :obj:`Encoding`, + then yields output chukns as Unicode strings. + + """ + decode = decoder.decode + input = iter(input) + for chunck in input: + output = decode(chunck) + if output: + assert decoder.encoding is not None + yield decoder.encoding + yield output + break + else: + # Input exhausted without determining the encoding + output = decode(b'', final=True) + assert decoder.encoding is not None + yield decoder.encoding + if output: + yield output + return + + for chunck in input: + output = decode(chunck) + if output: + yield output + output = decode(b'', final=True) + if output: + yield output + + +def iter_encode(input, encoding=UTF8, errors='strict'): + """ + “Pull”-based encoder. + + :param input: An iterable of Unicode strings. + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :returns: An iterable of byte strings. + + """ + # Fail early if `encoding` is an invalid label. + encode = IncrementalEncoder(encoding, errors).encode + return _iter_encode_generator(input, encode) + + +def _iter_encode_generator(input, encode): + for chunck in input: + output = encode(chunck) + if output: + yield output + output = encode('', final=True) + if output: + yield output + + +class IncrementalDecoder(object): + """ + “Push”-based decoder. + + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + + """ + def __init__(self, fallback_encoding, errors='replace'): + # Fail early if `encoding` is an invalid label. + self._fallback_encoding = _get_encoding(fallback_encoding) + self._errors = errors + self._buffer = b'' + self._decoder = None + #: The actual :class:`Encoding` that is being used, + #: or :obj:`None` if that is not determined yet. + #: (Ie. if there is not enough input yet to determine + #: if there is a BOM.) + self.encoding = None # Not known yet. + + def decode(self, input, final=False): + """Decode one chunk of the input. + + :param input: A byte string. + :param final: + Indicate that no more input is available. + Must be :obj:`True` if this is the last call. + :returns: An Unicode string. + + """ + decoder = self._decoder + if decoder is not None: + return decoder(input, final) + + input = self._buffer + input + encoding, input = _detect_bom(input) + if encoding is None: + if len(input) < 3 and not final: # Not enough data yet. + self._buffer = input + return '' + else: # No BOM + encoding = self._fallback_encoding + decoder = encoding.codec_info.incrementaldecoder(self._errors).decode + self._decoder = decoder + self.encoding = encoding + return decoder(input, final) + + +class IncrementalEncoder(object): + """ + “Push”-based encoder. + + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + + .. method:: encode(input, final=False) + + :param input: An Unicode string. + :param final: + Indicate that no more input is available. + Must be :obj:`True` if this is the last call. + :returns: A byte string. + + """ + def __init__(self, encoding=UTF8, errors='strict'): + encoding = _get_encoding(encoding) + self.encode = encoding.codec_info.incrementalencoder(errors).encode diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py new file mode 100755 index 0000000..9dae102 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py @@ -0,0 +1,231 @@ +""" + + webencodings.labels + ~~~~~~~~~~~~~~~~~~~ + + Map encoding labels to their name. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +# XXX Do not edit! +# This file is automatically generated by mklabels.py + +LABELS = { + 'unicode-1-1-utf-8': 'utf-8', + 'utf-8': 'utf-8', + 'utf8': 'utf-8', + '866': 'ibm866', + 'cp866': 'ibm866', + 'csibm866': 'ibm866', + 'ibm866': 'ibm866', + 'csisolatin2': 'iso-8859-2', + 'iso-8859-2': 'iso-8859-2', + 'iso-ir-101': 'iso-8859-2', + 'iso8859-2': 'iso-8859-2', + 'iso88592': 'iso-8859-2', + 'iso_8859-2': 'iso-8859-2', + 'iso_8859-2:1987': 'iso-8859-2', + 'l2': 'iso-8859-2', + 'latin2': 'iso-8859-2', + 'csisolatin3': 'iso-8859-3', + 'iso-8859-3': 'iso-8859-3', + 'iso-ir-109': 'iso-8859-3', + 'iso8859-3': 'iso-8859-3', + 'iso88593': 'iso-8859-3', + 'iso_8859-3': 'iso-8859-3', + 'iso_8859-3:1988': 'iso-8859-3', + 'l3': 'iso-8859-3', + 'latin3': 'iso-8859-3', + 'csisolatin4': 'iso-8859-4', + 'iso-8859-4': 'iso-8859-4', + 'iso-ir-110': 'iso-8859-4', + 'iso8859-4': 'iso-8859-4', + 'iso88594': 'iso-8859-4', + 'iso_8859-4': 'iso-8859-4', + 'iso_8859-4:1988': 'iso-8859-4', + 'l4': 'iso-8859-4', + 'latin4': 'iso-8859-4', + 'csisolatincyrillic': 'iso-8859-5', + 'cyrillic': 'iso-8859-5', + 'iso-8859-5': 'iso-8859-5', + 'iso-ir-144': 'iso-8859-5', + 'iso8859-5': 'iso-8859-5', + 'iso88595': 'iso-8859-5', + 'iso_8859-5': 'iso-8859-5', + 'iso_8859-5:1988': 'iso-8859-5', + 'arabic': 'iso-8859-6', + 'asmo-708': 'iso-8859-6', + 'csiso88596e': 'iso-8859-6', + 'csiso88596i': 'iso-8859-6', + 'csisolatinarabic': 'iso-8859-6', + 'ecma-114': 'iso-8859-6', + 'iso-8859-6': 'iso-8859-6', + 'iso-8859-6-e': 'iso-8859-6', + 'iso-8859-6-i': 'iso-8859-6', + 'iso-ir-127': 'iso-8859-6', + 'iso8859-6': 'iso-8859-6', + 'iso88596': 'iso-8859-6', + 'iso_8859-6': 'iso-8859-6', + 'iso_8859-6:1987': 'iso-8859-6', + 'csisolatingreek': 'iso-8859-7', + 'ecma-118': 'iso-8859-7', + 'elot_928': 'iso-8859-7', + 'greek': 'iso-8859-7', + 'greek8': 'iso-8859-7', + 'iso-8859-7': 'iso-8859-7', + 'iso-ir-126': 'iso-8859-7', + 'iso8859-7': 'iso-8859-7', + 'iso88597': 'iso-8859-7', + 'iso_8859-7': 'iso-8859-7', + 'iso_8859-7:1987': 'iso-8859-7', + 'sun_eu_greek': 'iso-8859-7', + 'csiso88598e': 'iso-8859-8', + 'csisolatinhebrew': 'iso-8859-8', + 'hebrew': 'iso-8859-8', + 'iso-8859-8': 'iso-8859-8', + 'iso-8859-8-e': 'iso-8859-8', + 'iso-ir-138': 'iso-8859-8', + 'iso8859-8': 'iso-8859-8', + 'iso88598': 'iso-8859-8', + 'iso_8859-8': 'iso-8859-8', + 'iso_8859-8:1988': 'iso-8859-8', + 'visual': 'iso-8859-8', + 'csiso88598i': 'iso-8859-8-i', + 'iso-8859-8-i': 'iso-8859-8-i', + 'logical': 'iso-8859-8-i', + 'csisolatin6': 'iso-8859-10', + 'iso-8859-10': 'iso-8859-10', + 'iso-ir-157': 'iso-8859-10', + 'iso8859-10': 'iso-8859-10', + 'iso885910': 'iso-8859-10', + 'l6': 'iso-8859-10', + 'latin6': 'iso-8859-10', + 'iso-8859-13': 'iso-8859-13', + 'iso8859-13': 'iso-8859-13', + 'iso885913': 'iso-8859-13', + 'iso-8859-14': 'iso-8859-14', + 'iso8859-14': 'iso-8859-14', + 'iso885914': 'iso-8859-14', + 'csisolatin9': 'iso-8859-15', + 'iso-8859-15': 'iso-8859-15', + 'iso8859-15': 'iso-8859-15', + 'iso885915': 'iso-8859-15', + 'iso_8859-15': 'iso-8859-15', + 'l9': 'iso-8859-15', + 'iso-8859-16': 'iso-8859-16', + 'cskoi8r': 'koi8-r', + 'koi': 'koi8-r', + 'koi8': 'koi8-r', + 'koi8-r': 'koi8-r', + 'koi8_r': 'koi8-r', + 'koi8-u': 'koi8-u', + 'csmacintosh': 'macintosh', + 'mac': 'macintosh', + 'macintosh': 'macintosh', + 'x-mac-roman': 'macintosh', + 'dos-874': 'windows-874', + 'iso-8859-11': 'windows-874', + 'iso8859-11': 'windows-874', + 'iso885911': 'windows-874', + 'tis-620': 'windows-874', + 'windows-874': 'windows-874', + 'cp1250': 'windows-1250', + 'windows-1250': 'windows-1250', + 'x-cp1250': 'windows-1250', + 'cp1251': 'windows-1251', + 'windows-1251': 'windows-1251', + 'x-cp1251': 'windows-1251', + 'ansi_x3.4-1968': 'windows-1252', + 'ascii': 'windows-1252', + 'cp1252': 'windows-1252', + 'cp819': 'windows-1252', + 'csisolatin1': 'windows-1252', + 'ibm819': 'windows-1252', + 'iso-8859-1': 'windows-1252', + 'iso-ir-100': 'windows-1252', + 'iso8859-1': 'windows-1252', + 'iso88591': 'windows-1252', + 'iso_8859-1': 'windows-1252', + 'iso_8859-1:1987': 'windows-1252', + 'l1': 'windows-1252', + 'latin1': 'windows-1252', + 'us-ascii': 'windows-1252', + 'windows-1252': 'windows-1252', + 'x-cp1252': 'windows-1252', + 'cp1253': 'windows-1253', + 'windows-1253': 'windows-1253', + 'x-cp1253': 'windows-1253', + 'cp1254': 'windows-1254', + 'csisolatin5': 'windows-1254', + 'iso-8859-9': 'windows-1254', + 'iso-ir-148': 'windows-1254', + 'iso8859-9': 'windows-1254', + 'iso88599': 'windows-1254', + 'iso_8859-9': 'windows-1254', + 'iso_8859-9:1989': 'windows-1254', + 'l5': 'windows-1254', + 'latin5': 'windows-1254', + 'windows-1254': 'windows-1254', + 'x-cp1254': 'windows-1254', + 'cp1255': 'windows-1255', + 'windows-1255': 'windows-1255', + 'x-cp1255': 'windows-1255', + 'cp1256': 'windows-1256', + 'windows-1256': 'windows-1256', + 'x-cp1256': 'windows-1256', + 'cp1257': 'windows-1257', + 'windows-1257': 'windows-1257', + 'x-cp1257': 'windows-1257', + 'cp1258': 'windows-1258', + 'windows-1258': 'windows-1258', + 'x-cp1258': 'windows-1258', + 'x-mac-cyrillic': 'x-mac-cyrillic', + 'x-mac-ukrainian': 'x-mac-cyrillic', + 'chinese': 'gbk', + 'csgb2312': 'gbk', + 'csiso58gb231280': 'gbk', + 'gb2312': 'gbk', + 'gb_2312': 'gbk', + 'gb_2312-80': 'gbk', + 'gbk': 'gbk', + 'iso-ir-58': 'gbk', + 'x-gbk': 'gbk', + 'gb18030': 'gb18030', + 'hz-gb-2312': 'hz-gb-2312', + 'big5': 'big5', + 'big5-hkscs': 'big5', + 'cn-big5': 'big5', + 'csbig5': 'big5', + 'x-x-big5': 'big5', + 'cseucpkdfmtjapanese': 'euc-jp', + 'euc-jp': 'euc-jp', + 'x-euc-jp': 'euc-jp', + 'csiso2022jp': 'iso-2022-jp', + 'iso-2022-jp': 'iso-2022-jp', + 'csshiftjis': 'shift_jis', + 'ms_kanji': 'shift_jis', + 'shift-jis': 'shift_jis', + 'shift_jis': 'shift_jis', + 'sjis': 'shift_jis', + 'windows-31j': 'shift_jis', + 'x-sjis': 'shift_jis', + 'cseuckr': 'euc-kr', + 'csksc56011987': 'euc-kr', + 'euc-kr': 'euc-kr', + 'iso-ir-149': 'euc-kr', + 'korean': 'euc-kr', + 'ks_c_5601-1987': 'euc-kr', + 'ks_c_5601-1989': 'euc-kr', + 'ksc5601': 'euc-kr', + 'ksc_5601': 'euc-kr', + 'windows-949': 'euc-kr', + 'csiso2022kr': 'iso-2022-kr', + 'iso-2022-kr': 'iso-2022-kr', + 'utf-16be': 'utf-16be', + 'utf-16': 'utf-16le', + 'utf-16le': 'utf-16le', + 'x-user-defined': 'x-user-defined', +} diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py new file mode 100755 index 0000000..a7f7e76 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py @@ -0,0 +1,59 @@ +""" + + webencodings.mklabels + ~~~~~~~~~~~~~~~~~~~~~ + + Regenarate the webencodings.labels module. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +import json +try: + from urllib import urlopen +except ImportError: + from urllib.request import urlopen + + +def assert_lower(string): + assert string == string.lower() + return string + + +def generate(url): + parts = ['''\ +""" + + webencodings.labels + ~~~~~~~~~~~~~~~~~~~ + + Map encoding labels to their name. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +# XXX Do not edit! +# This file is automatically generated by mklabels.py + +LABELS = { +'''] + labels = [ + (repr(assert_lower(label)).lstrip('u'), + repr(encoding['name']).lstrip('u')) + for category in json.loads(urlopen(url).read().decode('ascii')) + for encoding in category['encodings'] + for label in encoding['labels']] + max_len = max(len(label) for label, name in labels) + parts.extend( + ' %s:%s %s,\n' % (label, ' ' * (max_len - len(label)), name) + for label, name in labels) + parts.append('}') + return ''.join(parts) + + +if __name__ == '__main__': + print(generate('http://encoding.spec.whatwg.org/encodings.json')) diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py new file mode 100755 index 0000000..f6cdbf9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py @@ -0,0 +1,153 @@ +# coding: utf-8 +""" + + webencodings.tests + ~~~~~~~~~~~~~~~~~~ + + A basic test suite for Encoding. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +from . import (lookup, LABELS, decode, encode, iter_decode, iter_encode, + IncrementalDecoder, IncrementalEncoder, UTF8) + + +def assert_raises(exception, function, *args, **kwargs): + try: + function(*args, **kwargs) + except exception: + return + else: # pragma: no cover + raise AssertionError('Did not raise %s.' % exception) + + +def test_labels(): + assert lookup('utf-8').name == 'utf-8' + assert lookup('Utf-8').name == 'utf-8' + assert lookup('UTF-8').name == 'utf-8' + assert lookup('utf8').name == 'utf-8' + assert lookup('utf8').name == 'utf-8' + assert lookup('utf8 ').name == 'utf-8' + assert lookup(' \r\nutf8\t').name == 'utf-8' + assert lookup('u8') is None # Python label. + assert lookup('utf-8 ') is None # Non-ASCII white space. + + assert lookup('US-ASCII').name == 'windows-1252' + assert lookup('iso-8859-1').name == 'windows-1252' + assert lookup('latin1').name == 'windows-1252' + assert lookup('LATIN1').name == 'windows-1252' + assert lookup('latin-1') is None + assert lookup('LATİN1') is None # ASCII-only case insensitivity. + + +def test_all_labels(): + for label in LABELS: + assert decode(b'', label) == ('', lookup(label)) + assert encode('', label) == b'' + for repeat in [0, 1, 12]: + output, _ = iter_decode([b''] * repeat, label) + assert list(output) == [] + assert list(iter_encode([''] * repeat, label)) == [] + decoder = IncrementalDecoder(label) + assert decoder.decode(b'') == '' + assert decoder.decode(b'', final=True) == '' + encoder = IncrementalEncoder(label) + assert encoder.encode('') == b'' + assert encoder.encode('', final=True) == b'' + # All encoding names are valid labels too: + for name in set(LABELS.values()): + assert lookup(name).name == name + + +def test_invalid_label(): + assert_raises(LookupError, decode, b'\xEF\xBB\xBF\xc3\xa9', 'invalid') + assert_raises(LookupError, encode, 'é', 'invalid') + assert_raises(LookupError, iter_decode, [], 'invalid') + assert_raises(LookupError, iter_encode, [], 'invalid') + assert_raises(LookupError, IncrementalDecoder, 'invalid') + assert_raises(LookupError, IncrementalEncoder, 'invalid') + + +def test_decode(): + assert decode(b'\x80', 'latin1') == ('€', lookup('latin1')) + assert decode(b'\x80', lookup('latin1')) == ('€', lookup('latin1')) + assert decode(b'\xc3\xa9', 'utf8') == ('é', lookup('utf8')) + assert decode(b'\xc3\xa9', UTF8) == ('é', lookup('utf8')) + assert decode(b'\xc3\xa9', 'ascii') == ('é', lookup('ascii')) + assert decode(b'\xEF\xBB\xBF\xc3\xa9', 'ascii') == ('é', lookup('utf8')) # UTF-8 with BOM + + assert decode(b'\xFE\xFF\x00\xe9', 'ascii') == ('é', lookup('utf-16be')) # UTF-16-BE with BOM + assert decode(b'\xFF\xFE\xe9\x00', 'ascii') == ('é', lookup('utf-16le')) # UTF-16-LE with BOM + assert decode(b'\xFE\xFF\xe9\x00', 'ascii') == ('\ue900', lookup('utf-16be')) + assert decode(b'\xFF\xFE\x00\xe9', 'ascii') == ('\ue900', lookup('utf-16le')) + + assert decode(b'\x00\xe9', 'UTF-16BE') == ('é', lookup('utf-16be')) + assert decode(b'\xe9\x00', 'UTF-16LE') == ('é', lookup('utf-16le')) + assert decode(b'\xe9\x00', 'UTF-16') == ('é', lookup('utf-16le')) + + assert decode(b'\xe9\x00', 'UTF-16BE') == ('\ue900', lookup('utf-16be')) + assert decode(b'\x00\xe9', 'UTF-16LE') == ('\ue900', lookup('utf-16le')) + assert decode(b'\x00\xe9', 'UTF-16') == ('\ue900', lookup('utf-16le')) + + +def test_encode(): + assert encode('é', 'latin1') == b'\xe9' + assert encode('é', 'utf8') == b'\xc3\xa9' + assert encode('é', 'utf8') == b'\xc3\xa9' + assert encode('é', 'utf-16') == b'\xe9\x00' + assert encode('é', 'utf-16le') == b'\xe9\x00' + assert encode('é', 'utf-16be') == b'\x00\xe9' + + +def test_iter_decode(): + def iter_decode_to_string(input, fallback_encoding): + output, _encoding = iter_decode(input, fallback_encoding) + return ''.join(output) + assert iter_decode_to_string([], 'latin1') == '' + assert iter_decode_to_string([b''], 'latin1') == '' + assert iter_decode_to_string([b'\xe9'], 'latin1') == 'é' + assert iter_decode_to_string([b'hello'], 'latin1') == 'hello' + assert iter_decode_to_string([b'he', b'llo'], 'latin1') == 'hello' + assert iter_decode_to_string([b'hell', b'o'], 'latin1') == 'hello' + assert iter_decode_to_string([b'\xc3\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xEF\xBB\xBF\xc3\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'\xEF\xBB\xBF', b'\xc3', b'\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'\xEF\xBB\xBF', b'a', b'\xc3'], 'latin1') == 'a\uFFFD' + assert iter_decode_to_string([ + b'', b'\xEF', b'', b'', b'\xBB\xBF\xc3', b'\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xEF\xBB\xBF'], 'latin1') == '' + assert iter_decode_to_string([b'\xEF\xBB'], 'latin1') == 'ï»' + assert iter_decode_to_string([b'\xFE\xFF\x00\xe9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xFF\xFE\xe9\x00'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'', b'\xFF', b'', b'', b'\xFE\xe9', b'\x00'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'', b'h\xe9', b'llo'], 'x-user-defined') == 'h\uF7E9llo' + + +def test_iter_encode(): + assert b''.join(iter_encode([], 'latin1')) == b'' + assert b''.join(iter_encode([''], 'latin1')) == b'' + assert b''.join(iter_encode(['é'], 'latin1')) == b'\xe9' + assert b''.join(iter_encode(['', 'é', '', ''], 'latin1')) == b'\xe9' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16')) == b'\xe9\x00' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16le')) == b'\xe9\x00' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16be')) == b'\x00\xe9' + assert b''.join(iter_encode([ + '', 'h\uF7E9', '', 'llo'], 'x-user-defined')) == b'h\xe9llo' + + +def test_x_user_defined(): + encoded = b'2,\x0c\x0b\x1aO\xd9#\xcb\x0f\xc9\xbbt\xcf\xa8\xca' + decoded = '2,\x0c\x0b\x1aO\uf7d9#\uf7cb\x0f\uf7c9\uf7bbt\uf7cf\uf7a8\uf7ca' + encoded = b'aa' + decoded = 'aa' + assert decode(encoded, 'x-user-defined') == (decoded, lookup('x-user-defined')) + assert encode(decoded, 'x-user-defined') == encoded diff --git a/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py new file mode 100755 index 0000000..748e2c9 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py @@ -0,0 +1,325 @@ +# coding: utf-8 +""" + + webencodings.x_user_defined + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + An implementation of the x-user-defined encoding. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +import codecs + + +### Codec APIs + +class Codec(codecs.Codec): + + def encode(self, input, errors='strict'): + return codecs.charmap_encode(input, errors, encoding_table) + + def decode(self, input, errors='strict'): + return codecs.charmap_decode(input, errors, decoding_table) + + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input, final=False): + return codecs.charmap_encode(input, self.errors, encoding_table)[0] + + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input, final=False): + return codecs.charmap_decode(input, self.errors, decoding_table)[0] + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + + +class StreamReader(Codec, codecs.StreamReader): + pass + + +### encodings module API + +codec_info = codecs.CodecInfo( + name='x-user-defined', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamreader=StreamReader, + streamwriter=StreamWriter, +) + + +### Decoding Table + +# Python 3: +# for c in range(256): print(' %r' % chr(c if c < 128 else c + 0xF700)) +decoding_table = ( + '\x00' + '\x01' + '\x02' + '\x03' + '\x04' + '\x05' + '\x06' + '\x07' + '\x08' + '\t' + '\n' + '\x0b' + '\x0c' + '\r' + '\x0e' + '\x0f' + '\x10' + '\x11' + '\x12' + '\x13' + '\x14' + '\x15' + '\x16' + '\x17' + '\x18' + '\x19' + '\x1a' + '\x1b' + '\x1c' + '\x1d' + '\x1e' + '\x1f' + ' ' + '!' + '"' + '#' + '$' + '%' + '&' + "'" + '(' + ')' + '*' + '+' + ',' + '-' + '.' + '/' + '0' + '1' + '2' + '3' + '4' + '5' + '6' + '7' + '8' + '9' + ':' + ';' + '<' + '=' + '>' + '?' + '@' + 'A' + 'B' + 'C' + 'D' + 'E' + 'F' + 'G' + 'H' + 'I' + 'J' + 'K' + 'L' + 'M' + 'N' + 'O' + 'P' + 'Q' + 'R' + 'S' + 'T' + 'U' + 'V' + 'W' + 'X' + 'Y' + 'Z' + '[' + '\\' + ']' + '^' + '_' + '`' + 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' + 'h' + 'i' + 'j' + 'k' + 'l' + 'm' + 'n' + 'o' + 'p' + 'q' + 'r' + 's' + 't' + 'u' + 'v' + 'w' + 'x' + 'y' + 'z' + '{' + '|' + '}' + '~' + '\x7f' + '\uf780' + '\uf781' + '\uf782' + '\uf783' + '\uf784' + '\uf785' + '\uf786' + '\uf787' + '\uf788' + '\uf789' + '\uf78a' + '\uf78b' + '\uf78c' + '\uf78d' + '\uf78e' + '\uf78f' + '\uf790' + '\uf791' + '\uf792' + '\uf793' + '\uf794' + '\uf795' + '\uf796' + '\uf797' + '\uf798' + '\uf799' + '\uf79a' + '\uf79b' + '\uf79c' + '\uf79d' + '\uf79e' + '\uf79f' + '\uf7a0' + '\uf7a1' + '\uf7a2' + '\uf7a3' + '\uf7a4' + '\uf7a5' + '\uf7a6' + '\uf7a7' + '\uf7a8' + '\uf7a9' + '\uf7aa' + '\uf7ab' + '\uf7ac' + '\uf7ad' + '\uf7ae' + '\uf7af' + '\uf7b0' + '\uf7b1' + '\uf7b2' + '\uf7b3' + '\uf7b4' + '\uf7b5' + '\uf7b6' + '\uf7b7' + '\uf7b8' + '\uf7b9' + '\uf7ba' + '\uf7bb' + '\uf7bc' + '\uf7bd' + '\uf7be' + '\uf7bf' + '\uf7c0' + '\uf7c1' + '\uf7c2' + '\uf7c3' + '\uf7c4' + '\uf7c5' + '\uf7c6' + '\uf7c7' + '\uf7c8' + '\uf7c9' + '\uf7ca' + '\uf7cb' + '\uf7cc' + '\uf7cd' + '\uf7ce' + '\uf7cf' + '\uf7d0' + '\uf7d1' + '\uf7d2' + '\uf7d3' + '\uf7d4' + '\uf7d5' + '\uf7d6' + '\uf7d7' + '\uf7d8' + '\uf7d9' + '\uf7da' + '\uf7db' + '\uf7dc' + '\uf7dd' + '\uf7de' + '\uf7df' + '\uf7e0' + '\uf7e1' + '\uf7e2' + '\uf7e3' + '\uf7e4' + '\uf7e5' + '\uf7e6' + '\uf7e7' + '\uf7e8' + '\uf7e9' + '\uf7ea' + '\uf7eb' + '\uf7ec' + '\uf7ed' + '\uf7ee' + '\uf7ef' + '\uf7f0' + '\uf7f1' + '\uf7f2' + '\uf7f3' + '\uf7f4' + '\uf7f5' + '\uf7f6' + '\uf7f7' + '\uf7f8' + '\uf7f9' + '\uf7fa' + '\uf7fb' + '\uf7fc' + '\uf7fd' + '\uf7fe' + '\uf7ff' +) + +### Encoding table +encoding_table = codecs.charmap_build(decoding_table) diff --git a/meta_updater/venv/lib/python3.5/site-packages/setuptools-39.1.0-py3.5.egg b/meta_updater/venv/lib/python3.5/site-packages/setuptools-39.1.0-py3.5.egg new file mode 100755 index 0000000..c93cfda Binary files /dev/null and b/meta_updater/venv/lib/python3.5/site-packages/setuptools-39.1.0-py3.5.egg differ diff --git a/meta_updater/venv/lib/python3.5/site-packages/setuptools.pth b/meta_updater/venv/lib/python3.5/site-packages/setuptools.pth new file mode 100755 index 0000000..9cbfe51 --- /dev/null +++ b/meta_updater/venv/lib/python3.5/site-packages/setuptools.pth @@ -0,0 +1 @@ +./setuptools-39.1.0-py3.5.egg diff --git a/meta_updater/venv/lib64/python3.5/site-packages/easy-install.pth b/meta_updater/venv/lib64/python3.5/site-packages/easy-install.pth new file mode 100755 index 0000000..8af99eb --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/easy-install.pth @@ -0,0 +1,2 @@ +./setuptools-39.1.0-py3.5.egg +./pip-10.0.1-py3.5.egg diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO new file mode 100755 index 0000000..c91d709 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/PKG-INFO @@ -0,0 +1,69 @@ +Metadata-Version: 2.1 +Name: pip +Version: 10.0.1 +Summary: The PyPA recommended tool for installing Python packages. +Home-page: https://pip.pypa.io/ +Author: The pip developers +Author-email: python-virtualenv@groups.google.com +License: MIT +Description: pip + === + + The `PyPA recommended`_ tool for installing Python packages. + + .. image:: https://img.shields.io/pypi/v/pip.svg + :target: https://pypi.org/project/pip/ + + .. image:: https://img.shields.io/travis/pypa/pip/master.svg + :target: http://travis-ci.org/pypa/pip + + .. image:: https://img.shields.io/appveyor/ci/pypa/pip.svg + :target: https://ci.appveyor.com/project/pypa/pip/history + + .. image:: https://readthedocs.org/projects/pip/badge/?version=latest + :target: https://pip.pypa.io/en/latest + + * `Installation`_ + * `Documentation`_ + * `Changelog`_ + * `GitHub Page`_ + * `Issue Tracking`_ + * `User mailing list`_ + * `Dev mailing list`_ + * User IRC: #pypa on Freenode. + * Dev IRC: #pypa-dev on Freenode. + + Code of Conduct + --------------- + + Everyone interacting in the pip project's codebases, issue trackers, chat + rooms and mailing lists is expected to follow the `PyPA Code of Conduct`_. + + .. _PyPA recommended: https://packaging.python.org/en/latest/current/ + .. _Installation: https://pip.pypa.io/en/stable/installing.html + .. _Documentation: https://pip.pypa.io/en/stable/ + .. _Changelog: https://pip.pypa.io/en/stable/news.html + .. _GitHub Page: https://github.com/pypa/pip + .. _Issue Tracking: https://github.com/pypa/pip/issues + .. _User mailing list: http://groups.google.com/group/python-virtualenv + .. _Dev mailing list: http://groups.google.com/group/pypa-dev + .. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ + +Keywords: easy_install distutils setuptools egg virtualenv +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Build Tools +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.* +Provides-Extra: testing diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt new file mode 100755 index 0000000..5a15329 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/SOURCES.txt @@ -0,0 +1,347 @@ +AUTHORS.txt +LICENSE.txt +MANIFEST.in +NEWS.rst +README.rst +pyproject.toml +setup.cfg +setup.py +docs/Makefile +docs/__init__.py +docs/conf.py +docs/configuration.rst +docs/cookbook.rst +docs/development.rst +docs/docutils.conf +docs/index.rst +docs/installing.rst +docs/logic.rst +docs/make.bat +docs/news.rst +docs/pipext.py +docs/quickstart.rst +docs/usage.rst +docs/user_guide.rst +docs/man/pip.rst +docs/man/commands/check.rst +docs/man/commands/config.rst +docs/man/commands/download.rst +docs/man/commands/freeze.rst +docs/man/commands/hash.rst +docs/man/commands/help.rst +docs/man/commands/install.rst +docs/man/commands/list.rst +docs/man/commands/search.rst +docs/man/commands/show.rst +docs/man/commands/uninstall.rst +docs/man/commands/wheel.rst +docs/reference/index.rst +docs/reference/pip.rst +docs/reference/pip_check.rst +docs/reference/pip_config.rst +docs/reference/pip_download.rst +docs/reference/pip_freeze.rst +docs/reference/pip_hash.rst +docs/reference/pip_install.rst +docs/reference/pip_list.rst +docs/reference/pip_search.rst +docs/reference/pip_show.rst +docs/reference/pip_uninstall.rst +docs/reference/pip_wheel.rst +src/pip/__init__.py +src/pip/__main__.py +src/pip.egg-info/PKG-INFO +src/pip.egg-info/SOURCES.txt +src/pip.egg-info/dependency_links.txt +src/pip.egg-info/entry_points.txt +src/pip.egg-info/not-zip-safe +src/pip.egg-info/requires.txt +src/pip.egg-info/top_level.txt +src/pip/_internal/__init__.py +src/pip/_internal/basecommand.py +src/pip/_internal/baseparser.py +src/pip/_internal/build_env.py +src/pip/_internal/cache.py +src/pip/_internal/cmdoptions.py +src/pip/_internal/compat.py +src/pip/_internal/configuration.py +src/pip/_internal/download.py +src/pip/_internal/exceptions.py +src/pip/_internal/index.py +src/pip/_internal/locations.py +src/pip/_internal/pep425tags.py +src/pip/_internal/resolve.py +src/pip/_internal/status_codes.py +src/pip/_internal/wheel.py +src/pip/_internal/commands/__init__.py +src/pip/_internal/commands/check.py +src/pip/_internal/commands/completion.py +src/pip/_internal/commands/configuration.py +src/pip/_internal/commands/download.py +src/pip/_internal/commands/freeze.py +src/pip/_internal/commands/hash.py +src/pip/_internal/commands/help.py +src/pip/_internal/commands/install.py +src/pip/_internal/commands/list.py +src/pip/_internal/commands/search.py +src/pip/_internal/commands/show.py +src/pip/_internal/commands/uninstall.py +src/pip/_internal/commands/wheel.py +src/pip/_internal/models/__init__.py +src/pip/_internal/models/index.py +src/pip/_internal/operations/__init__.py +src/pip/_internal/operations/check.py +src/pip/_internal/operations/freeze.py +src/pip/_internal/operations/prepare.py +src/pip/_internal/req/__init__.py +src/pip/_internal/req/req_file.py +src/pip/_internal/req/req_install.py +src/pip/_internal/req/req_set.py +src/pip/_internal/req/req_uninstall.py +src/pip/_internal/utils/__init__.py +src/pip/_internal/utils/appdirs.py +src/pip/_internal/utils/deprecation.py +src/pip/_internal/utils/encoding.py +src/pip/_internal/utils/filesystem.py +src/pip/_internal/utils/glibc.py +src/pip/_internal/utils/hashes.py +src/pip/_internal/utils/logging.py +src/pip/_internal/utils/misc.py +src/pip/_internal/utils/outdated.py +src/pip/_internal/utils/packaging.py +src/pip/_internal/utils/setuptools_build.py +src/pip/_internal/utils/temp_dir.py +src/pip/_internal/utils/typing.py +src/pip/_internal/utils/ui.py +src/pip/_internal/vcs/__init__.py +src/pip/_internal/vcs/bazaar.py +src/pip/_internal/vcs/git.py +src/pip/_internal/vcs/mercurial.py +src/pip/_internal/vcs/subversion.py +src/pip/_vendor/README.rst +src/pip/_vendor/__init__.py +src/pip/_vendor/appdirs.py +src/pip/_vendor/distro.py +src/pip/_vendor/ipaddress.py +src/pip/_vendor/pyparsing.py +src/pip/_vendor/retrying.py +src/pip/_vendor/six.py +src/pip/_vendor/vendor.txt +src/pip/_vendor/cachecontrol/__init__.py +src/pip/_vendor/cachecontrol/_cmd.py +src/pip/_vendor/cachecontrol/adapter.py +src/pip/_vendor/cachecontrol/cache.py +src/pip/_vendor/cachecontrol/compat.py +src/pip/_vendor/cachecontrol/controller.py +src/pip/_vendor/cachecontrol/filewrapper.py +src/pip/_vendor/cachecontrol/heuristics.py +src/pip/_vendor/cachecontrol/serialize.py +src/pip/_vendor/cachecontrol/wrapper.py +src/pip/_vendor/cachecontrol/caches/__init__.py +src/pip/_vendor/cachecontrol/caches/file_cache.py +src/pip/_vendor/cachecontrol/caches/redis_cache.py +src/pip/_vendor/certifi/__init__.py +src/pip/_vendor/certifi/__main__.py +src/pip/_vendor/certifi/cacert.pem +src/pip/_vendor/certifi/core.py +src/pip/_vendor/chardet/__init__.py +src/pip/_vendor/chardet/big5freq.py +src/pip/_vendor/chardet/big5prober.py +src/pip/_vendor/chardet/chardistribution.py +src/pip/_vendor/chardet/charsetgroupprober.py +src/pip/_vendor/chardet/charsetprober.py +src/pip/_vendor/chardet/codingstatemachine.py +src/pip/_vendor/chardet/compat.py +src/pip/_vendor/chardet/cp949prober.py +src/pip/_vendor/chardet/enums.py +src/pip/_vendor/chardet/escprober.py +src/pip/_vendor/chardet/escsm.py +src/pip/_vendor/chardet/eucjpprober.py +src/pip/_vendor/chardet/euckrfreq.py +src/pip/_vendor/chardet/euckrprober.py +src/pip/_vendor/chardet/euctwfreq.py +src/pip/_vendor/chardet/euctwprober.py +src/pip/_vendor/chardet/gb2312freq.py +src/pip/_vendor/chardet/gb2312prober.py +src/pip/_vendor/chardet/hebrewprober.py +src/pip/_vendor/chardet/jisfreq.py +src/pip/_vendor/chardet/jpcntx.py +src/pip/_vendor/chardet/langbulgarianmodel.py +src/pip/_vendor/chardet/langcyrillicmodel.py +src/pip/_vendor/chardet/langgreekmodel.py +src/pip/_vendor/chardet/langhebrewmodel.py +src/pip/_vendor/chardet/langhungarianmodel.py +src/pip/_vendor/chardet/langthaimodel.py +src/pip/_vendor/chardet/langturkishmodel.py +src/pip/_vendor/chardet/latin1prober.py +src/pip/_vendor/chardet/mbcharsetprober.py +src/pip/_vendor/chardet/mbcsgroupprober.py +src/pip/_vendor/chardet/mbcssm.py +src/pip/_vendor/chardet/sbcharsetprober.py +src/pip/_vendor/chardet/sbcsgroupprober.py +src/pip/_vendor/chardet/sjisprober.py +src/pip/_vendor/chardet/universaldetector.py +src/pip/_vendor/chardet/utf8prober.py +src/pip/_vendor/chardet/version.py +src/pip/_vendor/chardet/cli/__init__.py +src/pip/_vendor/chardet/cli/chardetect.py +src/pip/_vendor/colorama/__init__.py +src/pip/_vendor/colorama/ansi.py +src/pip/_vendor/colorama/ansitowin32.py +src/pip/_vendor/colorama/initialise.py +src/pip/_vendor/colorama/win32.py +src/pip/_vendor/colorama/winterm.py +src/pip/_vendor/distlib/__init__.py +src/pip/_vendor/distlib/compat.py +src/pip/_vendor/distlib/database.py +src/pip/_vendor/distlib/index.py +src/pip/_vendor/distlib/locators.py +src/pip/_vendor/distlib/manifest.py +src/pip/_vendor/distlib/markers.py +src/pip/_vendor/distlib/metadata.py +src/pip/_vendor/distlib/resources.py +src/pip/_vendor/distlib/scripts.py +src/pip/_vendor/distlib/t32.exe +src/pip/_vendor/distlib/t64.exe +src/pip/_vendor/distlib/util.py +src/pip/_vendor/distlib/version.py +src/pip/_vendor/distlib/w32.exe +src/pip/_vendor/distlib/w64.exe +src/pip/_vendor/distlib/wheel.py +src/pip/_vendor/distlib/_backport/__init__.py +src/pip/_vendor/distlib/_backport/misc.py +src/pip/_vendor/distlib/_backport/shutil.py +src/pip/_vendor/distlib/_backport/sysconfig.cfg +src/pip/_vendor/distlib/_backport/sysconfig.py +src/pip/_vendor/distlib/_backport/tarfile.py +src/pip/_vendor/html5lib/__init__.py +src/pip/_vendor/html5lib/_ihatexml.py +src/pip/_vendor/html5lib/_inputstream.py +src/pip/_vendor/html5lib/_tokenizer.py +src/pip/_vendor/html5lib/_utils.py +src/pip/_vendor/html5lib/constants.py +src/pip/_vendor/html5lib/html5parser.py +src/pip/_vendor/html5lib/serializer.py +src/pip/_vendor/html5lib/_trie/__init__.py +src/pip/_vendor/html5lib/_trie/_base.py +src/pip/_vendor/html5lib/_trie/datrie.py +src/pip/_vendor/html5lib/_trie/py.py +src/pip/_vendor/html5lib/filters/__init__.py +src/pip/_vendor/html5lib/filters/alphabeticalattributes.py +src/pip/_vendor/html5lib/filters/base.py +src/pip/_vendor/html5lib/filters/inject_meta_charset.py +src/pip/_vendor/html5lib/filters/lint.py +src/pip/_vendor/html5lib/filters/optionaltags.py +src/pip/_vendor/html5lib/filters/sanitizer.py +src/pip/_vendor/html5lib/filters/whitespace.py +src/pip/_vendor/html5lib/treeadapters/__init__.py +src/pip/_vendor/html5lib/treeadapters/genshi.py +src/pip/_vendor/html5lib/treeadapters/sax.py +src/pip/_vendor/html5lib/treebuilders/__init__.py +src/pip/_vendor/html5lib/treebuilders/base.py +src/pip/_vendor/html5lib/treebuilders/dom.py +src/pip/_vendor/html5lib/treebuilders/etree.py +src/pip/_vendor/html5lib/treebuilders/etree_lxml.py +src/pip/_vendor/html5lib/treewalkers/__init__.py +src/pip/_vendor/html5lib/treewalkers/base.py +src/pip/_vendor/html5lib/treewalkers/dom.py +src/pip/_vendor/html5lib/treewalkers/etree.py +src/pip/_vendor/html5lib/treewalkers/etree_lxml.py +src/pip/_vendor/html5lib/treewalkers/genshi.py +src/pip/_vendor/idna/__init__.py +src/pip/_vendor/idna/codec.py +src/pip/_vendor/idna/compat.py +src/pip/_vendor/idna/core.py +src/pip/_vendor/idna/idnadata.py +src/pip/_vendor/idna/intranges.py +src/pip/_vendor/idna/package_data.py +src/pip/_vendor/idna/uts46data.py +src/pip/_vendor/lockfile/__init__.py +src/pip/_vendor/lockfile/linklockfile.py +src/pip/_vendor/lockfile/mkdirlockfile.py +src/pip/_vendor/lockfile/pidlockfile.py +src/pip/_vendor/lockfile/sqlitelockfile.py +src/pip/_vendor/lockfile/symlinklockfile.py +src/pip/_vendor/msgpack/__init__.py +src/pip/_vendor/msgpack/_version.py +src/pip/_vendor/msgpack/exceptions.py +src/pip/_vendor/msgpack/fallback.py +src/pip/_vendor/packaging/__about__.py +src/pip/_vendor/packaging/__init__.py +src/pip/_vendor/packaging/_compat.py +src/pip/_vendor/packaging/_structures.py +src/pip/_vendor/packaging/markers.py +src/pip/_vendor/packaging/requirements.py +src/pip/_vendor/packaging/specifiers.py +src/pip/_vendor/packaging/utils.py +src/pip/_vendor/packaging/version.py +src/pip/_vendor/pkg_resources/__init__.py +src/pip/_vendor/pkg_resources/py31compat.py +src/pip/_vendor/progress/__init__.py +src/pip/_vendor/progress/bar.py +src/pip/_vendor/progress/counter.py +src/pip/_vendor/progress/helpers.py +src/pip/_vendor/progress/spinner.py +src/pip/_vendor/pytoml/__init__.py +src/pip/_vendor/pytoml/core.py +src/pip/_vendor/pytoml/parser.py +src/pip/_vendor/pytoml/writer.py +src/pip/_vendor/requests/__init__.py +src/pip/_vendor/requests/__version__.py +src/pip/_vendor/requests/_internal_utils.py +src/pip/_vendor/requests/adapters.py +src/pip/_vendor/requests/api.py +src/pip/_vendor/requests/auth.py +src/pip/_vendor/requests/certs.py +src/pip/_vendor/requests/compat.py +src/pip/_vendor/requests/cookies.py +src/pip/_vendor/requests/exceptions.py +src/pip/_vendor/requests/help.py +src/pip/_vendor/requests/hooks.py +src/pip/_vendor/requests/models.py +src/pip/_vendor/requests/packages.py +src/pip/_vendor/requests/sessions.py +src/pip/_vendor/requests/status_codes.py +src/pip/_vendor/requests/structures.py +src/pip/_vendor/requests/utils.py +src/pip/_vendor/urllib3/__init__.py +src/pip/_vendor/urllib3/_collections.py +src/pip/_vendor/urllib3/connection.py +src/pip/_vendor/urllib3/connectionpool.py +src/pip/_vendor/urllib3/exceptions.py +src/pip/_vendor/urllib3/fields.py +src/pip/_vendor/urllib3/filepost.py +src/pip/_vendor/urllib3/poolmanager.py +src/pip/_vendor/urllib3/request.py +src/pip/_vendor/urllib3/response.py +src/pip/_vendor/urllib3/contrib/__init__.py +src/pip/_vendor/urllib3/contrib/appengine.py +src/pip/_vendor/urllib3/contrib/ntlmpool.py +src/pip/_vendor/urllib3/contrib/pyopenssl.py +src/pip/_vendor/urllib3/contrib/securetransport.py +src/pip/_vendor/urllib3/contrib/socks.py +src/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +src/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +src/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +src/pip/_vendor/urllib3/packages/__init__.py +src/pip/_vendor/urllib3/packages/ordered_dict.py +src/pip/_vendor/urllib3/packages/six.py +src/pip/_vendor/urllib3/packages/backports/__init__.py +src/pip/_vendor/urllib3/packages/backports/makefile.py +src/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py +src/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py +src/pip/_vendor/urllib3/util/__init__.py +src/pip/_vendor/urllib3/util/connection.py +src/pip/_vendor/urllib3/util/request.py +src/pip/_vendor/urllib3/util/response.py +src/pip/_vendor/urllib3/util/retry.py +src/pip/_vendor/urllib3/util/selectors.py +src/pip/_vendor/urllib3/util/ssl_.py +src/pip/_vendor/urllib3/util/timeout.py +src/pip/_vendor/urllib3/util/url.py +src/pip/_vendor/urllib3/util/wait.py +src/pip/_vendor/webencodings/__init__.py +src/pip/_vendor/webencodings/labels.py +src/pip/_vendor/webencodings/mklabels.py +src/pip/_vendor/webencodings/tests.py +src/pip/_vendor/webencodings/x_user_defined.py \ No newline at end of file diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt new file mode 100755 index 0000000..d6133a2 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +pip = pip._internal:main +pip3 = pip._internal:main +pip3.5 = pip._internal:main + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe new file mode 100755 index 0000000..d3f5a12 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/not-zip-safe @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt new file mode 100755 index 0000000..fdea1b5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/requires.txt @@ -0,0 +1,8 @@ + +[testing] +pytest +mock +pretend +scripttest>=1.3 +virtualenv>=1.10 +freezegun diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt new file mode 100755 index 0000000..a1b589e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/EGG-INFO/top_level.txt @@ -0,0 +1 @@ +pip diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py new file mode 100755 index 0000000..0a3b850 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__init__.py @@ -0,0 +1 @@ +__version__ = "10.0.1" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py new file mode 100755 index 0000000..a128ee3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/__main__.py @@ -0,0 +1,19 @@ +from __future__ import absolute_import + +import os +import sys + +# If we are running from a wheel, add the wheel to sys.path +# This allows the usage python pip-*.whl/pip install pip-*.whl +if __package__ == '': + # __file__ is pip-*.whl/pip/__main__.py + # first dirname call strips of '/__main__.py', second strips off '/pip' + # Resulting path is the name of the wheel itself + # Add that to sys.path so we can import pip + path = os.path.dirname(os.path.dirname(__file__)) + sys.path.insert(0, path) + +from pip._internal import main as _main # noqa + +if __name__ == '__main__': + sys.exit(_main()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py new file mode 100755 index 0000000..d713b0d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/__init__.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python +from __future__ import absolute_import + +import locale +import logging +import os +import optparse +import warnings + +import sys + +# 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks, +# but if invoked (i.e. imported), it will issue a warning to stderr if socks +# isn't available. requests unconditionally imports urllib3's socks contrib +# module, triggering this warning. The warning breaks DEP-8 tests (because of +# the stderr output) and is just plain annoying in normal usage. I don't want +# to add socks as yet another dependency for pip, nor do I want to allow-stder +# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to +# be done before the import of pip.vcs. +from pip._vendor.urllib3.exceptions import DependencyWarning +warnings.filterwarnings("ignore", category=DependencyWarning) # noqa + +# We want to inject the use of SecureTransport as early as possible so that any +# references or sessions or what have you are ensured to have it, however we +# only want to do this in the case that we're running on macOS and the linked +# OpenSSL is too old to handle TLSv1.2 +try: + import ssl +except ImportError: + pass +else: + # Checks for OpenSSL 1.0.1 on MacOS + if sys.platform == "darwin" and ssl.OPENSSL_VERSION_NUMBER < 0x1000100f: + try: + from pip._vendor.urllib3.contrib import securetransport + except (ImportError, OSError): + pass + else: + securetransport.inject_into_urllib3() + +from pip import __version__ +from pip._internal import cmdoptions +from pip._internal.exceptions import CommandError, PipError +from pip._internal.utils.misc import get_installed_distributions, get_prog +from pip._internal.utils import deprecation +from pip._internal.vcs import git, mercurial, subversion, bazaar # noqa +from pip._internal.baseparser import ( + ConfigOptionParser, UpdatingDefaultsHelpFormatter, +) +from pip._internal.commands import get_summaries, get_similar_commands +from pip._internal.commands import commands_dict +from pip._vendor.urllib3.exceptions import InsecureRequestWarning + +logger = logging.getLogger(__name__) + +# Hide the InsecureRequestWarning from urllib3 +warnings.filterwarnings("ignore", category=InsecureRequestWarning) + + +def autocomplete(): + """Command and option completion for the main option parser (and options) + and its subcommands (and options). + + Enable by sourcing one of the completion shell scripts (bash, zsh or fish). + """ + # Don't complete if user hasn't sourced bash_completion file. + if 'PIP_AUTO_COMPLETE' not in os.environ: + return + cwords = os.environ['COMP_WORDS'].split()[1:] + cword = int(os.environ['COMP_CWORD']) + try: + current = cwords[cword - 1] + except IndexError: + current = '' + + subcommands = [cmd for cmd, summary in get_summaries()] + options = [] + # subcommand + try: + subcommand_name = [w for w in cwords if w in subcommands][0] + except IndexError: + subcommand_name = None + + parser = create_main_parser() + # subcommand options + if subcommand_name: + # special case: 'help' subcommand has no options + if subcommand_name == 'help': + sys.exit(1) + # special case: list locally installed dists for show and uninstall + should_list_installed = ( + subcommand_name in ['show', 'uninstall'] and + not current.startswith('-') + ) + if should_list_installed: + installed = [] + lc = current.lower() + for dist in get_installed_distributions(local_only=True): + if dist.key.startswith(lc) and dist.key not in cwords[1:]: + installed.append(dist.key) + # if there are no dists installed, fall back to option completion + if installed: + for dist in installed: + print(dist) + sys.exit(1) + + subcommand = commands_dict[subcommand_name]() + + for opt in subcommand.parser.option_list_all: + if opt.help != optparse.SUPPRESS_HELP: + for opt_str in opt._long_opts + opt._short_opts: + options.append((opt_str, opt.nargs)) + + # filter out previously specified options from available options + prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] + options = [(x, v) for (x, v) in options if x not in prev_opts] + # filter options by current input + options = [(k, v) for k, v in options if k.startswith(current)] + for option in options: + opt_label = option[0] + # append '=' to options which require args + if option[1] and option[0][:2] == "--": + opt_label += '=' + print(opt_label) + else: + # show main parser options only when necessary + if current.startswith('-') or current.startswith('--'): + opts = [i.option_list for i in parser.option_groups] + opts.append(parser.option_list) + opts = (o for it in opts for o in it) + + for opt in opts: + if opt.help != optparse.SUPPRESS_HELP: + subcommands += opt._long_opts + opt._short_opts + + print(' '.join([x for x in subcommands if x.startswith(current)])) + sys.exit(1) + + +def create_main_parser(): + parser_kw = { + 'usage': '\n%prog <command> [options]', + 'add_help_option': False, + 'formatter': UpdatingDefaultsHelpFormatter(), + 'name': 'global', + 'prog': get_prog(), + } + + parser = ConfigOptionParser(**parser_kw) + parser.disable_interspersed_args() + + pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + parser.version = 'pip %s from %s (python %s)' % ( + __version__, pip_pkg_dir, sys.version[:3], + ) + + # add the general options + gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) + parser.add_option_group(gen_opts) + + parser.main = True # so the help formatter knows + + # create command listing for description + command_summaries = get_summaries() + description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] + parser.description = '\n'.join(description) + + return parser + + +def parseopts(args): + parser = create_main_parser() + + # Note: parser calls disable_interspersed_args(), so the result of this + # call is to split the initial args into the general options before the + # subcommand and everything else. + # For example: + # args: ['--timeout=5', 'install', '--user', 'INITools'] + # general_options: ['--timeout==5'] + # args_else: ['install', '--user', 'INITools'] + general_options, args_else = parser.parse_args(args) + + # --version + if general_options.version: + sys.stdout.write(parser.version) + sys.stdout.write(os.linesep) + sys.exit() + + # pip || pip help -> print_help() + if not args_else or (args_else[0] == 'help' and len(args_else) == 1): + parser.print_help() + sys.exit() + + # the subcommand name + cmd_name = args_else[0] + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "%s"' % cmd_name] + if guess: + msg.append('maybe you meant "%s"' % guess) + + raise CommandError(' - '.join(msg)) + + # all the args without the subcommand + cmd_args = args[:] + cmd_args.remove(cmd_name) + + return cmd_name, cmd_args + + +def check_isolated(args): + isolated = False + + if "--isolated" in args: + isolated = True + + return isolated + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + # Configure our deprecation warnings to be sent through loggers + deprecation.install_warning_logger() + + autocomplete() + + try: + cmd_name, cmd_args = parseopts(args) + except PipError as exc: + sys.stderr.write("ERROR: %s" % exc) + sys.stderr.write(os.linesep) + sys.exit(1) + + # Needed for locale.getpreferredencoding(False) to work + # in pip._internal.utils.encoding.auto_decode + try: + locale.setlocale(locale.LC_ALL, '') + except locale.Error as e: + # setlocale can apparently crash if locale are uninitialized + logger.debug("Ignoring error %s when setting locale", e) + command = commands_dict[cmd_name](isolated=check_isolated(cmd_args)) + return command.main(cmd_args) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py new file mode 100755 index 0000000..e900928 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/basecommand.py @@ -0,0 +1,373 @@ +"""Base Command class, and related routines""" +from __future__ import absolute_import + +import logging +import logging.config +import optparse +import os +import sys +import warnings + +from pip._internal import cmdoptions +from pip._internal.baseparser import ( + ConfigOptionParser, UpdatingDefaultsHelpFormatter, +) +from pip._internal.compat import WINDOWS +from pip._internal.download import PipSession +from pip._internal.exceptions import ( + BadCommand, CommandError, InstallationError, PreviousBuildDirError, + UninstallationError, +) +from pip._internal.index import PackageFinder +from pip._internal.locations import running_under_virtualenv +from pip._internal.req.req_file import parse_requirements +from pip._internal.req.req_install import InstallRequirement +from pip._internal.status_codes import ( + ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR, + VIRTUALENV_NOT_FOUND, +) +from pip._internal.utils import deprecation +from pip._internal.utils.logging import IndentingFormatter +from pip._internal.utils.misc import get_prog, normalize_path +from pip._internal.utils.outdated import pip_version_check +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + +__all__ = ['Command'] + +logger = logging.getLogger(__name__) + + +class Command(object): + name = None # type: Optional[str] + usage = None # type: Optional[str] + hidden = False # type: bool + ignore_require_venv = False # type: bool + log_streams = ("ext://sys.stdout", "ext://sys.stderr") + + def __init__(self, isolated=False): + parser_kw = { + 'usage': self.usage, + 'prog': '%s %s' % (get_prog(), self.name), + 'formatter': UpdatingDefaultsHelpFormatter(), + 'add_help_option': False, + 'name': self.name, + 'description': self.__doc__, + 'isolated': isolated, + } + + self.parser = ConfigOptionParser(**parser_kw) + + # Commands should add options to this option group + optgroup_name = '%s Options' % self.name.capitalize() + self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) + + # Add the general options + gen_opts = cmdoptions.make_option_group( + cmdoptions.general_group, + self.parser, + ) + self.parser.add_option_group(gen_opts) + + def _build_session(self, options, retries=None, timeout=None): + session = PipSession( + cache=( + normalize_path(os.path.join(options.cache_dir, "http")) + if options.cache_dir else None + ), + retries=retries if retries is not None else options.retries, + insecure_hosts=options.trusted_hosts, + ) + + # Handle custom ca-bundles from the user + if options.cert: + session.verify = options.cert + + # Handle SSL client certificate + if options.client_cert: + session.cert = options.client_cert + + # Handle timeouts + if options.timeout or timeout: + session.timeout = ( + timeout if timeout is not None else options.timeout + ) + + # Handle configured proxies + if options.proxy: + session.proxies = { + "http": options.proxy, + "https": options.proxy, + } + + # Determine if we can prompt the user for authentication or not + session.auth.prompting = not options.no_input + + return session + + def parse_args(self, args): + # factored out for testability + return self.parser.parse_args(args) + + def main(self, args): + options, args = self.parse_args(args) + + # Set verbosity so that it can be used elsewhere. + self.verbosity = options.verbose - options.quiet + + if self.verbosity >= 1: + level = "DEBUG" + elif self.verbosity == -1: + level = "WARNING" + elif self.verbosity == -2: + level = "ERROR" + elif self.verbosity <= -3: + level = "CRITICAL" + else: + level = "INFO" + + # The root logger should match the "console" level *unless* we + # specified "--log" to send debug logs to a file. + root_level = level + if options.log: + root_level = "DEBUG" + + logger_class = "pip._internal.utils.logging.ColorizedStreamHandler" + handler_class = "pip._internal.utils.logging.BetterRotatingFileHandler" + + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "filters": { + "exclude_warnings": { + "()": "pip._internal.utils.logging.MaxLevelFilter", + "level": logging.WARNING, + }, + }, + "formatters": { + "indent": { + "()": IndentingFormatter, + "format": "%(message)s", + }, + }, + "handlers": { + "console": { + "level": level, + "class": logger_class, + "no_color": options.no_color, + "stream": self.log_streams[0], + "filters": ["exclude_warnings"], + "formatter": "indent", + }, + "console_errors": { + "level": "WARNING", + "class": logger_class, + "no_color": options.no_color, + "stream": self.log_streams[1], + "formatter": "indent", + }, + "user_log": { + "level": "DEBUG", + "class": handler_class, + "filename": options.log or "/dev/null", + "delay": True, + "formatter": "indent", + }, + }, + "root": { + "level": root_level, + "handlers": list(filter(None, [ + "console", + "console_errors", + "user_log" if options.log else None, + ])), + }, + # Disable any logging besides WARNING unless we have DEBUG level + # logging enabled. These use both pip._vendor and the bare names + # for the case where someone unbundles our libraries. + "loggers": { + name: { + "level": ( + "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" + ) + } for name in [ + "pip._vendor", "distlib", "requests", "urllib3" + ] + }, + }) + + if sys.version_info[:2] == (3, 3): + warnings.warn( + "Python 3.3 supported has been deprecated and support for it " + "will be dropped in the future. Please upgrade your Python.", + deprecation.RemovedInPip11Warning, + ) + + # TODO: try to get these passing down from the command? + # without resorting to os.environ to hold these. + + if options.no_input: + os.environ['PIP_NO_INPUT'] = '1' + + if options.exists_action: + os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) + + if options.require_venv and not self.ignore_require_venv: + # If a venv is required check if it can really be found + if not running_under_virtualenv(): + logger.critical( + 'Could not find an activated virtualenv (required).' + ) + sys.exit(VIRTUALENV_NOT_FOUND) + + original_root_handlers = set(logging.root.handlers) + + try: + status = self.run(options, args) + # FIXME: all commands should return an exit status + # and when it is done, isinstance is not needed anymore + if isinstance(status, int): + return status + except PreviousBuildDirError as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return PREVIOUS_BUILD_DIR_ERROR + except (InstallationError, UninstallationError, BadCommand) as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except CommandError as exc: + logger.critical('ERROR: %s', exc) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except KeyboardInterrupt: + logger.critical('Operation cancelled by user') + logger.debug('Exception information:', exc_info=True) + + return ERROR + except: + logger.critical('Exception:', exc_info=True) + + return UNKNOWN_ERROR + finally: + # Check if we're using the latest version of pip available + if (not options.disable_pip_version_check and not + getattr(options, "no_index", False)): + with self._build_session( + options, + retries=0, + timeout=min(5, options.timeout)) as session: + pip_version_check(session, options) + # Avoid leaking loggers + for handler in set(logging.root.handlers) - original_root_handlers: + # this method benefit from the Logger class internal lock + logging.root.removeHandler(handler) + + return SUCCESS + + +class RequirementCommand(Command): + + @staticmethod + def populate_requirement_set(requirement_set, args, options, finder, + session, name, wheel_cache): + """ + Marshal cmd line args into a requirement set. + """ + # NOTE: As a side-effect, options.require_hashes and + # requirement_set.require_hashes may be updated + + for filename in options.constraints: + for req_to_add in parse_requirements( + filename, + constraint=True, finder=finder, options=options, + session=session, wheel_cache=wheel_cache): + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in args: + req_to_add = InstallRequirement.from_line( + req, None, isolated=options.isolated_mode, + wheel_cache=wheel_cache + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in options.editables: + req_to_add = InstallRequirement.from_editable( + req, + isolated=options.isolated_mode, + wheel_cache=wheel_cache + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for filename in options.requirements: + for req_to_add in parse_requirements( + filename, + finder=finder, options=options, session=session, + wheel_cache=wheel_cache): + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + # If --require-hashes was a line in a requirements file, tell + # RequirementSet about it: + requirement_set.require_hashes = options.require_hashes + + if not (args or options.editables or options.requirements): + opts = {'name': name} + if options.find_links: + raise CommandError( + 'You must give at least one requirement to %(name)s ' + '(maybe you meant "pip %(name)s %(links)s"?)' % + dict(opts, links=' '.join(options.find_links))) + else: + raise CommandError( + 'You must give at least one requirement to %(name)s ' + '(see "pip help %(name)s")' % opts) + + # On Windows, any operation modifying pip should be run as: + # python -m pip ... + # See https://github.com/pypa/pip/issues/1299 for more discussion + should_show_use_python_msg = ( + WINDOWS and + requirement_set.has_requirement("pip") and + os.path.basename(sys.argv[0]).startswith("pip") + ) + if should_show_use_python_msg: + new_command = [ + sys.executable, "-m", "pip" + ] + sys.argv[1:] + raise CommandError( + 'To modify pip, please run the following command:\n{}' + .format(" ".join(new_command)) + ) + + def _build_package_finder(self, options, session, + platform=None, python_versions=None, + abi=None, implementation=None): + """ + Create a package finder appropriate to this requirement command. + """ + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + return PackageFinder( + find_links=options.find_links, + format_control=options.format_control, + index_urls=index_urls, + trusted_hosts=options.trusted_hosts, + allow_all_prereleases=options.pre, + process_dependency_links=options.process_dependency_links, + session=session, + platform=platform, + versions=python_versions, + abi=abi, + implementation=implementation, + ) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py new file mode 100755 index 0000000..ed28a1b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/baseparser.py @@ -0,0 +1,240 @@ +"""Base option parser setup""" +from __future__ import absolute_import + +import logging +import optparse +import sys +import textwrap +from distutils.util import strtobool + +from pip._vendor.six import string_types + +from pip._internal.compat import get_terminal_size +from pip._internal.configuration import Configuration, ConfigurationError + +logger = logging.getLogger(__name__) + + +class PrettyHelpFormatter(optparse.IndentedHelpFormatter): + """A prettier/less verbose help formatter for optparse.""" + + def __init__(self, *args, **kwargs): + # help position must be aligned with __init__.parseopts.description + kwargs['max_help_position'] = 30 + kwargs['indent_increment'] = 1 + kwargs['width'] = get_terminal_size()[0] - 2 + optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) + + def format_option_strings(self, option): + return self._format_option_strings(option, ' <%s>', ', ') + + def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '): + """ + Return a comma-separated list of option strings and metavars. + + :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') + :param mvarfmt: metavar format string - evaluated as mvarfmt % metavar + :param optsep: separator + """ + opts = [] + + if option._short_opts: + opts.append(option._short_opts[0]) + if option._long_opts: + opts.append(option._long_opts[0]) + if len(opts) > 1: + opts.insert(1, optsep) + + if option.takes_value(): + metavar = option.metavar or option.dest.lower() + opts.append(mvarfmt % metavar.lower()) + + return ''.join(opts) + + def format_heading(self, heading): + if heading == 'Options': + return '' + return heading + ':\n' + + def format_usage(self, usage): + """ + Ensure there is only one newline between usage and the first heading + if there is no description. + """ + msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), " ") + return msg + + def format_description(self, description): + # leave full control over description to us + if description: + if hasattr(self.parser, 'main'): + label = 'Commands' + else: + label = 'Description' + # some doc strings have initial newlines, some don't + description = description.lstrip('\n') + # some doc strings have final newlines and spaces, some don't + description = description.rstrip() + # dedent, then reindent + description = self.indent_lines(textwrap.dedent(description), " ") + description = '%s:\n%s\n' % (label, description) + return description + else: + return '' + + def format_epilog(self, epilog): + # leave full control over epilog to us + if epilog: + return epilog + else: + return '' + + def indent_lines(self, text, indent): + new_lines = [indent + line for line in text.split('\n')] + return "\n".join(new_lines) + + +class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): + """Custom help formatter for use in ConfigOptionParser. + + This is updates the defaults before expanding them, allowing + them to show up correctly in the help listing. + """ + + def expand_default(self, option): + if self.parser is not None: + self.parser._update_defaults(self.parser.defaults) + return optparse.IndentedHelpFormatter.expand_default(self, option) + + +class CustomOptionParser(optparse.OptionParser): + + def insert_option_group(self, idx, *args, **kwargs): + """Insert an OptionGroup at a given position.""" + group = self.add_option_group(*args, **kwargs) + + self.option_groups.pop() + self.option_groups.insert(idx, group) + + return group + + @property + def option_list_all(self): + """Get a list of all options, including those in option groups.""" + res = self.option_list[:] + for i in self.option_groups: + res.extend(i.option_list) + + return res + + +class ConfigOptionParser(CustomOptionParser): + """Custom option parser which updates its defaults by checking the + configuration files and environmental variables""" + + def __init__(self, *args, **kwargs): + self.name = kwargs.pop('name') + + isolated = kwargs.pop("isolated", False) + self.config = Configuration(isolated) + + assert self.name + optparse.OptionParser.__init__(self, *args, **kwargs) + + def check_default(self, option, key, val): + try: + return option.check_value(key, val) + except optparse.OptionValueError as exc: + print("An error occurred during configuration: %s" % exc) + sys.exit(3) + + def _get_ordered_configuration_items(self): + # Configuration gives keys in an unordered manner. Order them. + override_order = ["global", self.name, ":env:"] + + # Pool the options into different groups + section_items = {name: [] for name in override_order} + for section_key, val in self.config.items(): + # ignore empty values + if not val: + logger.debug( + "Ignoring configuration key '%s' as it's value is empty.", + section_key + ) + continue + + section, key = section_key.split(".", 1) + if section in override_order: + section_items[section].append((key, val)) + + # Yield each group in their override order + for section in override_order: + for key, val in section_items[section]: + yield key, val + + def _update_defaults(self, defaults): + """Updates the given defaults with values from the config files and + the environ. Does a little special handling for certain types of + options (lists).""" + + # Accumulate complex default state. + self.values = optparse.Values(self.defaults) + late_eval = set() + # Then set the options with those values + for key, val in self._get_ordered_configuration_items(): + # '--' because configuration supports only long names + option = self.get_option('--' + key) + + # Ignore options not present in this parser. E.g. non-globals put + # in [global] by users that want them to apply to all applicable + # commands. + if option is None: + continue + + if option.action in ('store_true', 'store_false', 'count'): + val = strtobool(val) + elif option.action == 'append': + val = val.split() + val = [self.check_default(option, key, v) for v in val] + elif option.action == 'callback': + late_eval.add(option.dest) + opt_str = option.get_opt_string() + val = option.convert_value(opt_str, val) + # From take_action + args = option.callback_args or () + kwargs = option.callback_kwargs or {} + option.callback(option, opt_str, val, self, *args, **kwargs) + else: + val = self.check_default(option, key, val) + + defaults[option.dest] = val + + for key in late_eval: + defaults[key] = getattr(self.values, key) + self.values = None + return defaults + + def get_default_values(self): + """Overriding to make updating the defaults after instantiation of + the option parser possible, _update_defaults() does the dirty work.""" + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return optparse.Values(self.defaults) + + # Load the configuration, or error out in case of an error + try: + self.config.load() + except ConfigurationError as err: + self.exit(2, err.args[0]) + + defaults = self._update_defaults(self.defaults.copy()) # ours + for option in self._get_all_options(): + default = defaults.get(option.dest) + if isinstance(default, string_types): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + return optparse.Values(defaults) + + def error(self, msg): + self.print_usage(sys.stderr) + self.exit(2, "%s\n" % msg) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py new file mode 100755 index 0000000..8ad7735 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/build_env.py @@ -0,0 +1,92 @@ +"""Build Environment used for isolation during sdist building +""" + +import os +from distutils.sysconfig import get_python_lib +from sysconfig import get_paths + +from pip._internal.utils.temp_dir import TempDirectory + + +class BuildEnvironment(object): + """Creates and manages an isolated environment to install build deps + """ + + def __init__(self, no_clean): + self._temp_dir = TempDirectory(kind="build-env") + self._no_clean = no_clean + + @property + def path(self): + return self._temp_dir.path + + def __enter__(self): + self._temp_dir.create() + + self.save_path = os.environ.get('PATH', None) + self.save_pythonpath = os.environ.get('PYTHONPATH', None) + self.save_nousersite = os.environ.get('PYTHONNOUSERSITE', None) + + install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix' + install_dirs = get_paths(install_scheme, vars={ + 'base': self.path, + 'platbase': self.path, + }) + + scripts = install_dirs['scripts'] + if self.save_path: + os.environ['PATH'] = scripts + os.pathsep + self.save_path + else: + os.environ['PATH'] = scripts + os.pathsep + os.defpath + + # Note: prefer distutils' sysconfig to get the + # library paths so PyPy is correctly supported. + purelib = get_python_lib(plat_specific=0, prefix=self.path) + platlib = get_python_lib(plat_specific=1, prefix=self.path) + if purelib == platlib: + lib_dirs = purelib + else: + lib_dirs = purelib + os.pathsep + platlib + if self.save_pythonpath: + os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \ + self.save_pythonpath + else: + os.environ['PYTHONPATH'] = lib_dirs + + os.environ['PYTHONNOUSERSITE'] = '1' + + return self.path + + def __exit__(self, exc_type, exc_val, exc_tb): + if not self._no_clean: + self._temp_dir.cleanup() + + def restore_var(varname, old_value): + if old_value is None: + os.environ.pop(varname, None) + else: + os.environ[varname] = old_value + + restore_var('PATH', self.save_path) + restore_var('PYTHONPATH', self.save_pythonpath) + restore_var('PYTHONNOUSERSITE', self.save_nousersite) + + def cleanup(self): + self._temp_dir.cleanup() + + +class NoOpBuildEnvironment(BuildEnvironment): + """A no-op drop-in replacement for BuildEnvironment + """ + + def __init__(self, no_clean): + pass + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + def cleanup(self): + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py new file mode 100755 index 0000000..5547d73 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cache.py @@ -0,0 +1,202 @@ +"""Cache Management +""" + +import errno +import hashlib +import logging +import os + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal import index +from pip._internal.compat import expanduser +from pip._internal.download import path_to_url +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import InvalidWheelFilename, Wheel + +logger = logging.getLogger(__name__) + + +class Cache(object): + """An abstract class - provides cache directories for data from links + + + :param cache_dir: The root of the cache. + :param format_control: A pip.index.FormatControl object to limit + binaries being read from the cache. + :param allowed_formats: which formats of files the cache should store. + ('binary' and 'source' are the only allowed values) + """ + + def __init__(self, cache_dir, format_control, allowed_formats): + super(Cache, self).__init__() + self.cache_dir = expanduser(cache_dir) if cache_dir else None + self.format_control = format_control + self.allowed_formats = allowed_formats + + _valid_formats = {"source", "binary"} + assert self.allowed_formats.union(_valid_formats) == _valid_formats + + def _get_cache_path_parts(self, link): + """Get parts of part that must be os.path.joined with cache_dir + """ + + # We want to generate an url to use as our cache key, we don't want to + # just re-use the URL because it might have other items in the fragment + # and we don't care about those. + key_parts = [link.url_without_fragment] + if link.hash_name is not None and link.hash is not None: + key_parts.append("=".join([link.hash_name, link.hash])) + key_url = "#".join(key_parts) + + # Encode our key url with sha224, we'll use this because it has similar + # security properties to sha256, but with a shorter total output (and + # thus less secure). However the differences don't make a lot of + # difference for our use case here. + hashed = hashlib.sha224(key_url.encode()).hexdigest() + + # We want to nest the directories some to prevent having a ton of top + # level directories where we might run out of sub directories on some + # FS. + parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] + + return parts + + def _get_candidates(self, link, package_name): + can_not_cache = ( + not self.cache_dir or + not package_name or + not link + ) + if can_not_cache: + return [] + + canonical_name = canonicalize_name(package_name) + formats = index.fmt_ctl_formats( + self.format_control, canonical_name + ) + if not self.allowed_formats.intersection(formats): + return [] + + root = self.get_path_for_link(link) + try: + return os.listdir(root) + except OSError as err: + if err.errno in {errno.ENOENT, errno.ENOTDIR}: + return [] + raise + + def get_path_for_link(self, link): + """Return a directory to store cached items in for link. + """ + raise NotImplementedError() + + def get(self, link, package_name): + """Returns a link to a cached item if it exists, otherwise returns the + passed link. + """ + raise NotImplementedError() + + def _link_for_candidate(self, link, candidate): + root = self.get_path_for_link(link) + path = os.path.join(root, candidate) + + return index.Link(path_to_url(path)) + + def cleanup(self): + pass + + +class SimpleWheelCache(Cache): + """A cache of wheels for future installs. + """ + + def __init__(self, cache_dir, format_control): + super(SimpleWheelCache, self).__init__( + cache_dir, format_control, {"binary"} + ) + + def get_path_for_link(self, link): + """Return a directory to store cached wheels for link + + Because there are M wheels for any one sdist, we provide a directory + to cache them in, and then consult that directory when looking up + cache hits. + + We only insert things into the cache if they have plausible version + numbers, so that we don't contaminate the cache with things that were + not unique. E.g. ./package might have dozens of installs done for it + and build a version of 0.0...and if we built and cached a wheel, we'd + end up using the same wheel even if the source has been edited. + + :param link: The link of the sdist for which this will cache wheels. + """ + parts = self._get_cache_path_parts(link) + + # Store wheels within the root cache_dir + return os.path.join(self.cache_dir, "wheels", *parts) + + def get(self, link, package_name): + candidates = [] + + for wheel_name in self._get_candidates(link, package_name): + try: + wheel = Wheel(wheel_name) + except InvalidWheelFilename: + continue + if not wheel.supported(): + # Built for a different python/arch/etc + continue + candidates.append((wheel.support_index_min(), wheel_name)) + + if not candidates: + return link + + return self._link_for_candidate(link, min(candidates)[1]) + + +class EphemWheelCache(SimpleWheelCache): + """A SimpleWheelCache that creates it's own temporary cache directory + """ + + def __init__(self, format_control): + self._temp_dir = TempDirectory(kind="ephem-wheel-cache") + self._temp_dir.create() + + super(EphemWheelCache, self).__init__( + self._temp_dir.path, format_control + ) + + def cleanup(self): + self._temp_dir.cleanup() + + +class WheelCache(Cache): + """Wraps EphemWheelCache and SimpleWheelCache into a single Cache + + This Cache allows for gracefully degradation, using the ephem wheel cache + when a certain link is not found in the simple wheel cache first. + """ + + def __init__(self, cache_dir, format_control): + super(WheelCache, self).__init__( + cache_dir, format_control, {'binary'} + ) + self._wheel_cache = SimpleWheelCache(cache_dir, format_control) + self._ephem_cache = EphemWheelCache(format_control) + + def get_path_for_link(self, link): + return self._wheel_cache.get_path_for_link(link) + + def get_ephem_path_for_link(self, link): + return self._ephem_cache.get_path_for_link(link) + + def get(self, link, package_name): + retval = self._wheel_cache.get(link, package_name) + if retval is link: + retval = self._ephem_cache.get(link, package_name) + return retval + + def cleanup(self): + self._wheel_cache.cleanup() + self._ephem_cache.cleanup() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py new file mode 100755 index 0000000..58854e3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/cmdoptions.py @@ -0,0 +1,609 @@ +""" +shared options and groups + +The principle here is to define options once, but *not* instantiate them +globally. One reason being that options with action='append' can carry state +between parses. pip parses general options twice internally, and shouldn't +pass on state. To be consistent, all options will follow this design. + +""" +from __future__ import absolute_import + +import warnings +from functools import partial +from optparse import SUPPRESS_HELP, Option, OptionGroup + +from pip._internal.index import ( + FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_binary, +) +from pip._internal.locations import USER_CACHE_DIR, src_prefix +from pip._internal.models import PyPI +from pip._internal.utils.hashes import STRONG_HASHES +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.ui import BAR_TYPES + +if MYPY_CHECK_RUNNING: + from typing import Any + + +def make_option_group(group, parser): + """ + Return an OptionGroup object + group -- assumed to be dict with 'name' and 'options' keys + parser -- an optparse Parser + """ + option_group = OptionGroup(parser, group['name']) + for option in group['options']: + option_group.add_option(option()) + return option_group + + +def check_install_build_global(options, check_options=None): + """Disable wheels if per-setup.py call options are set. + + :param options: The OptionParser options to update. + :param check_options: The options to check, if not supplied defaults to + options. + """ + if check_options is None: + check_options = options + + def getname(n): + return getattr(check_options, n, None) + names = ["build_options", "global_options", "install_options"] + if any(map(getname, names)): + control = options.format_control + fmt_ctl_no_binary(control) + warnings.warn( + 'Disabling all use of wheels due to the use of --build-options ' + '/ --global-options / --install-options.', stacklevel=2, + ) + + +########### +# options # +########### + +help_ = partial( + Option, + '-h', '--help', + dest='help', + action='help', + help='Show help.', +) # type: Any + +isolated_mode = partial( + Option, + "--isolated", + dest="isolated_mode", + action="store_true", + default=False, + help=( + "Run pip in an isolated mode, ignoring environment variables and user " + "configuration." + ), +) + +require_virtualenv = partial( + Option, + # Run only if inside a virtualenv, bail if not. + '--require-virtualenv', '--require-venv', + dest='require_venv', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Any + +verbose = partial( + Option, + '-v', '--verbose', + dest='verbose', + action='count', + default=0, + help='Give more output. Option is additive, and can be used up to 3 times.' +) + +no_color = partial( + Option, + '--no-color', + dest='no_color', + action='store_true', + default=False, + help="Suppress colored output", +) + +version = partial( + Option, + '-V', '--version', + dest='version', + action='store_true', + help='Show version and exit.', +) # type: Any + +quiet = partial( + Option, + '-q', '--quiet', + dest='quiet', + action='count', + default=0, + help=( + 'Give less output. Option is additive, and can be used up to 3' + ' times (corresponding to WARNING, ERROR, and CRITICAL logging' + ' levels).' + ), +) # type: Any + +progress_bar = partial( + Option, + '--progress-bar', + dest='progress_bar', + type='choice', + choices=list(BAR_TYPES.keys()), + default='on', + help=( + 'Specify type of progress to be displayed [' + + '|'.join(BAR_TYPES.keys()) + '] (default: %default)' + ), +) # type: Any + +log = partial( + Option, + "--log", "--log-file", "--local-log", + dest="log", + metavar="path", + help="Path to a verbose appending log." +) # type: Any + +no_input = partial( + Option, + # Don't ask for input + '--no-input', + dest='no_input', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Any + +proxy = partial( + Option, + '--proxy', + dest='proxy', + type='str', + default='', + help="Specify a proxy in the form [user:passwd@]proxy.server:port." +) # type: Any + +retries = partial( + Option, + '--retries', + dest='retries', + type='int', + default=5, + help="Maximum number of retries each connection should attempt " + "(default %default times).", +) # type: Any + +timeout = partial( + Option, + '--timeout', '--default-timeout', + metavar='sec', + dest='timeout', + type='float', + default=15, + help='Set the socket timeout (default %default seconds).', +) # type: Any + +skip_requirements_regex = partial( + Option, + # A regex to be used to skip requirements + '--skip-requirements-regex', + dest='skip_requirements_regex', + type='str', + default='', + help=SUPPRESS_HELP, +) # type: Any + + +def exists_action(): + return Option( + # Option when path already exist + '--exists-action', + dest='exists_action', + type='choice', + choices=['s', 'i', 'w', 'b', 'a'], + default=[], + action='append', + metavar='action', + help="Default action when a path already exists: " + "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).", + ) + + +cert = partial( + Option, + '--cert', + dest='cert', + type='str', + metavar='path', + help="Path to alternate CA bundle.", +) # type: Any + +client_cert = partial( + Option, + '--client-cert', + dest='client_cert', + type='str', + default=None, + metavar='path', + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM format.", +) # type: Any + +index_url = partial( + Option, + '-i', '--index-url', '--pypi-url', + dest='index_url', + metavar='URL', + default=PyPI.simple_url, + help="Base URL of Python Package Index (default %default). " + "This should point to a repository compliant with PEP 503 " + "(the simple repository API) or a local directory laid out " + "in the same format.", +) # type: Any + + +def extra_index_url(): + return Option( + '--extra-index-url', + dest='extra_index_urls', + metavar='URL', + action='append', + default=[], + help="Extra URLs of package indexes to use in addition to " + "--index-url. Should follow the same rules as " + "--index-url.", + ) + + +no_index = partial( + Option, + '--no-index', + dest='no_index', + action='store_true', + default=False, + help='Ignore package index (only looking at --find-links URLs instead).', +) # type: Any + + +def find_links(): + return Option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='url', + help="If a url or path to an html file, then parse for links to " + "archives. If a local path or file:// url that's a directory, " + "then look for archives in the directory listing.", + ) + + +def trusted_host(): + return Option( + "--trusted-host", + dest="trusted_hosts", + action="append", + metavar="HOSTNAME", + default=[], + help="Mark this host as trusted, even though it does not have valid " + "or any HTTPS.", + ) + + +# Remove after 1.5 +process_dependency_links = partial( + Option, + "--process-dependency-links", + dest="process_dependency_links", + action="store_true", + default=False, + help="Enable the processing of dependency links.", +) # type: Any + + +def constraints(): + return Option( + '-c', '--constraint', + dest='constraints', + action='append', + default=[], + metavar='file', + help='Constrain versions using the given constraints file. ' + 'This option can be used multiple times.' + ) + + +def requirements(): + return Option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Install from the given requirements file. ' + 'This option can be used multiple times.' + ) + + +def editable(): + return Option( + '-e', '--editable', + dest='editables', + action='append', + default=[], + metavar='path/url', + help=('Install a project in editable mode (i.e. setuptools ' + '"develop mode") from a local project path or a VCS url.'), + ) + + +src = partial( + Option, + '--src', '--source', '--source-dir', '--source-directory', + dest='src_dir', + metavar='dir', + default=src_prefix, + help='Directory to check out editable projects into. ' + 'The default in a virtualenv is "<venv path>/src". ' + 'The default for global installs is "<current dir>/src".' +) # type: Any + + +def _get_format_control(values, option): + """Get a format_control object.""" + return getattr(values, option.dest) + + +def _handle_no_binary(option, opt_str, value, parser): + existing = getattr(parser.values, option.dest) + fmt_ctl_handle_mutual_exclude( + value, existing.no_binary, existing.only_binary, + ) + + +def _handle_only_binary(option, opt_str, value, parser): + existing = getattr(parser.values, option.dest) + fmt_ctl_handle_mutual_exclude( + value, existing.only_binary, existing.no_binary, + ) + + +def no_binary(): + return Option( + "--no-binary", dest="format_control", action="callback", + callback=_handle_no_binary, type="str", + default=FormatControl(set(), set()), + help="Do not use binary packages. Can be supplied multiple times, and " + "each time adds to the existing value. Accepts either :all: to " + "disable all binary packages, :none: to empty the set, or one or " + "more package names with commas between them. Note that some " + "packages are tricky to compile and may fail to install when " + "this option is used on them.", + ) + + +def only_binary(): + return Option( + "--only-binary", dest="format_control", action="callback", + callback=_handle_only_binary, type="str", + default=FormatControl(set(), set()), + help="Do not use source packages. Can be supplied multiple times, and " + "each time adds to the existing value. Accepts either :all: to " + "disable all source packages, :none: to empty the set, or one or " + "more package names with commas between them. Packages without " + "binary distributions will fail to install when this option is " + "used on them.", + ) + + +cache_dir = partial( + Option, + "--cache-dir", + dest="cache_dir", + default=USER_CACHE_DIR, + metavar="dir", + help="Store the cache data in <dir>." +) + +no_cache = partial( + Option, + "--no-cache-dir", + dest="cache_dir", + action="store_false", + help="Disable the cache.", +) + +no_deps = partial( + Option, + '--no-deps', '--no-dependencies', + dest='ignore_dependencies', + action='store_true', + default=False, + help="Don't install package dependencies.", +) # type: Any + +build_dir = partial( + Option, + '-b', '--build', '--build-dir', '--build-directory', + dest='build_dir', + metavar='dir', + help='Directory to unpack packages into and build in. Note that ' + 'an initial build still takes place in a temporary directory. ' + 'The location of temporary directories can be controlled by setting ' + 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' + 'When passed, build directories are not cleaned in case of failures.' +) # type: Any + +ignore_requires_python = partial( + Option, + '--ignore-requires-python', + dest='ignore_requires_python', + action='store_true', + help='Ignore the Requires-Python information.' +) # type: Any + +no_build_isolation = partial( + Option, + '--no-build-isolation', + dest='build_isolation', + action='store_false', + default=True, + help='Disable isolation when building a modern source distribution. ' + 'Build dependencies specified by PEP 518 must be already installed ' + 'if this option is used.' +) # type: Any + +install_options = partial( + Option, + '--install-option', + dest='install_options', + action='append', + metavar='options', + help="Extra arguments to be supplied to the setup.py install " + "command (use like --install-option=\"--install-scripts=/usr/local/" + "bin\"). Use multiple --install-option options to pass multiple " + "options to setup.py install. If you are using an option with a " + "directory path, be sure to use absolute path.", +) # type: Any + +global_options = partial( + Option, + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the install command.", +) # type: Any + +no_clean = partial( + Option, + '--no-clean', + action='store_true', + default=False, + help="Don't clean up build directories)." +) # type: Any + +pre = partial( + Option, + '--pre', + action='store_true', + default=False, + help="Include pre-release and development versions. By default, " + "pip only finds stable versions.", +) # type: Any + +disable_pip_version_check = partial( + Option, + "--disable-pip-version-check", + dest="disable_pip_version_check", + action="store_true", + default=False, + help="Don't periodically check PyPI to determine whether a new version " + "of pip is available for download. Implied with --no-index.", +) # type: Any + + +# Deprecated, Remove later +always_unzip = partial( + Option, + '-Z', '--always-unzip', + dest='always_unzip', + action='store_true', + help=SUPPRESS_HELP, +) # type: Any + + +def _merge_hash(option, opt_str, value, parser): + """Given a value spelled "algo:digest", append the digest to a list + pointed to in a dict by the algo name.""" + if not parser.values.hashes: + parser.values.hashes = {} + try: + algo, digest = value.split(':', 1) + except ValueError: + parser.error('Arguments to %s must be a hash name ' + 'followed by a value, like --hash=sha256:abcde...' % + opt_str) + if algo not in STRONG_HASHES: + parser.error('Allowed hash algorithms for %s are %s.' % + (opt_str, ', '.join(STRONG_HASHES))) + parser.values.hashes.setdefault(algo, []).append(digest) + + +hash = partial( + Option, + '--hash', + # Hash values eventually end up in InstallRequirement.hashes due to + # __dict__ copying in process_line(). + dest='hashes', + action='callback', + callback=_merge_hash, + type='string', + help="Verify that the package's archive matches this " + 'hash before installing. Example: --hash=sha256:abcdef...', +) # type: Any + + +require_hashes = partial( + Option, + '--require-hashes', + dest='require_hashes', + action='store_true', + default=False, + help='Require a hash to check each requirement against, for ' + 'repeatable installs. This option is implied when any package in a ' + 'requirements file has a --hash option.', +) # type: Any + + +########## +# groups # +########## + +general_group = { + 'name': 'General Options', + 'options': [ + help_, + isolated_mode, + require_virtualenv, + verbose, + version, + quiet, + log, + no_input, + proxy, + retries, + timeout, + skip_requirements_regex, + exists_action, + trusted_host, + cert, + client_cert, + cache_dir, + no_cache, + disable_pip_version_check, + no_color, + ] +} + +index_group = { + 'name': 'Package Index Options', + 'options': [ + index_url, + extra_index_url, + no_index, + find_links, + process_dependency_links, + ] +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py new file mode 100755 index 0000000..d44e6f1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/__init__.py @@ -0,0 +1,79 @@ +""" +Package containing all pip commands +""" +from __future__ import absolute_import + +from pip._internal.commands.completion import CompletionCommand +from pip._internal.commands.configuration import ConfigurationCommand +from pip._internal.commands.download import DownloadCommand +from pip._internal.commands.freeze import FreezeCommand +from pip._internal.commands.hash import HashCommand +from pip._internal.commands.help import HelpCommand +from pip._internal.commands.list import ListCommand +from pip._internal.commands.check import CheckCommand +from pip._internal.commands.search import SearchCommand +from pip._internal.commands.show import ShowCommand +from pip._internal.commands.install import InstallCommand +from pip._internal.commands.uninstall import UninstallCommand +from pip._internal.commands.wheel import WheelCommand + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Type + from pip._internal.basecommand import Command + +commands_order = [ + InstallCommand, + DownloadCommand, + UninstallCommand, + FreezeCommand, + ListCommand, + ShowCommand, + CheckCommand, + ConfigurationCommand, + SearchCommand, + WheelCommand, + HashCommand, + CompletionCommand, + HelpCommand, +] # type: List[Type[Command]] + +commands_dict = {c.name: c for c in commands_order} + + +def get_summaries(ordered=True): + """Yields sorted (command name, command summary) tuples.""" + + if ordered: + cmditems = _sort_commands(commands_dict, commands_order) + else: + cmditems = commands_dict.items() + + for name, command_class in cmditems: + yield (name, command_class.summary) + + +def get_similar_commands(name): + """Command name auto-correct.""" + from difflib import get_close_matches + + name = name.lower() + + close_commands = get_close_matches(name, commands_dict.keys()) + + if close_commands: + return close_commands[0] + else: + return False + + +def _sort_commands(cmddict, order): + def keyfn(key): + try: + return order.index(key[1]) + except ValueError: + # unordered items should come last + return 0xff + + return sorted(cmddict.items(), key=keyfn) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py new file mode 100755 index 0000000..b1bf38a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/check.py @@ -0,0 +1,42 @@ +import logging + +from pip._internal.basecommand import Command +from pip._internal.operations.check import ( + check_package_set, create_package_set_from_installed, +) +from pip._internal.utils.misc import get_installed_distributions + +logger = logging.getLogger(__name__) + + +class CheckCommand(Command): + """Verify installed packages have compatible dependencies.""" + name = 'check' + usage = """ + %prog [options]""" + summary = 'Verify installed packages have compatible dependencies.' + + def run(self, options, args): + package_set = create_package_set_from_installed() + missing, conflicting = check_package_set(package_set) + + for project_name in missing: + version = package_set[project_name].version + for dependency in missing[project_name]: + logger.info( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[0], + ) + + for project_name in conflicting: + version = package_set[project_name].version + for dep_name, dep_version, req in conflicting[project_name]: + logger.info( + "%s %s has requirement %s, but you have %s %s.", + project_name, version, req, dep_name, dep_version, + ) + + if missing or conflicting: + return 1 + else: + logger.info("No broken requirements found.") diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py new file mode 100755 index 0000000..8da1e83 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/completion.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import + +import sys +import textwrap + +from pip._internal.basecommand import Command +from pip._internal.utils.misc import get_prog + +BASE_COMPLETION = """ +# pip %(shell)s completion start%(script)s# pip %(shell)s completion end +""" + +COMPLETION_SCRIPTS = { + 'bash': """ + _pip_completion() + { + COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 ) ) + } + complete -o default -F _pip_completion %(prog)s + """, + 'zsh': """ + function _pip_completion { + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] ) ) + } + compctl -K _pip_completion %(prog)s + """, + 'fish': """ + function __fish_complete_pip + set -lx COMP_WORDS (commandline -o) "" + set -lx COMP_CWORD ( \\ + math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ + ) + set -lx PIP_AUTO_COMPLETE 1 + string split \\ -- (eval $COMP_WORDS[1]) + end + complete -fa "(__fish_complete_pip)" -c %(prog)s + """, +} + + +class CompletionCommand(Command): + """A helper command to be used for command completion.""" + name = 'completion' + summary = 'A helper command used for command completion.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(CompletionCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '--bash', '-b', + action='store_const', + const='bash', + dest='shell', + help='Emit completion code for bash') + cmd_opts.add_option( + '--zsh', '-z', + action='store_const', + const='zsh', + dest='shell', + help='Emit completion code for zsh') + cmd_opts.add_option( + '--fish', '-f', + action='store_const', + const='fish', + dest='shell', + help='Emit completion code for fish') + + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ['--' + shell for shell in sorted(shells)] + if options.shell in shells: + script = textwrap.dedent( + COMPLETION_SCRIPTS.get(options.shell, '') % { + 'prog': get_prog(), + } + ) + print(BASE_COMPLETION % {'script': script, 'shell': options.shell}) + else: + sys.stderr.write( + 'ERROR: You must pass %s\n' % ' or '.join(shell_options) + ) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py new file mode 100755 index 0000000..e10d9a9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/configuration.py @@ -0,0 +1,227 @@ +import logging +import os +import subprocess + +from pip._internal.basecommand import Command +from pip._internal.configuration import Configuration, kinds +from pip._internal.exceptions import PipError +from pip._internal.locations import venv_config_file +from pip._internal.status_codes import ERROR, SUCCESS +from pip._internal.utils.misc import get_prog + +logger = logging.getLogger(__name__) + + +class ConfigurationCommand(Command): + """Manage local and global configuration. + + Subcommands: + + list: List the active configuration (or from the file specified) + edit: Edit the configuration file in an editor + get: Get the value associated with name + set: Set the name=value + unset: Unset the value associated with name + + If none of --user, --global and --venv are passed, a virtual + environment configuration file is used if one is active and the file + exists. Otherwise, all modifications happen on the to the user file by + default. + """ + + name = 'config' + usage = """ + %prog [<file-option>] list + %prog [<file-option>] [--editor <editor-path>] edit + + %prog [<file-option>] get name + %prog [<file-option>] set name value + %prog [<file-option>] unset name + """ + + summary = "Manage local and global configuration." + + def __init__(self, *args, **kwargs): + super(ConfigurationCommand, self).__init__(*args, **kwargs) + + self.configuration = None + + self.cmd_opts.add_option( + '--editor', + dest='editor', + action='store', + default=None, + help=( + 'Editor to use to edit the file. Uses VISUAL or EDITOR ' + 'environment variables if not provided.' + ) + ) + + self.cmd_opts.add_option( + '--global', + dest='global_file', + action='store_true', + default=False, + help='Use the system-wide configuration file only' + ) + + self.cmd_opts.add_option( + '--user', + dest='user_file', + action='store_true', + default=False, + help='Use the user configuration file only' + ) + + self.cmd_opts.add_option( + '--venv', + dest='venv_file', + action='store_true', + default=False, + help='Use the virtualenv configuration file only' + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + handlers = { + "list": self.list_values, + "edit": self.open_in_editor, + "get": self.get_name, + "set": self.set_name_value, + "unset": self.unset_name + } + + # Determine action + if not args or args[0] not in handlers: + logger.error("Need an action ({}) to perform.".format( + ", ".join(sorted(handlers))) + ) + return ERROR + + action = args[0] + + # Determine which configuration files are to be loaded + # Depends on whether the command is modifying. + try: + load_only = self._determine_file( + options, need_value=(action in ["get", "set", "unset", "edit"]) + ) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + # Load a new configuration + self.configuration = Configuration( + isolated=options.isolated_mode, load_only=load_only + ) + self.configuration.load() + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _determine_file(self, options, need_value): + file_options = { + kinds.USER: options.user_file, + kinds.GLOBAL: options.global_file, + kinds.VENV: options.venv_file + } + + if sum(file_options.values()) == 0: + if not need_value: + return None + # Default to user, unless there's a virtualenv file. + elif os.path.exists(venv_config_file): + return kinds.VENV + else: + return kinds.USER + elif sum(file_options.values()) == 1: + # There's probably a better expression for this. + return [key for key in file_options if file_options[key]][0] + + raise PipError( + "Need exactly one file to operate upon " + "(--user, --venv, --global) to perform." + ) + + def list_values(self, options, args): + self._get_n_args(args, "list", n=0) + + for key, value in sorted(self.configuration.items()): + logger.info("%s=%r", key, value) + + def get_name(self, options, args): + key = self._get_n_args(args, "get [name]", n=1) + value = self.configuration.get_value(key) + + logger.info("%s", value) + + def set_name_value(self, options, args): + key, value = self._get_n_args(args, "set [name] [value]", n=2) + self.configuration.set_value(key, value) + + self._save_configuration() + + def unset_name(self, options, args): + key = self._get_n_args(args, "unset [name]", n=1) + self.configuration.unset_value(key) + + self._save_configuration() + + def open_in_editor(self, options, args): + editor = self._determine_editor(options) + + fname = self.configuration.get_file_to_edit() + if fname is None: + raise PipError("Could not determine appropriate file.") + + try: + subprocess.check_call([editor, fname]) + except subprocess.CalledProcessError as e: + raise PipError( + "Editor Subprocess exited with exit code {}" + .format(e.returncode) + ) + + def _get_n_args(self, args, example, n): + """Helper to make sure the command got the right number of arguments + """ + if len(args) != n: + msg = ( + 'Got unexpected number of arguments, expected {}. ' + '(example: "{} config {}")' + ).format(n, get_prog(), example) + raise PipError(msg) + + if n == 1: + return args[0] + else: + return args + + def _save_configuration(self): + # We successfully ran a modifying command. Need to save the + # configuration. + try: + self.configuration.save() + except Exception: + logger.error( + "Unable to save configuration. Please report this as a bug.", + exc_info=1 + ) + raise PipError("Internal Error.") + + def _determine_editor(self, options): + if options.editor is not None: + return options.editor + elif "VISUAL" in os.environ: + return os.environ["VISUAL"] + elif "EDITOR" in os.environ: + return os.environ["EDITOR"] + else: + raise PipError("Could not determine editor to use.") diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py new file mode 100755 index 0000000..916a470 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/download.py @@ -0,0 +1,233 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.exceptions import CommandError +from pip._internal.index import FormatControl +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet +from pip._internal.resolve import Resolver +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, normalize_path +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +class DownloadCommand(RequirementCommand): + """ + Download packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports downloading from "requirements files", which provide + an easy way to specify a whole environment to be downloaded. + """ + name = 'download' + + usage = """ + %prog [options] <requirement specifier> [package-index-options] ... + %prog [options] -r <requirements file> [package-index-options] ... + %prog [options] <vcs project url> ... + %prog [options] <local project path> ... + %prog [options] <archive url/path> ...""" + + summary = 'Download packages.' + + def __init__(self, *args, **kw): + super(DownloadCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.global_options()) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.pre()) + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + + cmd_opts.add_option( + '-d', '--dest', '--destination-dir', '--destination-directory', + dest='download_dir', + metavar='dir', + default=os.curdir, + help=("Download packages into <dir>."), + ) + + cmd_opts.add_option( + '--platform', + dest='platform', + metavar='platform', + default=None, + help=("Only download wheels compatible with <platform>. " + "Defaults to the platform of the running system."), + ) + + cmd_opts.add_option( + '--python-version', + dest='python_version', + metavar='python_version', + default=None, + help=("Only download wheels compatible with Python " + "interpreter version <version>. If not specified, then the " + "current system interpreter minor version is used. A major " + "version (e.g. '2') can be specified to match all " + "minor revs of that major version. A minor version " + "(e.g. '34') can also be specified."), + ) + + cmd_opts.add_option( + '--implementation', + dest='implementation', + metavar='implementation', + default=None, + help=("Only download wheels compatible with Python " + "implementation <implementation>, e.g. 'pp', 'jy', 'cp', " + " or 'ip'. If not specified, then the current " + "interpreter implementation is used. Use 'py' to force " + "implementation-agnostic wheels."), + ) + + cmd_opts.add_option( + '--abi', + dest='abi', + metavar='abi', + default=None, + help=("Only download wheels compatible with Python " + "abi <abi>, e.g. 'pypy_41'. If not specified, then the " + "current interpreter abi tag is used. Generally " + "you will need to specify --implementation, " + "--platform, and --python-version when using " + "this option."), + ) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + options.ignore_installed = True + # editable doesn't really make sense for `pip download`, but the bowels + # of the RequirementSet code require that property. + options.editables = [] + + if options.python_version: + python_versions = [options.python_version] + else: + python_versions = None + + dist_restriction_set = any([ + options.python_version, + options.platform, + options.abi, + options.implementation, + ]) + binary_only = FormatControl(set(), {':all:'}) + no_sdist_dependencies = ( + options.format_control != binary_only and + not options.ignore_dependencies + ) + if dist_restriction_set and no_sdist_dependencies: + raise CommandError( + "When restricting platform and interpreter constraints using " + "--python-version, --platform, --abi, or --implementation, " + "either --no-deps must be set, or --only-binary=:all: must be " + "set and --no-binary must not be set (or must be set to " + ":none:)." + ) + + options.src_dir = os.path.abspath(options.src_dir) + options.download_dir = normalize_path(options.download_dir) + + ensure_dir(options.download_dir) + + with self._build_session(options) as session: + finder = self._build_package_finder( + options=options, + session=session, + platform=options.platform, + python_versions=python_versions, + abi=options.abi, + implementation=options.implementation, + ) + build_delete = (not (options.no_clean or options.build_dir)) + if options.cache_dir and not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "by the current user and caching wheels has been " + "disabled. check the permissions and owner of that " + "directory. If executing pip with sudo, you may want " + "sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + with TempDirectory( + options.build_dir, delete=build_delete, kind="download" + ) as directory: + + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + self.populate_requirement_set( + requirement_set, + args, + options, + finder, + session, + self.name, + None + ) + + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=options.download_dir, + wheel_download_dir=None, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=None, + use_user_site=False, + upgrade_strategy="to-satisfy-only", + force_reinstall=False, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=False, + ignore_installed=True, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + downloaded = ' '.join([ + req.name for req in requirement_set.successfully_downloaded + ]) + if downloaded: + logger.info('Successfully downloaded %s', downloaded) + + # Clean up + if not options.no_clean: + requirement_set.cleanup_files() + + return requirement_set diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py new file mode 100755 index 0000000..ac562d7 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/freeze.py @@ -0,0 +1,96 @@ +from __future__ import absolute_import + +import sys + +from pip._internal import index +from pip._internal.basecommand import Command +from pip._internal.cache import WheelCache +from pip._internal.compat import stdlib_pkgs +from pip._internal.operations.freeze import freeze + +DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} + + +class FreezeCommand(Command): + """ + Output installed packages in requirements format. + + packages are listed in a case-insensitive sorted order. + """ + name = 'freeze' + usage = """ + %prog [options]""" + summary = 'Output installed packages in requirements format.' + log_streams = ("ext://sys.stderr", "ext://sys.stderr") + + def __init__(self, *args, **kw): + super(FreezeCommand, self).__init__(*args, **kw) + + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help="Use the order in the given requirements file and its " + "comments when generating output. This option can be " + "used multiple times.") + self.cmd_opts.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL for finding packages, which will be added to the ' + 'output.') + self.cmd_opts.add_option( + '-l', '--local', + dest='local', + action='store_true', + default=False, + help='If in a virtualenv that has global access, do not output ' + 'globally-installed packages.') + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + self.cmd_opts.add_option( + '--all', + dest='freeze_all', + action='store_true', + help='Do not skip these packages in the output:' + ' %s' % ', '.join(DEV_PKGS)) + self.cmd_opts.add_option( + '--exclude-editable', + dest='exclude_editable', + action='store_true', + help='Exclude editable package from output.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + format_control = index.FormatControl(set(), set()) + wheel_cache = WheelCache(options.cache_dir, format_control) + skip = set(stdlib_pkgs) + if not options.freeze_all: + skip.update(DEV_PKGS) + + freeze_kwargs = dict( + requirement=options.requirements, + find_links=options.find_links, + local_only=options.local, + user_only=options.user, + skip_regex=options.skip_requirements_regex, + isolated=options.isolated_mode, + wheel_cache=wheel_cache, + skip=skip, + exclude_editable=options.exclude_editable, + ) + + try: + for line in freeze(**freeze_kwargs): + sys.stdout.write(line + '\n') + finally: + wheel_cache.cleanup() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py new file mode 100755 index 0000000..0ce1419 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/hash.py @@ -0,0 +1,57 @@ +from __future__ import absolute_import + +import hashlib +import logging +import sys + +from pip._internal.basecommand import Command +from pip._internal.status_codes import ERROR +from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES +from pip._internal.utils.misc import read_chunks + +logger = logging.getLogger(__name__) + + +class HashCommand(Command): + """ + Compute a hash of a local package archive. + + These can be used with --hash in a requirements file to do repeatable + installs. + + """ + name = 'hash' + usage = '%prog [options] <file> ...' + summary = 'Compute hashes of package archives.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(HashCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-a', '--algorithm', + dest='algorithm', + choices=STRONG_HASHES, + action='store', + default=FAVORITE_HASH, + help='The hash algorithm to use: one of %s' % + ', '.join(STRONG_HASHES)) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + self.parser.print_usage(sys.stderr) + return ERROR + + algorithm = options.algorithm + for path in args: + logger.info('%s:\n--hash=%s:%s', + path, algorithm, _hash_of_file(path, algorithm)) + + +def _hash_of_file(path, algorithm): + """Return the hash digest of a file.""" + with open(path, 'rb') as archive: + hash = hashlib.new(algorithm) + for chunk in read_chunks(archive): + hash.update(chunk) + return hash.hexdigest() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py new file mode 100755 index 0000000..f4a0e40 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/help.py @@ -0,0 +1,36 @@ +from __future__ import absolute_import + +from pip._internal.basecommand import SUCCESS, Command +from pip._internal.exceptions import CommandError + + +class HelpCommand(Command): + """Show help for commands""" + name = 'help' + usage = """ + %prog <command>""" + summary = 'Show help for commands.' + ignore_require_venv = True + + def run(self, options, args): + from pip._internal.commands import commands_dict, get_similar_commands + + try: + # 'pip help' with no args is handled by pip.__init__.parseopt() + cmd_name = args[0] # the command we need help for + except IndexError: + return SUCCESS + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "%s"' % cmd_name] + if guess: + msg.append('maybe you meant "%s"' % guess) + + raise CommandError(' - '.join(msg)) + + command = commands_dict[cmd_name]() + command.parser.print_help() + + return SUCCESS diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py new file mode 100755 index 0000000..057a64e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/install.py @@ -0,0 +1,502 @@ +from __future__ import absolute_import + +import errno +import logging +import operator +import os +import shutil +from optparse import SUPPRESS_HELP + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.cache import WheelCache +from pip._internal.exceptions import ( + CommandError, InstallationError, PreviousBuildDirError, +) +from pip._internal.locations import distutils_scheme, virtualenv_no_global +from pip._internal.operations.check import check_install_conflicts +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet, install_given_reqs +from pip._internal.resolve import Resolver +from pip._internal.status_codes import ERROR +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, get_installed_version +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import WheelBuilder + +try: + import wheel +except ImportError: + wheel = None + + +logger = logging.getLogger(__name__) + + +class InstallCommand(RequirementCommand): + """ + Install packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports installing from "requirements files", which provide + an easy way to specify a whole environment to be installed. + """ + name = 'install' + + usage = """ + %prog [options] <requirement specifier> [package-index-options] ... + %prog [options] -r <requirements file> [package-index-options] ... + %prog [options] [-e] <vcs project url> ... + %prog [options] [-e] <local project path> ... + %prog [options] <archive url/path> ...""" + + summary = 'Install packages.' + + def __init__(self, *args, **kw): + super(InstallCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.pre()) + + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option( + '-t', '--target', + dest='target_dir', + metavar='dir', + default=None, + help='Install packages into <dir>. ' + 'By default this will not replace existing files/folders in ' + '<dir>. Use --upgrade to replace existing packages in <dir> ' + 'with new versions.' + ) + cmd_opts.add_option( + '--user', + dest='use_user_site', + action='store_true', + help="Install to the Python user install directory for your " + "platform. Typically ~/.local/, or %APPDATA%\\Python on " + "Windows. (See the Python documentation for site.USER_BASE " + "for full details.)") + cmd_opts.add_option( + '--no-user', + dest='use_user_site', + action='store_false', + help=SUPPRESS_HELP) + cmd_opts.add_option( + '--root', + dest='root_path', + metavar='dir', + default=None, + help="Install everything relative to this alternate root " + "directory.") + cmd_opts.add_option( + '--prefix', + dest='prefix_path', + metavar='dir', + default=None, + help="Installation prefix where lib, bin and other top-level " + "folders are placed") + + cmd_opts.add_option(cmdoptions.build_dir()) + + cmd_opts.add_option(cmdoptions.src()) + + cmd_opts.add_option( + '-U', '--upgrade', + dest='upgrade', + action='store_true', + help='Upgrade all specified packages to the newest available ' + 'version. The handling of dependencies depends on the ' + 'upgrade-strategy used.' + ) + + cmd_opts.add_option( + '--upgrade-strategy', + dest='upgrade_strategy', + default='only-if-needed', + choices=['only-if-needed', 'eager'], + help='Determines how dependency upgrading should be handled ' + '[default: %default]. ' + '"eager" - dependencies are upgraded regardless of ' + 'whether the currently installed version satisfies the ' + 'requirements of the upgraded package(s). ' + '"only-if-needed" - are upgraded only when they do not ' + 'satisfy the requirements of the upgraded package(s).' + ) + + cmd_opts.add_option( + '--force-reinstall', + dest='force_reinstall', + action='store_true', + help='Reinstall all packages even if they are already ' + 'up-to-date.') + + cmd_opts.add_option( + '-I', '--ignore-installed', + dest='ignore_installed', + action='store_true', + help='Ignore the installed packages (reinstalling instead).') + + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + + cmd_opts.add_option(cmdoptions.install_options()) + cmd_opts.add_option(cmdoptions.global_options()) + + cmd_opts.add_option( + "--compile", + action="store_true", + dest="compile", + default=True, + help="Compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-compile", + action="store_false", + dest="compile", + help="Do not compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-warn-script-location", + action="store_false", + dest="warn_script_location", + default=True, + help="Do not warn when installing scripts outside PATH", + ) + cmd_opts.add_option( + "--no-warn-conflicts", + action="store_false", + dest="warn_about_conflicts", + default=True, + help="Do not warn about broken dependencies", + ) + + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + cmdoptions.check_install_build_global(options) + + upgrade_strategy = "to-satisfy-only" + if options.upgrade: + upgrade_strategy = options.upgrade_strategy + + if options.build_dir: + options.build_dir = os.path.abspath(options.build_dir) + + options.src_dir = os.path.abspath(options.src_dir) + install_options = options.install_options or [] + if options.use_user_site: + if options.prefix_path: + raise CommandError( + "Can not combine '--user' and '--prefix' as they imply " + "different installation locations" + ) + if virtualenv_no_global(): + raise InstallationError( + "Can not perform a '--user' install. User site-packages " + "are not visible in this virtualenv." + ) + install_options.append('--user') + install_options.append('--prefix=') + + target_temp_dir = TempDirectory(kind="target") + if options.target_dir: + options.ignore_installed = True + options.target_dir = os.path.abspath(options.target_dir) + if (os.path.exists(options.target_dir) and not + os.path.isdir(options.target_dir)): + raise CommandError( + "Target path exists but is not a directory, will not " + "continue." + ) + + # Create a target directory for using with the target option + target_temp_dir.create() + install_options.append('--home=' + target_temp_dir.path) + + global_options = options.global_options or [] + + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + if options.cache_dir and not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "by the current user and caching wheels has been " + "disabled. check the permissions and owner of that " + "directory. If executing pip with sudo, you may want " + "sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + with TempDirectory( + options.build_dir, delete=build_delete, kind="install" + ) as directory: + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + + try: + self.populate_requirement_set( + requirement_set, args, options, finder, session, + self.name, wheel_cache + ) + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=None, + wheel_download_dir=None, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=wheel_cache, + use_user_site=options.use_user_site, + upgrade_strategy=upgrade_strategy, + force_reinstall=options.force_reinstall, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=options.ignore_requires_python, + ignore_installed=options.ignore_installed, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + # If caching is disabled or wheel is not installed don't + # try to build wheels. + if wheel and options.cache_dir: + # build wheels before install. + wb = WheelBuilder( + finder, preparer, wheel_cache, + build_options=[], global_options=[], + ) + # Ignore the result: a failed wheel will be + # installed from the sdist/vcs whatever. + wb.build( + requirement_set.requirements.values(), + session=session, autobuilding=True + ) + + to_install = resolver.get_installation_order( + requirement_set + ) + + # Consistency Checking of the package set we're installing. + should_warn_about_conflicts = ( + not options.ignore_dependencies and + options.warn_about_conflicts + ) + if should_warn_about_conflicts: + self._warn_about_conflicts(to_install) + + # Don't warn about script install locations if + # --target has been specified + warn_script_location = options.warn_script_location + if options.target_dir: + warn_script_location = False + + installed = install_given_reqs( + to_install, + install_options, + global_options, + root=options.root_path, + home=target_temp_dir.path, + prefix=options.prefix_path, + pycompile=options.compile, + warn_script_location=warn_script_location, + use_user_site=options.use_user_site, + ) + + possible_lib_locations = get_lib_location_guesses( + user=options.use_user_site, + home=target_temp_dir.path, + root=options.root_path, + prefix=options.prefix_path, + isolated=options.isolated_mode, + ) + reqs = sorted(installed, key=operator.attrgetter('name')) + items = [] + for req in reqs: + item = req.name + try: + installed_version = get_installed_version( + req.name, possible_lib_locations + ) + if installed_version: + item += '-' + installed_version + except Exception: + pass + items.append(item) + installed = ' '.join(items) + if installed: + logger.info('Successfully installed %s', installed) + except EnvironmentError as error: + show_traceback = (self.verbosity >= 1) + + message = create_env_error_message( + error, show_traceback, options.use_user_site, + ) + logger.error(message, exc_info=show_traceback) + + return ERROR + except PreviousBuildDirError: + options.no_clean = True + raise + finally: + # Clean up + if not options.no_clean: + requirement_set.cleanup_files() + wheel_cache.cleanup() + + if options.target_dir: + self._handle_target_dir( + options.target_dir, target_temp_dir, options.upgrade + ) + return requirement_set + + def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): + ensure_dir(target_dir) + + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + lib_dir_list = [] + + with target_temp_dir: + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + scheme = distutils_scheme('', home=target_temp_dir.path) + purelib_dir = scheme['purelib'] + platlib_dir = scheme['platlib'] + data_dir = scheme['data'] + + if os.path.exists(purelib_dir): + lib_dir_list.append(purelib_dir) + if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: + lib_dir_list.append(platlib_dir) + if os.path.exists(data_dir): + lib_dir_list.append(data_dir) + + for lib_dir in lib_dir_list: + for item in os.listdir(lib_dir): + if lib_dir == data_dir: + ddir = os.path.join(data_dir, item) + if any(s.startswith(ddir) for s in lib_dir_list[:-1]): + continue + target_item_dir = os.path.join(target_dir, item) + if os.path.exists(target_item_dir): + if not upgrade: + logger.warning( + 'Target directory %s already exists. Specify ' + '--upgrade to force replacement.', + target_item_dir + ) + continue + if os.path.islink(target_item_dir): + logger.warning( + 'Target directory %s already exists and is ' + 'a link. Pip will not automatically replace ' + 'links, please remove if replacement is ' + 'desired.', + target_item_dir + ) + continue + if os.path.isdir(target_item_dir): + shutil.rmtree(target_item_dir) + else: + os.remove(target_item_dir) + + shutil.move( + os.path.join(lib_dir, item), + target_item_dir + ) + + def _warn_about_conflicts(self, to_install): + package_set, _dep_info = check_install_conflicts(to_install) + missing, conflicting = _dep_info + + # NOTE: There is some duplication here from pip check + for project_name in missing: + version = package_set[project_name][0] + for dependency in missing[project_name]: + logger.critical( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[1], + ) + + for project_name in conflicting: + version = package_set[project_name][0] + for dep_name, dep_version, req in conflicting[project_name]: + logger.critical( + "%s %s has requirement %s, but you'll have %s %s which is " + "incompatible.", + project_name, version, req, dep_name, dep_version, + ) + + +def get_lib_location_guesses(*args, **kwargs): + scheme = distutils_scheme('', *args, **kwargs) + return [scheme['purelib'], scheme['platlib']] + + +def create_env_error_message(error, show_traceback, using_user_site): + """Format an error message for an EnvironmentError + + It may occur anytime during the execution of the install command. + """ + parts = [] + + # Mention the error if we are not going to show a traceback + parts.append("Could not install packages due to an EnvironmentError") + if not show_traceback: + parts.append(": ") + parts.append(str(error)) + else: + parts.append(".") + + # Spilt the error indication from a helper message (if any) + parts[-1] += "\n" + + # Suggest useful actions to the user: + # (1) using user site-packages or (2) verifying the permissions + if error.errno == errno.EACCES: + user_option_part = "Consider using the `--user` option" + permissions_part = "Check the permissions" + + if not using_user_site: + parts.extend([ + user_option_part, " or ", + permissions_part.lower(), + ]) + else: + parts.append(permissions_part) + parts.append(".\n") + + return "".join(parts).strip() + "\n" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py new file mode 100755 index 0000000..1b46c6f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/list.py @@ -0,0 +1,343 @@ +from __future__ import absolute_import + +import json +import logging +import warnings + +from pip._vendor import six +from pip._vendor.six.moves import zip_longest + +from pip._internal.basecommand import Command +from pip._internal.cmdoptions import index_group, make_option_group +from pip._internal.exceptions import CommandError +from pip._internal.index import PackageFinder +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.misc import ( + dist_is_editable, get_installed_distributions, +) +from pip._internal.utils.packaging import get_installer + +logger = logging.getLogger(__name__) + + +class ListCommand(Command): + """ + List installed packages, including editables. + + Packages are listed in a case-insensitive sorted order. + """ + name = 'list' + usage = """ + %prog [options]""" + summary = 'List installed packages.' + + def __init__(self, *args, **kw): + super(ListCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-o', '--outdated', + action='store_true', + default=False, + help='List outdated packages') + cmd_opts.add_option( + '-u', '--uptodate', + action='store_true', + default=False, + help='List uptodate packages') + cmd_opts.add_option( + '-e', '--editable', + action='store_true', + default=False, + help='List editable projects.') + cmd_opts.add_option( + '-l', '--local', + action='store_true', + default=False, + help=('If in a virtualenv that has global access, do not list ' + 'globally-installed packages.'), + ) + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option( + '--format', + action='store', + dest='list_format', + default="columns", + choices=('legacy', 'columns', 'freeze', 'json'), + help="Select the output format among: columns (default), freeze, " + "json, or legacy.", + ) + + cmd_opts.add_option( + '--not-required', + action='store_true', + dest='not_required', + help="List packages that are not dependencies of " + "installed packages.", + ) + + cmd_opts.add_option( + '--exclude-editable', + action='store_false', + dest='include_editable', + help='Exclude editable package from output.', + ) + cmd_opts.add_option( + '--include-editable', + action='store_true', + dest='include_editable', + help='Include editable package from output.', + default=True, + ) + index_opts = make_option_group(index_group, self.parser) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def _build_package_finder(self, options, index_urls, session): + """ + Create a package finder appropriate to this list command. + """ + return PackageFinder( + find_links=options.find_links, + index_urls=index_urls, + allow_all_prereleases=options.pre, + trusted_hosts=options.trusted_hosts, + process_dependency_links=options.process_dependency_links, + session=session, + ) + + def run(self, options, args): + if options.list_format == "legacy": + warnings.warn( + "The legacy format has been deprecated and will be removed " + "in the future.", + RemovedInPip11Warning, + ) + + if options.outdated and options.uptodate: + raise CommandError( + "Options --outdated and --uptodate cannot be combined.") + + packages = get_installed_distributions( + local_only=options.local, + user_only=options.user, + editables_only=options.editable, + include_editables=options.include_editable, + ) + + if options.outdated: + packages = self.get_outdated(packages, options) + elif options.uptodate: + packages = self.get_uptodate(packages, options) + + if options.not_required: + packages = self.get_not_required(packages, options) + + self.output_package_listing(packages, options) + + def get_outdated(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version > dist.parsed_version + ] + + def get_uptodate(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if dist.latest_version == dist.parsed_version + ] + + def get_not_required(self, packages, options): + dep_keys = set() + for dist in packages: + dep_keys.update(requirement.key for requirement in dist.requires()) + return {pkg for pkg in packages if pkg.key not in dep_keys} + + def iter_packages_latest_infos(self, packages, options): + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + dependency_links = [] + for dist in packages: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend( + dist.get_metadata_lines('dependency_links.txt'), + ) + + with self._build_session(options) as session: + finder = self._build_package_finder(options, index_urls, session) + finder.add_dependency_links(dependency_links) + + for dist in packages: + typ = 'unknown' + all_candidates = finder.find_all_candidates(dist.key) + if not options.pre: + # Remove prereleases + all_candidates = [candidate for candidate in all_candidates + if not candidate.version.is_prerelease] + + if not all_candidates: + continue + best_candidate = max(all_candidates, + key=finder._candidate_sort_key) + remote_version = best_candidate.version + if best_candidate.location.is_wheel: + typ = 'wheel' + else: + typ = 'sdist' + # This is dirty but makes the rest of the code much cleaner + dist.latest_version = remote_version + dist.latest_filetype = typ + yield dist + + def output_legacy(self, dist, options): + if options.verbose >= 1: + return '%s (%s, %s, %s)' % ( + dist.project_name, + dist.version, + dist.location, + get_installer(dist), + ) + elif dist_is_editable(dist): + return '%s (%s, %s)' % ( + dist.project_name, + dist.version, + dist.location, + ) + else: + return '%s (%s)' % (dist.project_name, dist.version) + + def output_legacy_latest(self, dist, options): + return '%s - Latest: %s [%s]' % ( + self.output_legacy(dist, options), + dist.latest_version, + dist.latest_filetype, + ) + + def output_package_listing(self, packages, options): + packages = sorted( + packages, + key=lambda dist: dist.project_name.lower(), + ) + if options.list_format == 'columns' and packages: + data, header = format_for_columns(packages, options) + self.output_package_listing_columns(data, header) + elif options.list_format == 'freeze': + for dist in packages: + if options.verbose >= 1: + logger.info("%s==%s (%s)", dist.project_name, + dist.version, dist.location) + else: + logger.info("%s==%s", dist.project_name, dist.version) + elif options.list_format == 'json': + logger.info(format_for_json(packages, options)) + elif options.list_format == "legacy": + for dist in packages: + if options.outdated: + logger.info(self.output_legacy_latest(dist, options)) + else: + logger.info(self.output_legacy(dist, options)) + + def output_package_listing_columns(self, data, header): + # insert the header first: we need to know the size of column names + if len(data) > 0: + data.insert(0, header) + + pkg_strings, sizes = tabulate(data) + + # Create and add a separator. + if len(data) > 0: + pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) + + for val in pkg_strings: + logger.info(val) + + +def tabulate(vals): + # From pfmoore on GitHub: + # https://github.com/pypa/pip/issues/3651#issuecomment-216932564 + assert len(vals) > 0 + + sizes = [0] * max(len(x) for x in vals) + for row in vals: + sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)] + + result = [] + for row in vals: + display = " ".join([str(c).ljust(s) if c is not None else '' + for s, c in zip_longest(sizes, row)]) + result.append(display) + + return result, sizes + + +def format_for_columns(pkgs, options): + """ + Convert the package data into something usable + by output_package_listing_columns. + """ + running_outdated = options.outdated + # Adjust the header for the `pip list --outdated` case. + if running_outdated: + header = ["Package", "Version", "Latest", "Type"] + else: + header = ["Package", "Version"] + + data = [] + if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): + header.append("Location") + if options.verbose >= 1: + header.append("Installer") + + for proj in pkgs: + # if we're working on the 'outdated' list, separate out the + # latest_version and type + row = [proj.project_name, proj.version] + + if running_outdated: + row.append(proj.latest_version) + row.append(proj.latest_filetype) + + if options.verbose >= 1 or dist_is_editable(proj): + row.append(proj.location) + if options.verbose >= 1: + row.append(get_installer(proj)) + + data.append(row) + + return data, header + + +def format_for_json(packages, options): + data = [] + for dist in packages: + info = { + 'name': dist.project_name, + 'version': six.text_type(dist.version), + } + if options.verbose >= 1: + info['location'] = dist.location + info['installer'] = get_installer(dist) + if options.outdated: + info['latest_version'] = six.text_type(dist.latest_version) + info['latest_filetype'] = dist.latest_filetype + data.append(info) + return json.dumps(data) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py new file mode 100755 index 0000000..83895ce --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/search.py @@ -0,0 +1,135 @@ +from __future__ import absolute_import + +import logging +import sys +import textwrap +from collections import OrderedDict + +from pip._vendor import pkg_resources +from pip._vendor.packaging.version import parse as parse_version +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore + +from pip._internal.basecommand import SUCCESS, Command +from pip._internal.compat import get_terminal_size +from pip._internal.download import PipXmlrpcTransport +from pip._internal.exceptions import CommandError +from pip._internal.models import PyPI +from pip._internal.status_codes import NO_MATCHES_FOUND +from pip._internal.utils.logging import indent_log + +logger = logging.getLogger(__name__) + + +class SearchCommand(Command): + """Search for PyPI packages whose name or summary contains <query>.""" + name = 'search' + usage = """ + %prog [options] <query>""" + summary = 'Search PyPI for packages.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(SearchCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-i', '--index', + dest='index', + metavar='URL', + default=PyPI.pypi_url, + help='Base URL of Python Package Index (default %default)') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + raise CommandError('Missing required argument (search query).') + query = args + pypi_hits = self.search(query, options) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + if pypi_hits: + return SUCCESS + return NO_MATCHES_FOUND + + def search(self, query, options): + index_url = options.index + with self._build_session(options) as session: + transport = PipXmlrpcTransport(index_url, session) + pypi = xmlrpc_client.ServerProxy(index_url, transport) + hits = pypi.search({'name': query, 'summary': query}, 'or') + return hits + + +def transform_hits(hits): + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages = OrderedDict() + for hit in hits: + name = hit['name'] + summary = hit['summary'] + version = hit['version'] + + if name not in packages.keys(): + packages[name] = { + 'name': name, + 'summary': summary, + 'versions': [version], + } + else: + packages[name]['versions'].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]['versions']): + packages[name]['summary'] = summary + + return list(packages.values()) + + +def print_results(hits, name_column_width=None, terminal_width=None): + if not hits: + return + if name_column_width is None: + name_column_width = max([ + len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) + for hit in hits + ]) + 4 + + installed_packages = [p.project_name for p in pkg_resources.working_set] + for hit in hits: + name = hit['name'] + summary = hit['summary'] or '' + latest = highest_version(hit.get('versions', ['-'])) + if terminal_width is not None: + target_width = terminal_width - name_column_width - 5 + if target_width > 10: + # wrap and indent summary to fit terminal + summary = textwrap.wrap(summary, target_width) + summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + + line = '%-*s - %s' % (name_column_width, + '%s (%s)' % (name, latest), summary) + try: + logger.info(line) + if name in installed_packages: + dist = pkg_resources.get_distribution(name) + with indent_log(): + if dist.version == latest: + logger.info('INSTALLED: %s (latest)', dist.version) + else: + logger.info('INSTALLED: %s', dist.version) + logger.info('LATEST: %s', latest) + except UnicodeEncodeError: + pass + + +def highest_version(versions): + return max(versions, key=parse_version) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py new file mode 100755 index 0000000..bad9628 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/show.py @@ -0,0 +1,164 @@ +from __future__ import absolute_import + +import logging +import os +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.basecommand import Command +from pip._internal.status_codes import ERROR, SUCCESS + +logger = logging.getLogger(__name__) + + +class ShowCommand(Command): + """Show information about one or more installed packages.""" + name = 'show' + usage = """ + %prog [options] <package> ...""" + summary = 'Show information about installed packages.' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(ShowCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-f', '--files', + dest='files', + action='store_true', + default=False, + help='Show the full list of installed files for each package.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + logger.warning('ERROR: Please provide a package name or names.') + return ERROR + query = args + + results = search_packages_info(query) + if not print_results( + results, list_files=options.files, verbose=options.verbose): + return ERROR + return SUCCESS + + +def search_packages_info(query): + """ + Gather details from installed distributions. Print distribution name, + version, location, and installed files. Installed files requires a + pip generated 'installed-files.txt' in the distributions '.egg-info' + directory. + """ + installed = {} + for p in pkg_resources.working_set: + installed[canonicalize_name(p.project_name)] = p + + query_names = [canonicalize_name(name) for name in query] + + for dist in [installed[pkg] for pkg in query_names if pkg in installed]: + package = { + 'name': dist.project_name, + 'version': dist.version, + 'location': dist.location, + 'requires': [dep.project_name for dep in dist.requires()], + } + file_list = None + metadata = None + if isinstance(dist, pkg_resources.DistInfoDistribution): + # RECORDs should be part of .dist-info metadatas + if dist.has_metadata('RECORD'): + lines = dist.get_metadata_lines('RECORD') + paths = [l.split(',')[0] for l in lines] + paths = [os.path.join(dist.location, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('METADATA'): + metadata = dist.get_metadata('METADATA') + else: + # Otherwise use pip's log for .egg-info's + if dist.has_metadata('installed-files.txt'): + paths = dist.get_metadata_lines('installed-files.txt') + paths = [os.path.join(dist.egg_info, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('PKG-INFO'): + metadata = dist.get_metadata('PKG-INFO') + + if dist.has_metadata('entry_points.txt'): + entry_points = dist.get_metadata_lines('entry_points.txt') + package['entry_points'] = entry_points + + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + package['installer'] = line.strip() + break + + # @todo: Should pkg_resources.Distribution have a + # `get_pkg_info` method? + feed_parser = FeedParser() + feed_parser.feed(metadata) + pkg_info_dict = feed_parser.close() + for key in ('metadata-version', 'summary', + 'home-page', 'author', 'author-email', 'license'): + package[key] = pkg_info_dict.get(key) + + # It looks like FeedParser cannot deal with repeated headers + classifiers = [] + for line in metadata.splitlines(): + if line.startswith('Classifier: '): + classifiers.append(line[len('Classifier: '):]) + package['classifiers'] = classifiers + + if file_list: + package['files'] = sorted(file_list) + yield package + + +def print_results(distributions, list_files=False, verbose=False): + """ + Print the informations from installed distributions found. + """ + results_printed = False + for i, dist in enumerate(distributions): + results_printed = True + if i > 0: + logger.info("---") + + name = dist.get('name', '') + required_by = [ + pkg.project_name for pkg in pkg_resources.working_set + if name in [required.name for required in pkg.requires()] + ] + + logger.info("Name: %s", name) + logger.info("Version: %s", dist.get('version', '')) + logger.info("Summary: %s", dist.get('summary', '')) + logger.info("Home-page: %s", dist.get('home-page', '')) + logger.info("Author: %s", dist.get('author', '')) + logger.info("Author-email: %s", dist.get('author-email', '')) + logger.info("License: %s", dist.get('license', '')) + logger.info("Location: %s", dist.get('location', '')) + logger.info("Requires: %s", ', '.join(dist.get('requires', []))) + logger.info("Required-by: %s", ', '.join(required_by)) + + if verbose: + logger.info("Metadata-Version: %s", + dist.get('metadata-version', '')) + logger.info("Installer: %s", dist.get('installer', '')) + logger.info("Classifiers:") + for classifier in dist.get('classifiers', []): + logger.info(" %s", classifier) + logger.info("Entry-points:") + for entry in dist.get('entry_points', []): + logger.info(" %s", entry.strip()) + if list_files: + logger.info("Files:") + for line in dist.get('files', []): + logger.info(" %s", line.strip()) + if "files" not in dist: + logger.info("Cannot locate installed-files.txt") + return results_printed diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py new file mode 100755 index 0000000..3bfa07f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/uninstall.py @@ -0,0 +1,71 @@ +from __future__ import absolute_import + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.basecommand import Command +from pip._internal.exceptions import InstallationError +from pip._internal.req import InstallRequirement, parse_requirements + + +class UninstallCommand(Command): + """ + Uninstall packages. + + pip is able to uninstall most installed packages. Known exceptions are: + + - Pure distutils packages installed with ``python setup.py install``, which + leave behind no metadata to determine what files were installed. + - Script wrappers installed by ``python setup.py develop``. + """ + name = 'uninstall' + usage = """ + %prog [options] <package> ... + %prog [options] -r <requirements file> ...""" + summary = 'Uninstall packages.' + + def __init__(self, *args, **kw): + super(UninstallCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Uninstall all the packages listed in the given requirements ' + 'file. This option can be used multiple times.', + ) + self.cmd_opts.add_option( + '-y', '--yes', + dest='yes', + action='store_true', + help="Don't ask for confirmation of uninstall deletions.") + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + with self._build_session(options) as session: + reqs_to_uninstall = {} + for name in args: + req = InstallRequirement.from_line( + name, isolated=options.isolated_mode, + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + for filename in options.requirements: + for req in parse_requirements( + filename, + options=options, + session=session): + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + if not reqs_to_uninstall: + raise InstallationError( + 'You must give at least one requirement to %(name)s (see ' + '"pip help %(name)s")' % dict(name=self.name) + ) + for req in reqs_to_uninstall.values(): + uninstall_pathset = req.uninstall( + auto_confirm=options.yes, verbose=self.verbosity > 0, + ) + if uninstall_pathset: + uninstall_pathset.commit() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py new file mode 100755 index 0000000..ed8cdfc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/commands/wheel.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import logging +import os + +from pip._internal import cmdoptions +from pip._internal.basecommand import RequirementCommand +from pip._internal.cache import WheelCache +from pip._internal.exceptions import CommandError, PreviousBuildDirError +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req import RequirementSet +from pip._internal.resolve import Resolver +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.wheel import WheelBuilder + +logger = logging.getLogger(__name__) + + +class WheelCommand(RequirementCommand): + """ + Build Wheel archives for your requirements and dependencies. + + Wheel is a built-package format, and offers the advantage of not + recompiling your software during every install. For more details, see the + wheel docs: https://wheel.readthedocs.io/en/latest/ + + Requirements: setuptools>=0.8, and wheel. + + 'pip wheel' uses the bdist_wheel setuptools extension from the wheel + package to build individual wheels. + + """ + + name = 'wheel' + usage = """ + %prog [options] <requirement specifier> ... + %prog [options] -r <requirements file> ... + %prog [options] [-e] <vcs project url> ... + %prog [options] [-e] <local project path> ... + %prog [options] <archive url/path> ...""" + + summary = 'Build wheels from your requirements.' + + def __init__(self, *args, **kw): + super(WheelCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-w', '--wheel-dir', + dest='wheel_dir', + metavar='dir', + default=os.curdir, + help=("Build wheels into <dir>, where the default is the " + "current working directory."), + ) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option( + '--build-option', + dest='build_options', + metavar='options', + action='append', + help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", + ) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + cmd_opts.add_option( + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the 'bdist_wheel' command.") + + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option(cmdoptions.no_clean()) + cmd_opts.add_option(cmdoptions.require_hashes()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + cmdoptions.check_install_build_global(options) + + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index: + logger.debug('Ignoring indexes: %s', ','.join(index_urls)) + index_urls = [] + + if options.build_dir: + options.build_dir = os.path.abspath(options.build_dir) + + options.src_dir = os.path.abspath(options.src_dir) + + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + with TempDirectory( + options.build_dir, delete=build_delete, kind="wheel" + ) as directory: + requirement_set = RequirementSet( + require_hashes=options.require_hashes, + ) + + try: + self.populate_requirement_set( + requirement_set, args, options, finder, session, + self.name, wheel_cache + ) + + preparer = RequirementPreparer( + build_dir=directory.path, + src_dir=options.src_dir, + download_dir=None, + wheel_download_dir=options.wheel_dir, + progress_bar=options.progress_bar, + build_isolation=options.build_isolation, + ) + + resolver = Resolver( + preparer=preparer, + finder=finder, + session=session, + wheel_cache=wheel_cache, + use_user_site=False, + upgrade_strategy="to-satisfy-only", + force_reinstall=False, + ignore_dependencies=options.ignore_dependencies, + ignore_requires_python=options.ignore_requires_python, + ignore_installed=True, + isolated=options.isolated_mode, + ) + resolver.resolve(requirement_set) + + # build wheels + wb = WheelBuilder( + finder, preparer, wheel_cache, + build_options=options.build_options or [], + global_options=options.global_options or [], + no_clean=options.no_clean, + ) + wheels_built_successfully = wb.build( + requirement_set.requirements.values(), session=session, + ) + if not wheels_built_successfully: + raise CommandError( + "Failed to build one or more wheels" + ) + except PreviousBuildDirError: + options.no_clean = True + raise + finally: + if not options.no_clean: + requirement_set.cleanup_files() + wheel_cache.cleanup() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py new file mode 100755 index 0000000..064717d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/compat.py @@ -0,0 +1,235 @@ +"""Stuff that differs in different Python versions and platform +distributions.""" +from __future__ import absolute_import, division + +import codecs +import locale +import logging +import os +import shutil +import sys + +from pip._vendor.six import text_type + +try: + import ipaddress +except ImportError: + try: + from pip._vendor import ipaddress # type: ignore + except ImportError: + import ipaddr as ipaddress # type: ignore + ipaddress.ip_address = ipaddress.IPAddress + ipaddress.ip_network = ipaddress.IPNetwork + + +__all__ = [ + "ipaddress", "uses_pycache", "console_to_str", "native_str", + "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", +] + + +logger = logging.getLogger(__name__) + +if sys.version_info >= (3, 4): + uses_pycache = True + from importlib.util import cache_from_source +else: + import imp + + try: + cache_from_source = imp.cache_from_source # type: ignore + except AttributeError: + # does not use __pycache__ + cache_from_source = None + + uses_pycache = cache_from_source is not None + + +if sys.version_info >= (3, 5): + backslashreplace_decode = "backslashreplace" +else: + # In version 3.4 and older, backslashreplace exists + # but does not support use for decoding. + # We implement our own replace handler for this + # situation, so that we can consistently use + # backslash replacement for all versions. + def backslashreplace_decode_fn(err): + raw_bytes = (err.object[i] for i in range(err.start, err.end)) + if sys.version_info[0] == 2: + # Python 2 gave us characters - convert to numeric bytes + raw_bytes = (ord(b) for b in raw_bytes) + return u"".join(u"\\x%x" % c for c in raw_bytes), err.end + codecs.register_error( + "backslashreplace_decode", + backslashreplace_decode_fn, + ) + backslashreplace_decode = "backslashreplace_decode" + + +def console_to_str(data): + """Return a string, safe for output, of subprocess output. + + We assume the data is in the locale preferred encoding. + If it won't decode properly, we warn the user but decode as + best we can. + + We also ensure that the output can be safely written to + standard output without encoding errors. + """ + + # First, get the encoding we assume. This is the preferred + # encoding for the locale, unless that is not found, or + # it is ASCII, in which case assume UTF-8 + encoding = locale.getpreferredencoding() + if (not encoding) or codecs.lookup(encoding).name == "ascii": + encoding = "utf-8" + + # Now try to decode the data - if we fail, warn the user and + # decode with replacement. + try: + s = data.decode(encoding) + except UnicodeDecodeError: + logger.warning( + "Subprocess output does not appear to be encoded as %s", + encoding, + ) + s = data.decode(encoding, errors=backslashreplace_decode) + + # Make sure we can print the output, by encoding it to the output + # encoding with replacement of unencodable characters, and then + # decoding again. + # We use stderr's encoding because it's less likely to be + # redirected and if we don't find an encoding we skip this + # step (on the assumption that output is wrapped by something + # that won't fail). + # The double getattr is to deal with the possibility that we're + # being called in a situation where sys.__stderr__ doesn't exist, + # or doesn't have an encoding attribute. Neither of these cases + # should occur in normal pip use, but there's no harm in checking + # in case people use pip in (unsupported) unusual situations. + output_encoding = getattr(getattr(sys, "__stderr__", None), + "encoding", None) + + if output_encoding: + s = s.encode(output_encoding, errors="backslashreplace") + s = s.decode(output_encoding) + + return s + + +if sys.version_info >= (3,): + def native_str(s, replace=False): + if isinstance(s, bytes): + return s.decode('utf-8', 'replace' if replace else 'strict') + return s + +else: + def native_str(s, replace=False): + # Replace is ignored -- unicode to UTF-8 can't fail + if isinstance(s, text_type): + return s.encode('utf-8') + return s + + +def get_path_uid(path): + """ + Return path's uid. + + Does not follow symlinks: + https://github.com/pypa/pip/pull/935#discussion_r5307003 + + Placed this function in compat due to differences on AIX and + Jython, that should eventually go away. + + :raises OSError: When path is a symlink or can't be read. + """ + if hasattr(os, 'O_NOFOLLOW'): + fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) + file_uid = os.fstat(fd).st_uid + os.close(fd) + else: # AIX and Jython + # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW + if not os.path.islink(path): + # older versions of Jython don't have `os.fstat` + file_uid = os.stat(path).st_uid + else: + # raise OSError for parity with os.O_NOFOLLOW above + raise OSError( + "%s is a symlink; Will not return uid for symlinks" % path + ) + return file_uid + + +def expanduser(path): + """ + Expand ~ and ~user constructions. + + Includes a workaround for http://bugs.python.org/issue14768 + """ + expanded = os.path.expanduser(path) + if path.startswith('~/') and expanded.startswith('//'): + expanded = expanded[1:] + return expanded + + +# packages in the stdlib that may have installation metadata, but should not be +# considered 'installed'. this theoretically could be determined based on +# dist.location (py27:`sysconfig.get_paths()['stdlib']`, +# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may +# make this ineffective, so hard-coding +stdlib_pkgs = {"python", "wsgiref", "argparse"} + + +# windows detection, covers cpython and ironpython +WINDOWS = (sys.platform.startswith("win") or + (sys.platform == 'cli' and os.name == 'nt')) + + +def samefile(file1, file2): + """Provide an alternative for os.path.samefile on Windows/Python2""" + if hasattr(os.path, 'samefile'): + return os.path.samefile(file1, file2) + else: + path1 = os.path.normcase(os.path.abspath(file1)) + path2 = os.path.normcase(os.path.abspath(file2)) + return path1 == path2 + + +if hasattr(shutil, 'get_terminal_size'): + def get_terminal_size(): + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + return tuple(shutil.get_terminal_size()) +else: + def get_terminal_size(): + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + def ioctl_GWINSZ(fd): + try: + import fcntl + import termios + import struct + cr = struct.unpack_from( + 'hh', + fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') + ) + except: + return None + if cr == (0, 0): + return None + return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + cr = ioctl_GWINSZ(fd) + os.close(fd) + except: + pass + if not cr: + cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) + return int(cr[1]), int(cr[0]) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py new file mode 100755 index 0000000..07af373 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/configuration.py @@ -0,0 +1,378 @@ +"""Configuration management setup + +Some terminology: +- name + As written in config files. +- value + Value associated with a name +- key + Name combined with it's section (section.name) +- variant + A single word describing where the configuration key-value pair came from +""" + +import locale +import logging +import os + +from pip._vendor import six +from pip._vendor.six.moves import configparser + +from pip._internal.exceptions import ConfigurationError +from pip._internal.locations import ( + legacy_config_file, new_config_file, running_under_virtualenv, + site_config_files, venv_config_file, +) +from pip._internal.utils.misc import ensure_dir, enum +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple + + RawConfigParser = configparser.RawConfigParser # Shorthand + Kind = NewType("Kind", str) + +logger = logging.getLogger(__name__) + + +# NOTE: Maybe use the optionx attribute to normalize keynames. +def _normalize_name(name): + # type: (str) -> str + """Make a name consistent regardless of source (environment or file) + """ + name = name.lower().replace('_', '-') + if name.startswith('--'): + name = name[2:] # only prefer long opts + return name + + +def _disassemble_key(name): + # type: (str) -> List[str] + return name.split(".", 1) + + +# The kinds of configurations there are. +kinds = enum( + USER="user", # User Specific + GLOBAL="global", # System Wide + VENV="venv", # Virtual Environment Specific + ENV="env", # from PIP_CONFIG_FILE + ENV_VAR="env-var", # from Environment Variables +) + + +class Configuration(object): + """Handles management of configuration. + + Provides an interface to accessing and managing configuration files. + + This class converts provides an API that takes "section.key-name" style + keys and stores the value associated with it as "key-name" under the + section "section". + + This allows for a clean interface wherein the both the section and the + key-name are preserved in an easy to manage form in the configuration files + and the data stored is also nice. + """ + + def __init__(self, isolated, load_only=None): + # type: (bool, Kind) -> None + super(Configuration, self).__init__() + + _valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.VENV, None] + if load_only not in _valid_load_only: + raise ConfigurationError( + "Got invalid value for load_only - should be one of {}".format( + ", ".join(map(repr, _valid_load_only[:-1])) + ) + ) + self.isolated = isolated # type: bool + self.load_only = load_only # type: Optional[Kind] + + # The order here determines the override order. + self._override_order = [ + kinds.GLOBAL, kinds.USER, kinds.VENV, kinds.ENV, kinds.ENV_VAR + ] + + self._ignore_env_names = ["version", "help"] + + # Because we keep track of where we got the data from + self._parsers = { + variant: [] for variant in self._override_order + } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] + self._config = { + variant: {} for variant in self._override_order + } # type: Dict[Kind, Dict[str, Any]] + self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] + + def load(self): + # type: () -> None + """Loads configuration from configuration files and environment + """ + self._load_config_files() + if not self.isolated: + self._load_environment_vars() + + def get_file_to_edit(self): + # type: () -> Optional[str] + """Returns the file with highest priority in configuration + """ + assert self.load_only is not None, \ + "Need to be specified a file to be editing" + + try: + return self._get_parser_to_modify()[0] + except IndexError: + return None + + def items(self): + # type: () -> Iterable[Tuple[str, Any]] + """Returns key-value pairs like dict.items() representing the loaded + configuration + """ + return self._dictionary.items() + + def get_value(self, key): + # type: (str) -> Any + """Get a value from the configuration. + """ + try: + return self._dictionary[key] + except KeyError: + raise ConfigurationError("No such key - {}".format(key)) + + def set_value(self, key, value): + # type: (str, Any) -> None + """Modify a value in the configuration. + """ + self._ensure_have_load_only() + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Modify the parser and the configuration + if not parser.has_section(section): + parser.add_section(section) + parser.set(section, name, value) + + self._config[self.load_only][key] = value + self._mark_as_modified(fname, parser) + + def unset_value(self, key): + # type: (str) -> None + """Unset a value in the configuration. + """ + self._ensure_have_load_only() + + if key not in self._config[self.load_only]: + raise ConfigurationError("No such key - {}".format(key)) + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Remove the key in the parser + modified_something = False + if parser.has_section(section): + # Returns whether the option was removed or not + modified_something = parser.remove_option(section, name) + + if modified_something: + # name removed from parser, section may now be empty + section_iter = iter(parser.items(section)) + try: + val = six.next(section_iter) + except StopIteration: + val = None + + if val is None: + parser.remove_section(section) + + self._mark_as_modified(fname, parser) + else: + raise ConfigurationError( + "Fatal Internal error [id=1]. Please report as a bug." + ) + + del self._config[self.load_only][key] + + def save(self): + # type: () -> None + """Save the currentin-memory state. + """ + self._ensure_have_load_only() + + for fname, parser in self._modified_parsers: + logger.info("Writing to %s", fname) + + # Ensure directory exists. + ensure_dir(os.path.dirname(fname)) + + with open(fname, "w") as f: + parser.write(f) # type: ignore + + # + # Private routines + # + + def _ensure_have_load_only(self): + # type: () -> None + if self.load_only is None: + raise ConfigurationError("Needed a specific file to be modifying.") + logger.debug("Will be working with %s variant only", self.load_only) + + @property + def _dictionary(self): + # type: () -> Dict[str, Any] + """A dictionary representing the loaded configuration. + """ + # NOTE: Dictionaries are not populated if not loaded. So, conditionals + # are not needed here. + retval = {} + + for variant in self._override_order: + retval.update(self._config[variant]) + + return retval + + def _load_config_files(self): + # type: () -> None + """Loads configuration from configuration files + """ + config_files = dict(self._iter_config_files()) + if config_files[kinds.ENV][0:1] == [os.devnull]: + logger.debug( + "Skipping loading configuration files due to " + "environment's PIP_CONFIG_FILE being os.devnull" + ) + return + + for variant, files in config_files.items(): + for fname in files: + # If there's specific variant set in `load_only`, load only + # that variant, not the others. + if self.load_only is not None and variant != self.load_only: + logger.debug( + "Skipping file '%s' (variant: %s)", fname, variant + ) + continue + + parser = self._load_file(variant, fname) + + # Keeping track of the parsers used + self._parsers[variant].append((fname, parser)) + + def _load_file(self, variant, fname): + # type: (Kind, str) -> RawConfigParser + logger.debug("For variant '%s', will try loading '%s'", variant, fname) + parser = self._construct_parser(fname) + + for section in parser.sections(): + items = parser.items(section) + self._config[variant].update(self._normalized_keys(section, items)) + + return parser + + def _construct_parser(self, fname): + # type: (str) -> RawConfigParser + parser = configparser.RawConfigParser() + # If there is no such file, don't bother reading it but create the + # parser anyway, to hold the data. + # Doing this is useful when modifying and saving files, where we don't + # need to construct a parser. + if os.path.exists(fname): + try: + parser.read(fname) + except UnicodeDecodeError: + raise ConfigurationError(( + "ERROR: " + "Configuration file contains invalid %s characters.\n" + "Please fix your configuration, located at %s\n" + ) % (locale.getpreferredencoding(False), fname)) + return parser + + def _load_environment_vars(self): + # type: () -> None + """Loads configuration from environment variables + """ + self._config[kinds.ENV_VAR].update( + self._normalized_keys(":env:", self._get_environ_vars()) + ) + + def _normalized_keys(self, section, items): + # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] + """Normalizes items to construct a dictionary with normalized keys. + + This routine is where the names become keys and are made the same + regardless of source - configuration files or environment. + """ + normalized = {} + for name, val in items: + key = section + "." + _normalize_name(name) + normalized[key] = val + return normalized + + def _get_environ_vars(self): + # type: () -> Iterable[Tuple[str, str]] + """Returns a generator with all environmental vars with prefix PIP_""" + for key, val in os.environ.items(): + should_be_yielded = ( + key.startswith("PIP_") and + key[4:].lower() not in self._ignore_env_names + ) + if should_be_yielded: + yield key[4:].lower(), val + + # XXX: This is patched in the tests. + def _iter_config_files(self): + # type: () -> Iterable[Tuple[Kind, List[str]]] + """Yields variant and configuration files associated with it. + + This should be treated like items of a dictionary. + """ + # SMELL: Move the conditions out of this function + + # environment variables have the lowest priority + config_file = os.environ.get('PIP_CONFIG_FILE', None) + if config_file is not None: + yield kinds.ENV, [config_file] + else: + yield kinds.ENV, [] + + # at the base we have any global configuration + yield kinds.GLOBAL, list(site_config_files) + + # per-user configuration next + should_load_user_config = not self.isolated and not ( + config_file and os.path.exists(config_file) + ) + if should_load_user_config: + # The legacy config file is overridden by the new config file + yield kinds.USER, [legacy_config_file, new_config_file] + + # finally virtualenv configuration first trumping others + if running_under_virtualenv(): + yield kinds.VENV, [venv_config_file] + + def _get_parser_to_modify(self): + # type: () -> Tuple[str, RawConfigParser] + # Determine which parser to modify + parsers = self._parsers[self.load_only] + if not parsers: + # This should not happen if everything works correctly. + raise ConfigurationError( + "Fatal Internal error [id=2]. Please report as a bug." + ) + + # Use the highest priority parser. + return parsers[-1] + + # XXX: This is patched in the tests. + def _mark_as_modified(self, fname, parser): + # type: (str, RawConfigParser) -> None + file_parser_tuple = (fname, parser) + if file_parser_tuple not in self._modified_parsers: + self._modified_parsers.append(file_parser_tuple) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py new file mode 100755 index 0000000..e0e2d24 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/download.py @@ -0,0 +1,922 @@ +from __future__ import absolute_import + +import cgi +import email.utils +import getpass +import json +import logging +import mimetypes +import os +import platform +import re +import shutil +import sys + +from pip._vendor import requests, six, urllib3 +from pip._vendor.cachecontrol import CacheControlAdapter +from pip._vendor.cachecontrol.caches import FileCache +from pip._vendor.lockfile import LockError +from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter +from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth +from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.requests.utils import get_netrc_auth +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request +from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote +from pip._vendor.urllib3.util import IS_PYOPENSSL + +import pip +from pip._internal.compat import WINDOWS +from pip._internal.exceptions import HashMismatch, InstallationError +from pip._internal.locations import write_delete_marker_file +from pip._internal.models import PyPI +from pip._internal.utils.encoding import auto_decode +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.glibc import libc_ver +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + ARCHIVE_EXTENSIONS, ask_path_exists, backup_dir, call_subprocess, consume, + display_path, format_size, get_installed_version, rmtree, splitext, + unpack_file, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.ui import DownloadProgressProvider +from pip._internal.vcs import vcs + +try: + import ssl # noqa +except ImportError: + ssl = None + +HAS_TLS = (ssl is not None) or IS_PYOPENSSL + +__all__ = ['get_file_content', + 'is_url', 'url_to_path', 'path_to_url', + 'is_archive_file', 'unpack_vcs_link', + 'unpack_file_url', 'is_vcs_url', 'is_file_url', + 'unpack_http_url', 'unpack_url'] + + +logger = logging.getLogger(__name__) + + +def user_agent(): + """ + Return a string representing the user agent. + """ + data = { + "installer": {"name": "pip", "version": pip.__version__}, + "python": platform.python_version(), + "implementation": { + "name": platform.python_implementation(), + }, + } + + if data["implementation"]["name"] == 'CPython': + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'PyPy': + if sys.pypy_version_info.releaselevel == 'final': + pypy_version_info = sys.pypy_version_info[:3] + else: + pypy_version_info = sys.pypy_version_info + data["implementation"]["version"] = ".".join( + [str(x) for x in pypy_version_info] + ) + elif data["implementation"]["name"] == 'Jython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'IronPython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + + if sys.platform.startswith("linux"): + from pip._vendor import distro + distro_infos = dict(filter( + lambda x: x[1], + zip(["name", "version", "id"], distro.linux_distribution()), + )) + libc = dict(filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + )) + if libc: + distro_infos["libc"] = libc + if distro_infos: + data["distro"] = distro_infos + + if sys.platform.startswith("darwin") and platform.mac_ver()[0]: + data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} + + if platform.system(): + data.setdefault("system", {})["name"] = platform.system() + + if platform.release(): + data.setdefault("system", {})["release"] = platform.release() + + if platform.machine(): + data["cpu"] = platform.machine() + + if HAS_TLS: + data["openssl_version"] = ssl.OPENSSL_VERSION + + setuptools_version = get_installed_version("setuptools") + if setuptools_version is not None: + data["setuptools_version"] = setuptools_version + + return "{data[installer][name]}/{data[installer][version]} {json}".format( + data=data, + json=json.dumps(data, separators=(",", ":"), sort_keys=True), + ) + + +class MultiDomainBasicAuth(AuthBase): + + def __init__(self, prompting=True): + self.prompting = prompting + self.passwords = {} + + def __call__(self, req): + parsed = urllib_parse.urlparse(req.url) + + # Get the netloc without any embedded credentials + netloc = parsed.netloc.rsplit("@", 1)[-1] + + # Set the url of the request to the url without any credentials + req.url = urllib_parse.urlunparse(parsed[:1] + (netloc,) + parsed[2:]) + + # Use any stored credentials that we have for this netloc + username, password = self.passwords.get(netloc, (None, None)) + + # Extract credentials embedded in the url if we have none stored + if username is None: + username, password = self.parse_credentials(parsed.netloc) + + # Get creds from netrc if we still don't have them + if username is None and password is None: + netrc_auth = get_netrc_auth(req.url) + username, password = netrc_auth if netrc_auth else (None, None) + + if username or password: + # Store the username and password + self.passwords[netloc] = (username, password) + + # Send the basic auth with this request + req = HTTPBasicAuth(username or "", password or "")(req) + + # Attach a hook to handle 401 responses + req.register_hook("response", self.handle_401) + + return req + + def handle_401(self, resp, **kwargs): + # We only care about 401 responses, anything else we want to just + # pass through the actual response + if resp.status_code != 401: + return resp + + # We are not able to prompt the user so simply return the response + if not self.prompting: + return resp + + parsed = urllib_parse.urlparse(resp.url) + + # Prompt the user for a new username and password + username = six.moves.input("User for %s: " % parsed.netloc) + password = getpass.getpass("Password: ") + + # Store the new username and password to use for future requests + if username or password: + self.passwords[parsed.netloc] = (username, password) + + # Consume content and release the original connection to allow our new + # request to reuse the same one. + resp.content + resp.raw.release_conn() + + # Add our new username and password to the request + req = HTTPBasicAuth(username or "", password or "")(resp.request) + + # Send our new request + new_resp = resp.connection.send(req, **kwargs) + new_resp.history.append(resp) + + return new_resp + + def parse_credentials(self, netloc): + if "@" in netloc: + userinfo = netloc.rsplit("@", 1)[0] + if ":" in userinfo: + user, pwd = userinfo.split(":", 1) + return (urllib_unquote(user), urllib_unquote(pwd)) + return urllib_unquote(userinfo), None + return None, None + + +class LocalFSAdapter(BaseAdapter): + + def send(self, request, stream=None, timeout=None, verify=None, cert=None, + proxies=None): + pathname = url_to_path(request.url) + + resp = Response() + resp.status_code = 200 + resp.url = request.url + + try: + stats = os.stat(pathname) + except OSError as exc: + resp.status_code = 404 + resp.raw = exc + else: + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + content_type = mimetypes.guess_type(pathname)[0] or "text/plain" + resp.headers = CaseInsensitiveDict({ + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + }) + + resp.raw = open(pathname, "rb") + resp.close = resp.raw.close + + return resp + + def close(self): + pass + + +class SafeFileCache(FileCache): + """ + A file based cache which is safe to use even when the target directory may + not be accessible or writable. + """ + + def __init__(self, *args, **kwargs): + super(SafeFileCache, self).__init__(*args, **kwargs) + + # Check to ensure that the directory containing our cache directory + # is owned by the user current executing pip. If it does not exist + # we will check the parent directory until we find one that does exist. + # If it is not owned by the user executing pip then we will disable + # the cache and log a warning. + if not check_path_owner(self.directory): + logger.warning( + "The directory '%s' or its parent directory is not owned by " + "the current user and the cache has been disabled. Please " + "check the permissions and owner of that directory. If " + "executing pip with sudo, you may want sudo's -H flag.", + self.directory, + ) + + # Set our directory to None to disable the Cache + self.directory = None + + def get(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).get(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + def set(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).set(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + def delete(self, *args, **kwargs): + # If we don't have a directory, then the cache should be a no-op. + if self.directory is None: + return + + try: + return super(SafeFileCache, self).delete(*args, **kwargs) + except (LockError, OSError, IOError): + # We intentionally silence this error, if we can't access the cache + # then we can just skip caching and process the request as if + # caching wasn't enabled. + pass + + +class InsecureHTTPAdapter(HTTPAdapter): + + def cert_verify(self, conn, url, verify, cert): + conn.cert_reqs = 'CERT_NONE' + conn.ca_certs = None + + +class PipSession(requests.Session): + + timeout = None + + def __init__(self, *args, **kwargs): + retries = kwargs.pop("retries", 0) + cache = kwargs.pop("cache", None) + insecure_hosts = kwargs.pop("insecure_hosts", []) + + super(PipSession, self).__init__(*args, **kwargs) + + # Attach our User Agent to the request + self.headers["User-Agent"] = user_agent() + + # Attach our Authentication handler to the session + self.auth = MultiDomainBasicAuth() + + # Create our urllib3.Retry instance which will allow us to customize + # how we handle retries. + retries = urllib3.Retry( + # Set the total number of retries that a particular request can + # have. + total=retries, + + # A 503 error from PyPI typically means that the Fastly -> Origin + # connection got interrupted in some way. A 503 error in general + # is typically considered a transient error so we'll go ahead and + # retry it. + # A 500 may indicate transient error in Amazon S3 + # A 520 or 527 - may indicate transient error in CloudFlare + status_forcelist=[500, 503, 520, 527], + + # Add a small amount of back off between failed requests in + # order to prevent hammering the service. + backoff_factor=0.25, + ) + + # We want to _only_ cache responses on securely fetched origins. We do + # this because we can't validate the response of an insecurely fetched + # origin, and we don't want someone to be able to poison the cache and + # require manual eviction from the cache to fix it. + if cache: + secure_adapter = CacheControlAdapter( + cache=SafeFileCache(cache, use_dir_lock=True), + max_retries=retries, + ) + else: + secure_adapter = HTTPAdapter(max_retries=retries) + + # Our Insecure HTTPAdapter disables HTTPS validation. It does not + # support caching (see above) so we'll use it for all http:// URLs as + # well as any https:// host that we've marked as ignoring TLS errors + # for. + insecure_adapter = InsecureHTTPAdapter(max_retries=retries) + + self.mount("https://", secure_adapter) + self.mount("http://", insecure_adapter) + + # Enable file:// urls + self.mount("file://", LocalFSAdapter()) + + # We want to use a non-validating adapter for any requests which are + # deemed insecure. + for host in insecure_hosts: + self.mount("https://{}/".format(host), insecure_adapter) + + def request(self, method, url, *args, **kwargs): + # Allow setting a default timeout on a session + kwargs.setdefault("timeout", self.timeout) + + # Dispatch the actual request + return super(PipSession, self).request(method, url, *args, **kwargs) + + +def get_file_content(url, comes_from=None, session=None): + """Gets the content of a file; it may be a filename, file: URL, or + http: URL. Returns (location, content). Content is unicode. + + :param url: File path or url. + :param comes_from: Origin description of requirements. + :param session: Instance of pip.download.PipSession. + """ + if session is None: + raise TypeError( + "get_file_content() missing 1 required keyword argument: 'session'" + ) + + match = _scheme_re.search(url) + if match: + scheme = match.group(1).lower() + if (scheme == 'file' and comes_from and + comes_from.startswith('http')): + raise InstallationError( + 'Requirements file %s references URL %s, which is local' + % (comes_from, url)) + if scheme == 'file': + path = url.split(':', 1)[1] + path = path.replace('\\', '/') + match = _url_slash_drive_re.match(path) + if match: + path = match.group(1) + ':' + path.split('|', 1)[1] + path = urllib_parse.unquote(path) + if path.startswith('/'): + path = '/' + path.lstrip('/') + url = path + else: + # FIXME: catch some errors + resp = session.get(url) + resp.raise_for_status() + return resp.url, resp.text + try: + with open(url, 'rb') as f: + content = auto_decode(f.read()) + except IOError as exc: + raise InstallationError( + 'Could not open requirements file: %s' % str(exc) + ) + return url, content + + +_scheme_re = re.compile(r'^(http|https|file):', re.I) +_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) + + +def is_url(name): + """Returns true if the name looks like a URL""" + if ':' not in name: + return False + scheme = name.split(':', 1)[0].lower() + return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes + + +def url_to_path(url): + """ + Convert a file: URL to a path. + """ + assert url.startswith('file:'), ( + "You can only turn file: urls into filenames (not %r)" % url) + + _, netloc, path, _, _ = urllib_parse.urlsplit(url) + + # if we have a UNC path, prepend UNC share notation + if netloc: + netloc = '\\\\' + netloc + + path = urllib_request.url2pathname(netloc + path) + return path + + +def path_to_url(path): + """ + Convert a path to a file: URL. The path will be made absolute and have + quoted path parts. + """ + path = os.path.normpath(os.path.abspath(path)) + url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) + return url + + +def is_archive_file(name): + """Return True if `name` is a considered as an archive file.""" + ext = splitext(name)[1].lower() + if ext in ARCHIVE_EXTENSIONS: + return True + return False + + +def unpack_vcs_link(link, location): + vcs_backend = _get_used_vcs_backend(link) + vcs_backend.unpack(location) + + +def _get_used_vcs_backend(link): + for backend in vcs.backends: + if link.scheme in backend.schemes: + vcs_backend = backend(link.url) + return vcs_backend + + +def is_vcs_url(link): + return bool(_get_used_vcs_backend(link)) + + +def is_file_url(link): + return link.url.lower().startswith('file:') + + +def is_dir_url(link): + """Return whether a file:// Link points to a directory. + + ``link`` must not have any other scheme but file://. Call is_file_url() + first. + + """ + link_path = url_to_path(link.url_without_fragment) + return os.path.isdir(link_path) + + +def _progress_indicator(iterable, *args, **kwargs): + return iterable + + +def _download_url(resp, link, content_file, hashes, progress_bar): + try: + total_length = int(resp.headers['content-length']) + except (ValueError, KeyError, TypeError): + total_length = 0 + + cached_resp = getattr(resp, "from_cache", False) + if logger.getEffectiveLevel() > logging.INFO: + show_progress = False + elif cached_resp: + show_progress = False + elif total_length > (40 * 1000): + show_progress = True + elif not total_length: + show_progress = True + else: + show_progress = False + + show_url = link.show_url + + def resp_read(chunk_size): + try: + # Special case for urllib3. + for chunk in resp.raw.stream( + chunk_size, + # We use decode_content=False here because we don't + # want urllib3 to mess with the raw bytes we get + # from the server. If we decompress inside of + # urllib3 then we cannot verify the checksum + # because the checksum will be of the compressed + # file. This breakage will only occur if the + # server adds a Content-Encoding header, which + # depends on how the server was configured: + # - Some servers will notice that the file isn't a + # compressible file and will leave the file alone + # and with an empty Content-Encoding + # - Some servers will notice that the file is + # already compressed and will leave the file + # alone and will add a Content-Encoding: gzip + # header + # - Some servers won't notice anything at all and + # will take a file that's already been compressed + # and compress it again and set the + # Content-Encoding: gzip header + # + # By setting this not to decode automatically we + # hope to eliminate problems with the second case. + decode_content=False): + yield chunk + except AttributeError: + # Standard file-like object. + while True: + chunk = resp.raw.read(chunk_size) + if not chunk: + break + yield chunk + + def written_chunks(chunks): + for chunk in chunks: + content_file.write(chunk) + yield chunk + + progress_indicator = _progress_indicator + + if link.netloc == PyPI.netloc: + url = show_url + else: + url = link.url_without_fragment + + if show_progress: # We don't show progress on cached responses + progress_indicator = DownloadProgressProvider(progress_bar, + max=total_length) + if total_length: + logger.info("Downloading %s (%s)", url, format_size(total_length)) + else: + logger.info("Downloading %s", url) + elif cached_resp: + logger.info("Using cached %s", url) + else: + logger.info("Downloading %s", url) + + logger.debug('Downloading from URL %s', link) + + downloaded_chunks = written_chunks( + progress_indicator( + resp_read(CONTENT_CHUNK_SIZE), + CONTENT_CHUNK_SIZE + ) + ) + if hashes: + hashes.check_against_chunks(downloaded_chunks) + else: + consume(downloaded_chunks) + + +def _copy_file(filename, location, link): + copy = True + download_location = os.path.join(location, link.filename) + if os.path.exists(download_location): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)abort' % + display_path(download_location), ('i', 'w', 'b', 'a')) + if response == 'i': + copy = False + elif response == 'w': + logger.warning('Deleting %s', display_path(download_location)) + os.remove(download_location) + elif response == 'b': + dest_file = backup_dir(download_location) + logger.warning( + 'Backing up %s to %s', + display_path(download_location), + display_path(dest_file), + ) + shutil.move(download_location, dest_file) + elif response == 'a': + sys.exit(-1) + if copy: + shutil.copy(filename, download_location) + logger.info('Saved %s', display_path(download_location)) + + +def unpack_http_url(link, location, download_dir=None, + session=None, hashes=None, progress_bar="on"): + if session is None: + raise TypeError( + "unpack_http_url() missing 1 required keyword argument: 'session'" + ) + + with TempDirectory(kind="unpack") as temp_dir: + # If a download dir is specified, is the file already downloaded there? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, + download_dir, + hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + content_type = mimetypes.guess_type(from_path)[0] + else: + # let's download to a tmp dir + from_path, content_type = _download_http_url(link, + session, + temp_dir.path, + hashes, + progress_bar) + + # unpack the archive to the build dir location. even when only + # downloading archives, they have to be unpacked to parse dependencies + unpack_file(from_path, location, content_type, link) + + # a download dir is specified; let's copy the archive there + if download_dir and not already_downloaded_path: + _copy_file(from_path, download_dir, link) + + if not already_downloaded_path: + os.unlink(from_path) + + +def unpack_file_url(link, location, download_dir=None, hashes=None): + """Unpack link into location. + + If download_dir is provided and link points to a file, make a copy + of the link file inside download_dir. + """ + link_path = url_to_path(link.url_without_fragment) + + # If it's a url to a local directory + if is_dir_url(link): + if os.path.isdir(location): + rmtree(location) + shutil.copytree(link_path, location, symlinks=True) + if download_dir: + logger.info('Link is a directory, ignoring download_dir') + return + + # If --require-hashes is off, `hashes` is either empty, the + # link's embedded hash, or MissingHashes; it is required to + # match. If --require-hashes is on, we are satisfied by any + # hash in `hashes` matching: a URL-based or an option-based + # one; no internet-sourced hash will be in `hashes`. + if hashes: + hashes.check_against_path(link_path) + + # If a download dir is specified, is the file already there and valid? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir(link, + download_dir, + hashes) + + if already_downloaded_path: + from_path = already_downloaded_path + else: + from_path = link_path + + content_type = mimetypes.guess_type(from_path)[0] + + # unpack the archive to the build dir location. even when only downloading + # archives, they have to be unpacked to parse dependencies + unpack_file(from_path, location, content_type, link) + + # a download dir is specified and not already downloaded + if download_dir and not already_downloaded_path: + _copy_file(from_path, download_dir, link) + + +def _copy_dist_from_dir(link_path, location): + """Copy distribution files in `link_path` to `location`. + + Invoked when user requests to install a local directory. E.g.: + + pip install . + pip install ~/dev/git-repos/python-prompt-toolkit + + """ + + # Note: This is currently VERY SLOW if you have a lot of data in the + # directory, because it copies everything with `shutil.copytree`. + # What it should really do is build an sdist and install that. + # See https://github.com/pypa/pip/issues/2195 + + if os.path.isdir(location): + rmtree(location) + + # build an sdist + setup_py = 'setup.py' + sdist_args = [sys.executable] + sdist_args.append('-c') + sdist_args.append(SETUPTOOLS_SHIM % setup_py) + sdist_args.append('sdist') + sdist_args += ['--dist-dir', location] + logger.info('Running setup.py sdist for %s', link_path) + + with indent_log(): + call_subprocess(sdist_args, cwd=link_path, show_stdout=False) + + # unpack sdist into `location` + sdist = os.path.join(location, os.listdir(location)[0]) + logger.info('Unpacking sdist %s into %s', sdist, location) + unpack_file(sdist, location, content_type=None, link=None) + + +class PipXmlrpcTransport(xmlrpc_client.Transport): + """Provide a `xmlrpclib.Transport` implementation via a `PipSession` + object. + """ + + def __init__(self, index_url, session, use_datetime=False): + xmlrpc_client.Transport.__init__(self, use_datetime) + index_parts = urllib_parse.urlparse(index_url) + self._scheme = index_parts.scheme + self._session = session + + def request(self, host, handler, request_body, verbose=False): + parts = (self._scheme, host, handler, None, None, None) + url = urllib_parse.urlunparse(parts) + try: + headers = {'Content-Type': 'text/xml'} + response = self._session.post(url, data=request_body, + headers=headers, stream=True) + response.raise_for_status() + self.verbose = verbose + return self.parse_response(response.raw) + except requests.HTTPError as exc: + logger.critical( + "HTTP error %s while getting %s", + exc.response.status_code, url, + ) + raise + + +def unpack_url(link, location, download_dir=None, + only_download=False, session=None, hashes=None, + progress_bar="on"): + """Unpack link. + If link is a VCS link: + if only_download, export into download_dir and ignore location + else unpack into location + for other types of link: + - unpack into location + - if download_dir, copy the file into download_dir + - if only_download, mark location for deletion + + :param hashes: A Hashes object, one of whose embedded hashes must match, + or HashMismatch will be raised. If the Hashes is empty, no matches are + required, and unhashable types of requirements (like VCS ones, which + would ordinarily raise HashUnsupported) are allowed. + """ + # non-editable vcs urls + if is_vcs_url(link): + unpack_vcs_link(link, location) + + # file urls + elif is_file_url(link): + unpack_file_url(link, location, download_dir, hashes=hashes) + + # http urls + else: + if session is None: + session = PipSession() + + unpack_http_url( + link, + location, + download_dir, + session, + hashes=hashes, + progress_bar=progress_bar + ) + if only_download: + write_delete_marker_file(location) + + +def _download_http_url(link, session, temp_dir, hashes, progress_bar): + """Download link url into temp_dir using provided session""" + target_url = link.url.split('#', 1)[0] + try: + resp = session.get( + target_url, + # We use Accept-Encoding: identity here because requests + # defaults to accepting compressed responses. This breaks in + # a variety of ways depending on how the server is configured. + # - Some servers will notice that the file isn't a compressible + # file and will leave the file alone and with an empty + # Content-Encoding + # - Some servers will notice that the file is already + # compressed and will leave the file alone and will add a + # Content-Encoding: gzip header + # - Some servers won't notice anything at all and will take + # a file that's already been compressed and compress it again + # and set the Content-Encoding: gzip header + # By setting this to request only the identity encoding We're + # hoping to eliminate the third case. Hopefully there does not + # exist a server which when given a file will notice it is + # already compressed and that you're not asking for a + # compressed file and will then decompress it before sending + # because if that's the case I don't think it'll ever be + # possible to make this work. + headers={"Accept-Encoding": "identity"}, + stream=True, + ) + resp.raise_for_status() + except requests.HTTPError as exc: + logger.critical( + "HTTP error %s while getting %s", exc.response.status_code, link, + ) + raise + + content_type = resp.headers.get('content-type', '') + filename = link.filename # fallback + # Have a look at the Content-Disposition header for a better guess + content_disposition = resp.headers.get('content-disposition') + if content_disposition: + type, params = cgi.parse_header(content_disposition) + # We use ``or`` here because we don't want to use an "empty" value + # from the filename param. + filename = params.get('filename') or filename + ext = splitext(filename)[1] + if not ext: + ext = mimetypes.guess_extension(content_type) + if ext: + filename += ext + if not ext and link.url != resp.url: + ext = os.path.splitext(resp.url)[1] + if ext: + filename += ext + file_path = os.path.join(temp_dir, filename) + with open(file_path, 'wb') as content_file: + _download_url(resp, link, content_file, hashes, progress_bar) + return file_path, content_type + + +def _check_download_dir(link, download_dir, hashes): + """ Check download_dir for previously downloaded file with correct hash + If a correct file is found return its path else None + """ + download_path = os.path.join(download_dir, link.filename) + if os.path.exists(download_path): + # If already downloaded, does its hash match? + logger.info('File was already downloaded %s', download_path) + if hashes: + try: + hashes.check_against_path(download_path) + except HashMismatch: + logger.warning( + 'Previously-downloaded file %s has bad hash. ' + 'Re-downloading.', + download_path + ) + os.unlink(download_path) + return None + return download_path + return None diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py new file mode 100755 index 0000000..28705c8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/exceptions.py @@ -0,0 +1,249 @@ +"""Exceptions used throughout package""" +from __future__ import absolute_import + +from itertools import chain, groupby, repeat + +from pip._vendor.six import iteritems + + +class PipError(Exception): + """Base pip exception""" + + +class ConfigurationError(PipError): + """General exception in configuration""" + + +class InstallationError(PipError): + """General exception during installation""" + + +class UninstallationError(PipError): + """General exception during uninstallation""" + + +class DistributionNotFound(InstallationError): + """Raised when a distribution cannot be found to satisfy a requirement""" + + +class RequirementsFileParseError(InstallationError): + """Raised when a general error occurs parsing a requirements file line.""" + + +class BestVersionAlreadyInstalled(PipError): + """Raised when the most up-to-date version of a package is already + installed.""" + + +class BadCommand(PipError): + """Raised when virtualenv or a command is not found""" + + +class CommandError(PipError): + """Raised when there is an error in command-line arguments""" + + +class PreviousBuildDirError(PipError): + """Raised when there's a previous conflicting build directory""" + + +class InvalidWheelFilename(InstallationError): + """Invalid wheel filename.""" + + +class UnsupportedWheel(InstallationError): + """Unsupported wheel.""" + + +class HashErrors(InstallationError): + """Multiple HashError instances rolled into one for reporting""" + + def __init__(self): + self.errors = [] + + def append(self, error): + self.errors.append(error) + + def __str__(self): + lines = [] + self.errors.sort(key=lambda e: e.order) + for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): + lines.append(cls.head) + lines.extend(e.body() for e in errors_of_cls) + if lines: + return '\n'.join(lines) + + def __nonzero__(self): + return bool(self.errors) + + def __bool__(self): + return self.__nonzero__() + + +class HashError(InstallationError): + """ + A failure to verify a package against known-good hashes + + :cvar order: An int sorting hash exception classes by difficulty of + recovery (lower being harder), so the user doesn't bother fretting + about unpinned packages when he has deeper issues, like VCS + dependencies, to deal with. Also keeps error reports in a + deterministic order. + :cvar head: A section heading for display above potentially many + exceptions of this kind + :ivar req: The InstallRequirement that triggered this error. This is + pasted on after the exception is instantiated, because it's not + typically available earlier. + + """ + req = None + head = '' + + def body(self): + """Return a summary of me for display under the heading. + + This default implementation simply prints a description of the + triggering requirement. + + :param req: The InstallRequirement that provoked this error, with + populate_link() having already been called + + """ + return ' %s' % self._requirement_name() + + def __str__(self): + return '%s\n%s' % (self.head, self.body()) + + def _requirement_name(self): + """Return a description of the requirement that triggered me. + + This default implementation returns long description of the req, with + line numbers + + """ + return str(self.req) if self.req else 'unknown package' + + +class VcsHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 0 + head = ("Can't verify hashes for these requirements because we don't " + "have a way to hash version control repositories:") + + +class DirectoryUrlHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 1 + head = ("Can't verify hashes for these file:// requirements because they " + "point to directories:") + + +class HashMissing(HashError): + """A hash was needed for a requirement but is absent.""" + + order = 2 + head = ('Hashes are required in --require-hashes mode, but they are ' + 'missing from some requirements. Here is a list of those ' + 'requirements along with the hashes their downloaded archives ' + 'actually had. Add lines like these to your requirements files to ' + 'prevent tampering. (If you did not enable --require-hashes ' + 'manually, note that it turns on automatically when any package ' + 'has a hash.)') + + def __init__(self, gotten_hash): + """ + :param gotten_hash: The hash of the (possibly malicious) archive we + just downloaded + """ + self.gotten_hash = gotten_hash + + def body(self): + # Dodge circular import. + from pip._internal.utils.hashes import FAVORITE_HASH + + package = None + if self.req: + # In the case of URL-based requirements, display the original URL + # seen in the requirements file rather than the package name, + # so the output can be directly copied into the requirements file. + package = (self.req.original_link if self.req.original_link + # In case someone feeds something downright stupid + # to InstallRequirement's constructor. + else getattr(self.req, 'req', None)) + return ' %s --hash=%s:%s' % (package or 'unknown package', + FAVORITE_HASH, + self.gotten_hash) + + +class HashUnpinned(HashError): + """A requirement had a hash specified but was not pinned to a specific + version.""" + + order = 3 + head = ('In --require-hashes mode, all requirements must have their ' + 'versions pinned with ==. These do not:') + + +class HashMismatch(HashError): + """ + Distribution file hash values don't match. + + :ivar package_name: The name of the package that triggered the hash + mismatch. Feel free to write to this after the exception is raise to + improve its error message. + + """ + order = 4 + head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' + 'FILE. If you have updated the package versions, please update ' + 'the hashes. Otherwise, examine the package contents carefully; ' + 'someone may have tampered with them.') + + def __init__(self, allowed, gots): + """ + :param allowed: A dict of algorithm names pointing to lists of allowed + hex digests + :param gots: A dict of algorithm names pointing to hashes we + actually got from the files under suspicion + """ + self.allowed = allowed + self.gots = gots + + def body(self): + return ' %s:\n%s' % (self._requirement_name(), + self._hash_comparison()) + + def _hash_comparison(self): + """ + Return a comparison of actual and expected hash values. + + Example:: + + Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde + or 123451234512345123451234512345123451234512345 + Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef + + """ + def hash_then_or(hash_name): + # For now, all the decent hashes have 6-char names, so we can get + # away with hard-coding space literals. + return chain([hash_name], repeat(' or')) + + lines = [] + for hash_name, expecteds in iteritems(self.allowed): + prefix = hash_then_or(hash_name) + lines.extend((' Expected %s %s' % (next(prefix), e)) + for e in expecteds) + lines.append(' Got %s\n' % + self.gots[hash_name].hexdigest()) + prefix = ' or' + return '\n'.join(lines) + + +class UnsupportedPythonVersion(InstallationError): + """Unsupported python version according to Requires-Python package + metadata.""" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py new file mode 100755 index 0000000..15e0bf3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/index.py @@ -0,0 +1,1117 @@ +"""Routines related to PyPI, indexes""" +from __future__ import absolute_import + +import cgi +import itertools +import logging +import mimetypes +import os +import posixpath +import re +import sys +import warnings +from collections import namedtuple + +from pip._vendor import html5lib, requests, six +from pip._vendor.distlib.compat import unescape +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.requests.exceptions import SSLError +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.compat import ipaddress +from pip._internal.download import HAS_TLS, is_url, path_to_url, url_to_path +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, DistributionNotFound, InvalidWheelFilename, + UnsupportedWheel, +) +from pip._internal.models import PyPI +from pip._internal.pep425tags import get_supported +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, cached_property, normalize_path, + splitext, +) +from pip._internal.utils.packaging import check_requires_python +from pip._internal.wheel import Wheel, wheel_ext + +__all__ = ['FormatControl', 'fmt_ctl_handle_mutual_exclude', 'PackageFinder'] + + +SECURE_ORIGINS = [ + # protocol, hostname, port + # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) + ("https", "*", "*"), + ("*", "localhost", "*"), + ("*", "127.0.0.0/8", "*"), + ("*", "::1/128", "*"), + ("file", "*", None), + # ssh is always secure. + ("ssh", "*", "*"), +] + + +logger = logging.getLogger(__name__) + + +class InstallationCandidate(object): + + def __init__(self, project, version, location): + self.project = project + self.version = parse_version(version) + self.location = location + self._key = (self.project, self.version, self.location) + + def __repr__(self): + return "<InstallationCandidate({!r}, {!r}, {!r})>".format( + self.project, self.version, self.location, + ) + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, InstallationCandidate): + return NotImplemented + + return method(self._key, other._key) + + +class PackageFinder(object): + """This finds packages. + + This is meant to match easy_install's technique for looking for + packages, by reading pages and looking for appropriate links. + """ + + def __init__(self, find_links, index_urls, allow_all_prereleases=False, + trusted_hosts=None, process_dependency_links=False, + session=None, format_control=None, platform=None, + versions=None, abi=None, implementation=None): + """Create a PackageFinder. + + :param format_control: A FormatControl object or None. Used to control + the selection of source packages / binary packages when consulting + the index and links. + :param platform: A string or None. If None, searches for packages + that are supported by the current system. Otherwise, will find + packages that can be built on the platform passed in. These + packages will only be downloaded for distribution: they will + not be built locally. + :param versions: A list of strings or None. This is passed directly + to pep425tags.py in the get_supported() method. + :param abi: A string or None. This is passed directly + to pep425tags.py in the get_supported() method. + :param implementation: A string or None. This is passed directly + to pep425tags.py in the get_supported() method. + """ + if session is None: + raise TypeError( + "PackageFinder() missing 1 required keyword argument: " + "'session'" + ) + + # Build find_links. If an argument starts with ~, it may be + # a local file relative to a home directory. So try normalizing + # it and if it exists, use the normalized version. + # This is deliberately conservative - it might be fine just to + # blindly normalize anything starting with a ~... + self.find_links = [] + for link in find_links: + if link.startswith('~'): + new_link = normalize_path(link) + if os.path.exists(new_link): + link = new_link + self.find_links.append(link) + + self.index_urls = index_urls + self.dependency_links = [] + + # These are boring links that have already been logged somehow: + self.logged_links = set() + + self.format_control = format_control or FormatControl(set(), set()) + + # Domains that we won't emit warnings for when not using HTTPS + self.secure_origins = [ + ("*", host, "*") + for host in (trusted_hosts if trusted_hosts else []) + ] + + # Do we want to allow _all_ pre-releases? + self.allow_all_prereleases = allow_all_prereleases + + # Do we process dependency links? + self.process_dependency_links = process_dependency_links + + # The Session we'll use to make requests + self.session = session + + # The valid tags to check potential found wheel candidates against + self.valid_tags = get_supported( + versions=versions, + platform=platform, + abi=abi, + impl=implementation, + ) + + # If we don't have TLS enabled, then WARN if anyplace we're looking + # relies on TLS. + if not HAS_TLS: + for link in itertools.chain(self.index_urls, self.find_links): + parsed = urllib_parse.urlparse(link) + if parsed.scheme == "https": + logger.warning( + "pip is configured with locations that require " + "TLS/SSL, however the ssl module in Python is not " + "available." + ) + break + + def get_formatted_locations(self): + lines = [] + if self.index_urls and self.index_urls != [PyPI.simple_url]: + lines.append( + "Looking in indexes: {}".format(", ".join(self.index_urls)) + ) + if self.find_links: + lines.append( + "Looking in links: {}".format(", ".join(self.find_links)) + ) + return "\n".join(lines) + + def add_dependency_links(self, links): + # # FIXME: this shouldn't be global list this, it should only + # # apply to requirements of the package that specifies the + # # dependency_links value + # # FIXME: also, we should track comes_from (i.e., use Link) + if self.process_dependency_links: + warnings.warn( + "Dependency Links processing has been deprecated and will be " + "removed in a future release.", + RemovedInPip11Warning, + ) + self.dependency_links.extend(links) + + @staticmethod + def _sort_locations(locations, expand_dir=False): + """ + Sort locations into "files" (archives) and "urls", and return + a pair of lists (files,urls) + """ + files = [] + urls = [] + + # puts the url for the given file path into the appropriate list + def sort_path(path): + url = path_to_url(path) + if mimetypes.guess_type(url, strict=False)[0] == 'text/html': + urls.append(url) + else: + files.append(url) + + for url in locations: + + is_local_path = os.path.exists(url) + is_file_url = url.startswith('file:') + + if is_local_path or is_file_url: + if is_local_path: + path = url + else: + path = url_to_path(url) + if os.path.isdir(path): + if expand_dir: + path = os.path.realpath(path) + for item in os.listdir(path): + sort_path(os.path.join(path, item)) + elif is_file_url: + urls.append(url) + elif os.path.isfile(path): + sort_path(path) + else: + logger.warning( + "Url '%s' is ignored: it is neither a file " + "nor a directory.", url, + ) + elif is_url(url): + # Only add url with clear scheme + urls.append(url) + else: + logger.warning( + "Url '%s' is ignored. It is either a non-existing " + "path or lacks a specific scheme.", url, + ) + + return files, urls + + def _candidate_sort_key(self, candidate): + """ + Function used to generate link sort key for link tuples. + The greater the return value, the more preferred it is. + If not finding wheels, then sorted by version only. + If finding wheels, then the sort order is by version, then: + 1. existing installs + 2. wheels ordered via Wheel.support_index_min(self.valid_tags) + 3. source archives + Note: it was considered to embed this logic into the Link + comparison operators, but then different sdist links + with the same version, would have to be considered equal + """ + support_num = len(self.valid_tags) + build_tag = tuple() + if candidate.location.is_wheel: + # can raise InvalidWheelFilename + wheel = Wheel(candidate.location.filename) + if not wheel.supported(self.valid_tags): + raise UnsupportedWheel( + "%s is not a supported wheel for this platform. It " + "can't be sorted." % wheel.filename + ) + pri = -(wheel.support_index_min(self.valid_tags)) + if wheel.build_tag is not None: + match = re.match(r'^(\d+)(.*)$', wheel.build_tag) + build_tag_groups = match.groups() + build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) + else: # sdist + pri = -(support_num) + return (candidate.version, build_tag, pri) + + def _validate_secure_origin(self, logger, location): + # Determine if this url used a secure transport mechanism + parsed = urllib_parse.urlparse(str(location)) + origin = (parsed.scheme, parsed.hostname, parsed.port) + + # The protocol to use to see if the protocol matches. + # Don't count the repository type as part of the protocol: in + # cases such as "git+ssh", only use "ssh". (I.e., Only verify against + # the last scheme.) + protocol = origin[0].rsplit('+', 1)[-1] + + # Determine if our origin is a secure origin by looking through our + # hardcoded list of secure origins, as well as any additional ones + # configured on this PackageFinder instance. + for secure_origin in (SECURE_ORIGINS + self.secure_origins): + if protocol != secure_origin[0] and secure_origin[0] != "*": + continue + + try: + # We need to do this decode dance to ensure that we have a + # unicode object, even on Python 2.x. + addr = ipaddress.ip_address( + origin[1] + if ( + isinstance(origin[1], six.text_type) or + origin[1] is None + ) + else origin[1].decode("utf8") + ) + network = ipaddress.ip_network( + secure_origin[1] + if isinstance(secure_origin[1], six.text_type) + else secure_origin[1].decode("utf8") + ) + except ValueError: + # We don't have both a valid address or a valid network, so + # we'll check this origin against hostnames. + if (origin[1] and + origin[1].lower() != secure_origin[1].lower() and + secure_origin[1] != "*"): + continue + else: + # We have a valid address and network, so see if the address + # is contained within the network. + if addr not in network: + continue + + # Check to see if the port patches + if (origin[2] != secure_origin[2] and + secure_origin[2] != "*" and + secure_origin[2] is not None): + continue + + # If we've gotten here, then this origin matches the current + # secure origin and we should return True + return True + + # If we've gotten to this point, then the origin isn't secure and we + # will not accept it as a valid location to search. We will however + # log a warning that we are ignoring it. + logger.warning( + "The repository located at %s is not a trusted or secure host and " + "is being ignored. If this repository is available via HTTPS we " + "recommend you use HTTPS instead, otherwise you may silence " + "this warning and allow it anyway with '--trusted-host %s'.", + parsed.hostname, + parsed.hostname, + ) + + return False + + def _get_index_urls_locations(self, project_name): + """Returns the locations found via self.index_urls + + Checks the url_name on the main (first in the list) index and + use this url_name to produce all locations + """ + + def mkurl_pypi_url(url): + loc = posixpath.join( + url, + urllib_parse.quote(canonicalize_name(project_name))) + # For maximum compatibility with easy_install, ensure the path + # ends in a trailing slash. Although this isn't in the spec + # (and PyPI can handle it without the slash) some other index + # implementations might break if they relied on easy_install's + # behavior. + if not loc.endswith('/'): + loc = loc + '/' + return loc + + return [mkurl_pypi_url(url) for url in self.index_urls] + + def find_all_candidates(self, project_name): + """Find all available InstallationCandidate for project_name + + This checks index_urls, find_links and dependency_links. + All versions found are returned as an InstallationCandidate list. + + See _link_package_versions for details on which files are accepted + """ + index_locations = self._get_index_urls_locations(project_name) + index_file_loc, index_url_loc = self._sort_locations(index_locations) + fl_file_loc, fl_url_loc = self._sort_locations( + self.find_links, expand_dir=True, + ) + dep_file_loc, dep_url_loc = self._sort_locations(self.dependency_links) + + file_locations = (Link(url) for url in itertools.chain( + index_file_loc, fl_file_loc, dep_file_loc, + )) + + # We trust every url that the user has given us whether it was given + # via --index-url or --find-links + # We explicitly do not trust links that came from dependency_links + # We want to filter out any thing which does not have a secure origin. + url_locations = [ + link for link in itertools.chain( + (Link(url) for url in index_url_loc), + (Link(url) for url in fl_url_loc), + (Link(url) for url in dep_url_loc), + ) + if self._validate_secure_origin(logger, link) + ] + + logger.debug('%d location(s) to search for versions of %s:', + len(url_locations), project_name) + + for location in url_locations: + logger.debug('* %s', location) + + canonical_name = canonicalize_name(project_name) + formats = fmt_ctl_formats(self.format_control, canonical_name) + search = Search(project_name, canonical_name, formats) + find_links_versions = self._package_versions( + # We trust every directly linked archive in find_links + (Link(url, '-f') for url in self.find_links), + search + ) + + page_versions = [] + for page in self._get_pages(url_locations, project_name): + logger.debug('Analyzing links from page %s', page.url) + with indent_log(): + page_versions.extend( + self._package_versions(page.links, search) + ) + + dependency_versions = self._package_versions( + (Link(url) for url in self.dependency_links), search + ) + if dependency_versions: + logger.debug( + 'dependency_links found: %s', + ', '.join([ + version.location.url for version in dependency_versions + ]) + ) + + file_versions = self._package_versions(file_locations, search) + if file_versions: + file_versions.sort(reverse=True) + logger.debug( + 'Local files found: %s', + ', '.join([ + url_to_path(candidate.location.url) + for candidate in file_versions + ]) + ) + + # This is an intentional priority ordering + return ( + file_versions + find_links_versions + page_versions + + dependency_versions + ) + + def find_requirement(self, req, upgrade): + """Try to find a Link matching req + + Expects req, an InstallRequirement and upgrade, a boolean + Returns a Link if found, + Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise + """ + all_candidates = self.find_all_candidates(req.name) + + # Filter out anything which doesn't match our specifier + compatible_versions = set( + req.specifier.filter( + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + [str(c.version) for c in all_candidates], + prereleases=( + self.allow_all_prereleases + if self.allow_all_prereleases else None + ), + ) + ) + applicable_candidates = [ + # Again, converting to str to deal with debundling. + c for c in all_candidates if str(c.version) in compatible_versions + ] + + if applicable_candidates: + best_candidate = max(applicable_candidates, + key=self._candidate_sort_key) + else: + best_candidate = None + + if req.satisfied_by is not None: + installed_version = parse_version(req.satisfied_by.version) + else: + installed_version = None + + if installed_version is None and best_candidate is None: + logger.critical( + 'Could not find a version that satisfies the requirement %s ' + '(from versions: %s)', + req, + ', '.join( + sorted( + {str(c.version) for c in all_candidates}, + key=parse_version, + ) + ) + ) + + raise DistributionNotFound( + 'No matching distribution found for %s' % req + ) + + best_installed = False + if installed_version and ( + best_candidate is None or + best_candidate.version <= installed_version): + best_installed = True + + if not upgrade and installed_version is not None: + if best_installed: + logger.debug( + 'Existing installed version (%s) is most up-to-date and ' + 'satisfies requirement', + installed_version, + ) + else: + logger.debug( + 'Existing installed version (%s) satisfies requirement ' + '(most up-to-date version is %s)', + installed_version, + best_candidate.version, + ) + return None + + if best_installed: + # We have an existing version, and its the best version + logger.debug( + 'Installed version (%s) is most up-to-date (past versions: ' + '%s)', + installed_version, + ', '.join(sorted(compatible_versions, key=parse_version)) or + "none", + ) + raise BestVersionAlreadyInstalled + + logger.debug( + 'Using version %s (newest of versions: %s)', + best_candidate.version, + ', '.join(sorted(compatible_versions, key=parse_version)) + ) + return best_candidate.location + + def _get_pages(self, locations, project_name): + """ + Yields (page, page_url) from the given locations, skipping + locations that have errors. + """ + seen = set() + for location in locations: + if location in seen: + continue + seen.add(location) + + page = self._get_page(location) + if page is None: + continue + + yield page + + _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') + + def _sort_links(self, links): + """ + Returns elements of links in order, non-egg links first, egg links + second, while eliminating duplicates + """ + eggs, no_eggs = [], [] + seen = set() + for link in links: + if link not in seen: + seen.add(link) + if link.egg_fragment: + eggs.append(link) + else: + no_eggs.append(link) + return no_eggs + eggs + + def _package_versions(self, links, search): + result = [] + for link in self._sort_links(links): + v = self._link_package_versions(link, search) + if v is not None: + result.append(v) + return result + + def _log_skipped_link(self, link, reason): + if link not in self.logged_links: + logger.debug('Skipping link %s; %s', link, reason) + self.logged_links.add(link) + + def _link_package_versions(self, link, search): + """Return an InstallationCandidate or None""" + version = None + if link.egg_fragment: + egg_info = link.egg_fragment + ext = link.ext + else: + egg_info, ext = link.splitext() + if not ext: + self._log_skipped_link(link, 'not a file') + return + if ext not in SUPPORTED_EXTENSIONS: + self._log_skipped_link( + link, 'unsupported archive format: %s' % ext, + ) + return + if "binary" not in search.formats and ext == wheel_ext: + self._log_skipped_link( + link, 'No binaries permitted for %s' % search.supplied, + ) + return + if "macosx10" in link.path and ext == '.zip': + self._log_skipped_link(link, 'macosx10 one') + return + if ext == wheel_ext: + try: + wheel = Wheel(link.filename) + except InvalidWheelFilename: + self._log_skipped_link(link, 'invalid wheel filename') + return + if canonicalize_name(wheel.name) != search.canonical: + self._log_skipped_link( + link, 'wrong project name (not %s)' % search.supplied) + return + + if not wheel.supported(self.valid_tags): + self._log_skipped_link( + link, 'it is not compatible with this Python') + return + + version = wheel.version + + # This should be up by the search.ok_binary check, but see issue 2700. + if "source" not in search.formats and ext != wheel_ext: + self._log_skipped_link( + link, 'No sources permitted for %s' % search.supplied, + ) + return + + if not version: + version = egg_info_matches(egg_info, search.supplied, link) + if version is None: + self._log_skipped_link( + link, 'wrong project name (not %s)' % search.supplied) + return + + match = self._py_version_re.search(version) + if match: + version = version[:match.start()] + py_version = match.group(1) + if py_version != sys.version[:3]: + self._log_skipped_link( + link, 'Python version is incorrect') + return + try: + support_this_python = check_requires_python(link.requires_python) + except specifiers.InvalidSpecifier: + logger.debug("Package %s has an invalid Requires-Python entry: %s", + link.filename, link.requires_python) + support_this_python = True + + if not support_this_python: + logger.debug("The package %s is incompatible with the python" + "version in use. Acceptable python versions are:%s", + link, link.requires_python) + return + logger.debug('Found link %s, version: %s', link, version) + + return InstallationCandidate(search.supplied, version, link) + + def _get_page(self, link): + return HTMLPage.get_page(link, session=self.session) + + +def egg_info_matches( + egg_info, search_name, link, + _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)): + """Pull the version part out of a string. + + :param egg_info: The string to parse. E.g. foo-2.1 + :param search_name: The name of the package this belongs to. None to + infer the name. Note that this cannot unambiguously parse strings + like foo-2-2 which might be foo, 2-2 or foo-2, 2. + :param link: The link the string came from, for logging on failure. + """ + match = _egg_info_re.search(egg_info) + if not match: + logger.debug('Could not parse version from link: %s', link) + return None + if search_name is None: + full_match = match.group(0) + return full_match[full_match.index('-'):] + name = match.group(0).lower() + # To match the "safe" name that pkg_resources creates: + name = name.replace('_', '-') + # project name and version must be separated by a dash + look_for = search_name.lower() + "-" + if name.startswith(look_for): + return match.group(0)[len(look_for):] + else: + return None + + +class HTMLPage(object): + """Represents one page, along with its URL""" + + def __init__(self, content, url, headers=None): + # Determine if we have any encoding information in our headers + encoding = None + if headers and "Content-Type" in headers: + content_type, params = cgi.parse_header(headers["Content-Type"]) + + if "charset" in params: + encoding = params['charset'] + + self.content = content + self.parsed = html5lib.parse( + self.content, + transport_encoding=encoding, + namespaceHTMLElements=False, + ) + self.url = url + self.headers = headers + + def __str__(self): + return self.url + + @classmethod + def get_page(cls, link, skip_archives=True, session=None): + if session is None: + raise TypeError( + "get_page() missing 1 required keyword argument: 'session'" + ) + + url = link.url + url = url.split('#', 1)[0] + + # Check for VCS schemes that do not support lookup as web pages. + from pip._internal.vcs import VcsSupport + for scheme in VcsSupport.schemes: + if url.lower().startswith(scheme) and url[len(scheme)] in '+:': + logger.debug('Cannot look at %s URL %s', scheme, link) + return None + + try: + if skip_archives: + filename = link.filename + for bad_ext in ARCHIVE_EXTENSIONS: + if filename.endswith(bad_ext): + content_type = cls._get_content_type( + url, session=session, + ) + if content_type.lower().startswith('text/html'): + break + else: + logger.debug( + 'Skipping page %s because of Content-Type: %s', + link, + content_type, + ) + return + + logger.debug('Getting page %s', url) + + # Tack index.html onto file:// URLs that point to directories + (scheme, netloc, path, params, query, fragment) = \ + urllib_parse.urlparse(url) + if (scheme == 'file' and + os.path.isdir(urllib_request.url2pathname(path))): + # add trailing slash if not present so urljoin doesn't trim + # final segment + if not url.endswith('/'): + url += '/' + url = urllib_parse.urljoin(url, 'index.html') + logger.debug(' file: URL is directory, getting %s', url) + + resp = session.get( + url, + headers={ + "Accept": "text/html", + "Cache-Control": "max-age=600", + }, + ) + resp.raise_for_status() + + # The check for archives above only works if the url ends with + # something that looks like an archive. However that is not a + # requirement of an url. Unless we issue a HEAD request on every + # url we cannot know ahead of time for sure if something is HTML + # or not. However we can check after we've downloaded it. + content_type = resp.headers.get('Content-Type', 'unknown') + if not content_type.lower().startswith("text/html"): + logger.debug( + 'Skipping page %s because of Content-Type: %s', + link, + content_type, + ) + return + + inst = cls(resp.content, resp.url, resp.headers) + except requests.HTTPError as exc: + cls._handle_fail(link, exc, url) + except SSLError as exc: + reason = "There was a problem confirming the ssl certificate: " + reason += str(exc) + cls._handle_fail(link, reason, url, meth=logger.info) + except requests.ConnectionError as exc: + cls._handle_fail(link, "connection error: %s" % exc, url) + except requests.Timeout: + cls._handle_fail(link, "timed out", url) + else: + return inst + + @staticmethod + def _handle_fail(link, reason, url, meth=None): + if meth is None: + meth = logger.debug + + meth("Could not fetch URL %s: %s - skipping", link, reason) + + @staticmethod + def _get_content_type(url, session): + """Get the Content-Type of the given url, using a HEAD request""" + scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) + if scheme not in {'http', 'https'}: + # FIXME: some warning or something? + # assertion error? + return '' + + resp = session.head(url, allow_redirects=True) + resp.raise_for_status() + + return resp.headers.get("Content-Type", "") + + @cached_property + def base_url(self): + bases = [ + x for x in self.parsed.findall(".//base") + if x.get("href") is not None + ] + if bases and bases[0].get("href"): + return bases[0].get("href") + else: + return self.url + + @property + def links(self): + """Yields all links in the page""" + for anchor in self.parsed.findall(".//a"): + if anchor.get("href"): + href = anchor.get("href") + url = self.clean_link( + urllib_parse.urljoin(self.base_url, href) + ) + pyrequire = anchor.get('data-requires-python') + pyrequire = unescape(pyrequire) if pyrequire else None + yield Link(url, self, requires_python=pyrequire) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + def clean_link(self, url): + """Makes sure a link is fully encoded. That is, if a ' ' shows up in + the link, it will be rewritten to %20 (while not over-quoting + % or other characters).""" + return self._clean_re.sub( + lambda match: '%%%2x' % ord(match.group(0)), url) + + +class Link(object): + + def __init__(self, url, comes_from=None, requires_python=None): + """ + Object representing a parsed link from https://pypi.org/simple/* + + url: + url of the resource pointed to (href of the link) + comes_from: + instance of HTMLPage where the link was found, or string. + requires_python: + String containing the `Requires-Python` metadata field, specified + in PEP 345. This may be specified by a data-requires-python + attribute in the HTML link tag, as described in PEP 503. + """ + + # url can be a UNC windows share + if url.startswith('\\\\'): + url = path_to_url(url) + + self.url = url + self.comes_from = comes_from + self.requires_python = requires_python if requires_python else None + + def __str__(self): + if self.requires_python: + rp = ' (requires-python:%s)' % self.requires_python + else: + rp = '' + if self.comes_from: + return '%s (from %s)%s' % (self.url, self.comes_from, rp) + else: + return str(self.url) + + def __repr__(self): + return '<Link %s>' % self + + def __eq__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url == other.url + + def __ne__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url != other.url + + def __lt__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url < other.url + + def __le__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url <= other.url + + def __gt__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url > other.url + + def __ge__(self, other): + if not isinstance(other, Link): + return NotImplemented + return self.url >= other.url + + def __hash__(self): + return hash(self.url) + + @property + def filename(self): + _, netloc, path, _, _ = urllib_parse.urlsplit(self.url) + name = posixpath.basename(path.rstrip('/')) or netloc + name = urllib_parse.unquote(name) + assert name, ('URL %r produced no filename' % self.url) + return name + + @property + def scheme(self): + return urllib_parse.urlsplit(self.url)[0] + + @property + def netloc(self): + return urllib_parse.urlsplit(self.url)[1] + + @property + def path(self): + return urllib_parse.unquote(urllib_parse.urlsplit(self.url)[2]) + + def splitext(self): + return splitext(posixpath.basename(self.path.rstrip('/'))) + + @property + def ext(self): + return self.splitext()[1] + + @property + def url_without_fragment(self): + scheme, netloc, path, query, fragment = urllib_parse.urlsplit(self.url) + return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) + + _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') + + @property + def egg_fragment(self): + match = self._egg_fragment_re.search(self.url) + if not match: + return None + return match.group(1) + + _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') + + @property + def subdirectory_fragment(self): + match = self._subdirectory_fragment_re.search(self.url) + if not match: + return None + return match.group(1) + + _hash_re = re.compile( + r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' + ) + + @property + def hash(self): + match = self._hash_re.search(self.url) + if match: + return match.group(2) + return None + + @property + def hash_name(self): + match = self._hash_re.search(self.url) + if match: + return match.group(1) + return None + + @property + def show_url(self): + return posixpath.basename(self.url.split('#', 1)[0].split('?', 1)[0]) + + @property + def is_wheel(self): + return self.ext == wheel_ext + + @property + def is_artifact(self): + """ + Determines if this points to an actual artifact (e.g. a tarball) or if + it points to an "abstract" thing like a path or a VCS location. + """ + from pip._internal.vcs import vcs + + if self.scheme in vcs.all_schemes: + return False + + return True + + +FormatControl = namedtuple('FormatControl', 'no_binary only_binary') +"""This object has two fields, no_binary and only_binary. + +If a field is falsy, it isn't set. If it is {':all:'}, it should match all +packages except those listed in the other field. Only one field can be set +to {':all:'} at a time. The rest of the time exact package name matches +are listed, with any given package only showing up in one field at a time. +""" + + +def fmt_ctl_handle_mutual_exclude(value, target, other): + new = value.split(',') + while ':all:' in new: + other.clear() + target.clear() + target.add(':all:') + del new[:new.index(':all:') + 1] + if ':none:' not in new: + # Without a none, we want to discard everything as :all: covers it + return + for name in new: + if name == ':none:': + target.clear() + continue + name = canonicalize_name(name) + other.discard(name) + target.add(name) + + +def fmt_ctl_formats(fmt_ctl, canonical_name): + result = {"binary", "source"} + if canonical_name in fmt_ctl.only_binary: + result.discard('source') + elif canonical_name in fmt_ctl.no_binary: + result.discard('binary') + elif ':all:' in fmt_ctl.only_binary: + result.discard('source') + elif ':all:' in fmt_ctl.no_binary: + result.discard('binary') + return frozenset(result) + + +def fmt_ctl_no_binary(fmt_ctl): + fmt_ctl_handle_mutual_exclude( + ':all:', fmt_ctl.no_binary, fmt_ctl.only_binary, + ) + + +Search = namedtuple('Search', 'supplied canonical formats') +"""Capture key aspects of a search. + +:attribute supplied: The user supplied package. +:attribute canonical: The canonical package name. +:attribute formats: The formats allowed for this package. Should be a set + with 'binary' or 'source' or both in it. +""" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py new file mode 100755 index 0000000..ce8f7e9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/locations.py @@ -0,0 +1,194 @@ +"""Locations where we look for configs, install stuff, etc""" +from __future__ import absolute_import + +import os +import os.path +import platform +import site +import sys +import sysconfig +from distutils import sysconfig as distutils_sysconfig +from distutils.command.install import SCHEME_KEYS, install # type: ignore + +from pip._internal.compat import WINDOWS, expanduser +from pip._internal.utils import appdirs + +# Application Directories +USER_CACHE_DIR = appdirs.user_cache_dir("pip") + + +DELETE_MARKER_MESSAGE = '''\ +This file is placed here by pip to indicate the source was put +here by pip. + +Once this package is successfully installed this source code will be +deleted (unless you remove this file). +''' +PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt' + + +def write_delete_marker_file(directory): + """ + Write the pip delete marker file into this directory. + """ + filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME) + with open(filepath, 'w') as marker_fp: + marker_fp.write(DELETE_MARKER_MESSAGE) + + +def running_under_virtualenv(): + """ + Return True if we're running inside a virtualenv, False otherwise. + + """ + if hasattr(sys, 'real_prefix'): + return True + elif sys.prefix != getattr(sys, "base_prefix", sys.prefix): + return True + + return False + + +def virtualenv_no_global(): + """ + Return True if in a venv and no system site packages. + """ + # this mirrors the logic in virtualenv.py for locating the + # no-global-site-packages.txt file + site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) + no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt') + if running_under_virtualenv() and os.path.isfile(no_global_file): + return True + + +if running_under_virtualenv(): + src_prefix = os.path.join(sys.prefix, 'src') +else: + # FIXME: keep src in cwd for now (it is not a temporary folder) + try: + src_prefix = os.path.join(os.getcwd(), 'src') + except OSError: + # In case the current working directory has been renamed or deleted + sys.exit( + "The folder you are executing pip from can no longer be found." + ) + +# under macOS + virtualenv sys.prefix is not properly resolved +# it is something like /path/to/python/bin/.. +# Note: using realpath due to tmp dirs on OSX being symlinks +src_prefix = os.path.abspath(src_prefix) + +# FIXME doesn't account for venv linked to global site-packages + +site_packages = sysconfig.get_path("purelib") +# This is because of a bug in PyPy's sysconfig module, see +# https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths +# for more information. +if platform.python_implementation().lower() == "pypy": + site_packages = distutils_sysconfig.get_python_lib() +try: + # Use getusersitepackages if this is present, as it ensures that the + # value is initialised properly. + user_site = site.getusersitepackages() +except AttributeError: + user_site = site.USER_SITE +user_dir = expanduser('~') +if WINDOWS: + bin_py = os.path.join(sys.prefix, 'Scripts') + bin_user = os.path.join(user_site, 'Scripts') + # buildout uses 'bin' on Windows too? + if not os.path.exists(bin_py): + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') + + config_basename = 'pip.ini' + + legacy_storage_dir = os.path.join(user_dir, 'pip') + legacy_config_file = os.path.join( + legacy_storage_dir, + config_basename, + ) +else: + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') + + config_basename = 'pip.conf' + + legacy_storage_dir = os.path.join(user_dir, '.pip') + legacy_config_file = os.path.join( + legacy_storage_dir, + config_basename, + ) + # Forcing to use /usr/local/bin for standard macOS framework installs + # Also log to ~/Library/Logs/ for use with the Console.app log viewer + if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': + bin_py = '/usr/local/bin' + +site_config_files = [ + os.path.join(path, config_basename) + for path in appdirs.site_config_dirs('pip') +] + +venv_config_file = os.path.join(sys.prefix, config_basename) +new_config_file = os.path.join(appdirs.user_config_dir("pip"), config_basename) + + +def distutils_scheme(dist_name, user=False, home=None, root=None, + isolated=False, prefix=None): + """ + Return a distutils install scheme + """ + from distutils.dist import Distribution + + scheme = {} + + if isolated: + extra_dist_args = {"script_args": ["--no-user-cfg"]} + else: + extra_dist_args = {} + dist_args = {'name': dist_name} + dist_args.update(extra_dist_args) + + d = Distribution(dist_args) + d.parse_config_files() + i = d.get_command_obj('install', create=True) + # NOTE: setting user or home has the side-effect of creating the home dir + # or user base for installations during finalize_options() + # ideally, we'd prefer a scheme class that has no side-effects. + assert not (user and prefix), "user={} prefix={}".format(user, prefix) + i.user = user or i.user + if user: + i.prefix = "" + i.prefix = prefix or i.prefix + i.home = home or i.home + i.root = root or i.root + i.finalize_options() + for key in SCHEME_KEYS: + scheme[key] = getattr(i, 'install_' + key) + + # install_lib specified in setup.cfg should install *everything* + # into there (i.e. it takes precedence over both purelib and + # platlib). Note, i.install_lib is *always* set after + # finalize_options(); we only want to override here if the user + # has explicitly requested it hence going back to the config + if 'install_lib' in d.get_option_dict('install'): + scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) + + if running_under_virtualenv(): + scheme['headers'] = os.path.join( + sys.prefix, + 'include', + 'site', + 'python' + sys.version[:3], + dist_name, + ) + + if root is not None: + path_no_drive = os.path.splitdrive( + os.path.abspath(scheme["headers"]))[1] + scheme["headers"] = os.path.join( + root, + path_no_drive[1:], + ) + + return scheme diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py new file mode 100755 index 0000000..2d080a4 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/__init__.py @@ -0,0 +1,4 @@ +from pip._internal.models.index import Index, PyPI + + +__all__ = ["Index", "PyPI"] diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py new file mode 100755 index 0000000..161de50 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/models/index.py @@ -0,0 +1,15 @@ +from pip._vendor.six.moves.urllib import parse as urllib_parse + + +class Index(object): + def __init__(self, url): + self.url = url + self.netloc = urllib_parse.urlsplit(url).netloc + self.simple_url = self.url_to_path('simple') + self.pypi_url = self.url_to_path('pypi') + + def url_to_path(self, path): + return urllib_parse.urljoin(self.url, path) + + +PyPI = Index('https://pypi.org/') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py new file mode 100755 index 0000000..bab6b9f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/check.py @@ -0,0 +1,106 @@ +"""Validation of dependencies of packages +""" + +from collections import namedtuple + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.operations.prepare import make_abstract_dist + +from pip._internal.utils.misc import get_installed_distributions +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._internal.req.req_install import InstallRequirement + from typing import Any, Dict, Iterator, Set, Tuple, List + + # Shorthands + PackageSet = Dict[str, 'PackageDetails'] + Missing = Tuple[str, Any] + Conflicting = Tuple[str, str, Any] + + MissingDict = Dict[str, List[Missing]] + ConflictingDict = Dict[str, List[Conflicting]] + CheckResult = Tuple[MissingDict, ConflictingDict] + +PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) + + +def create_package_set_from_installed(**kwargs): + # type: (**Any) -> PackageSet + """Converts a list of distributions into a PackageSet. + """ + # Default to using all packages installed on the system + if kwargs == {}: + kwargs = {"local_only": False, "skip": ()} + retval = {} + for dist in get_installed_distributions(**kwargs): + name = canonicalize_name(dist.project_name) + retval[name] = PackageDetails(dist.version, dist.requires()) + return retval + + +def check_package_set(package_set): + # type: (PackageSet) -> CheckResult + """Check if a package set is consistent + """ + missing = dict() + conflicting = dict() + + for package_name in package_set: + # Info about dependencies of package_name + missing_deps = set() # type: Set[Missing] + conflicting_deps = set() # type: Set[Conflicting] + + for req in package_set[package_name].requires: + name = canonicalize_name(req.project_name) # type: str + + # Check if it's missing + if name not in package_set: + missed = True + if req.marker is not None: + missed = req.marker.evaluate() + if missed: + missing_deps.add((name, req)) + continue + + # Check if there's a conflict + version = package_set[name].version # type: str + if not req.specifier.contains(version, prereleases=True): + conflicting_deps.add((name, version, req)) + + def str_key(x): + return str(x) + + if missing_deps: + missing[package_name] = sorted(missing_deps, key=str_key) + if conflicting_deps: + conflicting[package_name] = sorted(conflicting_deps, key=str_key) + + return missing, conflicting + + +def check_install_conflicts(to_install): + # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] + """For checking if the dependency graph would be consistent after \ + installing given requirements + """ + # Start from the current state + state = create_package_set_from_installed() + _simulate_installation_of(to_install, state) + return state, check_package_set(state) + + +# NOTE from @pradyunsg +# This required a minor update in dependency link handling logic over at +# operations.prepare.IsSDist.dist() to get it working +def _simulate_installation_of(to_install, state): + # type: (List[InstallRequirement], PackageSet) -> None + """Computes the version of packages after installing to_install. + """ + + # Modify it as installing requirement_set would (assuming no errors) + for inst_req in to_install: + dist = make_abstract_dist(inst_req).dist(finder=None) + name = canonicalize_name(dist.key) + state[name] = PackageDetails(dist.version, dist.requires()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py new file mode 100755 index 0000000..000102d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/freeze.py @@ -0,0 +1,252 @@ +from __future__ import absolute_import + +import collections +import logging +import os +import re +import warnings + +from pip._vendor import pkg_resources, six +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.pkg_resources import RequirementParseError + +from pip._internal.exceptions import InstallationError +from pip._internal.req import InstallRequirement +from pip._internal.req.req_file import COMMENT_RE +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.misc import ( + dist_is_editable, get_installed_distributions, +) + +logger = logging.getLogger(__name__) + + +def freeze( + requirement=None, + find_links=None, local_only=None, user_only=None, skip_regex=None, + isolated=False, + wheel_cache=None, + exclude_editable=False, + skip=()): + find_links = find_links or [] + skip_match = None + + if skip_regex: + skip_match = re.compile(skip_regex).search + + dependency_links = [] + + for dist in pkg_resources.working_set: + if dist.has_metadata('dependency_links.txt'): + dependency_links.extend( + dist.get_metadata_lines('dependency_links.txt') + ) + for link in find_links: + if '#egg=' in link: + dependency_links.append(link) + for link in find_links: + yield '-f %s' % link + installations = {} + for dist in get_installed_distributions(local_only=local_only, + skip=(), + user_only=user_only): + try: + req = FrozenRequirement.from_dist( + dist, + dependency_links + ) + except RequirementParseError: + logger.warning( + "Could not parse requirement: %s", + dist.project_name + ) + continue + if exclude_editable and req.editable: + continue + installations[req.name] = req + + if requirement: + # the options that don't get turned into an InstallRequirement + # should only be emitted once, even if the same option is in multiple + # requirements files, so we need to keep track of what has been emitted + # so that we don't emit it again if it's seen again + emitted_options = set() + # keep track of which files a requirement is in so that we can + # give an accurate warning if a requirement appears multiple times. + req_files = collections.defaultdict(list) + for req_file_path in requirement: + with open(req_file_path) as req_file: + for line in req_file: + if (not line.strip() or + line.strip().startswith('#') or + (skip_match and skip_match(line)) or + line.startswith(( + '-r', '--requirement', + '-Z', '--always-unzip', + '-f', '--find-links', + '-i', '--index-url', + '--pre', + '--trusted-host', + '--process-dependency-links', + '--extra-index-url'))): + line = line.rstrip() + if line not in emitted_options: + emitted_options.add(line) + yield line + continue + + if line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + line_req = InstallRequirement.from_editable( + line, + isolated=isolated, + wheel_cache=wheel_cache, + ) + else: + line_req = InstallRequirement.from_line( + COMMENT_RE.sub('', line).strip(), + isolated=isolated, + wheel_cache=wheel_cache, + ) + + if not line_req.name: + logger.info( + "Skipping line in requirement file [%s] because " + "it's not clear what it would install: %s", + req_file_path, line.strip(), + ) + logger.info( + " (add #egg=PackageName to the URL to avoid" + " this warning)" + ) + elif line_req.name not in installations: + # either it's not installed, or it is installed + # but has been processed already + if not req_files[line_req.name]: + logger.warning( + "Requirement file [%s] contains %s, but that " + "package is not installed", + req_file_path, + COMMENT_RE.sub('', line).strip(), + ) + else: + req_files[line_req.name].append(req_file_path) + else: + yield str(installations[line_req.name]).rstrip() + del installations[line_req.name] + req_files[line_req.name].append(req_file_path) + + # Warn about requirements that were included multiple times (in a + # single requirements file or in different requirements files). + for name, files in six.iteritems(req_files): + if len(files) > 1: + logger.warning("Requirement %s included multiple times [%s]", + name, ', '.join(sorted(set(files)))) + + yield( + '## The following requirements were added by ' + 'pip freeze:' + ) + for installation in sorted( + installations.values(), key=lambda x: x.name.lower()): + if canonicalize_name(installation.name) not in skip: + yield str(installation).rstrip() + + +class FrozenRequirement(object): + def __init__(self, name, req, editable, comments=()): + self.name = name + self.req = req + self.editable = editable + self.comments = comments + + _rev_re = re.compile(r'-r(\d+)$') + _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') + + @classmethod + def from_dist(cls, dist, dependency_links): + location = os.path.normcase(os.path.abspath(dist.location)) + comments = [] + from pip._internal.vcs import vcs, get_src_requirement + if dist_is_editable(dist) and vcs.get_backend_name(location): + editable = True + try: + req = get_src_requirement(dist, location) + except InstallationError as exc: + logger.warning( + "Error when trying to get requirement for VCS system %s, " + "falling back to uneditable format", exc + ) + req = None + if req is None: + logger.warning( + 'Could not determine repository location of %s', location + ) + comments.append( + '## !! Could not determine repository location' + ) + req = dist.as_requirement() + editable = False + else: + editable = False + req = dist.as_requirement() + specs = req.specs + assert len(specs) == 1 and specs[0][0] in ["==", "==="], \ + 'Expected 1 spec with == or ===; specs = %r; dist = %r' % \ + (specs, dist) + version = specs[0][1] + ver_match = cls._rev_re.search(version) + date_match = cls._date_re.search(version) + if ver_match or date_match: + svn_backend = vcs.get_backend('svn') + if svn_backend: + svn_location = svn_backend().get_location( + dist, + dependency_links, + ) + if not svn_location: + logger.warning( + 'Warning: cannot find svn location for %s', req, + ) + comments.append( + '## FIXME: could not find svn URL in dependency_links ' + 'for this package:' + ) + else: + warnings.warn( + "SVN editable detection based on dependency links " + "will be dropped in the future.", + RemovedInPip11Warning, + ) + comments.append( + '# Installing as editable to satisfy requirement %s:' % + req + ) + if ver_match: + rev = ver_match.group(1) + else: + rev = '{%s}' % date_match.group(1) + editable = True + req = '%s@%s#egg=%s' % ( + svn_location, + rev, + cls.egg_name(dist) + ) + return cls(dist.project_name, req, editable, comments) + + @staticmethod + def egg_name(dist): + name = dist.egg_name() + match = re.search(r'-py\d\.\d$', name) + if match: + name = name[:match.start()] + return name + + def __str__(self): + req = self.req + if self.editable: + req = '-e %s' % req + return '\n'.join(list(self.comments) + [str(req)]) + '\n' diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py new file mode 100755 index 0000000..c1e8158 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/operations/prepare.py @@ -0,0 +1,380 @@ +"""Prepares a distribution for installation +""" + +import itertools +import logging +import os +import sys +from copy import copy + +from pip._vendor import pkg_resources, requests + +from pip._internal.build_env import NoOpBuildEnvironment +from pip._internal.compat import expanduser +from pip._internal.download import ( + is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path, +) +from pip._internal.exceptions import ( + DirectoryUrlHashUnsupported, HashUnpinned, InstallationError, + PreviousBuildDirError, VcsHashUnsupported, +) +from pip._internal.index import FormatControl +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.hashes import MissingHashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + call_subprocess, display_path, normalize_path, +) +from pip._internal.utils.ui import open_spinner +from pip._internal.vcs import vcs + +logger = logging.getLogger(__name__) + + +def make_abstract_dist(req): + """Factory to make an abstract dist object. + + Preconditions: Either an editable req with a source_dir, or satisfied_by or + a wheel link, or a non-editable req with a source_dir. + + :return: A concrete DistAbstraction. + """ + if req.editable: + return IsSDist(req) + elif req.link and req.link.is_wheel: + return IsWheel(req) + else: + return IsSDist(req) + + +def _install_build_reqs(finder, prefix, build_requirements): + # NOTE: What follows is not a very good thing. + # Eventually, this should move into the BuildEnvironment class and + # that should handle all the isolation and sub-process invocation. + finder = copy(finder) + finder.format_control = FormatControl(set(), set([":all:"])) + urls = [ + finder.find_requirement( + InstallRequirement.from_line(r), upgrade=False).url + for r in build_requirements + ] + args = [ + sys.executable, '-m', 'pip', 'install', '--ignore-installed', + '--no-user', '--prefix', prefix, + ] + list(urls) + + with open_spinner("Installing build dependencies") as spinner: + call_subprocess(args, show_stdout=False, spinner=spinner) + + +class DistAbstraction(object): + """Abstracts out the wheel vs non-wheel Resolver.resolve() logic. + + The requirements for anything installable are as follows: + - we must be able to determine the requirement name + (or we can't correctly handle the non-upgrade case). + - we must be able to generate a list of run-time dependencies + without installing any additional packages (or we would + have to either burn time by doing temporary isolated installs + or alternatively violate pips 'don't start installing unless + all requirements are available' rule - neither of which are + desirable). + - for packages with setup requirements, we must also be able + to determine their requirements without installing additional + packages (for the same reason as run-time dependencies) + - we must be able to create a Distribution object exposing the + above metadata. + """ + + def __init__(self, req): + self.req = req + + def dist(self, finder): + """Return a setuptools Dist object.""" + raise NotImplementedError(self.dist) + + def prep_for_dist(self, finder): + """Ensure that we can get a Dist for this requirement.""" + raise NotImplementedError(self.dist) + + +class IsWheel(DistAbstraction): + + def dist(self, finder): + return list(pkg_resources.find_distributions( + self.req.source_dir))[0] + + def prep_for_dist(self, finder, build_isolation): + # FIXME:https://github.com/pypa/pip/issues/1112 + pass + + +class IsSDist(DistAbstraction): + + def dist(self, finder): + dist = self.req.get_dist() + # FIXME: shouldn't be globally added. + if finder and dist.has_metadata('dependency_links.txt'): + finder.add_dependency_links( + dist.get_metadata_lines('dependency_links.txt') + ) + return dist + + def prep_for_dist(self, finder, build_isolation): + # Before calling "setup.py egg_info", we need to set-up the build + # environment. + build_requirements, isolate = self.req.get_pep_518_info() + should_isolate = build_isolation and isolate + + minimum_requirements = ('setuptools', 'wheel') + missing_requirements = set(minimum_requirements) - set( + pkg_resources.Requirement(r).key + for r in build_requirements + ) + if missing_requirements: + def format_reqs(rs): + return ' and '.join(map(repr, sorted(rs))) + logger.warning( + "Missing build time requirements in pyproject.toml for %s: " + "%s.", self.req, format_reqs(missing_requirements) + ) + logger.warning( + "This version of pip does not implement PEP 517 so it cannot " + "build a wheel without %s.", format_reqs(minimum_requirements) + ) + + if should_isolate: + with self.req.build_env: + pass + _install_build_reqs(finder, self.req.build_env.path, + build_requirements) + else: + self.req.build_env = NoOpBuildEnvironment(no_clean=False) + + self.req.run_egg_info() + self.req.assert_source_matches_version() + + +class Installed(DistAbstraction): + + def dist(self, finder): + return self.req.satisfied_by + + def prep_for_dist(self, finder): + pass + + +class RequirementPreparer(object): + """Prepares a Requirement + """ + + def __init__(self, build_dir, download_dir, src_dir, wheel_download_dir, + progress_bar, build_isolation): + super(RequirementPreparer, self).__init__() + + self.src_dir = src_dir + self.build_dir = build_dir + + # Where still packed archives should be written to. If None, they are + # not saved, and are deleted immediately after unpacking. + self.download_dir = download_dir + + # Where still-packed .whl files should be written to. If None, they are + # written to the download_dir parameter. Separate to download_dir to + # permit only keeping wheel archives for pip wheel. + if wheel_download_dir: + wheel_download_dir = normalize_path(wheel_download_dir) + self.wheel_download_dir = wheel_download_dir + + # NOTE + # download_dir and wheel_download_dir overlap semantically and may + # be combined if we're willing to have non-wheel archives present in + # the wheelhouse output by 'pip wheel'. + + self.progress_bar = progress_bar + + # Is build isolation allowed? + self.build_isolation = build_isolation + + @property + def _download_should_save(self): + # TODO: Modify to reduce indentation needed + if self.download_dir: + self.download_dir = expanduser(self.download_dir) + if os.path.exists(self.download_dir): + return True + else: + logger.critical('Could not find download directory') + raise InstallationError( + "Could not find or access download directory '%s'" + % display_path(self.download_dir)) + return False + + def prepare_linked_requirement(self, req, session, finder, + upgrade_allowed, require_hashes): + """Prepare a requirement that would be obtained from req.link + """ + # TODO: Breakup into smaller functions + if req.link and req.link.scheme == 'file': + path = url_to_path(req.link.url) + logger.info('Processing %s', display_path(path)) + else: + logger.info('Collecting %s', req) + + with indent_log(): + # @@ if filesystem packages are not marked + # editable in a req, a non deterministic error + # occurs when the script attempts to unpack the + # build directory + req.ensure_has_source_dir(self.build_dir) + # If a checkout exists, it's unwise to keep going. version + # inconsistencies are logged later, but do not fail the + # installation. + # FIXME: this won't upgrade when there's an existing + # package unpacked in `req.source_dir` + # package unpacked in `req.source_dir` + if os.path.exists(os.path.join(req.source_dir, 'setup.py')): + raise PreviousBuildDirError( + "pip can't proceed with requirements '%s' due to a" + " pre-existing build directory (%s). This is " + "likely due to a previous installation that failed" + ". pip is being responsible and not assuming it " + "can delete this. Please delete it and try again." + % (req, req.source_dir) + ) + req.populate_link(finder, upgrade_allowed, require_hashes) + + # We can't hit this spot and have populate_link return None. + # req.satisfied_by is None here (because we're + # guarded) and upgrade has no impact except when satisfied_by + # is not None. + # Then inside find_requirement existing_applicable -> False + # If no new versions are found, DistributionNotFound is raised, + # otherwise a result is guaranteed. + assert req.link + link = req.link + + # Now that we have the real link, we can tell what kind of + # requirements we have and raise some more informative errors + # than otherwise. (For example, we can raise VcsHashUnsupported + # for a VCS URL rather than HashMissing.) + if require_hashes: + # We could check these first 2 conditions inside + # unpack_url and save repetition of conditions, but then + # we would report less-useful error messages for + # unhashable requirements, complaining that there's no + # hash provided. + if is_vcs_url(link): + raise VcsHashUnsupported() + elif is_file_url(link) and is_dir_url(link): + raise DirectoryUrlHashUnsupported() + if not req.original_link and not req.is_pinned: + # Unpinned packages are asking for trouble when a new + # version is uploaded. This isn't a security check, but + # it saves users a surprising hash mismatch in the + # future. + # + # file:/// URLs aren't pinnable, so don't complain + # about them not being pinned. + raise HashUnpinned() + + hashes = req.hashes(trust_internet=not require_hashes) + if require_hashes and not hashes: + # Known-good hashes are missing for this requirement, so + # shim it with a facade object that will provoke hash + # computation and then raise a HashMissing exception + # showing the user what the hash should be. + hashes = MissingHashes() + + try: + download_dir = self.download_dir + # We always delete unpacked sdists after pip ran. + autodelete_unpacked = True + if req.link.is_wheel and self.wheel_download_dir: + # when doing 'pip wheel` we download wheels to a + # dedicated dir. + download_dir = self.wheel_download_dir + if req.link.is_wheel: + if download_dir: + # When downloading, we only unpack wheels to get + # metadata. + autodelete_unpacked = True + else: + # When installing a wheel, we use the unpacked + # wheel. + autodelete_unpacked = False + unpack_url( + req.link, req.source_dir, + download_dir, autodelete_unpacked, + session=session, hashes=hashes, + progress_bar=self.progress_bar + ) + except requests.HTTPError as exc: + logger.critical( + 'Could not install requirement %s because of error %s', + req, + exc, + ) + raise InstallationError( + 'Could not install requirement %s because of HTTP ' + 'error %s for URL %s' % + (req, exc, req.link) + ) + abstract_dist = make_abstract_dist(req) + abstract_dist.prep_for_dist(finder, self.build_isolation) + if self._download_should_save: + # Make a .zip of the source_dir we already created. + if req.link.scheme in vcs.all_schemes: + req.archive(self.download_dir) + return abstract_dist + + def prepare_editable_requirement(self, req, require_hashes, use_user_site, + finder): + """Prepare an editable requirement + """ + assert req.editable, "cannot prepare a non-editable req as editable" + + logger.info('Obtaining %s', req) + + with indent_log(): + if require_hashes: + raise InstallationError( + 'The editable requirement %s cannot be installed when ' + 'requiring hashes, because there is no single file to ' + 'hash.' % req + ) + req.ensure_has_source_dir(self.src_dir) + req.update_editable(not self._download_should_save) + + abstract_dist = make_abstract_dist(req) + abstract_dist.prep_for_dist(finder, self.build_isolation) + + if self._download_should_save: + req.archive(self.download_dir) + req.check_if_exists(use_user_site) + + return abstract_dist + + def prepare_installed_requirement(self, req, require_hashes, skip_reason): + """Prepare an already-installed requirement + """ + assert req.satisfied_by, "req should have been satisfied but isn't" + assert skip_reason is not None, ( + "did not get skip reason skipped but req.satisfied_by " + "is set to %r" % (req.satisfied_by,) + ) + logger.info( + 'Requirement %s: %s (%s)', + skip_reason, req, req.satisfied_by.version + ) + with indent_log(): + if require_hashes: + logger.debug( + 'Since it is already installed, we are trusting this ' + 'package without checking its hash. To ensure a ' + 'completely repeatable environment, install into an ' + 'empty virtualenv.' + ) + abstract_dist = Installed(req) + + return abstract_dist diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py new file mode 100755 index 0000000..5d31310 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/pep425tags.py @@ -0,0 +1,317 @@ +"""Generate and work with PEP 425 Compatibility Tags.""" +from __future__ import absolute_import + +import distutils.util +import logging +import platform +import re +import sys +import sysconfig +import warnings +from collections import OrderedDict + +import pip._internal.utils.glibc + +logger = logging.getLogger(__name__) + +_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') + + +def get_config_var(var): + try: + return sysconfig.get_config_var(var) + except IOError as e: # Issue #1074 + warnings.warn("{}".format(e), RuntimeWarning) + return None + + +def get_abbr_impl(): + """Return abbreviated implementation name.""" + if hasattr(sys, 'pypy_version_info'): + pyimpl = 'pp' + elif sys.platform.startswith('java'): + pyimpl = 'jy' + elif sys.platform == 'cli': + pyimpl = 'ip' + else: + pyimpl = 'cp' + return pyimpl + + +def get_impl_ver(): + """Return implementation version.""" + impl_ver = get_config_var("py_version_nodot") + if not impl_ver or get_abbr_impl() == 'pp': + impl_ver = ''.join(map(str, get_impl_version_info())) + return impl_ver + + +def get_impl_version_info(): + """Return sys.version_info-like tuple for use in decrementing the minor + version.""" + if get_abbr_impl() == 'pp': + # as per https://github.com/pypa/pip/issues/2882 + return (sys.version_info[0], sys.pypy_version_info.major, + sys.pypy_version_info.minor) + else: + return sys.version_info[0], sys.version_info[1] + + +def get_impl_tag(): + """ + Returns the Tag for this specific implementation. + """ + return "{}{}".format(get_abbr_impl(), get_impl_ver()) + + +def get_flag(var, fallback, expected=True, warn=True): + """Use a fallback method for determining SOABI flags if the needed config + var is unset or unavailable.""" + val = get_config_var(var) + if val is None: + if warn: + logger.debug("Config variable '%s' is unset, Python ABI tag may " + "be incorrect", var) + return fallback() + return val == expected + + +def get_abi_tag(): + """Return the ABI tag based on SOABI (if available) or emulate SOABI + (CPython 2, PyPy).""" + soabi = get_config_var('SOABI') + impl = get_abbr_impl() + if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'): + d = '' + m = '' + u = '' + if get_flag('Py_DEBUG', + lambda: hasattr(sys, 'gettotalrefcount'), + warn=(impl == 'cp')): + d = 'd' + if get_flag('WITH_PYMALLOC', + lambda: impl == 'cp', + warn=(impl == 'cp')): + m = 'm' + if get_flag('Py_UNICODE_SIZE', + lambda: sys.maxunicode == 0x10ffff, + expected=4, + warn=(impl == 'cp' and + sys.version_info < (3, 3))) \ + and sys.version_info < (3, 3): + u = 'u' + abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u) + elif soabi and soabi.startswith('cpython-'): + abi = 'cp' + soabi.split('-')[1] + elif soabi: + abi = soabi.replace('.', '_').replace('-', '_') + else: + abi = None + return abi + + +def _is_running_32bit(): + return sys.maxsize == 2147483647 + + +def get_platform(): + """Return our platform name 'win32', 'linux_x86_64'""" + if sys.platform == 'darwin': + # distutils.util.get_platform() returns the release based on the value + # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may + # be significantly older than the user's current machine. + release, _, machine = platform.mac_ver() + split_ver = release.split('.') + + if machine == "x86_64" and _is_running_32bit(): + machine = "i386" + elif machine == "ppc64" and _is_running_32bit(): + machine = "ppc" + + return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine) + + # XXX remove distutils dependency + result = distutils.util.get_platform().replace('.', '_').replace('-', '_') + if result == "linux_x86_64" and _is_running_32bit(): + # 32 bit Python program (running on a 64 bit Linux): pip should only + # install and run 32 bit compiled extensions in that case. + result = "linux_i686" + + return result + + +def is_manylinux1_compatible(): + # Only Linux, and only x86-64 / i686 + if get_platform() not in {"linux_x86_64", "linux_i686"}: + return False + + # Check for presence of _manylinux module + try: + import _manylinux + return bool(_manylinux.manylinux1_compatible) + except (ImportError, AttributeError): + # Fall through to heuristic check below + pass + + # Check glibc version. CentOS 5 uses glibc 2.5. + return pip._internal.utils.glibc.have_compatible_glibc(2, 5) + + +def get_darwin_arches(major, minor, machine): + """Return a list of supported arches (including group arches) for + the given major, minor and machine architecture of an macOS machine. + """ + arches = [] + + def _supports_arch(major, minor, arch): + # Looking at the application support for macOS versions in the chart + # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears + # our timeline looks roughly like: + # + # 10.0 - Introduces ppc support. + # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64 + # and x86_64 support is CLI only, and cannot be used for GUI + # applications. + # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications. + # 10.6 - Drops support for ppc64 + # 10.7 - Drops support for ppc + # + # Given that we do not know if we're installing a CLI or a GUI + # application, we must be conservative and assume it might be a GUI + # application and behave as if ppc64 and x86_64 support did not occur + # until 10.5. + # + # Note: The above information is taken from the "Application support" + # column in the chart not the "Processor support" since I believe + # that we care about what instruction sets an application can use + # not which processors the OS supports. + if arch == 'ppc': + return (major, minor) <= (10, 5) + if arch == 'ppc64': + return (major, minor) == (10, 5) + if arch == 'i386': + return (major, minor) >= (10, 4) + if arch == 'x86_64': + return (major, minor) >= (10, 5) + if arch in groups: + for garch in groups[arch]: + if _supports_arch(major, minor, garch): + return True + return False + + groups = OrderedDict([ + ("fat", ("i386", "ppc")), + ("intel", ("x86_64", "i386")), + ("fat64", ("x86_64", "ppc64")), + ("fat32", ("x86_64", "i386", "ppc")), + ]) + + if _supports_arch(major, minor, machine): + arches.append(machine) + + for garch in groups: + if machine in groups[garch] and _supports_arch(major, minor, garch): + arches.append(garch) + + arches.append('universal') + + return arches + + +def get_supported(versions=None, noarch=False, platform=None, + impl=None, abi=None): + """Return a list of supported tags for each version specified in + `versions`. + + :param versions: a list of string versions, of the form ["33", "32"], + or None. The first version will be assumed to support our ABI. + :param platform: specify the exact platform you want valid + tags for, or None. If None, use the local system platform. + :param impl: specify the exact implementation you want valid + tags for, or None. If None, use the local interpreter impl. + :param abi: specify the exact abi you want valid + tags for, or None. If None, use the local interpreter abi. + """ + supported = [] + + # Versions must be given with respect to the preference + if versions is None: + versions = [] + version_info = get_impl_version_info() + major = version_info[:-1] + # Support all previous minor Python versions. + for minor in range(version_info[-1], -1, -1): + versions.append(''.join(map(str, major + (minor,)))) + + impl = impl or get_abbr_impl() + + abis = [] + + abi = abi or get_abi_tag() + if abi: + abis[0:0] = [abi] + + abi3s = set() + import imp + for suffix in imp.get_suffixes(): + if suffix[0].startswith('.abi'): + abi3s.add(suffix[0].split('.', 2)[1]) + + abis.extend(sorted(list(abi3s))) + + abis.append('none') + + if not noarch: + arch = platform or get_platform() + if arch.startswith('macosx'): + # support macosx-10.6-intel on macosx-10.9-x86_64 + match = _osx_arch_pat.match(arch) + if match: + name, major, minor, actual_arch = match.groups() + tpl = '{}_{}_%i_%s'.format(name, major) + arches = [] + for m in reversed(range(int(minor) + 1)): + for a in get_darwin_arches(int(major), m, actual_arch): + arches.append(tpl % (m, a)) + else: + # arch pattern didn't match (?!) + arches = [arch] + elif platform is None and is_manylinux1_compatible(): + arches = [arch.replace('linux', 'manylinux1'), arch] + else: + arches = [arch] + + # Current version, current API (built specifically for our Python): + for abi in abis: + for arch in arches: + supported.append(('%s%s' % (impl, versions[0]), abi, arch)) + + # abi3 modules compatible with older version of Python + for version in versions[1:]: + # abi3 was introduced in Python 3.2 + if version in {'31', '30'}: + break + for abi in abi3s: # empty set if not Python 3 + for arch in arches: + supported.append(("%s%s" % (impl, version), abi, arch)) + + # Has binaries, does not use the Python API: + for arch in arches: + supported.append(('py%s' % (versions[0][0]), 'none', arch)) + + # No abi / arch, but requires our implementation: + supported.append(('%s%s' % (impl, versions[0]), 'none', 'any')) + # Tagged specifically as being cross-version compatible + # (with just the major version specified) + supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any')) + + # No abi / arch, generic Python + for i, version in enumerate(versions): + supported.append(('py%s' % (version,), 'none', 'any')) + if i == 0: + supported.append(('py%s' % (version[0]), 'none', 'any')) + + return supported + + +implementation_tag = get_impl_tag() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py new file mode 100755 index 0000000..07ae607 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/__init__.py @@ -0,0 +1,69 @@ +from __future__ import absolute_import + +import logging + +from .req_install import InstallRequirement +from .req_set import RequirementSet +from .req_file import parse_requirements +from pip._internal.utils.logging import indent_log + + +__all__ = [ + "RequirementSet", "InstallRequirement", + "parse_requirements", "install_given_reqs", +] + +logger = logging.getLogger(__name__) + + +def install_given_reqs(to_install, install_options, global_options=(), + *args, **kwargs): + """ + Install everything in the given list. + + (to be called after having downloaded and unpacked the packages) + """ + + if to_install: + logger.info( + 'Installing collected packages: %s', + ', '.join([req.name for req in to_install]), + ) + + with indent_log(): + for requirement in to_install: + if requirement.conflicts_with: + logger.info( + 'Found existing installation: %s', + requirement.conflicts_with, + ) + with indent_log(): + uninstalled_pathset = requirement.uninstall( + auto_confirm=True + ) + try: + requirement.install( + install_options, + global_options, + *args, + **kwargs + ) + except: + should_rollback = ( + requirement.conflicts_with and + not requirement.install_succeeded + ) + # if install did not succeed, rollback previous uninstall + if should_rollback: + uninstalled_pathset.rollback() + raise + else: + should_commit = ( + requirement.conflicts_with and + requirement.install_succeeded + ) + if should_commit: + uninstalled_pathset.commit() + requirement.remove_temporary_source() + + return to_install diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py new file mode 100755 index 0000000..9e6ef41 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_file.py @@ -0,0 +1,338 @@ +""" +Requirements file parsing +""" + +from __future__ import absolute_import + +import optparse +import os +import re +import shlex +import sys + +from pip._vendor.six.moves import filterfalse +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal import cmdoptions +from pip._internal.download import get_file_content +from pip._internal.exceptions import RequirementsFileParseError +from pip._internal.req.req_install import InstallRequirement + +__all__ = ['parse_requirements'] + +SCHEME_RE = re.compile(r'^(http|https|file):', re.I) +COMMENT_RE = re.compile(r'(^|\s)+#.*$') + +# Matches environment variable-style values in '${MY_VARIABLE_1}' with the +# variable name consisting of only uppercase letters, digits or the '_' +# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, +# 2013 Edition. +ENV_VAR_RE = re.compile(r'(?P<var>\$\{(?P<name>[A-Z0-9_]+)\})') + +SUPPORTED_OPTIONS = [ + cmdoptions.constraints, + cmdoptions.editable, + cmdoptions.requirements, + cmdoptions.no_index, + cmdoptions.index_url, + cmdoptions.find_links, + cmdoptions.extra_index_url, + cmdoptions.always_unzip, + cmdoptions.no_binary, + cmdoptions.only_binary, + cmdoptions.pre, + cmdoptions.process_dependency_links, + cmdoptions.trusted_host, + cmdoptions.require_hashes, +] + +# options to be passed to requirements +SUPPORTED_OPTIONS_REQ = [ + cmdoptions.install_options, + cmdoptions.global_options, + cmdoptions.hash, +] + +# the 'dest' string values +SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ] + + +def parse_requirements(filename, finder=None, comes_from=None, options=None, + session=None, constraint=False, wheel_cache=None): + """Parse a requirements file and yield InstallRequirement instances. + + :param filename: Path or url of requirements file. + :param finder: Instance of pip.index.PackageFinder. + :param comes_from: Origin description of requirements. + :param options: cli options. + :param session: Instance of pip.download.PipSession. + :param constraint: If true, parsing a constraint file rather than + requirements file. + :param wheel_cache: Instance of pip.wheel.WheelCache + """ + if session is None: + raise TypeError( + "parse_requirements() missing 1 required keyword argument: " + "'session'" + ) + + _, content = get_file_content( + filename, comes_from=comes_from, session=session + ) + + lines_enum = preprocess(content, options) + + for line_number, line in lines_enum: + req_iter = process_line(line, filename, line_number, finder, + comes_from, options, session, wheel_cache, + constraint=constraint) + for req in req_iter: + yield req + + +def preprocess(content, options): + """Split, filter, and join lines, and return a line iterator + + :param content: the content of the requirements file + :param options: cli options + """ + lines_enum = enumerate(content.splitlines(), start=1) + lines_enum = join_lines(lines_enum) + lines_enum = ignore_comments(lines_enum) + lines_enum = skip_regex(lines_enum, options) + lines_enum = expand_env_variables(lines_enum) + return lines_enum + + +def process_line(line, filename, line_number, finder=None, comes_from=None, + options=None, session=None, wheel_cache=None, + constraint=False): + """Process a single requirements line; This can result in creating/yielding + requirements, or updating the finder. + + For lines that contain requirements, the only options that have an effect + are from SUPPORTED_OPTIONS_REQ, and they are scoped to the + requirement. Other options from SUPPORTED_OPTIONS may be present, but are + ignored. + + For lines that do not contain requirements, the only options that have an + effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may + be present, but are ignored. These lines may contain multiple options + (although our docs imply only one is supported), and all our parsed and + affect the finder. + + :param constraint: If True, parsing a constraints file. + :param options: OptionParser options that we may update + """ + parser = build_parser(line) + defaults = parser.get_default_values() + defaults.index_url = None + if finder: + # `finder.format_control` will be updated during parsing + defaults.format_control = finder.format_control + args_str, options_str = break_args_options(line) + if sys.version_info < (2, 7, 3): + # Prior to 2.7.3, shlex cannot deal with unicode entries + options_str = options_str.encode('utf8') + opts, _ = parser.parse_args(shlex.split(options_str), defaults) + + # preserve for the nested code path + line_comes_from = '%s %s (line %s)' % ( + '-c' if constraint else '-r', filename, line_number, + ) + + # yield a line requirement + if args_str: + isolated = options.isolated_mode if options else False + if options: + cmdoptions.check_install_build_global(options, opts) + # get the options that apply to requirements + req_options = {} + for dest in SUPPORTED_OPTIONS_REQ_DEST: + if dest in opts.__dict__ and opts.__dict__[dest]: + req_options[dest] = opts.__dict__[dest] + yield InstallRequirement.from_line( + args_str, line_comes_from, constraint=constraint, + isolated=isolated, options=req_options, wheel_cache=wheel_cache + ) + + # yield an editable requirement + elif opts.editables: + isolated = options.isolated_mode if options else False + yield InstallRequirement.from_editable( + opts.editables[0], comes_from=line_comes_from, + constraint=constraint, isolated=isolated, wheel_cache=wheel_cache + ) + + # parse a nested requirements file + elif opts.requirements or opts.constraints: + if opts.requirements: + req_path = opts.requirements[0] + nested_constraint = False + else: + req_path = opts.constraints[0] + nested_constraint = True + # original file is over http + if SCHEME_RE.search(filename): + # do a url join so relative paths work + req_path = urllib_parse.urljoin(filename, req_path) + # original file and nested file are paths + elif not SCHEME_RE.search(req_path): + # do a join so relative paths work + req_path = os.path.join(os.path.dirname(filename), req_path) + # TODO: Why not use `comes_from='-r {} (line {})'` here as well? + parser = parse_requirements( + req_path, finder, comes_from, options, session, + constraint=nested_constraint, wheel_cache=wheel_cache + ) + for req in parser: + yield req + + # percolate hash-checking option upward + elif opts.require_hashes: + options.require_hashes = opts.require_hashes + + # set finder options + elif finder: + if opts.index_url: + finder.index_urls = [opts.index_url] + if opts.no_index is True: + finder.index_urls = [] + if opts.extra_index_urls: + finder.index_urls.extend(opts.extra_index_urls) + if opts.find_links: + # FIXME: it would be nice to keep track of the source + # of the find_links: support a find-links local path + # relative to a requirements file. + value = opts.find_links[0] + req_dir = os.path.dirname(os.path.abspath(filename)) + relative_to_reqs_file = os.path.join(req_dir, value) + if os.path.exists(relative_to_reqs_file): + value = relative_to_reqs_file + finder.find_links.append(value) + if opts.pre: + finder.allow_all_prereleases = True + if opts.process_dependency_links: + finder.process_dependency_links = True + if opts.trusted_hosts: + finder.secure_origins.extend( + ("*", host, "*") for host in opts.trusted_hosts) + + +def break_args_options(line): + """Break up the line into an args and options string. We only want to shlex + (and then optparse) the options, not the args. args can contain markers + which are corrupted by shlex. + """ + tokens = line.split(' ') + args = [] + options = tokens[:] + for token in tokens: + if token.startswith('-') or token.startswith('--'): + break + else: + args.append(token) + options.pop(0) + return ' '.join(args), ' '.join(options) + + +def build_parser(line): + """ + Return a parser for parsing requirement lines + """ + parser = optparse.OptionParser(add_help_option=False) + + option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ + for option_factory in option_factories: + option = option_factory() + parser.add_option(option) + + # By default optparse sys.exits on parsing errors. We want to wrap + # that in our own exception. + def parser_exit(self, msg): + # add offending line + msg = 'Invalid requirement: %s\n%s' % (line, msg) + raise RequirementsFileParseError(msg) + parser.exit = parser_exit + + return parser + + +def join_lines(lines_enum): + """Joins a line ending in '\' with the previous line (except when following + comments). The joined line takes on the index of the first line. + """ + primary_line_number = None + new_line = [] + for line_number, line in lines_enum: + if not line.endswith('\\') or COMMENT_RE.match(line): + if COMMENT_RE.match(line): + # this ensures comments are always matched later + line = ' ' + line + if new_line: + new_line.append(line) + yield primary_line_number, ''.join(new_line) + new_line = [] + else: + yield line_number, line + else: + if not new_line: + primary_line_number = line_number + new_line.append(line.strip('\\')) + + # last line contains \ + if new_line: + yield primary_line_number, ''.join(new_line) + + # TODO: handle space after '\'. + + +def ignore_comments(lines_enum): + """ + Strips comments and filter empty lines. + """ + for line_number, line in lines_enum: + line = COMMENT_RE.sub('', line) + line = line.strip() + if line: + yield line_number, line + + +def skip_regex(lines_enum, options): + """ + Skip lines that match '--skip-requirements-regex' pattern + + Note: the regex pattern is only built once + """ + skip_regex = options.skip_requirements_regex if options else None + if skip_regex: + pattern = re.compile(skip_regex) + lines_enum = filterfalse(lambda e: pattern.search(e[1]), lines_enum) + return lines_enum + + +def expand_env_variables(lines_enum): + """Replace all environment variables that can be retrieved via `os.getenv`. + + The only allowed format for environment variables defined in the + requirement file is `${MY_VARIABLE_1}` to ensure two things: + + 1. Strings that contain a `$` aren't accidentally (partially) expanded. + 2. Ensure consistency across platforms for requirement files. + + These points are the result of a discusssion on the `github pull + request #3514 <https://github.com/pypa/pip/pull/3514>`_. + + Valid characters in variable names follow the `POSIX standard + <http://pubs.opengroup.org/onlinepubs/9699919799/>`_ and are limited + to uppercase letter, digits and the `_` (underscore). + """ + for line_number, line in lines_enum: + for env_var, var_name in ENV_VAR_RE.findall(line): + value = os.getenv(var_name) + if not value: + continue + + line = line.replace(env_var, value) + + yield line_number, line diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py new file mode 100755 index 0000000..9dd1523 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_install.py @@ -0,0 +1,1115 @@ +from __future__ import absolute_import + +import logging +import os +import re +import shutil +import sys +import sysconfig +import traceback +import warnings +import zipfile +from distutils.util import change_root +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources, pytoml, six +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.markers import Marker +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.packaging.version import Version +from pip._vendor.pkg_resources import RequirementParseError, parse_requirements + +from pip._internal import wheel +from pip._internal.build_env import BuildEnvironment +from pip._internal.compat import native_str +from pip._internal.download import ( + is_archive_file, is_url, path_to_url, url_to_path, +) +from pip._internal.exceptions import InstallationError, UninstallationError +from pip._internal.locations import ( + PIP_DELETE_MARKER_FILENAME, running_under_virtualenv, +) +from pip._internal.req.req_uninstall import UninstallPathSet +from pip._internal.utils.deprecation import RemovedInPip11Warning +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + _make_build_dir, ask_path_exists, backup_dir, call_subprocess, + display_path, dist_in_site_packages, dist_in_usersite, ensure_dir, + get_installed_version, is_installable_dir, read_text_file, rmtree, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.ui import open_spinner +from pip._internal.vcs import vcs +from pip._internal.wheel import Wheel, move_wheel_files + +logger = logging.getLogger(__name__) + +operators = specifiers.Specifier._operators.keys() + + +def _strip_extras(path): + m = re.match(r'^(.+)(\[[^\]]+\])$', path) + extras = None + if m: + path_no_extras = m.group(1) + extras = m.group(2) + else: + path_no_extras = path + + return path_no_extras, extras + + +class InstallRequirement(object): + """ + Represents something that may be installed later on, may have information + about where to fetch the relavant requirement and also contains logic for + installing the said requirement. + """ + + def __init__(self, req, comes_from, source_dir=None, editable=False, + link=None, update=True, markers=None, + isolated=False, options=None, wheel_cache=None, + constraint=False, extras=()): + assert req is None or isinstance(req, Requirement), req + self.req = req + self.comes_from = comes_from + self.constraint = constraint + if source_dir is not None: + self.source_dir = os.path.normpath(os.path.abspath(source_dir)) + else: + self.source_dir = None + self.editable = editable + + self._wheel_cache = wheel_cache + if link is not None: + self.link = self.original_link = link + else: + from pip._internal.index import Link + self.link = self.original_link = req and req.url and Link(req.url) + + if extras: + self.extras = extras + elif req: + self.extras = { + pkg_resources.safe_extra(extra) for extra in req.extras + } + else: + self.extras = set() + if markers is not None: + self.markers = markers + else: + self.markers = req and req.marker + self._egg_info_path = None + # This holds the pkg_resources.Distribution object if this requirement + # is already available: + self.satisfied_by = None + # This hold the pkg_resources.Distribution object if this requirement + # conflicts with another installed distribution: + self.conflicts_with = None + # Temporary build location + self._temp_build_dir = TempDirectory(kind="req-build") + # Used to store the global directory where the _temp_build_dir should + # have been created. Cf _correct_build_location method. + self._ideal_build_dir = None + # True if the editable should be updated: + self.update = update + # Set to True after successful installation + self.install_succeeded = None + # UninstallPathSet of uninstalled distribution (for possible rollback) + self.uninstalled_pathset = None + self.options = options if options else {} + # Set to True after successful preparation of this requirement + self.prepared = False + self.is_direct = False + + self.isolated = isolated + self.build_env = BuildEnvironment(no_clean=True) + + @classmethod + def from_editable(cls, editable_req, comes_from=None, isolated=False, + options=None, wheel_cache=None, constraint=False): + from pip._internal.index import Link + + name, url, extras_override = parse_editable(editable_req) + if url.startswith('file:'): + source_dir = url_to_path(url) + else: + source_dir = None + + if name is not None: + try: + req = Requirement(name) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '%s'" % name) + else: + req = None + return cls( + req, comes_from, source_dir=source_dir, + editable=True, + link=Link(url), + constraint=constraint, + isolated=isolated, + options=options if options else {}, + wheel_cache=wheel_cache, + extras=extras_override or (), + ) + + @classmethod + def from_req(cls, req, comes_from=None, isolated=False, wheel_cache=None): + try: + req = Requirement(req) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '%s'" % req) + if req.url: + raise InstallationError( + "Direct url requirement (like %s) are not allowed for " + "dependencies" % req + ) + return cls(req, comes_from, isolated=isolated, wheel_cache=wheel_cache) + + @classmethod + def from_line( + cls, name, comes_from=None, isolated=False, options=None, + wheel_cache=None, constraint=False): + """Creates an InstallRequirement from a name, which might be a + requirement, directory containing 'setup.py', filename, or URL. + """ + from pip._internal.index import Link + + if is_url(name): + marker_sep = '; ' + else: + marker_sep = ';' + if marker_sep in name: + name, markers = name.split(marker_sep, 1) + markers = markers.strip() + if not markers: + markers = None + else: + markers = Marker(markers) + else: + markers = None + name = name.strip() + req = None + path = os.path.normpath(os.path.abspath(name)) + link = None + extras = None + + if is_url(name): + link = Link(name) + else: + p, extras = _strip_extras(path) + looks_like_dir = os.path.isdir(p) and ( + os.path.sep in name or + (os.path.altsep is not None and os.path.altsep in name) or + name.startswith('.') + ) + if looks_like_dir: + if not is_installable_dir(p): + raise InstallationError( + "Directory %r is not installable. File 'setup.py' " + "not found." % name + ) + link = Link(path_to_url(p)) + elif is_archive_file(p): + if not os.path.isfile(p): + logger.warning( + 'Requirement %r looks like a filename, but the ' + 'file does not exist', + name + ) + link = Link(path_to_url(p)) + + # it's a local file, dir, or url + if link: + # Handle relative file URLs + if link.scheme == 'file' and re.search(r'\.\./', link.url): + link = Link( + path_to_url(os.path.normpath(os.path.abspath(link.path)))) + # wheel file + if link.is_wheel: + wheel = Wheel(link.filename) # can raise InvalidWheelFilename + req = "%s==%s" % (wheel.name, wheel.version) + else: + # set the req to the egg fragment. when it's not there, this + # will become an 'unnamed' requirement + req = link.egg_fragment + + # a requirement specifier + else: + req = name + + if extras: + extras = Requirement("placeholder" + extras.lower()).extras + else: + extras = () + if req is not None: + try: + req = Requirement(req) + except InvalidRequirement: + if os.path.sep in req: + add_msg = "It looks like a path." + add_msg += deduce_helpful_msg(req) + elif '=' in req and not any(op in req for op in operators): + add_msg = "= is not a valid operator. Did you mean == ?" + else: + add_msg = traceback.format_exc() + raise InstallationError( + "Invalid requirement: '%s'\n%s" % (req, add_msg)) + return cls( + req, comes_from, link=link, markers=markers, + isolated=isolated, + options=options if options else {}, + wheel_cache=wheel_cache, + constraint=constraint, + extras=extras, + ) + + def __str__(self): + if self.req: + s = str(self.req) + if self.link: + s += ' from %s' % self.link.url + else: + s = self.link.url if self.link else None + if self.satisfied_by is not None: + s += ' in %s' % display_path(self.satisfied_by.location) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += ' (from %s)' % comes_from + return s + + def __repr__(self): + return '<%s object: %s editable=%r>' % ( + self.__class__.__name__, str(self), self.editable) + + def populate_link(self, finder, upgrade, require_hashes): + """Ensure that if a link can be found for this, that it is found. + + Note that self.link may still be None - if Upgrade is False and the + requirement is already installed. + + If require_hashes is True, don't use the wheel cache, because cached + wheels, always built locally, have different hashes than the files + downloaded from the index server and thus throw false hash mismatches. + Furthermore, cached wheels at present have undeterministic contents due + to file modification times. + """ + if self.link is None: + self.link = finder.find_requirement(self, upgrade) + if self._wheel_cache is not None and not require_hashes: + old_link = self.link + self.link = self._wheel_cache.get(self.link, self.name) + if old_link != self.link: + logger.debug('Using cached wheel link: %s', self.link) + + @property + def specifier(self): + return self.req.specifier + + @property + def is_pinned(self): + """Return whether I am pinned to an exact version. + + For example, some-package==1.2 is pinned; some-package>1.2 is not. + """ + specifiers = self.specifier + return (len(specifiers) == 1 and + next(iter(specifiers)).operator in {'==', '==='}) + + def from_path(self): + if self.req is None: + return None + s = str(self.req) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += '->' + comes_from + return s + + def build_location(self, build_dir): + assert build_dir is not None + if self._temp_build_dir.path is not None: + return self._temp_build_dir.path + if self.req is None: + # for requirement via a path to a directory: the name of the + # package is not available yet so we create a temp directory + # Once run_egg_info will have run, we'll be able + # to fix it via _correct_build_location + # Some systems have /tmp as a symlink which confuses custom + # builds (such as numpy). Thus, we ensure that the real path + # is returned. + self._temp_build_dir.create() + self._ideal_build_dir = build_dir + + return self._temp_build_dir.path + if self.editable: + name = self.name.lower() + else: + name = self.name + # FIXME: Is there a better place to create the build_dir? (hg and bzr + # need this) + if not os.path.exists(build_dir): + logger.debug('Creating directory %s', build_dir) + _make_build_dir(build_dir) + return os.path.join(build_dir, name) + + def _correct_build_location(self): + """Move self._temp_build_dir to self._ideal_build_dir/self.req.name + + For some requirements (e.g. a path to a directory), the name of the + package is not available until we run egg_info, so the build_location + will return a temporary directory and store the _ideal_build_dir. + + This is only called by self.egg_info_path to fix the temporary build + directory. + """ + if self.source_dir is not None: + return + assert self.req is not None + assert self._temp_build_dir.path + assert self._ideal_build_dir.path + old_location = self._temp_build_dir.path + self._temp_build_dir.path = None + + new_location = self.build_location(self._ideal_build_dir) + if os.path.exists(new_location): + raise InstallationError( + 'A package already exists in %s; please remove it to continue' + % display_path(new_location)) + logger.debug( + 'Moving package %s from %s to new location %s', + self, display_path(old_location), display_path(new_location), + ) + shutil.move(old_location, new_location) + self._temp_build_dir.path = new_location + self._ideal_build_dir = None + self.source_dir = os.path.normpath(os.path.abspath(new_location)) + self._egg_info_path = None + + @property + def name(self): + if self.req is None: + return None + return native_str(pkg_resources.safe_name(self.req.name)) + + @property + def setup_py_dir(self): + return os.path.join( + self.source_dir, + self.link and self.link.subdirectory_fragment or '') + + @property + def setup_py(self): + assert self.source_dir, "No source dir for %s" % self + + setup_py = os.path.join(self.setup_py_dir, 'setup.py') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(setup_py, six.text_type): + setup_py = setup_py.encode(sys.getfilesystemencoding()) + + return setup_py + + @property + def pyproject_toml(self): + assert self.source_dir, "No source dir for %s" % self + + pp_toml = os.path.join(self.setup_py_dir, 'pyproject.toml') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(pp_toml, six.text_type): + pp_toml = pp_toml.encode(sys.getfilesystemencoding()) + + return pp_toml + + def get_pep_518_info(self): + """Get a list of the packages required to build the project, if any, + and a flag indicating whether pyproject.toml is present, indicating + that the build should be isolated. + + Build requirements can be specified in a pyproject.toml, as described + in PEP 518. If this file exists but doesn't specify build + requirements, pip will default to installing setuptools and wheel. + """ + if os.path.isfile(self.pyproject_toml): + with open(self.pyproject_toml) as f: + pp_toml = pytoml.load(f) + build_sys = pp_toml.get('build-system', {}) + return (build_sys.get('requires', ['setuptools', 'wheel']), True) + return (['setuptools', 'wheel'], False) + + def run_egg_info(self): + assert self.source_dir + if self.name: + logger.debug( + 'Running setup.py (path:%s) egg_info for package %s', + self.setup_py, self.name, + ) + else: + logger.debug( + 'Running setup.py (path:%s) egg_info for package from %s', + self.setup_py, self.link, + ) + + with indent_log(): + script = SETUPTOOLS_SHIM % self.setup_py + base_cmd = [sys.executable, '-c', script] + if self.isolated: + base_cmd += ["--no-user-cfg"] + egg_info_cmd = base_cmd + ['egg_info'] + # We can't put the .egg-info files at the root, because then the + # source code will be mistaken for an installed egg, causing + # problems + if self.editable: + egg_base_option = [] + else: + egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info') + ensure_dir(egg_info_dir) + egg_base_option = ['--egg-base', 'pip-egg-info'] + with self.build_env: + call_subprocess( + egg_info_cmd + egg_base_option, + cwd=self.setup_py_dir, + show_stdout=False, + command_desc='python setup.py egg_info') + + if not self.req: + if isinstance(parse_version(self.pkg_info()["Version"]), Version): + op = "==" + else: + op = "===" + self.req = Requirement( + "".join([ + self.pkg_info()["Name"], + op, + self.pkg_info()["Version"], + ]) + ) + self._correct_build_location() + else: + metadata_name = canonicalize_name(self.pkg_info()["Name"]) + if canonicalize_name(self.req.name) != metadata_name: + logger.warning( + 'Running setup.py (path:%s) egg_info for package %s ' + 'produced metadata for project name %s. Fix your ' + '#egg=%s fragments.', + self.setup_py, self.name, metadata_name, self.name + ) + self.req = Requirement(metadata_name) + + def egg_info_data(self, filename): + if self.satisfied_by is not None: + if not self.satisfied_by.has_metadata(filename): + return None + return self.satisfied_by.get_metadata(filename) + assert self.source_dir + filename = self.egg_info_path(filename) + if not os.path.exists(filename): + return None + data = read_text_file(filename) + return data + + def egg_info_path(self, filename): + if self._egg_info_path is None: + if self.editable: + base = self.source_dir + else: + base = os.path.join(self.setup_py_dir, 'pip-egg-info') + filenames = os.listdir(base) + if self.editable: + filenames = [] + for root, dirs, files in os.walk(base): + for dir in vcs.dirnames: + if dir in dirs: + dirs.remove(dir) + # Iterate over a copy of ``dirs``, since mutating + # a list while iterating over it can cause trouble. + # (See https://github.com/pypa/pip/pull/462.) + for dir in list(dirs): + # Don't search in anything that looks like a virtualenv + # environment + if ( + os.path.lexists( + os.path.join(root, dir, 'bin', 'python') + ) or + os.path.exists( + os.path.join( + root, dir, 'Scripts', 'Python.exe' + ) + )): + dirs.remove(dir) + # Also don't search through tests + elif dir == 'test' or dir == 'tests': + dirs.remove(dir) + filenames.extend([os.path.join(root, dir) + for dir in dirs]) + filenames = [f for f in filenames if f.endswith('.egg-info')] + + if not filenames: + raise InstallationError( + 'No files/directories in %s (from %s)' % (base, filename) + ) + assert filenames, \ + "No files/directories in %s (from %s)" % (base, filename) + + # if we have more than one match, we pick the toplevel one. This + # can easily be the case if there is a dist folder which contains + # an extracted tarball for testing purposes. + if len(filenames) > 1: + filenames.sort( + key=lambda x: x.count(os.path.sep) + + (os.path.altsep and x.count(os.path.altsep) or 0) + ) + self._egg_info_path = os.path.join(base, filenames[0]) + return os.path.join(self._egg_info_path, filename) + + def pkg_info(self): + p = FeedParser() + data = self.egg_info_data('PKG-INFO') + if not data: + logger.warning( + 'No PKG-INFO file found in %s', + display_path(self.egg_info_path('PKG-INFO')), + ) + p.feed(data or '') + return p.close() + + _requirements_section_re = re.compile(r'\[(.*?)\]') + + @property + def installed_version(self): + return get_installed_version(self.name) + + def assert_source_matches_version(self): + assert self.source_dir + version = self.pkg_info()['version'] + if self.req.specifier and version not in self.req.specifier: + logger.warning( + 'Requested %s, but installing version %s', + self, + version, + ) + else: + logger.debug( + 'Source in %s has version %s, which satisfies requirement %s', + display_path(self.source_dir), + version, + self, + ) + + def update_editable(self, obtain=True): + if not self.link: + logger.debug( + "Cannot update repository at %s; repository location is " + "unknown", + self.source_dir, + ) + return + assert self.editable + assert self.source_dir + if self.link.scheme == 'file': + # Static paths don't get updated + return + assert '+' in self.link.url, "bad url: %r" % self.link.url + if not self.update: + return + vc_type, url = self.link.url.split('+', 1) + backend = vcs.get_backend(vc_type) + if backend: + vcs_backend = backend(self.link.url) + if obtain: + vcs_backend.obtain(self.source_dir) + else: + vcs_backend.export(self.source_dir) + else: + assert 0, ( + 'Unexpected version control type (in %s): %s' + % (self.link, vc_type)) + + def uninstall(self, auto_confirm=False, verbose=False, + use_user_site=False): + """ + Uninstall the distribution currently satisfying this requirement. + + Prompts before removing or modifying files unless + ``auto_confirm`` is True. + + Refuses to delete or modify files outside of ``sys.prefix`` - + thus uninstallation within a virtual environment can only + modify that virtual environment, even if the virtualenv is + linked to global site-packages. + + """ + if not self.check_if_exists(use_user_site): + logger.warning("Skipping %s as it is not installed.", self.name) + return + dist = self.satisfied_by or self.conflicts_with + + uninstalled_pathset = UninstallPathSet.from_dist(dist) + uninstalled_pathset.remove(auto_confirm, verbose) + return uninstalled_pathset + + def archive(self, build_dir): + assert self.source_dir + create_archive = True + archive_name = '%s-%s.zip' % (self.name, self.pkg_info()["version"]) + archive_path = os.path.join(build_dir, archive_name) + if os.path.exists(archive_path): + response = ask_path_exists( + 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' % + display_path(archive_path), ('i', 'w', 'b', 'a')) + if response == 'i': + create_archive = False + elif response == 'w': + logger.warning('Deleting %s', display_path(archive_path)) + os.remove(archive_path) + elif response == 'b': + dest_file = backup_dir(archive_path) + logger.warning( + 'Backing up %s to %s', + display_path(archive_path), + display_path(dest_file), + ) + shutil.move(archive_path, dest_file) + elif response == 'a': + sys.exit(-1) + if create_archive: + zip = zipfile.ZipFile( + archive_path, 'w', zipfile.ZIP_DEFLATED, + allowZip64=True + ) + dir = os.path.normcase(os.path.abspath(self.setup_py_dir)) + for dirpath, dirnames, filenames in os.walk(dir): + if 'pip-egg-info' in dirnames: + dirnames.remove('pip-egg-info') + for dirname in dirnames: + dirname = os.path.join(dirpath, dirname) + name = self._clean_zip_name(dirname, dir) + zipdir = zipfile.ZipInfo(self.name + '/' + name + '/') + zipdir.external_attr = 0x1ED << 16 # 0o755 + zip.writestr(zipdir, '') + for filename in filenames: + if filename == PIP_DELETE_MARKER_FILENAME: + continue + filename = os.path.join(dirpath, filename) + name = self._clean_zip_name(filename, dir) + zip.write(filename, self.name + '/' + name) + zip.close() + logger.info('Saved %s', display_path(archive_path)) + + def _clean_zip_name(self, name, prefix): + assert name.startswith(prefix + os.path.sep), ( + "name %r doesn't start with prefix %r" % (name, prefix) + ) + name = name[len(prefix) + 1:] + name = name.replace(os.path.sep, '/') + return name + + def match_markers(self, extras_requested=None): + if not extras_requested: + # Provide an extra to safely evaluate the markers + # without matching any extra + extras_requested = ('',) + if self.markers is not None: + return any( + self.markers.evaluate({'extra': extra}) + for extra in extras_requested) + else: + return True + + def install(self, install_options, global_options=None, root=None, + home=None, prefix=None, warn_script_location=True, + use_user_site=False, pycompile=True): + global_options = global_options if global_options is not None else [] + if self.editable: + self.install_editable( + install_options, global_options, prefix=prefix, + ) + return + if self.is_wheel: + version = wheel.wheel_version(self.source_dir) + wheel.check_compatibility(version, self.name) + + self.move_wheel_files( + self.source_dir, root=root, prefix=prefix, home=home, + warn_script_location=warn_script_location, + use_user_site=use_user_site, pycompile=pycompile, + ) + self.install_succeeded = True + return + + # Extend the list of global and install options passed on to + # the setup.py call with the ones from the requirements file. + # Options specified in requirements file override those + # specified on the command line, since the last option given + # to setup.py is the one that is used. + global_options = list(global_options) + \ + self.options.get('global_options', []) + install_options = list(install_options) + \ + self.options.get('install_options', []) + + if self.isolated: + global_options = global_options + ["--no-user-cfg"] + + with TempDirectory(kind="record") as temp_dir: + record_filename = os.path.join(temp_dir.path, 'install-record.txt') + install_args = self.get_install_args( + global_options, record_filename, root, prefix, pycompile, + ) + msg = 'Running setup.py install for %s' % (self.name,) + with open_spinner(msg) as spinner: + with indent_log(): + with self.build_env: + call_subprocess( + install_args + install_options, + cwd=self.setup_py_dir, + show_stdout=False, + spinner=spinner, + ) + + if not os.path.exists(record_filename): + logger.debug('Record file %s not found', record_filename) + return + self.install_succeeded = True + + def prepend_root(path): + if root is None or not os.path.isabs(path): + return path + else: + return change_root(root, path) + + with open(record_filename) as f: + for line in f: + directory = os.path.dirname(line) + if directory.endswith('.egg-info'): + egg_info_dir = prepend_root(directory) + break + else: + logger.warning( + 'Could not find .egg-info directory in install record' + ' for %s', + self, + ) + # FIXME: put the record somewhere + # FIXME: should this be an error? + return + new_lines = [] + with open(record_filename) as f: + for line in f: + filename = line.strip() + if os.path.isdir(filename): + filename += os.path.sep + new_lines.append( + os.path.relpath(prepend_root(filename), egg_info_dir) + ) + new_lines.sort() + ensure_dir(egg_info_dir) + inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') + with open(inst_files_path, 'w') as f: + f.write('\n'.join(new_lines) + '\n') + + def ensure_has_source_dir(self, parent_dir): + """Ensure that a source_dir is set. + + This will create a temporary build dir if the name of the requirement + isn't known yet. + + :param parent_dir: The ideal pip parent_dir for the source_dir. + Generally src_dir for editables and build_dir for sdists. + :return: self.source_dir + """ + if self.source_dir is None: + self.source_dir = self.build_location(parent_dir) + return self.source_dir + + def get_install_args(self, global_options, record_filename, root, prefix, + pycompile): + install_args = [sys.executable, "-u"] + install_args.append('-c') + install_args.append(SETUPTOOLS_SHIM % self.setup_py) + install_args += list(global_options) + \ + ['install', '--record', record_filename] + install_args += ['--single-version-externally-managed'] + + if root is not None: + install_args += ['--root', root] + if prefix is not None: + install_args += ['--prefix', prefix] + + if pycompile: + install_args += ["--compile"] + else: + install_args += ["--no-compile"] + + if running_under_virtualenv(): + py_ver_str = 'python' + sysconfig.get_python_version() + install_args += ['--install-headers', + os.path.join(sys.prefix, 'include', 'site', + py_ver_str, self.name)] + + return install_args + + def remove_temporary_source(self): + """Remove the source files from this requirement, if they are marked + for deletion""" + if self.source_dir and os.path.exists( + os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)): + logger.debug('Removing source in %s', self.source_dir) + rmtree(self.source_dir) + self.source_dir = None + self._temp_build_dir.cleanup() + self.build_env.cleanup() + + def install_editable(self, install_options, + global_options=(), prefix=None): + logger.info('Running setup.py develop for %s', self.name) + + if self.isolated: + global_options = list(global_options) + ["--no-user-cfg"] + + if prefix: + prefix_param = ['--prefix={}'.format(prefix)] + install_options = list(install_options) + prefix_param + + with indent_log(): + # FIXME: should we do --install-headers here too? + with self.build_env: + call_subprocess( + [ + sys.executable, + '-c', + SETUPTOOLS_SHIM % self.setup_py + ] + + list(global_options) + + ['develop', '--no-deps'] + + list(install_options), + + cwd=self.setup_py_dir, + show_stdout=False, + ) + + self.install_succeeded = True + + def check_if_exists(self, use_user_site): + """Find an installed distribution that satisfies or conflicts + with this requirement, and set self.satisfied_by or + self.conflicts_with appropriately. + """ + if self.req is None: + return False + try: + # get_distribution() will resolve the entire list of requirements + # anyway, and we've already determined that we need the requirement + # in question, so strip the marker so that we don't try to + # evaluate it. + no_marker = Requirement(str(self.req)) + no_marker.marker = None + self.satisfied_by = pkg_resources.get_distribution(str(no_marker)) + if self.editable and self.satisfied_by: + self.conflicts_with = self.satisfied_by + # when installing editables, nothing pre-existing should ever + # satisfy + self.satisfied_by = None + return True + except pkg_resources.DistributionNotFound: + return False + except pkg_resources.VersionConflict: + existing_dist = pkg_resources.get_distribution( + self.req.name + ) + if use_user_site: + if dist_in_usersite(existing_dist): + self.conflicts_with = existing_dist + elif (running_under_virtualenv() and + dist_in_site_packages(existing_dist)): + raise InstallationError( + "Will not install to the user site because it will " + "lack sys.path precedence to %s in %s" % + (existing_dist.project_name, existing_dist.location) + ) + else: + self.conflicts_with = existing_dist + return True + + @property + def is_wheel(self): + return self.link and self.link.is_wheel + + def move_wheel_files(self, wheeldir, root=None, home=None, prefix=None, + warn_script_location=True, use_user_site=False, + pycompile=True): + move_wheel_files( + self.name, self.req, wheeldir, + user=use_user_site, + home=home, + root=root, + prefix=prefix, + pycompile=pycompile, + isolated=self.isolated, + warn_script_location=warn_script_location, + ) + + def get_dist(self): + """Return a pkg_resources.Distribution built from self.egg_info_path""" + egg_info = self.egg_info_path('').rstrip(os.path.sep) + base_dir = os.path.dirname(egg_info) + metadata = pkg_resources.PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + return pkg_resources.Distribution( + os.path.dirname(egg_info), + project_name=dist_name, + metadata=metadata, + ) + + @property + def has_hash_options(self): + """Return whether any known-good hashes are specified as options. + + These activate --require-hashes mode; hashes specified as part of a + URL do not. + + """ + return bool(self.options.get('hashes', {})) + + def hashes(self, trust_internet=True): + """Return a hash-comparer that considers my option- and URL-based + hashes to be known-good. + + Hashes in URLs--ones embedded in the requirements file, not ones + downloaded from an index server--are almost peers with ones from + flags. They satisfy --require-hashes (whether it was implicitly or + explicitly activated) but do not activate it. md5 and sha224 are not + allowed in flags, which should nudge people toward good algos. We + always OR all hashes together, even ones from URLs. + + :param trust_internet: Whether to trust URL-based (#md5=...) hashes + downloaded from the internet, as by populate_link() + + """ + good_hashes = self.options.get('hashes', {}).copy() + link = self.link if trust_internet else self.original_link + if link and link.hash: + good_hashes.setdefault(link.hash_name, []).append(link.hash) + return Hashes(good_hashes) + + +def _strip_postfix(req): + """ + Strip req postfix ( -dev, 0.2, etc ) + """ + # FIXME: use package_to_requirement? + match = re.search(r'^(.*?)(?:-dev|-\d.*)$', req) + if match: + # Strip off -dev, -0.2, etc. + warnings.warn( + "#egg cleanup for editable urls will be dropped in the future", + RemovedInPip11Warning, + ) + req = match.group(1) + return req + + +def parse_editable(editable_req): + """Parses an editable requirement into: + - a requirement name + - an URL + - extras + - editable options + Accepted requirements: + svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir + .[some_extra] + """ + + from pip._internal.index import Link + + url = editable_req + + # If a file path is specified with extras, strip off the extras. + url_no_extras, extras = _strip_extras(url) + + if os.path.isdir(url_no_extras): + if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): + raise InstallationError( + "Directory %r is not installable. File 'setup.py' not found." % + url_no_extras + ) + # Treating it as code that has already been checked out + url_no_extras = path_to_url(url_no_extras) + + if url_no_extras.lower().startswith('file:'): + package_name = Link(url_no_extras).egg_fragment + if extras: + return ( + package_name, + url_no_extras, + Requirement("placeholder" + extras.lower()).extras, + ) + else: + return package_name, url_no_extras, None + + for version_control in vcs: + if url.lower().startswith('%s:' % version_control): + url = '%s+%s' % (version_control, url) + break + + if '+' not in url: + raise InstallationError( + '%s should either be a path to a local project or a VCS url ' + 'beginning with svn+, git+, hg+, or bzr+' % + editable_req + ) + + vc_type = url.split('+', 1)[0].lower() + + if not vcs.get_backend(vc_type): + error_message = 'For --editable=%s only ' % editable_req + \ + ', '.join([backend.name + '+URL' for backend in vcs.backends]) + \ + ' is currently supported' + raise InstallationError(error_message) + + package_name = Link(url).egg_fragment + if not package_name: + raise InstallationError( + "Could not detect requirement name for '%s', please specify one " + "with #egg=your_package_name" % editable_req + ) + return _strip_postfix(package_name), url, None + + +def deduce_helpful_msg(req): + """Returns helpful msg in case requirements file does not exist, + or cannot be parsed. + + :params req: Requirements file path + """ + msg = "" + if os.path.exists(req): + msg = " It does exist." + # Try to parse and check if it is a requirements file. + try: + with open(req, 'r') as fp: + # parse first line only + next(parse_requirements(fp.read())) + msg += " The argument you provided " + \ + "(%s) appears to be a" % (req) + \ + " requirements file. If that is the" + \ + " case, use the '-r' flag to install" + \ + " the packages specified within it." + except RequirementParseError: + logger.debug("Cannot parse '%s' as requirements \ + file" % (req), exc_info=1) + else: + msg += " File '%s' does not exist." % (req) + return msg diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py new file mode 100755 index 0000000..78b7d32 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_set.py @@ -0,0 +1,164 @@ +from __future__ import absolute_import + +import logging +from collections import OrderedDict + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.logging import indent_log +from pip._internal.wheel import Wheel + +logger = logging.getLogger(__name__) + + +class RequirementSet(object): + + def __init__(self, require_hashes=False): + """Create a RequirementSet. + + :param wheel_cache: The pip wheel cache, for passing to + InstallRequirement. + """ + + self.requirements = OrderedDict() + self.require_hashes = require_hashes + + # Mapping of alias: real_name + self.requirement_aliases = {} + self.unnamed_requirements = [] + self.successfully_downloaded = [] + self.reqs_to_cleanup = [] + + def __str__(self): + reqs = [req for req in self.requirements.values() + if not req.comes_from] + reqs.sort(key=lambda req: req.name.lower()) + return ' '.join([str(req.req) for req in reqs]) + + def __repr__(self): + reqs = [req for req in self.requirements.values()] + reqs.sort(key=lambda req: req.name.lower()) + reqs_str = ', '.join([str(req.req) for req in reqs]) + return ('<%s object; %d requirement(s): %s>' + % (self.__class__.__name__, len(reqs), reqs_str)) + + def add_requirement(self, install_req, parent_req_name=None, + extras_requested=None): + """Add install_req as a requirement to install. + + :param parent_req_name: The name of the requirement that needed this + added. The name is used because when multiple unnamed requirements + resolve to the same name, we could otherwise end up with dependency + links that point outside the Requirements set. parent_req must + already be added. Note that None implies that this is a user + supplied requirement, vs an inferred one. + :param extras_requested: an iterable of extras used to evaluate the + environment markers. + :return: Additional requirements to scan. That is either [] if + the requirement is not applicable, or [install_req] if the + requirement is applicable and has just been added. + """ + name = install_req.name + if not install_req.match_markers(extras_requested): + logger.info("Ignoring %s: markers '%s' don't match your " + "environment", install_req.name, + install_req.markers) + return [], None + + # This check has to come after we filter requirements with the + # environment markers. + if install_req.link and install_req.link.is_wheel: + wheel = Wheel(install_req.link.filename) + if not wheel.supported(): + raise InstallationError( + "%s is not a supported wheel on this platform." % + wheel.filename + ) + + # This next bit is really a sanity check. + assert install_req.is_direct == (parent_req_name is None), ( + "a direct req shouldn't have a parent and also, " + "a non direct req should have a parent" + ) + + if not name: + # url or path requirement w/o an egg fragment + self.unnamed_requirements.append(install_req) + return [install_req], None + else: + try: + existing_req = self.get_requirement(name) + except KeyError: + existing_req = None + if (parent_req_name is None and existing_req and not + existing_req.constraint and + existing_req.extras == install_req.extras and not + existing_req.req.specifier == install_req.req.specifier): + raise InstallationError( + 'Double requirement given: %s (already in %s, name=%r)' + % (install_req, existing_req, name)) + if not existing_req: + # Add requirement + self.requirements[name] = install_req + # FIXME: what about other normalizations? E.g., _ vs. -? + if name.lower() != name: + self.requirement_aliases[name.lower()] = name + result = [install_req] + else: + # Assume there's no need to scan, and that we've already + # encountered this for scanning. + result = [] + if not install_req.constraint and existing_req.constraint: + if (install_req.link and not (existing_req.link and + install_req.link.path == existing_req.link.path)): + self.reqs_to_cleanup.append(install_req) + raise InstallationError( + "Could not satisfy constraints for '%s': " + "installation from path or url cannot be " + "constrained to a version" % name, + ) + # If we're now installing a constraint, mark the existing + # object for real installation. + existing_req.constraint = False + existing_req.extras = tuple( + sorted(set(existing_req.extras).union( + set(install_req.extras)))) + logger.debug("Setting %s extras to: %s", + existing_req, existing_req.extras) + # And now we need to scan this. + result = [existing_req] + # Canonicalise to the already-added object for the backref + # check below. + install_req = existing_req + + # We return install_req here to allow for the caller to add it to + # the dependency information for the parent package. + return result, install_req + + def has_requirement(self, project_name): + name = project_name.lower() + if (name in self.requirements and + not self.requirements[name].constraint or + name in self.requirement_aliases and + not self.requirements[self.requirement_aliases[name]].constraint): + return True + return False + + @property + def has_requirements(self): + return list(req for req in self.requirements.values() if not + req.constraint) or self.unnamed_requirements + + def get_requirement(self, project_name): + for name in project_name, project_name.lower(): + if name in self.requirements: + return self.requirements[name] + if name in self.requirement_aliases: + return self.requirements[self.requirement_aliases[name]] + raise KeyError("No project with the name %r" % project_name) + + def cleanup_files(self): + """Clean up files, remove builds.""" + logger.debug('Cleaning up...') + with indent_log(): + for req in self.reqs_to_cleanup: + req.remove_temporary_source() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py new file mode 100755 index 0000000..a47520f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/req/req_uninstall.py @@ -0,0 +1,455 @@ +from __future__ import absolute_import + +import csv +import functools +import logging +import os +import sys +import sysconfig + +from pip._vendor import pkg_resources + +from pip._internal.compat import WINDOWS, cache_from_source, uses_pycache +from pip._internal.exceptions import UninstallationError +from pip._internal.locations import bin_py, bin_user +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + FakeFile, ask, dist_in_usersite, dist_is_local, egg_link_path, is_local, + normalize_path, renames, +) +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +def _script_names(dist, script_name, is_gui): + """Create the fully qualified name of the files created by + {console,gui}_scripts for the given ``dist``. + Returns the list of file names + """ + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + exe_name = os.path.join(bin_dir, script_name) + paths_to_remove = [exe_name] + if WINDOWS: + paths_to_remove.append(exe_name + '.exe') + paths_to_remove.append(exe_name + '.exe.manifest') + if is_gui: + paths_to_remove.append(exe_name + '-script.pyw') + else: + paths_to_remove.append(exe_name + '-script.py') + return paths_to_remove + + +def _unique(fn): + @functools.wraps(fn) + def unique(*args, **kw): + seen = set() + for item in fn(*args, **kw): + if item not in seen: + seen.add(item) + yield item + return unique + + +@_unique +def uninstallation_paths(dist): + """ + Yield all the uninstallation paths for dist based on RECORD-without-.pyc + + Yield paths to all the files in RECORD. For each .py file in RECORD, add + the .pyc in the same directory. + + UninstallPathSet.add() takes care of the __pycache__ .pyc. + """ + r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) + for row in r: + path = os.path.join(dist.location, row[0]) + yield path + if path.endswith('.py'): + dn, fn = os.path.split(path) + base = fn[:-3] + path = os.path.join(dn, base + '.pyc') + yield path + + +def compact(paths): + """Compact a path set to contain the minimal number of paths + necessary to contain all paths in the set. If /a/path/ and + /a/path/to/a/file.txt are both in the set, leave only the + shorter path.""" + + sep = os.path.sep + short_paths = set() + for path in sorted(paths, key=len): + should_add = any( + path.startswith(shortpath.rstrip("*")) and + path[len(shortpath.rstrip("*").rstrip(sep))] == sep + for shortpath in short_paths + ) + if not should_add: + short_paths.add(path) + return short_paths + + +def compress_for_output_listing(paths): + """Returns a tuple of 2 sets of which paths to display to user + + The first set contains paths that would be deleted. Files of a package + are not added and the top-level directory of the package has a '*' added + at the end - to signify that all it's contents are removed. + + The second set contains files that would have been skipped in the above + folders. + """ + + will_remove = list(paths) + will_skip = set() + + # Determine folders and files + folders = set() + files = set() + for path in will_remove: + if path.endswith(".pyc"): + continue + if path.endswith("__init__.py") or ".dist-info" in path: + folders.add(os.path.dirname(path)) + files.add(path) + + folders = compact(folders) + + # This walks the tree using os.walk to not miss extra folders + # that might get added. + for folder in folders: + for dirpath, _, dirfiles in os.walk(folder): + for fname in dirfiles: + if fname.endswith(".pyc"): + continue + + file_ = os.path.normcase(os.path.join(dirpath, fname)) + if os.path.isfile(file_) and file_ not in files: + # We are skipping this file. Add it to the set. + will_skip.add(file_) + + will_remove = files | { + os.path.join(folder, "*") for folder in folders + } + + return will_remove, will_skip + + +class UninstallPathSet(object): + """A set of file paths to be removed in the uninstallation of a + requirement.""" + def __init__(self, dist): + self.paths = set() + self._refuse = set() + self.pth = {} + self.dist = dist + self.save_dir = TempDirectory(kind="uninstall") + self._moved_paths = [] + + def _permitted(self, path): + """ + Return True if the given path is one we are permitted to + remove/modify, False otherwise. + + """ + return is_local(path) + + def add(self, path): + head, tail = os.path.split(path) + + # we normalize the head to resolve parent directory symlinks, but not + # the tail, since we only want to uninstall symlinks, not their targets + path = os.path.join(normalize_path(head), os.path.normcase(tail)) + + if not os.path.exists(path): + return + if self._permitted(path): + self.paths.add(path) + else: + self._refuse.add(path) + + # __pycache__ files can show up after 'installed-files.txt' is created, + # due to imports + if os.path.splitext(path)[1] == '.py' and uses_pycache: + self.add(cache_from_source(path)) + + def add_pth(self, pth_file, entry): + pth_file = normalize_path(pth_file) + if self._permitted(pth_file): + if pth_file not in self.pth: + self.pth[pth_file] = UninstallPthEntries(pth_file) + self.pth[pth_file].add(entry) + else: + self._refuse.add(pth_file) + + def _stash(self, path): + return os.path.join( + self.save_dir.path, os.path.splitdrive(path)[1].lstrip(os.path.sep) + ) + + def remove(self, auto_confirm=False, verbose=False): + """Remove paths in ``self.paths`` with confirmation (unless + ``auto_confirm`` is True).""" + + if not self.paths: + logger.info( + "Can't uninstall '%s'. No files were found to uninstall.", + self.dist.project_name, + ) + return + + dist_name_version = ( + self.dist.project_name + "-" + self.dist.version + ) + logger.info('Uninstalling %s:', dist_name_version) + + with indent_log(): + if auto_confirm or self._allowed_to_proceed(verbose): + self.save_dir.create() + + for path in sorted(compact(self.paths)): + new_path = self._stash(path) + logger.debug('Removing file or directory %s', path) + self._moved_paths.append(path) + renames(path, new_path) + for pth in self.pth.values(): + pth.remove() + + logger.info('Successfully uninstalled %s', dist_name_version) + + def _allowed_to_proceed(self, verbose): + """Display which files would be deleted and prompt for confirmation + """ + + def _display(msg, paths): + if not paths: + return + + logger.info(msg) + with indent_log(): + for path in sorted(compact(paths)): + logger.info(path) + + if not verbose: + will_remove, will_skip = compress_for_output_listing(self.paths) + else: + # In verbose mode, display all the files that are going to be + # deleted. + will_remove = list(self.paths) + will_skip = set() + + _display('Would remove:', will_remove) + _display('Would not remove (might be manually added):', will_skip) + _display('Would not remove (outside of prefix):', self._refuse) + + return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' + + def rollback(self): + """Rollback the changes previously made by remove().""" + if self.save_dir.path is None: + logger.error( + "Can't roll back %s; was not uninstalled", + self.dist.project_name, + ) + return False + logger.info('Rolling back uninstall of %s', self.dist.project_name) + for path in self._moved_paths: + tmp_path = self._stash(path) + logger.debug('Replacing %s', path) + renames(tmp_path, path) + for pth in self.pth.values(): + pth.rollback() + + def commit(self): + """Remove temporary save dir: rollback will no longer be possible.""" + self.save_dir.cleanup() + self._moved_paths = [] + + @classmethod + def from_dist(cls, dist): + dist_path = normalize_path(dist.location) + if not dist_is_local(dist): + logger.info( + "Not uninstalling %s at %s, outside environment %s", + dist.key, + dist_path, + sys.prefix, + ) + return cls(dist) + + if dist_path in {p for p in {sysconfig.get_path("stdlib"), + sysconfig.get_path("platstdlib")} + if p}: + logger.info( + "Not uninstalling %s at %s, as it is in the standard library.", + dist.key, + dist_path, + ) + return cls(dist) + + paths_to_remove = cls(dist) + develop_egg_link = egg_link_path(dist) + develop_egg_link_egg_info = '{}.egg-info'.format( + pkg_resources.to_filename(dist.project_name)) + egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) + # Special case for distutils installed package + distutils_egg_info = getattr(dist._provider, 'path', None) + + # Uninstall cases order do matter as in the case of 2 installs of the + # same package, pip needs to uninstall the currently detected version + if (egg_info_exists and dist.egg_info.endswith('.egg-info') and + not dist.egg_info.endswith(develop_egg_link_egg_info)): + # if dist.egg_info.endswith(develop_egg_link_egg_info), we + # are in fact in the develop_egg_link case + paths_to_remove.add(dist.egg_info) + if dist.has_metadata('installed-files.txt'): + for installed_file in dist.get_metadata( + 'installed-files.txt').splitlines(): + path = os.path.normpath( + os.path.join(dist.egg_info, installed_file) + ) + paths_to_remove.add(path) + # FIXME: need a test for this elif block + # occurs with --single-version-externally-managed/--record outside + # of pip + elif dist.has_metadata('top_level.txt'): + if dist.has_metadata('namespace_packages.txt'): + namespaces = dist.get_metadata('namespace_packages.txt') + else: + namespaces = [] + for top_level_pkg in [ + p for p + in dist.get_metadata('top_level.txt').splitlines() + if p and p not in namespaces]: + path = os.path.join(dist.location, top_level_pkg) + paths_to_remove.add(path) + paths_to_remove.add(path + '.py') + paths_to_remove.add(path + '.pyc') + paths_to_remove.add(path + '.pyo') + + elif distutils_egg_info: + raise UninstallationError( + "Cannot uninstall {!r}. It is a distutils installed project " + "and thus we cannot accurately determine which files belong " + "to it which would lead to only a partial uninstall.".format( + dist.project_name, + ) + ) + + elif dist.location.endswith('.egg'): + # package installed by easy_install + # We cannot match on dist.egg_name because it can slightly vary + # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg + paths_to_remove.add(dist.location) + easy_install_egg = os.path.split(dist.location)[1] + easy_install_pth = os.path.join(os.path.dirname(dist.location), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) + + elif egg_info_exists and dist.egg_info.endswith('.dist-info'): + for path in uninstallation_paths(dist): + paths_to_remove.add(path) + + elif develop_egg_link: + # develop egg + with open(develop_egg_link, 'r') as fh: + link_pointer = os.path.normcase(fh.readline().strip()) + assert (link_pointer == dist.location), ( + 'Egg-link %s does not match installed location of %s ' + '(at %s)' % (link_pointer, dist.project_name, dist.location) + ) + paths_to_remove.add(develop_egg_link) + easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, dist.location) + + else: + logger.debug( + 'Not sure how to uninstall: %s - Check: %s', + dist, dist.location, + ) + + # find distutils scripts= scripts + if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): + for script in dist.metadata_listdir('scripts'): + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + paths_to_remove.add(os.path.join(bin_dir, script)) + if WINDOWS: + paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') + + # find console_scripts + _scripts_to_remove = [] + console_scripts = dist.get_entry_map(group='console_scripts') + for name in console_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, False)) + # find gui_scripts + gui_scripts = dist.get_entry_map(group='gui_scripts') + for name in gui_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, True)) + + for s in _scripts_to_remove: + paths_to_remove.add(s) + + return paths_to_remove + + +class UninstallPthEntries(object): + def __init__(self, pth_file): + if not os.path.isfile(pth_file): + raise UninstallationError( + "Cannot remove entries from nonexistent file %s" % pth_file + ) + self.file = pth_file + self.entries = set() + self._saved_lines = None + + def add(self, entry): + entry = os.path.normcase(entry) + # On Windows, os.path.normcase converts the entry to use + # backslashes. This is correct for entries that describe absolute + # paths outside of site-packages, but all the others use forward + # slashes. + if WINDOWS and not os.path.splitdrive(entry)[0]: + entry = entry.replace('\\', '/') + self.entries.add(entry) + + def remove(self): + logger.debug('Removing pth entries from %s:', self.file) + with open(self.file, 'rb') as fh: + # windows uses '\r\n' with py3k, but uses '\n' with py2.x + lines = fh.readlines() + self._saved_lines = lines + if any(b'\r\n' in line for line in lines): + endline = '\r\n' + else: + endline = '\n' + # handle missing trailing newline + if lines and not lines[-1].endswith(endline.encode("utf-8")): + lines[-1] = lines[-1] + endline.encode("utf-8") + for entry in self.entries: + try: + logger.debug('Removing entry: %s', entry) + lines.remove((entry + endline).encode("utf-8")) + except ValueError: + pass + with open(self.file, 'wb') as fh: + fh.writelines(lines) + + def rollback(self): + if self._saved_lines is None: + logger.error( + 'Cannot roll back changes to %s, none were made', self.file + ) + return False + logger.debug('Rolling %s back to previous state', self.file) + with open(self.file, 'wb') as fh: + fh.writelines(self._saved_lines) + return True diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py new file mode 100755 index 0000000..189827e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/resolve.py @@ -0,0 +1,354 @@ +"""Dependency Resolution + +The dependency resolution in pip is performed as follows: + +for top-level requirements: + a. only one spec allowed per project, regardless of conflicts or not. + otherwise a "double requirement" exception is raised + b. they override sub-dependency requirements. +for sub-dependencies + a. "first found, wins" (where the order is breadth first) +""" + +import logging +from collections import defaultdict +from itertools import chain + +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, DistributionNotFound, HashError, HashErrors, + UnsupportedPythonVersion, +) + +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import dist_in_usersite, ensure_dir +from pip._internal.utils.packaging import check_dist_requires_python + +logger = logging.getLogger(__name__) + + +class Resolver(object): + """Resolves which packages need to be installed/uninstalled to perform \ + the requested operation without breaking the requirements of any package. + """ + + _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} + + def __init__(self, preparer, session, finder, wheel_cache, use_user_site, + ignore_dependencies, ignore_installed, ignore_requires_python, + force_reinstall, isolated, upgrade_strategy): + super(Resolver, self).__init__() + assert upgrade_strategy in self._allowed_strategies + + self.preparer = preparer + self.finder = finder + self.session = session + + # NOTE: This would eventually be replaced with a cache that can give + # information about both sdist and wheels transparently. + self.wheel_cache = wheel_cache + + self.require_hashes = None # This is set in resolve + + self.upgrade_strategy = upgrade_strategy + self.force_reinstall = force_reinstall + self.isolated = isolated + self.ignore_dependencies = ignore_dependencies + self.ignore_installed = ignore_installed + self.ignore_requires_python = ignore_requires_python + self.use_user_site = use_user_site + + self._discovered_dependencies = defaultdict(list) + + def resolve(self, requirement_set): + """Resolve what operations need to be done + + As a side-effect of this method, the packages (and their dependencies) + are downloaded, unpacked and prepared for installation. This + preparation is done by ``pip.operations.prepare``. + + Once PyPI has static dependency metadata available, it would be + possible to move the preparation to become a step separated from + dependency resolution. + """ + # make the wheelhouse + if self.preparer.wheel_download_dir: + ensure_dir(self.preparer.wheel_download_dir) + + # If any top-level requirement has a hash specified, enter + # hash-checking mode, which requires hashes from all. + root_reqs = ( + requirement_set.unnamed_requirements + + list(requirement_set.requirements.values()) + ) + self.require_hashes = ( + requirement_set.require_hashes or + any(req.has_hash_options for req in root_reqs) + ) + + # Display where finder is looking for packages + locations = self.finder.get_formatted_locations() + if locations: + logger.info(locations) + + # Actually prepare the files, and collect any exceptions. Most hash + # exceptions cannot be checked ahead of time, because + # req.populate_link() needs to be called before we can make decisions + # based on link type. + discovered_reqs = [] + hash_errors = HashErrors() + for req in chain(root_reqs, discovered_reqs): + try: + discovered_reqs.extend( + self._resolve_one(requirement_set, req) + ) + except HashError as exc: + exc.req = req + hash_errors.append(exc) + + if hash_errors: + raise hash_errors + + def _is_upgrade_allowed(self, req): + if self.upgrade_strategy == "to-satisfy-only": + return False + elif self.upgrade_strategy == "eager": + return True + else: + assert self.upgrade_strategy == "only-if-needed" + return req.is_direct + + def _set_req_to_reinstall(self, req): + """ + Set a requirement to be installed. + """ + # Don't uninstall the conflict if doing a user install and the + # conflict is not a user install. + if not self.use_user_site or dist_in_usersite(req.satisfied_by): + req.conflicts_with = req.satisfied_by + req.satisfied_by = None + + # XXX: Stop passing requirement_set for options + def _check_skip_installed(self, req_to_install): + """Check if req_to_install should be skipped. + + This will check if the req is installed, and whether we should upgrade + or reinstall it, taking into account all the relevant user options. + + After calling this req_to_install will only have satisfied_by set to + None if the req_to_install is to be upgraded/reinstalled etc. Any + other value will be a dist recording the current thing installed that + satisfies the requirement. + + Note that for vcs urls and the like we can't assess skipping in this + routine - we simply identify that we need to pull the thing down, + then later on it is pulled down and introspected to assess upgrade/ + reinstalls etc. + + :return: A text reason for why it was skipped, or None. + """ + if self.ignore_installed: + return None + + req_to_install.check_if_exists(self.use_user_site) + if not req_to_install.satisfied_by: + return None + + if self.force_reinstall: + self._set_req_to_reinstall(req_to_install) + return None + + if not self._is_upgrade_allowed(req_to_install): + if self.upgrade_strategy == "only-if-needed": + return 'not upgraded as not directly required' + return 'already satisfied' + + # Check for the possibility of an upgrade. For link-based + # requirements we have to pull the tree down and inspect to assess + # the version #, so it's handled way down. + if not req_to_install.link: + try: + self.finder.find_requirement(req_to_install, upgrade=True) + except BestVersionAlreadyInstalled: + # Then the best version is installed. + return 'already up-to-date' + except DistributionNotFound: + # No distribution found, so we squash the error. It will + # be raised later when we re-try later to do the install. + # Why don't we just raise here? + pass + + self._set_req_to_reinstall(req_to_install) + return None + + def _get_abstract_dist_for(self, req): + """Takes a InstallRequirement and returns a single AbstractDist \ + representing a prepared variant of the same. + """ + assert self.require_hashes is not None, ( + "require_hashes should have been set in Resolver.resolve()" + ) + + if req.editable: + return self.preparer.prepare_editable_requirement( + req, self.require_hashes, self.use_user_site, self.finder, + ) + + # satisfied_by is only evaluated by calling _check_skip_installed, + # so it must be None here. + assert req.satisfied_by is None + skip_reason = self._check_skip_installed(req) + + if req.satisfied_by: + return self.preparer.prepare_installed_requirement( + req, self.require_hashes, skip_reason + ) + + upgrade_allowed = self._is_upgrade_allowed(req) + abstract_dist = self.preparer.prepare_linked_requirement( + req, self.session, self.finder, upgrade_allowed, + self.require_hashes + ) + + # NOTE + # The following portion is for determining if a certain package is + # going to be re-installed/upgraded or not and reporting to the user. + # This should probably get cleaned up in a future refactor. + + # req.req is only avail after unpack for URL + # pkgs repeat check_if_exists to uninstall-on-upgrade + # (#14) + if not self.ignore_installed: + req.check_if_exists(self.use_user_site) + + if req.satisfied_by: + should_modify = ( + self.upgrade_strategy != "to-satisfy-only" or + self.force_reinstall or + self.ignore_installed or + req.link.scheme == 'file' + ) + if should_modify: + self._set_req_to_reinstall(req) + else: + logger.info( + 'Requirement already satisfied (use --upgrade to upgrade):' + ' %s', req, + ) + + return abstract_dist + + def _resolve_one(self, requirement_set, req_to_install): + """Prepare a single requirements file. + + :return: A list of additional InstallRequirements to also install. + """ + # Tell user what we are doing for this requirement: + # obtain (editable), skipping, processing (local url), collecting + # (remote url or package name) + if req_to_install.constraint or req_to_install.prepared: + return [] + + req_to_install.prepared = True + + # register tmp src for cleanup in case something goes wrong + requirement_set.reqs_to_cleanup.append(req_to_install) + + abstract_dist = self._get_abstract_dist_for(req_to_install) + + # Parse and return dependencies + dist = abstract_dist.dist(self.finder) + try: + check_dist_requires_python(dist) + except UnsupportedPythonVersion as err: + if self.ignore_requires_python: + logger.warning(err.args[0]) + else: + raise + + more_reqs = [] + + def add_req(subreq, extras_requested): + sub_install_req = InstallRequirement.from_req( + str(subreq), + req_to_install, + isolated=self.isolated, + wheel_cache=self.wheel_cache, + ) + parent_req_name = req_to_install.name + to_scan_again, add_to_parent = requirement_set.add_requirement( + sub_install_req, + parent_req_name=parent_req_name, + extras_requested=extras_requested, + ) + if parent_req_name and add_to_parent: + self._discovered_dependencies[parent_req_name].append( + add_to_parent + ) + more_reqs.extend(to_scan_again) + + with indent_log(): + # We add req_to_install before its dependencies, so that we + # can refer to it when adding dependencies. + if not requirement_set.has_requirement(req_to_install.name): + # 'unnamed' requirements will get added here + req_to_install.is_direct = True + requirement_set.add_requirement( + req_to_install, parent_req_name=None, + ) + + if not self.ignore_dependencies: + if req_to_install.extras: + logger.debug( + "Installing extra requirements: %r", + ','.join(req_to_install.extras), + ) + missing_requested = sorted( + set(req_to_install.extras) - set(dist.extras) + ) + for missing in missing_requested: + logger.warning( + '%s does not provide the extra \'%s\'', + dist, missing + ) + + available_requested = sorted( + set(dist.extras) & set(req_to_install.extras) + ) + for subreq in dist.requires(available_requested): + add_req(subreq, extras_requested=available_requested) + + if not req_to_install.editable and not req_to_install.satisfied_by: + # XXX: --no-install leads this to report 'Successfully + # downloaded' for only non-editable reqs, even though we took + # action on them. + requirement_set.successfully_downloaded.append(req_to_install) + + return more_reqs + + def get_installation_order(self, req_set): + """Create the installation order. + + The installation order is topological - requirements are installed + before the requiring thing. We break cycles at an arbitrary point, + and make no other guarantees. + """ + # The current implementation, which we may change at any point + # installs the user specified things in the order given, except when + # dependencies must come earlier to achieve topological order. + order = [] + ordered_reqs = set() + + def schedule(req): + if req.satisfied_by or req in ordered_reqs: + return + if req.constraint: + return + ordered_reqs.add(req) + for dep in self._discovered_dependencies[req.name]: + schedule(dep) + order.append(req) + + for install_req in req_set.requirements.values(): + schedule(install_req) + return order diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py new file mode 100755 index 0000000..2b56931 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/status_codes.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +SUCCESS = 0 +ERROR = 1 +UNKNOWN_ERROR = 2 +VIRTUALENV_NOT_FOUND = 3 +PREVIOUS_BUILD_DIR_ERROR = 4 +NO_MATCHES_FOUND = 23 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py new file mode 100755 index 0000000..0eb87ca --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/appdirs.py @@ -0,0 +1,258 @@ +""" +This code was taken from https://github.com/ActiveState/appdirs and modified +to suit our purposes. +""" +from __future__ import absolute_import + +import os +import sys + +from pip._vendor.six import PY2, text_type + +from pip._internal.compat import WINDOWS, expanduser + + +def user_cache_dir(appname): + r""" + Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + + Typical user cache directories are: + macOS: ~/Library/Caches/<AppName> + Unix: ~/.cache/<AppName> (XDG default) + Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go + in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the + non-roaming app data dir (the default returned by `user_data_dir`). Apps + typically put cache data somewhere *under* the given dir here. Some + examples: + ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache + ...\Acme\SuperApp\Cache\1.0 + + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + """ + if WINDOWS: + # Get the base path + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + + # When using Python 2, return paths as bytes on Windows like we do on + # other operating systems. See helper function docs for more details. + if PY2 and isinstance(path, text_type): + path = _win_path_to_bytes(path) + + # Add our app name and Cache directory to it + path = os.path.join(path, appname, "Cache") + elif sys.platform == "darwin": + # Get the base path + path = expanduser("~/Library/Caches") + + # Add our app name to it + path = os.path.join(path, appname) + else: + # Get the base path + path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache")) + + # Add our app name to it + path = os.path.join(path, appname) + + return path + + +def user_data_dir(appname, roaming=False): + r""" + Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user data directories are: + macOS: ~/Library/Application Support/<AppName> + if it exists, else ~/.config/<AppName> + Unix: ~/.local/share/<AppName> # or in + $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\<username>\ ... + ...Application Data\<AppName> + Win XP (roaming): C:\Documents and Settings\<username>\Local ... + ...Settings\Application Data\<AppName> + Win 7 (not roaming): C:\\Users\<username>\AppData\Local\<AppName> + Win 7 (roaming): C:\\Users\<username>\AppData\Roaming\<AppName> + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/<AppName>". + """ + if WINDOWS: + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.join(os.path.normpath(_get_win_folder(const)), appname) + elif sys.platform == "darwin": + path = os.path.join( + expanduser('~/Library/Application Support/'), + appname, + ) if os.path.isdir(os.path.join( + expanduser('~/Library/Application Support/'), + appname, + ) + ) else os.path.join( + expanduser('~/.config/'), + appname, + ) + else: + path = os.path.join( + os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")), + appname, + ) + + return path + + +def user_config_dir(appname, roaming=True): + """Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "roaming" (boolean, default True) can be set False to not use the + Windows roaming appdata directory. That means that for users on a + Windows network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user data directories are: + macOS: same as user_data_dir + Unix: ~/.config/<AppName> + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/<AppName>". + """ + if WINDOWS: + path = user_data_dir(appname, roaming=roaming) + elif sys.platform == "darwin": + path = user_data_dir(appname) + else: + path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config")) + path = os.path.join(path, appname) + + return path + + +# for the discussion regarding site_config_dirs locations +# see <https://github.com/pypa/pip/issues/1733> +def site_config_dirs(appname): + r"""Return a list of potential user-shared config dirs for this application. + + "appname" is the name of application. + + Typical user config directories are: + macOS: /Library/Application Support/<AppName>/ + Unix: /etc or $XDG_CONFIG_DIRS[i]/<AppName>/ for each value in + $XDG_CONFIG_DIRS + Win XP: C:\Documents and Settings\All Users\Application ... + ...Data\<AppName>\ + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory + on Vista.) + Win 7: Hidden, but writeable on Win 7: + C:\ProgramData\<AppName>\ + """ + if WINDOWS: + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + pathlist = [os.path.join(path, appname)] + elif sys.platform == 'darwin': + pathlist = [os.path.join('/Library/Application Support', appname)] + else: + # try looking in $XDG_CONFIG_DIRS + xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + if xdg_config_dirs: + pathlist = [ + os.path.join(expanduser(x), appname) + for x in xdg_config_dirs.split(os.pathsep) + ] + else: + pathlist = [] + + # always look in /etc directly as well + pathlist.append('/etc') + + return pathlist + + +# -- Windows support functions -- + +def _get_win_folder_from_registry(csidl_name): + """ + This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + directory, _type = _winreg.QueryValueEx(key, shell_folder_name) + return directory + + +def _get_win_folder_with_ctypes(csidl_name): + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + + +if WINDOWS: + try: + import ctypes + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +def _win_path_to_bytes(path): + """Encode Windows paths to bytes. Only used on Python 2. + + Motivation is to be consistent with other operating systems where paths + are also returned as bytes. This avoids problems mixing bytes and Unicode + elsewhere in the codebase. For more details and discussion see + <https://github.com/pypa/pip/issues/3463>. + + If encoding using ASCII and MBCS fails, return the original Unicode path. + """ + for encoding in ('ASCII', 'MBCS'): + try: + return path.encode(encoding) + except (UnicodeEncodeError, LookupError): + pass + return path diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py new file mode 100755 index 0000000..c0e3884 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/deprecation.py @@ -0,0 +1,77 @@ +""" +A module that implements tooling to enable easy warnings about deprecations. +""" +from __future__ import absolute_import + +import logging +import warnings + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any + + +class PipDeprecationWarning(Warning): + pass + + +class Pending(object): + pass + + +class RemovedInPip11Warning(PipDeprecationWarning): + pass + + +class RemovedInPip12Warning(PipDeprecationWarning, Pending): + pass + + +# Warnings <-> Logging Integration + + +_warnings_showwarning = None # type: Any + + +def _showwarning(message, category, filename, lineno, file=None, line=None): + if file is not None: + if _warnings_showwarning is not None: + _warnings_showwarning( + message, category, filename, lineno, file, line, + ) + else: + if issubclass(category, PipDeprecationWarning): + # We use a specially named logger which will handle all of the + # deprecation messages for pip. + logger = logging.getLogger("pip._internal.deprecations") + + # This is purposely using the % formatter here instead of letting + # the logging module handle the interpolation. This is because we + # want it to appear as if someone typed this entire message out. + log_message = "DEPRECATION: %s" % message + + # PipDeprecationWarnings that are Pending still have at least 2 + # versions to go until they are removed so they can just be + # warnings. Otherwise, they will be removed in the very next + # version of pip. We want these to be more obvious so we use the + # ERROR logging level. + if issubclass(category, Pending): + logger.warning(log_message) + else: + logger.error(log_message) + else: + _warnings_showwarning( + message, category, filename, lineno, file, line, + ) + + +def install_warning_logger(): + # Enable our Deprecation Warnings + warnings.simplefilter("default", PipDeprecationWarning, append=True) + + global _warnings_showwarning + + if _warnings_showwarning is None: + _warnings_showwarning = warnings.showwarning + warnings.showwarning = _showwarning diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py new file mode 100755 index 0000000..831f3f6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/encoding.py @@ -0,0 +1,33 @@ +import codecs +import locale +import re +import sys + +BOMS = [ + (codecs.BOM_UTF8, 'utf8'), + (codecs.BOM_UTF16, 'utf16'), + (codecs.BOM_UTF16_BE, 'utf16-be'), + (codecs.BOM_UTF16_LE, 'utf16-le'), + (codecs.BOM_UTF32, 'utf32'), + (codecs.BOM_UTF32_BE, 'utf32-be'), + (codecs.BOM_UTF32_LE, 'utf32-le'), +] + +ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') + + +def auto_decode(data): + """Check a bytes string for a BOM to correctly detect the encoding + + Fallback to locale.getpreferredencoding(False) like open() on Python3""" + for bom, encoding in BOMS: + if data.startswith(bom): + return data[len(bom):].decode(encoding) + # Lets check the first two lines as in PEP263 + for line in data.split(b'\n')[:2]: + if line[0:1] == b'#' and ENCODING_RE.search(line): + encoding = ENCODING_RE.search(line).groups()[0].decode('ascii') + return data.decode(encoding) + return data.decode( + locale.getpreferredencoding(False) or sys.getdefaultencoding(), + ) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py new file mode 100755 index 0000000..94fa2c6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/filesystem.py @@ -0,0 +1,28 @@ +import os +import os.path + +from pip._internal.compat import get_path_uid + + +def check_path_owner(path): + # If we don't have a way to check the effective uid of this process, then + # we'll just assume that we own the directory. + if not hasattr(os, "geteuid"): + return True + + previous = None + while path != previous: + if os.path.lexists(path): + # Check if path is writable by current user. + if os.geteuid() == 0: + # Special handling for root user in order to handle properly + # cases where users use sudo without -H flag. + try: + path_uid = get_path_uid(path) + except OSError: + return False + return path_uid == 0 + else: + return os.access(path, os.W_OK) + else: + previous, path = path, os.path.dirname(path) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py new file mode 100755 index 0000000..5900a10 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/glibc.py @@ -0,0 +1,84 @@ +from __future__ import absolute_import + +import ctypes +import re +import warnings + + +def glibc_version_string(): + "Returns glibc version string, or None if not using glibc." + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + process_namespace = ctypes.CDLL(None) + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# Separated out from have_compatible_glibc for easier unit testing +def check_glibc_version(version_str, required_major, minimum_minor): + # Parse string and check against requested version. + # + # We use a regexp instead of str.split because we want to discard any + # random junk that might come after the minor version -- this might happen + # in patched/forked versions of glibc (e.g. Linaro's version of glibc + # uses version strings like "2.20-2014.11"). See gh-3588. + m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str) + if not m: + warnings.warn("Expected glibc version with 2 components major.minor," + " got: %s" % version_str, RuntimeWarning) + return False + return (int(m.group("major")) == required_major and + int(m.group("minor")) >= minimum_minor) + + +def have_compatible_glibc(required_major, minimum_minor): + version_str = glibc_version_string() + if version_str is None: + return False + return check_glibc_version(version_str, required_major, minimum_minor) + + +# platform.libc_ver regularly returns completely nonsensical glibc +# versions. E.g. on my computer, platform says: +# +# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.7') +# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.9') +# +# But the truth is: +# +# ~$ ldd --version +# ldd (Debian GLIBC 2.22-11) 2.22 +# +# This is unfortunate, because it means that the linehaul data on libc +# versions that was generated by pip 8.1.2 and earlier is useless and +# misleading. Solution: instead of using platform, use our code that actually +# works. +def libc_ver(): + """Try to determine the glibc version + + Returns a tuple of strings (lib, version) which default to empty strings + in case the lookup fails. + """ + glibc_version = glibc_version_string() + if glibc_version is None: + return ("", "") + else: + return ("glibc", glibc_version) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py new file mode 100755 index 0000000..8cf6367 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/hashes.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import + +import hashlib + +from pip._vendor.six import iteritems, iterkeys, itervalues + +from pip._internal.exceptions import ( + HashMismatch, HashMissing, InstallationError, +) +from pip._internal.utils.misc import read_chunks + +# The recommended hash algo of the moment. Change this whenever the state of +# the art changes; it won't hurt backward compatibility. +FAVORITE_HASH = 'sha256' + + +# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` +# Currently, those are the ones at least as collision-resistant as sha256. +STRONG_HASHES = ['sha256', 'sha384', 'sha512'] + + +class Hashes(object): + """A wrapper that builds multiple hashes at once and checks them against + known-good values + + """ + def __init__(self, hashes=None): + """ + :param hashes: A dict of algorithm names pointing to lists of allowed + hex digests + """ + self._allowed = {} if hashes is None else hashes + + def check_against_chunks(self, chunks): + """Check good hashes against ones built from iterable of chunks of + data. + + Raise HashMismatch if none match. + + """ + gots = {} + for hash_name in iterkeys(self._allowed): + try: + gots[hash_name] = hashlib.new(hash_name) + except (ValueError, TypeError): + raise InstallationError('Unknown hash name: %s' % hash_name) + + for chunk in chunks: + for hash in itervalues(gots): + hash.update(chunk) + + for hash_name, got in iteritems(gots): + if got.hexdigest() in self._allowed[hash_name]: + return + self._raise(gots) + + def _raise(self, gots): + raise HashMismatch(self._allowed, gots) + + def check_against_file(self, file): + """Check good hashes against a file-like object + + Raise HashMismatch if none match. + + """ + return self.check_against_chunks(read_chunks(file)) + + def check_against_path(self, path): + with open(path, 'rb') as file: + return self.check_against_file(file) + + def __nonzero__(self): + """Return whether I know any known-good hashes.""" + return bool(self._allowed) + + def __bool__(self): + return self.__nonzero__() + + +class MissingHashes(Hashes): + """A workalike for Hashes used when we're missing a hash for a requirement + + It computes the actual hash of the requirement and raises a HashMissing + exception showing it to the user. + + """ + def __init__(self): + """Don't offer the ``hashes`` kwarg.""" + # Pass our favorite hash in to generate a "gotten hash". With the + # empty list, it will never match, so an error will always raise. + super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []}) + + def _raise(self, gots): + raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py new file mode 100755 index 0000000..1fb3e8a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/logging.py @@ -0,0 +1,132 @@ +from __future__ import absolute_import + +import contextlib +import logging +import logging.handlers +import os + +from pip._internal.compat import WINDOWS +from pip._internal.utils.misc import ensure_dir + +try: + import threading +except ImportError: + import dummy_threading as threading # type: ignore + + +try: + from pip._vendor import colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None + + +_log_state = threading.local() +_log_state.indentation = 0 + + +@contextlib.contextmanager +def indent_log(num=2): + """ + A context manager which will cause the log output to be indented for any + log messages emitted inside it. + """ + _log_state.indentation += num + try: + yield + finally: + _log_state.indentation -= num + + +def get_indentation(): + return getattr(_log_state, 'indentation', 0) + + +class IndentingFormatter(logging.Formatter): + + def format(self, record): + """ + Calls the standard formatter, but will indent all of the log messages + by our current indentation level. + """ + formatted = logging.Formatter.format(self, record) + formatted = "".join([ + (" " * get_indentation()) + line + for line in formatted.splitlines(True) + ]) + return formatted + + +def _color_wrap(*colors): + def wrapped(inp): + return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) + return wrapped + + +class ColorizedStreamHandler(logging.StreamHandler): + + # Don't build up a list of colors if we don't have colorama + if colorama: + COLORS = [ + # This needs to be in order from highest logging level to lowest. + (logging.ERROR, _color_wrap(colorama.Fore.RED)), + (logging.WARNING, _color_wrap(colorama.Fore.YELLOW)), + ] + else: + COLORS = [] + + def __init__(self, stream=None, no_color=None): + logging.StreamHandler.__init__(self, stream) + self._no_color = no_color + + if WINDOWS and colorama: + self.stream = colorama.AnsiToWin32(self.stream) + + def should_color(self): + # Don't colorize things if we do not have colorama or if told not to + if not colorama or self._no_color: + return False + + real_stream = ( + self.stream if not isinstance(self.stream, colorama.AnsiToWin32) + else self.stream.wrapped + ) + + # If the stream is a tty we should color it + if hasattr(real_stream, "isatty") and real_stream.isatty(): + return True + + # If we have an ASNI term we should color it + if os.environ.get("TERM") == "ANSI": + return True + + # If anything else we should not color it + return False + + def format(self, record): + msg = logging.StreamHandler.format(self, record) + + if self.should_color(): + for level, color in self.COLORS: + if record.levelno >= level: + msg = color(msg) + break + + return msg + + +class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): + + def _open(self): + ensure_dir(os.path.dirname(self.baseFilename)) + return logging.handlers.RotatingFileHandler._open(self) + + +class MaxLevelFilter(logging.Filter): + + def __init__(self, level): + self.level = level + + def filter(self, record): + return record.levelno < self.level diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py new file mode 100755 index 0000000..db84a7c --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/misc.py @@ -0,0 +1,851 @@ +from __future__ import absolute_import + +import contextlib +import errno +import io +import locale +# we have a submodule named 'logging' which would shadow this if we used the +# regular name: +import logging as std_logging +import os +import posixpath +import re +import shutil +import stat +import subprocess +import sys +import tarfile +import zipfile +from collections import deque + +from pip._vendor import pkg_resources +# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import. +from pip._vendor.retrying import retry # type: ignore +from pip._vendor.six import PY2 +from pip._vendor.six.moves import input + +from pip._internal.compat import console_to_str, expanduser, stdlib_pkgs +from pip._internal.exceptions import InstallationError +from pip._internal.locations import ( + running_under_virtualenv, site_packages, user_site, virtualenv_no_global, + write_delete_marker_file, +) + +if PY2: + from io import BytesIO as StringIO +else: + from io import StringIO + +__all__ = ['rmtree', 'display_path', 'backup_dir', + 'ask', 'splitext', + 'format_size', 'is_installable_dir', + 'is_svn_page', 'file_contents', + 'split_leading_dir', 'has_leading_dir', + 'normalize_path', + 'renames', 'get_prog', + 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess', + 'captured_stdout', 'ensure_dir', + 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS', + 'get_installed_version'] + + +logger = std_logging.getLogger(__name__) + +BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') +XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', '.tar.lz', '.tar.lzma') +ZIP_EXTENSIONS = ('.zip', '.whl') +TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') +ARCHIVE_EXTENSIONS = ( + ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS) +SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS +try: + import bz2 # noqa + SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS +except ImportError: + logger.debug('bz2 module is not available') + +try: + # Only for Python 3.3+ + import lzma # noqa + SUPPORTED_EXTENSIONS += XZ_EXTENSIONS +except ImportError: + logger.debug('lzma module is not available') + + +def import_or_raise(pkg_or_module_string, ExceptionType, *args, **kwargs): + try: + return __import__(pkg_or_module_string) + except ImportError: + raise ExceptionType(*args, **kwargs) + + +def ensure_dir(path): + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + +def get_prog(): + try: + prog = os.path.basename(sys.argv[0]) + if prog in ('__main__.py', '-c'): + return "%s -m pip" % sys.executable + else: + return prog + except (AttributeError, TypeError, IndexError): + pass + return 'pip' + + +# Retry every half second for up to 3 seconds +@retry(stop_max_delay=3000, wait_fixed=500) +def rmtree(dir, ignore_errors=False): + shutil.rmtree(dir, ignore_errors=ignore_errors, + onerror=rmtree_errorhandler) + + +def rmtree_errorhandler(func, path, exc_info): + """On Windows, the files in .svn are read-only, so when rmtree() tries to + remove them, an exception is thrown. We catch that here, remove the + read-only attribute, and hopefully continue without problems.""" + # if file type currently read only + if os.stat(path).st_mode & stat.S_IREAD: + # convert to read/write + os.chmod(path, stat.S_IWRITE) + # use the original function to repeat the operation + func(path) + return + else: + raise + + +def display_path(path): + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if sys.version_info[0] == 2: + path = path.decode(sys.getfilesystemencoding(), 'replace') + path = path.encode(sys.getdefaultencoding(), 'replace') + if path.startswith(os.getcwd() + os.path.sep): + path = '.' + path[len(os.getcwd()):] + return path + + +def backup_dir(dir, ext='.bak'): + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def ask_path_exists(message, options): + for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): + if action in options: + return action + return ask(message, options) + + +def ask(message, options): + """Ask the message interactively, with the given possible responses""" + while 1: + if os.environ.get('PIP_NO_INPUT'): + raise Exception( + 'No input was expected ($PIP_NO_INPUT set); question: %s' % + message + ) + response = input(message) + response = response.strip().lower() + if response not in options: + print( + 'Your response (%r) was not one of the expected responses: ' + '%s' % (response, ', '.join(options)) + ) + else: + return response + + +def format_size(bytes): + if bytes > 1000 * 1000: + return '%.1fMB' % (bytes / 1000.0 / 1000) + elif bytes > 10 * 1000: + return '%ikB' % (bytes / 1000) + elif bytes > 1000: + return '%.1fkB' % (bytes / 1000.0) + else: + return '%ibytes' % bytes + + +def is_installable_dir(path): + """Return True if `path` is a directory containing a setup.py file.""" + if not os.path.isdir(path): + return False + setup_py = os.path.join(path, 'setup.py') + if os.path.isfile(setup_py): + return True + return False + + +def is_svn_page(html): + """ + Returns true if the page appears to be the index page of an svn repository + """ + return (re.search(r'<title>[^<]*Revision \d+:', html) and + re.search(r'Powered by (?:<a[^>]*?>)?Subversion', html, re.I)) + + +def file_contents(filename): + with open(filename, 'rb') as fp: + return fp.read().decode('utf-8') + + +def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): + """Yield pieces of data from a file-like object until EOF.""" + while True: + chunk = file.read(size) + if not chunk: + break + yield chunk + + +def split_leading_dir(path): + path = path.lstrip('/').lstrip('\\') + if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or + '\\' not in path): + return path.split('/', 1) + elif '\\' in path: + return path.split('\\', 1) + else: + return path, '' + + +def has_leading_dir(paths): + """Returns true if all the paths have the same leading path name + (i.e., everything is in one subdirectory in an archive)""" + common_prefix = None + for path in paths: + prefix, rest = split_leading_dir(path) + if not prefix: + return False + elif common_prefix is None: + common_prefix = prefix + elif prefix != common_prefix: + return False + return True + + +def normalize_path(path, resolve_symlinks=True): + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + path = expanduser(path) + if resolve_symlinks: + path = os.path.realpath(path) + else: + path = os.path.abspath(path) + return os.path.normcase(path) + + +def splitext(path): + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith('.tar'): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old, new): + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path): + """ + Return True if path is within sys.prefix, if we're running in a virtualenv. + + If we're not in a virtualenv, all paths are considered "local." + + """ + if not running_under_virtualenv(): + return True + return normalize_path(path).startswith(normalize_path(sys.prefix)) + + +def dist_is_local(dist): + """ + Return True if given Distribution object is installed locally + (i.e. within current virtualenv). + + Always True if we're not in a virtualenv. + + """ + return is_local(dist_location(dist)) + + +def dist_in_usersite(dist): + """ + Return True if given Distribution is installed in user site. + """ + norm_path = normalize_path(dist_location(dist)) + return norm_path.startswith(normalize_path(user_site)) + + +def dist_in_site_packages(dist): + """ + Return True if given Distribution is installed in + sysconfig.get_python_lib(). + """ + return normalize_path( + dist_location(dist) + ).startswith(normalize_path(site_packages)) + + +def dist_is_editable(dist): + """Is distribution an editable install?""" + for path_item in sys.path: + egg_link = os.path.join(path_item, dist.project_name + '.egg-link') + if os.path.isfile(egg_link): + return True + return False + + +def get_installed_distributions(local_only=True, + skip=stdlib_pkgs, + include_editables=True, + editables_only=False, + user_only=False): + """ + Return a list of installed Distribution objects. + + If ``local_only`` is True (default), only return installations + local to the current virtualenv, if in a virtualenv. + + ``skip`` argument is an iterable of lower-case project names to + ignore; defaults to stdlib_pkgs + + If ``include_editables`` is False, don't report editables. + + If ``editables_only`` is True , only report editables. + + If ``user_only`` is True , only report installations in the user + site directory. + + """ + if local_only: + local_test = dist_is_local + else: + def local_test(d): + return True + + if include_editables: + def editable_test(d): + return True + else: + def editable_test(d): + return not dist_is_editable(d) + + if editables_only: + def editables_only_test(d): + return dist_is_editable(d) + else: + def editables_only_test(d): + return True + + if user_only: + user_test = dist_in_usersite + else: + def user_test(d): + return True + + return [d for d in pkg_resources.working_set + if local_test(d) and + d.key not in skip and + editable_test(d) and + editables_only_test(d) and + user_test(d) + ] + + +def egg_link_path(dist): + """ + Return the path for the .egg-link file if it exists, otherwise, None. + + There's 3 scenarios: + 1) not in a virtualenv + try to find in site.USER_SITE, then site_packages + 2) in a no-global virtualenv + try to find in site_packages + 3) in a yes-global virtualenv + try to find in site_packages, then site.USER_SITE + (don't look in global location) + + For #1 and #3, there could be odd cases, where there's an egg-link in 2 + locations. + + This method will just return the first one found. + """ + sites = [] + if running_under_virtualenv(): + if virtualenv_no_global(): + sites.append(site_packages) + else: + sites.append(site_packages) + if user_site: + sites.append(user_site) + else: + if user_site: + sites.append(user_site) + sites.append(site_packages) + + for site in sites: + egglink = os.path.join(site, dist.project_name) + '.egg-link' + if os.path.isfile(egglink): + return egglink + + +def dist_location(dist): + """ + Get the site-packages location of this distribution. Generally + this is dist.location, except in the case of develop-installed + packages, where dist.location is the source code location, and we + want to know where the egg-link file is. + + """ + egg_link = egg_link_path(dist) + if egg_link: + return egg_link + return dist.location + + +def current_umask(): + """Get the current umask which involves having to set it temporarily.""" + mask = os.umask(0) + os.umask(mask) + return mask + + +def unzip_file(filename, location, flatten=True): + """ + Unzip the file (with path `filename`) to the destination `location`. All + files are written based on system defaults and umask (i.e. permissions are + not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + zipfp = open(filename, 'rb') + try: + zip = zipfile.ZipFile(zipfp, allowZip64=True) + leading = has_leading_dir(zip.namelist()) and flatten + for info in zip.infolist(): + name = info.filename + data = zip.read(name) + fn = name + if leading: + fn = split_leading_dir(name)[1] + fn = os.path.join(location, fn) + dir = os.path.dirname(fn) + if fn.endswith('/') or fn.endswith('\\'): + # A directory + ensure_dir(fn) + else: + ensure_dir(dir) + fp = open(fn, 'wb') + try: + fp.write(data) + finally: + fp.close() + mode = info.external_attr >> 16 + # if mode and regular file and any execute permissions for + # user/group/world? + if mode and stat.S_ISREG(mode) and mode & 0o111: + # make dest file have execute for user/group/world + # (chmod +x) no-op on windows per python docs + os.chmod(fn, (0o777 - current_umask() | 0o111)) + finally: + zipfp.close() + + +def untar_file(filename, location): + """ + Untar the file (with path `filename`) to the destination `location`. + All files are written based on system defaults and umask (i.e. permissions + are not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): + mode = 'r:gz' + elif filename.lower().endswith(BZ2_EXTENSIONS): + mode = 'r:bz2' + elif filename.lower().endswith(XZ_EXTENSIONS): + mode = 'r:xz' + elif filename.lower().endswith('.tar'): + mode = 'r' + else: + logger.warning( + 'Cannot determine compression type for file %s', filename, + ) + mode = 'r:*' + tar = tarfile.open(filename, mode) + try: + # note: python<=2.5 doesn't seem to know about pax headers, filter them + leading = has_leading_dir([ + member.name for member in tar.getmembers() + if member.name != 'pax_global_header' + ]) + for member in tar.getmembers(): + fn = member.name + if fn == 'pax_global_header': + continue + if leading: + fn = split_leading_dir(fn)[1] + path = os.path.join(location, fn) + if member.isdir(): + ensure_dir(path) + elif member.issym(): + try: + tar._extract_member(member, path) + except Exception as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + else: + try: + fp = tar.extractfile(member) + except (KeyError, AttributeError) as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + ensure_dir(os.path.dirname(path)) + with open(path, 'wb') as destfp: + shutil.copyfileobj(fp, destfp) + fp.close() + # Update the timestamp (useful for cython compiled files) + tar.utime(member, path) + # member have any execute permissions for user/group/world? + if member.mode & 0o111: + # make dest file have execute for user/group/world + # no-op on windows per python docs + os.chmod(path, (0o777 - current_umask() | 0o111)) + finally: + tar.close() + + +def unpack_file(filename, location, content_type, link): + filename = os.path.realpath(filename) + if (content_type == 'application/zip' or + filename.lower().endswith(ZIP_EXTENSIONS) or + zipfile.is_zipfile(filename)): + unzip_file( + filename, + location, + flatten=not filename.endswith('.whl') + ) + elif (content_type == 'application/x-gzip' or + tarfile.is_tarfile(filename) or + filename.lower().endswith( + TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)): + untar_file(filename, location) + elif (content_type and content_type.startswith('text/html') and + is_svn_page(file_contents(filename))): + # We don't really care about this + from pip._internal.vcs.subversion import Subversion + Subversion('svn+' + link.url).unpack(location) + else: + # FIXME: handle? + # FIXME: magic signatures? + logger.critical( + 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' + 'cannot detect archive format', + filename, location, content_type, + ) + raise InstallationError( + 'Cannot determine archive format of %s' % location + ) + + +def call_subprocess(cmd, show_stdout=True, cwd=None, + on_returncode='raise', + command_desc=None, + extra_environ=None, unset_environ=None, spinner=None): + """ + Args: + unset_environ: an iterable of environment variable names to unset + prior to calling subprocess.Popen(). + """ + if unset_environ is None: + unset_environ = [] + # This function's handling of subprocess output is confusing and I + # previously broke it terribly, so as penance I will write a long comment + # explaining things. + # + # The obvious thing that affects output is the show_stdout= + # kwarg. show_stdout=True means, let the subprocess write directly to our + # stdout. Even though it is nominally the default, it is almost never used + # inside pip (and should not be used in new code without a very good + # reason); as of 2016-02-22 it is only used in a few places inside the VCS + # wrapper code. Ideally we should get rid of it entirely, because it + # creates a lot of complexity here for a rarely used feature. + # + # Most places in pip set show_stdout=False. What this means is: + # - We connect the child stdout to a pipe, which we read. + # - By default, we hide the output but show a spinner -- unless the + # subprocess exits with an error, in which case we show the output. + # - If the --verbose option was passed (= loglevel is DEBUG), then we show + # the output unconditionally. (But in this case we don't want to show + # the output a second time if it turns out that there was an error.) + # + # stderr is always merged with stdout (even if show_stdout=True). + if show_stdout: + stdout = None + else: + stdout = subprocess.PIPE + if command_desc is None: + cmd_parts = [] + for part in cmd: + if ' ' in part or '\n' in part or '"' in part or "'" in part: + part = '"%s"' % part.replace('"', '\\"') + cmd_parts.append(part) + command_desc = ' '.join(cmd_parts) + logger.debug("Running command %s", command_desc) + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + for name in unset_environ: + env.pop(name, None) + try: + proc = subprocess.Popen( + cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, + stdout=stdout, cwd=cwd, env=env, + ) + proc.stdin.close() + except Exception as exc: + logger.critical( + "Error %s while executing command %s", exc, command_desc, + ) + raise + all_output = [] + if stdout is not None: + while True: + line = console_to_str(proc.stdout.readline()) + if not line: + break + line = line.rstrip() + all_output.append(line + '\n') + if logger.getEffectiveLevel() <= std_logging.DEBUG: + # Show the line immediately + logger.debug(line) + else: + # Update the spinner + if spinner is not None: + spinner.spin() + try: + proc.wait() + finally: + if proc.stdout: + proc.stdout.close() + if spinner is not None: + if proc.returncode: + spinner.finish("error") + else: + spinner.finish("done") + if proc.returncode: + if on_returncode == 'raise': + if (logger.getEffectiveLevel() > std_logging.DEBUG and + not show_stdout): + logger.info( + 'Complete output from command %s:', command_desc, + ) + logger.info( + ''.join(all_output) + + '\n----------------------------------------' + ) + raise InstallationError( + 'Command "%s" failed with error code %s in %s' + % (command_desc, proc.returncode, cwd)) + elif on_returncode == 'warn': + logger.warning( + 'Command "%s" had error code %s in %s', + command_desc, proc.returncode, cwd, + ) + elif on_returncode == 'ignore': + pass + else: + raise ValueError('Invalid value: on_returncode=%s' % + repr(on_returncode)) + if not show_stdout: + return ''.join(all_output) + + +def read_text_file(filename): + """Return the contents of *filename*. + + Try to decode the file contents with utf-8, the preferred system encoding + (e.g., cp1252 on some Windows machines), and latin1, in that order. + Decoding a byte string with latin1 will never raise an error. In the worst + case, the returned string will contain some garbage characters. + + """ + with open(filename, 'rb') as fp: + data = fp.read() + + encodings = ['utf-8', locale.getpreferredencoding(False), 'latin1'] + for enc in encodings: + try: + data = data.decode(enc) + except UnicodeDecodeError: + continue + break + + assert type(data) != bytes # Latin1 should have worked. + return data + + +def _make_build_dir(build_dir): + os.makedirs(build_dir) + write_delete_marker_file(build_dir) + + +class FakeFile(object): + """Wrap a list of lines in an object with readline() to make + ConfigParser happy.""" + def __init__(self, lines): + self._gen = (l for l in lines) + + def readline(self): + try: + try: + return next(self._gen) + except NameError: + return self._gen.next() + except StopIteration: + return '' + + def __iter__(self): + return self._gen + + +class StreamWrapper(StringIO): + + @classmethod + def from_stream(cls, orig_stream): + cls.orig_stream = orig_stream + return cls() + + # compileall.compile_dir() needs stdout.encoding to print to stdout + @property + def encoding(self): + return self.orig_stream.encoding + + +@contextlib.contextmanager +def captured_output(stream_name): + """Return a context manager used by captured_stdout/stdin/stderr + that temporarily replaces the sys stream *stream_name* with a StringIO. + + Taken from Lib/support/__init__.py in the CPython repo. + """ + orig_stdout = getattr(sys, stream_name) + setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) + try: + yield getattr(sys, stream_name) + finally: + setattr(sys, stream_name, orig_stdout) + + +def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as stdout: + print('hello') + self.assertEqual(stdout.getvalue(), 'hello\n') + + Taken from Lib/support/__init__.py in the CPython repo. + """ + return captured_output('stdout') + + +class cached_property(object): + """A property that is only computed once per instance and then replaces + itself with an ordinary attribute. Deleting the attribute resets the + property. + + Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175 + """ + + def __init__(self, func): + self.__doc__ = getattr(func, '__doc__') + self.func = func + + def __get__(self, obj, cls): + if obj is None: + # We're being accessed from the class itself, not from an object + return self + value = obj.__dict__[self.func.__name__] = self.func(obj) + return value + + +def get_installed_version(dist_name, lookup_dirs=None): + """Get the installed version of dist_name avoiding pkg_resources cache""" + # Create a requirement that we'll look for inside of setuptools. + req = pkg_resources.Requirement.parse(dist_name) + + # We want to avoid having this cached, so we need to construct a new + # working set each time. + if lookup_dirs is None: + working_set = pkg_resources.WorkingSet() + else: + working_set = pkg_resources.WorkingSet(lookup_dirs) + + # Get the installed distribution from our working set + dist = working_set.find(req) + + # Check to see if we got an installed distribution or not, if we did + # we want to return it's version. + return dist.version if dist else None + + +def consume(iterator): + """Consume an iterable at C speed.""" + deque(iterator, maxlen=0) + + +# Simulates an enum +def enum(*sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = {value: key for key, value in enums.items()} + enums['reverse_mapping'] = reverse + return type('Enum', (), enums) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py new file mode 100755 index 0000000..f4572ab --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/outdated.py @@ -0,0 +1,163 @@ +from __future__ import absolute_import + +import datetime +import json +import logging +import os.path +import sys + +from pip._vendor import lockfile +from pip._vendor.packaging import version as packaging_version + +from pip._internal.compat import WINDOWS +from pip._internal.index import PackageFinder +from pip._internal.locations import USER_CACHE_DIR, running_under_virtualenv +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.misc import ensure_dir, get_installed_version + +SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" + + +logger = logging.getLogger(__name__) + + +class VirtualenvSelfCheckState(object): + def __init__(self): + self.statefile_path = os.path.join(sys.prefix, "pip-selfcheck.json") + + # Load the existing state + try: + with open(self.statefile_path) as statefile: + self.state = json.load(statefile) + except (IOError, ValueError): + self.state = {} + + def save(self, pypi_version, current_time): + # Attempt to write out our version check file + with open(self.statefile_path, "w") as statefile: + json.dump( + { + "last_check": current_time.strftime(SELFCHECK_DATE_FMT), + "pypi_version": pypi_version, + }, + statefile, + sort_keys=True, + separators=(",", ":") + ) + + +class GlobalSelfCheckState(object): + def __init__(self): + self.statefile_path = os.path.join(USER_CACHE_DIR, "selfcheck.json") + + # Load the existing state + try: + with open(self.statefile_path) as statefile: + self.state = json.load(statefile)[sys.prefix] + except (IOError, ValueError, KeyError): + self.state = {} + + def save(self, pypi_version, current_time): + # Check to make sure that we own the directory + if not check_path_owner(os.path.dirname(self.statefile_path)): + return + + # Now that we've ensured the directory is owned by this user, we'll go + # ahead and make sure that all our directories are created. + ensure_dir(os.path.dirname(self.statefile_path)) + + # Attempt to write out our version check file + with lockfile.LockFile(self.statefile_path): + if os.path.exists(self.statefile_path): + with open(self.statefile_path) as statefile: + state = json.load(statefile) + else: + state = {} + + state[sys.prefix] = { + "last_check": current_time.strftime(SELFCHECK_DATE_FMT), + "pypi_version": pypi_version, + } + + with open(self.statefile_path, "w") as statefile: + json.dump(state, statefile, sort_keys=True, + separators=(",", ":")) + + +def load_selfcheck_statefile(): + if running_under_virtualenv(): + return VirtualenvSelfCheckState() + else: + return GlobalSelfCheckState() + + +def pip_version_check(session, options): + """Check for an update for pip. + + Limit the frequency of checks to once per week. State is stored either in + the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix + of the pip script path. + """ + installed_version = get_installed_version("pip") + if not installed_version: + return + + pip_version = packaging_version.parse(installed_version) + pypi_version = None + + try: + state = load_selfcheck_statefile() + + current_time = datetime.datetime.utcnow() + # Determine if we need to refresh the state + if "last_check" in state.state and "pypi_version" in state.state: + last_check = datetime.datetime.strptime( + state.state["last_check"], + SELFCHECK_DATE_FMT + ) + if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: + pypi_version = state.state["pypi_version"] + + # Refresh the version if we need to or just see if we need to warn + if pypi_version is None: + # Lets use PackageFinder to see what the latest pip version is + finder = PackageFinder( + find_links=options.find_links, + index_urls=[options.index_url] + options.extra_index_urls, + allow_all_prereleases=False, # Explicitly set to False + trusted_hosts=options.trusted_hosts, + process_dependency_links=options.process_dependency_links, + session=session, + ) + all_candidates = finder.find_all_candidates("pip") + if not all_candidates: + return + pypi_version = str( + max(all_candidates, key=lambda c: c.version).version + ) + + # save that we've performed a check + state.save(pypi_version, current_time) + + remote_version = packaging_version.parse(pypi_version) + + # Determine if our pypi_version is older + if (pip_version < remote_version and + pip_version.base_version != remote_version.base_version): + # Advise "python -m pip" on Windows to avoid issues + # with overwriting pip.exe. + if WINDOWS: + pip_cmd = "python -m pip" + else: + pip_cmd = "pip" + logger.warning( + "You are using pip version %s, however version %s is " + "available.\nYou should consider upgrading via the " + "'%s install --upgrade pip' command.", + pip_version, pypi_version, pip_cmd + ) + except Exception: + logger.debug( + "There was an error checking the latest version of pip", + exc_info=True, + ) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py new file mode 100755 index 0000000..d523953 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/packaging.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import + +import logging +import sys +from email.parser import FeedParser # type: ignore + +from pip._vendor import pkg_resources +from pip._vendor.packaging import specifiers, version + +from pip._internal import exceptions + +logger = logging.getLogger(__name__) + + +def check_requires_python(requires_python): + """ + Check if the python version in use match the `requires_python` specifier. + + Returns `True` if the version of python in use matches the requirement. + Returns `False` if the version of python in use does not matches the + requirement. + + Raises an InvalidSpecifier if `requires_python` have an invalid format. + """ + if requires_python is None: + # The package provides no information + return True + requires_python_specifier = specifiers.SpecifierSet(requires_python) + + # We only use major.minor.micro + python_version = version.parse('.'.join(map(str, sys.version_info[:3]))) + return python_version in requires_python_specifier + + +def get_metadata(dist): + if (isinstance(dist, pkg_resources.DistInfoDistribution) and + dist.has_metadata('METADATA')): + return dist.get_metadata('METADATA') + elif dist.has_metadata('PKG-INFO'): + return dist.get_metadata('PKG-INFO') + + +def check_dist_requires_python(dist): + metadata = get_metadata(dist) + feed_parser = FeedParser() + feed_parser.feed(metadata) + pkg_info_dict = feed_parser.close() + requires_python = pkg_info_dict.get('Requires-Python') + try: + if not check_requires_python(requires_python): + raise exceptions.UnsupportedPythonVersion( + "%s requires Python '%s' but the running Python is %s" % ( + dist.project_name, + requires_python, + '.'.join(map(str, sys.version_info[:3])),) + ) + except specifiers.InvalidSpecifier as e: + logger.warning( + "Package %s has an invalid Requires-Python entry %s - %s", + dist.project_name, requires_python, e, + ) + return + + +def get_installer(dist): + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + return line.strip() + return '' diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py new file mode 100755 index 0000000..9d32174 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/setuptools_build.py @@ -0,0 +1,8 @@ +# Shim to wrap setup.py invocation with setuptools +SETUPTOOLS_SHIM = ( + "import setuptools, tokenize;__file__=%r;" + "f=getattr(tokenize, 'open', open)(__file__);" + "code=f.read().replace('\\r\\n', '\\n');" + "f.close();" + "exec(compile(code, __file__, 'exec'))" +) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py new file mode 100755 index 0000000..25bc0d9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/temp_dir.py @@ -0,0 +1,82 @@ +from __future__ import absolute_import + +import logging +import os.path +import tempfile + +from pip._internal.utils.misc import rmtree + +logger = logging.getLogger(__name__) + + +class TempDirectory(object): + """Helper class that owns and cleans up a temporary directory. + + This class can be used as a context manager or as an OO representation of a + temporary directory. + + Attributes: + path + Location to the created temporary directory or None + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + Methods: + create() + Creates a temporary directory and stores its path in the path + attribute. + cleanup() + Deletes the temporary directory and sets path attribute to None + + When used as a context manager, a temporary directory is created on + entering the context and, if the delete attribute is True, on exiting the + context the created directory is deleted. + """ + + def __init__(self, path=None, delete=None, kind="temp"): + super(TempDirectory, self).__init__() + + if path is None and delete is None: + # If we were not given an explicit directory, and we were not given + # an explicit delete option, then we'll default to deleting. + delete = True + + self.path = path + self.delete = delete + self.kind = kind + + def __repr__(self): + return "<{} {!r}>".format(self.__class__.__name__, self.path) + + def __enter__(self): + self.create() + return self + + def __exit__(self, exc, value, tb): + if self.delete: + self.cleanup() + + def create(self): + """Create a temporary directory and store it's path in self.path + """ + if self.path is not None: + logger.debug( + "Skipped creation of temporary directory: {}".format(self.path) + ) + return + # We realpath here because some systems have their default tmpdir + # symlinked to another directory. This tends to confuse build + # scripts, so we canonicalize the path by traversing potential + # symlinks here. + self.path = os.path.realpath( + tempfile.mkdtemp(prefix="pip-{}-".format(self.kind)) + ) + logger.debug("Created temporary directory: {}".format(self.path)) + + def cleanup(self): + """Remove the temporary directory created and reset state + """ + if self.path is not None and os.path.exists(self.path): + rmtree(self.path) + self.path = None diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py new file mode 100755 index 0000000..4e25ae6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/typing.py @@ -0,0 +1,29 @@ +"""For neatly implementing static typing in pip. + +`mypy` - the static type analysis tool we use - uses the `typing` module, which +provides core functionality fundamental to mypy's functioning. + +Generally, `typing` would be imported at runtime and used in that fashion - +it acts as a no-op at runtime and does not have any run-time overhead by +design. + +As it turns out, `typing` is not vendorable - it uses separate sources for +Python 2/Python 3. Thus, this codebase can not expect it to be present. +To work around this, mypy allows the typing import to be behind a False-y +optional to prevent it from running at runtime and type-comments can be used +to remove the need for the types to be accessible directly during runtime. + +This module provides the False-y guard in a nicely named fashion so that a +curious maintainer can reach here to read this. + +In pip, all static-typing related imports should be guarded as follows: + + from pip.utils.typing import MYPY_CHECK_RUNNING + + if MYPY_CHECK_RUNNING: + from typing import ... + +Ref: https://github.com/python/mypy/issues/3216 +""" + +MYPY_CHECK_RUNNING = False diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py new file mode 100755 index 0000000..d97ea36 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/utils/ui.py @@ -0,0 +1,421 @@ +from __future__ import absolute_import, division + +import contextlib +import itertools +import logging +import sys +import time +from signal import SIGINT, default_int_handler, signal + +from pip._vendor import six +from pip._vendor.progress.bar import ( + Bar, ChargingBar, FillingCirclesBar, FillingSquaresBar, IncrementalBar, + ShadyBar, +) +from pip._vendor.progress.helpers import HIDE_CURSOR, SHOW_CURSOR, WritelnMixin +from pip._vendor.progress.spinner import Spinner + +from pip._internal.compat import WINDOWS +from pip._internal.utils.logging import get_indentation +from pip._internal.utils.misc import format_size +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any + +try: + from pip._vendor import colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None + +logger = logging.getLogger(__name__) + + +def _select_progress_class(preferred, fallback): + encoding = getattr(preferred.file, "encoding", None) + + # If we don't know what encoding this file is in, then we'll just assume + # that it doesn't support unicode and use the ASCII bar. + if not encoding: + return fallback + + # Collect all of the possible characters we want to use with the preferred + # bar. + characters = [ + getattr(preferred, "empty_fill", six.text_type()), + getattr(preferred, "fill", six.text_type()), + ] + characters += list(getattr(preferred, "phases", [])) + + # Try to decode the characters we're using for the bar using the encoding + # of the given file, if this works then we'll assume that we can use the + # fancier bar and if not we'll fall back to the plaintext bar. + try: + six.text_type().join(characters).encode(encoding) + except UnicodeEncodeError: + return fallback + else: + return preferred + + +_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any + + +class InterruptibleMixin(object): + """ + Helper to ensure that self.finish() gets called on keyboard interrupt. + + This allows downloads to be interrupted without leaving temporary state + (like hidden cursors) behind. + + This class is similar to the progress library's existing SigIntMixin + helper, but as of version 1.2, that helper has the following problems: + + 1. It calls sys.exit(). + 2. It discards the existing SIGINT handler completely. + 3. It leaves its own handler in place even after an uninterrupted finish, + which will have unexpected delayed effects if the user triggers an + unrelated keyboard interrupt some time after a progress-displaying + download has already completed, for example. + """ + + def __init__(self, *args, **kwargs): + """ + Save the original SIGINT handler for later. + """ + super(InterruptibleMixin, self).__init__(*args, **kwargs) + + self.original_handler = signal(SIGINT, self.handle_sigint) + + # If signal() returns None, the previous handler was not installed from + # Python, and we cannot restore it. This probably should not happen, + # but if it does, we must restore something sensible instead, at least. + # The least bad option should be Python's default SIGINT handler, which + # just raises KeyboardInterrupt. + if self.original_handler is None: + self.original_handler = default_int_handler + + def finish(self): + """ + Restore the original SIGINT handler after finishing. + + This should happen regardless of whether the progress display finishes + normally, or gets interrupted. + """ + super(InterruptibleMixin, self).finish() + signal(SIGINT, self.original_handler) + + def handle_sigint(self, signum, frame): + """ + Call self.finish() before delegating to the original SIGINT handler. + + This handler should only be in place while the progress display is + active. + """ + self.finish() + self.original_handler(signum, frame) + + +class SilentBar(Bar): + + def update(self): + pass + + +class BlueEmojiBar(IncrementalBar): + + suffix = "%(percent)d%%" + bar_prefix = " " + bar_suffix = " " + phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any + + +class DownloadProgressMixin(object): + + def __init__(self, *args, **kwargs): + super(DownloadProgressMixin, self).__init__(*args, **kwargs) + self.message = (" " * (get_indentation() + 2)) + self.message + + @property + def downloaded(self): + return format_size(self.index) + + @property + def download_speed(self): + # Avoid zero division errors... + if self.avg == 0.0: + return "..." + return format_size(1 / self.avg) + "/s" + + @property + def pretty_eta(self): + if self.eta: + return "eta %s" % self.eta_td + return "" + + def iter(self, it, n=1): + for x in it: + yield x + self.next(n) + self.finish() + + +class WindowsMixin(object): + + def __init__(self, *args, **kwargs): + # The Windows terminal does not support the hide/show cursor ANSI codes + # even with colorama. So we'll ensure that hide_cursor is False on + # Windows. + # This call neds to go before the super() call, so that hide_cursor + # is set in time. The base progress bar class writes the "hide cursor" + # code to the terminal in its init, so if we don't set this soon + # enough, we get a "hide" with no corresponding "show"... + if WINDOWS and self.hide_cursor: + self.hide_cursor = False + + super(WindowsMixin, self).__init__(*args, **kwargs) + + # Check if we are running on Windows and we have the colorama module, + # if we do then wrap our file with it. + if WINDOWS and colorama: + self.file = colorama.AnsiToWin32(self.file) + # The progress code expects to be able to call self.file.isatty() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.isatty = lambda: self.file.wrapped.isatty() + # The progress code expects to be able to call self.file.flush() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.flush = lambda: self.file.wrapped.flush() + + +class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin): + + file = sys.stdout + message = "%(percent)d%%" + suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" + +# NOTE: The "type: ignore" comments on the following classes are there to +# work around https://github.com/python/typing/issues/241 + + +class DefaultDownloadProgressBar(BaseDownloadProgressBar, + _BaseBar): # type: ignore + pass + + +class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore + pass + + +class DownloadIncrementalBar(BaseDownloadProgressBar, # type: ignore + IncrementalBar): + pass + + +class DownloadChargingBar(BaseDownloadProgressBar, # type: ignore + ChargingBar): + pass + + +class DownloadShadyBar(BaseDownloadProgressBar, ShadyBar): # type: ignore + pass + + +class DownloadFillingSquaresBar(BaseDownloadProgressBar, # type: ignore + FillingSquaresBar): + pass + + +class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore + FillingCirclesBar): + pass + + +class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore + BlueEmojiBar): + pass + + +class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin, WritelnMixin, Spinner): + + file = sys.stdout + suffix = "%(downloaded)s %(download_speed)s" + + def next_phase(self): + if not hasattr(self, "_phaser"): + self._phaser = itertools.cycle(self.phases) + return next(self._phaser) + + def update(self): + message = self.message % self + phase = self.next_phase() + suffix = self.suffix % self + line = ''.join([ + message, + " " if message else "", + phase, + " " if suffix else "", + suffix, + ]) + + self.writeln(line) + + +BAR_TYPES = { + "off": (DownloadSilentBar, DownloadSilentBar), + "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), + "ascii": (DownloadIncrementalBar, DownloadProgressSpinner), + "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), + "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) +} + + +def DownloadProgressProvider(progress_bar, max=None): + if max is None or max == 0: + return BAR_TYPES[progress_bar][1]().iter + else: + return BAR_TYPES[progress_bar][0](max=max).iter + + +################################################################ +# Generic "something is happening" spinners +# +# We don't even try using progress.spinner.Spinner here because it's actually +# simpler to reimplement from scratch than to coerce their code into doing +# what we need. +################################################################ + +@contextlib.contextmanager +def hidden_cursor(file): + # The Windows terminal does not support the hide/show cursor ANSI codes, + # even via colorama. So don't even try. + if WINDOWS: + yield + # We don't want to clutter the output with control characters if we're + # writing to a file, or if the user is running with --quiet. + # See https://github.com/pypa/pip/issues/3418 + elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: + yield + else: + file.write(HIDE_CURSOR) + try: + yield + finally: + file.write(SHOW_CURSOR) + + +class RateLimiter(object): + def __init__(self, min_update_interval_seconds): + self._min_update_interval_seconds = min_update_interval_seconds + self._last_update = 0 + + def ready(self): + now = time.time() + delta = now - self._last_update + return delta >= self._min_update_interval_seconds + + def reset(self): + self._last_update = time.time() + + +class InteractiveSpinner(object): + def __init__(self, message, file=None, spin_chars="-\\|/", + # Empirically, 8 updates/second looks nice + min_update_interval_seconds=0.125): + self._message = message + if file is None: + file = sys.stdout + self._file = file + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._finished = False + + self._spin_cycle = itertools.cycle(spin_chars) + + self._file.write(" " * get_indentation() + self._message + " ... ") + self._width = 0 + + def _write(self, status): + assert not self._finished + # Erase what we wrote before by backspacing to the beginning, writing + # spaces to overwrite the old text, and then backspacing again + backup = "\b" * self._width + self._file.write(backup + " " * self._width + backup) + # Now we have a blank slate to add our status + self._file.write(status) + self._width = len(status) + self._file.flush() + self._rate_limiter.reset() + + def spin(self): + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._write(next(self._spin_cycle)) + + def finish(self, final_status): + if self._finished: + return + self._write(final_status) + self._file.write("\n") + self._file.flush() + self._finished = True + + +# Used for dumb terminals, non-interactive installs (no tty), etc. +# We still print updates occasionally (once every 60 seconds by default) to +# act as a keep-alive for systems like Travis-CI that take lack-of-output as +# an indication that a task has frozen. +class NonInteractiveSpinner(object): + def __init__(self, message, min_update_interval_seconds=60): + self._message = message + self._finished = False + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._update("started") + + def _update(self, status): + assert not self._finished + self._rate_limiter.reset() + logger.info("%s: %s", self._message, status) + + def spin(self): + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._update("still running...") + + def finish(self, final_status): + if self._finished: + return + self._update("finished with status '%s'" % (final_status,)) + self._finished = True + + +@contextlib.contextmanager +def open_spinner(message): + # Interactive spinner goes directly to sys.stdout rather than being routed + # through the logging system, but it acts like it has level INFO, + # i.e. it's only displayed if we're at level INFO or better. + # Non-interactive spinner goes through the logging system, so it is always + # in sync with logging configuration. + if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: + spinner = InteractiveSpinner(message) + else: + spinner = NonInteractiveSpinner(message) + try: + with hidden_cursor(sys.stdout): + yield spinner + except KeyboardInterrupt: + spinner.finish("canceled") + raise + except Exception: + spinner.finish("error") + raise + else: + spinner.finish("done") diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py new file mode 100755 index 0000000..bff94fa --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/__init__.py @@ -0,0 +1,471 @@ +"""Handles all VCS (version control) support""" +from __future__ import absolute_import + +import copy +import errno +import logging +import os +import shutil +import sys + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.exceptions import BadCommand +from pip._internal.utils.misc import ( + display_path, backup_dir, call_subprocess, rmtree, ask_path_exists, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Dict, Optional, Tuple + from pip._internal.basecommand import Command + +__all__ = ['vcs', 'get_src_requirement'] + + +logger = logging.getLogger(__name__) + + +class RevOptions(object): + + """ + Encapsulates a VCS-specific revision to install, along with any VCS + install options. + + Instances of this class should be treated as if immutable. + """ + + def __init__(self, vcs, rev=None, extra_args=None): + """ + Args: + vcs: a VersionControl object. + rev: the name of the revision to install. + extra_args: a list of extra options. + """ + if extra_args is None: + extra_args = [] + + self.extra_args = extra_args + self.rev = rev + self.vcs = vcs + + def __repr__(self): + return '<RevOptions {}: rev={!r}>'.format(self.vcs.name, self.rev) + + @property + def arg_rev(self): + if self.rev is None: + return self.vcs.default_arg_rev + + return self.rev + + def to_args(self): + """ + Return the VCS-specific command arguments. + """ + args = [] + rev = self.arg_rev + if rev is not None: + args += self.vcs.get_base_rev_args(rev) + args += self.extra_args + + return args + + def to_display(self): + if not self.rev: + return '' + + return ' (to revision {})'.format(self.rev) + + def make_new(self, rev): + """ + Make a copy of the current instance, but with a new rev. + + Args: + rev: the name of the revision for the new object. + """ + return self.vcs.make_rev_options(rev, extra_args=self.extra_args) + + +class VcsSupport(object): + _registry = {} # type: Dict[str, Command] + schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] + + def __init__(self): + # Register more schemes with urlparse for various version control + # systems + urllib_parse.uses_netloc.extend(self.schemes) + # Python >= 2.7.4, 3.3 doesn't have uses_fragment + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(self.schemes) + super(VcsSupport, self).__init__() + + def __iter__(self): + return self._registry.__iter__() + + @property + def backends(self): + return list(self._registry.values()) + + @property + def dirnames(self): + return [backend.dirname for backend in self.backends] + + @property + def all_schemes(self): + schemes = [] + for backend in self.backends: + schemes.extend(backend.schemes) + return schemes + + def register(self, cls): + if not hasattr(cls, 'name'): + logger.warning('Cannot register VCS %s', cls.__name__) + return + if cls.name not in self._registry: + self._registry[cls.name] = cls + logger.debug('Registered VCS backend: %s', cls.name) + + def unregister(self, cls=None, name=None): + if name in self._registry: + del self._registry[name] + elif cls in self._registry.values(): + del self._registry[cls.name] + else: + logger.warning('Cannot unregister because no class or name given') + + def get_backend_name(self, location): + """ + Return the name of the version control backend if found at given + location, e.g. vcs.get_backend_name('/path/to/vcs/checkout') + """ + for vc_type in self._registry.values(): + if vc_type.controls_location(location): + logger.debug('Determine that %s uses VCS: %s', + location, vc_type.name) + return vc_type.name + return None + + def get_backend(self, name): + name = name.lower() + if name in self._registry: + return self._registry[name] + + def get_backend_from_location(self, location): + vc_type = self.get_backend_name(location) + if vc_type: + return self.get_backend(vc_type) + return None + + +vcs = VcsSupport() + + +class VersionControl(object): + name = '' + dirname = '' + # List of supported schemes for this Version Control + schemes = () # type: Tuple[str, ...] + # Iterable of environment variable names to pass to call_subprocess(). + unset_environ = () # type: Tuple[str, ...] + default_arg_rev = None # type: Optional[str] + + def __init__(self, url=None, *args, **kwargs): + self.url = url + super(VersionControl, self).__init__(*args, **kwargs) + + def get_base_rev_args(self, rev): + """ + Return the base revision arguments for a vcs command. + + Args: + rev: the name of a revision to install. Cannot be None. + """ + raise NotImplementedError + + def make_rev_options(self, rev=None, extra_args=None): + """ + Return a RevOptions object. + + Args: + rev: the name of a revision to install. + extra_args: a list of extra options. + """ + return RevOptions(self, rev, extra_args=extra_args) + + def _is_local_repository(self, repo): + """ + posix absolute paths start with os.path.sep, + win32 ones start with drive (like c:\\folder) + """ + drive, tail = os.path.splitdrive(repo) + return repo.startswith(os.path.sep) or drive + + # See issue #1083 for why this method was introduced: + # https://github.com/pypa/pip/issues/1083 + def translate_egg_surname(self, surname): + # For example, Django has branches of the form "stable/1.7.x". + return surname.replace('/', '_') + + def export(self, location): + """ + Export the repository at the url to the destination location + i.e. only download the files, without vcs informations + """ + raise NotImplementedError + + def get_url_rev(self): + """ + Returns the correct repository URL and revision by parsing the given + repository URL + """ + error_message = ( + "Sorry, '%s' is a malformed VCS url. " + "The format is <vcs>+<protocol>://<url>, " + "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" + ) + assert '+' in self.url, error_message % self.url + url = self.url.split('+', 1)[1] + scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) + return url, rev + + def get_info(self, location): + """ + Returns (url, revision), where both are strings + """ + assert not location.rstrip('/').endswith(self.dirname), \ + 'Bad directory: %s' % location + return self.get_url(location), self.get_revision(location) + + def normalize_url(self, url): + """ + Normalize a URL for comparison by unquoting it and removing any + trailing slash. + """ + return urllib_parse.unquote(url).rstrip('/') + + def compare_urls(self, url1, url2): + """ + Compare two repo URLs for identity, ignoring incidental differences. + """ + return (self.normalize_url(url1) == self.normalize_url(url2)) + + def obtain(self, dest): + """ + Called when installing or updating an editable package, takes the + source path of the checkout. + """ + raise NotImplementedError + + def switch(self, dest, url, rev_options): + """ + Switch the repo at ``dest`` to point to ``URL``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def update(self, dest, rev_options): + """ + Update an already-existing repo to the given ``rev_options``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def is_commit_id_equal(self, dest, name): + """ + Return whether the id of the current commit equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + raise NotImplementedError + + def check_destination(self, dest, url, rev_options): + """ + Prepare a location to receive a checkout/clone. + + Return True if the location is ready for (and requires) a + checkout/clone, False otherwise. + + Args: + rev_options: a RevOptions object. + """ + checkout = True + prompt = False + rev_display = rev_options.to_display() + if os.path.exists(dest): + checkout = False + if os.path.exists(os.path.join(dest, self.dirname)): + existing_url = self.get_url(dest) + if self.compare_urls(existing_url, url): + logger.debug( + '%s in %s exists, and has correct URL (%s)', + self.repo_name.title(), + display_path(dest), + url, + ) + if not self.is_commit_id_equal(dest, rev_options.rev): + logger.info( + 'Updating %s %s%s', + display_path(dest), + self.repo_name, + rev_display, + ) + self.update(dest, rev_options) + else: + logger.info( + 'Skipping because already up-to-date.') + else: + logger.warning( + '%s %s in %s exists with URL %s', + self.name, + self.repo_name, + display_path(dest), + existing_url, + ) + prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', + ('s', 'i', 'w', 'b')) + else: + logger.warning( + 'Directory %s already exists, and is not a %s %s.', + dest, + self.name, + self.repo_name, + ) + prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b')) + if prompt: + logger.warning( + 'The plan is to install the %s repository %s', + self.name, + url, + ) + response = ask_path_exists('What to do? %s' % prompt[0], + prompt[1]) + + if response == 's': + logger.info( + 'Switching %s %s to %s%s', + self.repo_name, + display_path(dest), + url, + rev_display, + ) + self.switch(dest, url, rev_options) + elif response == 'i': + # do nothing + pass + elif response == 'w': + logger.warning('Deleting %s', display_path(dest)) + rmtree(dest) + checkout = True + elif response == 'b': + dest_dir = backup_dir(dest) + logger.warning( + 'Backing up %s to %s', display_path(dest), dest_dir, + ) + shutil.move(dest, dest_dir) + checkout = True + elif response == 'a': + sys.exit(-1) + return checkout + + def unpack(self, location): + """ + Clean up current location and download the url repository + (and vcs infos) into location + """ + if os.path.exists(location): + rmtree(location) + self.obtain(location) + + def get_src_requirement(self, dist, location): + """ + Return a string representing the requirement needed to + redownload the files currently present in location, something + like: + {repository_url}@{revision}#egg={project_name}-{version_identifier} + """ + raise NotImplementedError + + def get_url(self, location): + """ + Return the url used at location + Used in get_info or check_destination + """ + raise NotImplementedError + + def get_revision(self, location): + """ + Return the current commit id of the files at the given location. + """ + raise NotImplementedError + + def run_command(self, cmd, show_stdout=True, cwd=None, + on_returncode='raise', + command_desc=None, + extra_environ=None, spinner=None): + """ + Run a VCS subcommand + This is simply a wrapper around call_subprocess that adds the VCS + command name, and checks that the VCS is available + """ + cmd = [self.name] + cmd + try: + return call_subprocess(cmd, show_stdout, cwd, + on_returncode, + command_desc, extra_environ, + unset_environ=self.unset_environ, + spinner=spinner) + except OSError as e: + # errno.ENOENT = no such file or directory + # In other words, the VCS executable isn't available + if e.errno == errno.ENOENT: + raise BadCommand( + 'Cannot find command %r - do you have ' + '%r installed and in your ' + 'PATH?' % (self.name, self.name)) + else: + raise # re-raise exception if a different error occurred + + @classmethod + def controls_location(cls, location): + """ + Check if a location is controlled by the vcs. + It is meant to be overridden to implement smarter detection + mechanisms for specific vcs. + """ + logger.debug('Checking in %s for %s (%s)...', + location, cls.dirname, cls.name) + path = os.path.join(location, cls.dirname) + return os.path.exists(path) + + +def get_src_requirement(dist, location): + version_control = vcs.get_backend_from_location(location) + if version_control: + try: + return version_control().get_src_requirement(dist, + location) + except BadCommand: + logger.warning( + 'cannot determine version of editable source in %s ' + '(%s command not found in path)', + location, + version_control.name, + ) + return dist.as_requirement() + logger.warning( + 'cannot determine version of editable source in %s (is not SVN ' + 'checkout, Git clone, Mercurial clone or Bazaar branch)', + location, + ) + return dist.as_requirement() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py new file mode 100755 index 0000000..6ed629a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/bazaar.py @@ -0,0 +1,113 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.download import path_to_url +from pip._internal.utils.misc import display_path, rmtree +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +logger = logging.getLogger(__name__) + + +class Bazaar(VersionControl): + name = 'bzr' + dirname = '.bzr' + repo_name = 'branch' + schemes = ( + 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', + 'bzr+lp', + ) + + def __init__(self, url=None, *args, **kwargs): + super(Bazaar, self).__init__(url, *args, **kwargs) + # This is only needed for python <2.7.5 + # Register lp but do not expose as a scheme to support bzr+lp. + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(['lp']) + + def get_base_rev_args(self, rev): + return ['-r', rev] + + def export(self, location): + """ + Export the Bazaar repository at the url to the destination location + """ + # Remove the location to make sure Bazaar can export it correctly + if os.path.exists(location): + rmtree(location) + + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + + self.run_command( + ['export', location], + cwd=temp_dir.path, show_stdout=False, + ) + + def switch(self, dest, url, rev_options): + self.run_command(['switch', url], cwd=dest) + + def update(self, dest, rev_options): + cmd_args = ['pull', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = ['branch', '-q'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def get_url_rev(self): + # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it + url, rev = super(Bazaar, self).get_url_rev() + if url.startswith('ssh://'): + url = 'bzr+' + url + return url, rev + + def get_url(self, location): + urls = self.run_command(['info'], show_stdout=False, cwd=location) + for line in urls.splitlines(): + line = line.strip() + for x in ('checkout of branch: ', + 'parent branch: '): + if line.startswith(x): + repo = line.split(x)[1] + if self._is_local_repository(repo): + return path_to_url(repo) + return repo + return None + + def get_revision(self, location): + revision = self.run_command( + ['revno'], show_stdout=False, cwd=location, + ) + return revision.splitlines()[-1] + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo: + return None + if not repo.lower().startswith('bzr:'): + repo = 'bzr+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + current_rev = self.get_revision(location) + return '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + +vcs.register(Bazaar) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py new file mode 100755 index 0000000..7a63dfa --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/git.py @@ -0,0 +1,311 @@ +from __future__ import absolute_import + +import logging +import os.path +import re + +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.compat import samefile +from pip._internal.exceptions import BadCommand +from pip._internal.utils.misc import display_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +urlsplit = urllib_parse.urlsplit +urlunsplit = urllib_parse.urlunsplit + + +logger = logging.getLogger(__name__) + + +HASH_REGEX = re.compile('[a-fA-F0-9]{40}') + + +def looks_like_hash(sha): + return bool(HASH_REGEX.match(sha)) + + +class Git(VersionControl): + name = 'git' + dirname = '.git' + repo_name = 'clone' + schemes = ( + 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', + ) + # Prevent the user's environment variables from interfering with pip: + # https://github.com/pypa/pip/issues/1130 + unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') + default_arg_rev = 'HEAD' + + def __init__(self, url=None, *args, **kwargs): + + # Works around an apparent Git bug + # (see http://article.gmane.org/gmane.comp.version-control.git/146500) + if url: + scheme, netloc, path, query, fragment = urlsplit(url) + if scheme.endswith('file'): + initial_slashes = path[:-len(path.lstrip('/'))] + newpath = ( + initial_slashes + + urllib_request.url2pathname(path) + .replace('\\', '/').lstrip('/') + ) + url = urlunsplit((scheme, netloc, newpath, query, fragment)) + after_plus = scheme.find('+') + 1 + url = scheme[:after_plus] + urlunsplit( + (scheme[after_plus:], netloc, newpath, query, fragment), + ) + + super(Git, self).__init__(url, *args, **kwargs) + + def get_base_rev_args(self, rev): + return [rev] + + def get_git_version(self): + VERSION_PFX = 'git version ' + version = self.run_command(['version'], show_stdout=False) + if version.startswith(VERSION_PFX): + version = version[len(VERSION_PFX):].split()[0] + else: + version = '' + # get first 3 positions of the git version becasue + # on windows it is x.y.z.windows.t, and this parses as + # LegacyVersion which always smaller than a Version. + version = '.'.join(version.split('.')[:3]) + return parse_version(version) + + def export(self, location): + """Export the Git repository at the url to the destination location""" + if not location.endswith('/'): + location = location + '/' + + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + self.run_command( + ['checkout-index', '-a', '-f', '--prefix', location], + show_stdout=False, cwd=temp_dir.path + ) + + def get_revision_sha(self, dest, rev): + """ + Return a commit hash for the given revision if it names a remote + branch or tag. Otherwise, return None. + + Args: + dest: the repository directory. + rev: the revision name. + """ + # Pass rev to pre-filter the list. + output = self.run_command(['show-ref', rev], cwd=dest, + show_stdout=False, on_returncode='ignore') + refs = {} + for line in output.strip().splitlines(): + try: + sha, ref = line.split() + except ValueError: + # Include the offending line to simplify troubleshooting if + # this error ever occurs. + raise ValueError('unexpected show-ref line: {!r}'.format(line)) + + refs[ref] = sha + + branch_ref = 'refs/remotes/origin/{}'.format(rev) + tag_ref = 'refs/tags/{}'.format(rev) + + return refs.get(branch_ref) or refs.get(tag_ref) + + def check_rev_options(self, dest, rev_options): + """Check the revision options before checkout. + + Returns a new RevOptions object for the SHA1 of the branch or tag + if found. + + Args: + rev_options: a RevOptions object. + """ + rev = rev_options.arg_rev + sha = self.get_revision_sha(dest, rev) + + if sha is not None: + return rev_options.make_new(sha) + + # Do not show a warning for the common case of something that has + # the form of a Git commit hash. + if not looks_like_hash(rev): + logger.warning( + "Did not find branch or tag '%s', assuming revision or ref.", + rev, + ) + return rev_options + + def is_commit_id_equal(self, dest, name): + """ + Return whether the current commit hash equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + if not name: + # Then avoid an unnecessary subprocess call. + return False + + return self.get_revision(dest) == name + + def switch(self, dest, url, rev_options): + self.run_command(['config', 'remote.origin.url', url], cwd=dest) + cmd_args = ['checkout', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + self.update_submodules(dest) + + def update(self, dest, rev_options): + # First fetch changes from the default remote + if self.get_git_version() >= parse_version('1.9.0'): + # fetch tags in addition to everything else + self.run_command(['fetch', '-q', '--tags'], cwd=dest) + else: + self.run_command(['fetch', '-q'], cwd=dest) + # Then reset to wanted revision (maybe even origin/master) + rev_options = self.check_rev_options(dest, rev_options) + cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + #: update submodules + self.update_submodules(dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Cloning %s%s to %s', url, rev_display, display_path(dest), + ) + self.run_command(['clone', '-q', url, dest]) + + if rev: + rev_options = self.check_rev_options(dest, rev_options) + # Only do a checkout if the current commit id doesn't match + # the requested revision. + if not self.is_commit_id_equal(dest, rev_options.rev): + rev = rev_options.rev + # Only fetch the revision if it's a ref + if rev.startswith('refs/'): + self.run_command( + ['fetch', '-q', url] + rev_options.to_args(), + cwd=dest, + ) + # Change the revision to the SHA of the ref we fetched + rev = 'FETCH_HEAD' + self.run_command(['checkout', '-q', rev], cwd=dest) + + #: repo may contain submodules + self.update_submodules(dest) + + def get_url(self, location): + """Return URL of the first remote encountered.""" + remotes = self.run_command( + ['config', '--get-regexp', r'remote\..*\.url'], + show_stdout=False, cwd=location, + ) + remotes = remotes.splitlines() + found_remote = remotes[0] + for remote in remotes: + if remote.startswith('remote.origin.url '): + found_remote = remote + break + url = found_remote.split(' ')[1] + return url.strip() + + def get_revision(self, location): + current_rev = self.run_command( + ['rev-parse', 'HEAD'], show_stdout=False, cwd=location, + ) + return current_rev.strip() + + def _get_subdirectory(self, location): + """Return the relative path of setup.py to the git repo root.""" + # find the repo root + git_dir = self.run_command(['rev-parse', '--git-dir'], + show_stdout=False, cwd=location).strip() + if not os.path.isabs(git_dir): + git_dir = os.path.join(location, git_dir) + root_dir = os.path.join(git_dir, '..') + # find setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + # relative path of setup.py to repo root + if samefile(root_dir, location): + return None + return os.path.relpath(location, root_dir) + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo.lower().startswith('git:'): + repo = 'git+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev = self.get_revision(location) + req = '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) + subdirectory = self._get_subdirectory(location) + if subdirectory: + req += '&subdirectory=' + subdirectory + return req + + def get_url_rev(self): + """ + Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. + That's required because although they use SSH they sometimes doesn't + work with a ssh:// scheme (e.g. Github). But we need a scheme for + parsing. Hence we remove it again afterwards and return it as a stub. + """ + if '://' not in self.url: + assert 'file:' not in self.url + self.url = self.url.replace('git+', 'git+ssh://') + url, rev = super(Git, self).get_url_rev() + url = url.replace('ssh://', '') + else: + url, rev = super(Git, self).get_url_rev() + + return url, rev + + def update_submodules(self, location): + if not os.path.exists(os.path.join(location, '.gitmodules')): + return + self.run_command( + ['submodule', 'update', '--init', '--recursive', '-q'], + cwd=location, + ) + + @classmethod + def controls_location(cls, location): + if super(Git, cls).controls_location(location): + return True + try: + r = cls().run_command(['rev-parse'], + cwd=location, + show_stdout=False, + on_returncode='ignore') + return not r + except BadCommand: + logger.debug("could not determine if %s is under git control " + "because git is not available", location) + return False + + +vcs.register(Git) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py new file mode 100755 index 0000000..3936473 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/mercurial.py @@ -0,0 +1,105 @@ +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves import configparser + +from pip._internal.download import path_to_url +from pip._internal.utils.misc import display_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.vcs import VersionControl, vcs + +logger = logging.getLogger(__name__) + + +class Mercurial(VersionControl): + name = 'hg' + dirname = '.hg' + repo_name = 'clone' + schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http') + + def get_base_rev_args(self, rev): + return [rev] + + def export(self, location): + """Export the Hg repository at the url to the destination location""" + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path) + + self.run_command( + ['archive', location], show_stdout=False, cwd=temp_dir.path + ) + + def switch(self, dest, url, rev_options): + repo_config = os.path.join(dest, self.dirname, 'hgrc') + config = configparser.SafeConfigParser() + try: + config.read(repo_config) + config.set('paths', 'default', url) + with open(repo_config, 'w') as config_file: + config.write(config_file) + except (OSError, configparser.NoSectionError) as exc: + logger.warning( + 'Could not switch Mercurial repository to %s: %s', url, exc, + ) + else: + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def update(self, dest, rev_options): + self.run_command(['pull', '-q'], cwd=dest) + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = self.make_rev_options(rev) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Cloning hg %s%s to %s', + url, + rev_display, + display_path(dest), + ) + self.run_command(['clone', '--noupdate', '-q', url, dest]) + cmd_args = ['update', '-q'] + rev_options.to_args() + self.run_command(cmd_args, cwd=dest) + + def get_url(self, location): + url = self.run_command( + ['showconfig', 'paths.default'], + show_stdout=False, cwd=location).strip() + if self._is_local_repository(url): + url = path_to_url(url) + return url.strip() + + def get_revision(self, location): + current_revision = self.run_command( + ['parents', '--template={rev}'], + show_stdout=False, cwd=location).strip() + return current_revision + + def get_revision_hash(self, location): + current_rev_hash = self.run_command( + ['parents', '--template={node}'], + show_stdout=False, cwd=location).strip() + return current_rev_hash + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if not repo.lower().startswith('hg:'): + repo = 'hg+' + repo + egg_project_name = dist.egg_name().split('-', 1)[0] + if not repo: + return None + current_rev_hash = self.get_revision_hash(location) + return '%s@%s#egg=%s' % (repo, current_rev_hash, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + +vcs.register(Mercurial) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py new file mode 100755 index 0000000..95e5440 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/vcs/subversion.py @@ -0,0 +1,271 @@ +from __future__ import absolute_import + +import logging +import os +import re + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.index import Link +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import display_path, rmtree +from pip._internal.vcs import VersionControl, vcs + +_svn_xml_url_re = re.compile('url="([^"]+)"') +_svn_rev_re = re.compile(r'committed-rev="(\d+)"') +_svn_url_re = re.compile(r'URL: (.+)') +_svn_revision_re = re.compile(r'Revision: (.+)') +_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') +_svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') + + +logger = logging.getLogger(__name__) + + +class Subversion(VersionControl): + name = 'svn' + dirname = '.svn' + repo_name = 'checkout' + schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') + + def get_base_rev_args(self, rev): + return ['-r', rev] + + def get_info(self, location): + """Returns (url, revision), where both are strings""" + assert not location.rstrip('/').endswith(self.dirname), \ + 'Bad directory: %s' % location + output = self.run_command( + ['info', location], + show_stdout=False, + extra_environ={'LANG': 'C'}, + ) + match = _svn_url_re.search(output) + if not match: + logger.warning( + 'Cannot determine URL of svn checkout %s', + display_path(location), + ) + logger.debug('Output that cannot be parsed: \n%s', output) + return None, None + url = match.group(1).strip() + match = _svn_revision_re.search(output) + if not match: + logger.warning( + 'Cannot determine revision of svn checkout %s', + display_path(location), + ) + logger.debug('Output that cannot be parsed: \n%s', output) + return url, None + return url, match.group(1) + + def export(self, location): + """Export the svn repository at the url to the destination location""" + url, rev = self.get_url_rev() + rev_options = get_rev_options(self, url, rev) + url = self.remove_auth_from_url(url) + logger.info('Exporting svn repository %s to %s', url, location) + with indent_log(): + if os.path.exists(location): + # Subversion doesn't like to check out over an existing + # directory --force fixes this, but was only added in svn 1.5 + rmtree(location) + cmd_args = ['export'] + rev_options.to_args() + [url, location] + self.run_command(cmd_args, show_stdout=False) + + def switch(self, dest, url, rev_options): + cmd_args = ['switch'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def update(self, dest, rev_options): + cmd_args = ['update'] + rev_options.to_args() + [dest] + self.run_command(cmd_args) + + def obtain(self, dest): + url, rev = self.get_url_rev() + rev_options = get_rev_options(self, url, rev) + url = self.remove_auth_from_url(url) + if self.check_destination(dest, url, rev_options): + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = ['checkout', '-q'] + rev_options.to_args() + [url, dest] + self.run_command(cmd_args) + + def get_location(self, dist, dependency_links): + for url in dependency_links: + egg_fragment = Link(url).egg_fragment + if not egg_fragment: + continue + if '-' in egg_fragment: + # FIXME: will this work when a package has - in the name? + key = '-'.join(egg_fragment.split('-')[:-1]).lower() + else: + key = egg_fragment + if key == dist.key: + return url.split('#', 1)[0] + return None + + def get_revision(self, location): + """ + Return the maximum revision for all files under a given location + """ + # Note: taken from setuptools.command.egg_info + revision = 0 + + for base, dirs, files in os.walk(location): + if self.dirname not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove(self.dirname) + entries_fn = os.path.join(base, self.dirname, 'entries') + if not os.path.exists(entries_fn): + # FIXME: should we warn? + continue + + dirurl, localrev = self._get_svn_url_rev(base) + + if base == location: + base = dirurl + '/' # save the root url + elif not dirurl or not dirurl.startswith(base): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + return revision + + def get_url_rev(self): + # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it + url, rev = super(Subversion, self).get_url_rev() + if url.startswith('ssh://'): + url = 'svn+' + url + return url, rev + + def get_url(self, location): + # In cases where the source is in a subdirectory, not alongside + # setup.py we have to look up in the location until we find a real + # setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + + return self._get_svn_url_rev(location)[0] + + def _get_svn_url_rev(self, location): + from pip._internal.exceptions import InstallationError + + entries_path = os.path.join(location, self.dirname, 'entries') + if os.path.exists(entries_path): + with open(entries_path) as f: + data = f.read() + else: # subversion >= 1.7 does not have the 'entries' file + data = '' + + if (data.startswith('8') or + data.startswith('9') or + data.startswith('10')): + data = list(map(str.splitlines, data.split('\n\x0c\n'))) + del data[0][0] # get rid of the '8' + url = data[0][3] + revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] + elif data.startswith('<?xml'): + match = _svn_xml_url_re.search(data) + if not match: + raise ValueError('Badly formatted data: %r' % data) + url = match.group(1) # get repository URL + revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)] + [0] + else: + try: + # subversion >= 1.7 + xml = self.run_command( + ['info', '--xml', location], + show_stdout=False, + ) + url = _svn_info_xml_url_re.search(xml).group(1) + revs = [ + int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) + ] + except InstallationError: + url, revs = None, [] + + if revs: + rev = max(revs) + else: + rev = 0 + + return url, rev + + def get_src_requirement(self, dist, location): + repo = self.get_url(location) + if repo is None: + return None + # FIXME: why not project name? + egg_project_name = dist.egg_name().split('-', 1)[0] + rev = self.get_revision(location) + return 'svn+%s@%s#egg=%s' % (repo, rev, egg_project_name) + + def is_commit_id_equal(self, dest, name): + """Always assume the versions don't match""" + return False + + @staticmethod + def remove_auth_from_url(url): + # Return a copy of url with 'username:password@' removed. + # username/pass params are passed to subversion through flags + # and are not recognized in the url. + + # parsed url + purl = urllib_parse.urlsplit(url) + stripped_netloc = \ + purl.netloc.split('@')[-1] + + # stripped url + url_pieces = ( + purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment + ) + surl = urllib_parse.urlunsplit(url_pieces) + return surl + + +def get_rev_options(vcs, url, rev): + """ + Return a RevOptions object. + """ + r = urllib_parse.urlsplit(url) + if hasattr(r, 'username'): + # >= Python-2.5 + username, password = r.username, r.password + else: + netloc = r[1] + if '@' in netloc: + auth = netloc.split('@')[0] + if ':' in auth: + username, password = auth.split(':', 1) + else: + username, password = auth, None + else: + username, password = None, None + + extra_args = [] + if username: + extra_args += ['--username', username] + if password: + extra_args += ['--password', password] + + return vcs.make_rev_options(rev, extra_args=extra_args) + + +vcs.register(Subversion) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py new file mode 100755 index 0000000..36459dd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_internal/wheel.py @@ -0,0 +1,817 @@ +""" +Support for installing and building the "wheel" binary package format. +""" +from __future__ import absolute_import + +import collections +import compileall +import copy +import csv +import hashlib +import logging +import os.path +import re +import shutil +import stat +import sys +import warnings +from base64 import urlsafe_b64encode +from email.parser import Parser + +from pip._vendor import pkg_resources +from pip._vendor.distlib.scripts import ScriptMaker +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.six import StringIO + +from pip._internal import pep425tags +from pip._internal.build_env import BuildEnvironment +from pip._internal.download import path_to_url, unpack_url +from pip._internal.exceptions import ( + InstallationError, InvalidWheelFilename, UnsupportedWheel, +) +from pip._internal.locations import ( + PIP_DELETE_MARKER_FILENAME, distutils_scheme, +) +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + call_subprocess, captured_stdout, ensure_dir, read_chunks, +) +from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.ui import open_spinner + +if MYPY_CHECK_RUNNING: + from typing import Dict, List, Optional + +wheel_ext = '.whl' + +VERSION_COMPATIBLE = (1, 0) + + +logger = logging.getLogger(__name__) + + +def rehash(path, algo='sha256', blocksize=1 << 20): + """Return (hash, length) for path using hashlib.new(algo)""" + h = hashlib.new(algo) + length = 0 + with open(path, 'rb') as f: + for block in read_chunks(f, size=blocksize): + length += len(block) + h.update(block) + digest = 'sha256=' + urlsafe_b64encode( + h.digest() + ).decode('latin1').rstrip('=') + return (digest, length) + + +def open_for_csv(name, mode): + if sys.version_info[0] < 3: + nl = {} + bin = 'b' + else: + nl = {'newline': ''} + bin = '' + return open(name, mode + bin, **nl) + + +def fix_script(path): + """Replace #!python with #!/path/to/python + Return True if file was changed.""" + # XXX RECORD hashes will need to be updated + if os.path.isfile(path): + with open(path, 'rb') as script: + firstline = script.readline() + if not firstline.startswith(b'#!python'): + return False + exename = sys.executable.encode(sys.getfilesystemencoding()) + firstline = b'#!' + exename + os.linesep.encode("ascii") + rest = script.read() + with open(path, 'wb') as script: + script.write(firstline) + script.write(rest) + return True + + +dist_info_re = re.compile(r"""^(?P<namever>(?P<name>.+?)(-(?P<ver>.+?))?) + \.dist-info$""", re.VERBOSE) + + +def root_is_purelib(name, wheeldir): + """ + Return True if the extracted wheel in wheeldir should go into purelib. + """ + name_folded = name.replace("-", "_") + for item in os.listdir(wheeldir): + match = dist_info_re.match(item) + if match and match.group('name') == name_folded: + with open(os.path.join(wheeldir, item, 'WHEEL')) as wheel: + for line in wheel: + line = line.lower().rstrip() + if line == "root-is-purelib: true": + return True + return False + + +def get_entrypoints(filename): + if not os.path.exists(filename): + return {}, {} + + # This is done because you can pass a string to entry_points wrappers which + # means that they may or may not be valid INI files. The attempt here is to + # strip leading and trailing whitespace in order to make them valid INI + # files. + with open(filename) as fp: + data = StringIO() + for line in fp: + data.write(line.strip()) + data.write("\n") + data.seek(0) + + # get the entry points and then the script names + entry_points = pkg_resources.EntryPoint.parse_map(data) + console = entry_points.get('console_scripts', {}) + gui = entry_points.get('gui_scripts', {}) + + def _split_ep(s): + """get the string representation of EntryPoint, remove space and split + on '='""" + return str(s).replace(" ", "").split("=") + + # convert the EntryPoint objects into strings with module:function + console = dict(_split_ep(v) for v in console.values()) + gui = dict(_split_ep(v) for v in gui.values()) + return console, gui + + +def message_about_scripts_not_on_PATH(scripts): + # type: (List[str]) -> Optional[str] + """Determine if any scripts are not on PATH and format a warning. + + Returns a warning message if one or more scripts are not on PATH, + otherwise None. + """ + if not scripts: + return None + + # Group scripts by the path they were installed in + grouped_by_dir = collections.defaultdict(set) # type: Dict[str, set] + for destfile in scripts: + parent_dir = os.path.dirname(destfile) + script_name = os.path.basename(destfile) + grouped_by_dir[parent_dir].add(script_name) + + # We don't want to warn for directories that are on PATH. + not_warn_dirs = [ + os.path.normcase(i) for i in os.environ["PATH"].split(os.pathsep) + ] + # If an executable sits with sys.executable, we don't warn for it. + # This covers the case of venv invocations without activating the venv. + not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) + warn_for = { + parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() + if os.path.normcase(parent_dir) not in not_warn_dirs + } + if not warn_for: + return None + + # Format a message + msg_lines = [] + for parent_dir, scripts in warn_for.items(): + scripts = sorted(scripts) + if len(scripts) == 1: + start_text = "script {} is".format(scripts[0]) + else: + start_text = "scripts {} are".format( + ", ".join(scripts[:-1]) + " and " + scripts[-1] + ) + + msg_lines.append( + "The {} installed in '{}' which is not on PATH." + .format(start_text, parent_dir) + ) + + last_line_fmt = ( + "Consider adding {} to PATH or, if you prefer " + "to suppress this warning, use --no-warn-script-location." + ) + if len(msg_lines) == 1: + msg_lines.append(last_line_fmt.format("this directory")) + else: + msg_lines.append(last_line_fmt.format("these directories")) + + # Returns the formatted multiline message + return "\n".join(msg_lines) + + +def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, + pycompile=True, scheme=None, isolated=False, prefix=None, + warn_script_location=True): + """Install a wheel""" + + if not scheme: + scheme = distutils_scheme( + name, user=user, home=home, root=root, isolated=isolated, + prefix=prefix, + ) + + if root_is_purelib(name, wheeldir): + lib_dir = scheme['purelib'] + else: + lib_dir = scheme['platlib'] + + info_dir = [] + data_dirs = [] + source = wheeldir.rstrip(os.path.sep) + os.path.sep + + # Record details of the files moved + # installed = files copied from the wheel to the destination + # changed = files changed while installing (scripts #! line typically) + # generated = files newly generated during the install (script wrappers) + installed = {} + changed = set() + generated = [] + + # Compile all of the pyc files that we're going to be installing + if pycompile: + with captured_stdout() as stdout: + with warnings.catch_warnings(): + warnings.filterwarnings('ignore') + compileall.compile_dir(source, force=True, quiet=True) + logger.debug(stdout.getvalue()) + + def normpath(src, p): + return os.path.relpath(src, p).replace(os.path.sep, '/') + + def record_installed(srcfile, destfile, modified=False): + """Map archive RECORD paths to installation RECORD paths.""" + oldpath = normpath(srcfile, wheeldir) + newpath = normpath(destfile, lib_dir) + installed[oldpath] = newpath + if modified: + changed.add(destfile) + + def clobber(source, dest, is_base, fixer=None, filter=None): + ensure_dir(dest) # common for the 'include' path + + for dir, subdirs, files in os.walk(source): + basedir = dir[len(source):].lstrip(os.path.sep) + destdir = os.path.join(dest, basedir) + if is_base and basedir.split(os.path.sep, 1)[0].endswith('.data'): + continue + for s in subdirs: + destsubdir = os.path.join(dest, basedir, s) + if is_base and basedir == '' and destsubdir.endswith('.data'): + data_dirs.append(s) + continue + elif (is_base and + s.endswith('.dist-info') and + canonicalize_name(s).startswith( + canonicalize_name(req.name))): + assert not info_dir, ('Multiple .dist-info directories: ' + + destsubdir + ', ' + + ', '.join(info_dir)) + info_dir.append(destsubdir) + for f in files: + # Skip unwanted files + if filter and filter(f): + continue + srcfile = os.path.join(dir, f) + destfile = os.path.join(dest, basedir, f) + # directory creation is lazy and after the file filtering above + # to ensure we don't install empty dirs; empty dirs can't be + # uninstalled. + ensure_dir(destdir) + + # We use copyfile (not move, copy, or copy2) to be extra sure + # that we are not moving directories over (copyfile fails for + # directories) as well as to ensure that we are not copying + # over any metadata because we want more control over what + # metadata we actually copy over. + shutil.copyfile(srcfile, destfile) + + # Copy over the metadata for the file, currently this only + # includes the atime and mtime. + st = os.stat(srcfile) + if hasattr(os, "utime"): + os.utime(destfile, (st.st_atime, st.st_mtime)) + + # If our file is executable, then make our destination file + # executable. + if os.access(srcfile, os.X_OK): + st = os.stat(srcfile) + permissions = ( + st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + ) + os.chmod(destfile, permissions) + + changed = False + if fixer: + changed = fixer(destfile) + record_installed(srcfile, destfile, changed) + + clobber(source, lib_dir, True) + + assert info_dir, "%s .dist-info directory not found" % req + + # Get the defined entry points + ep_file = os.path.join(info_dir[0], 'entry_points.txt') + console, gui = get_entrypoints(ep_file) + + def is_entrypoint_wrapper(name): + # EP, EP.exe and EP-script.py are scripts generated for + # entry point EP by setuptools + if name.lower().endswith('.exe'): + matchname = name[:-4] + elif name.lower().endswith('-script.py'): + matchname = name[:-10] + elif name.lower().endswith(".pya"): + matchname = name[:-4] + else: + matchname = name + # Ignore setuptools-generated scripts + return (matchname in console or matchname in gui) + + for datadir in data_dirs: + fixer = None + filter = None + for subdir in os.listdir(os.path.join(wheeldir, datadir)): + fixer = None + if subdir == 'scripts': + fixer = fix_script + filter = is_entrypoint_wrapper + source = os.path.join(wheeldir, datadir, subdir) + dest = scheme[subdir] + clobber(source, dest, False, fixer=fixer, filter=filter) + + maker = ScriptMaker(None, scheme['scripts']) + + # Ensure old scripts are overwritten. + # See https://github.com/pypa/pip/issues/1800 + maker.clobber = True + + # Ensure we don't generate any variants for scripts because this is almost + # never what somebody wants. + # See https://bitbucket.org/pypa/distlib/issue/35/ + maker.variants = {''} + + # This is required because otherwise distlib creates scripts that are not + # executable. + # See https://bitbucket.org/pypa/distlib/issue/32/ + maker.set_mode = True + + # Simplify the script and fix the fact that the default script swallows + # every single stack trace. + # See https://bitbucket.org/pypa/distlib/issue/34/ + # See https://bitbucket.org/pypa/distlib/issue/33/ + def _get_script_text(entry): + if entry.suffix is None: + raise InstallationError( + "Invalid script entry point: %s for req: %s - A callable " + "suffix is required. Cf https://packaging.python.org/en/" + "latest/distributing.html#console-scripts for more " + "information." % (entry, req) + ) + return maker.script_template % { + "module": entry.prefix, + "import_name": entry.suffix.split(".")[0], + "func": entry.suffix, + } + + maker._get_script_text = _get_script_text + maker.script_template = r"""# -*- coding: utf-8 -*- +import re +import sys + +from %(module)s import %(import_name)s + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(%(func)s()) +""" + + # Special case pip and setuptools to generate versioned wrappers + # + # The issue is that some projects (specifically, pip and setuptools) use + # code in setup.py to create "versioned" entry points - pip2.7 on Python + # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into + # the wheel metadata at build time, and so if the wheel is installed with + # a *different* version of Python the entry points will be wrong. The + # correct fix for this is to enhance the metadata to be able to describe + # such versioned entry points, but that won't happen till Metadata 2.0 is + # available. + # In the meantime, projects using versioned entry points will either have + # incorrect versioned entry points, or they will not be able to distribute + # "universal" wheels (i.e., they will need a wheel per Python version). + # + # Because setuptools and pip are bundled with _ensurepip and virtualenv, + # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we + # override the versioned entry points in the wheel and generate the + # correct ones. This code is purely a short-term measure until Metadata 2.0 + # is available. + # + # To add the level of hack in this section of code, in order to support + # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment + # variable which will control which version scripts get installed. + # + # ENSUREPIP_OPTIONS=altinstall + # - Only pipX.Y and easy_install-X.Y will be generated and installed + # ENSUREPIP_OPTIONS=install + # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note + # that this option is technically if ENSUREPIP_OPTIONS is set and is + # not altinstall + # DEFAULT + # - The default behavior is to install pip, pipX, pipX.Y, easy_install + # and easy_install-X.Y. + pip_script = console.pop('pip', None) + if pip_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + spec = 'pip = ' + pip_script + generated.extend(maker.make(spec)) + + if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": + spec = 'pip%s = %s' % (sys.version[:1], pip_script) + generated.extend(maker.make(spec)) + + spec = 'pip%s = %s' % (sys.version[:3], pip_script) + generated.extend(maker.make(spec)) + # Delete any other versioned pip entry points + pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] + for k in pip_ep: + del console[k] + easy_install_script = console.pop('easy_install', None) + if easy_install_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + spec = 'easy_install = ' + easy_install_script + generated.extend(maker.make(spec)) + + spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script) + generated.extend(maker.make(spec)) + # Delete any other versioned easy_install entry points + easy_install_ep = [ + k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) + ] + for k in easy_install_ep: + del console[k] + + # Generate the console and GUI entry points specified in the wheel + if len(console) > 0: + generated_console_scripts = maker.make_multiple( + ['%s = %s' % kv for kv in console.items()] + ) + generated.extend(generated_console_scripts) + + if warn_script_location: + msg = message_about_scripts_not_on_PATH(generated_console_scripts) + if msg is not None: + logger.warn(msg) + + if len(gui) > 0: + generated.extend( + maker.make_multiple( + ['%s = %s' % kv for kv in gui.items()], + {'gui': True} + ) + ) + + # Record pip as the installer + installer = os.path.join(info_dir[0], 'INSTALLER') + temp_installer = os.path.join(info_dir[0], 'INSTALLER.pip') + with open(temp_installer, 'wb') as installer_file: + installer_file.write(b'pip\n') + shutil.move(temp_installer, installer) + generated.append(installer) + + # Record details of all files installed + record = os.path.join(info_dir[0], 'RECORD') + temp_record = os.path.join(info_dir[0], 'RECORD.pip') + with open_for_csv(record, 'r') as record_in: + with open_for_csv(temp_record, 'w+') as record_out: + reader = csv.reader(record_in) + writer = csv.writer(record_out) + for row in reader: + row[0] = installed.pop(row[0], row[0]) + if row[0] in changed: + row[1], row[2] = rehash(row[0]) + writer.writerow(row) + for f in generated: + h, l = rehash(f) + writer.writerow((normpath(f, lib_dir), h, l)) + for f in installed: + writer.writerow((installed[f], '', '')) + shutil.move(temp_record, record) + + +def wheel_version(source_dir): + """ + Return the Wheel-Version of an extracted wheel, if possible. + + Otherwise, return False if we couldn't parse / extract it. + """ + try: + dist = [d for d in pkg_resources.find_on_path(None, source_dir)][0] + + wheel_data = dist.get_metadata('WHEEL') + wheel_data = Parser().parsestr(wheel_data) + + version = wheel_data['Wheel-Version'].strip() + version = tuple(map(int, version.split('.'))) + return version + except: + return False + + +def check_compatibility(version, name): + """ + Raises errors or warns if called with an incompatible Wheel-Version. + + Pip should refuse to install a Wheel-Version that's a major series + ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when + installing a version only minor version ahead (e.g 1.2 > 1.1). + + version: a 2-tuple representing a Wheel-Version (Major, Minor) + name: name of wheel or package to raise exception about + + :raises UnsupportedWheel: when an incompatible Wheel-Version is given + """ + if not version: + raise UnsupportedWheel( + "%s is in an unsupported or invalid wheel" % name + ) + if version[0] > VERSION_COMPATIBLE[0]: + raise UnsupportedWheel( + "%s's Wheel-Version (%s) is not compatible with this version " + "of pip" % (name, '.'.join(map(str, version))) + ) + elif version > VERSION_COMPATIBLE: + logger.warning( + 'Installing from a newer Wheel-Version (%s)', + '.'.join(map(str, version)), + ) + + +class Wheel(object): + """A wheel file""" + + # TODO: maybe move the install code into this class + + wheel_file_re = re.compile( + r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) + ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) + \.whl|\.dist-info)$""", + re.VERBOSE + ) + + def __init__(self, filename): + """ + :raises InvalidWheelFilename: when the filename is invalid for a wheel + """ + wheel_info = self.wheel_file_re.match(filename) + if not wheel_info: + raise InvalidWheelFilename( + "%s is not a valid wheel filename." % filename + ) + self.filename = filename + self.name = wheel_info.group('name').replace('_', '-') + # we'll assume "_" means "-" due to wheel naming scheme + # (https://github.com/pypa/pip/issues/1150) + self.version = wheel_info.group('ver').replace('_', '-') + self.build_tag = wheel_info.group('build') + self.pyversions = wheel_info.group('pyver').split('.') + self.abis = wheel_info.group('abi').split('.') + self.plats = wheel_info.group('plat').split('.') + + # All the tag combinations from this file + self.file_tags = { + (x, y, z) for x in self.pyversions + for y in self.abis for z in self.plats + } + + def support_index_min(self, tags=None): + """ + Return the lowest index that one of the wheel's file_tag combinations + achieves in the supported_tags list e.g. if there are 8 supported tags, + and one of the file tags is first in the list, then return 0. Returns + None is the wheel is not supported. + """ + if tags is None: # for mock + tags = pep425tags.get_supported() + indexes = [tags.index(c) for c in self.file_tags if c in tags] + return min(indexes) if indexes else None + + def supported(self, tags=None): + """Is this wheel supported on this system?""" + if tags is None: # for mock + tags = pep425tags.get_supported() + return bool(set(tags).intersection(self.file_tags)) + + +class WheelBuilder(object): + """Build wheels from a RequirementSet.""" + + def __init__(self, finder, preparer, wheel_cache, + build_options=None, global_options=None, no_clean=False): + self.finder = finder + self.preparer = preparer + self.wheel_cache = wheel_cache + + self._wheel_dir = preparer.wheel_download_dir + + self.build_options = build_options or [] + self.global_options = global_options or [] + self.no_clean = no_clean + + def _build_one(self, req, output_dir, python_tag=None): + """Build one wheel. + + :return: The filename of the built wheel, or None if the build failed. + """ + # Install build deps into temporary directory (PEP 518) + with req.build_env: + return self._build_one_inside_env(req, output_dir, + python_tag=python_tag) + + def _build_one_inside_env(self, req, output_dir, python_tag=None): + with TempDirectory(kind="wheel") as temp_dir: + if self.__build_one(req, temp_dir.path, python_tag=python_tag): + try: + wheel_name = os.listdir(temp_dir.path)[0] + wheel_path = os.path.join(output_dir, wheel_name) + shutil.move( + os.path.join(temp_dir.path, wheel_name), wheel_path + ) + logger.info('Stored in directory: %s', output_dir) + return wheel_path + except: + pass + # Ignore return, we can't do anything else useful. + self._clean_one(req) + return None + + def _base_setup_args(self, req): + # NOTE: Eventually, we'd want to also -S to the flags here, when we're + # isolating. Currently, it breaks Python in virtualenvs, because it + # relies on site.py to find parts of the standard library outside the + # virtualenv. + return [ + sys.executable, '-u', '-c', + SETUPTOOLS_SHIM % req.setup_py + ] + list(self.global_options) + + def __build_one(self, req, tempd, python_tag=None): + base_args = self._base_setup_args(req) + + spin_message = 'Running setup.py bdist_wheel for %s' % (req.name,) + with open_spinner(spin_message) as spinner: + logger.debug('Destination directory: %s', tempd) + wheel_args = base_args + ['bdist_wheel', '-d', tempd] \ + + self.build_options + + if python_tag is not None: + wheel_args += ["--python-tag", python_tag] + + try: + call_subprocess(wheel_args, cwd=req.setup_py_dir, + show_stdout=False, spinner=spinner) + return True + except: + spinner.finish("error") + logger.error('Failed building wheel for %s', req.name) + return False + + def _clean_one(self, req): + base_args = self._base_setup_args(req) + + logger.info('Running setup.py clean for %s', req.name) + clean_args = base_args + ['clean', '--all'] + try: + call_subprocess(clean_args, cwd=req.source_dir, show_stdout=False) + return True + except: + logger.error('Failed cleaning build dir for %s', req.name) + return False + + def build(self, requirements, session, autobuilding=False): + """Build wheels. + + :param unpack: If True, replace the sdist we built from with the + newly built wheel, in preparation for installation. + :return: True if all the wheels built correctly. + """ + from pip._internal import index + + building_is_possible = self._wheel_dir or ( + autobuilding and self.wheel_cache.cache_dir + ) + assert building_is_possible + + buildset = [] + for req in requirements: + if req.constraint: + continue + if req.is_wheel: + if not autobuilding: + logger.info( + 'Skipping %s, due to already being wheel.', req.name, + ) + elif autobuilding and req.editable: + pass + elif autobuilding and not req.source_dir: + pass + elif autobuilding and req.link and not req.link.is_artifact: + # VCS checkout. Build wheel just for this run. + buildset.append((req, True)) + else: + ephem_cache = False + if autobuilding: + link = req.link + base, ext = link.splitext() + if index.egg_info_matches(base, None, link) is None: + # E.g. local directory. Build wheel just for this run. + ephem_cache = True + if "binary" not in index.fmt_ctl_formats( + self.finder.format_control, + canonicalize_name(req.name)): + logger.info( + "Skipping bdist_wheel for %s, due to binaries " + "being disabled for it.", req.name, + ) + continue + buildset.append((req, ephem_cache)) + + if not buildset: + return True + + # Build the wheels. + logger.info( + 'Building wheels for collected packages: %s', + ', '.join([req.name for (req, _) in buildset]), + ) + _cache = self.wheel_cache # shorter name + with indent_log(): + build_success, build_failure = [], [] + for req, ephem in buildset: + python_tag = None + if autobuilding: + python_tag = pep425tags.implementation_tag + if ephem: + output_dir = _cache.get_ephem_path_for_link(req.link) + else: + output_dir = _cache.get_path_for_link(req.link) + try: + ensure_dir(output_dir) + except OSError as e: + logger.warning("Building wheel for %s failed: %s", + req.name, e) + build_failure.append(req) + continue + else: + output_dir = self._wheel_dir + wheel_file = self._build_one( + req, output_dir, + python_tag=python_tag, + ) + if wheel_file: + build_success.append(req) + if autobuilding: + # XXX: This is mildly duplicative with prepare_files, + # but not close enough to pull out to a single common + # method. + # The code below assumes temporary source dirs - + # prevent it doing bad things. + if req.source_dir and not os.path.exists(os.path.join( + req.source_dir, PIP_DELETE_MARKER_FILENAME)): + raise AssertionError( + "bad source dir - missing marker") + # Delete the source we built the wheel from + req.remove_temporary_source() + # set the build directory again - name is known from + # the work prepare_files did. + req.source_dir = req.build_location( + self.preparer.build_dir + ) + # Update the link for this. + req.link = index.Link(path_to_url(wheel_file)) + assert req.link.is_wheel + # extract the wheel into the dir + unpack_url( + req.link, req.source_dir, None, False, + session=session, + ) + else: + build_failure.append(req) + + # notify success/failure + if build_success: + logger.info( + 'Successfully built %s', + ' '.join([req.name for req in build_success]), + ) + if build_failure: + logger.info( + 'Failed to build %s', + ' '.join([req.name for req in build_failure]), + ) + # Return True if all builds were successful + return len(build_failure) == 0 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py new file mode 100755 index 0000000..607757f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/__init__.py @@ -0,0 +1,109 @@ +""" +pip._vendor is for vendoring dependencies of pip to prevent needing pip to +depend on something external. + +Files inside of pip._vendor should be considered immutable and should only be +updated to versions from upstream. +""" +from __future__ import absolute_import + +import glob +import os.path +import sys + +# Downstream redistributors which have debundled our dependencies should also +# patch this value to be true. This will trigger the additional patching +# to cause things like "six" to be available as pip. +DEBUNDLED = False + +# By default, look in this directory for a bunch of .whl files which we will +# add to the beginning of sys.path before attempting to import anything. This +# is done to support downstream re-distributors like Debian and Fedora who +# wish to create their own Wheels for our dependencies to aid in debundling. +WHEEL_DIR = os.path.abspath(os.path.dirname(__file__)) + + +# Define a small helper function to alias our vendored modules to the real ones +# if the vendored ones do not exist. This idea of this was taken from +# https://github.com/kennethreitz/requests/pull/2567. +def vendored(modulename): + vendored_name = "{0}.{1}".format(__name__, modulename) + + try: + __import__(vendored_name, globals(), locals(), level=0) + except ImportError: + try: + __import__(modulename, globals(), locals(), level=0) + except ImportError: + # We can just silently allow import failures to pass here. If we + # got to this point it means that ``import pip._vendor.whatever`` + # failed and so did ``import whatever``. Since we're importing this + # upfront in an attempt to alias imports, not erroring here will + # just mean we get a regular import error whenever pip *actually* + # tries to import one of these modules to use it, which actually + # gives us a better error message than we would have otherwise + # gotten. + pass + else: + sys.modules[vendored_name] = sys.modules[modulename] + base, head = vendored_name.rsplit(".", 1) + setattr(sys.modules[base], head, sys.modules[modulename]) + + +# If we're operating in a debundled setup, then we want to go ahead and trigger +# the aliasing of our vendored libraries as well as looking for wheels to add +# to our sys.path. This will cause all of this code to be a no-op typically +# however downstream redistributors can enable it in a consistent way across +# all platforms. +if DEBUNDLED: + # Actually look inside of WHEEL_DIR to find .whl files and add them to the + # front of our sys.path. + sys.path[:] = glob.glob(os.path.join(WHEEL_DIR, "*.whl")) + sys.path + + # Actually alias all of our vendored dependencies. + vendored("cachecontrol") + vendored("colorama") + vendored("distlib") + vendored("distro") + vendored("html5lib") + vendored("lockfile") + vendored("six") + vendored("six.moves") + vendored("six.moves.urllib") + vendored("six.moves.urllib.parse") + vendored("packaging") + vendored("packaging.version") + vendored("packaging.specifiers") + vendored("pkg_resources") + vendored("progress") + vendored("pytoml") + vendored("retrying") + vendored("requests") + vendored("requests.packages") + vendored("requests.packages.urllib3") + vendored("requests.packages.urllib3._collections") + vendored("requests.packages.urllib3.connection") + vendored("requests.packages.urllib3.connectionpool") + vendored("requests.packages.urllib3.contrib") + vendored("requests.packages.urllib3.contrib.ntlmpool") + vendored("requests.packages.urllib3.contrib.pyopenssl") + vendored("requests.packages.urllib3.exceptions") + vendored("requests.packages.urllib3.fields") + vendored("requests.packages.urllib3.filepost") + vendored("requests.packages.urllib3.packages") + vendored("requests.packages.urllib3.packages.ordered_dict") + vendored("requests.packages.urllib3.packages.six") + vendored("requests.packages.urllib3.packages.ssl_match_hostname") + vendored("requests.packages.urllib3.packages.ssl_match_hostname." + "_implementation") + vendored("requests.packages.urllib3.poolmanager") + vendored("requests.packages.urllib3.request") + vendored("requests.packages.urllib3.response") + vendored("requests.packages.urllib3.util") + vendored("requests.packages.urllib3.util.connection") + vendored("requests.packages.urllib3.util.request") + vendored("requests.packages.urllib3.util.response") + vendored("requests.packages.urllib3.util.retry") + vendored("requests.packages.urllib3.util.ssl_") + vendored("requests.packages.urllib3.util.timeout") + vendored("requests.packages.urllib3.util.url") diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py new file mode 100755 index 0000000..7ff6a07 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/appdirs.py @@ -0,0 +1,604 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2005-2010 ActiveState Software Inc. +# Copyright (c) 2013 Eddy Petrișor + +"""Utilities for determining application-specific dirs. + +See <http://github.com/ActiveState/appdirs> for details and usage. +""" +# Dev Notes: +# - MSDN on where to store app data files: +# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 +# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html +# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +__version_info__ = (1, 4, 3) +__version__ = '.'.join(map(str, __version_info__)) + + +import sys +import os + +PY3 = sys.version_info[0] == 3 + +if PY3: + unicode = str + +if sys.platform.startswith('java'): + import platform + os_name = platform.java_ver()[3][0] + if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. + system = 'win32' + elif os_name.startswith('Mac'): # "Mac OS X", etc. + system = 'darwin' + else: # "Linux", "SunOS", "FreeBSD", etc. + # Setting this to "linux2" is not ideal, but only Windows or Mac + # are actually checked for and the rest of the module expects + # *sys.platform* style strings. + system = 'linux2' +else: + system = sys.platform + + + +def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user data directories are: + Mac OS X: ~/Library/Application Support/<AppName> + Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName> + Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName> + Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName> + Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName> + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/<AppName>". + """ + if system == "win32": + if appauthor is None: + appauthor = appname + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(_get_win_folder(const)) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('~/Library/Application Support/') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of data dirs should be + returned. By default, the first item from XDG_DATA_DIRS is + returned, or '/usr/local/share/<AppName>', + if XDG_DATA_DIRS is not set + + Typical site data directories are: + Mac OS X: /Library/Application Support/<AppName> + Unix: /usr/local/share/<AppName> or /usr/share/<AppName> + Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName> + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7. + + For Unix, this is using the $XDG_DATA_DIRS[0] default. + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('/Library/Application Support') + if appname: + path = os.path.join(path, appname) + else: + # XDG default for $XDG_DATA_DIRS + # only first, if multipath is False + path = os.getenv('XDG_DATA_DIRS', + os.pathsep.join(['/usr/local/share', '/usr/share'])) + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + if appname and version: + path = os.path.join(path, version) + return path + + +def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user config directories are: + Mac OS X: same as user_data_dir + Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/<AppName>". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of config dirs should be + returned. By default, the first item from XDG_CONFIG_DIRS is + returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set + + Typical site config directories are: + Mac OS X: same as site_data_dir + Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in + $XDG_CONFIG_DIRS + Win *: same as site_data_dir + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + + For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system in ["win32", "darwin"]: + path = site_data_dir(appname, appauthor) + if appname and version: + path = os.path.join(path, version) + else: + # XDG default for $XDG_CONFIG_DIRS + # only first, if multipath is False + path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + +def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Cache" to the base app data dir for Windows. See + discussion below. + + Typical user cache directories are: + Mac OS X: ~/Library/Caches/<AppName> + Unix: ~/.cache/<AppName> (XDG default) + Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache + Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go in + the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming + app data dir (the default returned by `user_data_dir` above). Apps typically + put cache data somewhere *under* the given dir here. Some examples: + ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache + ...\Acme\SuperApp\Cache\1.0 + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + This can be disabled with the `opinion=False` option. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + if opinion: + path = os.path.join(path, "Cache") + elif system == 'darwin': + path = os.path.expanduser('~/Library/Caches') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state> + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/<AppName>". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific log dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be "<major>.<minor>". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Logs" to the base app data dir for Windows, and "log" to the + base cache dir for Unix. See discussion below. + + Typical user log directories are: + Mac OS X: ~/Library/Logs/<AppName> + Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined + Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs + Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs + + On Windows the only suggestion in the MSDN docs is that local settings + go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in + examples of what some windows apps use for a logs dir.) + + OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` + value for Windows and appends "log" to the user cache dir for Unix. + This can be disabled with the `opinion=False` option. + """ + if system == "darwin": + path = os.path.join( + os.path.expanduser('~/Library/Logs'), + appname) + elif system == "win32": + path = user_data_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "Logs") + else: + path = user_cache_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "log") + if appname and version: + path = os.path.join(path, version) + return path + + +class AppDirs(object): + """Convenience wrapper for getting application dirs.""" + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): + self.appname = appname + self.appauthor = appauthor + self.version = version + self.roaming = roaming + self.multipath = multipath + + @property + def user_data_dir(self): + return user_data_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_data_dir(self): + return site_data_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_config_dir(self): + return user_config_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_config_dir(self): + return site_config_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_cache_dir(self): + return user_cache_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_log_dir(self): + return user_log_dir(self.appname, self.appauthor, + version=self.version) + + +#---- internal support stuff + +def _get_win_folder_from_registry(csidl_name): + """This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + if PY3: + import winreg as _winreg + else: + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + dir, type = _winreg.QueryValueEx(key, shell_folder_name) + return dir + + +def _get_win_folder_with_pywin32(csidl_name): + from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) + # Try to make this a unicode path because SHGetFolderPath does + # not return unicode strings when there is unicode data in the + # path. + try: + dir = unicode(dir) + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + try: + import win32api + dir = win32api.GetShortPathName(dir) + except ImportError: + pass + except UnicodeError: + pass + return dir + + +def _get_win_folder_with_ctypes(csidl_name): + import ctypes + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + +def _get_win_folder_with_jna(csidl_name): + import array + from com.sun import jna + from com.sun.jna.platform import win32 + + buf_size = win32.WinDef.MAX_PATH * 2 + buf = array.zeros('c', buf_size) + shell = win32.Shell32.INSTANCE + shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + # Downgrade to short path name if have highbit chars. See + # <http://bugs.activestate.com/show_bug.cgi?id=85099>. + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf = array.zeros('c', buf_size) + kernel = win32.Kernel32.INSTANCE + if kernel.GetShortPathName(dir, buf, buf_size): + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + return dir + +if system == "win32": + try: + from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + try: + import com.sun.jna + _get_win_folder = _get_win_folder_with_jna + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +#---- self test code + +if __name__ == "__main__": + appname = "MyApp" + appauthor = "MyCompany" + + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) + + print("-- app dirs (with optional 'version')") + dirs = AppDirs(appname, appauthor, version="1.0") + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'version')") + dirs = AppDirs(appname, appauthor) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'appauthor')") + dirs = AppDirs(appname) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (with disabled 'appauthor')") + dirs = AppDirs(appname, appauthor=False) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py new file mode 100755 index 0000000..ced6d94 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/__init__.py @@ -0,0 +1,11 @@ +"""CacheControl import Interface. + +Make it easy to import from cachecontrol without long namespaces. +""" +__author__ = 'Eric Larson' +__email__ = 'eric@ionrock.org' +__version__ = '0.12.4' + +from .wrapper import CacheControl +from .adapter import CacheControlAdapter +from .controller import CacheController diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py new file mode 100755 index 0000000..10bc01e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/_cmd.py @@ -0,0 +1,60 @@ +import logging + +from pip._vendor import requests + +from pip._vendor.cachecontrol.adapter import CacheControlAdapter +from pip._vendor.cachecontrol.cache import DictCache +from pip._vendor.cachecontrol.controller import logger + +from argparse import ArgumentParser + + +def setup_logging(): + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + logger.addHandler(handler) + + +def get_session(): + adapter = CacheControlAdapter( + DictCache(), + cache_etags=True, + serializer=None, + heuristic=None, + ) + sess = requests.Session() + sess.mount('http://', adapter) + sess.mount('https://', adapter) + + sess.cache_controller = adapter.controller + return sess + + +def get_args(): + parser = ArgumentParser() + parser.add_argument('url', help='The URL to try and cache') + return parser.parse_args() + + +def main(args=None): + args = get_args() + sess = get_session() + + # Make a request to get a response + resp = sess.get(args.url) + + # Turn on logging + setup_logging() + + # try setting the cache + sess.cache_controller.cache_response(resp.request, resp.raw) + + # Now try to get it + if sess.cache_controller.cached_request(resp.request): + print('Cached!') + else: + print('Not cached :(') + + +if __name__ == '__main__': + main() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py new file mode 100755 index 0000000..03c95c9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/adapter.py @@ -0,0 +1,134 @@ +import types +import functools +import zlib + +from pip._vendor.requests.adapters import HTTPAdapter + +from .controller import CacheController +from .cache import DictCache +from .filewrapper import CallbackFileWrapper + + +class CacheControlAdapter(HTTPAdapter): + invalidating_methods = set(['PUT', 'DELETE']) + + def __init__(self, cache=None, + cache_etags=True, + controller_class=None, + serializer=None, + heuristic=None, + cacheable_methods=None, + *args, **kw): + super(CacheControlAdapter, self).__init__(*args, **kw) + self.cache = cache or DictCache() + self.heuristic = heuristic + self.cacheable_methods = cacheable_methods or ('GET',) + + controller_factory = controller_class or CacheController + self.controller = controller_factory( + self.cache, + cache_etags=cache_etags, + serializer=serializer, + ) + + def send(self, request, cacheable_methods=None, **kw): + """ + Send a request. Use the request information to see if it + exists in the cache and cache the response if we need to and can. + """ + cacheable = cacheable_methods or self.cacheable_methods + if request.method in cacheable: + try: + cached_response = self.controller.cached_request(request) + except zlib.error: + cached_response = None + if cached_response: + return self.build_response(request, cached_response, + from_cache=True) + + # check for etags and add headers if appropriate + request.headers.update( + self.controller.conditional_headers(request) + ) + + resp = super(CacheControlAdapter, self).send(request, **kw) + + return resp + + def build_response(self, request, response, from_cache=False, + cacheable_methods=None): + """ + Build a response by making a request or using the cache. + + This will end up calling send and returning a potentially + cached response + """ + cacheable = cacheable_methods or self.cacheable_methods + if not from_cache and request.method in cacheable: + # Check for any heuristics that might update headers + # before trying to cache. + if self.heuristic: + response = self.heuristic.apply(response) + + # apply any expiration heuristics + if response.status == 304: + # We must have sent an ETag request. This could mean + # that we've been expired already or that we simply + # have an etag. In either case, we want to try and + # update the cache if that is the case. + cached_response = self.controller.update_cached_response( + request, response + ) + + if cached_response is not response: + from_cache = True + + # We are done with the server response, read a + # possible response body (compliant servers will + # not return one, but we cannot be 100% sure) and + # release the connection back to the pool. + response.read(decode_content=False) + response.release_conn() + + response = cached_response + + # We always cache the 301 responses + elif response.status == 301: + self.controller.cache_response(request, response) + else: + # Wrap the response file with a wrapper that will cache the + # response when the stream has been consumed. + response._fp = CallbackFileWrapper( + response._fp, + functools.partial( + self.controller.cache_response, + request, + response, + ) + ) + if response.chunked: + super_update_chunk_length = response._update_chunk_length + + def _update_chunk_length(self): + super_update_chunk_length() + if self.chunk_left == 0: + self._fp._close() + response._update_chunk_length = types.MethodType(_update_chunk_length, response) + + resp = super(CacheControlAdapter, self).build_response( + request, response + ) + + # See if we should invalidate the cache. + if request.method in self.invalidating_methods and resp.ok: + cache_url = self.controller.cache_url(request.url) + self.cache.delete(cache_url) + + # Give the request a from_cache attr to let people use it + resp.from_cache = from_cache + + return resp + + def close(self): + self.cache.close() + super(CacheControlAdapter, self).close() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py new file mode 100755 index 0000000..04d1488 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/cache.py @@ -0,0 +1,39 @@ +""" +The cache object API for implementing caches. The default is a thread +safe in-memory dictionary. +""" +from threading import Lock + + +class BaseCache(object): + + def get(self, key): + raise NotImplemented() + + def set(self, key, value): + raise NotImplemented() + + def delete(self, key): + raise NotImplemented() + + def close(self): + pass + + +class DictCache(BaseCache): + + def __init__(self, init_dict=None): + self.lock = Lock() + self.data = init_dict or {} + + def get(self, key): + return self.data.get(key, None) + + def set(self, key, value): + with self.lock: + self.data.update({key: value}) + + def delete(self, key): + with self.lock: + if key in self.data: + self.data.pop(key) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py new file mode 100755 index 0000000..1193f26 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/__init__.py @@ -0,0 +1,2 @@ +from .file_cache import FileCache # noqa +from .redis_cache import RedisCache # noqa diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py new file mode 100755 index 0000000..f7eb890 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/file_cache.py @@ -0,0 +1,133 @@ +import hashlib +import os +from textwrap import dedent + +from ..cache import BaseCache +from ..controller import CacheController + +try: + FileNotFoundError +except NameError: + # py2.X + FileNotFoundError = OSError + + +def _secure_open_write(filename, fmode): + # We only want to write to this file, so open it in write only mode + flags = os.O_WRONLY + + # os.O_CREAT | os.O_EXCL will fail if the file already exists, so we only + # will open *new* files. + # We specify this because we want to ensure that the mode we pass is the + # mode of the file. + flags |= os.O_CREAT | os.O_EXCL + + # Do not follow symlinks to prevent someone from making a symlink that + # we follow and insecurely open a cache file. + if hasattr(os, "O_NOFOLLOW"): + flags |= os.O_NOFOLLOW + + # On Windows we'll mark this file as binary + if hasattr(os, "O_BINARY"): + flags |= os.O_BINARY + + # Before we open our file, we want to delete any existing file that is + # there + try: + os.remove(filename) + except (IOError, OSError): + # The file must not exist already, so we can just skip ahead to opening + pass + + # Open our file, the use of os.O_CREAT | os.O_EXCL will ensure that if a + # race condition happens between the os.remove and this line, that an + # error will be raised. Because we utilize a lockfile this should only + # happen if someone is attempting to attack us. + fd = os.open(filename, flags, fmode) + try: + return os.fdopen(fd, "wb") + except: + # An error occurred wrapping our FD in a file object + os.close(fd) + raise + + +class FileCache(BaseCache): + def __init__(self, directory, forever=False, filemode=0o0600, + dirmode=0o0700, use_dir_lock=None, lock_class=None): + + if use_dir_lock is not None and lock_class is not None: + raise ValueError("Cannot use use_dir_lock and lock_class together") + + try: + from pip._vendor.lockfile import LockFile + from pip._vendor.lockfile.mkdirlockfile import MkdirLockFile + except ImportError: + notice = dedent(""" + NOTE: In order to use the FileCache you must have + lockfile installed. You can install it via pip: + pip install lockfile + """) + raise ImportError(notice) + else: + if use_dir_lock: + lock_class = MkdirLockFile + + elif lock_class is None: + lock_class = LockFile + + self.directory = directory + self.forever = forever + self.filemode = filemode + self.dirmode = dirmode + self.lock_class = lock_class + + @staticmethod + def encode(x): + return hashlib.sha224(x.encode()).hexdigest() + + def _fn(self, name): + # NOTE: This method should not change as some may depend on it. + # See: https://github.com/ionrock/cachecontrol/issues/63 + hashed = self.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key): + name = self._fn(key) + if not os.path.exists(name): + return None + + with open(name, 'rb') as fh: + return fh.read() + + def set(self, key, value): + name = self._fn(key) + + # Make sure the directory exists + try: + os.makedirs(os.path.dirname(name), self.dirmode) + except (IOError, OSError): + pass + + with self.lock_class(name) as lock: + # Write our actual file + with _secure_open_write(lock.path, self.filemode) as fh: + fh.write(value) + + def delete(self, key): + name = self._fn(key) + if not self.forever: + try: + os.remove(name) + except FileNotFoundError: + pass + + +def url_to_file_path(url, filecache): + """Return the file cache path based on the URL. + + This does not ensure the file exists! + """ + key = CacheController.cache_url(url) + return filecache._fn(key) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py new file mode 100755 index 0000000..db1e09d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/caches/redis_cache.py @@ -0,0 +1,43 @@ +from __future__ import division + +from datetime import datetime +from pip._vendor.cachecontrol.cache import BaseCache + + +def total_seconds(td): + """Python 2.6 compatability""" + if hasattr(td, 'total_seconds'): + return int(td.total_seconds()) + + ms = td.microseconds + secs = (td.seconds + td.days * 24 * 3600) + return int((ms + secs * 10**6) / 10**6) + + +class RedisCache(BaseCache): + + def __init__(self, conn): + self.conn = conn + + def get(self, key): + return self.conn.get(key) + + def set(self, key, value, expires=None): + if not expires: + self.conn.set(key, value) + else: + expires = expires - datetime.utcnow() + self.conn.setex(key, total_seconds(expires), value) + + def delete(self, key): + self.conn.delete(key) + + def clear(self): + """Helper for clearing all the keys in a database. Use with + caution!""" + for key in self.conn.keys(): + self.conn.delete(key) + + def close(self): + """Redis uses connection pooling, no need to close the connection.""" + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py new file mode 100755 index 0000000..e3f3243 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/compat.py @@ -0,0 +1,29 @@ +try: + from urllib.parse import urljoin +except ImportError: + from urlparse import urljoin + + +try: + import cPickle as pickle +except ImportError: + import pickle + + +# Handle the case where the requests module has been patched to not have +# urllib3 bundled as part of its source. +try: + from pip._vendor.requests.packages.urllib3.response import HTTPResponse +except ImportError: + from pip._vendor.urllib3.response import HTTPResponse + +try: + from pip._vendor.requests.packages.urllib3.util import is_fp_closed +except ImportError: + from pip._vendor.urllib3.util import is_fp_closed + +# Replicate some six behaviour +try: + text_type = unicode +except NameError: + text_type = str diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py new file mode 100755 index 0000000..bf4cc7f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/controller.py @@ -0,0 +1,373 @@ +""" +The httplib2 algorithms ported for use with requests. +""" +import logging +import re +import calendar +import time +from email.utils import parsedate_tz + +from pip._vendor.requests.structures import CaseInsensitiveDict + +from .cache import DictCache +from .serialize import Serializer + + +logger = logging.getLogger(__name__) + +URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") + + +def parse_uri(uri): + """Parses a URI using the regex given in Appendix B of RFC 3986. + + (scheme, authority, path, query, fragment) = parse_uri(uri) + """ + groups = URI.match(uri).groups() + return (groups[1], groups[3], groups[4], groups[6], groups[8]) + + +class CacheController(object): + """An interface to see if request should cached or not. + """ + def __init__(self, cache=None, cache_etags=True, serializer=None, + status_codes=None): + self.cache = cache or DictCache() + self.cache_etags = cache_etags + self.serializer = serializer or Serializer() + self.cacheable_status_codes = status_codes or (200, 203, 300, 301) + + @classmethod + def _urlnorm(cls, uri): + """Normalize the URL to create a safe key for the cache""" + (scheme, authority, path, query, fragment) = parse_uri(uri) + if not scheme or not authority: + raise Exception("Only absolute URIs are allowed. uri = %s" % uri) + + scheme = scheme.lower() + authority = authority.lower() + + if not path: + path = "/" + + # Could do syntax based normalization of the URI before + # computing the digest. See Section 6.2.2 of Std 66. + request_uri = query and "?".join([path, query]) or path + defrag_uri = scheme + "://" + authority + request_uri + + return defrag_uri + + @classmethod + def cache_url(cls, uri): + return cls._urlnorm(uri) + + def parse_cache_control(self, headers): + known_directives = { + # https://tools.ietf.org/html/rfc7234#section-5.2 + 'max-age': (int, True,), + 'max-stale': (int, False,), + 'min-fresh': (int, True,), + 'no-cache': (None, False,), + 'no-store': (None, False,), + 'no-transform': (None, False,), + 'only-if-cached' : (None, False,), + 'must-revalidate': (None, False,), + 'public': (None, False,), + 'private': (None, False,), + 'proxy-revalidate': (None, False,), + 's-maxage': (int, True,) + } + + cc_headers = headers.get('cache-control', + headers.get('Cache-Control', '')) + + retval = {} + + for cc_directive in cc_headers.split(','): + parts = cc_directive.split('=', 1) + directive = parts[0].strip() + + try: + typ, required = known_directives[directive] + except KeyError: + logger.debug('Ignoring unknown cache-control directive: %s', + directive) + continue + + if not typ or not required: + retval[directive] = None + if typ: + try: + retval[directive] = typ(parts[1].strip()) + except IndexError: + if required: + logger.debug('Missing value for cache-control ' + 'directive: %s', directive) + except ValueError: + logger.debug('Invalid value for cache-control directive ' + '%s, must be %s', directive, typ.__name__) + + return retval + + def cached_request(self, request): + """ + Return a cached response if it exists in the cache, otherwise + return False. + """ + cache_url = self.cache_url(request.url) + logger.debug('Looking up "%s" in the cache', cache_url) + cc = self.parse_cache_control(request.headers) + + # Bail out if the request insists on fresh data + if 'no-cache' in cc: + logger.debug('Request header has "no-cache", cache bypassed') + return False + + if 'max-age' in cc and cc['max-age'] == 0: + logger.debug('Request header has "max_age" as 0, cache bypassed') + return False + + # Request allows serving from the cache, let's see if we find something + cache_data = self.cache.get(cache_url) + if cache_data is None: + logger.debug('No cache entry available') + return False + + # Check whether it can be deserialized + resp = self.serializer.loads(request, cache_data) + if not resp: + logger.warning('Cache entry deserialization failed, entry ignored') + return False + + # If we have a cached 301, return it immediately. We don't + # need to test our response for other headers b/c it is + # intrinsically "cacheable" as it is Permanent. + # See: + # https://tools.ietf.org/html/rfc7231#section-6.4.2 + # + # Client can try to refresh the value by repeating the request + # with cache busting headers as usual (ie no-cache). + if resp.status == 301: + msg = ('Returning cached "301 Moved Permanently" response ' + '(ignoring date and etag information)') + logger.debug(msg) + return resp + + headers = CaseInsensitiveDict(resp.headers) + if not headers or 'date' not in headers: + if 'etag' not in headers: + # Without date or etag, the cached response can never be used + # and should be deleted. + logger.debug('Purging cached response: no date or etag') + self.cache.delete(cache_url) + logger.debug('Ignoring cached response: no date') + return False + + now = time.time() + date = calendar.timegm( + parsedate_tz(headers['date']) + ) + current_age = max(0, now - date) + logger.debug('Current age based on date: %i', current_age) + + # TODO: There is an assumption that the result will be a + # urllib3 response object. This may not be best since we + # could probably avoid instantiating or constructing the + # response until we know we need it. + resp_cc = self.parse_cache_control(headers) + + # determine freshness + freshness_lifetime = 0 + + # Check the max-age pragma in the cache control header + if 'max-age' in resp_cc: + freshness_lifetime = resp_cc['max-age'] + logger.debug('Freshness lifetime from max-age: %i', + freshness_lifetime) + + # If there isn't a max-age, check for an expires header + elif 'expires' in headers: + expires = parsedate_tz(headers['expires']) + if expires is not None: + expire_time = calendar.timegm(expires) - date + freshness_lifetime = max(0, expire_time) + logger.debug("Freshness lifetime from expires: %i", + freshness_lifetime) + + # Determine if we are setting freshness limit in the + # request. Note, this overrides what was in the response. + if 'max-age' in cc: + freshness_lifetime = cc['max-age'] + logger.debug('Freshness lifetime from request max-age: %i', + freshness_lifetime) + + if 'min-fresh' in cc: + min_fresh = cc['min-fresh'] + # adjust our current age by our min fresh + current_age += min_fresh + logger.debug('Adjusted current age from min-fresh: %i', + current_age) + + # Return entry if it is fresh enough + if freshness_lifetime > current_age: + logger.debug('The response is "fresh", returning cached response') + logger.debug('%i > %i', freshness_lifetime, current_age) + return resp + + # we're not fresh. If we don't have an Etag, clear it out + if 'etag' not in headers: + logger.debug( + 'The cached response is "stale" with no etag, purging' + ) + self.cache.delete(cache_url) + + # return the original handler + return False + + def conditional_headers(self, request): + cache_url = self.cache_url(request.url) + resp = self.serializer.loads(request, self.cache.get(cache_url)) + new_headers = {} + + if resp: + headers = CaseInsensitiveDict(resp.headers) + + if 'etag' in headers: + new_headers['If-None-Match'] = headers['ETag'] + + if 'last-modified' in headers: + new_headers['If-Modified-Since'] = headers['Last-Modified'] + + return new_headers + + def cache_response(self, request, response, body=None, + status_codes=None): + """ + Algorithm for caching requests. + + This assumes a requests Response object. + """ + # From httplib2: Don't cache 206's since we aren't going to + # handle byte range requests + cacheable_status_codes = status_codes or self.cacheable_status_codes + if response.status not in cacheable_status_codes: + logger.debug( + 'Status code %s not in %s', + response.status, + cacheable_status_codes + ) + return + + response_headers = CaseInsensitiveDict(response.headers) + + # If we've been given a body, our response has a Content-Length, that + # Content-Length is valid then we can check to see if the body we've + # been given matches the expected size, and if it doesn't we'll just + # skip trying to cache it. + if (body is not None and + "content-length" in response_headers and + response_headers["content-length"].isdigit() and + int(response_headers["content-length"]) != len(body)): + return + + cc_req = self.parse_cache_control(request.headers) + cc = self.parse_cache_control(response_headers) + + cache_url = self.cache_url(request.url) + logger.debug('Updating cache with response from "%s"', cache_url) + + # Delete it from the cache if we happen to have it stored there + no_store = False + if 'no-store' in cc: + no_store = True + logger.debug('Response header has "no-store"') + if 'no-store' in cc_req: + no_store = True + logger.debug('Request header has "no-store"') + if no_store and self.cache.get(cache_url): + logger.debug('Purging existing cache entry to honor "no-store"') + self.cache.delete(cache_url) + + # If we've been given an etag, then keep the response + if self.cache_etags and 'etag' in response_headers: + logger.debug('Caching due to etag') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + # Add to the cache any 301s. We do this before looking that + # the Date headers. + elif response.status == 301: + logger.debug('Caching permanant redirect') + self.cache.set( + cache_url, + self.serializer.dumps(request, response) + ) + + # Add to the cache if the response headers demand it. If there + # is no date header then we can't do anything about expiring + # the cache. + elif 'date' in response_headers: + # cache when there is a max-age > 0 + if 'max-age' in cc and cc['max-age'] > 0: + logger.debug('Caching b/c date exists and max-age > 0') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + # If the request can expire, it means we should cache it + # in the meantime. + elif 'expires' in response_headers: + if response_headers['expires']: + logger.debug('Caching b/c of expires header') + self.cache.set( + cache_url, + self.serializer.dumps(request, response, body=body), + ) + + def update_cached_response(self, request, response): + """On a 304 we will get a new set of headers that we want to + update our cached value with, assuming we have one. + + This should only ever be called when we've sent an ETag and + gotten a 304 as the response. + """ + cache_url = self.cache_url(request.url) + + cached_response = self.serializer.loads( + request, + self.cache.get(cache_url) + ) + + if not cached_response: + # we didn't have a cached response + return response + + # Lets update our headers with the headers from the new request: + # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1 + # + # The server isn't supposed to send headers that would make + # the cached body invalid. But... just in case, we'll be sure + # to strip out ones we know that might be problmatic due to + # typical assumptions. + excluded_headers = [ + "content-length", + ] + + cached_response.headers.update( + dict((k, v) for k, v in response.headers.items() + if k.lower() not in excluded_headers) + ) + + # we want a 200 b/c we have content via the cache + cached_response.status = 200 + + # update our cache + self.cache.set( + cache_url, + self.serializer.dumps(request, cached_response), + ) + + return cached_response diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py new file mode 100755 index 0000000..83ce912 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/filewrapper.py @@ -0,0 +1,78 @@ +from io import BytesIO + + +class CallbackFileWrapper(object): + """ + Small wrapper around a fp object which will tee everything read into a + buffer, and when that file is closed it will execute a callback with the + contents of that buffer. + + All attributes are proxied to the underlying file object. + + This class uses members with a double underscore (__) leading prefix so as + not to accidentally shadow an attribute. + """ + + def __init__(self, fp, callback): + self.__buf = BytesIO() + self.__fp = fp + self.__callback = callback + + def __getattr__(self, name): + # The vaguaries of garbage collection means that self.__fp is + # not always set. By using __getattribute__ and the private + # name[0] allows looking up the attribute value and raising an + # AttributeError when it doesn't exist. This stop thigns from + # infinitely recursing calls to getattr in the case where + # self.__fp hasn't been set. + # + # [0] https://docs.python.org/2/reference/expressions.html#atom-identifiers + fp = self.__getattribute__('_CallbackFileWrapper__fp') + return getattr(fp, name) + + def __is_fp_closed(self): + try: + return self.__fp.fp is None + except AttributeError: + pass + + try: + return self.__fp.closed + except AttributeError: + pass + + # We just don't cache it then. + # TODO: Add some logging here... + return False + + def _close(self): + if self.__callback: + self.__callback(self.__buf.getvalue()) + + # We assign this to None here, because otherwise we can get into + # really tricky problems where the CPython interpreter dead locks + # because the callback is holding a reference to something which + # has a __del__ method. Setting this to None breaks the cycle + # and allows the garbage collector to do it's thing normally. + self.__callback = None + + def read(self, amt=None): + data = self.__fp.read(amt) + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data + + def _safe_read(self, amt): + data = self.__fp._safe_read(amt) + if amt == 2 and data == b'\r\n': + # urllib executes this read to toss the CRLF at the end + # of the chunk. + return data + + self.__buf.write(data) + if self.__is_fp_closed(): + self._close() + + return data diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py new file mode 100755 index 0000000..aad333d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/heuristics.py @@ -0,0 +1,138 @@ +import calendar +import time + +from email.utils import formatdate, parsedate, parsedate_tz + +from datetime import datetime, timedelta + +TIME_FMT = "%a, %d %b %Y %H:%M:%S GMT" + + +def expire_after(delta, date=None): + date = date or datetime.utcnow() + return date + delta + + +def datetime_to_header(dt): + return formatdate(calendar.timegm(dt.timetuple())) + + +class BaseHeuristic(object): + + def warning(self, response): + """ + Return a valid 1xx warning header value describing the cache + adjustments. + + The response is provided too allow warnings like 113 + http://tools.ietf.org/html/rfc7234#section-5.5.4 where we need + to explicitly say response is over 24 hours old. + """ + return '110 - "Response is Stale"' + + def update_headers(self, response): + """Update the response headers with any new headers. + + NOTE: This SHOULD always include some Warning header to + signify that the response was cached by the client, not + by way of the provided headers. + """ + return {} + + def apply(self, response): + updated_headers = self.update_headers(response) + + if updated_headers: + response.headers.update(updated_headers) + warning_header_value = self.warning(response) + if warning_header_value is not None: + response.headers.update({'Warning': warning_header_value}) + + return response + + +class OneDayCache(BaseHeuristic): + """ + Cache the response by providing an expires 1 day in the + future. + """ + def update_headers(self, response): + headers = {} + + if 'expires' not in response.headers: + date = parsedate(response.headers['date']) + expires = expire_after(timedelta(days=1), + date=datetime(*date[:6])) + headers['expires'] = datetime_to_header(expires) + headers['cache-control'] = 'public' + return headers + + +class ExpiresAfter(BaseHeuristic): + """ + Cache **all** requests for a defined time period. + """ + + def __init__(self, **kw): + self.delta = timedelta(**kw) + + def update_headers(self, response): + expires = expire_after(self.delta) + return { + 'expires': datetime_to_header(expires), + 'cache-control': 'public', + } + + def warning(self, response): + tmpl = '110 - Automatically cached for %s. Response might be stale' + return tmpl % self.delta + + +class LastModified(BaseHeuristic): + """ + If there is no Expires header already, fall back on Last-Modified + using the heuristic from + http://tools.ietf.org/html/rfc7234#section-4.2.2 + to calculate a reasonable value. + + Firefox also does something like this per + https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ + http://lxr.mozilla.org/mozilla-release/source/netwerk/protocol/http/nsHttpResponseHead.cpp#397 + Unlike mozilla we limit this to 24-hr. + """ + cacheable_by_default_statuses = set([ + 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501 + ]) + + def update_headers(self, resp): + headers = resp.headers + + if 'expires' in headers: + return {} + + if 'cache-control' in headers and headers['cache-control'] != 'public': + return {} + + if resp.status not in self.cacheable_by_default_statuses: + return {} + + if 'date' not in headers or 'last-modified' not in headers: + return {} + + date = calendar.timegm(parsedate_tz(headers['date'])) + last_modified = parsedate(headers['last-modified']) + if date is None or last_modified is None: + return {} + + now = time.time() + current_age = max(0, now - date) + delta = date - calendar.timegm(last_modified) + freshness_lifetime = max(0, min(delta / 10, 24 * 3600)) + if freshness_lifetime <= current_age: + return {} + + expires = date + freshness_lifetime + return {'expires': time.strftime(TIME_FMT, time.gmtime(expires))} + + def warning(self, resp): + return None diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py new file mode 100755 index 0000000..cd21cae --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/serialize.py @@ -0,0 +1,194 @@ +import base64 +import io +import json +import zlib + +from pip._vendor import msgpack +from pip._vendor.requests.structures import CaseInsensitiveDict + +from .compat import HTTPResponse, pickle, text_type + + +def _b64_decode_bytes(b): + return base64.b64decode(b.encode("ascii")) + + +def _b64_decode_str(s): + return _b64_decode_bytes(s).decode("utf8") + + +class Serializer(object): + + def dumps(self, request, response, body=None): + response_headers = CaseInsensitiveDict(response.headers) + + if body is None: + body = response.read(decode_content=False) + + # NOTE: 99% sure this is dead code. I'm only leaving it + # here b/c I don't have a test yet to prove + # it. Basically, before using + # `cachecontrol.filewrapper.CallbackFileWrapper`, + # this made an effort to reset the file handle. The + # `CallbackFileWrapper` short circuits this code by + # setting the body as the content is consumed, the + # result being a `body` argument is *always* passed + # into cache_response, and in turn, + # `Serializer.dump`. + response._fp = io.BytesIO(body) + + # NOTE: This is all a bit weird, but it's really important that on + # Python 2.x these objects are unicode and not str, even when + # they contain only ascii. The problem here is that msgpack + # understands the difference between unicode and bytes and we + # have it set to differentiate between them, however Python 2 + # doesn't know the difference. Forcing these to unicode will be + # enough to have msgpack know the difference. + data = { + u"response": { + u"body": body, + u"headers": dict( + (text_type(k), text_type(v)) + for k, v in response.headers.items() + ), + u"status": response.status, + u"version": response.version, + u"reason": text_type(response.reason), + u"strict": response.strict, + u"decode_content": response.decode_content, + }, + } + + # Construct our vary headers + data[u"vary"] = {} + if u"vary" in response_headers: + varied_headers = response_headers[u'vary'].split(',') + for header in varied_headers: + header = header.strip() + header_value = request.headers.get(header, None) + if header_value is not None: + header_value = text_type(header_value) + data[u"vary"][header] = header_value + + return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)]) + + def loads(self, request, data): + # Short circuit if we've been given an empty set of data + if not data: + return + + # Determine what version of the serializer the data was serialized + # with + try: + ver, data = data.split(b",", 1) + except ValueError: + ver = b"cc=0" + + # Make sure that our "ver" is actually a version and isn't a false + # positive from a , being in the data stream. + if ver[:3] != b"cc=": + data = ver + data + ver = b"cc=0" + + # Get the version number out of the cc=N + ver = ver.split(b"=", 1)[-1].decode("ascii") + + # Dispatch to the actual load method for the given version + try: + return getattr(self, "_loads_v{0}".format(ver))(request, data) + except AttributeError: + # This is a version we don't have a loads function for, so we'll + # just treat it as a miss and return None + return + + def prepare_response(self, request, cached): + """Verify our vary headers match and construct a real urllib3 + HTTPResponse object. + """ + # Special case the '*' Vary value as it means we cannot actually + # determine if the cached response is suitable for this request. + if "*" in cached.get("vary", {}): + return + + # Ensure that the Vary headers for the cached response match our + # request + for header, value in cached.get("vary", {}).items(): + if request.headers.get(header, None) != value: + return + + body_raw = cached["response"].pop("body") + + headers = CaseInsensitiveDict(data=cached['response']['headers']) + if headers.get('transfer-encoding', '') == 'chunked': + headers.pop('transfer-encoding') + + cached['response']['headers'] = headers + + try: + body = io.BytesIO(body_raw) + except TypeError: + # This can happen if cachecontrol serialized to v1 format (pickle) + # using Python 2. A Python 2 str(byte string) will be unpickled as + # a Python 3 str (unicode string), which will cause the above to + # fail with: + # + # TypeError: 'str' does not support the buffer interface + body = io.BytesIO(body_raw.encode('utf8')) + + return HTTPResponse( + body=body, + preload_content=False, + **cached["response"] + ) + + def _loads_v0(self, request, data): + # The original legacy cache data. This doesn't contain enough + # information to construct everything we need, so we'll treat this as + # a miss. + return + + def _loads_v1(self, request, data): + try: + cached = pickle.loads(data) + except ValueError: + return + + return self.prepare_response(request, cached) + + def _loads_v2(self, request, data): + try: + cached = json.loads(zlib.decompress(data).decode("utf8")) + except (ValueError, zlib.error): + return + + # We need to decode the items that we've base64 encoded + cached["response"]["body"] = _b64_decode_bytes( + cached["response"]["body"] + ) + cached["response"]["headers"] = dict( + (_b64_decode_str(k), _b64_decode_str(v)) + for k, v in cached["response"]["headers"].items() + ) + cached["response"]["reason"] = _b64_decode_str( + cached["response"]["reason"], + ) + cached["vary"] = dict( + (_b64_decode_str(k), _b64_decode_str(v) if v is not None else v) + for k, v in cached["vary"].items() + ) + + return self.prepare_response(request, cached) + + def _loads_v3(self, request, data): + # Due to Python 2 encoding issues, it's impossible to know for sure + # exactly how to load v3 entries, thus we'll treat these as a miss so + # that they get rewritten out as v4 entries. + return + + def _loads_v4(self, request, data): + try: + cached = msgpack.loads(data, encoding='utf-8') + except ValueError: + return + + return self.prepare_response(request, cached) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py new file mode 100755 index 0000000..2ceac99 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/cachecontrol/wrapper.py @@ -0,0 +1,27 @@ +from .adapter import CacheControlAdapter +from .cache import DictCache + + +def CacheControl(sess, + cache=None, + cache_etags=True, + serializer=None, + heuristic=None, + controller_class=None, + adapter_class=None, + cacheable_methods=None): + + cache = cache or DictCache() + adapter_class = adapter_class or CacheControlAdapter + adapter = adapter_class( + cache, + cache_etags=cache_etags, + serializer=serializer, + heuristic=heuristic, + controller_class=controller_class, + cacheable_methods=cacheable_methods + ) + sess.mount('http://', adapter) + sess.mount('https://', adapter) + + return sess diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py new file mode 100755 index 0000000..3d73ece --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import where, old_where + +__version__ = "2018.01.18" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py new file mode 100755 index 0000000..e30b50d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/__main__.py @@ -0,0 +1,2 @@ +from certifi import where +print(where()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem new file mode 100755 index 0000000..101ac98 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/cacert.pem @@ -0,0 +1,4433 @@ + +# 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=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only +# Label: "Verisign Class 3 Public Primary Certification Authority - G3" +# Serial: 206684696279472310254277870180966723415 +# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09 +# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6 +# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----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=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network +# Label: "AddTrust External Root" +# Serial: 1 +# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f +# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68 +# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2 +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----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=GeoTrust Global CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. +# Label: "GeoTrust Global CA" +# Serial: 144470 +# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 +# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 +# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Label: "GeoTrust Universal CA" +# Serial: 1 +# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 +# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 +# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Universal CA 2" +# Serial: 1 +# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 +# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 +# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +# Issuer: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Subject: CN=Visa eCommerce Root O=VISA OU=Visa International Service Association +# Label: "Visa eCommerce Root" +# Serial: 25952180776285836048024890241505565794 +# MD5 Fingerprint: fc:11:b8:d8:08:93:30:00:6d:23:f9:7e:eb:52:1e:02 +# SHA1 Fingerprint: 70:17:9b:86:8c:00:a4:fa:60:91:52:22:3f:9f:3e:32:bd:e0:05:62 +# SHA256 Fingerprint: 69:fa:c9:bd:55:fb:0a:c7:8d:53:bb:ee:5c:f1:d5:97:98:9f:d0:aa:ab:20:a2:51:51:bd:f1:73:3e:e7:d1:22 +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----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 Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Label: "QuoVadis Root CA" +# Serial: 985026699 +# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 +# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 +# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----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=Sonera Class2 CA O=Sonera +# Subject: CN=Sonera Class2 CA O=Sonera +# Label: "Sonera Class 2 Root CA" +# Serial: 29 +# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb +# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 +# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----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: O=Government Root Certification Authority +# Subject: O=Government Root Certification Authority +# Label: "Taiwan GRCA" +# Serial: 42023070807708724159991140556527066870 +# MD5 Fingerprint: 37:85:44:53:32:45:1f:20:f0:f3:95:e1:25:c4:43:4e +# SHA1 Fingerprint: f4:8b:11:bf:de:ab:be:94:54:20:71:e6:41:de:6b:be:88:2b:40:b9 +# SHA256 Fingerprint: 76:00:29:5e:ef:e8:5b:9e:1f:d6:24:db:76:06:2a:aa:ae:59:81:8a:54:d2:77:4c:d4:c0:b2:c0:11:31:e1:b3 +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----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=Class 2 Primary CA O=Certplus +# Subject: CN=Class 2 Primary CA O=Certplus +# Label: "Certplus Class 2 Primary CA" +# Serial: 177770208045934040241468760488327595043 +# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b +# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb +# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----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----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----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----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Label: "GeoTrust Primary Certification Authority" +# Serial: 32798226551256963324313806436981982369 +# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf +# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 +# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA" +# Serial: 69529181992039203566298953787712940909 +# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 +# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 +# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" +# Serial: 33037644167568058970164719475676101450 +# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c +# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 +# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----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=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GA CA O=WISeKey OU=Copyright (c) 2005/OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GA CA" +# Serial: 86718877871133159090080555911823548314 +# MD5 Fingerprint: bc:6c:51:33:a7:e9:d3:66:63:54:15:72:1b:21:92:93 +# SHA1 Fingerprint: 59:22:a1:e1:5a:ea:16:35:21:f8:98:39:6a:46:46:b0:44:1b:0f:a9 +# SHA256 Fingerprint: 41:c9:23:86:6a:b4:ca:d6:b7:ad:57:80:81:58:2e:02:07:97:a6:cb:df:4f:ff:78:ce:83:96:b3:89:37:d7:f5 +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----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=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center +# Label: "Deutsche Telekom Root CA 2" +# Serial: 38 +# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08 +# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf +# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3 +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----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=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G3" +# Serial: 28809105769928564313984085209975885599 +# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 +# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd +# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G2" +# Serial: 71758320672825410020661621085256472406 +# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f +# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 +# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G3" +# Serial: 127614157056681299805556476275995414779 +# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 +# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 +# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G2" +# Serial: 80682863203381065782177908751794619243 +# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a +# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 +# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Universal Root Certification Authority" +# Serial: 85209574734084581917763752644031726877 +# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 +# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 +# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" +# Serial: 63143484348153506665311985501458640051 +# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 +# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a +# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----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=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G2" +# Serial: 10000012 +# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a +# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16 +# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----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----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Label: "Chambers of Commerce Root - 2008" +# Serial: 11806822484801597146 +# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 +# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c +# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- + +# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Label: "Global Chambersign Root - 2008" +# Serial: 14541511773111788494 +# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 +# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c +# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----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=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: O=Trustis Limited OU=Trustis FPS Root CA +# Subject: O=Trustis Limited OU=Trustis FPS Root CA +# Label: "Trustis FPS Root CA" +# Serial: 36053640375399034304724988975563710553 +# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d +# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 +# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----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=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Subject: CN=EE Certification Centre Root CA O=AS Sertifitseerimiskeskus +# Label: "EE Certification Centre Root CA" +# Serial: 112324828676200291871926431888494945866 +# MD5 Fingerprint: 43:5e:88:d4:7d:1a:4a:7e:fd:84:2e:52:eb:01:d4:6f +# SHA1 Fingerprint: c9:a8:b9:e7:55:80:5e:58:e3:53:77:a7:25:eb:af:c3:7b:27:cc:d7 +# SHA256 Fingerprint: 3e:84:ba:43:42:90:85:16:e7:75:73:c0:99:2f:09:79:ca:08:4e:46:85:68:1f:f1:95:cc:ba:8a:22:9b:8a:76 +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----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 Root CA - G3 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G3" +# Serial: 10003001 +# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37 +# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc +# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----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=T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5 O=T\xdcRKTRUST Bilgi \u0130leti\u015fim ve Bili\u015fim G\xfcvenli\u011fi Hizmetleri A.\u015e. +# Subject: CN=T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5 O=T\xdcRKTRUST Bilgi \u0130leti\u015fim ve Bili\u015fim G\xfcvenli\u011fi Hizmetleri A.\u015e. +# Label: "T\xdcRKTRUST Elektronik Sertifika Hizmet Sa\u011flay\u0131c\u0131s\u0131 H5" +# Serial: 156233699172481 +# MD5 Fingerprint: da:70:8e:f0:22:df:93:26:f6:5f:9f:d3:15:06:52:4e +# SHA1 Fingerprint: c4:18:f6:4d:46:d1:df:00:3d:27:30:13:72:43:a9:12:11:c6:75:fb +# SHA256 Fingerprint: 49:35:1b:90:34:44:c1:85:cc:dc:5c:69:3d:24:d8:55:5c:b2:08:d6:a8:14:13:07:69:9f:4a:f0:63:19:9d:78 +-----BEGIN CERTIFICATE----- +MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE +BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn +aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg +QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0 +MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD +VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 +dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom +/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR +Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3 +4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z +5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0 +hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID +AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX +SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l +VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq +URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf +peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF +Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW ++qtB4Uu2NQvAmxU= +-----END CERTIFICATE----- + +# Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903 +# Label: "Certinomis - Root CA" +# Serial: 1 +# MD5 Fingerprint: 14:0a:fd:8d:a8:28:b5:38:69:db:56:7e:61:22:03:3f +# SHA1 Fingerprint: 9d:70:bb:01:a5:a4:a0:18:11:2e:f7:1c:01:b9:32:c5:34:e7:88:a8 +# SHA256 Fingerprint: 2a:99:f5:bc:11:74:b7:3c:bb:1d:62:08:84:e0:1c:34:e5:1c:cb:39:78:da:12:5f:0e:33:26:88:83:bf:41:58 +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----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=Certplus Root CA G1 O=Certplus +# Subject: CN=Certplus Root CA G1 O=Certplus +# Label: "Certplus Root CA G1" +# Serial: 1491911565779898356709731176965615564637713 +# MD5 Fingerprint: 7f:09:9c:f7:d9:b9:5c:69:69:56:d5:37:3e:14:0d:42 +# SHA1 Fingerprint: 22:fd:d0:b7:fd:a2:4e:0d:ac:49:2c:a0:ac:a6:7b:6a:1f:e3:f7:66 +# SHA256 Fingerprint: 15:2a:40:2b:fc:df:2c:d5:48:05:4d:22:75:b3:9c:7f:ca:3e:c0:97:80:78:b0:f0:ea:76:e5:61:a6:c7:43:3e +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a +iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt +6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP +0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f +6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE +EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN +1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc +h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT +mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV +4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO +WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd +Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq +hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh +66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 +/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS +S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j +2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R +Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr +RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy +6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV +V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 +g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl +++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= +-----END CERTIFICATE----- + +# Issuer: CN=Certplus Root CA G2 O=Certplus +# Subject: CN=Certplus Root CA G2 O=Certplus +# Label: "Certplus Root CA G2" +# Serial: 1492087096131536844209563509228951875861589 +# MD5 Fingerprint: a7:ee:c4:78:2d:1b:ee:2d:b9:29:ce:d6:a7:96:32:31 +# SHA1 Fingerprint: 4f:65:8e:1f:e9:06:d8:28:02:e9:54:47:41:c9:54:25:5d:69:cc:1a +# SHA256 Fingerprint: 6c:c0:50:41:e6:44:5e:74:69:6c:4c:fb:c9:f8:0f:54:3b:7e:ab:bb:44:b4:ce:6f:78:7c:6a:99:71:c4:2f:17 +-----BEGIN CERTIFICATE----- +MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat +93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x +Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj +FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG +SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch +p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal +U5ORGpOucGpnutee5WEaXw== +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G1 O=OpenTrust +# Subject: CN=OpenTrust Root CA G1 O=OpenTrust +# Label: "OpenTrust Root CA G1" +# Serial: 1492036577811947013770400127034825178844775 +# MD5 Fingerprint: 76:00:cc:81:29:cd:55:5e:88:6a:7a:2e:f7:4d:39:da +# SHA1 Fingerprint: 79:91:e8:34:f7:e2:ee:dd:08:95:01:52:e9:55:2d:14:e9:58:d5:7e +# SHA256 Fingerprint: 56:c7:71:28:d9:8c:18:d9:1b:4c:fd:ff:bc:25:ee:91:03:d4:75:8e:a2:ab:ad:82:6a:90:f3:45:7d:46:0e:b4 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b +wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX +/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0 +77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP +uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx +p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx +Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2 +TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W +G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw +vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY +EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1 +2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw +DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E +PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf +gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS +FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0 +V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P +XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I +i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t +TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91 +09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky +Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ +AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj +1oxx +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G2 O=OpenTrust +# Subject: CN=OpenTrust Root CA G2 O=OpenTrust +# Label: "OpenTrust Root CA G2" +# Serial: 1492012448042702096986875987676935573415441 +# MD5 Fingerprint: 57:24:b6:59:24:6b:ae:c8:fe:1c:0c:20:f2:c0:4e:eb +# SHA1 Fingerprint: 79:5f:88:60:c5:ab:7c:3d:92:e6:cb:f4:8d:e1:45:cd:11:ef:60:0b +# SHA256 Fingerprint: 27:99:58:29:fe:6a:75:15:c1:bf:e8:48:f9:c4:76:1d:b1:6c:22:59:29:25:7b:f4:0d:08:94:f2:9e:a8:ba:f2 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh +/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e +CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 +1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE +FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS +gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X +G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy +YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH +vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 +t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ +gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 +5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w +DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz +Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 +nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT +RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT +wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 +t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa +TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 +o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU +3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA +iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f +WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM +S1IK +-----END CERTIFICATE----- + +# Issuer: CN=OpenTrust Root CA G3 O=OpenTrust +# Subject: CN=OpenTrust Root CA G3 O=OpenTrust +# Label: "OpenTrust Root CA G3" +# Serial: 1492104908271485653071219941864171170455615 +# MD5 Fingerprint: 21:37:b4:17:16:92:7b:67:46:70:a9:96:d7:a8:13:24 +# SHA1 Fingerprint: 6e:26:64:f3:56:bf:34:55:bf:d1:93:3f:7c:01:de:d8:13:da:8a:a6 +# SHA256 Fingerprint: b7:c3:62:31:70:6e:81:07:8c:36:7c:b8:96:19:8f:1e:32:08:dd:92:69:49:dd:8f:57:09:a4:10:f7:5b:62:92 +-----BEGIN CERTIFICATE----- +MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx +CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U +cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow +QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl +blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm +3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d +oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 +DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK +BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q +j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx +4nxp5V2a+EEfOzmTk51V6s2N8fvB +-----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=LuxTrust Global Root 2 O=LuxTrust S.A. +# Subject: CN=LuxTrust Global Root 2 O=LuxTrust S.A. +# Label: "LuxTrust Global Root 2" +# Serial: 59914338225734147123941058376788110305822489521 +# MD5 Fingerprint: b2:e1:09:00:61:af:f7:f1:91:6f:c4:ad:8d:5e:3b:7c +# SHA1 Fingerprint: 1e:0e:56:19:0a:d1:8b:25:98:b2:04:44:ff:66:8a:04:17:99:5f:3f +# SHA256 Fingerprint: 54:45:5f:71:29:c2:0b:14:47:c4:18:f9:97:16:8f:24:c5:8f:c5:02:3b:f5:da:5b:e2:eb:6e:1d:d8:90:2e:d5 +-----BEGIN CERTIFICATE----- +MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL +BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV +BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw +MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B +LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F +ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem +hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1 +EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn +Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4 +zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ +96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m +j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g +DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+ +8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j +X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH +hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB +KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0 +Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT ++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL +BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9 +BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO +jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9 +loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c +qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+ +2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/ +JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre +zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf +LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+ +x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6 +oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr +-----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----- diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py new file mode 100755 index 0000000..0ac5ee1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/certifi/core.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem. +""" +import os +import warnings + + +class DeprecatedBundleWarning(DeprecationWarning): + """ + The weak security bundle is being deprecated. Please bother your service + provider to get them to stop using cross-signed roots. + """ + + +def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, 'cacert.pem') + + +def old_where(): + warnings.warn( + "The weak security bundle has been removed. certifi.old_where() is now an alias " + "of certifi.where(). Please update your code to use certifi.where() instead. " + "certifi.old_where() will be removed in 2018.", + DeprecatedBundleWarning + ) + return where() + +if __name__ == '__main__': + print(where()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py new file mode 100755 index 0000000..45bf7e6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/__init__.py @@ -0,0 +1,39 @@ +######################## 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 .compat import PY2, PY3 +from .universaldetector import UniversalDetector +from .version import __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: ' + '{0}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5freq.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5freq.py new file mode 100755 index 0000000..88023ae --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 +# <http://www.edu.tw:81/mandr/> +# +# 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5prober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/big5prober.py new file mode 100755 index 0000000..5b1227a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/chardistribution.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/chardistribution.py new file mode 100755 index 0000000..e5509a0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py new file mode 100755 index 0000000..1720ddc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## 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 + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/charsetprober.py new file mode 100755 index 0000000..1fc2746 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py new file mode 100755 index 0000000..d3f5a12 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py new file mode 100755 index 0000000..daabecd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cli/chardetect.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" +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 pip._vendor.chardet import __version__ +from pip._vendor.chardet.compat import PY2 +from pip._vendor.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 '{0}: {1} with confidence {2}'.format(name, result['encoding'], + result['confidence']) + else: + return '{0}: 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 {0}'.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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/codingstatemachine.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/codingstatemachine.py new file mode 100755 index 0000000..c562e1d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py new file mode 100755 index 0000000..fa100a3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/compat.py @@ -0,0 +1,34 @@ +######################## 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 + base_str = (str, unicode) + text_type = unicode +else: + PY2 = False + PY3 = True + base_str = (bytes, str) + text_type = str diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cp949prober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/cp949prober.py new file mode 100755 index 0000000..de0ceab --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/enums.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/enums.py new file mode 100755 index 0000000..c8e6001 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escprober.py new file mode 100755 index 0000000..c52060d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escsm.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/escsm.py new file mode 100755 index 0000000..b837704 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/eucjpprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/eucjpprober.py new file mode 100755 index 0000000..a81ee1e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrfreq.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrfreq.py new file mode 100755 index 0000000..ae25c1b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euckrprober.py new file mode 100755 index 0000000..99d5b15 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwfreq.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwfreq.py new file mode 100755 index 0000000..5195275 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 +# <http:#www.edu.tw:81/mandr/> + +# 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/euctwprober.py new file mode 100755 index 0000000..7dbc136 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312freq.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312freq.py new file mode 100755 index 0000000..a0167b3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312prober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/gb2312prober.py new file mode 100755 index 0000000..7cae6b5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/hebrewprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/hebrewprober.py new file mode 100755 index 0000000..10b8122 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jisfreq.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jisfreq.py new file mode 100755 index 0000000..510b940 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jpcntx.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/jpcntx.py new file mode 100755 index 0000000..624d534 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py new file mode 100755 index 0000000..eb6f19a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { + 'char_to_order_map': Latin5_BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Bulgairan', +} + +Win1251BulgarianModel = { + 'char_to_order_map': win1251BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Bulgarian', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py new file mode 100755 index 0000000..bdbad70 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langcyrillicmodel.py @@ -0,0 +1,333 @@ +######################## 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 ######################### + +# KOI8-R language model +# Character Mapping Table: +KOI8R_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { + 'char_to_order_map': KOI8R_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "KOI8-R", + 'language': 'Russian', +} + +Win1251CyrillicModel = { + 'char_to_order_map': win1251_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Russian', +} + +Latin5CyrillicModel = { + 'char_to_order_map': latin5_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Russian', +} + +MacCyrillicModel = { + 'char_to_order_map': macCyrillic_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "MacCyrillic", + 'language': 'Russian', +} + +Ibm866Model = { + 'char_to_order_map': IBM866_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM866", + 'language': 'Russian', +} + +Ibm855Model = { + 'char_to_order_map': IBM855_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM855", + 'language': 'Russian', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py new file mode 100755 index 0000000..73541cc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { + 'char_to_order_map': Latin7_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-7", + 'language': 'Greek', +} + +Win1253GreekModel = { + 'char_to_order_map': win1253_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "windows-1253", + 'language': 'Greek', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py new file mode 100755 index 0000000..07029b6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhebrewmodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +WIN1255_CHAR_TO_ORDER_MAP = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HEBREW_LANG_MODEL = ( +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { + 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, + 'precedence_matrix': HEBREW_LANG_MODEL, + 'typical_positive_ratio': 0.984004, + 'keep_english_letter': False, + 'charset_name': "windows-1255", + 'language': 'Hebrew', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py new file mode 100755 index 0000000..6de87b7 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { + 'char_to_order_map': Latin2_HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-2", + 'language': 'Hungarian', +} + +Win1250HungarianModel = { + 'char_to_order_map': win1250HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "windows-1250", + 'language': 'Hungarian', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py new file mode 100755 index 0000000..fdb3313 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langthaimodel.py @@ -0,0 +1,199 @@ +######################## 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 ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { + 'char_to_order_map': TIS620CharToOrderMap, + 'precedence_matrix': ThaiLangModel, + 'typical_positive_ratio': 0.926386, + 'keep_english_letter': False, + 'charset_name': "TIS-620", + 'language': 'Thai', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py new file mode 100755 index 0000000..64ec9bd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/langturkishmodel.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +######################## 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 +# Özgür Baskın - Turkish Language Model +# +# 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 ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin5_TurkishCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, + 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, +255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, + 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, +180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, +164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, +150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, + 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, +124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, + 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, + 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, + 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, +) + +TurkishLangModel = ( +3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, +3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, +3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, +3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, +3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, +3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, +2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, +3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, +1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, +3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, +3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, +2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, +2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, +3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, +0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, +3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, +3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, +0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, +1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, +3,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, +3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, +3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, +0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, +3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, +1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, +1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, +2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, +2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, +1,0,0,1,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,1, +1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, +0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, +3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,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,0,0,0,0,0,0, +3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, +0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, +3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, +1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, +2,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, +3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, +0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, +3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, +0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, +0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, +3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, +0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, +0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, +3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, +0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, +3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, +0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, +0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, +3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, +0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, +3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, +0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, +0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, +0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, +0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, +0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, +0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, +1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, +0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, +0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, +3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, +0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, +2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, +2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, +0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, +0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,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,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin5TurkishModel = { + 'char_to_order_map': Latin5_TurkishCharToOrderMap, + 'precedence_matrix': TurkishLangModel, + 'typical_positive_ratio': 0.970290, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-9", + 'language': 'Turkish', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/latin1prober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/latin1prober.py new file mode 100755 index 0000000..7c37520 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcharsetprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcharsetprober.py new file mode 100755 index 0000000..4609154 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcsgroupprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcsgroupprober.py new file mode 100755 index 0000000..4b04929 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcssm.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/mbcssm.py new file mode 100755 index 0000000..d68f6f6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py new file mode 100755 index 0000000..66e0dfc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcharsetprober.py @@ -0,0 +1,132 @@ +######################## 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 CharacterCategory, ProbingState, SequenceLikelihood + + +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.get('language') + + def feed(self, byte_str): + if not self._model['keep_english_letter']: + 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'] + for i, c in enumerate(byte_str): + # XXX: Order is in range 1-64, so one would think we want 0-63 here, + # but that leads to 27 more test failures than before. + order = char_to_order_map[c] + # 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 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + i = (self._last_order * self.SAMPLE_SIZE) + order + model = self._model['precedence_matrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * self.SAMPLE_SIZE) + self._last_order + model = self._model['precedence_matrix'][i] + self._seq_counters[model] += 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py new file mode 100755 index 0000000..29bcc2a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sbcsgroupprober.py @@ -0,0 +1,73 @@ +######################## 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 .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, + Latin5CyrillicModel, MacCyrillicModel, + Ibm866Model, Ibm855Model) +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber +from .langturkishmodel import Latin5TurkishModel + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + self.probers = [ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(Latin2HungarianModel), + # SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + SingleByteCharSetProber(Latin5TurkishModel), + ] + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) + self.probers.extend([hebrew_prober, logical_hebrew_prober, + visual_hebrew_prober]) + + self.reset() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sjisprober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/sjisprober.py new file mode 100755 index 0000000..683add0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/universaldetector.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/universaldetector.py new file mode 100755 index 0000000..8a6de3b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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', + prober.charset_name, + prober.language, + prober.get_confidence()) + return self.result diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/utf8prober.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/utf8prober.py new file mode 100755 index 0000000..4573267 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/version.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/chardet/version.py new file mode 100755 index 0000000..f24d042 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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__ = "3.0.4" +VERSION = __version__.split('.') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py new file mode 100755 index 0000000..10c372d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/__init__.py @@ -0,0 +1,7 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.3.9' + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py new file mode 100755 index 0000000..8530fd0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansi.py @@ -0,0 +1,102 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +''' +This module generates ANSI character codes to printing colors to terminals. +See: http://en.wikipedia.org/wiki/ANSI_escape_code +''' + +CSI = '\033[' +OSC = '\033]' +BEL = '\007' + + +def code_to_chars(code): + return CSI + str(code) + 'm' + +def set_title(title): + return OSC + '2;' + title + BEL + +def clear_screen(mode=2): + return CSI + str(mode) + 'J' + +def clear_line(mode=2): + return CSI + str(mode) + 'K' + + +class AnsiCodes(object): + def __init__(self): + # the subclasses declare class attributes which are numbers. + # Upon instantiation we define instance attributes, which are the same + # as the class attributes but wrapped with the ANSI escape sequence + for name in dir(self): + if not name.startswith('_'): + value = getattr(self, name) + setattr(self, name, code_to_chars(value)) + + +class AnsiCursor(object): + def UP(self, n=1): + return CSI + str(n) + 'A' + def DOWN(self, n=1): + return CSI + str(n) + 'B' + def FORWARD(self, n=1): + return CSI + str(n) + 'C' + def BACK(self, n=1): + return CSI + str(n) + 'D' + def POS(self, x=1, y=1): + return CSI + str(y) + ';' + str(x) + 'H' + + +class AnsiFore(AnsiCodes): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + RESET = 39 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 90 + LIGHTRED_EX = 91 + LIGHTGREEN_EX = 92 + LIGHTYELLOW_EX = 93 + LIGHTBLUE_EX = 94 + LIGHTMAGENTA_EX = 95 + LIGHTCYAN_EX = 96 + LIGHTWHITE_EX = 97 + + +class AnsiBack(AnsiCodes): + BLACK = 40 + RED = 41 + GREEN = 42 + YELLOW = 43 + BLUE = 44 + MAGENTA = 45 + CYAN = 46 + WHITE = 47 + RESET = 49 + + # These are fairly well supported, but not part of the standard. + LIGHTBLACK_EX = 100 + LIGHTRED_EX = 101 + LIGHTGREEN_EX = 102 + LIGHTYELLOW_EX = 103 + LIGHTBLUE_EX = 104 + LIGHTMAGENTA_EX = 105 + LIGHTCYAN_EX = 106 + LIGHTWHITE_EX = 107 + + +class AnsiStyle(AnsiCodes): + BRIGHT = 1 + DIM = 2 + NORMAL = 22 + RESET_ALL = 0 + +Fore = AnsiFore() +Back = AnsiBack() +Style = AnsiStyle() +Cursor = AnsiCursor() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py new file mode 100755 index 0000000..0cb9efc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/ansitowin32.py @@ -0,0 +1,236 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import re +import sys +import os + +from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style +from .winterm import WinTerm, WinColor, WinStyle +from .win32 import windll, winapi_test + + +winterm = None +if windll is not None: + winterm = WinTerm() + + +def is_stream_closed(stream): + return not hasattr(stream, 'closed') or stream.closed + + +def is_a_tty(stream): + return hasattr(stream, 'isatty') and stream.isatty() + + +class StreamWrapper(object): + ''' + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()', which is delegated to our + Converter instance. + ''' + def __init__(self, wrapped, converter): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + self.__convertor = converter + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def write(self, text): + self.__convertor.write(text) + + +class AnsiToWin32(object): + ''' + Implements a 'write()' method which, on Windows, will strip ANSI character + sequences from the text, and if outputting to a tty, will convert them into + win32 function calls. + ''' + ANSI_CSI_RE = re.compile('\001?\033\\[((?:\\d|;)*)([a-zA-Z])\002?') # Control Sequence Introducer + ANSI_OSC_RE = re.compile('\001?\033\\]((?:.|;)*?)(\x07)\002?') # Operating System Command + + def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + # The wrapped stream (normally sys.stdout or sys.stderr) + self.wrapped = wrapped + + # should we reset colors to defaults after every .write() + self.autoreset = autoreset + + # create the proxy wrapping our output stream + self.stream = StreamWrapper(wrapped, self) + + on_windows = os.name == 'nt' + # We test if the WinAPI works, because even if we are on Windows + # we may be using a terminal that doesn't support the WinAPI + # (e.g. Cygwin Terminal). In this case it's up to the terminal + # to support the ANSI codes. + conversion_supported = on_windows and winapi_test() + + # should we strip ANSI sequences from our output? + if strip is None: + strip = conversion_supported or (not is_stream_closed(wrapped) and not is_a_tty(wrapped)) + self.strip = strip + + # should we should convert ANSI sequences into win32 calls? + if convert is None: + convert = conversion_supported and not is_stream_closed(wrapped) and is_a_tty(wrapped) + self.convert = convert + + # dict of ansi codes to win32 functions and parameters + self.win32_calls = self.get_win32_calls() + + # are we wrapping stderr? + self.on_stderr = self.wrapped is sys.stderr + + def should_wrap(self): + ''' + True if this class is actually needed. If false, then the output + stream will not be affected, nor will win32 calls be issued, so + wrapping stdout is not actually required. This will generally be + False on non-Windows platforms, unless optional functionality like + autoreset has been requested using kwargs to init() + ''' + return self.convert or self.strip or self.autoreset + + def get_win32_calls(self): + if self.convert and winterm: + return { + AnsiStyle.RESET_ALL: (winterm.reset_all, ), + AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), + AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), + AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), + AnsiFore.RED: (winterm.fore, WinColor.RED), + AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), + AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), + AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), + AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), + AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), + AnsiFore.WHITE: (winterm.fore, WinColor.GREY), + AnsiFore.RESET: (winterm.fore, ), + AnsiFore.LIGHTBLACK_EX: (winterm.fore, WinColor.BLACK, True), + AnsiFore.LIGHTRED_EX: (winterm.fore, WinColor.RED, True), + AnsiFore.LIGHTGREEN_EX: (winterm.fore, WinColor.GREEN, True), + AnsiFore.LIGHTYELLOW_EX: (winterm.fore, WinColor.YELLOW, True), + AnsiFore.LIGHTBLUE_EX: (winterm.fore, WinColor.BLUE, True), + AnsiFore.LIGHTMAGENTA_EX: (winterm.fore, WinColor.MAGENTA, True), + AnsiFore.LIGHTCYAN_EX: (winterm.fore, WinColor.CYAN, True), + AnsiFore.LIGHTWHITE_EX: (winterm.fore, WinColor.GREY, True), + AnsiBack.BLACK: (winterm.back, WinColor.BLACK), + AnsiBack.RED: (winterm.back, WinColor.RED), + AnsiBack.GREEN: (winterm.back, WinColor.GREEN), + AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), + AnsiBack.BLUE: (winterm.back, WinColor.BLUE), + AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), + AnsiBack.CYAN: (winterm.back, WinColor.CYAN), + AnsiBack.WHITE: (winterm.back, WinColor.GREY), + AnsiBack.RESET: (winterm.back, ), + AnsiBack.LIGHTBLACK_EX: (winterm.back, WinColor.BLACK, True), + AnsiBack.LIGHTRED_EX: (winterm.back, WinColor.RED, True), + AnsiBack.LIGHTGREEN_EX: (winterm.back, WinColor.GREEN, True), + AnsiBack.LIGHTYELLOW_EX: (winterm.back, WinColor.YELLOW, True), + AnsiBack.LIGHTBLUE_EX: (winterm.back, WinColor.BLUE, True), + AnsiBack.LIGHTMAGENTA_EX: (winterm.back, WinColor.MAGENTA, True), + AnsiBack.LIGHTCYAN_EX: (winterm.back, WinColor.CYAN, True), + AnsiBack.LIGHTWHITE_EX: (winterm.back, WinColor.GREY, True), + } + return dict() + + def write(self, text): + if self.strip or self.convert: + self.write_and_convert(text) + else: + self.wrapped.write(text) + self.wrapped.flush() + if self.autoreset: + self.reset_all() + + + def reset_all(self): + if self.convert: + self.call_win32('m', (0,)) + elif not self.strip and not is_stream_closed(self.wrapped): + self.wrapped.write(Style.RESET_ALL) + + + def write_and_convert(self, text): + ''' + Write the given text to our wrapped stream, stripping any ANSI + sequences from the text, and optionally converting them into win32 + calls. + ''' + cursor = 0 + text = self.convert_osc(text) + for match in self.ANSI_CSI_RE.finditer(text): + start, end = match.span() + self.write_plain_text(text, cursor, start) + self.convert_ansi(*match.groups()) + cursor = end + self.write_plain_text(text, cursor, len(text)) + + + def write_plain_text(self, text, start, end): + if start < end: + self.wrapped.write(text[start:end]) + self.wrapped.flush() + + + def convert_ansi(self, paramstring, command): + if self.convert: + params = self.extract_params(command, paramstring) + self.call_win32(command, params) + + + def extract_params(self, command, paramstring): + if command in 'Hf': + params = tuple(int(p) if len(p) != 0 else 1 for p in paramstring.split(';')) + while len(params) < 2: + # defaults: + params = params + (1,) + else: + params = tuple(int(p) for p in paramstring.split(';') if len(p) != 0) + if len(params) == 0: + # defaults: + if command in 'JKm': + params = (0,) + elif command in 'ABCD': + params = (1,) + + return params + + + def call_win32(self, command, params): + if command == 'm': + for param in params: + if param in self.win32_calls: + func_args = self.win32_calls[param] + func = func_args[0] + args = func_args[1:] + kwargs = dict(on_stderr=self.on_stderr) + func(*args, **kwargs) + elif command in 'J': + winterm.erase_screen(params[0], on_stderr=self.on_stderr) + elif command in 'K': + winterm.erase_line(params[0], on_stderr=self.on_stderr) + elif command in 'Hf': # cursor position - absolute + winterm.set_cursor_position(params, on_stderr=self.on_stderr) + elif command in 'ABCD': # cursor position - relative + n = params[0] + # A - up, B - down, C - forward, D - back + x, y = {'A': (0, -n), 'B': (0, n), 'C': (n, 0), 'D': (-n, 0)}[command] + winterm.cursor_adjust(x, y, on_stderr=self.on_stderr) + + + def convert_osc(self, text): + for match in self.ANSI_OSC_RE.finditer(text): + start, end = match.span() + text = text[:start] + text[end:] + paramstring, command = match.groups() + if command in '\x07': # \x07 = BEL + params = paramstring.split(";") + # 0 - change title and icon (we will only change title) + # 1 - change icon (we don't support this) + # 2 - change title + if params[0] in '02': + winterm.set_title(params[1]) + return text diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py new file mode 100755 index 0000000..7f03156 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/initialise.py @@ -0,0 +1,82 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +import atexit +import contextlib +import sys + +from .ansitowin32 import AnsiToWin32 + + +orig_stdout = None +orig_stderr = None + +wrapped_stdout = None +wrapped_stderr = None + +atexit_done = False + + +def reset_all(): + if AnsiToWin32 is not None: # Issue #74: objects might become None at exit + AnsiToWin32(orig_stdout).reset_all() + + +def init(autoreset=False, convert=None, strip=None, wrap=True): + + if not wrap and any([autoreset, convert, strip]): + raise ValueError('wrap=False conflicts with any other arg=True') + + global wrapped_stdout, wrapped_stderr + global orig_stdout, orig_stderr + + orig_stdout = sys.stdout + orig_stderr = sys.stderr + + if sys.stdout is None: + wrapped_stdout = None + else: + sys.stdout = wrapped_stdout = \ + wrap_stream(orig_stdout, convert, strip, autoreset, wrap) + if sys.stderr is None: + wrapped_stderr = None + else: + sys.stderr = wrapped_stderr = \ + wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + + global atexit_done + if not atexit_done: + atexit.register(reset_all) + atexit_done = True + + +def deinit(): + if orig_stdout is not None: + sys.stdout = orig_stdout + if orig_stderr is not None: + sys.stderr = orig_stderr + + +@contextlib.contextmanager +def colorama_text(*args, **kwargs): + init(*args, **kwargs) + try: + yield + finally: + deinit() + + +def reinit(): + if wrapped_stdout is not None: + sys.stdout = wrapped_stdout + if wrapped_stderr is not None: + sys.stderr = wrapped_stderr + + +def wrap_stream(stream, convert, strip, autoreset, wrap): + if wrap: + wrapper = AnsiToWin32(stream, + convert=convert, strip=strip, autoreset=autoreset) + if wrapper.should_wrap(): + stream = wrapper.stream + return stream + + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py new file mode 100755 index 0000000..1485e69 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/win32.py @@ -0,0 +1,156 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. + +# from winbase.h +STDOUT = -11 +STDERR = -12 + +try: + import ctypes + from ctypes import LibraryLoader + windll = LibraryLoader(ctypes.WinDLL) + from ctypes import wintypes +except (AttributeError, ImportError): + windll = None + SetConsoleTextAttribute = lambda *_: None + winapi_test = lambda *_: None +else: + from ctypes import byref, Structure, c_char, POINTER + + COORD = wintypes._COORD + + class CONSOLE_SCREEN_BUFFER_INFO(Structure): + """struct in wincon.h.""" + _fields_ = [ + ("dwSize", COORD), + ("dwCursorPosition", COORD), + ("wAttributes", wintypes.WORD), + ("srWindow", wintypes.SMALL_RECT), + ("dwMaximumWindowSize", COORD), + ] + def __str__(self): + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( + self.dwSize.Y, self.dwSize.X + , self.dwCursorPosition.Y, self.dwCursorPosition.X + , self.wAttributes + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X + ) + + _GetStdHandle = windll.kernel32.GetStdHandle + _GetStdHandle.argtypes = [ + wintypes.DWORD, + ] + _GetStdHandle.restype = wintypes.HANDLE + + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo + _GetConsoleScreenBufferInfo.argtypes = [ + wintypes.HANDLE, + POINTER(CONSOLE_SCREEN_BUFFER_INFO), + ] + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL + + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute + _SetConsoleTextAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + ] + _SetConsoleTextAttribute.restype = wintypes.BOOL + + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition + _SetConsoleCursorPosition.argtypes = [ + wintypes.HANDLE, + COORD, + ] + _SetConsoleCursorPosition.restype = wintypes.BOOL + + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA + _FillConsoleOutputCharacterA.argtypes = [ + wintypes.HANDLE, + c_char, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputCharacterA.restype = wintypes.BOOL + + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute + _FillConsoleOutputAttribute.argtypes = [ + wintypes.HANDLE, + wintypes.WORD, + wintypes.DWORD, + COORD, + POINTER(wintypes.DWORD), + ] + _FillConsoleOutputAttribute.restype = wintypes.BOOL + + _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW + _SetConsoleTitleW.argtypes = [ + wintypes.LPCWSTR + ] + _SetConsoleTitleW.restype = wintypes.BOOL + + handles = { + STDOUT: _GetStdHandle(STDOUT), + STDERR: _GetStdHandle(STDERR), + } + + def _winapi_test(handle): + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return bool(success) + + def winapi_test(): + return any(_winapi_test(h) for h in handles.values()) + + def GetConsoleScreenBufferInfo(stream_id=STDOUT): + handle = handles[stream_id] + csbi = CONSOLE_SCREEN_BUFFER_INFO() + success = _GetConsoleScreenBufferInfo( + handle, byref(csbi)) + return csbi + + def SetConsoleTextAttribute(stream_id, attrs): + handle = handles[stream_id] + return _SetConsoleTextAttribute(handle, attrs) + + def SetConsoleCursorPosition(stream_id, position, adjust=True): + position = COORD(*position) + # If the position is out of range, do nothing. + if position.Y <= 0 or position.X <= 0: + return + # Adjust for Windows' SetConsoleCursorPosition: + # 1. being 0-based, while ANSI is 1-based. + # 2. expecting (x,y), while ANSI uses (y,x). + adjusted_position = COORD(position.Y - 1, position.X - 1) + if adjust: + # Adjust for viewport's scroll position + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow + adjusted_position.Y += sr.Top + adjusted_position.X += sr.Left + # Resume normal processing + handle = handles[stream_id] + return _SetConsoleCursorPosition(handle, adjusted_position) + + def FillConsoleOutputCharacter(stream_id, char, length, start): + handle = handles[stream_id] + char = c_char(char.encode()) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + success = _FillConsoleOutputCharacterA( + handle, char, length, start, byref(num_written)) + return num_written.value + + def FillConsoleOutputAttribute(stream_id, attr, length, start): + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' + handle = handles[stream_id] + attribute = wintypes.WORD(attr) + length = wintypes.DWORD(length) + num_written = wintypes.DWORD(0) + # Note that this is hard-coded for ANSI (vs wide) bytes. + return _FillConsoleOutputAttribute( + handle, attribute, length, start, byref(num_written)) + + def SetConsoleTitle(title): + return _SetConsoleTitleW(title) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py new file mode 100755 index 0000000..385862e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/colorama/winterm.py @@ -0,0 +1,162 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from . import win32 + + +# from wincon.h +class WinColor(object): + BLACK = 0 + BLUE = 1 + GREEN = 2 + CYAN = 3 + RED = 4 + MAGENTA = 5 + YELLOW = 6 + GREY = 7 + +# from wincon.h +class WinStyle(object): + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + +class WinTerm(object): + + def __init__(self): + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self.set_attrs(self._default) + self._default_fore = self._fore + self._default_back = self._back + self._default_style = self._style + # In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. + # So that LIGHT_EX colors and BRIGHT style do not clobber each other, + # we track them separately, since LIGHT_EX is overwritten by Fore/Back + # and BRIGHT is overwritten by Style codes. + self._light = 0 + + def get_attrs(self): + return self._fore + self._back * 16 + (self._style | self._light) + + def set_attrs(self, value): + self._fore = value & 7 + self._back = (value >> 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + if mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + if mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py new file mode 100755 index 0000000..9430718 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import logging + +__version__ = '0.2.7' + +class DistlibException(Exception): + pass + +try: + from logging import NullHandler +except ImportError: # pragma: no cover + class NullHandler(logging.Handler): + def handle(self, record): pass + def emit(self, record): pass + def createLock(self): self.lock = None + +logger = logging.getLogger(__name__) +logger.addHandler(NullHandler()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py new file mode 100755 index 0000000..e6143f1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/__init__.py @@ -0,0 +1,6 @@ +"""Modules copied from Python 3 standard libraries, for internal use only. + +Individual classes and functions are found in d2._backport.misc. Intended +usage is to always import things missing from 3.1 from that module: the +built-in/stdlib objects will be used if found. +""" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py new file mode 100755 index 0000000..6eb7b86 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/misc.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Backports for individual classes and functions.""" + +import os +import sys + +__all__ = ['cache_from_source', 'callable', 'fsencode'] + + +try: + from imp import cache_from_source +except ImportError: + def cache_from_source(py_file, debug=__debug__): + ext = debug and 'c' or 'o' + return py_file + ext + + +try: + callable = callable +except NameError: + from collections import Callable + + def callable(obj): + return isinstance(obj, Callable) + + +try: + fsencode = os.fsencode +except AttributeError: + def fsencode(filename): + if isinstance(filename, bytes): + return filename + elif isinstance(filename, str): + return filename.encode(sys.getfilesystemencoding()) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py new file mode 100755 index 0000000..becbfd7 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/shutil.py @@ -0,0 +1,761 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Utility functions for copying and archiving files and directory trees. + +XXX The functions here don't copy the resource fork or other metadata on Mac. + +""" + +import os +import sys +import stat +from os.path import abspath +import fnmatch +import collections +import errno +from . import tarfile + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False + +try: + from pwd import getpwnam +except ImportError: + getpwnam = None + +try: + from grp import getgrnam +except ImportError: + getgrnam = None + +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive", "ignore_patterns"] + +class Error(EnvironmentError): + pass + +class SpecialFileError(EnvironmentError): + """Raised when trying to do a kind of operation (e.g. copying) which is + not supported on a special file (e.g. a named pipe)""" + +class ExecError(EnvironmentError): + """Raised when a command could not be executed""" + +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registry operation with the archiving + and unpacking registries fails""" + + +try: + WindowsError +except NameError: + WindowsError = None + +def copyfileobj(fsrc, fdst, length=16*1024): + """copy data from file-like object fsrc to file-like object fdst""" + while 1: + buf = fsrc.read(length) + if not buf: + break + fdst.write(buf) + +def _samefile(src, dst): + # Macintosh, Unix. + if hasattr(os.path, 'samefile'): + try: + return os.path.samefile(src, dst) + except OSError: + return False + + # All other platforms: check for same pathname. + return (os.path.normcase(os.path.abspath(src)) == + os.path.normcase(os.path.abspath(dst))) + +def copyfile(src, dst): + """Copy data from src to dst""" + if _samefile(src, dst): + raise Error("`%s` and `%s` are the same file" % (src, dst)) + + for fn in [src, dst]: + try: + st = os.stat(fn) + except OSError: + # File most likely does not exist + pass + else: + # XXX What about other special files? (sockets, devices...) + if stat.S_ISFIFO(st.st_mode): + raise SpecialFileError("`%s` is a named pipe" % fn) + + with open(src, 'rb') as fsrc: + with open(dst, 'wb') as fdst: + copyfileobj(fsrc, fdst) + +def copymode(src, dst): + """Copy mode bits from src to dst""" + if hasattr(os, 'chmod'): + st = os.stat(src) + mode = stat.S_IMODE(st.st_mode) + os.chmod(dst, mode) + +def copystat(src, dst): + """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" + st = os.stat(src) + mode = stat.S_IMODE(st.st_mode) + if hasattr(os, 'utime'): + os.utime(dst, (st.st_atime, st.st_mtime)) + if hasattr(os, 'chmod'): + os.chmod(dst, mode) + if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): + try: + os.chflags(dst, st.st_flags) + except OSError as why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise + +def copy(src, dst): + """Copy data and mode bits ("cp src dst"). + + The destination may be a directory. + + """ + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + copyfile(src, dst) + copymode(src, dst) + +def copy2(src, dst): + """Copy data and all stat info ("cp -p src dst"). + + The destination may be a directory. + + """ + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + copyfile(src, dst) + copystat(src, dst) + +def ignore_patterns(*patterns): + """Function that can be used as copytree() ignore parameter. + + Patterns is a sequence of glob-style patterns + that are used to exclude files""" + def _ignore_patterns(path, names): + ignored_names = [] + for pattern in patterns: + ignored_names.extend(fnmatch.filter(names, pattern)) + return set(ignored_names) + return _ignore_patterns + +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. + + The destination directory must not already exist. + If exception(s) occur, an Error is raised with a list of reasons. + + If the optional symlinks flag is true, symbolic links in the + source tree result in symbolic links in the destination tree; if + it is false, the contents of the files pointed to by symbolic + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. + + The optional ignore argument is a callable. If given, it + is called with the `src` parameter, which is the directory + being visited by copytree(), and `names` which is the list of + `src` contents, as returned by os.listdir(): + + callable(src, names) -> ignored_names + + Since copytree() is called recursively, the callable will be + called once for each directory that is copied. It returns a + list of names relative to the `src` directory that should + not be copied. + + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. + + """ + names = os.listdir(src) + if ignore is not None: + ignored_names = ignore(src, names) + else: + ignored_names = set() + + os.makedirs(dst) + errors = [] + for name in names: + if name in ignored_names: + continue + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if os.path.islink(srcname): + linkto = os.readlink(srcname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) + elif os.path.isdir(srcname): + copytree(srcname, dstname, symlinks, ignore, copy_function) + else: + # Will raise a SpecialFileError for unsupported file types + copy_function(srcname, dstname) + # catch the Error from the recursive copytree so that we can + # continue with other files + except Error as err: + errors.extend(err.args[0]) + except EnvironmentError as why: + errors.append((srcname, dstname, str(why))) + try: + copystat(src, dst) + except OSError as why: + if WindowsError is not None and isinstance(why, WindowsError): + # Copying file access times may fail on Windows + pass + else: + errors.extend((src, dst, str(why))) + if errors: + raise Error(errors) + +def rmtree(path, ignore_errors=False, onerror=None): + """Recursively delete a directory tree. + + If ignore_errors is set, errors are ignored; otherwise, if onerror + is set, it is called to handle the error with arguments (func, + path, exc_info) where func is os.listdir, os.remove, or os.rmdir; + path is the argument to that function that caused it to fail; and + exc_info is a tuple returned by sys.exc_info(). If ignore_errors + is false and onerror is None, an exception is raised. + + """ + if ignore_errors: + def onerror(*args): + pass + elif onerror is None: + def onerror(*args): + raise + try: + if os.path.islink(path): + # symlinks to directories are forbidden, see bug #1669 + raise OSError("Cannot call rmtree on a symbolic link") + except OSError: + onerror(os.path.islink, path, sys.exc_info()) + # can't continue even if onerror hook returns + return + names = [] + try: + names = os.listdir(path) + except os.error: + onerror(os.listdir, path, sys.exc_info()) + for name in names: + fullname = os.path.join(path, name) + try: + mode = os.lstat(fullname).st_mode + except os.error: + mode = 0 + if stat.S_ISDIR(mode): + rmtree(fullname, ignore_errors, onerror) + else: + try: + os.remove(fullname) + except os.error: + onerror(os.remove, fullname, sys.exc_info()) + try: + os.rmdir(path) + except os.error: + onerror(os.rmdir, path, sys.exc_info()) + + +def _basename(path): + # A basename() variant which first strips the trailing slash, if present. + # Thus we always get the last component of the path, even for directories. + return os.path.basename(path.rstrip(os.path.sep)) + +def move(src, dst): + """Recursively move a file or directory to another location. This is + similar to the Unix "mv" command. + + If the destination is a directory or a symlink to a directory, the source + is moved inside the directory. The destination path must not already + exist. + + If the destination already exists but is not a directory, it may be + overwritten depending on os.rename() semantics. + + If the destination is on our current filesystem, then rename() is used. + Otherwise, src is copied to the destination and then removed. + A lot more could be done here... A look at a mv.c shows a lot of + the issues this implementation glosses over. + + """ + real_dst = dst + if os.path.isdir(dst): + if _samefile(src, dst): + # We might be on a case insensitive filesystem, + # perform the rename anyway. + os.rename(src, dst) + return + + real_dst = os.path.join(dst, _basename(src)) + if os.path.exists(real_dst): + raise Error("Destination path '%s' already exists" % real_dst) + try: + os.rename(src, real_dst) + except OSError: + if os.path.isdir(src): + if _destinsrc(src, dst): + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) + copytree(src, real_dst, symlinks=True) + rmtree(src) + else: + copy2(src, real_dst) + os.unlink(src) + +def _destinsrc(src, dst): + src = abspath(src) + dst = abspath(dst) + if not src.endswith(os.path.sep): + src += os.path.sep + if not dst.endswith(os.path.sep): + dst += os.path.sep + return dst.startswith(src) + +def _get_gid(name): + """Returns a gid, given a group name.""" + if getgrnam is None or name is None: + return None + try: + result = getgrnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def _get_uid(name): + """Returns an uid, given a user name.""" + if getpwnam is None or name is None: + return None + try: + result = getpwnam(name) + except KeyError: + result = None + if result is not None: + return result[2] + return None + +def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, + owner=None, group=None, logger=None): + """Create a (possibly compressed) tar file from all the files under + 'base_dir'. + + 'compress' must be "gzip" (the default), "bzip2", or None. + + 'owner' and 'group' can be used to define an owner and a group for the + archive that is being built. If not provided, the current owner and group + will be used. + + The output tar file will be named 'base_name' + ".tar", possibly plus + the appropriate compression extension (".gz", or ".bz2"). + + Returns the output filename. + """ + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' + + # flags for compression program, each element of list will be an argument + if compress is not None and compress not in compress_ext: + raise ValueError("bad value for 'compress', or compression format not " + "supported : {0}".format(compress)) + + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) + + if not os.path.exists(archive_dir): + if logger is not None: + logger.info("creating %s", archive_dir) + if not dry_run: + os.makedirs(archive_dir) + + # creating the tarball + if logger is not None: + logger.info('Creating tar archive') + + uid = _get_uid(owner) + gid = _get_gid(group) + + def _set_uid_gid(tarinfo): + if gid is not None: + tarinfo.gid = gid + tarinfo.gname = group + if uid is not None: + tarinfo.uid = uid + tarinfo.uname = owner + return tarinfo + + if not dry_run: + tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) + try: + tar.add(base_dir, filter=_set_uid_gid) + finally: + tar.close() + + return archive_name + +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): + # XXX see if we want to keep an external call here + if verbose: + zipoptions = "-r" + else: + zipoptions = "-rq" + from distutils.errors import DistutilsExecError + from distutils.spawn import spawn + try: + spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) + except DistutilsExecError: + # XXX really should distinguish between "couldn't find + # external 'zip' command" and "zip failed". + raise ExecError("unable to create zip file '%s': " + "could neither import the 'zipfile' module nor " + "find a standalone zip utility") % zip_filename + +def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): + """Create a zip file from all the files under 'base_dir'. + + The output zip file will be named 'base_name' + ".zip". Uses either the + "zipfile" Python module (if available) or the InfoZIP "zip" utility + (if installed and found on the default search path). If neither tool is + available, raises ExecError. Returns the name of the output zip + file. + """ + zip_filename = base_name + ".zip" + archive_dir = os.path.dirname(base_name) + + if not os.path.exists(archive_dir): + if logger is not None: + logger.info("creating %s", archive_dir) + if not dry_run: + os.makedirs(archive_dir) + + # If zipfile module is not available, try spawning an external 'zip' + # command. + try: + import zipfile + except ImportError: + zipfile = None + + if zipfile is None: + _call_external_zip(base_dir, zip_filename, verbose, dry_run) + else: + if logger is not None: + logger.info("creating '%s' and adding '%s' to it", + zip_filename, base_dir) + + if not dry_run: + zip = zipfile.ZipFile(zip_filename, "w", + compression=zipfile.ZIP_DEFLATED) + + for dirpath, dirnames, filenames in os.walk(base_dir): + for name in filenames: + path = os.path.normpath(os.path.join(dirpath, name)) + if os.path.isfile(path): + zip.write(path, path) + if logger is not None: + logger.info("adding '%s'", path) + zip.close() + + return zip_filename + +_ARCHIVE_FORMATS = { + 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), + 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), + 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), + 'zip': (_make_zipfile, [], "ZIP file"), + } + +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + +def get_archive_formats(): + """Returns a list of supported formats for archiving and unarchiving. + + Each element of the returned sequence is a tuple (name, description) + """ + formats = [(name, registry[2]) for name, registry in + _ARCHIVE_FORMATS.items()] + formats.sort() + return formats + +def register_archive_format(name, function, extra_args=None, description=''): + """Registers an archive format. + + name is the name of the format. function is the callable that will be + used to create archives. If provided, extra_args is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_archive_formats() function. + """ + if extra_args is None: + extra_args = [] + if not isinstance(function, collections.Callable): + raise TypeError('The %s object is not callable' % function) + if not isinstance(extra_args, (tuple, list)): + raise TypeError('extra_args needs to be a sequence') + for element in extra_args: + if not isinstance(element, (tuple, list)) or len(element) !=2: + raise TypeError('extra_args elements are : (arg_name, value)') + + _ARCHIVE_FORMATS[name] = (function, extra_args, description) + +def unregister_archive_format(name): + del _ARCHIVE_FORMATS[name] + +def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, + dry_run=0, owner=None, group=None, logger=None): + """Create an archive file (eg. zip or tar). + + 'base_name' is the name of the file to create, minus any format-specific + extension; 'format' is the archive format: one of "zip", "tar", "bztar" + or "gztar". + + 'root_dir' is a directory that will be the root directory of the + archive; ie. we typically chdir into 'root_dir' before creating the + archive. 'base_dir' is the directory where we start archiving from; + ie. 'base_dir' will be the common prefix of all files and + directories in the archive. 'root_dir' and 'base_dir' both default + to the current directory. Returns the name of the archive file. + + 'owner' and 'group' are used when creating a tar archive. By default, + uses the current owner and group. + """ + save_cwd = os.getcwd() + if root_dir is not None: + if logger is not None: + logger.debug("changing into '%s'", root_dir) + base_name = os.path.abspath(base_name) + if not dry_run: + os.chdir(root_dir) + + if base_dir is None: + base_dir = os.curdir + + kwargs = {'dry_run': dry_run, 'logger': logger} + + try: + format_info = _ARCHIVE_FORMATS[format] + except KeyError: + raise ValueError("unknown archive format '%s'" % format) + + func = format_info[0] + for arg, val in format_info[1]: + kwargs[arg] = val + + if format != 'zip': + kwargs['owner'] = owner + kwargs['group'] = group + + try: + filename = func(base_name, base_dir, **kwargs) + finally: + if root_dir is not None: + if logger is not None: + logger.debug("changing back to '%s'", save_cwd) + os.chdir(save_cwd) + + return filename + + +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.items()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.items(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not isinstance(function, collections.Callable): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registry.""" + del _UNPACK_FORMATS[name] + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target, 'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } + +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") + +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.items(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None + +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ + if extract_dir is None: + extract_dir = os.getcwd() + + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + + func = format_info[1] + func(filename, extract_dir, **dict(format_info[2])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) + func(filename, extract_dir, **kwargs) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg new file mode 100755 index 0000000..c92cd48 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.cfg @@ -0,0 +1,84 @@ +[posix_prefix] +# Configuration directories. Some of these come straight out of the +# configure script. They are for implementing the other variables, not to +# be used directly in [resource_locations]. +confdir = /etc +datadir = /usr/share +libdir = /usr/lib +statedir = /var +# User resource directory +local = ~/.local/{distribution.name} + +stdlib = {base}/lib/python{py_version_short} +platstdlib = {platbase}/lib/python{py_version_short} +purelib = {base}/lib/python{py_version_short}/site-packages +platlib = {platbase}/lib/python{py_version_short}/site-packages +include = {base}/include/python{py_version_short}{abiflags} +platinclude = {platbase}/include/python{py_version_short}{abiflags} +data = {base} + +[posix_home] +stdlib = {base}/lib/python +platstdlib = {base}/lib/python +purelib = {base}/lib/python +platlib = {base}/lib/python +include = {base}/include/python +platinclude = {base}/include/python +scripts = {base}/bin +data = {base} + +[nt] +stdlib = {base}/Lib +platstdlib = {base}/Lib +purelib = {base}/Lib/site-packages +platlib = {base}/Lib/site-packages +include = {base}/Include +platinclude = {base}/Include +scripts = {base}/Scripts +data = {base} + +[os2] +stdlib = {base}/Lib +platstdlib = {base}/Lib +purelib = {base}/Lib/site-packages +platlib = {base}/Lib/site-packages +include = {base}/Include +platinclude = {base}/Include +scripts = {base}/Scripts +data = {base} + +[os2_home] +stdlib = {userbase}/lib/python{py_version_short} +platstdlib = {userbase}/lib/python{py_version_short} +purelib = {userbase}/lib/python{py_version_short}/site-packages +platlib = {userbase}/lib/python{py_version_short}/site-packages +include = {userbase}/include/python{py_version_short} +scripts = {userbase}/bin +data = {userbase} + +[nt_user] +stdlib = {userbase}/Python{py_version_nodot} +platstdlib = {userbase}/Python{py_version_nodot} +purelib = {userbase}/Python{py_version_nodot}/site-packages +platlib = {userbase}/Python{py_version_nodot}/site-packages +include = {userbase}/Python{py_version_nodot}/Include +scripts = {userbase}/Scripts +data = {userbase} + +[posix_user] +stdlib = {userbase}/lib/python{py_version_short} +platstdlib = {userbase}/lib/python{py_version_short} +purelib = {userbase}/lib/python{py_version_short}/site-packages +platlib = {userbase}/lib/python{py_version_short}/site-packages +include = {userbase}/include/python{py_version_short} +scripts = {userbase}/bin +data = {userbase} + +[osx_framework_user] +stdlib = {userbase}/lib/python +platstdlib = {userbase}/lib/python +purelib = {userbase}/lib/python/site-packages +platlib = {userbase}/lib/python/site-packages +include = {userbase}/include +scripts = {userbase}/bin +data = {userbase} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py new file mode 100755 index 0000000..b243da3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/sysconfig.py @@ -0,0 +1,788 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Access to Python's configuration information.""" + +import codecs +import os +import re +import sys +from os.path import pardir, realpath +try: + import configparser +except ImportError: + import ConfigParser as configparser + + +__all__ = [ + 'get_config_h_filename', + 'get_config_var', + 'get_config_vars', + 'get_makefile_filename', + 'get_path', + 'get_path_names', + 'get_paths', + 'get_platform', + 'get_python_version', + 'get_scheme_names', + 'parse_config_h', +] + + +def _safe_realpath(path): + try: + return realpath(path) + except OSError: + return path + + +if sys.executable: + _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable)) +else: + # sys.executable can be empty if argv[0] has been changed and Python is + # unable to retrieve the real program name + _PROJECT_BASE = _safe_realpath(os.getcwd()) + +if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir)) +# PC/VS7.1 +if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) +# PC/AMD64 +if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): + _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) + + +def is_python_build(): + for fn in ("Setup.dist", "Setup.local"): + if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): + return True + return False + +_PYTHON_BUILD = is_python_build() + +_cfg_read = False + +def _ensure_cfg_read(): + global _cfg_read + if not _cfg_read: + from ..resources import finder + backport_package = __name__.rsplit('.', 1)[0] + _finder = finder(backport_package) + _cfgfile = _finder.find('sysconfig.cfg') + assert _cfgfile, 'sysconfig.cfg exists' + with _cfgfile.as_stream() as s: + _SCHEMES.readfp(s) + if _PYTHON_BUILD: + for scheme in ('posix_prefix', 'posix_home'): + _SCHEMES.set(scheme, 'include', '{srcdir}/Include') + _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') + + _cfg_read = True + + +_SCHEMES = configparser.RawConfigParser() +_VAR_REPL = re.compile(r'\{([^{]*?)\}') + +def _expand_globals(config): + _ensure_cfg_read() + if config.has_section('globals'): + globals = config.items('globals') + else: + globals = tuple() + + sections = config.sections() + for section in sections: + if section == 'globals': + continue + for option, value in globals: + if config.has_option(section, option): + continue + config.set(section, option, value) + config.remove_section('globals') + + # now expanding local variables defined in the cfg file + # + for section in config.sections(): + variables = dict(config.items(section)) + + def _replacer(matchobj): + name = matchobj.group(1) + if name in variables: + return variables[name] + return matchobj.group(0) + + for option, value in config.items(section): + config.set(section, option, _VAR_REPL.sub(_replacer, value)) + +#_expand_globals(_SCHEMES) + + # FIXME don't rely on sys.version here, its format is an implementation detail + # of CPython, use sys.version_info or sys.hexversion +_PY_VERSION = sys.version.split()[0] +_PY_VERSION_SHORT = sys.version[:3] +_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2] +_PREFIX = os.path.normpath(sys.prefix) +_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) +_CONFIG_VARS = None +_USER_BASE = None + + +def _subst_vars(path, local_vars): + """In the string `path`, replace tokens like {some.thing} with the + corresponding value from the map `local_vars`. + + If there is no corresponding value, leave the token unchanged. + """ + def _replacer(matchobj): + name = matchobj.group(1) + if name in local_vars: + return local_vars[name] + elif name in os.environ: + return os.environ[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, path) + + +def _extend_dict(target_dict, other_dict): + target_keys = target_dict.keys() + for key, value in other_dict.items(): + if key in target_keys: + continue + target_dict[key] = value + + +def _expand_vars(scheme, vars): + res = {} + if vars is None: + vars = {} + _extend_dict(vars, get_config_vars()) + + for key, value in _SCHEMES.items(scheme): + if os.name in ('posix', 'nt'): + value = os.path.expanduser(value) + res[key] = os.path.normpath(_subst_vars(value, vars)) + return res + + +def format_value(value, vars): + def _replacer(matchobj): + name = matchobj.group(1) + if name in vars: + return vars[name] + return matchobj.group(0) + return _VAR_REPL.sub(_replacer, value) + + +def _get_default_scheme(): + if os.name == 'posix': + # the default scheme for posix is posix_prefix + return 'posix_prefix' + return os.name + + +def _getuserbase(): + env_base = os.environ.get("PYTHONUSERBASE", None) + + def joinuser(*args): + return os.path.expanduser(os.path.join(*args)) + + # what about 'os2emx', 'riscos' ? + if os.name == "nt": + base = os.environ.get("APPDATA") or "~" + if env_base: + return env_base + else: + return joinuser(base, "Python") + + if sys.platform == "darwin": + framework = get_config_var("PYTHONFRAMEWORK") + if framework: + if env_base: + return env_base + else: + return joinuser("~", "Library", framework, "%d.%d" % + sys.version_info[:2]) + + if env_base: + return env_base + else: + return joinuser("~", ".local") + + +def _parse_makefile(filename, vars=None): + """Parse a Makefile-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + # Regexes needed for parsing Makefile (and similar syntaxes, + # like old-style Setup files). + _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") + _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") + _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + + if vars is None: + vars = {} + done = {} + notdone = {} + + with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f: + lines = f.readlines() + + for line in lines: + if line.startswith('#') or line.strip() == '': + continue + m = _variable_rx.match(line) + if m: + n, v = m.group(1, 2) + v = v.strip() + # `$$' is a literal `$' in make + tmpv = v.replace('$$', '') + + if "$" in tmpv: + notdone[n] = v + else: + try: + v = int(v) + except ValueError: + # insert literal `$' + done[n] = v.replace('$$', '$') + else: + done[n] = v + + # do variable interpolation here + variables = list(notdone.keys()) + + # Variables with a 'PY_' prefix in the makefile. These need to + # be made available without that prefix through sysconfig. + # Special care is needed to ensure that variable expansion works, even + # if the expansion uses the name without a prefix. + renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') + + while len(variables) > 0: + for name in tuple(variables): + value = notdone[name] + m = _findvar1_rx.search(value) or _findvar2_rx.search(value) + if m is not None: + n = m.group(1) + found = True + if n in done: + item = str(done[n]) + elif n in notdone: + # get it on a subsequent round + found = False + elif n in os.environ: + # do it like make: fall back to environment + item = os.environ[n] + + elif n in renamed_variables: + if (name.startswith('PY_') and + name[3:] in renamed_variables): + item = "" + + elif 'PY_' + n in notdone: + found = False + + else: + item = str(done['PY_' + n]) + + else: + done[n] = item = "" + + if found: + after = value[m.end():] + value = value[:m.start()] + item + after + if "$" in after: + notdone[name] = value + else: + try: + value = int(value) + except ValueError: + done[name] = value.strip() + else: + done[name] = value + variables.remove(name) + + if (name.startswith('PY_') and + name[3:] in renamed_variables): + + name = name[3:] + if name not in done: + done[name] = value + + else: + # bogus variable reference (e.g. "prefix=$/opt/python"); + # just drop it since we can't deal + done[name] = value + variables.remove(name) + + # strip spurious spaces + for k, v in done.items(): + if isinstance(v, str): + done[k] = v.strip() + + # save the results in the global dictionary + vars.update(done) + return vars + + +def get_makefile_filename(): + """Return the path of the Makefile.""" + if _PYTHON_BUILD: + return os.path.join(_PROJECT_BASE, "Makefile") + if hasattr(sys, 'abiflags'): + config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) + else: + config_dir_name = 'config' + return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') + + +def _init_posix(vars): + """Initialize the module as appropriate for POSIX systems.""" + # load the installed Makefile: + makefile = get_makefile_filename() + try: + _parse_makefile(makefile, vars) + except IOError as e: + msg = "invalid Python installation: unable to open %s" % makefile + if hasattr(e, "strerror"): + msg = msg + " (%s)" % e.strerror + raise IOError(msg) + # load the installed pyconfig.h: + config_h = get_config_h_filename() + try: + with open(config_h) as f: + parse_config_h(f, vars) + except IOError as e: + msg = "invalid Python installation: unable to open %s" % config_h + if hasattr(e, "strerror"): + msg = msg + " (%s)" % e.strerror + raise IOError(msg) + # On AIX, there are wrong paths to the linker scripts in the Makefile + # -- these paths are relative to the Python source, but when installed + # the scripts are in another directory. + if _PYTHON_BUILD: + vars['LDSHARED'] = vars['BLDSHARED'] + + +def _init_non_posix(vars): + """Initialize the module as appropriate for NT""" + # set basic install directories + vars['LIBDEST'] = get_path('stdlib') + vars['BINLIBDEST'] = get_path('platstdlib') + vars['INCLUDEPY'] = get_path('include') + vars['SO'] = '.pyd' + vars['EXE'] = '.exe' + vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT + vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) + +# +# public APIs +# + + +def parse_config_h(fp, vars=None): + """Parse a config.h-style file. + + A dictionary containing name/value pairs is returned. If an + optional dictionary is passed in as the second argument, it is + used instead of a new dictionary. + """ + if vars is None: + vars = {} + define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") + undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") + + while True: + line = fp.readline() + if not line: + break + m = define_rx.match(line) + if m: + n, v = m.group(1, 2) + try: + v = int(v) + except ValueError: + pass + vars[n] = v + else: + m = undef_rx.match(line) + if m: + vars[m.group(1)] = 0 + return vars + + +def get_config_h_filename(): + """Return the path of pyconfig.h.""" + if _PYTHON_BUILD: + if os.name == "nt": + inc_dir = os.path.join(_PROJECT_BASE, "PC") + else: + inc_dir = _PROJECT_BASE + else: + inc_dir = get_path('platinclude') + return os.path.join(inc_dir, 'pyconfig.h') + + +def get_scheme_names(): + """Return a tuple containing the schemes names.""" + return tuple(sorted(_SCHEMES.sections())) + + +def get_path_names(): + """Return a tuple containing the paths names.""" + # xxx see if we want a static list + return _SCHEMES.options('posix_prefix') + + +def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): + """Return a mapping containing an install scheme. + + ``scheme`` is the install scheme name. If not provided, it will + return the default scheme for the current platform. + """ + _ensure_cfg_read() + if expand: + return _expand_vars(scheme, vars) + else: + return dict(_SCHEMES.items(scheme)) + + +def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): + """Return a path corresponding to the scheme. + + ``scheme`` is the install scheme name. + """ + return get_paths(scheme, vars, expand)[name] + + +def get_config_vars(*args): + """With no arguments, return a dictionary of all configuration + variables relevant for the current platform. + + On Unix, this means every variable defined in Python's installed Makefile; + On Windows and Mac OS it's a much smaller set. + + With arguments, return a list of values that result from looking up + each argument in the configuration variable dictionary. + """ + global _CONFIG_VARS + if _CONFIG_VARS is None: + _CONFIG_VARS = {} + # Normalized versions of prefix and exec_prefix are handy to have; + # in fact, these are the standard versions used most places in the + # distutils2 module. + _CONFIG_VARS['prefix'] = _PREFIX + _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX + _CONFIG_VARS['py_version'] = _PY_VERSION + _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT + _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] + _CONFIG_VARS['base'] = _PREFIX + _CONFIG_VARS['platbase'] = _EXEC_PREFIX + _CONFIG_VARS['projectbase'] = _PROJECT_BASE + try: + _CONFIG_VARS['abiflags'] = sys.abiflags + except AttributeError: + # sys.abiflags may not be defined on all platforms. + _CONFIG_VARS['abiflags'] = '' + + if os.name in ('nt', 'os2'): + _init_non_posix(_CONFIG_VARS) + if os.name == 'posix': + _init_posix(_CONFIG_VARS) + # Setting 'userbase' is done below the call to the + # init function to enable using 'get_config_var' in + # the init-function. + if sys.version >= '2.6': + _CONFIG_VARS['userbase'] = _getuserbase() + + if 'srcdir' not in _CONFIG_VARS: + _CONFIG_VARS['srcdir'] = _PROJECT_BASE + else: + _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) + + # Convert srcdir into an absolute path if it appears necessary. + # Normally it is relative to the build directory. However, during + # testing, for example, we might be running a non-installed python + # from a different directory. + if _PYTHON_BUILD and os.name == "posix": + base = _PROJECT_BASE + try: + cwd = os.getcwd() + except OSError: + cwd = None + if (not os.path.isabs(_CONFIG_VARS['srcdir']) and + base != cwd): + # srcdir is relative and we are not in the same directory + # as the executable. Assume executable is in the build + # directory and make srcdir absolute. + srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) + _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) + + if sys.platform == 'darwin': + kernel_version = os.uname()[2] # Kernel version (8.4.3) + major_version = int(kernel_version.split('.')[0]) + + if major_version < 8: + # On Mac OS X before 10.4, check if -arch and -isysroot + # are in CFLAGS or LDFLAGS and remove them if they are. + # This is needed when building extensions on a 10.3 system + # using a universal build of python. + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + flags = _CONFIG_VARS[key] + flags = re.sub(r'-arch\s+\w+\s', ' ', flags) + flags = re.sub('-isysroot [^ \t]*', ' ', flags) + _CONFIG_VARS[key] = flags + else: + # Allow the user to override the architecture flags using + # an environment variable. + # NOTE: This name was introduced by Apple in OSX 10.5 and + # is used by several scripting languages distributed with + # that OS release. + if 'ARCHFLAGS' in os.environ: + arch = os.environ['ARCHFLAGS'] + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + + flags = _CONFIG_VARS[key] + flags = re.sub(r'-arch\s+\w+\s', ' ', flags) + flags = flags + ' ' + arch + _CONFIG_VARS[key] = flags + + # If we're on OSX 10.5 or later and the user tries to + # compiles an extension using an SDK that is not present + # on the current machine it is better to not use an SDK + # than to fail. + # + # The major usecase for this is users using a Python.org + # binary installer on OSX 10.6: that installer uses + # the 10.4u SDK, but that SDK is not installed by default + # when you install Xcode. + # + CFLAGS = _CONFIG_VARS.get('CFLAGS', '') + m = re.search(r'-isysroot\s+(\S+)', CFLAGS) + if m is not None: + sdk = m.group(1) + if not os.path.exists(sdk): + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + + flags = _CONFIG_VARS[key] + flags = re.sub(r'-isysroot\s+\S+(\s|$)', ' ', flags) + _CONFIG_VARS[key] = flags + + if args: + vals = [] + for name in args: + vals.append(_CONFIG_VARS.get(name)) + return vals + else: + return _CONFIG_VARS + + +def get_config_var(name): + """Return the value of a single variable using the dictionary returned by + 'get_config_vars()'. + + Equivalent to get_config_vars().get(name) + """ + return get_config_vars().get(name) + + +def get_platform(): + """Return a string that identifies the current platform. + + This is used mainly to distinguish platform-specific build directories and + platform-specific built distributions. Typically includes the OS name + and version and the architecture (as supplied by 'os.uname()'), + although the exact information included depends on the OS; eg. for IRIX + the architecture isn't particularly important (IRIX only runs on SGI + hardware), but for Linux the kernel version isn't particularly + important. + + Examples of returned values: + linux-i586 + linux-alpha (?) + solaris-2.6-sun4u + irix-5.3 + irix64-6.2 + + Windows will return one of: + win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) + win-ia64 (64bit Windows on Itanium) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. + """ + if os.name == 'nt': + # sniff sys.version for architecture. + prefix = " bit (" + i = sys.version.find(prefix) + if i == -1: + return sys.platform + j = sys.version.find(")", i) + look = sys.version[i+len(prefix):j].lower() + if look == 'amd64': + return 'win-amd64' + if look == 'itanium': + return 'win-ia64' + return sys.platform + + if os.name != "posix" or not hasattr(os, 'uname'): + # XXX what about the architecture? NT is Intel or Alpha, + # Mac OS is M68k or PPC, etc. + return sys.platform + + # Try to distinguish various flavours of Unix + osname, host, release, version, machine = os.uname() + + # Convert the OS name to lowercase, remove '/' characters + # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") + osname = osname.lower().replace('/', '') + machine = machine.replace(' ', '_') + machine = machine.replace('/', '-') + + if osname[:5] == "linux": + # At least on Linux/Intel, 'machine' is the processor -- + # i386, etc. + # XXX what about Alpha, SPARC, etc? + return "%s-%s" % (osname, machine) + elif osname[:5] == "sunos": + if release[0] >= "5": # SunOS 5 == Solaris 2 + osname = "solaris" + release = "%d.%s" % (int(release[0]) - 3, release[2:]) + # fall through to standard osname-release-machine representation + elif osname[:4] == "irix": # could be "irix64"! + return "%s-%s" % (osname, release) + elif osname[:3] == "aix": + return "%s-%s.%s" % (osname, version, release) + elif osname[:6] == "cygwin": + osname = "cygwin" + rel_re = re.compile(r'[\d.]+') + m = rel_re.match(release) + if m: + release = m.group() + elif osname[:6] == "darwin": + # + # For our purposes, we'll assume that the system version from + # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set + # to. This makes the compatibility story a bit more sane because the + # machine is going to compile and link as if it were + # MACOSX_DEPLOYMENT_TARGET. + cfgvars = get_config_vars() + macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') + + if True: + # Always calculate the release of the running machine, + # needed to determine if we can build fat binaries or not. + + macrelease = macver + # Get the system version. Reading this plist is a documented + # way to get the system version (see the documentation for + # the Gestalt Manager) + try: + f = open('/System/Library/CoreServices/SystemVersion.plist') + except IOError: + # We're on a plain darwin box, fall back to the default + # behaviour. + pass + else: + try: + m = re.search(r'<key>ProductUserVisibleVersion</key>\s*' + r'<string>(.*?)</string>', f.read()) + finally: + f.close() + if m is not None: + macrelease = '.'.join(m.group(1).split('.')[:2]) + # else: fall back to the default behaviour + + if not macver: + macver = macrelease + + if macver: + release = macver + osname = "macosx" + + if ((macrelease + '.') >= '10.4.' and + '-arch' in get_config_vars().get('CFLAGS', '').strip()): + # The universal build will build fat binaries, but not on + # systems before 10.4 + # + # Try to detect 4-way universal builds, those have machine-type + # 'universal' instead of 'fat'. + + machine = 'fat' + cflags = get_config_vars().get('CFLAGS') + + archs = re.findall(r'-arch\s+(\S+)', cflags) + archs = tuple(sorted(set(archs))) + + if len(archs) == 1: + machine = archs[0] + elif archs == ('i386', 'ppc'): + machine = 'fat' + elif archs == ('i386', 'x86_64'): + machine = 'intel' + elif archs == ('i386', 'ppc', 'x86_64'): + machine = 'fat3' + elif archs == ('ppc64', 'x86_64'): + machine = 'fat64' + elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): + machine = 'universal' + else: + raise ValueError( + "Don't know machine value for archs=%r" % (archs,)) + + elif machine == 'i386': + # On OSX the machine type returned by uname is always the + # 32-bit variant, even if the executable architecture is + # the 64-bit variant + if sys.maxsize >= 2**32: + machine = 'x86_64' + + elif machine in ('PowerPC', 'Power_Macintosh'): + # Pick a sane name for the PPC architecture. + # See 'i386' case + if sys.maxsize >= 2**32: + machine = 'ppc64' + else: + machine = 'ppc' + + return "%s-%s-%s" % (osname, release, machine) + + +def get_python_version(): + return _PY_VERSION_SHORT + + +def _print_dict(title, data): + for index, (key, value) in enumerate(sorted(data.items())): + if index == 0: + print('%s: ' % (title)) + print('\t%s = "%s"' % (key, value)) + + +def _main(): + """Display all information sysconfig detains.""" + print('Platform: "%s"' % get_platform()) + print('Python version: "%s"' % get_python_version()) + print('Current installation scheme: "%s"' % _get_default_scheme()) + print() + _print_dict('Paths', get_paths()) + print() + _print_dict('Variables', get_config_vars()) + + +if __name__ == '__main__': + _main() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py new file mode 100755 index 0000000..b0599bc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/_backport/tarfile.py @@ -0,0 +1,2607 @@ +#------------------------------------------------------------------- +# tarfile.py +#------------------------------------------------------------------- +# Copyright (C) 2002 Lars Gustaebel <lars@gustaebel.de> +# All rights reserved. +# +# 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 print_function + +"""Read from and write to tar format archives. +""" + +__version__ = "$Revision$" + +version = "0.9.0" +__author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" +__date__ = "$Date: 2011-02-25 17:42:01 +0200 (Fri, 25 Feb 2011) $" +__cvsid__ = "$Id: tarfile.py 88586 2011-02-25 15:42:01Z marc-andre.lemburg $" +__credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." + +#--------- +# Imports +#--------- +import sys +import os +import stat +import errno +import time +import struct +import copy +import re + +try: + import grp, pwd +except ImportError: + grp = pwd = None + +# os.symlink on Windows prior to 6.0 raises NotImplementedError +symlink_exception = (AttributeError, NotImplementedError) +try: + # WindowsError (1314) will be raised if the caller does not hold the + # SeCreateSymbolicLinkPrivilege privilege + symlink_exception += (WindowsError,) +except NameError: + pass + +# from tarfile import * +__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] + +if sys.version_info[0] < 3: + import __builtin__ as builtins +else: + import builtins + +_open = builtins.open # Since 'open' is TarFile.open + +#--------------------------------------------------------- +# tar constants +#--------------------------------------------------------- +NUL = b"\0" # the null character +BLOCKSIZE = 512 # length of processing blocks +RECORDSIZE = BLOCKSIZE * 20 # length of records +GNU_MAGIC = b"ustar \0" # magic gnu tar string +POSIX_MAGIC = b"ustar\x0000" # magic posix tar string + +LENGTH_NAME = 100 # maximum length of a filename +LENGTH_LINK = 100 # maximum length of a linkname +LENGTH_PREFIX = 155 # maximum length of the prefix field + +REGTYPE = b"0" # regular file +AREGTYPE = b"\0" # regular file +LNKTYPE = b"1" # link (inside tarfile) +SYMTYPE = b"2" # symbolic link +CHRTYPE = b"3" # character special device +BLKTYPE = b"4" # block special device +DIRTYPE = b"5" # directory +FIFOTYPE = b"6" # fifo special device +CONTTYPE = b"7" # contiguous file + +GNUTYPE_LONGNAME = b"L" # GNU tar longname +GNUTYPE_LONGLINK = b"K" # GNU tar longlink +GNUTYPE_SPARSE = b"S" # GNU tar sparse file + +XHDTYPE = b"x" # POSIX.1-2001 extended header +XGLTYPE = b"g" # POSIX.1-2001 global header +SOLARIS_XHDTYPE = b"X" # Solaris extended header + +USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format +GNU_FORMAT = 1 # GNU tar format +PAX_FORMAT = 2 # POSIX.1-2001 (pax) format +DEFAULT_FORMAT = GNU_FORMAT + +#--------------------------------------------------------- +# tarfile constants +#--------------------------------------------------------- +# File types that tarfile supports: +SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, + SYMTYPE, DIRTYPE, FIFOTYPE, + CONTTYPE, CHRTYPE, BLKTYPE, + GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, + GNUTYPE_SPARSE) + +# File types that will be treated as a regular file. +REGULAR_TYPES = (REGTYPE, AREGTYPE, + CONTTYPE, GNUTYPE_SPARSE) + +# File types that are part of the GNU tar format. +GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, + GNUTYPE_SPARSE) + +# Fields from a pax header that override a TarInfo attribute. +PAX_FIELDS = ("path", "linkpath", "size", "mtime", + "uid", "gid", "uname", "gname") + +# Fields from a pax header that are affected by hdrcharset. +PAX_NAME_FIELDS = set(("path", "linkpath", "uname", "gname")) + +# Fields in a pax header that are numbers, all other fields +# are treated as strings. +PAX_NUMBER_FIELDS = { + "atime": float, + "ctime": float, + "mtime": float, + "uid": int, + "gid": int, + "size": int +} + +#--------------------------------------------------------- +# Bits used in the mode field, values in octal. +#--------------------------------------------------------- +S_IFLNK = 0o120000 # symbolic link +S_IFREG = 0o100000 # regular file +S_IFBLK = 0o060000 # block device +S_IFDIR = 0o040000 # directory +S_IFCHR = 0o020000 # character device +S_IFIFO = 0o010000 # fifo + +TSUID = 0o4000 # set UID on execution +TSGID = 0o2000 # set GID on execution +TSVTX = 0o1000 # reserved + +TUREAD = 0o400 # read by owner +TUWRITE = 0o200 # write by owner +TUEXEC = 0o100 # execute/search by owner +TGREAD = 0o040 # read by group +TGWRITE = 0o020 # write by group +TGEXEC = 0o010 # execute/search by group +TOREAD = 0o004 # read by other +TOWRITE = 0o002 # write by other +TOEXEC = 0o001 # execute/search by other + +#--------------------------------------------------------- +# initialization +#--------------------------------------------------------- +if os.name in ("nt", "ce"): + ENCODING = "utf-8" +else: + ENCODING = sys.getfilesystemencoding() + +#--------------------------------------------------------- +# Some useful functions +#--------------------------------------------------------- + +def stn(s, length, encoding, errors): + """Convert a string to a null-terminated bytes object. + """ + s = s.encode(encoding, errors) + return s[:length] + (length - len(s)) * NUL + +def nts(s, encoding, errors): + """Convert a null-terminated bytes object to a string. + """ + p = s.find(b"\0") + if p != -1: + s = s[:p] + return s.decode(encoding, errors) + +def nti(s): + """Convert a number field to a python number. + """ + # There are two possible encodings for a number field, see + # itn() below. + if s[0] != chr(0o200): + try: + n = int(nts(s, "ascii", "strict") or "0", 8) + except ValueError: + raise InvalidHeaderError("invalid header") + else: + n = 0 + for i in range(len(s) - 1): + n <<= 8 + n += ord(s[i + 1]) + return n + +def itn(n, digits=8, format=DEFAULT_FORMAT): + """Convert a python number to a number field. + """ + # POSIX 1003.1-1988 requires numbers to be encoded as a string of + # octal digits followed by a null-byte, this allows values up to + # (8**(digits-1))-1. GNU tar allows storing numbers greater than + # that if necessary. A leading 0o200 byte indicates this particular + # encoding, the following digits-1 bytes are a big-endian + # representation. This allows values up to (256**(digits-1))-1. + if 0 <= n < 8 ** (digits - 1): + s = ("%0*o" % (digits - 1, n)).encode("ascii") + NUL + else: + if format != GNU_FORMAT or n >= 256 ** (digits - 1): + raise ValueError("overflow in number field") + + if n < 0: + # XXX We mimic GNU tar's behaviour with negative numbers, + # this could raise OverflowError. + n = struct.unpack("L", struct.pack("l", n))[0] + + s = bytearray() + for i in range(digits - 1): + s.insert(0, n & 0o377) + n >>= 8 + s.insert(0, 0o200) + return s + +def calc_chksums(buf): + """Calculate the checksum for a member's header by summing up all + characters except for the chksum field which is treated as if + it was filled with spaces. According to the GNU tar sources, + some tars (Sun and NeXT) calculate chksum with signed char, + which will be different if there are chars in the buffer with + the high bit set. So we calculate two checksums, unsigned and + signed. + """ + unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) + signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) + return unsigned_chksum, signed_chksum + +def copyfileobj(src, dst, length=None): + """Copy length bytes from fileobj src to fileobj dst. + If length is None, copy the entire content. + """ + if length == 0: + return + if length is None: + while True: + buf = src.read(16*1024) + if not buf: + break + dst.write(buf) + return + + BUFSIZE = 16 * 1024 + blocks, remainder = divmod(length, BUFSIZE) + for b in range(blocks): + buf = src.read(BUFSIZE) + if len(buf) < BUFSIZE: + raise IOError("end of file reached") + dst.write(buf) + + if remainder != 0: + buf = src.read(remainder) + if len(buf) < remainder: + raise IOError("end of file reached") + dst.write(buf) + return + +filemode_table = ( + ((S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p")), + + ((TUREAD, "r"),), + ((TUWRITE, "w"),), + ((TUEXEC|TSUID, "s"), + (TSUID, "S"), + (TUEXEC, "x")), + + ((TGREAD, "r"),), + ((TGWRITE, "w"),), + ((TGEXEC|TSGID, "s"), + (TSGID, "S"), + (TGEXEC, "x")), + + ((TOREAD, "r"),), + ((TOWRITE, "w"),), + ((TOEXEC|TSVTX, "t"), + (TSVTX, "T"), + (TOEXEC, "x")) +) + +def filemode(mode): + """Convert a file's mode to a string of the form + -rwxrwxrwx. + Used by TarFile.list() + """ + perm = [] + for table in filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) + +class TarError(Exception): + """Base exception.""" + pass +class ExtractError(TarError): + """General exception for extract errors.""" + pass +class ReadError(TarError): + """Exception for unreadable tar archives.""" + pass +class CompressionError(TarError): + """Exception for unavailable compression methods.""" + pass +class StreamError(TarError): + """Exception for unsupported operations on stream-like TarFiles.""" + pass +class HeaderError(TarError): + """Base exception for header errors.""" + pass +class EmptyHeaderError(HeaderError): + """Exception for empty headers.""" + pass +class TruncatedHeaderError(HeaderError): + """Exception for truncated headers.""" + pass +class EOFHeaderError(HeaderError): + """Exception for end of file headers.""" + pass +class InvalidHeaderError(HeaderError): + """Exception for invalid headers.""" + pass +class SubsequentHeaderError(HeaderError): + """Exception for missing and invalid extended headers.""" + pass + +#--------------------------- +# internal stream interface +#--------------------------- +class _LowLevelFile(object): + """Low-level file object. Supports reading and writing. + It is used instead of a regular file object for streaming + access. + """ + + def __init__(self, name, mode): + mode = { + "r": os.O_RDONLY, + "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, + }[mode] + if hasattr(os, "O_BINARY"): + mode |= os.O_BINARY + self.fd = os.open(name, mode, 0o666) + + def close(self): + os.close(self.fd) + + def read(self, size): + return os.read(self.fd, size) + + def write(self, s): + os.write(self.fd, s) + +class _Stream(object): + """Class that serves as an adapter between TarFile and + a stream-like object. The stream-like object only + needs to have a read() or write() method and is accessed + blockwise. Use of gzip or bzip2 compression is possible. + A stream-like object could be for example: sys.stdin, + sys.stdout, a socket, a tape device etc. + + _Stream is intended to be used only internally. + """ + + def __init__(self, name, mode, comptype, fileobj, bufsize): + """Construct a _Stream object. + """ + self._extfileobj = True + if fileobj is None: + fileobj = _LowLevelFile(name, mode) + self._extfileobj = False + + if comptype == '*': + # Enable transparent compression detection for the + # stream interface + fileobj = _StreamProxy(fileobj) + comptype = fileobj.getcomptype() + + self.name = name or "" + self.mode = mode + self.comptype = comptype + self.fileobj = fileobj + self.bufsize = bufsize + self.buf = b"" + self.pos = 0 + self.closed = False + + try: + if comptype == "gz": + try: + import zlib + except ImportError: + raise CompressionError("zlib module is not available") + self.zlib = zlib + self.crc = zlib.crc32(b"") + if mode == "r": + self._init_read_gz() + else: + self._init_write_gz() + + if comptype == "bz2": + try: + import bz2 + except ImportError: + raise CompressionError("bz2 module is not available") + if mode == "r": + self.dbuf = b"" + self.cmp = bz2.BZ2Decompressor() + else: + self.cmp = bz2.BZ2Compressor() + except: + if not self._extfileobj: + self.fileobj.close() + self.closed = True + raise + + def __del__(self): + if hasattr(self, "closed") and not self.closed: + self.close() + + def _init_write_gz(self): + """Initialize for writing with gzip compression. + """ + self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, + -self.zlib.MAX_WBITS, + self.zlib.DEF_MEM_LEVEL, + 0) + timestamp = struct.pack("<L", int(time.time())) + self.__write(b"\037\213\010\010" + timestamp + b"\002\377") + if self.name.endswith(".gz"): + self.name = self.name[:-3] + # RFC1952 says we must use ISO-8859-1 for the FNAME field. + self.__write(self.name.encode("iso-8859-1", "replace") + NUL) + + def write(self, s): + """Write string s to the stream. + """ + if self.comptype == "gz": + self.crc = self.zlib.crc32(s, self.crc) + self.pos += len(s) + if self.comptype != "tar": + s = self.cmp.compress(s) + self.__write(s) + + def __write(self, s): + """Write string s to the stream if a whole new block + is ready to be written. + """ + self.buf += s + while len(self.buf) > self.bufsize: + self.fileobj.write(self.buf[:self.bufsize]) + self.buf = self.buf[self.bufsize:] + + def close(self): + """Close the _Stream object. No operation should be + done on it afterwards. + """ + if self.closed: + return + + if self.mode == "w" and self.comptype != "tar": + self.buf += self.cmp.flush() + + if self.mode == "w" and self.buf: + self.fileobj.write(self.buf) + self.buf = b"" + if self.comptype == "gz": + # The native zlib crc is an unsigned 32-bit integer, but + # the Python wrapper implicitly casts that to a signed C + # long. So, on a 32-bit box self.crc may "look negative", + # while the same crc on a 64-bit box may "look positive". + # To avoid irksome warnings from the `struct` module, force + # it to look positive on all boxes. + self.fileobj.write(struct.pack("<L", self.crc & 0xffffffff)) + self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFF)) + + if not self._extfileobj: + self.fileobj.close() + + self.closed = True + + def _init_read_gz(self): + """Initialize for reading a gzip compressed fileobj. + """ + self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS) + self.dbuf = b"" + + # taken from gzip.GzipFile with some alterations + if self.__read(2) != b"\037\213": + raise ReadError("not a gzip file") + if self.__read(1) != b"\010": + raise CompressionError("unsupported compression method") + + flag = ord(self.__read(1)) + self.__read(6) + + if flag & 4: + xlen = ord(self.__read(1)) + 256 * ord(self.__read(1)) + self.read(xlen) + if flag & 8: + while True: + s = self.__read(1) + if not s or s == NUL: + break + if flag & 16: + while True: + s = self.__read(1) + if not s or s == NUL: + break + if flag & 2: + self.__read(2) + + def tell(self): + """Return the stream's file pointer position. + """ + return self.pos + + def seek(self, pos=0): + """Set the stream's file pointer to pos. Negative seeking + is forbidden. + """ + if pos - self.pos >= 0: + blocks, remainder = divmod(pos - self.pos, self.bufsize) + for i in range(blocks): + self.read(self.bufsize) + self.read(remainder) + else: + raise StreamError("seeking backwards is not allowed") + return self.pos + + def read(self, size=None): + """Return the next size number of bytes from the stream. + If size is not defined, return all bytes of the stream + up to EOF. + """ + if size is None: + t = [] + while True: + buf = self._read(self.bufsize) + if not buf: + break + t.append(buf) + buf = "".join(t) + else: + buf = self._read(size) + self.pos += len(buf) + return buf + + def _read(self, size): + """Return size bytes from the stream. + """ + if self.comptype == "tar": + return self.__read(size) + + c = len(self.dbuf) + while c < size: + buf = self.__read(self.bufsize) + if not buf: + break + try: + buf = self.cmp.decompress(buf) + except IOError: + raise ReadError("invalid compressed data") + self.dbuf += buf + c += len(buf) + buf = self.dbuf[:size] + self.dbuf = self.dbuf[size:] + return buf + + def __read(self, size): + """Return size bytes from stream. If internal buffer is empty, + read another block from the stream. + """ + c = len(self.buf) + while c < size: + buf = self.fileobj.read(self.bufsize) + if not buf: + break + self.buf += buf + c += len(buf) + buf = self.buf[:size] + self.buf = self.buf[size:] + return buf +# class _Stream + +class _StreamProxy(object): + """Small proxy class that enables transparent compression + detection for the Stream interface (mode 'r|*'). + """ + + def __init__(self, fileobj): + self.fileobj = fileobj + self.buf = self.fileobj.read(BLOCKSIZE) + + def read(self, size): + self.read = self.fileobj.read + return self.buf + + def getcomptype(self): + if self.buf.startswith(b"\037\213\010"): + return "gz" + if self.buf.startswith(b"BZh91"): + return "bz2" + return "tar" + + def close(self): + self.fileobj.close() +# class StreamProxy + +class _BZ2Proxy(object): + """Small proxy class that enables external file object + support for "r:bz2" and "w:bz2" modes. This is actually + a workaround for a limitation in bz2 module's BZ2File + class which (unlike gzip.GzipFile) has no support for + a file object argument. + """ + + blocksize = 16 * 1024 + + def __init__(self, fileobj, mode): + self.fileobj = fileobj + self.mode = mode + self.name = getattr(self.fileobj, "name", None) + self.init() + + def init(self): + import bz2 + self.pos = 0 + if self.mode == "r": + self.bz2obj = bz2.BZ2Decompressor() + self.fileobj.seek(0) + self.buf = b"" + else: + self.bz2obj = bz2.BZ2Compressor() + + def read(self, size): + x = len(self.buf) + while x < size: + raw = self.fileobj.read(self.blocksize) + if not raw: + break + data = self.bz2obj.decompress(raw) + self.buf += data + x += len(data) + + buf = self.buf[:size] + self.buf = self.buf[size:] + self.pos += len(buf) + return buf + + def seek(self, pos): + if pos < self.pos: + self.init() + self.read(pos - self.pos) + + def tell(self): + return self.pos + + def write(self, data): + self.pos += len(data) + raw = self.bz2obj.compress(data) + self.fileobj.write(raw) + + def close(self): + if self.mode == "w": + raw = self.bz2obj.flush() + self.fileobj.write(raw) +# class _BZ2Proxy + +#------------------------ +# Extraction file object +#------------------------ +class _FileInFile(object): + """A thin wrapper around an existing file object that + provides a part of its data as an individual file + object. + """ + + def __init__(self, fileobj, offset, size, blockinfo=None): + self.fileobj = fileobj + self.offset = offset + self.size = size + self.position = 0 + + if blockinfo is None: + blockinfo = [(0, size)] + + # Construct a map with data and zero blocks. + self.map_index = 0 + self.map = [] + lastpos = 0 + realpos = self.offset + for offset, size in blockinfo: + if offset > lastpos: + self.map.append((False, lastpos, offset, None)) + self.map.append((True, offset, offset + size, realpos)) + realpos += size + lastpos = offset + size + if lastpos < self.size: + self.map.append((False, lastpos, self.size, None)) + + def seekable(self): + if not hasattr(self.fileobj, "seekable"): + # XXX gzip.GzipFile and bz2.BZ2File + return True + return self.fileobj.seekable() + + def tell(self): + """Return the current file position. + """ + return self.position + + def seek(self, position): + """Seek to a position in the file. + """ + self.position = position + + def read(self, size=None): + """Read data from the file. + """ + if size is None: + size = self.size - self.position + else: + size = min(size, self.size - self.position) + + buf = b"" + while size > 0: + while True: + data, start, stop, offset = self.map[self.map_index] + if start <= self.position < stop: + break + else: + self.map_index += 1 + if self.map_index == len(self.map): + self.map_index = 0 + length = min(size, stop - self.position) + if data: + self.fileobj.seek(offset + (self.position - start)) + buf += self.fileobj.read(length) + else: + buf += NUL * length + size -= length + self.position += length + return buf +#class _FileInFile + + +class ExFileObject(object): + """File-like object for reading an archive member. + Is returned by TarFile.extractfile(). + """ + blocksize = 1024 + + def __init__(self, tarfile, tarinfo): + self.fileobj = _FileInFile(tarfile.fileobj, + tarinfo.offset_data, + tarinfo.size, + tarinfo.sparse) + self.name = tarinfo.name + self.mode = "r" + self.closed = False + self.size = tarinfo.size + + self.position = 0 + self.buffer = b"" + + def readable(self): + return True + + def writable(self): + return False + + def seekable(self): + return self.fileobj.seekable() + + def read(self, size=None): + """Read at most size bytes from the file. If size is not + present or None, read all data until EOF is reached. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + buf = b"" + if self.buffer: + if size is None: + buf = self.buffer + self.buffer = b"" + else: + buf = self.buffer[:size] + self.buffer = self.buffer[size:] + + if size is None: + buf += self.fileobj.read() + else: + buf += self.fileobj.read(size - len(buf)) + + self.position += len(buf) + return buf + + # XXX TextIOWrapper uses the read1() method. + read1 = read + + def readline(self, size=-1): + """Read one entire line from the file. If size is present + and non-negative, return a string with at most that + size, which may be an incomplete line. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + pos = self.buffer.find(b"\n") + 1 + if pos == 0: + # no newline found. + while True: + buf = self.fileobj.read(self.blocksize) + self.buffer += buf + if not buf or b"\n" in buf: + pos = self.buffer.find(b"\n") + 1 + if pos == 0: + # no newline found. + pos = len(self.buffer) + break + + if size != -1: + pos = min(size, pos) + + buf = self.buffer[:pos] + self.buffer = self.buffer[pos:] + self.position += len(buf) + return buf + + def readlines(self): + """Return a list with all remaining lines. + """ + result = [] + while True: + line = self.readline() + if not line: break + result.append(line) + return result + + def tell(self): + """Return the current file position. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + return self.position + + def seek(self, pos, whence=os.SEEK_SET): + """Seek to a position in the file. + """ + if self.closed: + raise ValueError("I/O operation on closed file") + + if whence == os.SEEK_SET: + self.position = min(max(pos, 0), self.size) + elif whence == os.SEEK_CUR: + if pos < 0: + self.position = max(self.position + pos, 0) + else: + self.position = min(self.position + pos, self.size) + elif whence == os.SEEK_END: + self.position = max(min(self.size + pos, self.size), 0) + else: + raise ValueError("Invalid argument") + + self.buffer = b"" + self.fileobj.seek(self.position) + + def close(self): + """Close the file object. + """ + self.closed = True + + def __iter__(self): + """Get an iterator over the file's lines. + """ + while True: + line = self.readline() + if not line: + break + yield line +#class ExFileObject + +#------------------ +# Exported Classes +#------------------ +class TarInfo(object): + """Informational class which holds the details about an + archive member given by a tar header block. + TarInfo objects are returned by TarFile.getmember(), + TarFile.getmembers() and TarFile.gettarinfo() and are + usually created internally. + """ + + __slots__ = ("name", "mode", "uid", "gid", "size", "mtime", + "chksum", "type", "linkname", "uname", "gname", + "devmajor", "devminor", + "offset", "offset_data", "pax_headers", "sparse", + "tarfile", "_sparse_structs", "_link_target") + + def __init__(self, name=""): + """Construct a TarInfo object. name is the optional name + of the member. + """ + self.name = name # member name + self.mode = 0o644 # file permissions + self.uid = 0 # user id + self.gid = 0 # group id + self.size = 0 # file size + self.mtime = 0 # modification time + self.chksum = 0 # header checksum + self.type = REGTYPE # member type + self.linkname = "" # link name + self.uname = "" # user name + self.gname = "" # group name + self.devmajor = 0 # device major number + self.devminor = 0 # device minor number + + self.offset = 0 # the tar header starts here + self.offset_data = 0 # the file's data starts here + + self.sparse = None # sparse member information + self.pax_headers = {} # pax header information + + # In pax headers the "name" and "linkname" field are called + # "path" and "linkpath". + def _getpath(self): + return self.name + def _setpath(self, name): + self.name = name + path = property(_getpath, _setpath) + + def _getlinkpath(self): + return self.linkname + def _setlinkpath(self, linkname): + self.linkname = linkname + linkpath = property(_getlinkpath, _setlinkpath) + + def __repr__(self): + return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) + + def get_info(self): + """Return the TarInfo's attributes as a dictionary. + """ + info = { + "name": self.name, + "mode": self.mode & 0o7777, + "uid": self.uid, + "gid": self.gid, + "size": self.size, + "mtime": self.mtime, + "chksum": self.chksum, + "type": self.type, + "linkname": self.linkname, + "uname": self.uname, + "gname": self.gname, + "devmajor": self.devmajor, + "devminor": self.devminor + } + + if info["type"] == DIRTYPE and not info["name"].endswith("/"): + info["name"] += "/" + + return info + + def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescape"): + """Return a tar header as a string of 512 byte blocks. + """ + info = self.get_info() + + if format == USTAR_FORMAT: + return self.create_ustar_header(info, encoding, errors) + elif format == GNU_FORMAT: + return self.create_gnu_header(info, encoding, errors) + elif format == PAX_FORMAT: + return self.create_pax_header(info, encoding) + else: + raise ValueError("invalid format") + + def create_ustar_header(self, info, encoding, errors): + """Return the object as a ustar header block. + """ + info["magic"] = POSIX_MAGIC + + if len(info["linkname"]) > LENGTH_LINK: + raise ValueError("linkname is too long") + + if len(info["name"]) > LENGTH_NAME: + info["prefix"], info["name"] = self._posix_split_name(info["name"]) + + return self._create_header(info, USTAR_FORMAT, encoding, errors) + + def create_gnu_header(self, info, encoding, errors): + """Return the object as a GNU header block sequence. + """ + info["magic"] = GNU_MAGIC + + buf = b"" + if len(info["linkname"]) > LENGTH_LINK: + buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK, encoding, errors) + + if len(info["name"]) > LENGTH_NAME: + buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME, encoding, errors) + + return buf + self._create_header(info, GNU_FORMAT, encoding, errors) + + def create_pax_header(self, info, encoding): + """Return the object as a ustar header block. If it cannot be + represented this way, prepend a pax extended header sequence + with supplement information. + """ + info["magic"] = POSIX_MAGIC + pax_headers = self.pax_headers.copy() + + # Test string fields for values that exceed the field length or cannot + # be represented in ASCII encoding. + for name, hname, length in ( + ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), + ("uname", "uname", 32), ("gname", "gname", 32)): + + if hname in pax_headers: + # The pax header has priority. + continue + + # Try to encode the string as ASCII. + try: + info[name].encode("ascii", "strict") + except UnicodeEncodeError: + pax_headers[hname] = info[name] + continue + + if len(info[name]) > length: + pax_headers[hname] = info[name] + + # Test number fields for values that exceed the field limit or values + # that like to be stored as float. + for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): + if name in pax_headers: + # The pax header has priority. Avoid overflow. + info[name] = 0 + continue + + val = info[name] + if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): + pax_headers[name] = str(val) + info[name] = 0 + + # Create a pax extended header if necessary. + if pax_headers: + buf = self._create_pax_generic_header(pax_headers, XHDTYPE, encoding) + else: + buf = b"" + + return buf + self._create_header(info, USTAR_FORMAT, "ascii", "replace") + + @classmethod + def create_pax_global_header(cls, pax_headers): + """Return the object as a pax global header block sequence. + """ + return cls._create_pax_generic_header(pax_headers, XGLTYPE, "utf8") + + def _posix_split_name(self, name): + """Split a name longer than 100 chars into a prefix + and a name part. + """ + prefix = name[:LENGTH_PREFIX + 1] + while prefix and prefix[-1] != "/": + prefix = prefix[:-1] + + name = name[len(prefix):] + prefix = prefix[:-1] + + if not prefix or len(name) > LENGTH_NAME: + raise ValueError("name is too long") + return prefix, name + + @staticmethod + def _create_header(info, format, encoding, errors): + """Return a header block. info is a dictionary with file + information, format must be one of the *_FORMAT constants. + """ + parts = [ + stn(info.get("name", ""), 100, encoding, errors), + itn(info.get("mode", 0) & 0o7777, 8, format), + itn(info.get("uid", 0), 8, format), + itn(info.get("gid", 0), 8, format), + itn(info.get("size", 0), 12, format), + itn(info.get("mtime", 0), 12, format), + b" ", # checksum field + info.get("type", REGTYPE), + stn(info.get("linkname", ""), 100, encoding, errors), + info.get("magic", POSIX_MAGIC), + stn(info.get("uname", ""), 32, encoding, errors), + stn(info.get("gname", ""), 32, encoding, errors), + itn(info.get("devmajor", 0), 8, format), + itn(info.get("devminor", 0), 8, format), + stn(info.get("prefix", ""), 155, encoding, errors) + ] + + buf = struct.pack("%ds" % BLOCKSIZE, b"".join(parts)) + chksum = calc_chksums(buf[-BLOCKSIZE:])[0] + buf = buf[:-364] + ("%06o\0" % chksum).encode("ascii") + buf[-357:] + return buf + + @staticmethod + def _create_payload(payload): + """Return the string payload filled with zero bytes + up to the next 512 byte border. + """ + blocks, remainder = divmod(len(payload), BLOCKSIZE) + if remainder > 0: + payload += (BLOCKSIZE - remainder) * NUL + return payload + + @classmethod + def _create_gnu_long_header(cls, name, type, encoding, errors): + """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence + for name. + """ + name = name.encode(encoding, errors) + NUL + + info = {} + info["name"] = "././@LongLink" + info["type"] = type + info["size"] = len(name) + info["magic"] = GNU_MAGIC + + # create extended header + name blocks. + return cls._create_header(info, USTAR_FORMAT, encoding, errors) + \ + cls._create_payload(name) + + @classmethod + def _create_pax_generic_header(cls, pax_headers, type, encoding): + """Return a POSIX.1-2008 extended or global header sequence + that contains a list of keyword, value pairs. The values + must be strings. + """ + # Check if one of the fields contains surrogate characters and thereby + # forces hdrcharset=BINARY, see _proc_pax() for more information. + binary = False + for keyword, value in pax_headers.items(): + try: + value.encode("utf8", "strict") + except UnicodeEncodeError: + binary = True + break + + records = b"" + if binary: + # Put the hdrcharset field at the beginning of the header. + records += b"21 hdrcharset=BINARY\n" + + for keyword, value in pax_headers.items(): + keyword = keyword.encode("utf8") + if binary: + # Try to restore the original byte representation of `value'. + # Needless to say, that the encoding must match the string. + value = value.encode(encoding, "surrogateescape") + else: + value = value.encode("utf8") + + l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' + n = p = 0 + while True: + n = l + len(str(p)) + if n == p: + break + p = n + records += bytes(str(p), "ascii") + b" " + keyword + b"=" + value + b"\n" + + # We use a hardcoded "././@PaxHeader" name like star does + # instead of the one that POSIX recommends. + info = {} + info["name"] = "././@PaxHeader" + info["type"] = type + info["size"] = len(records) + info["magic"] = POSIX_MAGIC + + # Create pax header + record blocks. + return cls._create_header(info, USTAR_FORMAT, "ascii", "replace") + \ + cls._create_payload(records) + + @classmethod + def frombuf(cls, buf, encoding, errors): + """Construct a TarInfo object from a 512 byte bytes object. + """ + if len(buf) == 0: + raise EmptyHeaderError("empty header") + if len(buf) != BLOCKSIZE: + raise TruncatedHeaderError("truncated header") + if buf.count(NUL) == BLOCKSIZE: + raise EOFHeaderError("end of file header") + + chksum = nti(buf[148:156]) + if chksum not in calc_chksums(buf): + raise InvalidHeaderError("bad checksum") + + obj = cls() + obj.name = nts(buf[0:100], encoding, errors) + obj.mode = nti(buf[100:108]) + obj.uid = nti(buf[108:116]) + obj.gid = nti(buf[116:124]) + obj.size = nti(buf[124:136]) + obj.mtime = nti(buf[136:148]) + obj.chksum = chksum + obj.type = buf[156:157] + obj.linkname = nts(buf[157:257], encoding, errors) + obj.uname = nts(buf[265:297], encoding, errors) + obj.gname = nts(buf[297:329], encoding, errors) + obj.devmajor = nti(buf[329:337]) + obj.devminor = nti(buf[337:345]) + prefix = nts(buf[345:500], encoding, errors) + + # Old V7 tar format represents a directory as a regular + # file with a trailing slash. + if obj.type == AREGTYPE and obj.name.endswith("/"): + obj.type = DIRTYPE + + # The old GNU sparse format occupies some of the unused + # space in the buffer for up to 4 sparse structures. + # Save the them for later processing in _proc_sparse(). + if obj.type == GNUTYPE_SPARSE: + pos = 386 + structs = [] + for i in range(4): + try: + offset = nti(buf[pos:pos + 12]) + numbytes = nti(buf[pos + 12:pos + 24]) + except ValueError: + break + structs.append((offset, numbytes)) + pos += 24 + isextended = bool(buf[482]) + origsize = nti(buf[483:495]) + obj._sparse_structs = (structs, isextended, origsize) + + # Remove redundant slashes from directories. + if obj.isdir(): + obj.name = obj.name.rstrip("/") + + # Reconstruct a ustar longname. + if prefix and obj.type not in GNU_TYPES: + obj.name = prefix + "/" + obj.name + return obj + + @classmethod + def fromtarfile(cls, tarfile): + """Return the next TarInfo object from TarFile object + tarfile. + """ + buf = tarfile.fileobj.read(BLOCKSIZE) + obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors) + obj.offset = tarfile.fileobj.tell() - BLOCKSIZE + return obj._proc_member(tarfile) + + #-------------------------------------------------------------------------- + # The following are methods that are called depending on the type of a + # member. The entry point is _proc_member() which can be overridden in a + # subclass to add custom _proc_*() methods. A _proc_*() method MUST + # implement the following + # operations: + # 1. Set self.offset_data to the position where the data blocks begin, + # if there is data that follows. + # 2. Set tarfile.offset to the position where the next member's header will + # begin. + # 3. Return self or another valid TarInfo object. + def _proc_member(self, tarfile): + """Choose the right processing method depending on + the type and call it. + """ + if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): + return self._proc_gnulong(tarfile) + elif self.type == GNUTYPE_SPARSE: + return self._proc_sparse(tarfile) + elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): + return self._proc_pax(tarfile) + else: + return self._proc_builtin(tarfile) + + def _proc_builtin(self, tarfile): + """Process a builtin type or an unknown type which + will be treated as a regular file. + """ + self.offset_data = tarfile.fileobj.tell() + offset = self.offset_data + if self.isreg() or self.type not in SUPPORTED_TYPES: + # Skip the following data blocks. + offset += self._block(self.size) + tarfile.offset = offset + + # Patch the TarInfo object with saved global + # header information. + self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) + + return self + + def _proc_gnulong(self, tarfile): + """Process the blocks that hold a GNU longname + or longlink member. + """ + buf = tarfile.fileobj.read(self._block(self.size)) + + # Fetch the next header and process it. + try: + next = self.fromtarfile(tarfile) + except HeaderError: + raise SubsequentHeaderError("missing or bad subsequent header") + + # Patch the TarInfo object from the next header with + # the longname information. + next.offset = self.offset + if self.type == GNUTYPE_LONGNAME: + next.name = nts(buf, tarfile.encoding, tarfile.errors) + elif self.type == GNUTYPE_LONGLINK: + next.linkname = nts(buf, tarfile.encoding, tarfile.errors) + + return next + + def _proc_sparse(self, tarfile): + """Process a GNU sparse header plus extra headers. + """ + # We already collected some sparse structures in frombuf(). + structs, isextended, origsize = self._sparse_structs + del self._sparse_structs + + # Collect sparse structures from extended header blocks. + while isextended: + buf = tarfile.fileobj.read(BLOCKSIZE) + pos = 0 + for i in range(21): + try: + offset = nti(buf[pos:pos + 12]) + numbytes = nti(buf[pos + 12:pos + 24]) + except ValueError: + break + if offset and numbytes: + structs.append((offset, numbytes)) + pos += 24 + isextended = bool(buf[504]) + self.sparse = structs + + self.offset_data = tarfile.fileobj.tell() + tarfile.offset = self.offset_data + self._block(self.size) + self.size = origsize + return self + + def _proc_pax(self, tarfile): + """Process an extended or global header as described in + POSIX.1-2008. + """ + # Read the header information. + buf = tarfile.fileobj.read(self._block(self.size)) + + # A pax header stores supplemental information for either + # the following file (extended) or all following files + # (global). + if self.type == XGLTYPE: + pax_headers = tarfile.pax_headers + else: + pax_headers = tarfile.pax_headers.copy() + + # Check if the pax header contains a hdrcharset field. This tells us + # the encoding of the path, linkpath, uname and gname fields. Normally, + # these fields are UTF-8 encoded but since POSIX.1-2008 tar + # implementations are allowed to store them as raw binary strings if + # the translation to UTF-8 fails. + match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) + if match is not None: + pax_headers["hdrcharset"] = match.group(1).decode("utf8") + + # For the time being, we don't care about anything other than "BINARY". + # The only other value that is currently allowed by the standard is + # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. + hdrcharset = pax_headers.get("hdrcharset") + if hdrcharset == "BINARY": + encoding = tarfile.encoding + else: + encoding = "utf8" + + # Parse pax header information. A record looks like that: + # "%d %s=%s\n" % (length, keyword, value). length is the size + # of the complete record including the length field itself and + # the newline. keyword and value are both UTF-8 encoded strings. + regex = re.compile(br"(\d+) ([^=]+)=") + pos = 0 + while True: + match = regex.match(buf, pos) + if not match: + break + + length, keyword = match.groups() + length = int(length) + value = buf[match.end(2) + 1:match.start(1) + length - 1] + + # Normally, we could just use "utf8" as the encoding and "strict" + # as the error handler, but we better not take the risk. For + # example, GNU tar <= 1.23 is known to store filenames it cannot + # translate to UTF-8 as raw strings (unfortunately without a + # hdrcharset=BINARY header). + # We first try the strict standard encoding, and if that fails we + # fall back on the user's encoding and error handler. + keyword = self._decode_pax_field(keyword, "utf8", "utf8", + tarfile.errors) + if keyword in PAX_NAME_FIELDS: + value = self._decode_pax_field(value, encoding, tarfile.encoding, + tarfile.errors) + else: + value = self._decode_pax_field(value, "utf8", "utf8", + tarfile.errors) + + pax_headers[keyword] = value + pos += length + + # Fetch the next header. + try: + next = self.fromtarfile(tarfile) + except HeaderError: + raise SubsequentHeaderError("missing or bad subsequent header") + + # Process GNU sparse information. + if "GNU.sparse.map" in pax_headers: + # GNU extended sparse format version 0.1. + self._proc_gnusparse_01(next, pax_headers) + + elif "GNU.sparse.size" in pax_headers: + # GNU extended sparse format version 0.0. + self._proc_gnusparse_00(next, pax_headers, buf) + + elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": + # GNU extended sparse format version 1.0. + self._proc_gnusparse_10(next, pax_headers, tarfile) + + if self.type in (XHDTYPE, SOLARIS_XHDTYPE): + # Patch the TarInfo object with the extended header info. + next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) + next.offset = self.offset + + if "size" in pax_headers: + # If the extended header replaces the size field, + # we need to recalculate the offset where the next + # header starts. + offset = next.offset_data + if next.isreg() or next.type not in SUPPORTED_TYPES: + offset += next._block(next.size) + tarfile.offset = offset + + return next + + def _proc_gnusparse_00(self, next, pax_headers, buf): + """Process a GNU tar extended sparse header, version 0.0. + """ + offsets = [] + for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): + offsets.append(int(match.group(1))) + numbytes = [] + for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): + numbytes.append(int(match.group(1))) + next.sparse = list(zip(offsets, numbytes)) + + def _proc_gnusparse_01(self, next, pax_headers): + """Process a GNU tar extended sparse header, version 0.1. + """ + sparse = [int(x) for x in pax_headers["GNU.sparse.map"].split(",")] + next.sparse = list(zip(sparse[::2], sparse[1::2])) + + def _proc_gnusparse_10(self, next, pax_headers, tarfile): + """Process a GNU tar extended sparse header, version 1.0. + """ + fields = None + sparse = [] + buf = tarfile.fileobj.read(BLOCKSIZE) + fields, buf = buf.split(b"\n", 1) + fields = int(fields) + while len(sparse) < fields * 2: + if b"\n" not in buf: + buf += tarfile.fileobj.read(BLOCKSIZE) + number, buf = buf.split(b"\n", 1) + sparse.append(int(number)) + next.offset_data = tarfile.fileobj.tell() + next.sparse = list(zip(sparse[::2], sparse[1::2])) + + def _apply_pax_info(self, pax_headers, encoding, errors): + """Replace fields with supplemental information from a previous + pax extended or global header. + """ + for keyword, value in pax_headers.items(): + if keyword == "GNU.sparse.name": + setattr(self, "path", value) + elif keyword == "GNU.sparse.size": + setattr(self, "size", int(value)) + elif keyword == "GNU.sparse.realsize": + setattr(self, "size", int(value)) + elif keyword in PAX_FIELDS: + if keyword in PAX_NUMBER_FIELDS: + try: + value = PAX_NUMBER_FIELDS[keyword](value) + except ValueError: + value = 0 + if keyword == "path": + value = value.rstrip("/") + setattr(self, keyword, value) + + self.pax_headers = pax_headers.copy() + + def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors): + """Decode a single field from a pax record. + """ + try: + return value.decode(encoding, "strict") + except UnicodeDecodeError: + return value.decode(fallback_encoding, fallback_errors) + + def _block(self, count): + """Round up a byte count by BLOCKSIZE and return it, + e.g. _block(834) => 1024. + """ + blocks, remainder = divmod(count, BLOCKSIZE) + if remainder: + blocks += 1 + return blocks * BLOCKSIZE + + def isreg(self): + return self.type in REGULAR_TYPES + def isfile(self): + return self.isreg() + def isdir(self): + return self.type == DIRTYPE + def issym(self): + return self.type == SYMTYPE + def islnk(self): + return self.type == LNKTYPE + def ischr(self): + return self.type == CHRTYPE + def isblk(self): + return self.type == BLKTYPE + def isfifo(self): + return self.type == FIFOTYPE + def issparse(self): + return self.sparse is not None + def isdev(self): + return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) +# class TarInfo + +class TarFile(object): + """The TarFile Class provides an interface to tar archives. + """ + + debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) + + dereference = False # If true, add content of linked file to the + # tar file, else the link. + + ignore_zeros = False # If true, skips empty or invalid blocks and + # continues processing. + + errorlevel = 1 # If 0, fatal errors only appear in debug + # messages (if debug >= 0). If > 0, errors + # are passed to the caller as exceptions. + + format = DEFAULT_FORMAT # The format to use when creating an archive. + + encoding = ENCODING # Encoding for 8-bit character strings. + + errors = None # Error handler for unicode conversion. + + tarinfo = TarInfo # The default TarInfo class to use. + + fileobject = ExFileObject # The default ExFileObject class to use. + + def __init__(self, name=None, mode="r", fileobj=None, format=None, + tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, + errors="surrogateescape", pax_headers=None, debug=None, errorlevel=None): + """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to + read from an existing archive, 'a' to append data to an existing + file or 'w' to create a new file overwriting an existing one. `mode' + defaults to 'r'. + If `fileobj' is given, it is used for reading or writing data. If it + can be determined, `mode' is overridden by `fileobj's mode. + `fileobj' is not closed, when TarFile is closed. + """ + if len(mode) > 1 or mode not in "raw": + raise ValueError("mode must be 'r', 'a' or 'w'") + self.mode = mode + self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] + + if not fileobj: + if self.mode == "a" and not os.path.exists(name): + # Create nonexistent files in append mode. + self.mode = "w" + self._mode = "wb" + fileobj = bltn_open(name, self._mode) + self._extfileobj = False + else: + if name is None and hasattr(fileobj, "name"): + name = fileobj.name + if hasattr(fileobj, "mode"): + self._mode = fileobj.mode + self._extfileobj = True + self.name = os.path.abspath(name) if name else None + self.fileobj = fileobj + + # Init attributes. + if format is not None: + self.format = format + if tarinfo is not None: + self.tarinfo = tarinfo + if dereference is not None: + self.dereference = dereference + if ignore_zeros is not None: + self.ignore_zeros = ignore_zeros + if encoding is not None: + self.encoding = encoding + self.errors = errors + + if pax_headers is not None and self.format == PAX_FORMAT: + self.pax_headers = pax_headers + else: + self.pax_headers = {} + + if debug is not None: + self.debug = debug + if errorlevel is not None: + self.errorlevel = errorlevel + + # Init datastructures. + self.closed = False + self.members = [] # list of members as TarInfo objects + self._loaded = False # flag if all members have been read + self.offset = self.fileobj.tell() + # current position in the archive file + self.inodes = {} # dictionary caching the inodes of + # archive members already added + + try: + if self.mode == "r": + self.firstmember = None + self.firstmember = self.next() + + if self.mode == "a": + # Move to the end of the archive, + # before the first empty block. + while True: + self.fileobj.seek(self.offset) + try: + tarinfo = self.tarinfo.fromtarfile(self) + self.members.append(tarinfo) + except EOFHeaderError: + self.fileobj.seek(self.offset) + break + except HeaderError as e: + raise ReadError(str(e)) + + if self.mode in "aw": + self._loaded = True + + if self.pax_headers: + buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) + self.fileobj.write(buf) + self.offset += len(buf) + except: + if not self._extfileobj: + self.fileobj.close() + self.closed = True + raise + + #-------------------------------------------------------------------------- + # Below are the classmethods which act as alternate constructors to the + # TarFile class. The open() method is the only one that is needed for + # public use; it is the "super"-constructor and is able to select an + # adequate "sub"-constructor for a particular compression using the mapping + # from OPEN_METH. + # + # This concept allows one to subclass TarFile without losing the comfort of + # the super-constructor. A sub-constructor is registered and made available + # by adding it to the mapping in OPEN_METH. + + @classmethod + def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): + """Open a tar archive for reading, writing or appending. Return + an appropriate TarFile class. + + mode: + 'r' or 'r:*' open for reading with transparent compression + 'r:' open for reading exclusively uncompressed + 'r:gz' open for reading with gzip compression + 'r:bz2' open for reading with bzip2 compression + 'a' or 'a:' open for appending, creating the file if necessary + 'w' or 'w:' open for writing without compression + 'w:gz' open for writing with gzip compression + 'w:bz2' open for writing with bzip2 compression + + 'r|*' open a stream of tar blocks with transparent compression + 'r|' open an uncompressed stream of tar blocks for reading + 'r|gz' open a gzip compressed stream of tar blocks + 'r|bz2' open a bzip2 compressed stream of tar blocks + 'w|' open an uncompressed stream for writing + 'w|gz' open a gzip compressed stream for writing + 'w|bz2' open a bzip2 compressed stream for writing + """ + + if not name and not fileobj: + raise ValueError("nothing to open") + + if mode in ("r", "r:*"): + # Find out which *open() is appropriate for opening the file. + for comptype in cls.OPEN_METH: + func = getattr(cls, cls.OPEN_METH[comptype]) + if fileobj is not None: + saved_pos = fileobj.tell() + try: + return func(name, "r", fileobj, **kwargs) + except (ReadError, CompressionError) as e: + if fileobj is not None: + fileobj.seek(saved_pos) + continue + raise ReadError("file could not be opened successfully") + + elif ":" in mode: + filemode, comptype = mode.split(":", 1) + filemode = filemode or "r" + comptype = comptype or "tar" + + # Select the *open() function according to + # given compression. + if comptype in cls.OPEN_METH: + func = getattr(cls, cls.OPEN_METH[comptype]) + else: + raise CompressionError("unknown compression type %r" % comptype) + return func(name, filemode, fileobj, **kwargs) + + elif "|" in mode: + filemode, comptype = mode.split("|", 1) + filemode = filemode or "r" + comptype = comptype or "tar" + + if filemode not in "rw": + raise ValueError("mode must be 'r' or 'w'") + + stream = _Stream(name, filemode, comptype, fileobj, bufsize) + try: + t = cls(name, filemode, stream, **kwargs) + except: + stream.close() + raise + t._extfileobj = False + return t + + elif mode in "aw": + return cls.taropen(name, mode, fileobj, **kwargs) + + raise ValueError("undiscernible mode") + + @classmethod + def taropen(cls, name, mode="r", fileobj=None, **kwargs): + """Open uncompressed tar archive name for reading or writing. + """ + if len(mode) > 1 or mode not in "raw": + raise ValueError("mode must be 'r', 'a' or 'w'") + return cls(name, mode, fileobj, **kwargs) + + @classmethod + def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): + """Open gzip compressed tar archive name for reading or writing. + Appending is not allowed. + """ + if len(mode) > 1 or mode not in "rw": + raise ValueError("mode must be 'r' or 'w'") + + try: + import gzip + gzip.GzipFile + except (ImportError, AttributeError): + raise CompressionError("gzip module is not available") + + extfileobj = fileobj is not None + try: + fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) + t = cls.taropen(name, mode, fileobj, **kwargs) + except IOError: + if not extfileobj and fileobj is not None: + fileobj.close() + if fileobj is None: + raise + raise ReadError("not a gzip file") + except: + if not extfileobj and fileobj is not None: + fileobj.close() + raise + t._extfileobj = extfileobj + return t + + @classmethod + def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): + """Open bzip2 compressed tar archive name for reading or writing. + Appending is not allowed. + """ + if len(mode) > 1 or mode not in "rw": + raise ValueError("mode must be 'r' or 'w'.") + + try: + import bz2 + except ImportError: + raise CompressionError("bz2 module is not available") + + if fileobj is not None: + fileobj = _BZ2Proxy(fileobj, mode) + else: + fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) + + try: + t = cls.taropen(name, mode, fileobj, **kwargs) + except (IOError, EOFError): + fileobj.close() + raise ReadError("not a bzip2 file") + t._extfileobj = False + return t + + # All *open() methods are registered here. + OPEN_METH = { + "tar": "taropen", # uncompressed tar + "gz": "gzopen", # gzip compressed tar + "bz2": "bz2open" # bzip2 compressed tar + } + + #-------------------------------------------------------------------------- + # The public methods which TarFile provides: + + def close(self): + """Close the TarFile. In write-mode, two finishing zero blocks are + appended to the archive. + """ + if self.closed: + return + + if self.mode in "aw": + self.fileobj.write(NUL * (BLOCKSIZE * 2)) + self.offset += (BLOCKSIZE * 2) + # fill up the end with zero-blocks + # (like option -b20 for tar does) + blocks, remainder = divmod(self.offset, RECORDSIZE) + if remainder > 0: + self.fileobj.write(NUL * (RECORDSIZE - remainder)) + + if not self._extfileobj: + self.fileobj.close() + self.closed = True + + def getmember(self, name): + """Return a TarInfo object for member `name'. If `name' can not be + found in the archive, KeyError is raised. If a member occurs more + than once in the archive, its last occurrence is assumed to be the + most up-to-date version. + """ + tarinfo = self._getmember(name) + if tarinfo is None: + raise KeyError("filename %r not found" % name) + return tarinfo + + def getmembers(self): + """Return the members of the archive as a list of TarInfo objects. The + list has the same order as the members in the archive. + """ + self._check() + if not self._loaded: # if we want to obtain a list of + self._load() # all members, we first have to + # scan the whole archive. + return self.members + + def getnames(self): + """Return the members of the archive as a list of their names. It has + the same order as the list returned by getmembers(). + """ + return [tarinfo.name for tarinfo in self.getmembers()] + + def gettarinfo(self, name=None, arcname=None, fileobj=None): + """Create a TarInfo object for either the file `name' or the file + object `fileobj' (using os.fstat on its file descriptor). You can + modify some of the TarInfo's attributes before you add it using + addfile(). If given, `arcname' specifies an alternative name for the + file in the archive. + """ + self._check("aw") + + # When fileobj is given, replace name by + # fileobj's real name. + if fileobj is not None: + name = fileobj.name + + # Building the name of the member in the archive. + # Backward slashes are converted to forward slashes, + # Absolute paths are turned to relative paths. + if arcname is None: + arcname = name + drv, arcname = os.path.splitdrive(arcname) + arcname = arcname.replace(os.sep, "/") + arcname = arcname.lstrip("/") + + # Now, fill the TarInfo object with + # information specific for the file. + tarinfo = self.tarinfo() + tarinfo.tarfile = self + + # Use os.stat or os.lstat, depending on platform + # and if symlinks shall be resolved. + if fileobj is None: + if hasattr(os, "lstat") and not self.dereference: + statres = os.lstat(name) + else: + statres = os.stat(name) + else: + statres = os.fstat(fileobj.fileno()) + linkname = "" + + stmd = statres.st_mode + if stat.S_ISREG(stmd): + inode = (statres.st_ino, statres.st_dev) + if not self.dereference and statres.st_nlink > 1 and \ + inode in self.inodes and arcname != self.inodes[inode]: + # Is it a hardlink to an already + # archived file? + type = LNKTYPE + linkname = self.inodes[inode] + else: + # The inode is added only if its valid. + # For win32 it is always 0. + type = REGTYPE + if inode[0]: + self.inodes[inode] = arcname + elif stat.S_ISDIR(stmd): + type = DIRTYPE + elif stat.S_ISFIFO(stmd): + type = FIFOTYPE + elif stat.S_ISLNK(stmd): + type = SYMTYPE + linkname = os.readlink(name) + elif stat.S_ISCHR(stmd): + type = CHRTYPE + elif stat.S_ISBLK(stmd): + type = BLKTYPE + else: + return None + + # Fill the TarInfo object with all + # information we can get. + tarinfo.name = arcname + tarinfo.mode = stmd + tarinfo.uid = statres.st_uid + tarinfo.gid = statres.st_gid + if type == REGTYPE: + tarinfo.size = statres.st_size + else: + tarinfo.size = 0 + tarinfo.mtime = statres.st_mtime + tarinfo.type = type + tarinfo.linkname = linkname + if pwd: + try: + tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] + except KeyError: + pass + if grp: + try: + tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] + except KeyError: + pass + + if type in (CHRTYPE, BLKTYPE): + if hasattr(os, "major") and hasattr(os, "minor"): + tarinfo.devmajor = os.major(statres.st_rdev) + tarinfo.devminor = os.minor(statres.st_rdev) + return tarinfo + + def list(self, verbose=True): + """Print a table of contents to sys.stdout. If `verbose' is False, only + the names of the members are printed. If it is True, an `ls -l'-like + output is produced. + """ + self._check() + + for tarinfo in self: + if verbose: + print(filemode(tarinfo.mode), end=' ') + print("%s/%s" % (tarinfo.uname or tarinfo.uid, + tarinfo.gname or tarinfo.gid), end=' ') + if tarinfo.ischr() or tarinfo.isblk(): + print("%10s" % ("%d,%d" \ + % (tarinfo.devmajor, tarinfo.devminor)), end=' ') + else: + print("%10d" % tarinfo.size, end=' ') + print("%d-%02d-%02d %02d:%02d:%02d" \ + % time.localtime(tarinfo.mtime)[:6], end=' ') + + print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') + + if verbose: + if tarinfo.issym(): + print("->", tarinfo.linkname, end=' ') + if tarinfo.islnk(): + print("link to", tarinfo.linkname, end=' ') + print() + + def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): + """Add the file `name' to the archive. `name' may be any type of file + (directory, fifo, symbolic link, etc.). If given, `arcname' + specifies an alternative name for the file in the archive. + Directories are added recursively by default. This can be avoided by + setting `recursive' to False. `exclude' is a function that should + return True for each filename to be excluded. `filter' is a function + that expects a TarInfo object argument and returns the changed + TarInfo object, if it returns None the TarInfo object will be + excluded from the archive. + """ + self._check("aw") + + if arcname is None: + arcname = name + + # Exclude pathnames. + if exclude is not None: + import warnings + warnings.warn("use the filter argument instead", + DeprecationWarning, 2) + if exclude(name): + self._dbg(2, "tarfile: Excluded %r" % name) + return + + # Skip if somebody tries to archive the archive... + if self.name is not None and os.path.abspath(name) == self.name: + self._dbg(2, "tarfile: Skipped %r" % name) + return + + self._dbg(1, name) + + # Create a TarInfo object from the file. + tarinfo = self.gettarinfo(name, arcname) + + if tarinfo is None: + self._dbg(1, "tarfile: Unsupported type %r" % name) + return + + # Change or exclude the TarInfo object. + if filter is not None: + tarinfo = filter(tarinfo) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % name) + return + + # Append the tar header and data to the archive. + if tarinfo.isreg(): + f = bltn_open(name, "rb") + self.addfile(tarinfo, f) + f.close() + + elif tarinfo.isdir(): + self.addfile(tarinfo) + if recursive: + for f in os.listdir(name): + self.add(os.path.join(name, f), os.path.join(arcname, f), + recursive, exclude, filter=filter) + + else: + self.addfile(tarinfo) + + def addfile(self, tarinfo, fileobj=None): + """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is + given, tarinfo.size bytes are read from it and added to the archive. + You can create TarInfo objects using gettarinfo(). + On Windows platforms, `fileobj' should always be opened with mode + 'rb' to avoid irritation about the file size. + """ + self._check("aw") + + tarinfo = copy.copy(tarinfo) + + buf = tarinfo.tobuf(self.format, self.encoding, self.errors) + self.fileobj.write(buf) + self.offset += len(buf) + + # If there's data to follow, append it. + if fileobj is not None: + copyfileobj(fileobj, self.fileobj, tarinfo.size) + blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) + if remainder > 0: + self.fileobj.write(NUL * (BLOCKSIZE - remainder)) + blocks += 1 + self.offset += blocks * BLOCKSIZE + + self.members.append(tarinfo) + + def extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 0o700 + # Do not set_attrs directories, as we will do that further down + self.extract(tarinfo, path, set_attrs=not tarinfo.isdir()) + + # Reverse sort directories. + directories.sort(key=lambda a: a.name) + directories.reverse() + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError as e: + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def extract(self, member, path="", set_attrs=True): + """Extract a member from the archive to the current working directory, + using its full name. Its file information is extracted as accurately + as possible. `member' may be a filename or a TarInfo object. You can + specify a different directory using `path'. File attributes (owner, + mtime, mode) are set unless `set_attrs' is False. + """ + self._check("r") + + if isinstance(member, str): + tarinfo = self.getmember(member) + else: + tarinfo = member + + # Prepare the link target for makelink(). + if tarinfo.islnk(): + tarinfo._link_target = os.path.join(path, tarinfo.linkname) + + try: + self._extract_member(tarinfo, os.path.join(path, tarinfo.name), + set_attrs=set_attrs) + except EnvironmentError as e: + if self.errorlevel > 0: + raise + else: + if e.filename is None: + self._dbg(1, "tarfile: %s" % e.strerror) + else: + self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + except ExtractError as e: + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def extractfile(self, member): + """Extract a member from the archive as a file object. `member' may be + a filename or a TarInfo object. If `member' is a regular file, a + file-like object is returned. If `member' is a link, a file-like + object is constructed from the link's target. If `member' is none of + the above, None is returned. + The file-like object is read-only and provides the following + methods: read(), readline(), readlines(), seek() and tell() + """ + self._check("r") + + if isinstance(member, str): + tarinfo = self.getmember(member) + else: + tarinfo = member + + if tarinfo.isreg(): + return self.fileobject(self, tarinfo) + + elif tarinfo.type not in SUPPORTED_TYPES: + # If a member's type is unknown, it is treated as a + # regular file. + return self.fileobject(self, tarinfo) + + elif tarinfo.islnk() or tarinfo.issym(): + if isinstance(self.fileobj, _Stream): + # A small but ugly workaround for the case that someone tries + # to extract a (sym)link as a file-object from a non-seekable + # stream of tar blocks. + raise StreamError("cannot extract (sym)link as file object") + else: + # A (sym)link's file object is its target's file object. + return self.extractfile(self._find_link_target(tarinfo)) + else: + # If there's no data associated with the member (directory, chrdev, + # blkdev, etc.), return None instead of a file object. + return None + + def _extract_member(self, tarinfo, targetpath, set_attrs=True): + """Extract the TarInfo object tarinfo to a physical + file called targetpath. + """ + # Fetch the TarInfo object for the given name + # and build the destination pathname, replacing + # forward slashes to platform specific separators. + targetpath = targetpath.rstrip("/") + targetpath = targetpath.replace("/", os.sep) + + # Create all upper directories. + upperdirs = os.path.dirname(targetpath) + if upperdirs and not os.path.exists(upperdirs): + # Create directories that are not part of the archive with + # default permissions. + os.makedirs(upperdirs) + + if tarinfo.islnk() or tarinfo.issym(): + self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) + else: + self._dbg(1, tarinfo.name) + + if tarinfo.isreg(): + self.makefile(tarinfo, targetpath) + elif tarinfo.isdir(): + self.makedir(tarinfo, targetpath) + elif tarinfo.isfifo(): + self.makefifo(tarinfo, targetpath) + elif tarinfo.ischr() or tarinfo.isblk(): + self.makedev(tarinfo, targetpath) + elif tarinfo.islnk() or tarinfo.issym(): + self.makelink(tarinfo, targetpath) + elif tarinfo.type not in SUPPORTED_TYPES: + self.makeunknown(tarinfo, targetpath) + else: + self.makefile(tarinfo, targetpath) + + if set_attrs: + self.chown(tarinfo, targetpath) + if not tarinfo.issym(): + self.chmod(tarinfo, targetpath) + self.utime(tarinfo, targetpath) + + #-------------------------------------------------------------------------- + # Below are the different file methods. They are called via + # _extract_member() when extract() is called. They can be replaced in a + # subclass to implement other functionality. + + def makedir(self, tarinfo, targetpath): + """Make a directory called targetpath. + """ + try: + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0o700) + except EnvironmentError as e: + if e.errno != errno.EEXIST: + raise + + def makefile(self, tarinfo, targetpath): + """Make a file called targetpath. + """ + source = self.fileobj + source.seek(tarinfo.offset_data) + target = bltn_open(targetpath, "wb") + if tarinfo.sparse is not None: + for offset, size in tarinfo.sparse: + target.seek(offset) + copyfileobj(source, target, size) + else: + copyfileobj(source, target, tarinfo.size) + target.seek(tarinfo.size) + target.truncate() + target.close() + + def makeunknown(self, tarinfo, targetpath): + """Make a file from a TarInfo object with an unknown type + at targetpath. + """ + self.makefile(tarinfo, targetpath) + self._dbg(1, "tarfile: Unknown file type %r, " \ + "extracted as regular file." % tarinfo.type) + + def makefifo(self, tarinfo, targetpath): + """Make a fifo called targetpath. + """ + if hasattr(os, "mkfifo"): + os.mkfifo(targetpath) + else: + raise ExtractError("fifo not supported by system") + + def makedev(self, tarinfo, targetpath): + """Make a character or block device called targetpath. + """ + if not hasattr(os, "mknod") or not hasattr(os, "makedev"): + raise ExtractError("special devices not supported by system") + + mode = tarinfo.mode + if tarinfo.isblk(): + mode |= stat.S_IFBLK + else: + mode |= stat.S_IFCHR + + os.mknod(targetpath, mode, + os.makedev(tarinfo.devmajor, tarinfo.devminor)) + + def makelink(self, tarinfo, targetpath): + """Make a (symbolic) link called targetpath. If it cannot be created + (platform limitation), we try to make a copy of the referenced file + instead of a link. + """ + try: + # For systems that support symbolic and hard links. + if tarinfo.issym(): + os.symlink(tarinfo.linkname, targetpath) + else: + # See extract(). + if os.path.exists(tarinfo._link_target): + os.link(tarinfo._link_target, targetpath) + else: + self._extract_member(self._find_link_target(tarinfo), + targetpath) + except symlink_exception: + if tarinfo.issym(): + linkpath = os.path.join(os.path.dirname(tarinfo.name), + tarinfo.linkname) + else: + linkpath = tarinfo.linkname + else: + try: + self._extract_member(self._find_link_target(tarinfo), + targetpath) + except KeyError: + raise ExtractError("unable to resolve link inside archive") + + def chown(self, tarinfo, targetpath): + """Set owner of targetpath according to tarinfo. + """ + if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: + # We have to be root to do so. + try: + g = grp.getgrnam(tarinfo.gname)[2] + except KeyError: + g = tarinfo.gid + try: + u = pwd.getpwnam(tarinfo.uname)[2] + except KeyError: + u = tarinfo.uid + try: + if tarinfo.issym() and hasattr(os, "lchown"): + os.lchown(targetpath, u, g) + else: + if sys.platform != "os2emx": + os.chown(targetpath, u, g) + except EnvironmentError as e: + raise ExtractError("could not change owner") + + def chmod(self, tarinfo, targetpath): + """Set file permissions of targetpath according to tarinfo. + """ + if hasattr(os, 'chmod'): + try: + os.chmod(targetpath, tarinfo.mode) + except EnvironmentError as e: + raise ExtractError("could not change mode") + + def utime(self, tarinfo, targetpath): + """Set modification time of targetpath according to tarinfo. + """ + if not hasattr(os, 'utime'): + return + try: + os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) + except EnvironmentError as e: + raise ExtractError("could not change modification time") + + #-------------------------------------------------------------------------- + def next(self): + """Return the next member of the archive as a TarInfo object, when + TarFile is opened for reading. Return None if there is no more + available. + """ + self._check("ra") + if self.firstmember is not None: + m = self.firstmember + self.firstmember = None + return m + + # Read the next block. + self.fileobj.seek(self.offset) + tarinfo = None + while True: + try: + tarinfo = self.tarinfo.fromtarfile(self) + except EOFHeaderError as e: + if self.ignore_zeros: + self._dbg(2, "0x%X: %s" % (self.offset, e)) + self.offset += BLOCKSIZE + continue + except InvalidHeaderError as e: + if self.ignore_zeros: + self._dbg(2, "0x%X: %s" % (self.offset, e)) + self.offset += BLOCKSIZE + continue + elif self.offset == 0: + raise ReadError(str(e)) + except EmptyHeaderError: + if self.offset == 0: + raise ReadError("empty file") + except TruncatedHeaderError as e: + if self.offset == 0: + raise ReadError(str(e)) + except SubsequentHeaderError as e: + raise ReadError(str(e)) + break + + if tarinfo is not None: + self.members.append(tarinfo) + else: + self._loaded = True + + return tarinfo + + #-------------------------------------------------------------------------- + # Little helper methods: + + def _getmember(self, name, tarinfo=None, normalize=False): + """Find an archive member by name from bottom to top. + If tarinfo is given, it is used as the starting point. + """ + # Ensure that all members have been loaded. + members = self.getmembers() + + # Limit the member search list up to tarinfo. + if tarinfo is not None: + members = members[:members.index(tarinfo)] + + if normalize: + name = os.path.normpath(name) + + for member in reversed(members): + if normalize: + member_name = os.path.normpath(member.name) + else: + member_name = member.name + + if name == member_name: + return member + + def _load(self): + """Read through the entire archive file and look for readable + members. + """ + while True: + tarinfo = self.next() + if tarinfo is None: + break + self._loaded = True + + def _check(self, mode=None): + """Check if TarFile is still open, and if the operation's mode + corresponds to TarFile's mode. + """ + if self.closed: + raise IOError("%s is closed" % self.__class__.__name__) + if mode is not None and self.mode not in mode: + raise IOError("bad operation for mode %r" % self.mode) + + def _find_link_target(self, tarinfo): + """Find the target member of a symlink or hardlink member in the + archive. + """ + if tarinfo.issym(): + # Always search the entire archive. + linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname + limit = None + else: + # Search the archive before the link, because a hard link is + # just a reference to an already archived file. + linkname = tarinfo.linkname + limit = tarinfo + + member = self._getmember(linkname, tarinfo=limit, normalize=True) + if member is None: + raise KeyError("linkname %r not found" % linkname) + return member + + def __iter__(self): + """Provide an iterator object. + """ + if self._loaded: + return iter(self.members) + else: + return TarIter(self) + + def _dbg(self, level, msg): + """Write debugging output to sys.stderr. + """ + if level <= self.debug: + print(msg, file=sys.stderr) + + def __enter__(self): + self._check() + return self + + def __exit__(self, type, value, traceback): + if type is None: + self.close() + else: + # An exception occurred. We must not call close() because + # it would try to write end-of-archive blocks and padding. + if not self._extfileobj: + self.fileobj.close() + self.closed = True +# class TarFile + +class TarIter(object): + """Iterator Class. + + for tarinfo in TarFile(...): + suite... + """ + + def __init__(self, tarfile): + """Construct a TarIter object. + """ + self.tarfile = tarfile + self.index = 0 + def __iter__(self): + """Return iterator object. + """ + return self + + def __next__(self): + """Return the next item using TarFile's next() method. + When all members have been read, set TarFile as _loaded. + """ + # Fix for SF #1100429: Under rare circumstances it can + # happen that getmembers() is called during iteration, + # which will cause TarIter to stop prematurely. + if not self.tarfile._loaded: + tarinfo = self.tarfile.next() + if not tarinfo: + self.tarfile._loaded = True + raise StopIteration + else: + try: + tarinfo = self.tarfile.members[self.index] + except IndexError: + raise StopIteration + self.index += 1 + return tarinfo + + next = __next__ # for Python 2.x + +#-------------------- +# exported functions +#-------------------- +def is_tarfile(name): + """Return True if name points to a tar archive that we + are able to handle, else return False. + """ + try: + t = open(name) + t.close() + return True + except TarError: + return False + +bltn_open = open +open = TarFile.open diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py new file mode 100755 index 0000000..09929b0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/compat.py @@ -0,0 +1,1120 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import absolute_import + +import os +import re +import sys + +try: + import ssl +except ImportError: # pragma: no cover + ssl = None + +if sys.version_info[0] < 3: # pragma: no cover + from StringIO import StringIO + string_types = basestring, + text_type = unicode + from types import FileType as file_type + import __builtin__ as builtins + import ConfigParser as configparser + from ._backport import shutil + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit + from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, + pathname2url, ContentTooShortError, splittype) + + def quote(s): + if isinstance(s, unicode): + s = s.encode('utf-8') + return _quote(s) + + import urllib2 + from urllib2 import (Request, urlopen, URLError, HTTPError, + HTTPBasicAuthHandler, HTTPPasswordMgr, + HTTPHandler, HTTPRedirectHandler, + build_opener) + if ssl: + from urllib2 import HTTPSHandler + import httplib + import xmlrpclib + import Queue as queue + from HTMLParser import HTMLParser + import htmlentitydefs + raw_input = raw_input + from itertools import ifilter as filter + from itertools import ifilterfalse as filterfalse + + _userprog = None + def splituser(host): + """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" + global _userprog + if _userprog is None: + import re + _userprog = re.compile('^(.*)@(.*)$') + + match = _userprog.match(host) + if match: return match.group(1, 2) + return None, host + +else: # pragma: no cover + from io import StringIO + string_types = str, + text_type = str + from io import TextIOWrapper as file_type + import builtins + import configparser + import shutil + from urllib.parse import (urlparse, urlunparse, urljoin, splituser, quote, + unquote, urlsplit, urlunsplit, splittype) + from urllib.request import (urlopen, urlretrieve, Request, url2pathname, + pathname2url, + HTTPBasicAuthHandler, HTTPPasswordMgr, + HTTPHandler, HTTPRedirectHandler, + build_opener) + if ssl: + from urllib.request import HTTPSHandler + from urllib.error import HTTPError, URLError, ContentTooShortError + import http.client as httplib + import urllib.request as urllib2 + import xmlrpc.client as xmlrpclib + import queue + from html.parser import HTMLParser + import html.entities as htmlentitydefs + raw_input = input + from itertools import filterfalse + filter = filter + +try: + from ssl import match_hostname, CertificateError +except ImportError: # pragma: no cover + 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 + + parts = dn.split('.') + leftmost, remainder = parts[0], 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 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") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_match(value, hostname): + 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") + + +try: + from types import SimpleNamespace as Container +except ImportError: # pragma: no cover + class Container(object): + """ + A generic container for when multiple values need to be returned + """ + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +try: + from shutil import which +except ImportError: # pragma: no cover + # Implementation from Python 3.3 + def which(cmd, mode=os.F_OK | os.X_OK, path=None): + """Given a command, mode, and a PATH string, return the path which + conforms to the given mode on the PATH, or None if there is no such + file. + + `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result + of os.environ.get("PATH"), or can be overridden with a custom search + path. + + """ + # Check that a given file can be accessed with the correct mode. + # Additionally check that `file` is not a directory, as on Windows + # directories pass the os.access check. + def _access_check(fn, mode): + return (os.path.exists(fn) and os.access(fn, mode) + and not os.path.isdir(fn)) + + # If we're given a path with a directory part, look it up directly rather + # than referring to PATH directories. This includes checking relative to the + # current directory, e.g. ./script + if os.path.dirname(cmd): + if _access_check(cmd, mode): + return cmd + return None + + if path is None: + path = os.environ.get("PATH", os.defpath) + if not path: + return None + path = path.split(os.pathsep) + + if sys.platform == "win32": + # The current directory takes precedence on Windows. + if not os.curdir in path: + path.insert(0, os.curdir) + + # PATHEXT is necessary to check on Windows. + pathext = os.environ.get("PATHEXT", "").split(os.pathsep) + # See if the given file matches any of the expected path extensions. + # This will allow us to short circuit when given "python.exe". + # If it does match, only test that one, otherwise we have to try + # others. + if any(cmd.lower().endswith(ext.lower()) for ext in pathext): + files = [cmd] + else: + files = [cmd + ext for ext in pathext] + else: + # On other platforms you don't have things like PATHEXT to tell you + # what file suffixes are executable, so just pass on cmd as-is. + files = [cmd] + + seen = set() + for dir in path: + normdir = os.path.normcase(dir) + if not normdir in seen: + seen.add(normdir) + for thefile in files: + name = os.path.join(dir, thefile) + if _access_check(name, mode): + return name + return None + + +# ZipFile is a context manager in 2.7, but not in 2.6 + +from zipfile import ZipFile as BaseZipFile + +if hasattr(BaseZipFile, '__enter__'): # pragma: no cover + ZipFile = BaseZipFile +else: # pragma: no cover + from zipfile import ZipExtFile as BaseZipExtFile + + class ZipExtFile(BaseZipExtFile): + def __init__(self, base): + self.__dict__.update(base.__dict__) + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + class ZipFile(BaseZipFile): + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.close() + # return None, so if an exception occurred, it will propagate + + def open(self, *args, **kwargs): + base = BaseZipFile.open(self, *args, **kwargs) + return ZipExtFile(base) + +try: + from platform import python_implementation +except ImportError: # pragma: no cover + def python_implementation(): + """Return a string identifying the Python implementation.""" + if 'PyPy' in sys.version: + return 'PyPy' + if os.name == 'java': + return 'Jython' + if sys.version.startswith('IronPython'): + return 'IronPython' + return 'CPython' + +try: + import sysconfig +except ImportError: # pragma: no cover + from ._backport import sysconfig + +try: + callable = callable +except NameError: # pragma: no cover + from collections import Callable + + def callable(obj): + return isinstance(obj, Callable) + + +try: + fsencode = os.fsencode + fsdecode = os.fsdecode +except AttributeError: # pragma: no cover + # Issue #99: on some systems (e.g. containerised), + # sys.getfilesystemencoding() returns None, and we need a real value, + # so fall back to utf-8. From the CPython 2.7 docs relating to Unix and + # sys.getfilesystemencoding(): the return value is "the user’s preference + # according to the result of nl_langinfo(CODESET), or None if the + # nl_langinfo(CODESET) failed." + _fsencoding = sys.getfilesystemencoding() or 'utf-8' + if _fsencoding == 'mbcs': + _fserrors = 'strict' + else: + _fserrors = 'surrogateescape' + + def fsencode(filename): + if isinstance(filename, bytes): + return filename + elif isinstance(filename, text_type): + return filename.encode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + + def fsdecode(filename): + if isinstance(filename, text_type): + return filename + elif isinstance(filename, bytes): + return filename.decode(_fsencoding, _fserrors) + else: + raise TypeError("expect bytes or str, not %s" % + type(filename).__name__) + +try: + from tokenize import detect_encoding +except ImportError: # pragma: no cover + from codecs import BOM_UTF8, lookup + import re + + cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)") + + def _get_normal_name(orig_enc): + """Imitates get_normal_name in tokenizer.c.""" + # Only care about the first 12 characters. + enc = orig_enc[:12].lower().replace("_", "-") + if enc == "utf-8" or enc.startswith("utf-8-"): + return "utf-8" + if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ + enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): + return "iso-8859-1" + return orig_enc + + def detect_encoding(readline): + """ + The detect_encoding() function is used to detect the encoding that should + be used to decode a Python source file. It requires one argument, readline, + in the same way as the tokenize() generator. + + It will call readline a maximum of twice, and return the encoding used + (as a string) and a list of any lines (left as bytes) it has read in. + + It detects the encoding from the presence of a utf-8 bom or an encoding + cookie as specified in pep-0263. If both a bom and a cookie are present, + but disagree, a SyntaxError will be raised. If the encoding cookie is an + invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, + 'utf-8-sig' is returned. + + If no encoding is specified, then the default of 'utf-8' will be returned. + """ + try: + filename = readline.__self__.name + except AttributeError: + filename = None + bom_found = False + encoding = None + default = 'utf-8' + def read_or_stop(): + try: + return readline() + except StopIteration: + return b'' + + def find_cookie(line): + try: + # Decode as UTF-8. Either the line is an encoding declaration, + # in which case it should be pure ASCII, or it must be UTF-8 + # per default encoding. + line_string = line.decode('utf-8') + except UnicodeDecodeError: + msg = "invalid or missing encoding declaration" + if filename is not None: + msg = '{} for {!r}'.format(msg, filename) + raise SyntaxError(msg) + + matches = cookie_re.findall(line_string) + if not matches: + return None + encoding = _get_normal_name(matches[0]) + try: + codec = lookup(encoding) + except LookupError: + # This behaviour mimics the Python interpreter + if filename is None: + msg = "unknown encoding: " + encoding + else: + msg = "unknown encoding for {!r}: {}".format(filename, + encoding) + raise SyntaxError(msg) + + if bom_found: + if codec.name != 'utf-8': + # This behaviour mimics the Python interpreter + if filename is None: + msg = 'encoding problem: utf-8' + else: + msg = 'encoding problem for {!r}: utf-8'.format(filename) + raise SyntaxError(msg) + encoding += '-sig' + return encoding + + first = read_or_stop() + if first.startswith(BOM_UTF8): + bom_found = True + first = first[3:] + default = 'utf-8-sig' + if not first: + return default, [] + + encoding = find_cookie(first) + if encoding: + return encoding, [first] + + second = read_or_stop() + if not second: + return default, [first] + + encoding = find_cookie(second) + if encoding: + return encoding, [first, second] + + return default, [first, second] + +# For converting & <-> & etc. +try: + from html import escape +except ImportError: + from cgi import escape +if sys.version_info[:2] < (3, 4): + unescape = HTMLParser().unescape +else: + from html import unescape + +try: + from collections import ChainMap +except ImportError: # pragma: no cover + from collections import MutableMapping + + try: + from reprlib import recursive_repr as _recursive_repr + except ImportError: + def _recursive_repr(fillvalue='...'): + ''' + Decorator to make a repr function return fillvalue for a recursive + call + ''' + + def decorating_function(user_function): + repr_running = set() + + def wrapper(self): + key = id(self), get_ident() + if key in repr_running: + return fillvalue + repr_running.add(key) + try: + result = user_function(self) + finally: + repr_running.discard(key) + return result + + # Can't use functools.wraps() here because of bootstrap issues + wrapper.__module__ = getattr(user_function, '__module__') + wrapper.__doc__ = getattr(user_function, '__doc__') + wrapper.__name__ = getattr(user_function, '__name__') + wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) + return wrapper + + return decorating_function + + class ChainMap(MutableMapping): + ''' A ChainMap groups multiple dicts (or other mappings) together + to create a single, updateable view. + + The underlying mappings are stored in a list. That list is public and can + accessed or updated using the *maps* attribute. There is no other state. + + Lookups search the underlying mappings successively until a key is found. + In contrast, writes, updates, and deletions only operate on the first + mapping. + + ''' + + def __init__(self, *maps): + '''Initialize a ChainMap by setting *maps* to the given mappings. + If no mappings are provided, a single empty dictionary is used. + + ''' + self.maps = list(maps) or [{}] # always at least one map + + def __missing__(self, key): + raise KeyError(key) + + def __getitem__(self, key): + for mapping in self.maps: + try: + return mapping[key] # can't use 'key in mapping' with defaultdict + except KeyError: + pass + return self.__missing__(key) # support subclasses that define __missing__ + + def get(self, key, default=None): + return self[key] if key in self else default + + def __len__(self): + return len(set().union(*self.maps)) # reuses stored hash values if possible + + def __iter__(self): + return iter(set().union(*self.maps)) + + def __contains__(self, key): + return any(key in m for m in self.maps) + + def __bool__(self): + return any(self.maps) + + @_recursive_repr() + def __repr__(self): + return '{0.__class__.__name__}({1})'.format( + self, ', '.join(map(repr, self.maps))) + + @classmethod + def fromkeys(cls, iterable, *args): + 'Create a ChainMap with a single dict created from the iterable.' + return cls(dict.fromkeys(iterable, *args)) + + def copy(self): + 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' + return self.__class__(self.maps[0].copy(), *self.maps[1:]) + + __copy__ = copy + + def new_child(self): # like Django's Context.push() + 'New ChainMap with a new dict followed by all previous maps.' + return self.__class__({}, *self.maps) + + @property + def parents(self): # like Django's Context.pop() + 'New ChainMap from maps[1:].' + return self.__class__(*self.maps[1:]) + + def __setitem__(self, key, value): + self.maps[0][key] = value + + def __delitem__(self, key): + try: + del self.maps[0][key] + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def popitem(self): + 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' + try: + return self.maps[0].popitem() + except KeyError: + raise KeyError('No keys found in the first mapping.') + + def pop(self, key, *args): + 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' + try: + return self.maps[0].pop(key, *args) + except KeyError: + raise KeyError('Key not found in the first mapping: {!r}'.format(key)) + + def clear(self): + 'Clear maps[0], leaving maps[1:] intact.' + self.maps[0].clear() + +try: + from importlib.util import cache_from_source # Python >= 3.4 +except ImportError: # pragma: no cover + try: + from imp import cache_from_source + except ImportError: # pragma: no cover + def cache_from_source(path, debug_override=None): + assert path.endswith('.py') + if debug_override is None: + debug_override = __debug__ + if debug_override: + suffix = 'c' + else: + suffix = 'o' + return path + suffix + +try: + from collections import OrderedDict +except ImportError: # pragma: no cover +## {{{ http://code.activestate.com/recipes/576693/ (r9) +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. + try: + from thread import get_ident as _get_ident + except ImportError: + from dummy_thread import get_ident as _get_ident + + try: + from _abcoll import KeysView, ValuesView, ItemsView + except ImportError: + pass + + + class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running=None): + 'od.__repr__() <==> repr(od)' + if not _repr_running: _repr_running = {} + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + +try: + from logging.config import BaseConfigurator, valid_ident +except ImportError: # pragma: no cover + IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) + + + def valid_ident(s): + m = IDENTIFIER.match(s) + if not m: + raise ValueError('Not a valid Python identifier: %r' % s) + return True + + + # The ConvertingXXX classes are wrappers around standard Python containers, + # and they serve to convert any suitable values in the container. The + # conversion converts base dicts, lists and tuples to their wrapped + # equivalents, whereas strings which match a conversion format are converted + # appropriately. + # + # Each wrapper should have a configurator attribute holding the actual + # configurator to use for conversion. + + class ConvertingDict(dict): + """A converting dictionary wrapper.""" + + def __getitem__(self, key): + value = dict.__getitem__(self, key) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def get(self, key, default=None): + value = dict.get(self, key, default) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, key, default=None): + value = dict.pop(self, key, default) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class ConvertingList(list): + """A converting list wrapper.""" + def __getitem__(self, key): + value = list.__getitem__(self, key) + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def pop(self, idx=-1): + value = list.pop(self, idx) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + return result + + class ConvertingTuple(tuple): + """A converting tuple wrapper.""" + def __getitem__(self, key): + value = tuple.__getitem__(self, key) + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + class BaseConfigurator(object): + """ + The configurator base class which defines some useful defaults. + """ + + CONVERT_PATTERN = re.compile(r'^(?P<prefix>[a-z]+)://(?P<suffix>.*)$') + + WORD_PATTERN = re.compile(r'^\s*(\w+)\s*') + DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*') + INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*') + DIGIT_PATTERN = re.compile(r'^\d+$') + + value_converters = { + 'ext' : 'ext_convert', + 'cfg' : 'cfg_convert', + } + + # We might want to use a different one, e.g. importlib + importer = staticmethod(__import__) + + def __init__(self, config): + self.config = ConvertingDict(config) + self.config.configurator = self + + def resolve(self, s): + """ + Resolve strings to objects using standard import and attribute + syntax. + """ + name = s.split('.') + used = name.pop(0) + try: + found = self.importer(used) + for frag in name: + used += '.' + frag + try: + found = getattr(found, frag) + except AttributeError: + self.importer(used) + found = getattr(found, frag) + return found + except ImportError: + e, tb = sys.exc_info()[1:] + v = ValueError('Cannot resolve %r: %s' % (s, e)) + v.__cause__, v.__traceback__ = e, tb + raise v + + def ext_convert(self, value): + """Default converter for the ext:// protocol.""" + return self.resolve(value) + + def cfg_convert(self, value): + """Default converter for the cfg:// protocol.""" + rest = value + m = self.WORD_PATTERN.match(rest) + if m is None: + raise ValueError("Unable to convert %r" % value) + else: + rest = rest[m.end():] + d = self.config[m.groups()[0]] + #print d, rest + while rest: + m = self.DOT_PATTERN.match(rest) + if m: + d = d[m.groups()[0]] + else: + m = self.INDEX_PATTERN.match(rest) + if m: + idx = m.groups()[0] + if not self.DIGIT_PATTERN.match(idx): + d = d[idx] + else: + try: + n = int(idx) # try as number first (most likely) + d = d[n] + except TypeError: + d = d[idx] + if m: + rest = rest[m.end():] + else: + raise ValueError('Unable to convert ' + '%r at %r' % (value, rest)) + #rest should be empty + return d + + def convert(self, value): + """ + Convert values to an appropriate type. dicts, lists and tuples are + replaced by their converting alternatives. Strings are checked to + see if they have a conversion format and are converted if they do. + """ + if not isinstance(value, ConvertingDict) and isinstance(value, dict): + value = ConvertingDict(value) + value.configurator = self + elif not isinstance(value, ConvertingList) and isinstance(value, list): + value = ConvertingList(value) + value.configurator = self + elif not isinstance(value, ConvertingTuple) and\ + isinstance(value, tuple): + value = ConvertingTuple(value) + value.configurator = self + elif isinstance(value, string_types): + m = self.CONVERT_PATTERN.match(value) + if m: + d = m.groupdict() + prefix = d['prefix'] + converter = self.value_converters.get(prefix, None) + if converter: + suffix = d['suffix'] + converter = getattr(self, converter) + value = converter(suffix) + return value + + def configure_custom(self, config): + """Configure an object with a user-supplied factory.""" + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) + result = c(**kwargs) + if props: + for name, value in props.items(): + setattr(result, name, value) + return result + + def as_tuple(self, value): + """Utility function which converts lists to tuples.""" + if isinstance(value, list): + value = tuple(value) + return value diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py new file mode 100755 index 0000000..54483e1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/database.py @@ -0,0 +1,1336 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""PEP 376 implementation.""" + +from __future__ import unicode_literals + +import base64 +import codecs +import contextlib +import hashlib +import logging +import os +import posixpath +import sys +import zipimport + +from . import DistlibException, resources +from .compat import StringIO +from .version import get_scheme, UnsupportedVersionError +from .metadata import Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME +from .util import (parse_requirement, cached_property, parse_name_and_version, + read_exports, write_exports, CSVReader, CSVWriter) + + +__all__ = ['Distribution', 'BaseInstalledDistribution', + 'InstalledDistribution', 'EggInfoDistribution', + 'DistributionPath'] + + +logger = logging.getLogger(__name__) + +EXPORTS_FILENAME = 'pydist-exports.json' +COMMANDS_FILENAME = 'pydist-commands.json' + +DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', + 'RESOURCES', EXPORTS_FILENAME, 'SHARED') + +DISTINFO_EXT = '.dist-info' + + +class _Cache(object): + """ + A simple cache mapping names and .dist-info paths to distributions + """ + def __init__(self): + """ + Initialise an instance. There is normally one for each DistributionPath. + """ + self.name = {} + self.path = {} + self.generated = False + + def clear(self): + """ + Clear the cache, setting it to its initial state. + """ + self.name.clear() + self.path.clear() + self.generated = False + + def add(self, dist): + """ + Add a distribution to the cache. + :param dist: The distribution to add. + """ + if dist.path not in self.path: + self.path[dist.path] = dist + self.name.setdefault(dist.key, []).append(dist) + + +class DistributionPath(object): + """ + Represents a set of distributions installed on a path (typically sys.path). + """ + def __init__(self, path=None, include_egg=False): + """ + Create an instance from a path, optionally including legacy (distutils/ + setuptools/distribute) distributions. + :param path: The path to use, as a list of directories. If not specified, + sys.path is used. + :param include_egg: If True, this instance will look for and return legacy + distributions as well as those based on PEP 376. + """ + if path is None: + path = sys.path + self.path = path + self._include_dist = True + self._include_egg = include_egg + + self._cache = _Cache() + self._cache_egg = _Cache() + self._cache_enabled = True + self._scheme = get_scheme('default') + + def _get_cache_enabled(self): + return self._cache_enabled + + def _set_cache_enabled(self, value): + self._cache_enabled = value + + cache_enabled = property(_get_cache_enabled, _set_cache_enabled) + + def clear_cache(self): + """ + Clears the internal cache. + """ + self._cache.clear() + self._cache_egg.clear() + + + def _yield_distributions(self): + """ + Yield .dist-info and/or .egg(-info) distributions. + """ + # We need to check if we've seen some resources already, because on + # some Linux systems (e.g. some Debian/Ubuntu variants) there are + # symlinks which alias other files in the environment. + seen = set() + for path in self.path: + finder = resources.finder_for_path(path) + if finder is None: + continue + r = finder.find('') + if not r or not r.is_container: + continue + rset = sorted(r.resources) + for entry in rset: + r = finder.find(entry) + if not r or r.path in seen: + continue + if self._include_dist and entry.endswith(DISTINFO_EXT): + possible_filenames = [METADATA_FILENAME, WHEEL_METADATA_FILENAME] + for metadata_filename in possible_filenames: + metadata_path = posixpath.join(entry, metadata_filename) + pydist = finder.find(metadata_path) + if pydist: + break + else: + continue + + with contextlib.closing(pydist.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + logger.debug('Found %s', r.path) + seen.add(r.path) + yield new_dist_class(r.path, metadata=metadata, + env=self) + elif self._include_egg and entry.endswith(('.egg-info', + '.egg')): + logger.debug('Found %s', r.path) + seen.add(r.path) + yield old_dist_class(r.path, self) + + def _generate_cache(self): + """ + Scan the path for distributions and populate the cache with + those that are found. + """ + gen_dist = not self._cache.generated + gen_egg = self._include_egg and not self._cache_egg.generated + if gen_dist or gen_egg: + for dist in self._yield_distributions(): + if isinstance(dist, InstalledDistribution): + self._cache.add(dist) + else: + self._cache_egg.add(dist) + + if gen_dist: + self._cache.generated = True + if gen_egg: + self._cache_egg.generated = True + + @classmethod + def distinfo_dirname(cls, name, version): + """ + The *name* and *version* parameters are converted into their + filename-escaped form, i.e. any ``'-'`` characters are replaced + with ``'_'`` other than the one in ``'dist-info'`` and the one + separating the name from the version number. + + :parameter name: is converted to a standard distribution name by replacing + any runs of non- alphanumeric characters with a single + ``'-'``. + :type name: string + :parameter version: is converted to a standard version string. Spaces + become dots, and all other non-alphanumeric characters + (except dots) become dashes, with runs of multiple + dashes condensed to a single dash. + :type version: string + :returns: directory name + :rtype: string""" + name = name.replace('-', '_') + return '-'.join([name, version]) + DISTINFO_EXT + + def get_distributions(self): + """ + Provides an iterator that looks for distributions and returns + :class:`InstalledDistribution` or + :class:`EggInfoDistribution` instances for each one of them. + + :rtype: iterator of :class:`InstalledDistribution` and + :class:`EggInfoDistribution` instances + """ + if not self._cache_enabled: + for dist in self._yield_distributions(): + yield dist + else: + self._generate_cache() + + for dist in self._cache.path.values(): + yield dist + + if self._include_egg: + for dist in self._cache_egg.path.values(): + yield dist + + def get_distribution(self, name): + """ + Looks for a named distribution on the path. + + This function only returns the first result found, as no more than one + value is expected. If nothing is found, ``None`` is returned. + + :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` + or ``None`` + """ + result = None + name = name.lower() + if not self._cache_enabled: + for dist in self._yield_distributions(): + if dist.key == name: + result = dist + break + else: + self._generate_cache() + + if name in self._cache.name: + result = self._cache.name[name][0] + elif self._include_egg and name in self._cache_egg.name: + result = self._cache_egg.name[name][0] + return result + + def provides_distribution(self, name, version=None): + """ + Iterates over all distributions to find which distributions provide *name*. + If a *version* is provided, it will be used to filter the results. + + This function only returns the first result found, since no more than + one values are expected. If the directory is not found, returns ``None``. + + :parameter version: a version specifier that indicates the version + required, conforming to the format in ``PEP-345`` + + :type name: string + :type version: string + """ + matcher = None + if version is not None: + try: + matcher = self._scheme.matcher('%s (%s)' % (name, version)) + except ValueError: + raise DistlibException('invalid name or version: %r, %r' % + (name, version)) + + for dist in self.get_distributions(): + # We hit a problem on Travis where enum34 was installed and doesn't + # have a provides attribute ... + if not hasattr(dist, 'provides'): + logger.debug('No "provides": %s', dist) + else: + provided = dist.provides + + for p in provided: + p_name, p_ver = parse_name_and_version(p) + if matcher is None: + if p_name == name: + yield dist + break + else: + if p_name == name and matcher.match(p_ver): + yield dist + break + + def get_file_path(self, name, relative_path): + """ + Return the path to a resource file. + """ + dist = self.get_distribution(name) + if dist is None: + raise LookupError('no distribution named %r found' % name) + return dist.get_resource_path(relative_path) + + def get_exported_entries(self, category, name=None): + """ + Return all of the exported entries in a particular category. + + :param category: The category to search for entries. + :param name: If specified, only entries with that name are returned. + """ + for dist in self.get_distributions(): + r = dist.exports + if category in r: + d = r[category] + if name is not None: + if name in d: + yield d[name] + else: + for v in d.values(): + yield v + + +class Distribution(object): + """ + A base class for distributions, whether installed or from indexes. + Either way, it must have some metadata, so that's all that's needed + for construction. + """ + + build_time_dependency = False + """ + Set to True if it's known to be only a build-time dependency (i.e. + not needed after installation). + """ + + requested = False + """A boolean that indicates whether the ``REQUESTED`` metadata file is + present (in other words, whether the package was installed by user + request or it was installed as a dependency).""" + + def __init__(self, metadata): + """ + Initialise an instance. + :param metadata: The instance of :class:`Metadata` describing this + distribution. + """ + self.metadata = metadata + self.name = metadata.name + self.key = self.name.lower() # for case-insensitive comparisons + self.version = metadata.version + self.locator = None + self.digest = None + self.extras = None # additional features requested + self.context = None # environment marker overrides + self.download_urls = set() + self.digests = {} + + @property + def source_url(self): + """ + The source archive download URL for this distribution. + """ + return self.metadata.source_url + + download_url = source_url # Backward compatibility + + @property + def name_and_version(self): + """ + A utility property which displays the name and version in parentheses. + """ + return '%s (%s)' % (self.name, self.version) + + @property + def provides(self): + """ + A set of distribution names and versions provided by this distribution. + :return: A set of "name (version)" strings. + """ + plist = self.metadata.provides + s = '%s (%s)' % (self.name, self.version) + if s not in plist: + plist.append(s) + return plist + + def _get_requirements(self, req_attr): + md = self.metadata + logger.debug('Getting requirements from metadata %r', md.todict()) + reqts = getattr(md, req_attr) + return set(md.get_requirements(reqts, extras=self.extras, + env=self.context)) + + @property + def run_requires(self): + return self._get_requirements('run_requires') + + @property + def meta_requires(self): + return self._get_requirements('meta_requires') + + @property + def build_requires(self): + return self._get_requirements('build_requires') + + @property + def test_requires(self): + return self._get_requirements('test_requires') + + @property + def dev_requires(self): + return self._get_requirements('dev_requires') + + def matches_requirement(self, req): + """ + Say if this instance matches (fulfills) a requirement. + :param req: The requirement to match. + :rtype req: str + :return: True if it matches, else False. + """ + # Requirement may contain extras - parse to lose those + # from what's passed to the matcher + r = parse_requirement(req) + scheme = get_scheme(self.metadata.scheme) + try: + matcher = scheme.matcher(r.requirement) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', + req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + result = False + for p in self.provides: + p_name, p_ver = parse_name_and_version(p) + if p_name != name: + continue + try: + result = matcher.match(p_ver) + break + except UnsupportedVersionError: + pass + return result + + def __repr__(self): + """ + Return a textual representation of this instance, + """ + if self.source_url: + suffix = ' [%s]' % self.source_url + else: + suffix = '' + return '<Distribution %s (%s)%s>' % (self.name, self.version, suffix) + + def __eq__(self, other): + """ + See if this distribution is the same as another. + :param other: The distribution to compare with. To be equal to one + another. distributions must have the same type, name, + version and source_url. + :return: True if it is the same, else False. + """ + if type(other) is not type(self): + result = False + else: + result = (self.name == other.name and + self.version == other.version and + self.source_url == other.source_url) + return result + + def __hash__(self): + """ + Compute hash in a way which matches the equality test. + """ + return hash(self.name) + hash(self.version) + hash(self.source_url) + + +class BaseInstalledDistribution(Distribution): + """ + This is the base class for installed distributions (whether PEP 376 or + legacy). + """ + + hasher = None + + def __init__(self, metadata, path, env=None): + """ + Initialise an instance. + :param metadata: An instance of :class:`Metadata` which describes the + distribution. This will normally have been initialised + from a metadata file in the ``path``. + :param path: The path of the ``.dist-info`` or ``.egg-info`` + directory for the distribution. + :param env: This is normally the :class:`DistributionPath` + instance where this distribution was found. + """ + super(BaseInstalledDistribution, self).__init__(metadata) + self.path = path + self.dist_path = env + + def get_hash(self, data, hasher=None): + """ + Get the hash of some data, using a particular hash algorithm, if + specified. + + :param data: The data to be hashed. + :type data: bytes + :param hasher: The name of a hash implementation, supported by hashlib, + or ``None``. Examples of valid values are ``'sha1'``, + ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and + ``'sha512'``. If no hasher is specified, the ``hasher`` + attribute of the :class:`InstalledDistribution` instance + is used. If the hasher is determined to be ``None``, MD5 + is used as the hashing algorithm. + :returns: The hash of the data. If a hasher was explicitly specified, + the returned hash will be prefixed with the specified hasher + followed by '='. + :rtype: str + """ + if hasher is None: + hasher = self.hasher + if hasher is None: + hasher = hashlib.md5 + prefix = '' + else: + hasher = getattr(hashlib, hasher) + prefix = '%s=' % self.hasher + digest = hasher(data).digest() + digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') + return '%s%s' % (prefix, digest) + + +class InstalledDistribution(BaseInstalledDistribution): + """ + Created with the *path* of the ``.dist-info`` directory provided to the + constructor. It reads the metadata contained in ``pydist.json`` when it is + instantiated., or uses a passed in Metadata instance (useful for when + dry-run mode is being used). + """ + + hasher = 'sha256' + + def __init__(self, path, metadata=None, env=None): + self.modules = [] + self.finder = finder = resources.finder_for_path(path) + if finder is None: + raise ValueError('finder unavailable for %s' % path) + if env and env._cache_enabled and path in env._cache.path: + metadata = env._cache.path[path].metadata + elif metadata is None: + r = finder.find(METADATA_FILENAME) + # Temporary - for Wheel 0.23 support + if r is None: + r = finder.find(WHEEL_METADATA_FILENAME) + # Temporary - for legacy support + if r is None: + r = finder.find('METADATA') + if r is None: + raise ValueError('no %s found in %s' % (METADATA_FILENAME, + path)) + with contextlib.closing(r.as_stream()) as stream: + metadata = Metadata(fileobj=stream, scheme='legacy') + + super(InstalledDistribution, self).__init__(metadata, path, env) + + if env and env._cache_enabled: + env._cache.add(self) + + r = finder.find('REQUESTED') + self.requested = r is not None + p = os.path.join(path, 'top_level.txt') + if os.path.exists(p): + with open(p, 'rb') as f: + data = f.read() + self.modules = data.splitlines() + + def __repr__(self): + return '<InstalledDistribution %r %s at %r>' % ( + self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def _get_records(self): + """ + Get the list of installed files for the distribution + :return: A list of tuples of path, hash and size. Note that hash and + size might be ``None`` for some entries. The path is exactly + as stored in the file (which is as in PEP 376). + """ + results = [] + r = self.get_distinfo_resource('RECORD') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as record_reader: + # Base location is parent dir of .dist-info dir + #base_location = os.path.dirname(self.path) + #base_location = os.path.abspath(base_location) + for row in record_reader: + missing = [None for i in range(len(row), 3)] + path, checksum, size = row + missing + #if not os.path.isabs(path): + # path = path.replace('/', os.sep) + # path = os.path.join(base_location, path) + results.append((path, checksum, size)) + return results + + @cached_property + def exports(self): + """ + Return the information exported by this distribution. + :return: A dictionary of exports, mapping an export category to a dict + of :class:`ExportEntry` instances describing the individual + export entries, and keyed by name. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + result = self.read_exports() + return result + + def read_exports(self): + """ + Read exports data from a file in .ini format. + + :return: A dictionary of exports, mapping an export category to a list + of :class:`ExportEntry` instances describing the individual + export entries. + """ + result = {} + r = self.get_distinfo_resource(EXPORTS_FILENAME) + if r: + with contextlib.closing(r.as_stream()) as stream: + result = read_exports(stream) + return result + + def write_exports(self, exports): + """ + Write a dictionary of exports to a file in .ini format. + :param exports: A dictionary of exports, mapping an export category to + a list of :class:`ExportEntry` instances describing the + individual export entries. + """ + rf = self.get_distinfo_file(EXPORTS_FILENAME) + with open(rf, 'w') as f: + write_exports(exports, f) + + def get_resource_path(self, relative_path): + """ + NOTE: This API may change in the future. + + Return the absolute path to a resource file with the given relative + path. + + :param relative_path: The path, relative to .dist-info, of the resource + of interest. + :return: The absolute path where the resource is to be found. + """ + r = self.get_distinfo_resource('RESOURCES') + with contextlib.closing(r.as_stream()) as stream: + with CSVReader(stream=stream) as resources_reader: + for relative, destination in resources_reader: + if relative == relative_path: + return destination + raise KeyError('no resource file with relative path %r ' + 'is installed' % relative_path) + + def list_installed_files(self): + """ + Iterates over the ``RECORD`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: iterator of (path, hash, size) + """ + for result in self._get_records(): + yield result + + def write_installed_files(self, paths, prefix, dry_run=False): + """ + Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any + existing ``RECORD`` file is silently overwritten. + + prefix is used to determine when to write absolute paths. + """ + prefix = os.path.join(prefix, '') + base = os.path.dirname(self.path) + base_under_prefix = base.startswith(prefix) + base = os.path.join(base, '') + record_path = self.get_distinfo_file('RECORD') + logger.info('creating %s', record_path) + if dry_run: + return None + with CSVWriter(record_path) as writer: + for path in paths: + if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')): + # do not put size and hash, as in PEP-376 + hash_value = size = '' + else: + size = '%d' % os.path.getsize(path) + with open(path, 'rb') as fp: + hash_value = self.get_hash(fp.read()) + if path.startswith(base) or (base_under_prefix and + path.startswith(prefix)): + path = os.path.relpath(path, base) + writer.writerow((path, hash_value, size)) + + # add the RECORD file itself + if record_path.startswith(base): + record_path = os.path.relpath(record_path, base) + writer.writerow((record_path, '', '')) + return record_path + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + base = os.path.dirname(self.path) + record_path = self.get_distinfo_file('RECORD') + for path, hash_value, size in self.list_installed_files(): + if not os.path.isabs(path): + path = os.path.join(base, path) + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + elif os.path.isfile(path): + actual_size = str(os.path.getsize(path)) + if size and actual_size != size: + mismatches.append((path, 'size', size, actual_size)) + elif hash_value: + if '=' in hash_value: + hasher = hash_value.split('=', 1)[0] + else: + hasher = None + + with open(path, 'rb') as f: + actual_hash = self.get_hash(f.read(), hasher) + if actual_hash != hash_value: + mismatches.append((path, 'hash', hash_value, actual_hash)) + return mismatches + + @cached_property + def shared_locations(self): + """ + A dictionary of shared locations whose keys are in the set 'prefix', + 'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'. + The corresponding value is the absolute path of that category for + this distribution, and takes into account any paths selected by the + user at installation time (e.g. via command-line arguments). In the + case of the 'namespace' key, this would be a list of absolute paths + for the roots of namespace packages in this distribution. + + The first time this property is accessed, the relevant information is + read from the SHARED file in the .dist-info directory. + """ + result = {} + shared_path = os.path.join(self.path, 'SHARED') + if os.path.isfile(shared_path): + with codecs.open(shared_path, 'r', encoding='utf-8') as f: + lines = f.read().splitlines() + for line in lines: + key, value = line.split('=', 1) + if key == 'namespace': + result.setdefault(key, []).append(value) + else: + result[key] = value + return result + + def write_shared_locations(self, paths, dry_run=False): + """ + Write shared location information to the SHARED file in .dist-info. + :param paths: A dictionary as described in the documentation for + :meth:`shared_locations`. + :param dry_run: If True, the action is logged but no file is actually + written. + :return: The path of the file written to. + """ + shared_path = os.path.join(self.path, 'SHARED') + logger.info('creating %s', shared_path) + if dry_run: + return None + lines = [] + for key in ('prefix', 'lib', 'headers', 'scripts', 'data'): + path = paths[key] + if os.path.isdir(paths[key]): + lines.append('%s=%s' % (key, path)) + for ns in paths.get('namespace', ()): + lines.append('namespace=%s' % ns) + + with codecs.open(shared_path, 'w', encoding='utf-8') as f: + f.write('\n'.join(lines)) + return shared_path + + def get_distinfo_resource(self, path): + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + finder = resources.finder_for_path(self.path) + if finder is None: + raise DistlibException('Unable to get a finder for %s' % self.path) + return finder.find(path) + + def get_distinfo_file(self, path): + """ + Returns a path located under the ``.dist-info`` directory. Returns a + string representing the path. + + :parameter path: a ``'/'``-separated path relative to the + ``.dist-info`` directory or an absolute path; + If *path* is an absolute path and doesn't start + with the ``.dist-info`` directory path, + a :class:`DistlibException` is raised + :type path: str + :rtype: str + """ + # Check if it is an absolute path # XXX use relpath, add tests + if path.find(os.sep) >= 0: + # it's an absolute path? + distinfo_dirname, path = path.split(os.sep)[-2:] + if distinfo_dirname != self.path.split(os.sep)[-1]: + raise DistlibException( + 'dist-info file %r does not belong to the %r %s ' + 'distribution' % (path, self.name, self.version)) + + # The file must be relative + if path not in DIST_FILES: + raise DistlibException('invalid path for a dist-info file: ' + '%r at %r' % (path, self.path)) + + return os.path.join(self.path, path) + + def list_distinfo_files(self): + """ + Iterates over the ``RECORD`` entries and returns paths for each line if + the path is pointing to a file located in the ``.dist-info`` directory + or one of its subdirectories. + + :returns: iterator of paths + """ + base = os.path.dirname(self.path) + for path, checksum, size in self._get_records(): + # XXX add separator or use real relpath algo + if not os.path.isabs(path): + path = os.path.join(base, path) + if path.startswith(self.path): + yield path + + def __eq__(self, other): + return (isinstance(other, InstalledDistribution) and + self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + + +class EggInfoDistribution(BaseInstalledDistribution): + """Created with the *path* of the ``.egg-info`` directory or file provided + to the constructor. It reads the metadata contained in the file itself, or + if the given path happens to be a directory, the metadata is read from the + file ``PKG-INFO`` under that directory.""" + + requested = True # as we have no way of knowing, assume it was + shared_locations = {} + + def __init__(self, path, env=None): + def set_name_and_version(s, n, v): + s.name = n + s.key = n.lower() # for case-insensitive comparisons + s.version = v + + self.path = path + self.dist_path = env + if env and env._cache_enabled and path in env._cache_egg.path: + metadata = env._cache_egg.path[path].metadata + set_name_and_version(self, metadata.name, metadata.version) + else: + metadata = self._get_metadata(path) + + # Need to be set before caching + set_name_and_version(self, metadata.name, metadata.version) + + if env and env._cache_enabled: + env._cache_egg.add(self) + super(EggInfoDistribution, self).__init__(metadata, path, env) + + def _get_metadata(self, path): + requires = None + + def parse_requires_data(data): + """Create a list of dependencies from a requires.txt file. + + *data*: the contents of a setuptools-produced requires.txt file. + """ + reqs = [] + lines = data.splitlines() + for line in lines: + line = line.strip() + if line.startswith('['): + logger.warning('Unexpected line: quitting requirement scan: %r', + line) + break + r = parse_requirement(line) + if not r: + logger.warning('Not recognised as a requirement: %r', line) + continue + if r.extras: + logger.warning('extra requirements in requires.txt are ' + 'not supported') + if not r.constraints: + reqs.append(r.name) + else: + cons = ', '.join('%s%s' % c for c in r.constraints) + reqs.append('%s (%s)' % (r.name, cons)) + return reqs + + def parse_requires_path(req_path): + """Create a list of dependencies from a requires.txt file. + + *req_path*: the path to a setuptools-produced requires.txt file. + """ + + reqs = [] + try: + with codecs.open(req_path, 'r', 'utf-8') as fp: + reqs = parse_requires_data(fp.read()) + except IOError: + pass + return reqs + + tl_path = tl_data = None + if path.endswith('.egg'): + if os.path.isdir(path): + p = os.path.join(path, 'EGG-INFO') + meta_path = os.path.join(p, 'PKG-INFO') + metadata = Metadata(path=meta_path, scheme='legacy') + req_path = os.path.join(p, 'requires.txt') + tl_path = os.path.join(p, 'top_level.txt') + requires = parse_requires_path(req_path) + else: + # FIXME handle the case where zipfile is not available + zipf = zipimport.zipimporter(path) + fileobj = StringIO( + zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) + metadata = Metadata(fileobj=fileobj, scheme='legacy') + try: + data = zipf.get_data('EGG-INFO/requires.txt') + tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode('utf-8') + requires = parse_requires_data(data.decode('utf-8')) + except IOError: + requires = None + elif path.endswith('.egg-info'): + if os.path.isdir(path): + req_path = os.path.join(path, 'requires.txt') + requires = parse_requires_path(req_path) + path = os.path.join(path, 'PKG-INFO') + tl_path = os.path.join(path, 'top_level.txt') + metadata = Metadata(path=path, scheme='legacy') + else: + raise DistlibException('path must end with .egg-info or .egg, ' + 'got %r' % path) + + if requires: + metadata.add_requirements(requires) + # look for top-level modules in top_level.txt, if present + if tl_data is None: + if tl_path is not None and os.path.exists(tl_path): + with open(tl_path, 'rb') as f: + tl_data = f.read().decode('utf-8') + if not tl_data: + tl_data = [] + else: + tl_data = tl_data.splitlines() + self.modules = tl_data + return metadata + + def __repr__(self): + return '<EggInfoDistribution %r %s at %r>' % ( + self.name, self.version, self.path) + + def __str__(self): + return "%s %s" % (self.name, self.version) + + def check_installed_files(self): + """ + Checks that the hashes and sizes of the files in ``RECORD`` are + matched by the files themselves. Returns a (possibly empty) list of + mismatches. Each entry in the mismatch list will be a tuple consisting + of the path, 'exists', 'size' or 'hash' according to what didn't match + (existence is checked first, then size, then hash), the expected + value and the actual value. + """ + mismatches = [] + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + for path, _, _ in self.list_installed_files(): + if path == record_path: + continue + if not os.path.exists(path): + mismatches.append((path, 'exists', True, False)) + return mismatches + + def list_installed_files(self): + """ + Iterates over the ``installed-files.txt`` entries and returns a tuple + ``(path, hash, size)`` for each line. + + :returns: a list of (path, hash, size) + """ + + def _md5(path): + f = open(path, 'rb') + try: + content = f.read() + finally: + f.close() + return hashlib.md5(content).hexdigest() + + def _size(path): + return os.stat(path).st_size + + record_path = os.path.join(self.path, 'installed-files.txt') + result = [] + if os.path.exists(record_path): + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + p = os.path.normpath(os.path.join(self.path, line)) + # "./" is present as a marker between installed files + # and installation metadata files + if not os.path.exists(p): + logger.warning('Non-existent file: %s', p) + if p.endswith(('.pyc', '.pyo')): + continue + #otherwise fall through and fail + if not os.path.isdir(p): + result.append((p, _md5(p), _size(p))) + result.append((record_path, None, None)) + return result + + def list_distinfo_files(self, absolute=False): + """ + Iterates over the ``installed-files.txt`` entries and returns paths for + each line if the path is pointing to a file located in the + ``.egg-info`` directory or one of its subdirectories. + + :parameter absolute: If *absolute* is ``True``, each returned path is + transformed into a local absolute path. Otherwise the + raw value from ``installed-files.txt`` is returned. + :type absolute: boolean + :returns: iterator of paths + """ + record_path = os.path.join(self.path, 'installed-files.txt') + if os.path.exists(record_path): + skip = True + with codecs.open(record_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line == './': + skip = False + continue + if not skip: + p = os.path.normpath(os.path.join(self.path, line)) + if p.startswith(self.path): + if absolute: + yield p + else: + yield line + + def __eq__(self, other): + return (isinstance(other, EggInfoDistribution) and + self.path == other.path) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + __hash__ = object.__hash__ + +new_dist_class = InstalledDistribution +old_dist_class = EggInfoDistribution + + +class DependencyGraph(object): + """ + Represents a dependency graph between distributions. + + The dependency relationships are stored in an ``adjacency_list`` that maps + distributions to a list of ``(other, label)`` tuples where ``other`` + is a distribution and the edge is labeled with ``label`` (i.e. the version + specifier, if such was provided). Also, for more efficient traversal, for + every distribution ``x``, a list of predecessors is kept in + ``reverse_list[x]``. An edge from distribution ``a`` to + distribution ``b`` means that ``a`` depends on ``b``. If any missing + dependencies are found, they are stored in ``missing``, which is a + dictionary that maps distributions to a list of requirements that were not + provided by any other distributions. + """ + + def __init__(self): + self.adjacency_list = {} + self.reverse_list = {} + self.missing = {} + + def add_distribution(self, distribution): + """Add the *distribution* to the graph. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + """ + self.adjacency_list[distribution] = [] + self.reverse_list[distribution] = [] + #self.missing[distribution] = [] + + def add_edge(self, x, y, label=None): + """Add an edge from distribution *x* to distribution *y* with the given + *label*. + + :type x: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type y: :class:`distutils2.database.InstalledDistribution` or + :class:`distutils2.database.EggInfoDistribution` + :type label: ``str`` or ``None`` + """ + self.adjacency_list[x].append((y, label)) + # multiple edges are allowed, so be careful + if x not in self.reverse_list[y]: + self.reverse_list[y].append(x) + + def add_missing(self, distribution, requirement): + """ + Add a missing *requirement* for the given *distribution*. + + :type distribution: :class:`distutils2.database.InstalledDistribution` + or :class:`distutils2.database.EggInfoDistribution` + :type requirement: ``str`` + """ + logger.debug('%s missing %r', distribution, requirement) + self.missing.setdefault(distribution, []).append(requirement) + + def _repr_dist(self, dist): + return '%s %s' % (dist.name, dist.version) + + def repr_node(self, dist, level=1): + """Prints only a subgraph""" + output = [self._repr_dist(dist)] + for other, label in self.adjacency_list[dist]: + dist = self._repr_dist(other) + if label is not None: + dist = '%s [%s]' % (dist, label) + output.append(' ' * level + str(dist)) + suboutput = self.repr_node(other, level + 1) + subs = suboutput.split('\n') + output.extend(subs[1:]) + return '\n'.join(output) + + def to_dot(self, f, skip_disconnected=True): + """Writes a DOT output for the graph to the provided file *f*. + + If *skip_disconnected* is set to ``True``, then all distributions + that are not dependent on any other distribution are skipped. + + :type f: has to support ``file``-like operations + :type skip_disconnected: ``bool`` + """ + disconnected = [] + + f.write("digraph dependencies {\n") + for dist, adjs in self.adjacency_list.items(): + if len(adjs) == 0 and not skip_disconnected: + disconnected.append(dist) + for other, label in adjs: + if not label is None: + f.write('"%s" -> "%s" [label="%s"]\n' % + (dist.name, other.name, label)) + else: + f.write('"%s" -> "%s"\n' % (dist.name, other.name)) + if not skip_disconnected and len(disconnected) > 0: + f.write('subgraph disconnected {\n') + f.write('label = "Disconnected"\n') + f.write('bgcolor = red\n') + + for dist in disconnected: + f.write('"%s"' % dist.name) + f.write('\n') + f.write('}\n') + f.write('}\n') + + def topological_sort(self): + """ + Perform a topological sort of the graph. + :return: A tuple, the first element of which is a topologically sorted + list of distributions, and the second element of which is a + list of distributions that cannot be sorted because they have + circular dependencies and so form a cycle. + """ + result = [] + # Make a shallow copy of the adjacency list + alist = {} + for k, v in self.adjacency_list.items(): + alist[k] = v[:] + while True: + # See what we can remove in this run + to_remove = [] + for k, v in list(alist.items())[:]: + if not v: + to_remove.append(k) + del alist[k] + if not to_remove: + # What's left in alist (if anything) is a cycle. + break + # Remove from the adjacency list of others + for k, v in alist.items(): + alist[k] = [(d, r) for d, r in v if d not in to_remove] + logger.debug('Moving to result: %s', + ['%s (%s)' % (d.name, d.version) for d in to_remove]) + result.extend(to_remove) + return result, list(alist.keys()) + + def __repr__(self): + """Representation of the graph""" + output = [] + for dist, adjs in self.adjacency_list.items(): + output.append(self.repr_node(dist)) + return '\n'.join(output) + + +def make_graph(dists, scheme='default'): + """Makes a dependency graph from the given distributions. + + :parameter dists: a list of distributions + :type dists: list of :class:`distutils2.database.InstalledDistribution` and + :class:`distutils2.database.EggInfoDistribution` instances + :rtype: a :class:`DependencyGraph` instance + """ + scheme = get_scheme(scheme) + graph = DependencyGraph() + provided = {} # maps names to lists of (version, dist) tuples + + # first, build the graph and find out what's provided + for dist in dists: + graph.add_distribution(dist) + + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + provided.setdefault(name, []).append((version, dist)) + + # now make the edges + for dist in dists: + requires = (dist.run_requires | dist.meta_requires | + dist.build_requires | dist.dev_requires) + for req in requires: + try: + matcher = scheme.matcher(req) + except UnsupportedVersionError: + # XXX compat-mode if cannot read the version + logger.warning('could not read version %r - using name only', + req) + name = req.split()[0] + matcher = scheme.matcher(name) + + name = matcher.key # case-insensitive + + matched = False + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + graph.add_edge(dist, provider, req) + matched = True + break + if not matched: + graph.add_missing(dist, req) + return graph + + +def get_dependent_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + dependent on *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + dep = [dist] # dependent distributions + todo = graph.reverse_list[dist] # list of nodes we should inspect + + while todo: + d = todo.pop() + dep.append(d) + for succ in graph.reverse_list[d]: + if succ not in dep: + todo.append(succ) + + dep.pop(0) # remove dist from dep, was there to prevent infinite loops + return dep + + +def get_required_dists(dists, dist): + """Recursively generate a list of distributions from *dists* that are + required by *dist*. + + :param dists: a list of distributions + :param dist: a distribution, member of *dists* for which we are interested + """ + if dist not in dists: + raise DistlibException('given distribution %r is not a member ' + 'of the list' % dist.name) + graph = make_graph(dists) + + req = [] # required distributions + todo = graph.adjacency_list[dist] # list of nodes we should inspect + + while todo: + d = todo.pop()[0] + req.append(d) + for pred in graph.adjacency_list[d]: + if pred not in req: + todo.append(pred) + + return req + + +def make_dist(name, version, **kwargs): + """ + A convenience method for making a dist given just a name and version. + """ + summary = kwargs.pop('summary', 'Placeholder for summary') + md = Metadata(**kwargs) + md.name = name + md.version = version + md.summary = summary or 'Placeholder for summary' + return Distribution(md) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py new file mode 100755 index 0000000..7197238 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/index.py @@ -0,0 +1,516 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import hashlib +import logging +import os +import shutil +import subprocess +import tempfile +try: + from threading import Thread +except ImportError: + from dummy_threading import Thread + +from . import DistlibException +from .compat import (HTTPBasicAuthHandler, Request, HTTPPasswordMgr, + urlparse, build_opener, string_types) +from .util import cached_property, zip_dir, ServerProxy + +logger = logging.getLogger(__name__) + +DEFAULT_INDEX = 'https://pypi.python.org/pypi' +DEFAULT_REALM = 'pypi' + +class PackageIndex(object): + """ + This class represents a package index compatible with PyPI, the Python + Package Index. + """ + + boundary = b'----------ThIs_Is_tHe_distlib_index_bouNdaRY_$' + + def __init__(self, url=None): + """ + Initialise an instance. + + :param url: The URL of the index. If not specified, the URL for PyPI is + used. + """ + self.url = url or DEFAULT_INDEX + self.read_configuration() + scheme, netloc, path, params, query, frag = urlparse(self.url) + if params or query or frag or scheme not in ('http', 'https'): + raise DistlibException('invalid repository: %s' % self.url) + self.password_handler = None + self.ssl_verifier = None + self.gpg = None + self.gpg_home = None + with open(os.devnull, 'w') as sink: + # Use gpg by default rather than gpg2, as gpg2 insists on + # prompting for passwords + for s in ('gpg', 'gpg2'): + try: + rc = subprocess.check_call([s, '--version'], stdout=sink, + stderr=sink) + if rc == 0: + self.gpg = s + break + except OSError: + pass + + def _get_pypirc_command(self): + """ + Get the distutils command for interacting with PyPI configurations. + :return: the command. + """ + from distutils.core import Distribution + from distutils.config import PyPIRCCommand + d = Distribution() + return PyPIRCCommand(d) + + def read_configuration(self): + """ + Read the PyPI access configuration as supported by distutils, getting + PyPI to do the actual work. This populates ``username``, ``password``, + ``realm`` and ``url`` attributes from the configuration. + """ + # get distutils to do the work + c = self._get_pypirc_command() + c.repository = self.url + cfg = c._read_pypirc() + self.username = cfg.get('username') + self.password = cfg.get('password') + self.realm = cfg.get('realm', 'pypi') + self.url = cfg.get('repository', self.url) + + def save_configuration(self): + """ + Save the PyPI access configuration. You must have set ``username`` and + ``password`` attributes before calling this method. + + Again, distutils is used to do the actual work. + """ + self.check_credentials() + # get distutils to do the work + c = self._get_pypirc_command() + c._store_pypirc(self.username, self.password) + + def check_credentials(self): + """ + Check that ``username`` and ``password`` have been set, and raise an + exception if not. + """ + if self.username is None or self.password is None: + raise DistlibException('username and password must be set') + pm = HTTPPasswordMgr() + _, netloc, _, _, _, _ = urlparse(self.url) + pm.add_password(self.realm, netloc, self.username, self.password) + self.password_handler = HTTPBasicAuthHandler(pm) + + def register(self, metadata): + """ + Register a distribution on PyPI, using the provided metadata. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the distribution to be + registered. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + metadata.validate() + d = metadata.todict() + d[':action'] = 'verify' + request = self.encode_request(d.items(), []) + response = self.send_request(request) + d[':action'] = 'submit' + request = self.encode_request(d.items(), []) + return self.send_request(request) + + def _reader(self, name, stream, outbuf): + """ + Thread runner for reading lines of from a subprocess into a buffer. + + :param name: The logical name of the stream (used for logging only). + :param stream: The stream to read from. This will typically a pipe + connected to the output stream of a subprocess. + :param outbuf: The list to append the read lines to. + """ + while True: + s = stream.readline() + if not s: + break + s = s.decode('utf-8').rstrip() + outbuf.append(s) + logger.debug('%s: %s' % (name, s)) + stream.close() + + def get_sign_command(self, filename, signer, sign_password, + keystore=None): + """ + Return a suitable command for signing a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The signing command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + if sign_password is not None: + cmd.extend(['--batch', '--passphrase-fd', '0']) + td = tempfile.mkdtemp() + sf = os.path.join(td, os.path.basename(filename) + '.asc') + cmd.extend(['--detach-sign', '--armor', '--local-user', + signer, '--output', sf, filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd, sf + + def run_command(self, cmd, input_data=None): + """ + Run a command in a child process , passing it any input data specified. + + :param cmd: The command to run. + :param input_data: If specified, this must be a byte string containing + data to be sent to the child process. + :return: A tuple consisting of the subprocess' exit code, a list of + lines read from the subprocess' ``stdout``, and a list of + lines read from the subprocess' ``stderr``. + """ + kwargs = { + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + } + if input_data is not None: + kwargs['stdin'] = subprocess.PIPE + stdout = [] + stderr = [] + p = subprocess.Popen(cmd, **kwargs) + # We don't use communicate() here because we may need to + # get clever with interacting with the command + t1 = Thread(target=self._reader, args=('stdout', p.stdout, stdout)) + t1.start() + t2 = Thread(target=self._reader, args=('stderr', p.stderr, stderr)) + t2.start() + if input_data is not None: + p.stdin.write(input_data) + p.stdin.close() + + p.wait() + t1.join() + t2.join() + return p.returncode, stdout, stderr + + def sign_file(self, filename, signer, sign_password, keystore=None): + """ + Sign a file. + + :param filename: The pathname to the file to be signed. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The absolute pathname of the file where the signature is + stored. + """ + cmd, sig_file = self.get_sign_command(filename, signer, sign_password, + keystore) + rc, stdout, stderr = self.run_command(cmd, + sign_password.encode('utf-8')) + if rc != 0: + raise DistlibException('sign command failed with error ' + 'code %s' % rc) + return sig_file + + def upload_file(self, metadata, filename, signer=None, sign_password=None, + filetype='sdist', pyversion='source', keystore=None): + """ + Upload a release file to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the file to be uploaded. + :param filename: The pathname of the file to be uploaded. + :param signer: The identifier of the signer of the file. + :param sign_password: The passphrase for the signer's + private key used for signing. + :param filetype: The type of the file being uploaded. This is the + distutils command which produced that file, e.g. + ``sdist`` or ``bdist_wheel``. + :param pyversion: The version of Python which the release relates + to. For code compatible with any Python, this would + be ``source``, otherwise it would be e.g. ``3.2``. + :param keystore: The path to a directory which contains the keys + used in signing. If not specified, the instance's + ``gpg_home`` attribute is used instead. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.exists(filename): + raise DistlibException('not found: %s' % filename) + metadata.validate() + d = metadata.todict() + sig_file = None + if signer: + if not self.gpg: + logger.warning('no signing program available - not signed') + else: + sig_file = self.sign_file(filename, signer, sign_password, + keystore) + with open(filename, 'rb') as f: + file_data = f.read() + md5_digest = hashlib.md5(file_data).hexdigest() + sha256_digest = hashlib.sha256(file_data).hexdigest() + d.update({ + ':action': 'file_upload', + 'protocol_version': '1', + 'filetype': filetype, + 'pyversion': pyversion, + 'md5_digest': md5_digest, + 'sha256_digest': sha256_digest, + }) + files = [('content', os.path.basename(filename), file_data)] + if sig_file: + with open(sig_file, 'rb') as f: + sig_data = f.read() + files.append(('gpg_signature', os.path.basename(sig_file), + sig_data)) + shutil.rmtree(os.path.dirname(sig_file)) + request = self.encode_request(d.items(), files) + return self.send_request(request) + + def upload_documentation(self, metadata, doc_dir): + """ + Upload documentation to the index. + + :param metadata: A :class:`Metadata` instance defining at least a name + and version number for the documentation to be + uploaded. + :param doc_dir: The pathname of the directory which contains the + documentation. This should be the directory that + contains the ``index.html`` for the documentation. + :return: The HTTP response received from PyPI upon submission of the + request. + """ + self.check_credentials() + if not os.path.isdir(doc_dir): + raise DistlibException('not a directory: %r' % doc_dir) + fn = os.path.join(doc_dir, 'index.html') + if not os.path.exists(fn): + raise DistlibException('not found: %r' % fn) + metadata.validate() + name, version = metadata.name, metadata.version + zip_data = zip_dir(doc_dir).getvalue() + fields = [(':action', 'doc_upload'), + ('name', name), ('version', version)] + files = [('content', name, zip_data)] + request = self.encode_request(fields, files) + return self.send_request(request) + + def get_verify_command(self, signature_filename, data_filename, + keystore=None): + """ + Return a suitable command for verifying a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: The verifying command as a list suitable to be + passed to :class:`subprocess.Popen`. + """ + cmd = [self.gpg, '--status-fd', '2', '--no-tty'] + if keystore is None: + keystore = self.gpg_home + if keystore: + cmd.extend(['--homedir', keystore]) + cmd.extend(['--verify', signature_filename, data_filename]) + logger.debug('invoking: %s', ' '.join(cmd)) + return cmd + + def verify_signature(self, signature_filename, data_filename, + keystore=None): + """ + Verify a signature for a file. + + :param signature_filename: The pathname to the file containing the + signature. + :param data_filename: The pathname to the file containing the + signed data. + :param keystore: The path to a directory which contains the keys + used in verification. If not specified, the + instance's ``gpg_home`` attribute is used instead. + :return: True if the signature was verified, else False. + """ + if not self.gpg: + raise DistlibException('verification unavailable because gpg ' + 'unavailable') + cmd = self.get_verify_command(signature_filename, data_filename, + keystore) + rc, stdout, stderr = self.run_command(cmd) + if rc not in (0, 1): + raise DistlibException('verify command failed with error ' + 'code %s' % rc) + return rc == 0 + + def download_file(self, url, destfile, digest=None, reporthook=None): + """ + This is a convenience method for downloading a file from an URL. + Normally, this will be a file from the index, though currently + no check is made for this (i.e. a file can be downloaded from + anywhere). + + The method is just like the :func:`urlretrieve` function in the + standard library, except that it allows digest computation to be + done during download and checking that the downloaded data + matched any expected value. + + :param url: The URL of the file to be downloaded (assumed to be + available via an HTTP GET request). + :param destfile: The pathname where the downloaded file is to be + saved. + :param digest: If specified, this must be a (hasher, value) + tuple, where hasher is the algorithm used (e.g. + ``'md5'``) and ``value`` is the expected value. + :param reporthook: The same as for :func:`urlretrieve` in the + standard library. + """ + if digest is None: + digester = None + logger.debug('No digest specified') + else: + if isinstance(digest, (list, tuple)): + hasher, digest = digest + else: + hasher = 'md5' + digester = getattr(hashlib, hasher)() + logger.debug('Digest specified: %s' % digest) + # The following code is equivalent to urlretrieve. + # We need to do it this way so that we can compute the + # digest of the file as we go. + with open(destfile, 'wb') as dfp: + # addinfourl is not a context manager on 2.x + # so we have to use try/finally + sfp = self.send_request(Request(url)) + try: + headers = sfp.info() + blocksize = 8192 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + if reporthook: + reporthook(blocknum, blocksize, size) + while True: + block = sfp.read(blocksize) + if not block: + break + read += len(block) + dfp.write(block) + if digester: + digester.update(block) + blocknum += 1 + if reporthook: + reporthook(blocknum, blocksize, size) + finally: + sfp.close() + + # check that we got the whole file, if we can + if size >= 0 and read < size: + raise DistlibException( + 'retrieval incomplete: got only %d out of %d bytes' + % (read, size)) + # if we have a digest, it must match. + if digester: + actual = digester.hexdigest() + if digest != actual: + raise DistlibException('%s digest mismatch for %s: expected ' + '%s, got %s' % (hasher, destfile, + digest, actual)) + logger.debug('Digest verified: %s', digest) + + def send_request(self, req): + """ + Send a standard library :class:`Request` to PyPI and return its + response. + + :param req: The request to send. + :return: The HTTP response from PyPI (a standard library HTTPResponse). + """ + handlers = [] + if self.password_handler: + handlers.append(self.password_handler) + if self.ssl_verifier: + handlers.append(self.ssl_verifier) + opener = build_opener(*handlers) + return opener.open(req) + + def encode_request(self, fields, files): + """ + Encode fields and files for posting to an HTTP server. + + :param fields: The fields to send as a list of (fieldname, value) + tuples. + :param files: The files to send as a list of (fieldname, filename, + file_bytes) tuple. + """ + # Adapted from packaging, which in turn was adapted from + # http://code.activestate.com/recipes/146306 + + parts = [] + boundary = self.boundary + for k, values in fields: + if not isinstance(values, (list, tuple)): + values = [values] + + for v in values: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"' % + k).encode('utf-8'), + b'', + v.encode('utf-8'))) + for key, filename, value in files: + parts.extend(( + b'--' + boundary, + ('Content-Disposition: form-data; name="%s"; filename="%s"' % + (key, filename)).encode('utf-8'), + b'', + value)) + + parts.extend((b'--' + boundary + b'--', b'')) + + body = b'\r\n'.join(parts) + ct = b'multipart/form-data; boundary=' + boundary + headers = { + 'Content-type': ct, + 'Content-length': str(len(body)) + } + return Request(self.url, body, headers) + + def search(self, terms, operator=None): + if isinstance(terms, string_types): + terms = {'name': terms} + rpc_proxy = ServerProxy(self.url, timeout=3.0) + try: + return rpc_proxy.search(terms, operator or 'and') + finally: + rpc_proxy('close')() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py new file mode 100755 index 0000000..9131b77 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/locators.py @@ -0,0 +1,1292 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2015 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# + +import gzip +from io import BytesIO +import json +import logging +import os +import posixpath +import re +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import zlib + +from . import DistlibException +from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, + queue, quote, unescape, string_types, build_opener, + HTTPRedirectHandler as BaseRedirectHandler, text_type, + Request, HTTPError, URLError) +from .database import Distribution, DistributionPath, make_dist +from .metadata import Metadata, MetadataInvalidError +from .util import (cached_property, parse_credentials, ensure_slash, + split_filename, get_project_data, parse_requirement, + parse_name_and_version, ServerProxy, normalize_name) +from .version import get_scheme, UnsupportedVersionError +from .wheel import Wheel, is_compatible + +logger = logging.getLogger(__name__) + +HASHER_HASH = re.compile(r'^(\w+)=([a-f0-9]+)') +CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I) +HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml') +DEFAULT_INDEX = 'https://pypi.python.org/pypi' + +def get_all_distribution_names(url=None): + """ + Return all distribution names known by an index. + :param url: The URL of the index. + :return: A list of all known distribution names. + """ + if url is None: + url = DEFAULT_INDEX + client = ServerProxy(url, timeout=3.0) + try: + return client.list_packages() + finally: + client('close')() + +class RedirectHandler(BaseRedirectHandler): + """ + A class to work around a bug in some Python 3.2.x releases. + """ + # There's a bug in the base version for some 3.2.x + # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header + # returns e.g. /abc, it bails because it says the scheme '' + # is bogus, when actually it should use the request's + # URL for the scheme. See Python issue #13696. + def http_error_302(self, req, fp, code, msg, headers): + # Some servers (incorrectly) return multiple Location headers + # (so probably same goes for URI). Use first header. + newurl = None + for key in ('location', 'uri'): + if key in headers: + newurl = headers[key] + break + if newurl is None: # pragma: no cover + return + urlparts = urlparse(newurl) + if urlparts.scheme == '': + newurl = urljoin(req.get_full_url(), newurl) + if hasattr(headers, 'replace_header'): + headers.replace_header(key, newurl) + else: + headers[key] = newurl + return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, + headers) + + http_error_301 = http_error_303 = http_error_307 = http_error_302 + +class Locator(object): + """ + A base class for locators - things that locate distributions. + """ + source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz') + binary_extensions = ('.egg', '.exe', '.whl') + excluded_extensions = ('.pdf',) + + # A list of tags indicating which wheels you want to match. The default + # value of None matches against the tags compatible with the running + # Python. If you want to match other values, set wheel_tags on a locator + # instance to a list of tuples (pyver, abi, arch) which you want to match. + wheel_tags = None + + downloadable_extensions = source_extensions + ('.whl',) + + def __init__(self, scheme='default'): + """ + Initialise an instance. + :param scheme: Because locators look for most recent versions, they + need to know the version scheme to use. This specifies + the current PEP-recommended scheme - use ``'legacy'`` + if you need to support existing distributions on PyPI. + """ + self._cache = {} + self.scheme = scheme + # Because of bugs in some of the handlers on some of the platforms, + # we use our own opener rather than just using urlopen. + self.opener = build_opener(RedirectHandler()) + # If get_project() is called from locate(), the matcher instance + # is set from the requirement passed to locate(). See issue #18 for + # why this can be useful to know. + self.matcher = None + self.errors = queue.Queue() + + def get_errors(self): + """ + Return any errors which have occurred. + """ + result = [] + while not self.errors.empty(): # pragma: no cover + try: + e = self.errors.get(False) + result.append(e) + except self.errors.Empty: + continue + self.errors.task_done() + return result + + def clear_errors(self): + """ + Clear any errors which may have been logged. + """ + # Just get the errors and throw them away + self.get_errors() + + def clear_cache(self): + self._cache.clear() + + def _get_scheme(self): + return self._scheme + + def _set_scheme(self, value): + self._scheme = value + + scheme = property(_get_scheme, _set_scheme) + + def _get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This should be implemented in subclasses. + + If called from a locate() request, self.matcher will be set to a + matcher for the requirement to satisfy, otherwise it will be None. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Please implement in the subclass') + + def get_project(self, name): + """ + For a given project, get a dictionary mapping available versions to Distribution + instances. + + This calls _get_project to do all the work, and just implements a caching layer on top. + """ + if self._cache is None: # pragma: no cover + result = self._get_project(name) + elif name in self._cache: + result = self._cache[name] + else: + self.clear_errors() + result = self._get_project(name) + self._cache[name] = result + return result + + def score_url(self, url): + """ + Give an url a score which can be used to choose preferred URLs + for a given project release. + """ + t = urlparse(url) + basename = posixpath.basename(t.path) + compatible = True + is_wheel = basename.endswith('.whl') + is_downloadable = basename.endswith(self.downloadable_extensions) + if is_wheel: + compatible = is_compatible(Wheel(basename), self.wheel_tags) + return (t.scheme == 'https', 'pypi.python.org' in t.netloc, + is_downloadable, is_wheel, compatible, basename) + + def prefer_url(self, url1, url2): + """ + Choose one of two URLs where both are candidates for distribution + archives for the same version of a distribution (for example, + .tar.gz vs. zip). + + The current implementation favours https:// URLs over http://, archives + from PyPI over those from other locations, wheel compatibility (if a + wheel) and then the archive name. + """ + result = url2 + if url1: + s1 = self.score_url(url1) + s2 = self.score_url(url2) + if s1 > s2: + result = url1 + if result != url2: + logger.debug('Not replacing %r with %r', url1, url2) + else: + logger.debug('Replacing %r with %r', url1, url2) + return result + + def split_filename(self, filename, project_name): + """ + Attempt to split a filename in project name, version and Python version. + """ + return split_filename(filename, project_name) + + def convert_url_to_download_info(self, url, project_name): + """ + See if a URL is a candidate for a download URL for a project (the URL + has typically been scraped from an HTML page). + + If it is, a dictionary is returned with keys "name", "version", + "filename" and "url"; otherwise, None is returned. + """ + def same_project(name1, name2): + return normalize_name(name1) == normalize_name(name2) + + result = None + scheme, netloc, path, params, query, frag = urlparse(url) + if frag.lower().startswith('egg='): # pragma: no cover + logger.debug('%s: version hint in fragment: %r', + project_name, frag) + m = HASHER_HASH.match(frag) + if m: + algo, digest = m.groups() + else: + algo, digest = None, None + origpath = path + if path and path[-1] == '/': # pragma: no cover + path = path[:-1] + if path.endswith('.whl'): + try: + wheel = Wheel(path) + if is_compatible(wheel, self.wheel_tags): + if project_name is None: + include = True + else: + include = same_project(wheel.name, project_name) + if include: + result = { + 'name': wheel.name, + 'version': wheel.version, + 'filename': wheel.filename, + 'url': urlunparse((scheme, netloc, origpath, + params, query, '')), + 'python-version': ', '.join( + ['.'.join(list(v[2:])) for v in wheel.pyver]), + } + except Exception as e: # pragma: no cover + logger.warning('invalid path for wheel: %s', path) + elif not path.endswith(self.downloadable_extensions): # pragma: no cover + logger.debug('Not downloadable: %s', path) + else: # downloadable extension + path = filename = posixpath.basename(path) + for ext in self.downloadable_extensions: + if path.endswith(ext): + path = path[:-len(ext)] + t = self.split_filename(path, project_name) + if not t: # pragma: no cover + logger.debug('No match for project/version: %s', path) + else: + name, version, pyver = t + if not project_name or same_project(project_name, name): + result = { + 'name': name, + 'version': version, + 'filename': filename, + 'url': urlunparse((scheme, netloc, origpath, + params, query, '')), + #'packagetype': 'sdist', + } + if pyver: # pragma: no cover + result['python-version'] = pyver + break + if result and algo: + result['%s_digest' % algo] = digest + return result + + def _get_digest(self, info): + """ + Get a digest from a dictionary by looking at keys of the form + 'algo_digest'. + + Returns a 2-tuple (algo, digest) if found, else None. Currently + looks only for SHA256, then MD5. + """ + result = None + for algo in ('sha256', 'md5'): + key = '%s_digest' % algo + if key in info: + result = (algo, info[key]) + break + return result + + def _update_version_data(self, result, info): + """ + Update a result dictionary (the final result from _get_project) with a + dictionary for a specific version, which typically holds information + gleaned from a filename or URL for an archive for the distribution. + """ + name = info.pop('name') + version = info.pop('version') + if version in result: + dist = result[version] + md = dist.metadata + else: + dist = make_dist(name, version, scheme=self.scheme) + md = dist.metadata + dist.digest = digest = self._get_digest(info) + url = info['url'] + result['digests'][url] = digest + if md.source_url != info['url']: + md.source_url = self.prefer_url(md.source_url, url) + result['urls'].setdefault(version, set()).add(url) + dist.locator = self + result[version] = dist + + def locate(self, requirement, prereleases=False): + """ + Find the most recent distribution which matches the given + requirement. + + :param requirement: A requirement of the form 'foo (1.0)' or perhaps + 'foo (>= 1.0, < 2.0, != 1.3)' + :param prereleases: If ``True``, allow pre-release versions + to be located. Otherwise, pre-release versions + are not returned. + :return: A :class:`Distribution` instance, or ``None`` if no such + distribution could be located. + """ + result = None + r = parse_requirement(requirement) + if r is None: # pragma: no cover + raise DistlibException('Not a valid requirement: %r' % requirement) + scheme = get_scheme(self.scheme) + self.matcher = matcher = scheme.matcher(r.requirement) + logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__) + versions = self.get_project(r.name) + if len(versions) > 2: # urls and digests keys are present + # sometimes, versions are invalid + slist = [] + vcls = matcher.version_class + for k in versions: + if k in ('urls', 'digests'): + continue + try: + if not matcher.match(k): + logger.debug('%s did not match %r', matcher, k) + else: + if prereleases or not vcls(k).is_prerelease: + slist.append(k) + else: + logger.debug('skipping pre-release ' + 'version %s of %s', k, matcher.name) + except Exception: # pragma: no cover + logger.warning('error matching %s with %r', matcher, k) + pass # slist.append(k) + if len(slist) > 1: + slist = sorted(slist, key=scheme.key) + if slist: + logger.debug('sorted list: %s', slist) + version = slist[-1] + result = versions[version] + if result: + if r.extras: + result.extras = r.extras + result.download_urls = versions.get('urls', {}).get(version, set()) + d = {} + sd = versions.get('digests', {}) + for url in result.download_urls: + if url in sd: # pragma: no cover + d[url] = sd[url] + result.digests = d + self.matcher = None + return result + + +class PyPIRPCLocator(Locator): + """ + This locator uses XML-RPC to locate distributions. It therefore + cannot be used with simple mirrors (that only mirror file content). + """ + def __init__(self, url, **kwargs): + """ + Initialise an instance. + + :param url: The URL to use for XML-RPC. + :param kwargs: Passed to the superclass constructor. + """ + super(PyPIRPCLocator, self).__init__(**kwargs) + self.base_url = url + self.client = ServerProxy(url, timeout=3.0) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + return set(self.client.list_packages()) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + versions = self.client.package_releases(name, True) + for v in versions: + urls = self.client.release_urls(name, v) + data = self.client.release_data(name, v) + metadata = Metadata(scheme=self.scheme) + metadata.name = data['name'] + metadata.version = data['version'] + metadata.license = data.get('license') + metadata.keywords = data.get('keywords', []) + metadata.summary = data.get('summary') + dist = Distribution(metadata) + if urls: + info = urls[0] + metadata.source_url = info['url'] + dist.digest = self._get_digest(info) + dist.locator = self + result[v] = dist + for info in urls: + url = info['url'] + digest = self._get_digest(info) + result['urls'].setdefault(v, set()).add(url) + result['digests'][url] = digest + return result + +class PyPIJSONLocator(Locator): + """ + This locator uses PyPI's JSON interface. It's very limited in functionality + and probably not worth using. + """ + def __init__(self, url, **kwargs): + super(PyPIJSONLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + url = urljoin(self.base_url, '%s/json' % quote(name)) + try: + resp = self.opener.open(url) + data = resp.read().decode() # for now + d = json.loads(data) + md = Metadata(scheme=self.scheme) + data = d['info'] + md.name = data['name'] + md.version = data['version'] + md.license = data.get('license') + md.keywords = data.get('keywords', []) + md.summary = data.get('summary') + dist = Distribution(md) + dist.locator = self + urls = d['urls'] + result[md.version] = dist + for info in d['urls']: + url = info['url'] + dist.download_urls.add(url) + dist.digests[url] = self._get_digest(info) + result['urls'].setdefault(md.version, set()).add(url) + result['digests'][url] = self._get_digest(info) + # Now get other releases + for version, infos in d['releases'].items(): + if version == md.version: + continue # already done + omd = Metadata(scheme=self.scheme) + omd.name = md.name + omd.version = version + odist = Distribution(omd) + odist.locator = self + result[version] = odist + for info in infos: + url = info['url'] + odist.download_urls.add(url) + odist.digests[url] = self._get_digest(info) + result['urls'].setdefault(version, set()).add(url) + result['digests'][url] = self._get_digest(info) +# for info in urls: +# md.source_url = info['url'] +# dist.digest = self._get_digest(info) +# dist.locator = self +# for info in urls: +# url = info['url'] +# result['urls'].setdefault(md.version, set()).add(url) +# result['digests'][url] = self._get_digest(info) + except Exception as e: + self.errors.put(text_type(e)) + logger.exception('JSON fetch failed: %s', e) + return result + + +class Page(object): + """ + This class represents a scraped HTML page. + """ + # The following slightly hairy-looking regex just looks for the contents of + # an anchor link, which has an attribute "href" either immediately preceded + # or immediately followed by a "rel" attribute. The attribute values can be + # declared with double quotes, single quotes or no quotes - which leads to + # the length of the expression. + _href = re.compile(""" +(rel\\s*=\\s*(?:"(?P<rel1>[^"]*)"|'(?P<rel2>[^']*)'|(?P<rel3>[^>\\s\n]*))\\s+)? +href\\s*=\\s*(?:"(?P<url1>[^"]*)"|'(?P<url2>[^']*)'|(?P<url3>[^>\\s\n]*)) +(\\s+rel\\s*=\\s*(?:"(?P<rel4>[^"]*)"|'(?P<rel5>[^']*)'|(?P<rel6>[^>\\s\n]*)))? +""", re.I | re.S | re.X) + _base = re.compile(r"""<base\s+href\s*=\s*['"]?([^'">]+)""", re.I | re.S) + + def __init__(self, data, url): + """ + Initialise an instance with the Unicode page contents and the URL they + came from. + """ + self.data = data + self.base_url = self.url = url + m = self._base.search(self.data) + if m: + self.base_url = m.group(1) + + _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) + + @cached_property + def links(self): + """ + Return the URLs of all the links on a page together with information + about their "rel" attribute, for determining which ones to treat as + downloads and which ones to queue for further scraping. + """ + def clean(url): + "Tidy up an URL." + scheme, netloc, path, params, query, frag = urlparse(url) + return urlunparse((scheme, netloc, quote(path), + params, query, frag)) + + result = set() + for match in self._href.finditer(self.data): + d = match.groupdict('') + rel = (d['rel1'] or d['rel2'] or d['rel3'] or + d['rel4'] or d['rel5'] or d['rel6']) + url = d['url1'] or d['url2'] or d['url3'] + url = urljoin(self.base_url, url) + url = unescape(url) + url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url) + result.add((url, rel)) + # We sort the result, hoping to bring the most recent versions + # to the front + result = sorted(result, key=lambda t: t[0], reverse=True) + return result + + +class SimpleScrapingLocator(Locator): + """ + A locator which scrapes HTML pages to locate downloads for a distribution. + This runs multiple threads to do the I/O; performance is at least as good + as pip's PackageFinder, which works in an analogous fashion. + """ + + # These are used to deal with various Content-Encoding schemes. + decoders = { + 'deflate': zlib.decompress, + 'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(d)).read(), + 'none': lambda b: b, + } + + def __init__(self, url, timeout=None, num_workers=10, **kwargs): + """ + Initialise an instance. + :param url: The root URL to use for scraping. + :param timeout: The timeout, in seconds, to be applied to requests. + This defaults to ``None`` (no timeout specified). + :param num_workers: The number of worker threads you want to do I/O, + This defaults to 10. + :param kwargs: Passed to the superclass. + """ + super(SimpleScrapingLocator, self).__init__(**kwargs) + self.base_url = ensure_slash(url) + self.timeout = timeout + self._page_cache = {} + self._seen = set() + self._to_fetch = queue.Queue() + self._bad_hosts = set() + self.skip_externals = False + self.num_workers = num_workers + self._lock = threading.RLock() + # See issue #45: we need to be resilient when the locator is used + # in a thread, e.g. with concurrent.futures. We can't use self._lock + # as it is for coordinating our internal threads - the ones created + # in _prepare_threads. + self._gplock = threading.RLock() + + def _prepare_threads(self): + """ + Threads are created only when get_project is called, and terminate + before it returns. They are there primarily to parallelise I/O (i.e. + fetching web pages). + """ + self._threads = [] + for i in range(self.num_workers): + t = threading.Thread(target=self._fetch) + t.setDaemon(True) + t.start() + self._threads.append(t) + + def _wait_threads(self): + """ + Tell all the threads to terminate (by sending a sentinel value) and + wait for them to do so. + """ + # Note that you need two loops, since you can't say which + # thread will get each sentinel + for t in self._threads: + self._to_fetch.put(None) # sentinel + for t in self._threads: + t.join() + self._threads = [] + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + with self._gplock: + self.result = result + self.project_name = name + url = urljoin(self.base_url, '%s/' % quote(name)) + self._seen.clear() + self._page_cache.clear() + self._prepare_threads() + try: + logger.debug('Queueing %s', url) + self._to_fetch.put(url) + self._to_fetch.join() + finally: + self._wait_threads() + del self.result + return result + + platform_dependent = re.compile(r'\b(linux-(i\d86|x86_64|arm\w+)|' + r'win(32|-amd64)|macosx-?\d+)\b', re.I) + + def _is_platform_dependent(self, url): + """ + Does an URL refer to a platform-specific download? + """ + return self.platform_dependent.search(url) + + def _process_download(self, url): + """ + See if an URL is a suitable download for a project. + + If it is, register information in the result dictionary (for + _get_project) about the specific version it's for. + + Note that the return value isn't actually used other than as a boolean + value. + """ + if self._is_platform_dependent(url): + info = None + else: + info = self.convert_url_to_download_info(url, self.project_name) + logger.debug('process_download: %s -> %s', url, info) + if info: + with self._lock: # needed because self.result is shared + self._update_version_data(self.result, info) + return info + + def _should_queue(self, link, referrer, rel): + """ + Determine whether a link URL from a referring page and with a + particular "rel" attribute should be queued for scraping. + """ + scheme, netloc, path, _, _, _ = urlparse(link) + if path.endswith(self.source_extensions + self.binary_extensions + + self.excluded_extensions): + result = False + elif self.skip_externals and not link.startswith(self.base_url): + result = False + elif not referrer.startswith(self.base_url): + result = False + elif rel not in ('homepage', 'download'): + result = False + elif scheme not in ('http', 'https', 'ftp'): + result = False + elif self._is_platform_dependent(link): + result = False + else: + host = netloc.split(':', 1)[0] + if host.lower() == 'localhost': + result = False + else: + result = True + logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, + referrer, result) + return result + + def _fetch(self): + """ + Get a URL to fetch from the work queue, get the HTML page, examine its + links for download candidates and candidates for further scraping. + + This is a handy method to run in a thread. + """ + while True: + url = self._to_fetch.get() + try: + if url: + page = self.get_page(url) + if page is None: # e.g. after an error + continue + for link, rel in page.links: + if link not in self._seen: + try: + self._seen.add(link) + if (not self._process_download(link) and + self._should_queue(link, url, rel)): + logger.debug('Queueing %s from %s', link, url) + self._to_fetch.put(link) + except MetadataInvalidError: # e.g. invalid versions + pass + except Exception as e: # pragma: no cover + self.errors.put(text_type(e)) + finally: + # always do this, to avoid hangs :-) + self._to_fetch.task_done() + if not url: + #logger.debug('Sentinel seen, quitting.') + break + + def get_page(self, url): + """ + Get the HTML for an URL, possibly from an in-memory cache. + + XXX TODO Note: this cache is never actually cleared. It's assumed that + the data won't get stale over the lifetime of a locator instance (not + necessarily true for the default_locator). + """ + # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api + scheme, netloc, path, _, _, _ = urlparse(url) + if scheme == 'file' and os.path.isdir(url2pathname(path)): + url = urljoin(ensure_slash(url), 'index.html') + + if url in self._page_cache: + result = self._page_cache[url] + logger.debug('Returning %s from cache: %s', url, result) + else: + host = netloc.split(':', 1)[0] + result = None + if host in self._bad_hosts: + logger.debug('Skipping %s due to bad host %s', url, host) + else: + req = Request(url, headers={'Accept-encoding': 'identity'}) + try: + logger.debug('Fetching %s', url) + resp = self.opener.open(req, timeout=self.timeout) + logger.debug('Fetched %s', url) + headers = resp.info() + content_type = headers.get('Content-Type', '') + if HTML_CONTENT_TYPE.match(content_type): + final_url = resp.geturl() + data = resp.read() + encoding = headers.get('Content-Encoding') + if encoding: + decoder = self.decoders[encoding] # fail if not found + data = decoder(data) + encoding = 'utf-8' + m = CHARSET.search(content_type) + if m: + encoding = m.group(1) + try: + data = data.decode(encoding) + except UnicodeError: # pragma: no cover + data = data.decode('latin-1') # fallback + result = Page(data, final_url) + self._page_cache[final_url] = result + except HTTPError as e: + if e.code != 404: + logger.exception('Fetch failed: %s: %s', url, e) + except URLError as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + with self._lock: + self._bad_hosts.add(host) + except Exception as e: # pragma: no cover + logger.exception('Fetch failed: %s: %s', url, e) + finally: + self._page_cache[url] = result # even if None (failure) + return result + + _distname_re = re.compile('<a href=[^>]*>([^<]+)<') + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + page = self.get_page(self.base_url) + if not page: + raise DistlibException('Unable to get %s' % self.base_url) + for match in self._distname_re.finditer(page.data): + result.add(match.group(1)) + return result + +class DirectoryLocator(Locator): + """ + This class locates distributions in a directory tree. + """ + + def __init__(self, path, **kwargs): + """ + Initialise an instance. + :param path: The root of the directory tree to search. + :param kwargs: Passed to the superclass constructor, + except for: + * recursive - if True (the default), subdirectories are + recursed into. If False, only the top-level directory + is searched, + """ + self.recursive = kwargs.pop('recursive', True) + super(DirectoryLocator, self).__init__(**kwargs) + path = os.path.abspath(path) + if not os.path.isdir(path): # pragma: no cover + raise DistlibException('Not a directory: %r' % path) + self.base_dir = path + + def should_include(self, filename, parent): + """ + Should a filename be considered as a candidate for a distribution + archive? As well as the filename, the directory which contains it + is provided, though not used by the current implementation. + """ + return filename.endswith(self.downloadable_extensions) + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', + pathname2url(os.path.abspath(fn)), + '', '', '')) + info = self.convert_url_to_download_info(url, name) + if info: + self._update_version_data(result, info) + if not self.recursive: + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for root, dirs, files in os.walk(self.base_dir): + for fn in files: + if self.should_include(fn, root): + fn = os.path.join(root, fn) + url = urlunparse(('file', '', + pathname2url(os.path.abspath(fn)), + '', '', '')) + info = self.convert_url_to_download_info(url, None) + if info: + result.add(info['name']) + if not self.recursive: + break + return result + +class JSONLocator(Locator): + """ + This locator uses special extended metadata (not available on PyPI) and is + the basis of performant dependency resolution in distlib. Other locators + require archive downloads before dependencies can be determined! As you + might imagine, that can be slow. + """ + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + raise NotImplementedError('Not available from this locator') + + def _get_project(self, name): + result = {'urls': {}, 'digests': {}} + data = get_project_data(name) + if data: + for info in data.get('files', []): + if info['ptype'] != 'sdist' or info['pyversion'] != 'source': + continue + # We don't store summary in project metadata as it makes + # the data bigger for no benefit during dependency + # resolution + dist = make_dist(data['name'], info['version'], + summary=data.get('summary', + 'Placeholder for summary'), + scheme=self.scheme) + md = dist.metadata + md.source_url = info['url'] + # TODO SHA256 digest + if 'digest' in info and info['digest']: + dist.digest = ('md5', info['digest']) + md.dependencies = info.get('requirements', {}) + dist.exports = info.get('exports', {}) + result[dist.version] = dist + result['urls'].setdefault(dist.version, set()).add(info['url']) + return result + +class DistPathLocator(Locator): + """ + This locator finds installed distributions in a path. It can be useful for + adding to an :class:`AggregatingLocator`. + """ + def __init__(self, distpath, **kwargs): + """ + Initialise an instance. + + :param distpath: A :class:`DistributionPath` instance to search. + """ + super(DistPathLocator, self).__init__(**kwargs) + assert isinstance(distpath, DistributionPath) + self.distpath = distpath + + def _get_project(self, name): + dist = self.distpath.get_distribution(name) + if dist is None: + result = {'urls': {}, 'digests': {}} + else: + result = { + dist.version: dist, + 'urls': {dist.version: set([dist.source_url])}, + 'digests': {dist.version: set([None])} + } + return result + + +class AggregatingLocator(Locator): + """ + This class allows you to chain and/or merge a list of locators. + """ + def __init__(self, *locators, **kwargs): + """ + Initialise an instance. + + :param locators: The list of locators to search. + :param kwargs: Passed to the superclass constructor, + except for: + * merge - if False (the default), the first successful + search from any of the locators is returned. If True, + the results from all locators are merged (this can be + slow). + """ + self.merge = kwargs.pop('merge', False) + self.locators = locators + super(AggregatingLocator, self).__init__(**kwargs) + + def clear_cache(self): + super(AggregatingLocator, self).clear_cache() + for locator in self.locators: + locator.clear_cache() + + def _set_scheme(self, value): + self._scheme = value + for locator in self.locators: + locator.scheme = value + + scheme = property(Locator.scheme.fget, _set_scheme) + + def _get_project(self, name): + result = {} + for locator in self.locators: + d = locator.get_project(name) + if d: + if self.merge: + files = result.get('urls', {}) + digests = result.get('digests', {}) + # next line could overwrite result['urls'], result['digests'] + result.update(d) + df = result.get('urls') + if files and df: + for k, v in files.items(): + if k in df: + df[k] |= v + else: + df[k] = v + dd = result.get('digests') + if digests and dd: + dd.update(digests) + else: + # See issue #18. If any dists are found and we're looking + # for specific constraints, we only return something if + # a match is found. For example, if a DirectoryLocator + # returns just foo (1.0) while we're looking for + # foo (>= 2.0), we'll pretend there was nothing there so + # that subsequent locators can be queried. Otherwise we + # would just return foo (1.0) which would then lead to a + # failure to find foo (>= 2.0), because other locators + # weren't searched. Note that this only matters when + # merge=False. + if self.matcher is None: + found = True + else: + found = False + for k in d: + if self.matcher.match(k): + found = True + break + if found: + result = d + break + return result + + def get_distribution_names(self): + """ + Return all the distribution names known to this locator. + """ + result = set() + for locator in self.locators: + try: + result |= locator.get_distribution_names() + except NotImplementedError: + pass + return result + + +# We use a legacy scheme simply because most of the dists on PyPI use legacy +# versions which don't conform to PEP 426 / PEP 440. +default_locator = AggregatingLocator( + JSONLocator(), + SimpleScrapingLocator('https://pypi.python.org/simple/', + timeout=3.0), + scheme='legacy') + +locate = default_locator.locate + +NAME_VERSION_RE = re.compile(r'(?P<name>[\w-]+)\s*' + r'\(\s*(==\s*)?(?P<ver>[^)]+)\)$') + +class DependencyFinder(object): + """ + Locate dependencies for distributions. + """ + + def __init__(self, locator=None): + """ + Initialise an instance, using the specified locator + to locate distributions. + """ + self.locator = locator or default_locator + self.scheme = get_scheme(self.locator.scheme) + + def add_distribution(self, dist): + """ + Add a distribution to the finder. This will update internal information + about who provides what. + :param dist: The distribution to add. + """ + logger.debug('adding distribution %s', dist) + name = dist.key + self.dists_by_name[name] = dist + self.dists[(name, dist.version)] = dist + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Add to provided: %s, %s, %s', name, version, dist) + self.provided.setdefault(name, set()).add((version, dist)) + + def remove_distribution(self, dist): + """ + Remove a distribution from the finder. This will update internal + information about who provides what. + :param dist: The distribution to remove. + """ + logger.debug('removing distribution %s', dist) + name = dist.key + del self.dists_by_name[name] + del self.dists[(name, dist.version)] + for p in dist.provides: + name, version = parse_name_and_version(p) + logger.debug('Remove from provided: %s, %s, %s', name, version, dist) + s = self.provided[name] + s.remove((version, dist)) + if not s: + del self.provided[name] + + def get_matcher(self, reqt): + """ + Get a version matcher for a requirement. + :param reqt: The requirement + :type reqt: str + :return: A version matcher (an instance of + :class:`distlib.version.Matcher`). + """ + try: + matcher = self.scheme.matcher(reqt) + except UnsupportedVersionError: # pragma: no cover + # XXX compat-mode if cannot read the version + name = reqt.split()[0] + matcher = self.scheme.matcher(name) + return matcher + + def find_providers(self, reqt): + """ + Find the distributions which can fulfill a requirement. + + :param reqt: The requirement. + :type reqt: str + :return: A set of distribution which can fulfill the requirement. + """ + matcher = self.get_matcher(reqt) + name = matcher.key # case-insensitive + result = set() + provided = self.provided + if name in provided: + for version, provider in provided[name]: + try: + match = matcher.match(version) + except UnsupportedVersionError: + match = False + + if match: + result.add(provider) + break + return result + + def try_to_replace(self, provider, other, problems): + """ + Attempt to replace one provider with another. This is typically used + when resolving dependencies from multiple sources, e.g. A requires + (B >= 1.0) while C requires (B >= 1.1). + + For successful replacement, ``provider`` must meet all the requirements + which ``other`` fulfills. + + :param provider: The provider we are trying to replace with. + :param other: The provider we're trying to replace. + :param problems: If False is returned, this will contain what + problems prevented replacement. This is currently + a tuple of the literal string 'cantreplace', + ``provider``, ``other`` and the set of requirements + that ``provider`` couldn't fulfill. + :return: True if we can replace ``other`` with ``provider``, else + False. + """ + rlist = self.reqts[other] + unmatched = set() + for s in rlist: + matcher = self.get_matcher(s) + if not matcher.match(provider.version): + unmatched.add(s) + if unmatched: + # can't replace other with provider + problems.add(('cantreplace', provider, other, + frozenset(unmatched))) + result = False + else: + # can replace other with provider + self.remove_distribution(other) + del self.reqts[other] + for s in rlist: + self.reqts.setdefault(provider, set()).add(s) + self.add_distribution(provider) + result = True + return result + + def find(self, requirement, meta_extras=None, prereleases=False): + """ + Find a distribution and all distributions it depends on. + + :param requirement: The requirement specifying the distribution to + find, or a Distribution instance. + :param meta_extras: A list of meta extras such as :test:, :build: and + so on. + :param prereleases: If ``True``, allow pre-release versions to be + returned - otherwise, don't return prereleases + unless they're all that's available. + + Return a set of :class:`Distribution` instances and a set of + problems. + + The distributions returned should be such that they have the + :attr:`required` attribute set to ``True`` if they were + from the ``requirement`` passed to ``find()``, and they have the + :attr:`build_time_dependency` attribute set to ``True`` unless they + are post-installation dependencies of the ``requirement``. + + The problems should be a tuple consisting of the string + ``'unsatisfied'`` and the requirement which couldn't be satisfied + by any distribution known to the locator. + """ + + self.provided = {} + self.dists = {} + self.dists_by_name = {} + self.reqts = {} + + meta_extras = set(meta_extras or []) + if ':*:' in meta_extras: + meta_extras.remove(':*:') + # :meta: and :run: are implicitly included + meta_extras |= set([':test:', ':build:', ':dev:']) + + if isinstance(requirement, Distribution): + dist = odist = requirement + logger.debug('passed %s as requirement', odist) + else: + dist = odist = self.locator.locate(requirement, + prereleases=prereleases) + if dist is None: + raise DistlibException('Unable to locate %r' % requirement) + logger.debug('located %s', odist) + dist.requested = True + problems = set() + todo = set([dist]) + install_dists = set([odist]) + while todo: + dist = todo.pop() + name = dist.key # case-insensitive + if name not in self.dists_by_name: + self.add_distribution(dist) + else: + #import pdb; pdb.set_trace() + other = self.dists_by_name[name] + if other != dist: + self.try_to_replace(dist, other, problems) + + ireqts = dist.run_requires | dist.meta_requires + sreqts = dist.build_requires + ereqts = set() + if meta_extras and dist in install_dists: + for key in ('test', 'build', 'dev'): + e = ':%s:' % key + if e in meta_extras: + ereqts |= getattr(dist, '%s_requires' % key) + all_reqts = ireqts | sreqts | ereqts + for r in all_reqts: + providers = self.find_providers(r) + if not providers: + logger.debug('No providers found for %r', r) + provider = self.locator.locate(r, prereleases=prereleases) + # If no provider is found and we didn't consider + # prereleases, consider them now. + if provider is None and not prereleases: + provider = self.locator.locate(r, prereleases=True) + if provider is None: + logger.debug('Cannot satisfy %r', r) + problems.add(('unsatisfied', r)) + else: + n, v = provider.key, provider.version + if (n, v) not in self.dists: + todo.add(provider) + providers.add(provider) + if r in ireqts and dist in install_dists: + install_dists.add(provider) + logger.debug('Adding %s to install_dists', + provider.name_and_version) + for p in providers: + name = p.key + if name not in self.dists_by_name: + self.reqts.setdefault(p, set()).add(r) + else: + other = self.dists_by_name[name] + if other != p: + # see if other can be replaced by p + self.try_to_replace(p, other, problems) + + dists = set(self.dists.values()) + for dist in dists: + dist.build_time_dependency = dist not in install_dists + if dist.build_time_dependency: + logger.debug('%s is a build-time dependency only.', + dist.name_and_version) + logger.debug('find done for %s', odist) + return dists, problems diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py new file mode 100755 index 0000000..92688d0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/manifest.py @@ -0,0 +1,393 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Class representing the list of files in a distribution. + +Equivalent to distutils.filelist, but fixes some problems. +""" +import fnmatch +import logging +import os +import re +import sys + +from . import DistlibException +from .compat import fsdecode +from .util import convert_path + + +__all__ = ['Manifest'] + +logger = logging.getLogger(__name__) + +# a \ followed by some spaces + EOL +_COLLAPSE_PATTERN = re.compile('\\\\w*\n', re.M) +_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) + +# +# Due to the different results returned by fnmatch.translate, we need +# to do slightly different processing for Python 2.7 and 3.2 ... this needed +# to be brought in for Python 3.6 onwards. +# +_PYTHON_VERSION = sys.version_info[:2] + +class Manifest(object): + """A list of files built by on exploring the filesystem and filtered by + applying various patterns to what we find there. + """ + + def __init__(self, base=None): + """ + Initialise an instance. + + :param base: The base directory to explore under. + """ + self.base = os.path.abspath(os.path.normpath(base or os.getcwd())) + self.prefix = self.base + os.sep + self.allfiles = None + self.files = set() + + # + # Public API + # + + def findall(self): + """Find all files under the base and set ``allfiles`` to the absolute + pathnames of files found. + """ + from stat import S_ISREG, S_ISDIR, S_ISLNK + + self.allfiles = allfiles = [] + root = self.base + stack = [root] + pop = stack.pop + push = stack.append + + while stack: + root = pop() + names = os.listdir(root) + + for name in names: + fullname = os.path.join(root, name) + + # Avoid excess stat calls -- just one will do, thank you! + stat = os.stat(fullname) + mode = stat.st_mode + if S_ISREG(mode): + allfiles.append(fsdecode(fullname)) + elif S_ISDIR(mode) and not S_ISLNK(mode): + push(fullname) + + def add(self, item): + """ + Add a file to the manifest. + + :param item: The pathname to add. This can be relative to the base. + """ + if not item.startswith(self.prefix): + item = os.path.join(self.base, item) + self.files.add(os.path.normpath(item)) + + def add_many(self, items): + """ + Add a list of files to the manifest. + + :param items: The pathnames to add. These can be relative to the base. + """ + for item in items: + self.add(item) + + def sorted(self, wantdirs=False): + """ + Return sorted files in directory order + """ + + def add_dir(dirs, d): + dirs.add(d) + logger.debug('add_dir added %s', d) + if d != self.base: + parent, _ = os.path.split(d) + assert parent not in ('', '/') + add_dir(dirs, parent) + + result = set(self.files) # make a copy! + if wantdirs: + dirs = set() + for f in result: + add_dir(dirs, os.path.dirname(f)) + result |= dirs + return [os.path.join(*path_tuple) for path_tuple in + sorted(os.path.split(path) for path in result)] + + def clear(self): + """Clear all collected files.""" + self.files = set() + self.allfiles = [] + + def process_directive(self, directive): + """ + Process a directive which either adds some files from ``allfiles`` to + ``files``, or removes some files from ``files``. + + :param directive: The directive to process. This should be in a format + compatible with distutils ``MANIFEST.in`` files: + + http://docs.python.org/distutils/sourcedist.html#commands + """ + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dirpattern). + action, patterns, thedir, dirpattern = self._parse_directive(directive) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=True): + logger.warning('no files found matching %r', pattern) + + elif action == 'exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, anchor=True) + #if not found: + # logger.warning('no previously-included files ' + # 'found matching %r', pattern) + + elif action == 'global-include': + for pattern in patterns: + if not self._include_pattern(pattern, anchor=False): + logger.warning('no files found matching %r ' + 'anywhere in distribution', pattern) + + elif action == 'global-exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, anchor=False) + #if not found: + # logger.warning('no previously-included files ' + # 'matching %r found anywhere in ' + # 'distribution', pattern) + + elif action == 'recursive-include': + for pattern in patterns: + if not self._include_pattern(pattern, prefix=thedir): + logger.warning('no files found matching %r ' + 'under directory %r', pattern, thedir) + + elif action == 'recursive-exclude': + for pattern in patterns: + found = self._exclude_pattern(pattern, prefix=thedir) + #if not found: + # logger.warning('no previously-included files ' + # 'matching %r found under directory %r', + # pattern, thedir) + + elif action == 'graft': + if not self._include_pattern(None, prefix=dirpattern): + logger.warning('no directories found matching %r', + dirpattern) + + elif action == 'prune': + if not self._exclude_pattern(None, prefix=dirpattern): + logger.warning('no previously-included directories found ' + 'matching %r', dirpattern) + else: # pragma: no cover + # This should never happen, as it should be caught in + # _parse_template_line + raise DistlibException( + 'invalid action %r' % action) + + # + # Private API + # + + def _parse_directive(self, directive): + """ + Validate a directive. + :param directive: The directive to validate. + :return: A tuple of action, patterns, thedir, dir_patterns + """ + words = directive.split() + if len(words) == 1 and words[0] not in ('include', 'exclude', + 'global-include', + 'global-exclude', + 'recursive-include', + 'recursive-exclude', + 'graft', 'prune'): + # no action given, let's use the default 'include' + words.insert(0, 'include') + + action = words[0] + patterns = thedir = dir_pattern = None + + if action in ('include', 'exclude', + 'global-include', 'global-exclude'): + if len(words) < 2: + raise DistlibException( + '%r expects <pattern1> <pattern2> ...' % action) + + patterns = [convert_path(word) for word in words[1:]] + + elif action in ('recursive-include', 'recursive-exclude'): + if len(words) < 3: + raise DistlibException( + '%r expects <dir> <pattern1> <pattern2> ...' % action) + + thedir = convert_path(words[1]) + patterns = [convert_path(word) for word in words[2:]] + + elif action in ('graft', 'prune'): + if len(words) != 2: + raise DistlibException( + '%r expects a single <dir_pattern>' % action) + + dir_pattern = convert_path(words[1]) + + else: + raise DistlibException('unknown action %r' % action) + + return action, patterns, thedir, dir_pattern + + def _include_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Select strings (presumably filenames) from 'self.files' that + match 'pattern', a Unix-style wildcard (glob) pattern. + + Patterns are not quite the same as implemented by the 'fnmatch' + module: '*' and '?' match non-special characters, where "special" + is platform-dependent: slash on Unix; colon, slash, and backslash on + DOS/Windows; and colon on Mac OS. + + If 'anchor' is true (the default), then the pattern match is more + stringent: "*.py" will match "foo.py" but not "foo/bar.py". If + 'anchor' is false, both of these will match. + + If 'prefix' is supplied, then only filenames starting with 'prefix' + (itself a pattern) and ending with 'pattern', with anything in between + them, will match. 'anchor' is ignored in this case. + + If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and + 'pattern' is assumed to be either a string containing a regex or a + regex object -- no translation is done, the regex is just compiled + and used as-is. + + Selected strings will be added to self.files. + + Return True if files are found. + """ + # XXX docstring lying about what the special chars are? + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + + # delayed loading of allfiles list + if self.allfiles is None: + self.findall() + + for name in self.allfiles: + if pattern_re.search(name): + self.files.add(name) + found = True + return found + + def _exclude_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Remove strings (presumably filenames) from 'files' that match + 'pattern'. + + Other parameters are the same as for 'include_pattern()', above. + The list 'self.files' is modified in place. Return True if files are + found. + + This API is public to allow e.g. exclusion of SCM subdirs, e.g. when + packaging source distributions + """ + found = False + pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) + for f in list(self.files): + if pattern_re.search(f): + self.files.remove(f) + found = True + return found + + def _translate_pattern(self, pattern, anchor=True, prefix=None, + is_regex=False): + """Translate a shell-like wildcard pattern to a compiled regular + expression. + + Return the compiled regex. If 'is_regex' true, + then 'pattern' is directly compiled to a regex (if it's a string) + or just returned as-is (assumes it's a regex object). + """ + if is_regex: + if isinstance(pattern, str): + return re.compile(pattern) + else: + return pattern + + if _PYTHON_VERSION > (3, 2): + # ditch start and end characters + start, _, end = self._glob_to_re('_').partition('_') + + if pattern: + pattern_re = self._glob_to_re(pattern) + if _PYTHON_VERSION > (3, 2): + assert pattern_re.startswith(start) and pattern_re.endswith(end) + else: + pattern_re = '' + + base = re.escape(os.path.join(self.base, '')) + if prefix is not None: + # ditch end of pattern character + if _PYTHON_VERSION <= (3, 2): + empty_pattern = self._glob_to_re('') + prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)] + else: + prefix_re = self._glob_to_re(prefix) + assert prefix_re.startswith(start) and prefix_re.endswith(end) + prefix_re = prefix_re[len(start): len(prefix_re) - len(end)] + sep = os.sep + if os.sep == '\\': + sep = r'\\' + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + sep.join((prefix_re, + '.*' + pattern_re)) + else: + pattern_re = pattern_re[len(start): len(pattern_re) - len(end)] + pattern_re = r'%s%s%s%s.*%s%s' % (start, base, prefix_re, sep, + pattern_re, end) + else: # no prefix -- respect anchor flag + if anchor: + if _PYTHON_VERSION <= (3, 2): + pattern_re = '^' + base + pattern_re + else: + pattern_re = r'%s%s%s' % (start, base, pattern_re[len(start):]) + + return re.compile(pattern_re) + + def _glob_to_re(self, pattern): + """Translate a shell-like glob pattern to a regular expression. + + Return a string containing the regex. Differs from + 'fnmatch.translate()' in that '*' does not match "special characters" + (which are platform-specific). + """ + pattern_re = fnmatch.translate(pattern) + + # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which + # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, + # and by extension they shouldn't match such "special characters" under + # any OS. So change all non-escaped dots in the RE to match any + # character except the special characters (currently: just os.sep). + sep = os.sep + if os.sep == '\\': + # we're using a regex to manipulate a regex, so we need + # to escape the backslash twice + sep = r'\\\\' + escaped = r'\1[^%s]' % sep + pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', escaped, pattern_re) + return pattern_re diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py new file mode 100755 index 0000000..82fcfb8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/markers.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Parser for the environment markers micro-language defined in PEP 508. +""" + +# Note: In PEP 345, the micro-language was Python compatible, so the ast +# module could be used to parse it. However, PEP 508 introduced operators such +# as ~= and === which aren't in Python, necessitating a different approach. + +import os +import sys +import platform +import re + +from .compat import python_implementation, urlparse, string_types +from .util import in_venv, parse_marker + +__all__ = ['interpret'] + +def _is_literal(o): + if not isinstance(o, string_types) or not o: + return False + return o[0] in '\'"' + +class Evaluator(object): + """ + This class is used to evaluate marker expessions. + """ + + operations = { + '==': lambda x, y: x == y, + '===': lambda x, y: x == y, + '~=': lambda x, y: x == y or x > y, + '!=': lambda x, y: x != y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x == y or x < y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x == y or x > y, + 'and': lambda x, y: x and y, + 'or': lambda x, y: x or y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y, + } + + def evaluate(self, expr, context): + """ + Evaluate a marker expression returned by the :func:`parse_requirement` + function in the specified context. + """ + if isinstance(expr, string_types): + if expr[0] in '\'"': + result = expr[1:-1] + else: + if expr not in context: + raise SyntaxError('unknown variable: %s' % expr) + result = context[expr] + else: + assert isinstance(expr, dict) + op = expr['op'] + if op not in self.operations: + raise NotImplementedError('op not implemented: %s' % op) + elhs = expr['lhs'] + erhs = expr['rhs'] + if _is_literal(expr['lhs']) and _is_literal(expr['rhs']): + raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs)) + + lhs = self.evaluate(elhs, context) + rhs = self.evaluate(erhs, context) + result = self.operations[op](lhs, rhs) + return result + +def default_context(): + def format_full_version(info): + version = '%s.%s.%s' % (info.major, info.minor, info.micro) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + if hasattr(sys, 'implementation'): + implementation_version = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + implementation_version = '0' + implementation_name = '' + + result = { + 'implementation_name': implementation_name, + 'implementation_version': implementation_version, + 'os_name': os.name, + 'platform_machine': platform.machine(), + 'platform_python_implementation': platform.python_implementation(), + 'platform_release': platform.release(), + 'platform_system': platform.system(), + 'platform_version': platform.version(), + 'platform_in_venv': str(in_venv()), + 'python_full_version': platform.python_version(), + 'python_version': platform.python_version()[:3], + 'sys_platform': sys.platform, + } + return result + +DEFAULT_CONTEXT = default_context() +del default_context + +evaluator = Evaluator() + +def interpret(marker, execution_context=None): + """ + Interpret a marker and return a result depending on environment. + + :param marker: The marker to interpret. + :type marker: str + :param execution_context: The context used for name lookup. + :type execution_context: mapping + """ + try: + expr, rest = parse_marker(marker) + except Exception as e: + raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e)) + if rest and rest[0] != '#': + raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest)) + context = dict(DEFAULT_CONTEXT) + if execution_context: + context.update(execution_context) + return evaluator.evaluate(expr, context) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py new file mode 100755 index 0000000..10a1fee --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/metadata.py @@ -0,0 +1,1091 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +"""Implementation of the Metadata for Python packages PEPs. + +Supports all metadata formats (1.0, 1.1, 1.2, and 2.0 experimental). +""" +from __future__ import unicode_literals + +import codecs +from email import message_from_file +import json +import logging +import re + + +from . import DistlibException, __version__ +from .compat import StringIO, string_types, text_type +from .markers import interpret +from .util import extract_by_key, get_extras +from .version import get_scheme, PEP440_VERSION_RE + +logger = logging.getLogger(__name__) + + +class MetadataMissingError(DistlibException): + """A required metadata is missing""" + + +class MetadataConflictError(DistlibException): + """Attempt to read or write metadata fields that are conflictual.""" + + +class MetadataUnrecognizedVersionError(DistlibException): + """Unknown metadata version number.""" + + +class MetadataInvalidError(DistlibException): + """A metadata value is invalid""" + +# public API of this module +__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] + +# Encoding used for the PKG-INFO files +PKG_INFO_ENCODING = 'utf-8' + +# preferred version. Hopefully will be changed +# to 1.2 once PEP 345 is supported everywhere +PKG_INFO_PREFERRED_VERSION = '1.1' + +_LINE_PREFIX_1_2 = re.compile('\n \\|') +_LINE_PREFIX_PRE_1_2 = re.compile('\n ') +_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License') + +_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'License', 'Classifier', 'Download-URL', 'Obsoletes', + 'Provides', 'Requires') + +_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', + 'Download-URL') + +_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', + 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External') + +_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', + 'Obsoletes-Dist', 'Requires-External', 'Maintainer', + 'Maintainer-email', 'Project-URL') + +_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', + 'Supported-Platform', 'Summary', 'Description', + 'Keywords', 'Home-page', 'Author', 'Author-email', + 'Maintainer', 'Maintainer-email', 'License', + 'Classifier', 'Download-URL', 'Obsoletes-Dist', + 'Project-URL', 'Provides-Dist', 'Requires-Dist', + 'Requires-Python', 'Requires-External', 'Private-Version', + 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension', + 'Provides-Extra') + +_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', + 'Setup-Requires-Dist', 'Extension') + +_566_FIELDS = _426_FIELDS + ('Description-Content-Type',) + +_566_MARKERS = ('Description-Content-Type',) + +_ALL_FIELDS = set() +_ALL_FIELDS.update(_241_FIELDS) +_ALL_FIELDS.update(_314_FIELDS) +_ALL_FIELDS.update(_345_FIELDS) +_ALL_FIELDS.update(_426_FIELDS) +_ALL_FIELDS.update(_566_FIELDS) + +EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') + + +def _version2fieldlist(version): + if version == '1.0': + return _241_FIELDS + elif version == '1.1': + return _314_FIELDS + elif version == '1.2': + return _345_FIELDS + elif version in ('1.3', '2.1'): + return _345_FIELDS + _566_FIELDS + elif version == '2.0': + return _426_FIELDS + raise MetadataUnrecognizedVersionError(version) + + +def _best_version(fields): + """Detect the best version depending on the fields used.""" + def _has_marker(keys, markers): + for marker in markers: + if marker in keys: + return True + return False + + keys = [] + for key, value in fields.items(): + if value in ([], 'UNKNOWN', None): + continue + keys.append(key) + + possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.0', '2.1'] + + # first let's try to see if a field is not part of one of the version + for key in keys: + if key not in _241_FIELDS and '1.0' in possible_versions: + possible_versions.remove('1.0') + logger.debug('Removed 1.0 due to %s', key) + if key not in _314_FIELDS and '1.1' in possible_versions: + possible_versions.remove('1.1') + logger.debug('Removed 1.1 due to %s', key) + if key not in _345_FIELDS and '1.2' in possible_versions: + possible_versions.remove('1.2') + logger.debug('Removed 1.2 due to %s', key) + if key not in _566_FIELDS and '1.3' in possible_versions: + possible_versions.remove('1.3') + logger.debug('Removed 1.3 due to %s', key) + if key not in _566_FIELDS and '2.1' in possible_versions: + if key != 'Description': # In 2.1, description allowed after headers + possible_versions.remove('2.1') + logger.debug('Removed 2.1 due to %s', key) + if key not in _426_FIELDS and '2.0' in possible_versions: + possible_versions.remove('2.0') + logger.debug('Removed 2.0 due to %s', key) + + # possible_version contains qualified versions + if len(possible_versions) == 1: + return possible_versions[0] # found ! + elif len(possible_versions) == 0: + logger.debug('Out of options - unknown metadata set: %s', fields) + raise MetadataConflictError('Unknown metadata set') + + # let's see if one unique marker is found + is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) + is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) + is_2_1 = '2.1' in possible_versions and _has_marker(keys, _566_MARKERS) + is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) + if int(is_1_1) + int(is_1_2) + int(is_2_1) + int(is_2_0) > 1: + raise MetadataConflictError('You used incompatible 1.1/1.2/2.0/2.1 fields') + + # we have the choice, 1.0, or 1.2, or 2.0 + # - 1.0 has a broken Summary field but works with all tools + # - 1.1 is to avoid + # - 1.2 fixes Summary but has little adoption + # - 2.0 adds more features and is very new + if not is_1_1 and not is_1_2 and not is_2_1 and not is_2_0: + # we couldn't find any specific marker + if PKG_INFO_PREFERRED_VERSION in possible_versions: + return PKG_INFO_PREFERRED_VERSION + if is_1_1: + return '1.1' + if is_1_2: + return '1.2' + if is_2_1: + return '2.1' + + return '2.0' + +_ATTR2FIELD = { + 'metadata_version': 'Metadata-Version', + 'name': 'Name', + 'version': 'Version', + 'platform': 'Platform', + 'supported_platform': 'Supported-Platform', + 'summary': 'Summary', + 'description': 'Description', + 'keywords': 'Keywords', + 'home_page': 'Home-page', + 'author': 'Author', + 'author_email': 'Author-email', + 'maintainer': 'Maintainer', + 'maintainer_email': 'Maintainer-email', + 'license': 'License', + 'classifier': 'Classifier', + 'download_url': 'Download-URL', + 'obsoletes_dist': 'Obsoletes-Dist', + 'provides_dist': 'Provides-Dist', + 'requires_dist': 'Requires-Dist', + 'setup_requires_dist': 'Setup-Requires-Dist', + 'requires_python': 'Requires-Python', + 'requires_external': 'Requires-External', + 'requires': 'Requires', + 'provides': 'Provides', + 'obsoletes': 'Obsoletes', + 'project_url': 'Project-URL', + 'private_version': 'Private-Version', + 'obsoleted_by': 'Obsoleted-By', + 'extension': 'Extension', + 'provides_extra': 'Provides-Extra', +} + +_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') +_VERSIONS_FIELDS = ('Requires-Python',) +_VERSION_FIELDS = ('Version',) +_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', + 'Requires', 'Provides', 'Obsoletes-Dist', + 'Provides-Dist', 'Requires-Dist', 'Requires-External', + 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', + 'Provides-Extra', 'Extension') +_LISTTUPLEFIELDS = ('Project-URL',) + +_ELEMENTSFIELD = ('Keywords',) + +_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') + +_MISSING = object() + +_FILESAFE = re.compile('[^A-Za-z0-9.]+') + + +def _get_name_and_version(name, version, for_filename=False): + """Return the distribution name with version. + + If for_filename is true, return a filename-escaped form.""" + if for_filename: + # For both name and version any runs of non-alphanumeric or '.' + # characters are replaced with a single '-'. Additionally any + # spaces in the version string become '.' + name = _FILESAFE.sub('-', name) + version = _FILESAFE.sub('-', version.replace(' ', '.')) + return '%s-%s' % (name, version) + + +class LegacyMetadata(object): + """The legacy metadata of a release. + + Supports versions 1.0, 1.1 and 1.2 (auto-detected). You can + instantiate the class with one of these arguments (or none): + - *path*, the path to a metadata file + - *fileobj* give a file-like object with metadata as content + - *mapping* is a dict-like object + - *scheme* is a version scheme name + """ + # TODO document the mapping API and UNKNOWN default key + + def __init__(self, path=None, fileobj=None, mapping=None, + scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._fields = {} + self.requires_files = [] + self._dependencies = None + self.scheme = scheme + if path is not None: + self.read(path) + elif fileobj is not None: + self.read_file(fileobj) + elif mapping is not None: + self.update(mapping) + self.set_metadata_version() + + def set_metadata_version(self): + self._fields['Metadata-Version'] = _best_version(self._fields) + + def _write_field(self, fileobj, name, value): + fileobj.write('%s: %s\n' % (name, value)) + + def __getitem__(self, name): + return self.get(name) + + def __setitem__(self, name, value): + return self.set(name, value) + + def __delitem__(self, name): + field_name = self._convert_name(name) + try: + del self._fields[field_name] + except KeyError: + raise KeyError(name) + + def __contains__(self, name): + return (name in self._fields or + self._convert_name(name) in self._fields) + + def _convert_name(self, name): + if name in _ALL_FIELDS: + return name + name = name.replace('-', '_').lower() + return _ATTR2FIELD.get(name, name) + + def _default_value(self, name): + if name in _LISTFIELDS or name in _ELEMENTSFIELD: + return [] + return 'UNKNOWN' + + def _remove_line_prefix(self, value): + if self.metadata_version in ('1.0', '1.1'): + return _LINE_PREFIX_PRE_1_2.sub('\n', value) + else: + return _LINE_PREFIX_1_2.sub('\n', value) + + def __getattr__(self, name): + if name in _ATTR2FIELD: + return self[name] + raise AttributeError(name) + + # + # Public API + # + +# dependencies = property(_get_dependencies, _set_dependencies) + + def get_fullname(self, filesafe=False): + """Return the distribution name with version. + + If filesafe is true, return a filename-escaped form.""" + return _get_name_and_version(self['Name'], self['Version'], filesafe) + + def is_field(self, name): + """return True if name is a valid metadata key""" + name = self._convert_name(name) + return name in _ALL_FIELDS + + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + + def read(self, filepath): + """Read the metadata values from a file path.""" + fp = codecs.open(filepath, 'r', encoding='utf-8') + try: + self.read_file(fp) + finally: + fp.close() + + def read_file(self, fileob): + """Read the metadata values from a file object.""" + msg = message_from_file(fileob) + self._fields['Metadata-Version'] = msg['metadata-version'] + + # When reading, get all the fields we can + for field in _ALL_FIELDS: + if field not in msg: + continue + if field in _LISTFIELDS: + # we can have multiple lines + values = msg.get_all(field) + if field in _LISTTUPLEFIELDS and values is not None: + values = [tuple(value.split(',')) for value in values] + self.set(field, values) + else: + # single line + value = msg[field] + if value is not None and value != 'UNKNOWN': + self.set(field, value) + logger.debug('Attempting to set metadata for %s', self) + self.set_metadata_version() + + def write(self, filepath, skip_unknown=False): + """Write the metadata fields to filepath.""" + fp = codecs.open(filepath, 'w', encoding='utf-8') + try: + self.write_file(fp, skip_unknown) + finally: + fp.close() + + def write_file(self, fileobject, skip_unknown=False): + """Write the PKG-INFO format data to a file object.""" + self.set_metadata_version() + + for field in _version2fieldlist(self['Metadata-Version']): + values = self.get(field) + if skip_unknown and values in ('UNKNOWN', [], ['UNKNOWN']): + continue + if field in _ELEMENTSFIELD: + self._write_field(fileobject, field, ','.join(values)) + continue + if field not in _LISTFIELDS: + if field == 'Description': + if self.metadata_version in ('1.0', '1.1'): + values = values.replace('\n', '\n ') + else: + values = values.replace('\n', '\n |') + values = [values] + + if field in _LISTTUPLEFIELDS: + values = [','.join(value) for value in values] + + for value in values: + self._write_field(fileobject, field, value) + + def update(self, other=None, **kwargs): + """Set metadata values from the given iterable `other` and kwargs. + + Behavior is like `dict.update`: If `other` has a ``keys`` method, + they are looped over and ``self[key]`` is assigned ``other[key]``. + Else, ``other`` is an iterable of ``(key, value)`` iterables. + + Keys that don't match a metadata field or that have an empty value are + dropped. + """ + def _set(key, value): + if key in _ATTR2FIELD and value: + self.set(self._convert_name(key), value) + + if not other: + # other is None or empty container + pass + elif hasattr(other, 'keys'): + for k in other.keys(): + _set(k, other[k]) + else: + for k, v in other: + _set(k, v) + + if kwargs: + for k, v in kwargs.items(): + _set(k, v) + + def set(self, name, value): + """Control then set a metadata field.""" + name = self._convert_name(name) + + if ((name in _ELEMENTSFIELD or name == 'Platform') and + not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [v.strip() for v in value.split(',')] + else: + value = [] + elif (name in _LISTFIELDS and + not isinstance(value, (list, tuple))): + if isinstance(value, string_types): + value = [value] + else: + value = [] + + if logger.isEnabledFor(logging.WARNING): + project_name = self['Name'] + + scheme = get_scheme(self.scheme) + if name in _PREDICATE_FIELDS and value is not None: + for v in value: + # check that the values are valid + if not scheme.is_valid_matcher(v.split(';')[0]): + logger.warning( + "'%s': '%s' is not valid (field '%s')", + project_name, v, name) + # FIXME this rejects UNKNOWN, is that right? + elif name in _VERSIONS_FIELDS and value is not None: + if not scheme.is_valid_constraint_list(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", + project_name, value, name) + elif name in _VERSION_FIELDS and value is not None: + if not scheme.is_valid_version(value): + logger.warning("'%s': '%s' is not a valid version (field '%s')", + project_name, value, name) + + if name in _UNICODEFIELDS: + if name == 'Description': + value = self._remove_line_prefix(value) + + self._fields[name] = value + + def get(self, name, default=_MISSING): + """Get a metadata field.""" + name = self._convert_name(name) + if name not in self._fields: + if default is _MISSING: + default = self._default_value(name) + return default + if name in _UNICODEFIELDS: + value = self._fields[name] + return value + elif name in _LISTFIELDS: + value = self._fields[name] + if value is None: + return [] + res = [] + for val in value: + if name not in _LISTTUPLEFIELDS: + res.append(val) + else: + # That's for Project-URL + res.append((val[0], val[1])) + return res + + elif name in _ELEMENTSFIELD: + value = self._fields[name] + if isinstance(value, string_types): + return value.split(',') + return self._fields[name] + + def check(self, strict=False): + """Check if the metadata is compliant. If strict is True then raise if + no Name or Version are provided""" + self.set_metadata_version() + + # XXX should check the versions (if the file was loaded) + missing, warnings = [], [] + + for attr in ('Name', 'Version'): # required by PEP 345 + if attr not in self: + missing.append(attr) + + if strict and missing != []: + msg = 'missing required metadata: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + + for attr in ('Home-page', 'Author'): + if attr not in self: + missing.append(attr) + + # checking metadata 1.2 (XXX needs to check 1.1, 1.0) + if self['Metadata-Version'] != '1.2': + return missing, warnings + + scheme = get_scheme(self.scheme) + + def are_valid_constraints(value): + for v in value: + if not scheme.is_valid_matcher(v.split(';')[0]): + return False + return True + + for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints), + (_VERSIONS_FIELDS, + scheme.is_valid_constraint_list), + (_VERSION_FIELDS, + scheme.is_valid_version)): + for field in fields: + value = self.get(field, None) + if value is not None and not controller(value): + warnings.append("Wrong value for '%s': %s" % (field, value)) + + return missing, warnings + + def todict(self, skip_missing=False): + """Return fields as a dict. + + Field names will be converted to use the underscore-lowercase style + instead of hyphen-mixed case (i.e. home_page instead of Home-page). + """ + self.set_metadata_version() + + mapping_1_0 = ( + ('metadata_version', 'Metadata-Version'), + ('name', 'Name'), + ('version', 'Version'), + ('summary', 'Summary'), + ('home_page', 'Home-page'), + ('author', 'Author'), + ('author_email', 'Author-email'), + ('license', 'License'), + ('description', 'Description'), + ('keywords', 'Keywords'), + ('platform', 'Platform'), + ('classifiers', 'Classifier'), + ('download_url', 'Download-URL'), + ) + + data = {} + for key, field_name in mapping_1_0: + if not skip_missing or field_name in self._fields: + data[key] = self[field_name] + + if self['Metadata-Version'] == '1.2': + mapping_1_2 = ( + ('requires_dist', 'Requires-Dist'), + ('requires_python', 'Requires-Python'), + ('requires_external', 'Requires-External'), + ('provides_dist', 'Provides-Dist'), + ('obsoletes_dist', 'Obsoletes-Dist'), + ('project_url', 'Project-URL'), + ('maintainer', 'Maintainer'), + ('maintainer_email', 'Maintainer-email'), + ) + for key, field_name in mapping_1_2: + if not skip_missing or field_name in self._fields: + if key != 'project_url': + data[key] = self[field_name] + else: + data[key] = [','.join(u) for u in self[field_name]] + + elif self['Metadata-Version'] == '1.1': + mapping_1_1 = ( + ('provides', 'Provides'), + ('requires', 'Requires'), + ('obsoletes', 'Obsoletes'), + ) + for key, field_name in mapping_1_1: + if not skip_missing or field_name in self._fields: + data[key] = self[field_name] + + return data + + def add_requirements(self, requirements): + if self['Metadata-Version'] == '1.1': + # we can't have 1.1 metadata *and* Setuptools requires + for field in ('Obsoletes', 'Requires', 'Provides'): + if field in self: + del self[field] + self['Requires-Dist'] += requirements + + # Mapping API + # TODO could add iter* variants + + def keys(self): + return list(_version2fieldlist(self['Metadata-Version'])) + + def __iter__(self): + for key in self.keys(): + yield key + + def values(self): + return [self[key] for key in self.keys()] + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def __repr__(self): + return '<%s %s %s>' % (self.__class__.__name__, self.name, + self.version) + + +METADATA_FILENAME = 'pydist.json' +WHEEL_METADATA_FILENAME = 'metadata.json' + + +class Metadata(object): + """ + The metadata of a release. This implementation uses 2.0 (JSON) + metadata where possible. If not possible, it wraps a LegacyMetadata + instance which handles the key-value metadata format. + """ + + METADATA_VERSION_MATCHER = re.compile(r'^\d+(\.\d+)*$') + + NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) + + VERSION_MATCHER = PEP440_VERSION_RE + + SUMMARY_MATCHER = re.compile('.{1,2047}') + + METADATA_VERSION = '2.0' + + GENERATOR = 'distlib (%s)' % __version__ + + MANDATORY_KEYS = { + 'name': (), + 'version': (), + 'summary': ('legacy',), + } + + INDEX_KEYS = ('name version license summary description author ' + 'author_email keywords platform home_page classifiers ' + 'download_url') + + DEPENDENCY_KEYS = ('extras run_requires test_requires build_requires ' + 'dev_requires provides meta_requires obsoleted_by ' + 'supports_environments') + + SYNTAX_VALIDATORS = { + 'metadata_version': (METADATA_VERSION_MATCHER, ()), + 'name': (NAME_MATCHER, ('legacy',)), + 'version': (VERSION_MATCHER, ('legacy',)), + 'summary': (SUMMARY_MATCHER, ('legacy',)), + } + + __slots__ = ('_legacy', '_data', 'scheme') + + def __init__(self, path=None, fileobj=None, mapping=None, + scheme='default'): + if [path, fileobj, mapping].count(None) < 2: + raise TypeError('path, fileobj and mapping are exclusive') + self._legacy = None + self._data = None + self.scheme = scheme + #import pdb; pdb.set_trace() + if mapping is not None: + try: + self._validate_mapping(mapping, scheme) + self._data = mapping + except MetadataUnrecognizedVersionError: + self._legacy = LegacyMetadata(mapping=mapping, scheme=scheme) + self.validate() + else: + data = None + if path: + with open(path, 'rb') as f: + data = f.read() + elif fileobj: + data = fileobj.read() + if data is None: + # Initialised with no args - to be added + self._data = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + else: + if not isinstance(data, text_type): + data = data.decode('utf-8') + try: + self._data = json.loads(data) + self._validate_mapping(self._data, scheme) + except ValueError: + # Note: MetadataUnrecognizedVersionError does not + # inherit from ValueError (it's a DistlibException, + # which should not inherit from ValueError). + # The ValueError comes from the json.load - if that + # succeeds and we get a validation error, we want + # that to propagate + self._legacy = LegacyMetadata(fileobj=StringIO(data), + scheme=scheme) + self.validate() + + common_keys = set(('name', 'version', 'license', 'keywords', 'summary')) + + none_list = (None, list) + none_dict = (None, dict) + + mapped_keys = { + 'run_requires': ('Requires-Dist', list), + 'build_requires': ('Setup-Requires-Dist', list), + 'dev_requires': none_list, + 'test_requires': none_list, + 'meta_requires': none_list, + 'extras': ('Provides-Extra', list), + 'modules': none_list, + 'namespaces': none_list, + 'exports': none_dict, + 'commands': none_dict, + 'classifiers': ('Classifier', list), + 'source_url': ('Download-URL', None), + 'metadata_version': ('Metadata-Version', None), + } + + del none_list, none_dict + + def __getattribute__(self, key): + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, maker = mapped[key] + if self._legacy: + if lk is None: + result = None if maker is None else maker() + else: + result = self._legacy.get(lk) + else: + value = None if maker is None else maker() + if key not in ('commands', 'exports', 'modules', 'namespaces', + 'classifiers'): + result = self._data.get(key, value) + else: + # special cases for PEP 459 + sentinel = object() + result = sentinel + d = self._data.get('extensions') + if d: + if key == 'commands': + result = d.get('python.commands', value) + elif key == 'classifiers': + d = d.get('python.details') + if d: + result = d.get(key, value) + else: + d = d.get('python.exports') + if not d: + d = self._data.get('python.exports') + if d: + result = d.get(key, value) + if result is sentinel: + result = value + elif key not in common: + result = object.__getattribute__(self, key) + elif self._legacy: + result = self._legacy.get(key) + else: + result = self._data.get(key) + return result + + def _validate_value(self, key, value, scheme=None): + if key in self.SYNTAX_VALIDATORS: + pattern, exclusions = self.SYNTAX_VALIDATORS[key] + if (scheme or self.scheme) not in exclusions: + m = pattern.match(value) + if not m: + raise MetadataInvalidError("'%s' is an invalid value for " + "the '%s' property" % (value, + key)) + + def __setattr__(self, key, value): + self._validate_value(key, value) + common = object.__getattribute__(self, 'common_keys') + mapped = object.__getattribute__(self, 'mapped_keys') + if key in mapped: + lk, _ = mapped[key] + if self._legacy: + if lk is None: + raise NotImplementedError + self._legacy[lk] = value + elif key not in ('commands', 'exports', 'modules', 'namespaces', + 'classifiers'): + self._data[key] = value + else: + # special cases for PEP 459 + d = self._data.setdefault('extensions', {}) + if key == 'commands': + d['python.commands'] = value + elif key == 'classifiers': + d = d.setdefault('python.details', {}) + d[key] = value + else: + d = d.setdefault('python.exports', {}) + d[key] = value + elif key not in common: + object.__setattr__(self, key, value) + else: + if key == 'keywords': + if isinstance(value, string_types): + value = value.strip() + if value: + value = value.split() + else: + value = [] + if self._legacy: + self._legacy[key] = value + else: + self._data[key] = value + + @property + def name_and_version(self): + return _get_name_and_version(self.name, self.version, True) + + @property + def provides(self): + if self._legacy: + result = self._legacy['Provides-Dist'] + else: + result = self._data.setdefault('provides', []) + s = '%s (%s)' % (self.name, self.version) + if s not in result: + result.append(s) + return result + + @provides.setter + def provides(self, value): + if self._legacy: + self._legacy['Provides-Dist'] = value + else: + self._data['provides'] = value + + def get_requirements(self, reqts, extras=None, env=None): + """ + Base method to get dependencies, given a set of extras + to satisfy and an optional environment context. + :param reqts: A list of sometimes-wanted dependencies, + perhaps dependent on extras and environment. + :param extras: A list of optional components being requested. + :param env: An optional environment for marker evaluation. + """ + if self._legacy: + result = reqts + else: + result = [] + extras = get_extras(extras or [], self.extras) + for d in reqts: + if 'extra' not in d and 'environment' not in d: + # unconditional + include = True + else: + if 'extra' not in d: + # Not extra-dependent - only environment-dependent + include = True + else: + include = d.get('extra') in extras + if include: + # Not excluded because of extras, check environment + marker = d.get('environment') + if marker: + include = interpret(marker, env) + if include: + result.extend(d['requires']) + for key in ('build', 'dev', 'test'): + e = ':%s:' % key + if e in extras: + extras.remove(e) + # A recursive call, but it should terminate since 'test' + # has been removed from the extras + reqts = self._data.get('%s_requires' % key, []) + result.extend(self.get_requirements(reqts, extras=extras, + env=env)) + return result + + @property + def dictionary(self): + if self._legacy: + return self._from_legacy() + return self._data + + @property + def dependencies(self): + if self._legacy: + raise NotImplementedError + else: + return extract_by_key(self._data, self.DEPENDENCY_KEYS) + + @dependencies.setter + def dependencies(self, value): + if self._legacy: + raise NotImplementedError + else: + self._data.update(value) + + def _validate_mapping(self, mapping, scheme): + if mapping.get('metadata_version') != self.METADATA_VERSION: + raise MetadataUnrecognizedVersionError() + missing = [] + for key, exclusions in self.MANDATORY_KEYS.items(): + if key not in mapping: + if scheme not in exclusions: + missing.append(key) + if missing: + msg = 'Missing metadata items: %s' % ', '.join(missing) + raise MetadataMissingError(msg) + for k, v in mapping.items(): + self._validate_value(k, v, scheme) + + def validate(self): + if self._legacy: + missing, warnings = self._legacy.check(True) + if missing or warnings: + logger.warning('Metadata: missing: %s, warnings: %s', + missing, warnings) + else: + self._validate_mapping(self._data, self.scheme) + + def todict(self): + if self._legacy: + return self._legacy.todict(True) + else: + result = extract_by_key(self._data, self.INDEX_KEYS) + return result + + def _from_legacy(self): + assert self._legacy and not self._data + result = { + 'metadata_version': self.METADATA_VERSION, + 'generator': self.GENERATOR, + } + lmd = self._legacy.todict(True) # skip missing ones + for k in ('name', 'version', 'license', 'summary', 'description', + 'classifier'): + if k in lmd: + if k == 'classifier': + nk = 'classifiers' + else: + nk = k + result[nk] = lmd[k] + kw = lmd.get('Keywords', []) + if kw == ['']: + kw = [] + result['keywords'] = kw + keys = (('requires_dist', 'run_requires'), + ('setup_requires_dist', 'build_requires')) + for ok, nk in keys: + if ok in lmd and lmd[ok]: + result[nk] = [{'requires': lmd[ok]}] + result['provides'] = self.provides + author = {} + maintainer = {} + return result + + LEGACY_MAPPING = { + 'name': 'Name', + 'version': 'Version', + 'license': 'License', + 'summary': 'Summary', + 'description': 'Description', + 'classifiers': 'Classifier', + } + + def _to_legacy(self): + def process_entries(entries): + reqts = set() + for e in entries: + extra = e.get('extra') + env = e.get('environment') + rlist = e['requires'] + for r in rlist: + if not env and not extra: + reqts.add(r) + else: + marker = '' + if extra: + marker = 'extra == "%s"' % extra + if env: + if marker: + marker = '(%s) and %s' % (env, marker) + else: + marker = env + reqts.add(';'.join((r, marker))) + return reqts + + assert self._data and not self._legacy + result = LegacyMetadata() + nmd = self._data + for nk, ok in self.LEGACY_MAPPING.items(): + if nk in nmd: + result[ok] = nmd[nk] + r1 = process_entries(self.run_requires + self.meta_requires) + r2 = process_entries(self.build_requires + self.dev_requires) + if self.extras: + result['Provides-Extra'] = sorted(self.extras) + result['Requires-Dist'] = sorted(r1) + result['Setup-Requires-Dist'] = sorted(r2) + # TODO: other fields such as contacts + return result + + def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True): + if [path, fileobj].count(None) != 1: + raise ValueError('Exactly one of path and fileobj is needed') + self.validate() + if legacy: + if self._legacy: + legacy_md = self._legacy + else: + legacy_md = self._to_legacy() + if path: + legacy_md.write(path, skip_unknown=skip_unknown) + else: + legacy_md.write_file(fileobj, skip_unknown=skip_unknown) + else: + if self._legacy: + d = self._from_legacy() + else: + d = self._data + if fileobj: + json.dump(d, fileobj, ensure_ascii=True, indent=2, + sort_keys=True) + else: + with codecs.open(path, 'w', 'utf-8') as f: + json.dump(d, f, ensure_ascii=True, indent=2, + sort_keys=True) + + def add_requirements(self, requirements): + if self._legacy: + self._legacy.add_requirements(requirements) + else: + run_requires = self._data.setdefault('run_requires', []) + always = None + for entry in run_requires: + if 'environment' not in entry and 'extra' not in entry: + always = entry + break + if always is None: + always = { 'requires': requirements } + run_requires.insert(0, always) + else: + rset = set(always['requires']) | set(requirements) + always['requires'] = sorted(rset) + + def __repr__(self): + name = self.name or '(no name)' + version = self.version or 'no version' + return '<%s %s %s (%s)>' % (self.__class__.__name__, + self.metadata_version, name, version) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py new file mode 100755 index 0000000..cd618a6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/resources.py @@ -0,0 +1,355 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import bisect +import io +import logging +import os +import pkgutil +import shutil +import sys +import types +import zipimport + +from . import DistlibException +from .util import cached_property, get_cache_base, path_to_cache_dir, Cache + +logger = logging.getLogger(__name__) + + +cache = None # created when needed + + +class ResourceCache(Cache): + def __init__(self, base=None): + if base is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('resource-cache')) + super(ResourceCache, self).__init__(base) + + def is_stale(self, resource, path): + """ + Is the cache stale for the given resource? + + :param resource: The :class:`Resource` being cached. + :param path: The path of the resource in the cache. + :return: True if the cache is stale. + """ + # Cache invalidation is a hard problem :-) + return True + + def get(self, resource): + """ + Get a resource into the cache, + + :param resource: A :class:`Resource` instance. + :return: The pathname of the resource in the cache. + """ + prefix, path = resource.finder.get_cache_info(resource) + if prefix is None: + result = path + else: + result = os.path.join(self.base, self.prefix_to_dir(prefix), path) + dirname = os.path.dirname(result) + if not os.path.isdir(dirname): + os.makedirs(dirname) + if not os.path.exists(result): + stale = True + else: + stale = self.is_stale(resource, path) + if stale: + # write the bytes of the resource to the cache location + with open(result, 'wb') as f: + f.write(resource.bytes) + return result + + +class ResourceBase(object): + def __init__(self, finder, name): + self.finder = finder + self.name = name + + +class Resource(ResourceBase): + """ + A class representing an in-package resource, such as a data file. This is + not normally instantiated by user code, but rather by a + :class:`ResourceFinder` which manages the resource. + """ + is_container = False # Backwards compatibility + + def as_stream(self): + """ + Get the resource as a stream. + + This is not a property to make it obvious that it returns a new stream + each time. + """ + return self.finder.get_stream(self) + + @cached_property + def file_path(self): + global cache + if cache is None: + cache = ResourceCache() + return cache.get(self) + + @cached_property + def bytes(self): + return self.finder.get_bytes(self) + + @cached_property + def size(self): + return self.finder.get_size(self) + + +class ResourceContainer(ResourceBase): + is_container = True # Backwards compatibility + + @cached_property + def resources(self): + return self.finder.get_resources(self) + + +class ResourceFinder(object): + """ + Resource finder for file system resources. + """ + + if sys.platform.startswith('java'): + skipped_extensions = ('.pyc', '.pyo', '.class') + else: + skipped_extensions = ('.pyc', '.pyo') + + def __init__(self, module): + self.module = module + self.loader = getattr(module, '__loader__', None) + self.base = os.path.dirname(getattr(module, '__file__', '')) + + def _adjust_path(self, path): + return os.path.realpath(path) + + def _make_path(self, resource_name): + # Issue #50: need to preserve type of path on Python 2.x + # like os.path._get_sep + if isinstance(resource_name, bytes): # should only happen on 2.x + sep = b'/' + else: + sep = '/' + parts = resource_name.split(sep) + parts.insert(0, self.base) + result = os.path.join(*parts) + return self._adjust_path(result) + + def _find(self, path): + return os.path.exists(path) + + def get_cache_info(self, resource): + return None, resource.path + + def find(self, resource_name): + path = self._make_path(resource_name) + if not self._find(path): + result = None + else: + if self._is_directory(path): + result = ResourceContainer(self, resource_name) + else: + result = Resource(self, resource_name) + result.path = path + return result + + def get_stream(self, resource): + return open(resource.path, 'rb') + + def get_bytes(self, resource): + with open(resource.path, 'rb') as f: + return f.read() + + def get_size(self, resource): + return os.path.getsize(resource.path) + + def get_resources(self, resource): + def allowed(f): + return (f != '__pycache__' and not + f.endswith(self.skipped_extensions)) + return set([f for f in os.listdir(resource.path) if allowed(f)]) + + def is_container(self, resource): + return self._is_directory(resource.path) + + _is_directory = staticmethod(os.path.isdir) + + def iterator(self, resource_name): + resource = self.find(resource_name) + if resource is not None: + todo = [resource] + while todo: + resource = todo.pop(0) + yield resource + if resource.is_container: + rname = resource.name + for name in resource.resources: + if not rname: + new_name = name + else: + new_name = '/'.join([rname, name]) + child = self.find(new_name) + if child.is_container: + todo.append(child) + else: + yield child + + +class ZipResourceFinder(ResourceFinder): + """ + Resource finder for resources in .zip files. + """ + def __init__(self, module): + super(ZipResourceFinder, self).__init__(module) + archive = self.loader.archive + self.prefix_len = 1 + len(archive) + # PyPy doesn't have a _files attr on zipimporter, and you can't set one + if hasattr(self.loader, '_files'): + self._files = self.loader._files + else: + self._files = zipimport._zip_directory_cache[archive] + self.index = sorted(self._files) + + def _adjust_path(self, path): + return path + + def _find(self, path): + path = path[self.prefix_len:] + if path in self._files: + result = True + else: + if path and path[-1] != os.sep: + path = path + os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + if not result: + logger.debug('_find failed: %r %r', path, self.loader.prefix) + else: + logger.debug('_find worked: %r %r', path, self.loader.prefix) + return result + + def get_cache_info(self, resource): + prefix = self.loader.archive + path = resource.path[1 + len(prefix):] + return prefix, path + + def get_bytes(self, resource): + return self.loader.get_data(resource.path) + + def get_stream(self, resource): + return io.BytesIO(self.get_bytes(resource)) + + def get_size(self, resource): + path = resource.path[self.prefix_len:] + return self._files[path][3] + + def get_resources(self, resource): + path = resource.path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + plen = len(path) + result = set() + i = bisect.bisect(self.index, path) + while i < len(self.index): + if not self.index[i].startswith(path): + break + s = self.index[i][plen:] + result.add(s.split(os.sep, 1)[0]) # only immediate children + i += 1 + return result + + def _is_directory(self, path): + path = path[self.prefix_len:] + if path and path[-1] != os.sep: + path += os.sep + i = bisect.bisect(self.index, path) + try: + result = self.index[i].startswith(path) + except IndexError: + result = False + return result + +_finder_registry = { + type(None): ResourceFinder, + zipimport.zipimporter: ZipResourceFinder +} + +try: + # In Python 3.6, _frozen_importlib -> _frozen_importlib_external + try: + import _frozen_importlib_external as _fi + except ImportError: + import _frozen_importlib as _fi + _finder_registry[_fi.SourceFileLoader] = ResourceFinder + _finder_registry[_fi.FileFinder] = ResourceFinder + del _fi +except (ImportError, AttributeError): + pass + + +def register_finder(loader, finder_maker): + _finder_registry[type(loader)] = finder_maker + +_finder_cache = {} + + +def finder(package): + """ + Return a resource finder for a package. + :param package: The name of the package. + :return: A :class:`ResourceFinder` instance for the package. + """ + if package in _finder_cache: + result = _finder_cache[package] + else: + if package not in sys.modules: + __import__(package) + module = sys.modules[package] + path = getattr(module, '__path__', None) + if path is None: + raise DistlibException('You cannot get a finder for a module, ' + 'only for a package') + loader = getattr(module, '__loader__', None) + finder_maker = _finder_registry.get(type(loader)) + if finder_maker is None: + raise DistlibException('Unable to locate finder for %r' % package) + result = finder_maker(module) + _finder_cache[package] = result + return result + + +_dummy_module = types.ModuleType(str('__dummy__')) + + +def finder_for_path(path): + """ + Return a resource finder for a path, which should represent a container. + + :param path: The path. + :return: A :class:`ResourceFinder` instance for the path. + """ + result = None + # calls any path hooks, gets importer into cache + pkgutil.get_importer(path) + loader = sys.path_importer_cache.get(path) + finder = _finder_registry.get(type(loader)) + if finder: + module = _dummy_module + module.__file__ = os.path.join(path, '') + module.__loader__ = loader + result = finder(module) + return result diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py new file mode 100755 index 0000000..440bd30 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/scripts.py @@ -0,0 +1,415 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2015 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from io import BytesIO +import logging +import os +import re +import struct +import sys + +from .compat import sysconfig, detect_encoding, ZipFile +from .resources import finder +from .util import (FileOperator, get_export_entry, convert_path, + get_executable, in_venv) + +logger = logging.getLogger(__name__) + +_DEFAULT_MANIFEST = ''' +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity version="1.0.0.0" + processorArchitecture="X86" + name="%s" + type="win32"/> + + <!-- Identify the application security requirements. --> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> +</assembly>'''.strip() + +# check if Python is called on the first line with this expression +FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$') +SCRIPT_TEMPLATE = r'''# -*- coding: utf-8 -*- +if __name__ == '__main__': + import sys, re + + def _resolve(module, func): + __import__(module) + mod = sys.modules[module] + parts = func.split('.') + result = getattr(mod, parts.pop(0)) + for p in parts: + result = getattr(result, p) + return result + + try: + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + + func = _resolve('%(module)s', '%(func)s') + rc = func() # None interpreted as 0 + except Exception as e: # only supporting Python >= 2.6 + sys.stderr.write('%%s\n' %% e) + rc = 1 + sys.exit(rc) +''' + + +def _enquote_executable(executable): + if ' ' in executable: + # make sure we quote only the executable in case of env + # for example /usr/bin/env "/dir with spaces/bin/jython" + # instead of "/usr/bin/env /dir with spaces/bin/jython" + # otherwise whole + if executable.startswith('/usr/bin/env '): + env, _executable = executable.split(' ', 1) + if ' ' in _executable and not _executable.startswith('"'): + executable = '%s "%s"' % (env, _executable) + else: + if not executable.startswith('"'): + executable = '"%s"' % executable + return executable + + +class ScriptMaker(object): + """ + A class to copy or create scripts from source scripts or callable + specifications. + """ + script_template = SCRIPT_TEMPLATE + + executable = None # for shebangs + + def __init__(self, source_dir, target_dir, add_launchers=True, + dry_run=False, fileop=None): + self.source_dir = source_dir + self.target_dir = target_dir + self.add_launchers = add_launchers + self.force = False + self.clobber = False + # It only makes sense to set mode bits on POSIX. + self.set_mode = (os.name == 'posix') or (os.name == 'java' and + os._name == 'posix') + self.variants = set(('', 'X.Y')) + self._fileop = fileop or FileOperator(dry_run) + + self._is_nt = os.name == 'nt' or ( + os.name == 'java' and os._name == 'nt') + + def _get_alternate_executable(self, executable, options): + if options.get('gui', False) and self._is_nt: # pragma: no cover + dn, fn = os.path.split(executable) + fn = fn.replace('python', 'pythonw') + executable = os.path.join(dn, fn) + return executable + + if sys.platform.startswith('java'): # pragma: no cover + def _is_shell(self, executable): + """ + Determine if the specified executable is a script + (contains a #! line) + """ + try: + with open(executable) as fp: + return fp.read(2) == '#!' + except (OSError, IOError): + logger.warning('Failed to open %s', executable) + return False + + def _fix_jython_executable(self, executable): + if self._is_shell(executable): + # Workaround for Jython is not needed on Linux systems. + import java + + if java.lang.System.getProperty('os.name') == 'Linux': + return executable + elif executable.lower().endswith('jython.exe'): + # Use wrapper exe for Jython on Windows + return executable + return '/usr/bin/env %s' % executable + + def _build_shebang(self, executable, post_interp): + """ + Build a shebang line. In the simple case (on Windows, or a shebang line + which is not too long or contains spaces) use a simple formulation for + the shebang. Otherwise, use /bin/sh as the executable, with a contrived + shebang which allows the script to run either under Python or sh, using + suitable quoting. Thanks to Harald Nordgren for his input. + + See also: http://www.in-ulm.de/~mascheck/various/shebang/#length + https://hg.mozilla.org/mozilla-central/file/tip/mach + """ + if os.name != 'posix': + simple_shebang = True + else: + # Add 3 for '#!' prefix and newline suffix. + shebang_length = len(executable) + len(post_interp) + 3 + if sys.platform == 'darwin': + max_shebang_length = 512 + else: + max_shebang_length = 127 + simple_shebang = ((b' ' not in executable) and + (shebang_length <= max_shebang_length)) + + if simple_shebang: + result = b'#!' + executable + post_interp + b'\n' + else: + result = b'#!/bin/sh\n' + result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n' + result += b"' '''" + return result + + def _get_shebang(self, encoding, post_interp=b'', options=None): + enquote = True + if self.executable: + executable = self.executable + enquote = False # assume this will be taken care of + elif not sysconfig.is_python_build(): + executable = get_executable() + elif in_venv(): # pragma: no cover + executable = os.path.join(sysconfig.get_path('scripts'), + 'python%s' % sysconfig.get_config_var('EXE')) + else: # pragma: no cover + executable = os.path.join( + sysconfig.get_config_var('BINDIR'), + 'python%s%s' % (sysconfig.get_config_var('VERSION'), + sysconfig.get_config_var('EXE'))) + if options: + executable = self._get_alternate_executable(executable, options) + + if sys.platform.startswith('java'): # pragma: no cover + executable = self._fix_jython_executable(executable) + # Normalise case for Windows + executable = os.path.normcase(executable) + # If the user didn't specify an executable, it may be necessary to + # cater for executable paths with spaces (not uncommon on Windows) + if enquote: + executable = _enquote_executable(executable) + # Issue #51: don't use fsencode, since we later try to + # check that the shebang is decodable using utf-8. + executable = executable.encode('utf-8') + # in case of IronPython, play safe and enable frames support + if (sys.platform == 'cli' and '-X:Frames' not in post_interp + and '-X:FullFrames' not in post_interp): # pragma: no cover + post_interp += b' -X:Frames' + shebang = self._build_shebang(executable, post_interp) + # Python parser starts to read a script using UTF-8 until + # it gets a #coding:xxx cookie. The shebang has to be the + # first line of a file, the #coding:xxx cookie cannot be + # written before. So the shebang has to be decodable from + # UTF-8. + try: + shebang.decode('utf-8') + except UnicodeDecodeError: # pragma: no cover + raise ValueError( + 'The shebang (%r) is not decodable from utf-8' % shebang) + # If the script is encoded to a custom encoding (use a + # #coding:xxx cookie), the shebang has to be decodable from + # the script encoding too. + if encoding != 'utf-8': + try: + shebang.decode(encoding) + except UnicodeDecodeError: # pragma: no cover + raise ValueError( + 'The shebang (%r) is not decodable ' + 'from the script encoding (%r)' % (shebang, encoding)) + return shebang + + def _get_script_text(self, entry): + return self.script_template % dict(module=entry.prefix, + func=entry.suffix) + + manifest = _DEFAULT_MANIFEST + + def get_manifest(self, exename): + base = os.path.basename(exename) + return self.manifest % base + + def _write_script(self, names, shebang, script_bytes, filenames, ext): + use_launcher = self.add_launchers and self._is_nt + linesep = os.linesep.encode('utf-8') + if not use_launcher: + script_bytes = shebang + linesep + script_bytes + else: # pragma: no cover + if ext == 'py': + launcher = self._get_launcher('t') + else: + launcher = self._get_launcher('w') + stream = BytesIO() + with ZipFile(stream, 'w') as zf: + zf.writestr('__main__.py', script_bytes) + zip_data = stream.getvalue() + script_bytes = launcher + shebang + linesep + zip_data + for name in names: + outname = os.path.join(self.target_dir, name) + if use_launcher: # pragma: no cover + n, e = os.path.splitext(outname) + if e.startswith('.py'): + outname = n + outname = '%s.exe' % outname + try: + self._fileop.write_binary_file(outname, script_bytes) + except Exception: + # Failed writing an executable - it might be in use. + logger.warning('Failed to write executable - trying to ' + 'use .deleteme logic') + dfname = '%s.deleteme' % outname + if os.path.exists(dfname): + os.remove(dfname) # Not allowed to fail here + os.rename(outname, dfname) # nor here + self._fileop.write_binary_file(outname, script_bytes) + logger.debug('Able to replace executable using ' + '.deleteme logic') + try: + os.remove(dfname) + except Exception: + pass # still in use - ignore error + else: + if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover + outname = '%s.%s' % (outname, ext) + if os.path.exists(outname) and not self.clobber: + logger.warning('Skipping existing file %s', outname) + continue + self._fileop.write_binary_file(outname, script_bytes) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + + def _make_script(self, entry, filenames, options=None): + post_interp = b'' + if options: + args = options.get('interpreter_args', []) + if args: + args = ' %s' % ' '.join(args) + post_interp = args.encode('utf-8') + shebang = self._get_shebang('utf-8', post_interp, options=options) + script = self._get_script_text(entry).encode('utf-8') + name = entry.name + scriptnames = set() + if '' in self.variants: + scriptnames.add(name) + if 'X' in self.variants: + scriptnames.add('%s%s' % (name, sys.version[0])) + if 'X.Y' in self.variants: + scriptnames.add('%s-%s' % (name, sys.version[:3])) + if options and options.get('gui', False): + ext = 'pyw' + else: + ext = 'py' + self._write_script(scriptnames, shebang, script, filenames, ext) + + def _copy_script(self, script, filenames): + adjust = False + script = os.path.join(self.source_dir, convert_path(script)) + outname = os.path.join(self.target_dir, os.path.basename(script)) + if not self.force and not self._fileop.newer(script, outname): + logger.debug('not copying %s (up-to-date)', script) + return + + # Always open the file, but ignore failures in dry-run mode -- + # that way, we'll get accurate feedback if we can read the + # script. + try: + f = open(script, 'rb') + except IOError: # pragma: no cover + if not self.dry_run: + raise + f = None + else: + first_line = f.readline() + if not first_line: # pragma: no cover + logger.warning('%s: %s is an empty file (skipping)', + self.get_command_name(), script) + return + + match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n')) + if match: + adjust = True + post_interp = match.group(1) or b'' + + if not adjust: + if f: + f.close() + self._fileop.copy_file(script, outname) + if self.set_mode: + self._fileop.set_executable_mode([outname]) + filenames.append(outname) + else: + logger.info('copying and adjusting %s -> %s', script, + self.target_dir) + if not self._fileop.dry_run: + encoding, lines = detect_encoding(f.readline) + f.seek(0) + shebang = self._get_shebang(encoding, post_interp) + if b'pythonw' in first_line: # pragma: no cover + ext = 'pyw' + else: + ext = 'py' + n = os.path.basename(outname) + self._write_script([n], shebang, f.read(), filenames, ext) + if f: + f.close() + + @property + def dry_run(self): + return self._fileop.dry_run + + @dry_run.setter + def dry_run(self, value): + self._fileop.dry_run = value + + if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover + # Executable launcher support. + # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/ + + def _get_launcher(self, kind): + if struct.calcsize('P') == 8: # 64-bit + bits = '64' + else: + bits = '32' + name = '%s%s.exe' % (kind, bits) + # Issue 31: don't hardcode an absolute package name, but + # determine it relative to the current package + distlib_package = __name__.rsplit('.', 1)[0] + result = finder(distlib_package).find(name).bytes + return result + + # Public API follows + + def make(self, specification, options=None): + """ + Make a script. + + :param specification: The specification, which is either a valid export + entry specification (to make a script from a + callable) or a filename (to make a script by + copying from a source location). + :param options: A dictionary of options controlling script generation. + :return: A list of all absolute pathnames written to. + """ + filenames = [] + entry = get_export_entry(specification) + if entry is None: + self._copy_script(specification, filenames) + else: + self._make_script(entry, filenames, options=options) + return filenames + + def make_multiple(self, specifications, options=None): + """ + Take a list of specifications and make scripts from them, + :param specifications: A list of specifications. + :return: A list of all absolute pathnames written to, + """ + filenames = [] + for specification in specifications: + filenames.extend(self.make(specification, options)) + return filenames diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe new file mode 100755 index 0000000..a09d926 Binary files /dev/null and b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t32.exe differ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe new file mode 100755 index 0000000..9da9b40 Binary files /dev/null and b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/t64.exe differ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py new file mode 100755 index 0000000..b1d3f90 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/util.py @@ -0,0 +1,1755 @@ +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +import codecs +from collections import deque +import contextlib +import csv +from glob import iglob as std_iglob +import io +import json +import logging +import os +import py_compile +import re +import socket +try: + import ssl +except ImportError: # pragma: no cover + ssl = None +import subprocess +import sys +import tarfile +import tempfile +import textwrap + +try: + import threading +except ImportError: # pragma: no cover + import dummy_threading as threading +import time + +from . import DistlibException +from .compat import (string_types, text_type, shutil, raw_input, StringIO, + cache_from_source, urlopen, urljoin, httplib, xmlrpclib, + splittype, HTTPHandler, BaseConfigurator, valid_ident, + Container, configparser, URLError, ZipFile, fsdecode, + unquote, urlparse) + +logger = logging.getLogger(__name__) + +# +# Requirement parsing code as per PEP 508 +# + +IDENTIFIER = re.compile(r'^([\w\.-]+)\s*') +VERSION_IDENTIFIER = re.compile(r'^([\w\.*+-]+)\s*') +COMPARE_OP = re.compile(r'^(<=?|>=?|={2,3}|[~!]=)\s*') +MARKER_OP = re.compile(r'^((<=?)|(>=?)|={2,3}|[~!]=|in|not\s+in)\s*') +OR = re.compile(r'^or\b\s*') +AND = re.compile(r'^and\b\s*') +NON_SPACE = re.compile(r'(\S+)\s*') +STRING_CHUNK = re.compile(r'([\s\w\.{}()*+#:;,/?!~`@$%^&=|<>\[\]-]+)') + + +def parse_marker(marker_string): + """ + Parse a marker string and return a dictionary containing a marker expression. + + The dictionary will contain keys "op", "lhs" and "rhs" for non-terminals in + the expression grammar, or strings. A string contained in quotes is to be + interpreted as a literal string, and a string not contained in quotes is a + variable (such as os_name). + """ + def marker_var(remaining): + # either identifier, or literal string + m = IDENTIFIER.match(remaining) + if m: + result = m.groups()[0] + remaining = remaining[m.end():] + elif not remaining: + raise SyntaxError('unexpected end of input') + else: + q = remaining[0] + if q not in '\'"': + raise SyntaxError('invalid expression: %s' % remaining) + oq = '\'"'.replace(q, '') + remaining = remaining[1:] + parts = [q] + while remaining: + # either a string chunk, or oq, or q to terminate + if remaining[0] == q: + break + elif remaining[0] == oq: + parts.append(oq) + remaining = remaining[1:] + else: + m = STRING_CHUNK.match(remaining) + if not m: + raise SyntaxError('error in string literal: %s' % remaining) + parts.append(m.groups()[0]) + remaining = remaining[m.end():] + else: + s = ''.join(parts) + raise SyntaxError('unterminated string: %s' % s) + parts.append(q) + result = ''.join(parts) + remaining = remaining[1:].lstrip() # skip past closing quote + return result, remaining + + def marker_expr(remaining): + if remaining and remaining[0] == '(': + result, remaining = marker(remaining[1:].lstrip()) + if remaining[0] != ')': + raise SyntaxError('unterminated parenthesis: %s' % remaining) + remaining = remaining[1:].lstrip() + else: + lhs, remaining = marker_var(remaining) + while remaining: + m = MARKER_OP.match(remaining) + if not m: + break + op = m.groups()[0] + remaining = remaining[m.end():] + rhs, remaining = marker_var(remaining) + lhs = {'op': op, 'lhs': lhs, 'rhs': rhs} + result = lhs + return result, remaining + + def marker_and(remaining): + lhs, remaining = marker_expr(remaining) + while remaining: + m = AND.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_expr(remaining) + lhs = {'op': 'and', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + def marker(remaining): + lhs, remaining = marker_and(remaining) + while remaining: + m = OR.match(remaining) + if not m: + break + remaining = remaining[m.end():] + rhs, remaining = marker_and(remaining) + lhs = {'op': 'or', 'lhs': lhs, 'rhs': rhs} + return lhs, remaining + + return marker(marker_string) + + +def parse_requirement(req): + """ + Parse a requirement passed in as a string. Return a Container + whose attributes contain the various parts of the requirement. + """ + remaining = req.strip() + if not remaining or remaining.startswith('#'): + return None + m = IDENTIFIER.match(remaining) + if not m: + raise SyntaxError('name expected: %s' % remaining) + distname = m.groups()[0] + remaining = remaining[m.end():] + extras = mark_expr = versions = uri = None + if remaining and remaining[0] == '[': + i = remaining.find(']', 1) + if i < 0: + raise SyntaxError('unterminated extra: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + extras = [] + while s: + m = IDENTIFIER.match(s) + if not m: + raise SyntaxError('malformed extra: %s' % s) + extras.append(m.groups()[0]) + s = s[m.end():] + if not s: + break + if s[0] != ',': + raise SyntaxError('comma expected in extras: %s' % s) + s = s[1:].lstrip() + if not extras: + extras = None + if remaining: + if remaining[0] == '@': + # it's a URI + remaining = remaining[1:].lstrip() + m = NON_SPACE.match(remaining) + if not m: + raise SyntaxError('invalid URI: %s' % remaining) + uri = m.groups()[0] + t = urlparse(uri) + # there are issues with Python and URL parsing, so this test + # is a bit crude. See bpo-20271, bpo-23505. Python doesn't + # always parse invalid URLs correctly - it should raise + # exceptions for malformed URLs + if not (t.scheme and t.netloc): + raise SyntaxError('Invalid URL: %s' % uri) + remaining = remaining[m.end():].lstrip() + else: + + def get_versions(ver_remaining): + """ + Return a list of operator, version tuples if any are + specified, else None. + """ + m = COMPARE_OP.match(ver_remaining) + versions = None + if m: + versions = [] + while True: + op = m.groups()[0] + ver_remaining = ver_remaining[m.end():] + m = VERSION_IDENTIFIER.match(ver_remaining) + if not m: + raise SyntaxError('invalid version: %s' % ver_remaining) + v = m.groups()[0] + versions.append((op, v)) + ver_remaining = ver_remaining[m.end():] + if not ver_remaining or ver_remaining[0] != ',': + break + ver_remaining = ver_remaining[1:].lstrip() + m = COMPARE_OP.match(ver_remaining) + if not m: + raise SyntaxError('invalid constraint: %s' % ver_remaining) + if not versions: + versions = None + return versions, ver_remaining + + if remaining[0] != '(': + versions, remaining = get_versions(remaining) + else: + i = remaining.find(')', 1) + if i < 0: + raise SyntaxError('unterminated parenthesis: %s' % remaining) + s = remaining[1:i] + remaining = remaining[i + 1:].lstrip() + # As a special diversion from PEP 508, allow a version number + # a.b.c in parentheses as a synonym for ~= a.b.c (because this + # is allowed in earlier PEPs) + if COMPARE_OP.match(s): + versions, _ = get_versions(s) + else: + m = VERSION_IDENTIFIER.match(s) + if not m: + raise SyntaxError('invalid constraint: %s' % s) + v = m.groups()[0] + s = s[m.end():].lstrip() + if s: + raise SyntaxError('invalid constraint: %s' % s) + versions = [('~=', v)] + + if remaining: + if remaining[0] != ';': + raise SyntaxError('invalid requirement: %s' % remaining) + remaining = remaining[1:].lstrip() + + mark_expr, remaining = parse_marker(remaining) + + if remaining and remaining[0] != '#': + raise SyntaxError('unexpected trailing data: %s' % remaining) + + if not versions: + rs = distname + else: + rs = '%s %s' % (distname, ', '.join(['%s %s' % con for con in versions])) + return Container(name=distname, extras=extras, constraints=versions, + marker=mark_expr, url=uri, requirement=rs) + + +def get_resources_dests(resources_root, rules): + """Find destinations for resources files""" + + def get_rel_path(root, path): + # normalizes and returns a lstripped-/-separated path + root = root.replace(os.path.sep, '/') + path = path.replace(os.path.sep, '/') + assert path.startswith(root) + return path[len(root):].lstrip('/') + + destinations = {} + for base, suffix, dest in rules: + prefix = os.path.join(resources_root, base) + for abs_base in iglob(prefix): + abs_glob = os.path.join(abs_base, suffix) + for abs_path in iglob(abs_glob): + resource_file = get_rel_path(resources_root, abs_path) + if dest is None: # remove the entry if it was here + destinations.pop(resource_file, None) + else: + rel_path = get_rel_path(abs_base, abs_path) + rel_dest = dest.replace(os.path.sep, '/').rstrip('/') + destinations[resource_file] = rel_dest + '/' + rel_path + return destinations + + +def in_venv(): + if hasattr(sys, 'real_prefix'): + # virtualenv venvs + result = True + else: + # PEP 405 venvs + result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix) + return result + + +def get_executable(): +# The __PYVENV_LAUNCHER__ dance is apparently no longer needed, as +# changes to the stub launcher mean that sys.executable always points +# to the stub on OS X +# if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__' +# in os.environ): +# result = os.environ['__PYVENV_LAUNCHER__'] +# else: +# result = sys.executable +# return result + result = os.path.normcase(sys.executable) + if not isinstance(result, text_type): + result = fsdecode(result) + return result + + +def proceed(prompt, allowed_chars, error_prompt=None, default=None): + p = prompt + while True: + s = raw_input(p) + p = prompt + if not s and default: + s = default + if s: + c = s[0].lower() + if c in allowed_chars: + break + if error_prompt: + p = '%c: %s\n%s' % (c, error_prompt, prompt) + return c + + +def extract_by_key(d, keys): + if isinstance(keys, string_types): + keys = keys.split() + result = {} + for key in keys: + if key in d: + result[key] = d[key] + return result + +def read_exports(stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + # Try to load as JSON, falling back on legacy format + data = stream.read() + stream = StringIO(data) + try: + jdata = json.load(stream) + result = jdata['extensions']['python.exports']['exports'] + for group, entries in result.items(): + for k, v in entries.items(): + s = '%s = %s' % (k, v) + entry = get_export_entry(s) + assert entry is not None + entries[k] = entry + return result + except Exception: + stream.seek(0, 0) + + def read_stream(cp, stream): + if hasattr(cp, 'read_file'): + cp.read_file(stream) + else: + cp.readfp(stream) + + cp = configparser.ConfigParser() + try: + read_stream(cp, stream) + except configparser.MissingSectionHeaderError: + stream.close() + data = textwrap.dedent(data) + stream = StringIO(data) + read_stream(cp, stream) + + result = {} + for key in cp.sections(): + result[key] = entries = {} + for name, value in cp.items(key): + s = '%s = %s' % (name, value) + entry = get_export_entry(s) + assert entry is not None + #entry.dist = self + entries[name] = entry + return result + + +def write_exports(exports, stream): + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getwriter('utf-8')(stream) + cp = configparser.ConfigParser() + for k, v in exports.items(): + # TODO check k, v for valid values + cp.add_section(k) + for entry in v.values(): + if entry.suffix is None: + s = entry.prefix + else: + s = '%s:%s' % (entry.prefix, entry.suffix) + if entry.flags: + s = '%s [%s]' % (s, ', '.join(entry.flags)) + cp.set(k, entry.name, s) + cp.write(stream) + + +@contextlib.contextmanager +def tempdir(): + td = tempfile.mkdtemp() + try: + yield td + finally: + shutil.rmtree(td) + +@contextlib.contextmanager +def chdir(d): + cwd = os.getcwd() + try: + os.chdir(d) + yield + finally: + os.chdir(cwd) + + +@contextlib.contextmanager +def socket_timeout(seconds=15): + cto = socket.getdefaulttimeout() + try: + socket.setdefaulttimeout(seconds) + yield + finally: + socket.setdefaulttimeout(cto) + + +class cached_property(object): + def __init__(self, func): + self.func = func + #for attr in ('__name__', '__module__', '__doc__'): + # setattr(self, attr, getattr(func, attr, None)) + + def __get__(self, obj, cls=None): + if obj is None: + return self + value = self.func(obj) + object.__setattr__(obj, self.func.__name__, value) + #obj.__dict__[self.func.__name__] = value = self.func(obj) + return value + +def convert_path(pathname): + """Return 'pathname' as a name that will work on the native filesystem. + + The path is split on '/' and put back together again using the current + directory separator. Needed because filenames in the setup script are + always supplied in Unix style, and have to be converted to the local + convention before we can actually use them in the filesystem. Raises + ValueError on non-Unix-ish systems if 'pathname' either starts or + ends with a slash. + """ + if os.sep == '/': + return pathname + if not pathname: + return pathname + if pathname[0] == '/': + raise ValueError("path '%s' cannot be absolute" % pathname) + if pathname[-1] == '/': + raise ValueError("path '%s' cannot end with '/'" % pathname) + + paths = pathname.split('/') + while os.curdir in paths: + paths.remove(os.curdir) + if not paths: + return os.curdir + return os.path.join(*paths) + + +class FileOperator(object): + def __init__(self, dry_run=False): + self.dry_run = dry_run + self.ensured = set() + self._init_record() + + def _init_record(self): + self.record = False + self.files_written = set() + self.dirs_created = set() + + def record_as_written(self, path): + if self.record: + self.files_written.add(path) + + def newer(self, source, target): + """Tell if the target is newer than the source. + + Returns true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. + + Returns false if both exist and 'target' is the same age or younger + than 'source'. Raise PackagingFileError if 'source' does not exist. + + Note that this test is not very accurate: files created in the same + second will have the same "age". + """ + if not os.path.exists(source): + raise DistlibException("file '%r' does not exist" % + os.path.abspath(source)) + if not os.path.exists(target): + return True + + return os.stat(source).st_mtime > os.stat(target).st_mtime + + def copy_file(self, infile, outfile, check=True): + """Copy a file respecting dry-run and force flags. + """ + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying %s to %s', infile, outfile) + if not self.dry_run: + msg = None + if check: + if os.path.islink(outfile): + msg = '%s is a symlink' % outfile + elif os.path.exists(outfile) and not os.path.isfile(outfile): + msg = '%s is a non-regular file' % outfile + if msg: + raise ValueError(msg + ' which would be overwritten') + shutil.copyfile(infile, outfile) + self.record_as_written(outfile) + + def copy_stream(self, instream, outfile, encoding=None): + assert not os.path.isdir(outfile) + self.ensure_dir(os.path.dirname(outfile)) + logger.info('Copying stream %s to %s', instream, outfile) + if not self.dry_run: + if encoding is None: + outstream = open(outfile, 'wb') + else: + outstream = codecs.open(outfile, 'w', encoding=encoding) + try: + shutil.copyfileobj(instream, outstream) + finally: + outstream.close() + self.record_as_written(outfile) + + def write_binary_file(self, path, data): + self.ensure_dir(os.path.dirname(path)) + if not self.dry_run: + with open(path, 'wb') as f: + f.write(data) + self.record_as_written(path) + + def write_text_file(self, path, data, encoding): + self.ensure_dir(os.path.dirname(path)) + if not self.dry_run: + with open(path, 'wb') as f: + f.write(data.encode(encoding)) + self.record_as_written(path) + + def set_mode(self, bits, mask, files): + if os.name == 'posix' or (os.name == 'java' and os._name == 'posix'): + # Set the executable bits (owner, group, and world) on + # all the files specified. + for f in files: + if self.dry_run: + logger.info("changing mode of %s", f) + else: + mode = (os.stat(f).st_mode | bits) & mask + logger.info("changing mode of %s to %o", f, mode) + os.chmod(f, mode) + + set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f) + + def ensure_dir(self, path): + path = os.path.abspath(path) + if path not in self.ensured and not os.path.exists(path): + self.ensured.add(path) + d, f = os.path.split(path) + self.ensure_dir(d) + logger.info('Creating %s' % path) + if not self.dry_run: + os.mkdir(path) + if self.record: + self.dirs_created.add(path) + + def byte_compile(self, path, optimize=False, force=False, prefix=None): + dpath = cache_from_source(path, not optimize) + logger.info('Byte-compiling %s to %s', path, dpath) + if not self.dry_run: + if force or self.newer(path, dpath): + if not prefix: + diagpath = None + else: + assert path.startswith(prefix) + diagpath = path[len(prefix):] + py_compile.compile(path, dpath, diagpath, True) # raise error + self.record_as_written(dpath) + return dpath + + def ensure_removed(self, path): + if os.path.exists(path): + if os.path.isdir(path) and not os.path.islink(path): + logger.debug('Removing directory tree at %s', path) + if not self.dry_run: + shutil.rmtree(path) + if self.record: + if path in self.dirs_created: + self.dirs_created.remove(path) + else: + if os.path.islink(path): + s = 'link' + else: + s = 'file' + logger.debug('Removing %s %s', s, path) + if not self.dry_run: + os.remove(path) + if self.record: + if path in self.files_written: + self.files_written.remove(path) + + def is_writable(self, path): + result = False + while not result: + if os.path.exists(path): + result = os.access(path, os.W_OK) + break + parent = os.path.dirname(path) + if parent == path: + break + path = parent + return result + + def commit(self): + """ + Commit recorded changes, turn off recording, return + changes. + """ + assert self.record + result = self.files_written, self.dirs_created + self._init_record() + return result + + def rollback(self): + if not self.dry_run: + for f in list(self.files_written): + if os.path.exists(f): + os.remove(f) + # dirs should all be empty now, except perhaps for + # __pycache__ subdirs + # reverse so that subdirs appear before their parents + dirs = sorted(self.dirs_created, reverse=True) + for d in dirs: + flist = os.listdir(d) + if flist: + assert flist == ['__pycache__'] + sd = os.path.join(d, flist[0]) + os.rmdir(sd) + os.rmdir(d) # should fail if non-empty + self._init_record() + +def resolve(module_name, dotted_path): + if module_name in sys.modules: + mod = sys.modules[module_name] + else: + mod = __import__(module_name) + if dotted_path is None: + result = mod + else: + parts = dotted_path.split('.') + result = getattr(mod, parts.pop(0)) + for p in parts: + result = getattr(result, p) + return result + + +class ExportEntry(object): + def __init__(self, name, prefix, suffix, flags): + self.name = name + self.prefix = prefix + self.suffix = suffix + self.flags = flags + + @cached_property + def value(self): + return resolve(self.prefix, self.suffix) + + def __repr__(self): # pragma: no cover + return '<ExportEntry %s = %s:%s %s>' % (self.name, self.prefix, + self.suffix, self.flags) + + def __eq__(self, other): + if not isinstance(other, ExportEntry): + result = False + else: + result = (self.name == other.name and + self.prefix == other.prefix and + self.suffix == other.suffix and + self.flags == other.flags) + return result + + __hash__ = object.__hash__ + + +ENTRY_RE = re.compile(r'''(?P<name>(\w|[-.+])+) + \s*=\s*(?P<callable>(\w+)([:\.]\w+)*) + \s*(\[\s*(?P<flags>\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])? + ''', re.VERBOSE) + +def get_export_entry(specification): + m = ENTRY_RE.search(specification) + if not m: + result = None + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + else: + d = m.groupdict() + name = d['name'] + path = d['callable'] + colons = path.count(':') + if colons == 0: + prefix, suffix = path, None + else: + if colons != 1: + raise DistlibException("Invalid specification " + "'%s'" % specification) + prefix, suffix = path.split(':') + flags = d['flags'] + if flags is None: + if '[' in specification or ']' in specification: + raise DistlibException("Invalid specification " + "'%s'" % specification) + flags = [] + else: + flags = [f.strip() for f in flags.split(',')] + result = ExportEntry(name, prefix, suffix, flags) + return result + + +def get_cache_base(suffix=None): + """ + Return the default base location for distlib caches. If the directory does + not exist, it is created. Use the suffix provided for the base directory, + and default to '.distlib' if it isn't provided. + + On Windows, if LOCALAPPDATA is defined in the environment, then it is + assumed to be a directory, and will be the parent directory of the result. + On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home + directory - using os.expanduser('~') - will be the parent directory of + the result. + + The result is just the directory '.distlib' in the parent directory as + determined above, or with the name specified with ``suffix``. + """ + if suffix is None: + suffix = '.distlib' + if os.name == 'nt' and 'LOCALAPPDATA' in os.environ: + result = os.path.expandvars('$localappdata') + else: + # Assume posix, or old Windows + result = os.path.expanduser('~') + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if os.path.isdir(result): + usable = os.access(result, os.W_OK) + if not usable: + logger.warning('Directory exists but is not writable: %s', result) + else: + try: + os.makedirs(result) + usable = True + except OSError: + logger.warning('Unable to create %s', result, exc_info=True) + usable = False + if not usable: + result = tempfile.mkdtemp() + logger.warning('Default location unusable, using %s', result) + return os.path.join(result, suffix) + + +def path_to_cache_dir(path): + """ + Convert an absolute path to a directory name for use in a cache. + + The algorithm used is: + + #. On Windows, any ``':'`` in the drive is replaced with ``'---'``. + #. Any occurrence of ``os.sep`` is replaced with ``'--'``. + #. ``'.cache'`` is appended. + """ + d, p = os.path.splitdrive(os.path.abspath(path)) + if d: + d = d.replace(':', '---') + p = p.replace(os.sep, '--') + return d + p + '.cache' + + +def ensure_slash(s): + if not s.endswith('/'): + return s + '/' + return s + + +def parse_credentials(netloc): + username = password = None + if '@' in netloc: + prefix, netloc = netloc.split('@', 1) + if ':' not in prefix: + username = prefix + else: + username, password = prefix.split(':', 1) + return username, password, netloc + + +def get_process_umask(): + result = os.umask(0o22) + os.umask(result) + return result + +def is_string_sequence(seq): + result = True + i = None + for i, s in enumerate(seq): + if not isinstance(s, string_types): + result = False + break + assert i is not None + return result + +PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-' + '([a-z0-9_.+-]+)', re.I) +PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)') + + +def split_filename(filename, project_name=None): + """ + Extract name, version, python version from a filename (no extension) + + Return name, version, pyver or None + """ + result = None + pyver = None + filename = unquote(filename).replace(' ', '-') + m = PYTHON_VERSION.search(filename) + if m: + pyver = m.group(1) + filename = filename[:m.start()] + if project_name and len(filename) > len(project_name) + 1: + m = re.match(re.escape(project_name) + r'\b', filename) + if m: + n = m.end() + result = filename[:n], filename[n + 1:], pyver + if result is None: + m = PROJECT_NAME_AND_VERSION.match(filename) + if m: + result = m.group(1), m.group(3), pyver + return result + +# Allow spaces in name because of legacy dists like "Twisted Core" +NAME_VERSION_RE = re.compile(r'(?P<name>[\w .-]+)\s*' + r'\(\s*(?P<ver>[^\s)]+)\)$') + +def parse_name_and_version(p): + """ + A utility method used to get name and version from a string. + + From e.g. a Provides-Dist value. + + :param p: A value in a form 'foo (1.0)' + :return: The name and version as a tuple. + """ + m = NAME_VERSION_RE.match(p) + if not m: + raise DistlibException('Ill-formed name/version string: \'%s\'' % p) + d = m.groupdict() + return d['name'].strip().lower(), d['ver'] + +def get_extras(requested, available): + result = set() + requested = set(requested or []) + available = set(available or []) + if '*' in requested: + requested.remove('*') + result |= available + for r in requested: + if r == '-': + result.add(r) + elif r.startswith('-'): + unwanted = r[1:] + if unwanted not in available: + logger.warning('undeclared extra: %s' % unwanted) + if unwanted in result: + result.remove(unwanted) + else: + if r not in available: + logger.warning('undeclared extra: %s' % r) + result.add(r) + return result +# +# Extended metadata functionality +# + +def _get_external_data(url): + result = {} + try: + # urlopen might fail if it runs into redirections, + # because of Python issue #13696. Fixed in locators + # using a custom redirect handler. + resp = urlopen(url) + headers = resp.info() + ct = headers.get('Content-Type') + if not ct.startswith('application/json'): + logger.debug('Unexpected response for JSON request: %s', ct) + else: + reader = codecs.getreader('utf-8')(resp) + #data = reader.read().decode('utf-8') + #result = json.loads(data) + result = json.load(reader) + except Exception as e: + logger.exception('Failed to get external data for %s: %s', url, e) + return result + +_external_data_base_url = 'https://www.red-dove.com/pypi/projects/' + +def get_project_data(name): + url = '%s/%s/project.json' % (name[0].upper(), name) + url = urljoin(_external_data_base_url, url) + result = _get_external_data(url) + return result + +def get_package_data(name, version): + url = '%s/%s/package-%s.json' % (name[0].upper(), name, version) + url = urljoin(_external_data_base_url, url) + return _get_external_data(url) + + +class Cache(object): + """ + A class implementing a cache for resources that need to live in the file system + e.g. shared libraries. This class was moved from resources to here because it + could be used by other modules, e.g. the wheel module. + """ + + def __init__(self, base): + """ + Initialise an instance. + + :param base: The base directory where the cache should be located. + """ + # we use 'isdir' instead of 'exists', because we want to + # fail if there's a file with that name + if not os.path.isdir(base): # pragma: no cover + os.makedirs(base) + if (os.stat(base).st_mode & 0o77) != 0: + logger.warning('Directory \'%s\' is not private', base) + self.base = os.path.abspath(os.path.normpath(base)) + + def prefix_to_dir(self, prefix): + """ + Converts a resource prefix to a directory name in the cache. + """ + return path_to_cache_dir(prefix) + + def clear(self): + """ + Clear the cache. + """ + not_removed = [] + for fn in os.listdir(self.base): + fn = os.path.join(self.base, fn) + try: + if os.path.islink(fn) or os.path.isfile(fn): + os.remove(fn) + elif os.path.isdir(fn): + shutil.rmtree(fn) + except Exception: + not_removed.append(fn) + return not_removed + + +class EventMixin(object): + """ + A very simple publish/subscribe system. + """ + def __init__(self): + self._subscribers = {} + + def add(self, event, subscriber, append=True): + """ + Add a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be added (and called when the + event is published). + :param append: Whether to append or prepend the subscriber to an + existing subscriber list for the event. + """ + subs = self._subscribers + if event not in subs: + subs[event] = deque([subscriber]) + else: + sq = subs[event] + if append: + sq.append(subscriber) + else: + sq.appendleft(subscriber) + + def remove(self, event, subscriber): + """ + Remove a subscriber for an event. + + :param event: The name of an event. + :param subscriber: The subscriber to be removed. + """ + subs = self._subscribers + if event not in subs: + raise ValueError('No subscribers: %r' % event) + subs[event].remove(subscriber) + + def get_subscribers(self, event): + """ + Return an iterator for the subscribers for an event. + :param event: The event to return subscribers for. + """ + return iter(self._subscribers.get(event, ())) + + def publish(self, event, *args, **kwargs): + """ + Publish a event and return a list of values returned by its + subscribers. + + :param event: The event to publish. + :param args: The positional arguments to pass to the event's + subscribers. + :param kwargs: The keyword arguments to pass to the event's + subscribers. + """ + result = [] + for subscriber in self.get_subscribers(event): + try: + value = subscriber(event, *args, **kwargs) + except Exception: + logger.exception('Exception during event publication') + value = None + result.append(value) + logger.debug('publish %s: args = %s, kwargs = %s, result = %s', + event, args, kwargs, result) + return result + +# +# Simple sequencing +# +class Sequencer(object): + def __init__(self): + self._preds = {} + self._succs = {} + self._nodes = set() # nodes with no preds/succs + + def add_node(self, node): + self._nodes.add(node) + + def remove_node(self, node, edges=False): + if node in self._nodes: + self._nodes.remove(node) + if edges: + for p in set(self._preds.get(node, ())): + self.remove(p, node) + for s in set(self._succs.get(node, ())): + self.remove(node, s) + # Remove empties + for k, v in list(self._preds.items()): + if not v: + del self._preds[k] + for k, v in list(self._succs.items()): + if not v: + del self._succs[k] + + def add(self, pred, succ): + assert pred != succ + self._preds.setdefault(succ, set()).add(pred) + self._succs.setdefault(pred, set()).add(succ) + + def remove(self, pred, succ): + assert pred != succ + try: + preds = self._preds[succ] + succs = self._succs[pred] + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of anything' % succ) + try: + preds.remove(pred) + succs.remove(succ) + except KeyError: # pragma: no cover + raise ValueError('%r not a successor of %r' % (succ, pred)) + + def is_step(self, step): + return (step in self._preds or step in self._succs or + step in self._nodes) + + def get_steps(self, final): + if not self.is_step(final): + raise ValueError('Unknown: %r' % final) + result = [] + todo = [] + seen = set() + todo.append(final) + while todo: + step = todo.pop(0) + if step in seen: + # if a step was already seen, + # move it to the end (so it will appear earlier + # when reversed on return) ... but not for the + # final step, as that would be confusing for + # users + if step != final: + result.remove(step) + result.append(step) + else: + seen.add(step) + result.append(step) + preds = self._preds.get(step, ()) + todo.extend(preds) + return reversed(result) + + @property + def strong_connections(self): + #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + index_counter = [0] + stack = [] + lowlinks = {} + index = {} + result = [] + + graph = self._succs + + def strongconnect(node): + # set the depth index for this node to the smallest unused index + index[node] = index_counter[0] + lowlinks[node] = index_counter[0] + index_counter[0] += 1 + stack.append(node) + + # Consider successors + try: + successors = graph[node] + except Exception: + successors = [] + for successor in successors: + if successor not in lowlinks: + # Successor has not yet been visited + strongconnect(successor) + lowlinks[node] = min(lowlinks[node],lowlinks[successor]) + elif successor in stack: + # the successor is in the stack and hence in the current + # strongly connected component (SCC) + lowlinks[node] = min(lowlinks[node],index[successor]) + + # If `node` is a root node, pop the stack and generate an SCC + if lowlinks[node] == index[node]: + connected_component = [] + + while True: + successor = stack.pop() + connected_component.append(successor) + if successor == node: break + component = tuple(connected_component) + # storing the result + result.append(component) + + for node in graph: + if node not in lowlinks: + strongconnect(node) + + return result + + @property + def dot(self): + result = ['digraph G {'] + for succ in self._preds: + preds = self._preds[succ] + for pred in preds: + result.append(' %s -> %s;' % (pred, succ)) + for node in self._nodes: + result.append(' %s;' % node) + result.append('}') + return '\n'.join(result) + +# +# Unarchiving functionality for zip, tar, tgz, tbz, whl +# + +ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', + '.tgz', '.tbz', '.whl') + +def unarchive(archive_filename, dest_dir, format=None, check=True): + + def check_path(path): + if not isinstance(path, text_type): + path = path.decode('utf-8') + p = os.path.abspath(os.path.join(dest_dir, path)) + if not p.startswith(dest_dir) or p[plen] != os.sep: + raise ValueError('path outside destination: %r' % p) + + dest_dir = os.path.abspath(dest_dir) + plen = len(dest_dir) + archive = None + if format is None: + if archive_filename.endswith(('.zip', '.whl')): + format = 'zip' + elif archive_filename.endswith(('.tar.gz', '.tgz')): + format = 'tgz' + mode = 'r:gz' + elif archive_filename.endswith(('.tar.bz2', '.tbz')): + format = 'tbz' + mode = 'r:bz2' + elif archive_filename.endswith('.tar'): + format = 'tar' + mode = 'r' + else: # pragma: no cover + raise ValueError('Unknown format for %r' % archive_filename) + try: + if format == 'zip': + archive = ZipFile(archive_filename, 'r') + if check: + names = archive.namelist() + for name in names: + check_path(name) + else: + archive = tarfile.open(archive_filename, mode) + if check: + names = archive.getnames() + for name in names: + check_path(name) + if format != 'zip' and sys.version_info[0] < 3: + # See Python issue 17153. If the dest path contains Unicode, + # tarfile extraction fails on Python 2.x if a member path name + # contains non-ASCII characters - it leads to an implicit + # bytes -> unicode conversion using ASCII to decode. + for tarinfo in archive.getmembers(): + if not isinstance(tarinfo.name, text_type): + tarinfo.name = tarinfo.name.decode('utf-8') + archive.extractall(dest_dir) + + finally: + if archive: + archive.close() + + +def zip_dir(directory): + """zip a directory tree into a BytesIO object""" + result = io.BytesIO() + dlen = len(directory) + with ZipFile(result, "w") as zf: + for root, dirs, files in os.walk(directory): + for name in files: + full = os.path.join(root, name) + rel = root[dlen:] + dest = os.path.join(rel, name) + zf.write(full, dest) + return result + +# +# Simple progress bar +# + +UNITS = ('', 'K', 'M', 'G','T','P') + + +class Progress(object): + unknown = 'UNKNOWN' + + def __init__(self, minval=0, maxval=100): + assert maxval is None or maxval >= minval + self.min = self.cur = minval + self.max = maxval + self.started = None + self.elapsed = 0 + self.done = False + + def update(self, curval): + assert self.min <= curval + assert self.max is None or curval <= self.max + self.cur = curval + now = time.time() + if self.started is None: + self.started = now + else: + self.elapsed = now - self.started + + def increment(self, incr): + assert incr >= 0 + self.update(self.cur + incr) + + def start(self): + self.update(self.min) + return self + + def stop(self): + if self.max is not None: + self.update(self.max) + self.done = True + + @property + def maximum(self): + return self.unknown if self.max is None else self.max + + @property + def percentage(self): + if self.done: + result = '100 %' + elif self.max is None: + result = ' ?? %' + else: + v = 100.0 * (self.cur - self.min) / (self.max - self.min) + result = '%3d %%' % v + return result + + def format_duration(self, duration): + if (duration <= 0) and self.max is None or self.cur == self.min: + result = '??:??:??' + #elif duration < 1: + # result = '--:--:--' + else: + result = time.strftime('%H:%M:%S', time.gmtime(duration)) + return result + + @property + def ETA(self): + if self.done: + prefix = 'Done' + t = self.elapsed + #import pdb; pdb.set_trace() + else: + prefix = 'ETA ' + if self.max is None: + t = -1 + elif self.elapsed == 0 or (self.cur == self.min): + t = 0 + else: + #import pdb; pdb.set_trace() + t = float(self.max - self.min) + t /= self.cur - self.min + t = (t - 1) * self.elapsed + return '%s: %s' % (prefix, self.format_duration(t)) + + @property + def speed(self): + if self.elapsed == 0: + result = 0.0 + else: + result = (self.cur - self.min) / self.elapsed + for unit in UNITS: + if result < 1000: + break + result /= 1000.0 + return '%d %sB/s' % (result, unit) + +# +# Glob functionality +# + +RICH_GLOB = re.compile(r'\{([^}]*)\}') +_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]') +_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$') + + +def iglob(path_glob): + """Extended globbing function that supports ** and {opt1,opt2,opt3}.""" + if _CHECK_RECURSIVE_GLOB.search(path_glob): + msg = """invalid glob %r: recursive glob "**" must be used alone""" + raise ValueError(msg % path_glob) + if _CHECK_MISMATCH_SET.search(path_glob): + msg = """invalid glob %r: mismatching set marker '{' or '}'""" + raise ValueError(msg % path_glob) + return _iglob(path_glob) + + +def _iglob(path_glob): + rich_path_glob = RICH_GLOB.split(path_glob, 1) + if len(rich_path_glob) > 1: + assert len(rich_path_glob) == 3, rich_path_glob + prefix, set, suffix = rich_path_glob + for item in set.split(','): + for path in _iglob(''.join((prefix, item, suffix))): + yield path + else: + if '**' not in path_glob: + for item in std_iglob(path_glob): + yield item + else: + prefix, radical = path_glob.split('**', 1) + if prefix == '': + prefix = '.' + if radical == '': + radical = '*' + else: + # we support both + radical = radical.lstrip('/') + radical = radical.lstrip('\\') + for path, dir, files in os.walk(prefix): + path = os.path.normpath(path) + for fn in _iglob(os.path.join(path, radical)): + yield fn + +if ssl: + from .compat import (HTTPSHandler as BaseHTTPSHandler, match_hostname, + CertificateError) + + +# +# HTTPSConnection which verifies certificates/matches domains +# + + class HTTPSConnection(httplib.HTTPSConnection): + ca_certs = None # set this to the path to the certs file (.pem) + check_domain = True # only used if ca_certs is not None + + # noinspection PyPropertyAccess + def connect(self): + sock = socket.create_connection((self.host, self.port), self.timeout) + if getattr(self, '_tunnel_host', False): + self.sock = sock + self._tunnel() + + if not hasattr(ssl, 'SSLContext'): + # For 2.x + if self.ca_certs: + cert_reqs = ssl.CERT_REQUIRED + else: + cert_reqs = ssl.CERT_NONE + self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, + cert_reqs=cert_reqs, + ssl_version=ssl.PROTOCOL_SSLv23, + ca_certs=self.ca_certs) + else: # pragma: no cover + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + context.options |= ssl.OP_NO_SSLv2 + if self.cert_file: + context.load_cert_chain(self.cert_file, self.key_file) + kwargs = {} + if self.ca_certs: + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(cafile=self.ca_certs) + if getattr(ssl, 'HAS_SNI', False): + kwargs['server_hostname'] = self.host + self.sock = context.wrap_socket(sock, **kwargs) + if self.ca_certs and self.check_domain: + try: + match_hostname(self.sock.getpeercert(), self.host) + logger.debug('Host verified: %s', self.host) + except CertificateError: # pragma: no cover + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + + class HTTPSHandler(BaseHTTPSHandler): + def __init__(self, ca_certs, check_domain=True): + BaseHTTPSHandler.__init__(self) + self.ca_certs = ca_certs + self.check_domain = check_domain + + def _conn_maker(self, *args, **kwargs): + """ + This is called to create a connection instance. Normally you'd + pass a connection class to do_open, but it doesn't actually check for + a class, and just expects a callable. As long as we behave just as a + constructor would have, we should be OK. If it ever changes so that + we *must* pass a class, we'll create an UnsafeHTTPSConnection class + which just sets check_domain to False in the class definition, and + choose which one to pass to do_open. + """ + result = HTTPSConnection(*args, **kwargs) + if self.ca_certs: + result.ca_certs = self.ca_certs + result.check_domain = self.check_domain + return result + + def https_open(self, req): + try: + return self.do_open(self._conn_maker, req) + except URLError as e: + if 'certificate verify failed' in str(e.reason): + raise CertificateError('Unable to verify server certificate ' + 'for %s' % req.host) + else: + raise + + # + # To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The- + # Middle proxy using HTTP listens on port 443, or an index mistakenly serves + # HTML containing a http://xyz link when it should be https://xyz), + # you can use the following handler class, which does not allow HTTP traffic. + # + # It works by inheriting from HTTPHandler - so build_opener won't add a + # handler for HTTP itself. + # + class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler): + def http_open(self, req): + raise URLError('Unexpected HTTP request on what should be a secure ' + 'connection: %s' % req) + +# +# XML-RPC with timeouts +# + +_ver_info = sys.version_info[:2] + +if _ver_info == (2, 6): + class HTTP(httplib.HTTP): + def __init__(self, host='', port=None, **kwargs): + if port == 0: # 0 means use port 0, not the default port + port = None + self._setup(self._connection_class(host, port, **kwargs)) + + + if ssl: + class HTTPS(httplib.HTTPS): + def __init__(self, host='', port=None, **kwargs): + if port == 0: # 0 means use port 0, not the default port + port = None + self._setup(self._connection_class(host, port, **kwargs)) + + +class Transport(xmlrpclib.Transport): + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.Transport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, x509 = self.get_host_info(host) + if _ver_info == (2, 6): + result = HTTP(h, timeout=self.timeout) + else: + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPConnection(h) + result = self._connection[1] + return result + +if ssl: + class SafeTransport(xmlrpclib.SafeTransport): + def __init__(self, timeout, use_datetime=0): + self.timeout = timeout + xmlrpclib.SafeTransport.__init__(self, use_datetime) + + def make_connection(self, host): + h, eh, kwargs = self.get_host_info(host) + if not kwargs: + kwargs = {} + kwargs['timeout'] = self.timeout + if _ver_info == (2, 6): + result = HTTPS(host, None, **kwargs) + else: + if not self._connection or host != self._connection[0]: + self._extra_headers = eh + self._connection = host, httplib.HTTPSConnection(h, None, + **kwargs) + result = self._connection[1] + return result + + +class ServerProxy(xmlrpclib.ServerProxy): + def __init__(self, uri, **kwargs): + self.timeout = timeout = kwargs.pop('timeout', None) + # The above classes only come into play if a timeout + # is specified + if timeout is not None: + scheme, _ = splittype(uri) + use_datetime = kwargs.get('use_datetime', 0) + if scheme == 'https': + tcls = SafeTransport + else: + tcls = Transport + kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime) + self.transport = t + xmlrpclib.ServerProxy.__init__(self, uri, **kwargs) + +# +# CSV functionality. This is provided because on 2.x, the csv module can't +# handle Unicode. However, we need to deal with Unicode in e.g. RECORD files. +# + +def _csv_open(fn, mode, **kwargs): + if sys.version_info[0] < 3: + mode += 'b' + else: + kwargs['newline'] = '' + # Python 3 determines encoding from locale. Force 'utf-8' + # file encoding to match other forced utf-8 encoding + kwargs['encoding'] = 'utf-8' + return open(fn, mode, **kwargs) + + +class CSVBase(object): + defaults = { + 'delimiter': str(','), # The strs are used because we need native + 'quotechar': str('"'), # str in the csv API (2.x won't take + 'lineterminator': str('\n') # Unicode) + } + + def __enter__(self): + return self + + def __exit__(self, *exc_info): + self.stream.close() + + +class CSVReader(CSVBase): + def __init__(self, **kwargs): + if 'stream' in kwargs: + stream = kwargs['stream'] + if sys.version_info[0] >= 3: + # needs to be a text stream + stream = codecs.getreader('utf-8')(stream) + self.stream = stream + else: + self.stream = _csv_open(kwargs['path'], 'r') + self.reader = csv.reader(self.stream, **self.defaults) + + def __iter__(self): + return self + + def next(self): + result = next(self.reader) + if sys.version_info[0] < 3: + for i, item in enumerate(result): + if not isinstance(item, text_type): + result[i] = item.decode('utf-8') + return result + + __next__ = next + +class CSVWriter(CSVBase): + def __init__(self, fn, **kwargs): + self.stream = _csv_open(fn, 'w') + self.writer = csv.writer(self.stream, **self.defaults) + + def writerow(self, row): + if sys.version_info[0] < 3: + r = [] + for item in row: + if isinstance(item, text_type): + item = item.encode('utf-8') + r.append(item) + row = r + self.writer.writerow(row) + +# +# Configurator functionality +# + +class Configurator(BaseConfigurator): + + value_converters = dict(BaseConfigurator.value_converters) + value_converters['inc'] = 'inc_convert' + + def __init__(self, config, base=None): + super(Configurator, self).__init__(config) + self.base = base or os.getcwd() + + def configure_custom(self, config): + def convert(o): + if isinstance(o, (list, tuple)): + result = type(o)([convert(i) for i in o]) + elif isinstance(o, dict): + if '()' in o: + result = self.configure_custom(o) + else: + result = {} + for k in o: + result[k] = convert(o[k]) + else: + result = self.convert(o) + return result + + c = config.pop('()') + if not callable(c): + c = self.resolve(c) + props = config.pop('.', None) + # Check for valid identifiers + args = config.pop('[]', ()) + if args: + args = tuple([convert(o) for o in args]) + items = [(k, convert(config[k])) for k in config if valid_ident(k)] + kwargs = dict(items) + result = c(*args, **kwargs) + if props: + for n, v in props.items(): + setattr(result, n, convert(v)) + return result + + def __getitem__(self, key): + result = self.config[key] + if isinstance(result, dict) and '()' in result: + self.config[key] = result = self.configure_custom(result) + return result + + def inc_convert(self, value): + """Default converter for the inc:// protocol.""" + if not os.path.isabs(value): + value = os.path.join(self.base, value) + with codecs.open(value, 'r', encoding='utf-8') as f: + result = json.load(f) + return result + + +class SubprocessMixin(object): + """ + Mixin for running subprocesses and capturing their output + """ + def __init__(self, verbose=False, progress=None): + self.verbose = verbose + self.progress = progress + + def reader(self, stream, context): + """ + Read lines from a subprocess' output stream and either pass to a progress + callable (if specified) or write progress information to sys.stderr. + """ + progress = self.progress + verbose = self.verbose + while True: + s = stream.readline() + if not s: + break + if progress is not None: + progress(s, context) + else: + if not verbose: + sys.stderr.write('.') + else: + sys.stderr.write(s.decode('utf-8')) + sys.stderr.flush() + stream.close() + + def run_command(self, cmd, **kwargs): + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, **kwargs) + t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout')) + t1.start() + t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr')) + t2.start() + p.wait() + t1.join() + t2.join() + if self.progress is not None: + self.progress('done.', 'main') + elif self.verbose: + sys.stderr.write('done.\n') + return p + + +def normalize_name(name): + """Normalize a python package name a la PEP 503""" + # https://www.python.org/dev/peps/pep-0503/#normalized-names + return re.sub('[-_.]+', '-', name).lower() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py new file mode 100755 index 0000000..959f153 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/version.py @@ -0,0 +1,736 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2017 The Python Software Foundation. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +""" +Implementation of a flexible versioning scheme providing support for PEP-440, +setuptools-compatible and semantic versioning. +""" + +import logging +import re + +from .compat import string_types +from .util import parse_requirement + +__all__ = ['NormalizedVersion', 'NormalizedMatcher', + 'LegacyVersion', 'LegacyMatcher', + 'SemanticVersion', 'SemanticMatcher', + 'UnsupportedVersionError', 'get_scheme'] + +logger = logging.getLogger(__name__) + + +class UnsupportedVersionError(ValueError): + """This is an unsupported version.""" + pass + + +class Version(object): + def __init__(self, s): + self._string = s = s.strip() + self._parts = parts = self.parse(s) + assert isinstance(parts, tuple) + assert len(parts) > 0 + + def parse(self, s): + raise NotImplementedError('please implement in a subclass') + + def _check_compatible(self, other): + if type(self) != type(other): + raise TypeError('cannot compare %r and %r' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + def __lt__(self, other): + self._check_compatible(other) + return self._parts < other._parts + + def __gt__(self, other): + return not (self.__lt__(other) or self.__eq__(other)) + + def __le__(self, other): + return self.__lt__(other) or self.__eq__(other) + + def __ge__(self, other): + return self.__gt__(other) or self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self._parts) + + def __repr__(self): + return "%s('%s')" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + @property + def is_prerelease(self): + raise NotImplementedError('Please implement in subclasses.') + + +class Matcher(object): + version_class = None + + # value is either a callable or the name of a method + _operators = { + '<': lambda v, c, p: v < c, + '>': lambda v, c, p: v > c, + '<=': lambda v, c, p: v == c or v < c, + '>=': lambda v, c, p: v == c or v > c, + '==': lambda v, c, p: v == c, + '===': lambda v, c, p: v == c, + # by default, compatible => >=. + '~=': lambda v, c, p: v == c or v > c, + '!=': lambda v, c, p: v != c, + } + + # this is a method only to support alternative implementations + # via overriding + def parse_requirement(self, s): + return parse_requirement(s) + + def __init__(self, s): + if self.version_class is None: + raise ValueError('Please specify a version class') + self._string = s = s.strip() + r = self.parse_requirement(s) + if not r: + raise ValueError('Not valid: %r' % s) + self.name = r.name + self.key = self.name.lower() # for case-insensitive comparisons + clist = [] + if r.constraints: + # import pdb; pdb.set_trace() + for op, s in r.constraints: + if s.endswith('.*'): + if op not in ('==', '!='): + raise ValueError('\'.*\' not allowed for ' + '%r constraints' % op) + # Could be a partial version (e.g. for '2.*') which + # won't parse as a version, so keep it as a string + vn, prefix = s[:-2], True + # Just to check that vn is a valid version + self.version_class(vn) + else: + # Should parse as a version, so we can create an + # instance for the comparison + vn, prefix = self.version_class(s), False + clist.append((op, vn, prefix)) + self._parts = tuple(clist) + + def match(self, version): + """ + Check if the provided version matches the constraints. + + :param version: The version to match against this instance. + :type version: String or :class:`Version` instance. + """ + if isinstance(version, string_types): + version = self.version_class(version) + for operator, constraint, prefix in self._parts: + f = self._operators.get(operator) + if isinstance(f, string_types): + f = getattr(self, f) + if not f: + msg = ('%r not implemented ' + 'for %s' % (operator, self.__class__.__name__)) + raise NotImplementedError(msg) + if not f(version, constraint, prefix): + return False + return True + + @property + def exact_version(self): + result = None + if len(self._parts) == 1 and self._parts[0][0] in ('==', '==='): + result = self._parts[0][1] + return result + + def _check_compatible(self, other): + if type(self) != type(other) or self.name != other.name: + raise TypeError('cannot compare %s and %s' % (self, other)) + + def __eq__(self, other): + self._check_compatible(other) + return self.key == other.key and self._parts == other._parts + + def __ne__(self, other): + return not self.__eq__(other) + + # See http://docs.python.org/reference/datamodel#object.__hash__ + def __hash__(self): + return hash(self.key) + hash(self._parts) + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self._string) + + def __str__(self): + return self._string + + +PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|b|c|rc)(\d+))?' + r'(\.(post)(\d+))?(\.(dev)(\d+))?' + r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$') + + +def _pep_440_key(s): + s = s.strip() + m = PEP440_VERSION_RE.match(s) + if not m: + raise UnsupportedVersionError('Not a valid version: %s' % s) + groups = m.groups() + nums = tuple(int(v) for v in groups[1].split('.')) + while len(nums) > 1 and nums[-1] == 0: + nums = nums[:-1] + + if not groups[0]: + epoch = 0 + else: + epoch = int(groups[0]) + pre = groups[4:6] + post = groups[7:9] + dev = groups[10:12] + local = groups[13] + if pre == (None, None): + pre = () + else: + pre = pre[0], int(pre[1]) + if post == (None, None): + post = () + else: + post = post[0], int(post[1]) + if dev == (None, None): + dev = () + else: + dev = dev[0], int(dev[1]) + if local is None: + local = () + else: + parts = [] + for part in local.split('.'): + # to ensure that numeric compares as > lexicographic, avoid + # comparing them directly, but encode a tuple which ensures + # correct sorting + if part.isdigit(): + part = (1, int(part)) + else: + part = (0, part) + parts.append(part) + local = tuple(parts) + if not pre: + # either before pre-release, or final release and after + if not post and dev: + # before pre-release + pre = ('a', -1) # to sort before a0 + else: + pre = ('z',) # to sort after all pre-releases + # now look at the state of post and dev. + if not post: + post = ('_',) # sort before 'a' + if not dev: + dev = ('final',) + + #print('%s -> %s' % (s, m.groups())) + return epoch, nums, pre, post, dev, local + + +_normalized_key = _pep_440_key + + +class NormalizedVersion(Version): + """A rational version. + + Good: + 1.2 # equivalent to "1.2.0" + 1.2.0 + 1.2a1 + 1.2.3a2 + 1.2.3b1 + 1.2.3c1 + 1.2.3.4 + TODO: fill this out + + Bad: + 1 # minimum two numbers + 1.2a # release level must have a release serial + 1.2.3b + """ + def parse(self, s): + result = _normalized_key(s) + # _normalized_key loses trailing zeroes in the release + # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0 + # However, PEP 440 prefix matching needs it: for example, + # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0). + m = PEP440_VERSION_RE.match(s) # must succeed + groups = m.groups() + self._release_clause = tuple(int(v) for v in groups[1].split('.')) + return result + + PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev']) + + @property + def is_prerelease(self): + return any(t[0] in self.PREREL_TAGS for t in self._parts if t) + + +def _match_prefix(x, y): + x = str(x) + y = str(y) + if x == y: + return True + if not x.startswith(y): + return False + n = len(y) + return x[n] == '.' + + +class NormalizedMatcher(Matcher): + version_class = NormalizedVersion + + # value is either a callable or the name of a method + _operators = { + '~=': '_match_compatible', + '<': '_match_lt', + '>': '_match_gt', + '<=': '_match_le', + '>=': '_match_ge', + '==': '_match_eq', + '===': '_match_arbitrary', + '!=': '_match_ne', + } + + def _adjust_local(self, version, constraint, prefix): + if prefix: + strip_local = '+' not in constraint and version._parts[-1] + else: + # both constraint and version are + # NormalizedVersion instances. + # If constraint does not have a local component, + # ensure the version doesn't, either. + strip_local = not constraint._parts[-1] and version._parts[-1] + if strip_local: + s = version._string.split('+', 1)[0] + version = self.version_class(s) + return version, constraint + + def _match_lt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version >= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_gt(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version <= constraint: + return False + release_clause = constraint._release_clause + pfx = '.'.join([str(i) for i in release_clause]) + return not _match_prefix(version, pfx) + + def _match_le(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version <= constraint + + def _match_ge(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + return version >= constraint + + def _match_eq(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version == constraint) + else: + result = _match_prefix(version, constraint) + return result + + def _match_arbitrary(self, version, constraint, prefix): + return str(version) == str(constraint) + + def _match_ne(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if not prefix: + result = (version != constraint) + else: + result = not _match_prefix(version, constraint) + return result + + def _match_compatible(self, version, constraint, prefix): + version, constraint = self._adjust_local(version, constraint, prefix) + if version == constraint: + return True + if version < constraint: + return False +# if not prefix: +# return True + release_clause = constraint._release_clause + if len(release_clause) > 1: + release_clause = release_clause[:-1] + pfx = '.'.join([str(i) for i in release_clause]) + return _match_prefix(version, pfx) + +_REPLACEMENTS = ( + (re.compile('[.+-]$'), ''), # remove trailing puncts + (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start + (re.compile('^[.-]'), ''), # remove leading puncts + (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses + (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion) + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha + (re.compile(r'\b(pre-alpha|prealpha)\b'), + 'pre.alpha'), # standardise + (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses +) + +_SUFFIX_REPLACEMENTS = ( + (re.compile('^[:~._+-]+'), ''), # remove leading puncts + (re.compile('[,*")([\\]]'), ''), # remove unwanted chars + (re.compile('[~:+_ -]'), '.'), # replace illegal chars + (re.compile('[.]{2,}'), '.'), # multiple runs of '.' + (re.compile(r'\.$'), ''), # trailing '.' +) + +_NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)') + + +def _suggest_semantic_version(s): + """ + Try to suggest a semantic form for a version for which + _suggest_normalized_version couldn't come up with anything. + """ + result = s.strip().lower() + for pat, repl in _REPLACEMENTS: + result = pat.sub(repl, result) + if not result: + result = '0.0.0' + + # Now look for numeric prefix, and separate it out from + # the rest. + #import pdb; pdb.set_trace() + m = _NUMERIC_PREFIX.match(result) + if not m: + prefix = '0.0.0' + suffix = result + else: + prefix = m.groups()[0].split('.') + prefix = [int(i) for i in prefix] + while len(prefix) < 3: + prefix.append(0) + if len(prefix) == 3: + suffix = result[m.end():] + else: + suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():] + prefix = prefix[:3] + prefix = '.'.join([str(i) for i in prefix]) + suffix = suffix.strip() + if suffix: + #import pdb; pdb.set_trace() + # massage the suffix. + for pat, repl in _SUFFIX_REPLACEMENTS: + suffix = pat.sub(repl, suffix) + + if not suffix: + result = prefix + else: + sep = '-' if 'dev' in suffix else '+' + result = prefix + sep + suffix + if not is_semver(result): + result = None + return result + + +def _suggest_normalized_version(s): + """Suggest a normalized version close to the given version string. + + If you have a version string that isn't rational (i.e. NormalizedVersion + doesn't like it) then you might be able to get an equivalent (or close) + rational version from this function. + + This does a number of simple normalizations to the given string, based + on observation of versions currently in use on PyPI. Given a dump of + those version during PyCon 2009, 4287 of them: + - 2312 (53.93%) match NormalizedVersion without change + with the automatic suggestion + - 3474 (81.04%) match when using this suggestion method + + @param s {str} An irrational version string. + @returns A rational version string, or None, if couldn't determine one. + """ + try: + _normalized_key(s) + return s # already rational + except UnsupportedVersionError: + pass + + rs = s.lower() + + # part of this could use maketrans + for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), + ('beta', 'b'), ('rc', 'c'), ('-final', ''), + ('-pre', 'c'), + ('-release', ''), ('.release', ''), ('-stable', ''), + ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), + ('final', '')): + rs = rs.replace(orig, repl) + + # if something ends with dev or pre, we add a 0 + rs = re.sub(r"pre$", r"pre0", rs) + rs = re.sub(r"dev$", r"dev0", rs) + + # if we have something like "b-2" or "a.2" at the end of the + # version, that is probably beta, alpha, etc + # let's remove the dash or dot + rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs) + + # 1.0-dev-r371 -> 1.0.dev371 + # 0.1-dev-r79 -> 0.1.dev79 + rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) + + # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 + rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) + + # Clean: v0.3, v1.0 + if rs.startswith('v'): + rs = rs[1:] + + # Clean leading '0's on numbers. + #TODO: unintended side-effect on, e.g., "2003.05.09" + # PyPI stats: 77 (~2%) better + rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) + + # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers + # zero. + # PyPI stats: 245 (7.56%) better + rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) + + # the 'dev-rNNN' tag is a dev tag + rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) + + # clean the - when used as a pre delimiter + rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) + + # a terminal "dev" or "devel" can be changed into ".dev0" + rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) + + # a terminal "dev" can be changed into ".dev0" + rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) + + # a terminal "final" or "stable" can be removed + rs = re.sub(r"(final|stable)$", "", rs) + + # The 'r' and the '-' tags are post release tags + # 0.4a1.r10 -> 0.4a1.post10 + # 0.9.33-17222 -> 0.9.33.post17222 + # 0.9.33-r17222 -> 0.9.33.post17222 + rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) + + # Clean 'r' instead of 'dev' usage: + # 0.9.33+r17222 -> 0.9.33.dev17222 + # 1.0dev123 -> 1.0.dev123 + # 1.0.git123 -> 1.0.dev123 + # 1.0.bzr123 -> 1.0.dev123 + # 0.1a0dev.123 -> 0.1a0.dev123 + # PyPI stats: ~150 (~4%) better + rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) + + # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: + # 0.2.pre1 -> 0.2c1 + # 0.2-c1 -> 0.2c1 + # 1.0preview123 -> 1.0c123 + # PyPI stats: ~21 (0.62%) better + rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) + + # Tcl/Tk uses "px" for their post release markers + rs = re.sub(r"p(\d+)$", r".post\1", rs) + + try: + _normalized_key(rs) + except UnsupportedVersionError: + rs = None + return rs + +# +# Legacy version processing (distribute-compatible) +# + +_VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I) +_VERSION_REPLACE = { + 'pre': 'c', + 'preview': 'c', + '-': 'final-', + 'rc': 'c', + 'dev': '@', + '': None, + '.': None, +} + + +def _legacy_key(s): + def get_parts(s): + result = [] + for p in _VERSION_PART.split(s.lower()): + p = _VERSION_REPLACE.get(p, p) + if p: + if '0' <= p[:1] <= '9': + p = p.zfill(8) + else: + p = '*' + p + result.append(p) + result.append('*final') + return result + + result = [] + for p in get_parts(s): + if p.startswith('*'): + if p < '*final': + while result and result[-1] == '*final-': + result.pop() + while result and result[-1] == '00000000': + result.pop() + result.append(p) + return tuple(result) + + +class LegacyVersion(Version): + def parse(self, s): + return _legacy_key(s) + + @property + def is_prerelease(self): + result = False + for x in self._parts: + if (isinstance(x, string_types) and x.startswith('*') and + x < '*final'): + result = True + break + return result + + +class LegacyMatcher(Matcher): + version_class = LegacyVersion + + _operators = dict(Matcher._operators) + _operators['~='] = '_match_compatible' + + numeric_re = re.compile(r'^(\d+(\.\d+)*)') + + def _match_compatible(self, version, constraint, prefix): + if version < constraint: + return False + m = self.numeric_re.match(str(constraint)) + if not m: + logger.warning('Cannot compute compatible match for version %s ' + ' and constraint %s', version, constraint) + return True + s = m.groups()[0] + if '.' in s: + s = s.rsplit('.', 1)[0] + return _match_prefix(version, s) + +# +# Semantic versioning +# + +_SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)' + r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?' + r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I) + + +def is_semver(s): + return _SEMVER_RE.match(s) + + +def _semantic_key(s): + def make_tuple(s, absent): + if s is None: + result = (absent,) + else: + parts = s[1:].split('.') + # We can't compare ints and strings on Python 3, so fudge it + # by zero-filling numeric values so simulate a numeric comparison + result = tuple([p.zfill(8) if p.isdigit() else p for p in parts]) + return result + + m = is_semver(s) + if not m: + raise UnsupportedVersionError(s) + groups = m.groups() + major, minor, patch = [int(i) for i in groups[:3]] + # choose the '|' and '*' so that versions sort correctly + pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*') + return (major, minor, patch), pre, build + + +class SemanticVersion(Version): + def parse(self, s): + return _semantic_key(s) + + @property + def is_prerelease(self): + return self._parts[1][0] != '|' + + +class SemanticMatcher(Matcher): + version_class = SemanticVersion + + +class VersionScheme(object): + def __init__(self, key, matcher, suggester=None): + self.key = key + self.matcher = matcher + self.suggester = suggester + + def is_valid_version(self, s): + try: + self.matcher.version_class(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_matcher(self, s): + try: + self.matcher(s) + result = True + except UnsupportedVersionError: + result = False + return result + + def is_valid_constraint_list(self, s): + """ + Used for processing some metadata fields + """ + return self.is_valid_matcher('dummy_name (%s)' % s) + + def suggest(self, s): + if self.suggester is None: + result = None + else: + result = self.suggester(s) + return result + +_SCHEMES = { + 'normalized': VersionScheme(_normalized_key, NormalizedMatcher, + _suggest_normalized_version), + 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s), + 'semantic': VersionScheme(_semantic_key, SemanticMatcher, + _suggest_semantic_version), +} + +_SCHEMES['default'] = _SCHEMES['normalized'] + + +def get_scheme(name): + if name not in _SCHEMES: + raise ValueError('unknown scheme name: %r' % name) + return _SCHEMES[name] diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe new file mode 100755 index 0000000..732215a Binary files /dev/null and b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w32.exe differ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe new file mode 100755 index 0000000..c41bd0a Binary files /dev/null and b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/w64.exe differ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py new file mode 100755 index 0000000..3693410 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distlib/wheel.py @@ -0,0 +1,984 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Vinay Sajip. +# Licensed to the Python Software Foundation under a contributor agreement. +# See LICENSE.txt and CONTRIBUTORS.txt. +# +from __future__ import unicode_literals + +import base64 +import codecs +import datetime +import distutils.util +from email import message_from_file +import hashlib +import imp +import json +import logging +import os +import posixpath +import re +import shutil +import sys +import tempfile +import zipfile + +from . import __version__, DistlibException +from .compat import sysconfig, ZipFile, fsdecode, text_type, filter +from .database import InstalledDistribution +from .metadata import Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME +from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, + cached_property, get_cache_base, read_exports, tempdir) +from .version import NormalizedVersion, UnsupportedVersionError + +logger = logging.getLogger(__name__) + +cache = None # created when needed + +if hasattr(sys, 'pypy_version_info'): # pragma: no cover + IMP_PREFIX = 'pp' +elif sys.platform.startswith('java'): # pragma: no cover + IMP_PREFIX = 'jy' +elif sys.platform == 'cli': # pragma: no cover + IMP_PREFIX = 'ip' +else: + IMP_PREFIX = 'cp' + +VER_SUFFIX = sysconfig.get_config_var('py_version_nodot') +if not VER_SUFFIX: # pragma: no cover + VER_SUFFIX = '%s%s' % sys.version_info[:2] +PYVER = 'py' + VER_SUFFIX +IMPVER = IMP_PREFIX + VER_SUFFIX + +ARCH = distutils.util.get_platform().replace('-', '_').replace('.', '_') + +ABI = sysconfig.get_config_var('SOABI') +if ABI and ABI.startswith('cpython-'): + ABI = ABI.replace('cpython-', 'cp') +else: + def _derive_abi(): + parts = ['cp', VER_SUFFIX] + if sysconfig.get_config_var('Py_DEBUG'): + parts.append('d') + if sysconfig.get_config_var('WITH_PYMALLOC'): + parts.append('m') + if sysconfig.get_config_var('Py_UNICODE_SIZE') == 4: + parts.append('u') + return ''.join(parts) + ABI = _derive_abi() + del _derive_abi + +FILENAME_RE = re.compile(r''' +(?P<nm>[^-]+) +-(?P<vn>\d+[^-]*) +(-(?P<bn>\d+[^-]*))? +-(?P<py>\w+\d+(\.\w+\d+)*) +-(?P<bi>\w+) +-(?P<ar>\w+(\.\w+)*) +\.whl$ +''', re.IGNORECASE | re.VERBOSE) + +NAME_VERSION_RE = re.compile(r''' +(?P<nm>[^-]+) +-(?P<vn>\d+[^-]*) +(-(?P<bn>\d+[^-]*))?$ +''', re.IGNORECASE | re.VERBOSE) + +SHEBANG_RE = re.compile(br'\s*#![^\r\n]*') +SHEBANG_DETAIL_RE = re.compile(br'^(\s*#!("[^"]+"|\S+))\s+(.*)$') +SHEBANG_PYTHON = b'#!python' +SHEBANG_PYTHONW = b'#!pythonw' + +if os.sep == '/': + to_posix = lambda o: o +else: + to_posix = lambda o: o.replace(os.sep, '/') + + +class Mounter(object): + def __init__(self): + self.impure_wheels = {} + self.libs = {} + + def add(self, pathname, extensions): + self.impure_wheels[pathname] = extensions + self.libs.update(extensions) + + def remove(self, pathname): + extensions = self.impure_wheels.pop(pathname) + for k, v in extensions: + if k in self.libs: + del self.libs[k] + + def find_module(self, fullname, path=None): + if fullname in self.libs: + result = self + else: + result = None + return result + + def load_module(self, fullname): + if fullname in sys.modules: + result = sys.modules[fullname] + else: + if fullname not in self.libs: + raise ImportError('unable to find extension for %s' % fullname) + result = imp.load_dynamic(fullname, self.libs[fullname]) + result.__loader__ = self + parts = fullname.rsplit('.', 1) + if len(parts) > 1: + result.__package__ = parts[0] + return result + +_hook = Mounter() + + +class Wheel(object): + """ + Class to build and install from Wheel files (PEP 427). + """ + + wheel_version = (1, 1) + hash_kind = 'sha256' + + def __init__(self, filename=None, sign=False, verify=False): + """ + Initialise an instance using a (valid) filename. + """ + self.sign = sign + self.should_verify = verify + self.buildver = '' + self.pyver = [PYVER] + self.abi = ['none'] + self.arch = ['any'] + self.dirname = os.getcwd() + if filename is None: + self.name = 'dummy' + self.version = '0.1' + self._filename = self.filename + else: + m = NAME_VERSION_RE.match(filename) + if m: + info = m.groupdict('') + self.name = info['nm'] + # Reinstate the local version separator + self.version = info['vn'].replace('_', '-') + self.buildver = info['bn'] + self._filename = self.filename + else: + dirname, filename = os.path.split(filename) + m = FILENAME_RE.match(filename) + if not m: + raise DistlibException('Invalid name or ' + 'filename: %r' % filename) + if dirname: + self.dirname = os.path.abspath(dirname) + self._filename = filename + info = m.groupdict('') + self.name = info['nm'] + self.version = info['vn'] + self.buildver = info['bn'] + self.pyver = info['py'].split('.') + self.abi = info['bi'].split('.') + self.arch = info['ar'].split('.') + + @property + def filename(self): + """ + Build and return a filename from the various components. + """ + if self.buildver: + buildver = '-' + self.buildver + else: + buildver = '' + pyver = '.'.join(self.pyver) + abi = '.'.join(self.abi) + arch = '.'.join(self.arch) + # replace - with _ as a local version separator + version = self.version.replace('-', '_') + return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, + pyver, abi, arch) + + @property + def exists(self): + path = os.path.join(self.dirname, self.filename) + return os.path.isfile(path) + + @property + def tags(self): + for pyver in self.pyver: + for abi in self.abi: + for arch in self.arch: + yield pyver, abi, arch + + @cached_property + def metadata(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + wrapper = codecs.getreader('utf-8') + with ZipFile(pathname, 'r') as zf: + wheel_metadata = self.get_wheel_metadata(zf) + wv = wheel_metadata['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + if file_version < (1, 1): + fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME, 'METADATA'] + else: + fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME] + result = None + for fn in fns: + try: + metadata_filename = posixpath.join(info_dir, fn) + with zf.open(metadata_filename) as bf: + wf = wrapper(bf) + result = Metadata(fileobj=wf) + if result: + break + except KeyError: + pass + if not result: + raise ValueError('Invalid wheel, because metadata is ' + 'missing: looked in %s' % ', '.join(fns)) + return result + + def get_wheel_metadata(self, zf): + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + metadata_filename = posixpath.join(info_dir, 'WHEEL') + with zf.open(metadata_filename) as bf: + wf = codecs.getreader('utf-8')(bf) + message = message_from_file(wf) + return dict(message) + + @cached_property + def info(self): + pathname = os.path.join(self.dirname, self.filename) + with ZipFile(pathname, 'r') as zf: + result = self.get_wheel_metadata(zf) + return result + + def process_shebang(self, data): + m = SHEBANG_RE.match(data) + if m: + end = m.end() + shebang, data_after_shebang = data[:end], data[end:] + # Preserve any arguments after the interpreter + if b'pythonw' in shebang.lower(): + shebang_python = SHEBANG_PYTHONW + else: + shebang_python = SHEBANG_PYTHON + m = SHEBANG_DETAIL_RE.match(shebang) + if m: + args = b' ' + m.groups()[-1] + else: + args = b'' + shebang = shebang_python + args + data = shebang + data_after_shebang + else: + cr = data.find(b'\r') + lf = data.find(b'\n') + if cr < 0 or cr > lf: + term = b'\n' + else: + if data[cr:cr + 2] == b'\r\n': + term = b'\r\n' + else: + term = b'\r' + data = SHEBANG_PYTHON + term + data + return data + + def get_hash(self, data, hash_kind=None): + if hash_kind is None: + hash_kind = self.hash_kind + try: + hasher = getattr(hashlib, hash_kind) + except AttributeError: + raise DistlibException('Unsupported hash algorithm: %r' % hash_kind) + result = hasher(data).digest() + result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') + return hash_kind, result + + def write_record(self, records, record_path, base): + records = list(records) # make a copy for sorting + p = to_posix(os.path.relpath(record_path, base)) + records.append((p, '', '')) + records.sort() + with CSVWriter(record_path) as writer: + for row in records: + writer.writerow(row) + + def write_records(self, info, libdir, archive_paths): + records = [] + distinfo, info_dir = info + hasher = getattr(hashlib, self.hash_kind) + for ap, p in archive_paths: + with open(p, 'rb') as f: + data = f.read() + digest = '%s=%s' % self.get_hash(data) + size = os.path.getsize(p) + records.append((ap, digest, size)) + + p = os.path.join(distinfo, 'RECORD') + self.write_record(records, p, libdir) + ap = to_posix(os.path.join(info_dir, 'RECORD')) + archive_paths.append((ap, p)) + + def build_zip(self, pathname, archive_paths): + with ZipFile(pathname, 'w', zipfile.ZIP_DEFLATED) as zf: + for ap, p in archive_paths: + logger.debug('Wrote %s to %s in wheel', p, ap) + zf.write(p, ap) + + def build(self, paths, tags=None, wheel_version=None): + """ + Build a wheel from files in specified paths, and use any specified tags + when determining the name of the wheel. + """ + if tags is None: + tags = {} + + libkey = list(filter(lambda o: o in paths, ('purelib', 'platlib')))[0] + if libkey == 'platlib': + is_pure = 'false' + default_pyver = [IMPVER] + default_abi = [ABI] + default_arch = [ARCH] + else: + is_pure = 'true' + default_pyver = [PYVER] + default_abi = ['none'] + default_arch = ['any'] + + self.pyver = tags.get('pyver', default_pyver) + self.abi = tags.get('abi', default_abi) + self.arch = tags.get('arch', default_arch) + + libdir = paths[libkey] + + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + archive_paths = [] + + # First, stuff which is not in site-packages + for key in ('data', 'headers', 'scripts'): + if key not in paths: + continue + path = paths[key] + if os.path.isdir(path): + for root, dirs, files in os.walk(path): + for fn in files: + p = fsdecode(os.path.join(root, fn)) + rp = os.path.relpath(p, path) + ap = to_posix(os.path.join(data_dir, key, rp)) + archive_paths.append((ap, p)) + if key == 'scripts' and not p.endswith('.exe'): + with open(p, 'rb') as f: + data = f.read() + data = self.process_shebang(data) + with open(p, 'wb') as f: + f.write(data) + + # Now, stuff which is in site-packages, other than the + # distinfo stuff. + path = libdir + distinfo = None + for root, dirs, files in os.walk(path): + if root == path: + # At the top level only, save distinfo for later + # and skip it for now + for i, dn in enumerate(dirs): + dn = fsdecode(dn) + if dn.endswith('.dist-info'): + distinfo = os.path.join(root, dn) + del dirs[i] + break + assert distinfo, '.dist-info directory expected, not found' + + for fn in files: + # comment out next suite to leave .pyc files in + if fsdecode(fn).endswith(('.pyc', '.pyo')): + continue + p = os.path.join(root, fn) + rp = to_posix(os.path.relpath(p, path)) + archive_paths.append((rp, p)) + + # Now distinfo. Assumed to be flat, i.e. os.listdir is enough. + files = os.listdir(distinfo) + for fn in files: + if fn not in ('RECORD', 'INSTALLER', 'SHARED', 'WHEEL'): + p = fsdecode(os.path.join(distinfo, fn)) + ap = to_posix(os.path.join(info_dir, fn)) + archive_paths.append((ap, p)) + + wheel_metadata = [ + 'Wheel-Version: %d.%d' % (wheel_version or self.wheel_version), + 'Generator: distlib %s' % __version__, + 'Root-Is-Purelib: %s' % is_pure, + ] + for pyver, abi, arch in self.tags: + wheel_metadata.append('Tag: %s-%s-%s' % (pyver, abi, arch)) + p = os.path.join(distinfo, 'WHEEL') + with open(p, 'w') as f: + f.write('\n'.join(wheel_metadata)) + ap = to_posix(os.path.join(info_dir, 'WHEEL')) + archive_paths.append((ap, p)) + + # Now, at last, RECORD. + # Paths in here are archive paths - nothing else makes sense. + self.write_records((distinfo, info_dir), libdir, archive_paths) + # Now, ready to build the zip file + pathname = os.path.join(self.dirname, self.filename) + self.build_zip(pathname, archive_paths) + return pathname + + def install(self, paths, maker, **kwargs): + """ + Install a wheel to the specified paths. If kwarg ``warner`` is + specified, it should be a callable, which will be called with two + tuples indicating the wheel version of this software and the wheel + version in the file, if there is a discrepancy in the versions. + This can be used to issue any warnings to raise any exceptions. + If kwarg ``lib_only`` is True, only the purelib/platlib files are + installed, and the headers, scripts, data and dist-info metadata are + not written. + + The return value is a :class:`InstalledDistribution` instance unless + ``options.lib_only`` is True, in which case the return value is ``None``. + """ + + dry_run = maker.dry_run + warner = kwargs.get('warner') + lib_only = kwargs.get('lib_only', False) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + metadata_name = posixpath.join(info_dir, METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message = message_from_file(wf) + wv = message['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + if (file_version != self.wheel_version) and warner: + warner(self.wheel_version, file_version) + + if message['Root-Is-Purelib'] == 'true': + libdir = paths['purelib'] + else: + libdir = paths['platlib'] + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + data_pfx = posixpath.join(data_dir, '') + info_pfx = posixpath.join(info_dir, '') + script_pfx = posixpath.join(data_dir, 'scripts', '') + + # make a new instance rather than a copy of maker's, + # as we mutate it + fileop = FileOperator(dry_run=dry_run) + fileop.record = True # so we can rollback if needed + + bc = not sys.dont_write_bytecode # Double negatives. Lovely! + + outfiles = [] # for RECORD writing + + # for script copying/shebang processing + workdir = tempfile.mkdtemp() + # set target dir later + # we default add_launchers to False, as the + # Python Launcher should be used instead + maker.source_dir = workdir + maker.target_dir = None + try: + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + # The signature file won't be in RECORD, + # and we don't currently don't do anything with it + if u_arcname.endswith('/RECORD.jws'): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + if lib_only and u_arcname.startswith((info_pfx, data_pfx)): + logger.debug('lib_only: skipping %s', u_arcname) + continue + is_script = (u_arcname.startswith(script_pfx) + and not u_arcname.endswith('.exe')) + + if u_arcname.startswith(data_pfx): + _, where, rp = u_arcname.split('/', 2) + outfile = os.path.join(paths[where], convert_path(rp)) + else: + # meant for site-packages. + if u_arcname in (wheel_metadata_name, record_name): + continue + outfile = os.path.join(libdir, convert_path(u_arcname)) + if not is_script: + with zf.open(arcname) as bf: + fileop.copy_stream(bf, outfile) + outfiles.append(outfile) + # Double check the digest of the written file + if not dry_run and row[1]: + with open(outfile, 'rb') as bf: + data = bf.read() + _, newdigest = self.get_hash(data, kind) + if newdigest != digest: + raise DistlibException('digest mismatch ' + 'on write for ' + '%s' % outfile) + if bc and outfile.endswith('.py'): + try: + pyc = fileop.byte_compile(outfile) + outfiles.append(pyc) + except Exception: + # Don't give up if byte-compilation fails, + # but log it and perhaps warn the user + logger.warning('Byte-compilation failed', + exc_info=True) + else: + fn = os.path.basename(convert_path(arcname)) + workname = os.path.join(workdir, fn) + with zf.open(arcname) as bf: + fileop.copy_stream(bf, workname) + + dn, fn = os.path.split(outfile) + maker.target_dir = dn + filenames = maker.make(fn) + fileop.set_executable_mode(filenames) + outfiles.extend(filenames) + + if lib_only: + logger.debug('lib_only: returning None') + dist = None + else: + # Generate scripts + + # Try to get pydist.json so we can see if there are + # any commands to generate. If this fails (e.g. because + # of a legacy wheel), log a warning but don't give up. + commands = None + file_version = self.info['Wheel-Version'] + if file_version == '1.0': + # Use legacy info + ep = posixpath.join(info_dir, 'entry_points.txt') + try: + with zf.open(ep) as bwf: + epdata = read_exports(bwf) + commands = {} + for key in ('console', 'gui'): + k = '%s_scripts' % key + if k in epdata: + commands['wrap_%s' % key] = d = {} + for v in epdata[k].values(): + s = '%s:%s' % (v.prefix, v.suffix) + if v.flags: + s += ' %s' % v.flags + d[v.name] = s + except Exception: + logger.warning('Unable to read legacy script ' + 'metadata, so cannot generate ' + 'scripts') + else: + try: + with zf.open(metadata_name) as bwf: + wf = wrapper(bwf) + commands = json.load(wf).get('extensions') + if commands: + commands = commands.get('python.commands') + except Exception: + logger.warning('Unable to read JSON metadata, so ' + 'cannot generate scripts') + if commands: + console_scripts = commands.get('wrap_console', {}) + gui_scripts = commands.get('wrap_gui', {}) + if console_scripts or gui_scripts: + script_dir = paths.get('scripts', '') + if not os.path.isdir(script_dir): + raise ValueError('Valid script path not ' + 'specified') + maker.target_dir = script_dir + for k, v in console_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script) + fileop.set_executable_mode(filenames) + + if gui_scripts: + options = {'gui': True } + for k, v in gui_scripts.items(): + script = '%s = %s' % (k, v) + filenames = maker.make(script, options) + fileop.set_executable_mode(filenames) + + p = os.path.join(libdir, info_dir) + dist = InstalledDistribution(p) + + # Write SHARED + paths = dict(paths) # don't change passed in dict + del paths['purelib'] + del paths['platlib'] + paths['lib'] = libdir + p = dist.write_shared_locations(paths, dry_run) + if p: + outfiles.append(p) + + # Write RECORD + dist.write_installed_files(outfiles, paths['prefix'], + dry_run) + return dist + except Exception: # pragma: no cover + logger.exception('installation failed.') + fileop.rollback() + raise + finally: + shutil.rmtree(workdir) + + def _get_dylib_cache(self): + global cache + if cache is None: + # Use native string to avoid issues on 2.x: see Python #20140. + base = os.path.join(get_cache_base(), str('dylib-cache'), + sys.version[:3]) + cache = Cache(base) + return cache + + def _get_extensions(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + arcname = posixpath.join(info_dir, 'EXTENSIONS') + wrapper = codecs.getreader('utf-8') + result = [] + with ZipFile(pathname, 'r') as zf: + try: + with zf.open(arcname) as bf: + wf = wrapper(bf) + extensions = json.load(wf) + cache = self._get_dylib_cache() + prefix = cache.prefix_to_dir(pathname) + cache_base = os.path.join(cache.base, prefix) + if not os.path.isdir(cache_base): + os.makedirs(cache_base) + for name, relpath in extensions.items(): + dest = os.path.join(cache_base, convert_path(relpath)) + if not os.path.exists(dest): + extract = True + else: + file_time = os.stat(dest).st_mtime + file_time = datetime.datetime.fromtimestamp(file_time) + info = zf.getinfo(relpath) + wheel_time = datetime.datetime(*info.date_time) + extract = wheel_time > file_time + if extract: + zf.extract(relpath, cache_base) + result.append((name, dest)) + except KeyError: + pass + return result + + def is_compatible(self): + """ + Determine if a wheel is compatible with the running system. + """ + return is_compatible(self) + + def is_mountable(self): + """ + Determine if a wheel is asserted as mountable by its metadata. + """ + return True # for now - metadata details TBD + + def mount(self, append=False): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if not self.is_compatible(): + msg = 'Wheel %s not compatible with this Python.' % pathname + raise DistlibException(msg) + if not self.is_mountable(): + msg = 'Wheel %s is marked as not mountable.' % pathname + raise DistlibException(msg) + if pathname in sys.path: + logger.debug('%s already in path', pathname) + else: + if append: + sys.path.append(pathname) + else: + sys.path.insert(0, pathname) + extensions = self._get_extensions() + if extensions: + if _hook not in sys.meta_path: + sys.meta_path.append(_hook) + _hook.add(pathname, extensions) + + def unmount(self): + pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) + if pathname not in sys.path: + logger.debug('%s not in path', pathname) + else: + sys.path.remove(pathname) + if pathname in _hook.impure_wheels: + _hook.remove(pathname) + if not _hook.impure_wheels: + if _hook in sys.meta_path: + sys.meta_path.remove(_hook) + + def verify(self): + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + data_dir = '%s.data' % name_ver + info_dir = '%s.dist-info' % name_ver + + metadata_name = posixpath.join(info_dir, METADATA_FILENAME) + wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') + record_name = posixpath.join(info_dir, 'RECORD') + + wrapper = codecs.getreader('utf-8') + + with ZipFile(pathname, 'r') as zf: + with zf.open(wheel_metadata_name) as bwf: + wf = wrapper(bwf) + message = message_from_file(wf) + wv = message['Wheel-Version'].split('.', 1) + file_version = tuple([int(i) for i in wv]) + # TODO version verification + + records = {} + with zf.open(record_name) as bf: + with CSVReader(stream=bf) as reader: + for row in reader: + p = row[0] + records[p] = row + + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if '..' in u_arcname: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + + # The signature file won't be in RECORD, + # and we don't currently don't do anything with it + if u_arcname.endswith('/RECORD.jws'): + continue + row = records[u_arcname] + if row[2] and str(zinfo.file_size) != row[2]: + raise DistlibException('size mismatch for ' + '%s' % u_arcname) + if row[1]: + kind, value = row[1].split('=', 1) + with zf.open(arcname) as bf: + data = bf.read() + _, digest = self.get_hash(data, kind) + if digest != value: + raise DistlibException('digest mismatch for ' + '%s' % arcname) + + def update(self, modifier, dest_dir=None, **kwargs): + """ + Update the contents of a wheel in a generic way. The modifier should + be a callable which expects a dictionary argument: its keys are + archive-entry paths, and its values are absolute filesystem paths + where the contents the corresponding archive entries can be found. The + modifier is free to change the contents of the files pointed to, add + new entries and remove entries, before returning. This method will + extract the entire contents of the wheel to a temporary location, call + the modifier, and then use the passed (and possibly updated) + dictionary to write a new wheel. If ``dest_dir`` is specified, the new + wheel is written there -- otherwise, the original wheel is overwritten. + + The modifier should return True if it updated the wheel, else False. + This method returns the same value the modifier returns. + """ + + def get_version(path_map, info_dir): + version = path = None + key = '%s/%s' % (info_dir, METADATA_FILENAME) + if key not in path_map: + key = '%s/PKG-INFO' % info_dir + if key in path_map: + path = path_map[key] + version = Metadata(path=path).version + return version, path + + def update_version(version, path): + updated = None + try: + v = NormalizedVersion(version) + i = version.find('-') + if i < 0: + updated = '%s+1' % version + else: + parts = [int(s) for s in version[i + 1:].split('.')] + parts[-1] += 1 + updated = '%s+%s' % (version[:i], + '.'.join(str(i) for i in parts)) + except UnsupportedVersionError: + logger.debug('Cannot update non-compliant (PEP-440) ' + 'version %r', version) + if updated: + md = Metadata(path=path) + md.version = updated + legacy = not path.endswith(METADATA_FILENAME) + md.write(path=path, legacy=legacy) + logger.debug('Version updated from %r to %r', version, + updated) + + pathname = os.path.join(self.dirname, self.filename) + name_ver = '%s-%s' % (self.name, self.version) + info_dir = '%s.dist-info' % name_ver + record_name = posixpath.join(info_dir, 'RECORD') + with tempdir() as workdir: + with ZipFile(pathname, 'r') as zf: + path_map = {} + for zinfo in zf.infolist(): + arcname = zinfo.filename + if isinstance(arcname, text_type): + u_arcname = arcname + else: + u_arcname = arcname.decode('utf-8') + if u_arcname == record_name: + continue + if '..' in u_arcname: + raise DistlibException('invalid entry in ' + 'wheel: %r' % u_arcname) + zf.extract(zinfo, workdir) + path = os.path.join(workdir, convert_path(u_arcname)) + path_map[u_arcname] = path + + # Remember the version. + original_version, _ = get_version(path_map, info_dir) + # Files extracted. Call the modifier. + modified = modifier(path_map, **kwargs) + if modified: + # Something changed - need to build a new wheel. + current_version, path = get_version(path_map, info_dir) + if current_version and (current_version == original_version): + # Add or update local version to signify changes. + update_version(current_version, path) + # Decide where the new wheel goes. + if dest_dir is None: + fd, newpath = tempfile.mkstemp(suffix='.whl', + prefix='wheel-update-', + dir=workdir) + os.close(fd) + else: + if not os.path.isdir(dest_dir): + raise DistlibException('Not a directory: %r' % dest_dir) + newpath = os.path.join(dest_dir, self.filename) + archive_paths = list(path_map.items()) + distinfo = os.path.join(workdir, info_dir) + info = distinfo, info_dir + self.write_records(info, workdir, archive_paths) + self.build_zip(newpath, archive_paths) + if dest_dir is None: + shutil.copyfile(newpath, pathname) + return modified + +def compatible_tags(): + """ + Return (pyver, abi, arch) tuples compatible with this Python. + """ + versions = [VER_SUFFIX] + major = VER_SUFFIX[0] + for minor in range(sys.version_info[1] - 1, - 1, -1): + versions.append(''.join([major, str(minor)])) + + abis = [] + for suffix, _, _ in imp.get_suffixes(): + if suffix.startswith('.abi'): + abis.append(suffix.split('.', 2)[1]) + abis.sort() + if ABI != 'none': + abis.insert(0, ABI) + abis.append('none') + result = [] + + arches = [ARCH] + if sys.platform == 'darwin': + m = re.match(r'(\w+)_(\d+)_(\d+)_(\w+)$', ARCH) + if m: + name, major, minor, arch = m.groups() + minor = int(minor) + matches = [arch] + if arch in ('i386', 'ppc'): + matches.append('fat') + if arch in ('i386', 'ppc', 'x86_64'): + matches.append('fat3') + if arch in ('ppc64', 'x86_64'): + matches.append('fat64') + if arch in ('i386', 'x86_64'): + matches.append('intel') + if arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): + matches.append('universal') + while minor >= 0: + for match in matches: + s = '%s_%s_%s_%s' % (name, major, minor, match) + if s != ARCH: # already there + arches.append(s) + minor -= 1 + + # Most specific - our Python version, ABI and arch + for abi in abis: + for arch in arches: + result.append((''.join((IMP_PREFIX, versions[0])), abi, arch)) + + # where no ABI / arch dependency, but IMP_PREFIX dependency + for i, version in enumerate(versions): + result.append((''.join((IMP_PREFIX, version)), 'none', 'any')) + if i == 0: + result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any')) + + # no IMP_PREFIX, ABI or arch dependency + for i, version in enumerate(versions): + result.append((''.join(('py', version)), 'none', 'any')) + if i == 0: + result.append((''.join(('py', version[0])), 'none', 'any')) + return set(result) + + +COMPATIBLE_TAGS = compatible_tags() + +del compatible_tags + + +def is_compatible(wheel, tags=None): + if not isinstance(wheel, Wheel): + wheel = Wheel(wheel) # assume it's a filename + result = False + if tags is None: + tags = COMPATIBLE_TAGS + for ver, abi, arch in tags: + if ver in wheel.pyver and abi in wheel.abi and arch in wheel.arch: + result = True + break + return result diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py new file mode 100755 index 0000000..0f792ea --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/distro.py @@ -0,0 +1,1104 @@ +# Copyright 2015,2016 Nir Cohen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +The ``distro`` package (``distro`` stands for Linux Distribution) provides +information about the Linux distribution it runs on, such as a reliable +machine-readable distro ID, or version information. + +It is a renewed alternative implementation for Python's original +:py:func:`platform.linux_distribution` function, but it provides much more +functionality. An alternative implementation became necessary because Python +3.5 deprecated this function, and Python 3.7 is expected to remove it +altogether. Its predecessor function :py:func:`platform.dist` was already +deprecated since Python 2.6 and is also expected to be removed in Python 3.7. +Still, there are many cases in which access to Linux distribution information +is needed. See `Python issue 1322 <https://bugs.python.org/issue1322>`_ for +more information. +""" + +import os +import re +import sys +import json +import shlex +import logging +import argparse +import subprocess + + +_UNIXCONFDIR = os.environ.get('UNIXCONFDIR', '/etc') +_OS_RELEASE_BASENAME = 'os-release' + +#: Translation table for normalizing the "ID" attribute defined in os-release +#: files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as defined in the os-release file, translated to lower case, +#: with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_OS_ID = {} + +#: Translation table for normalizing the "Distributor ID" attribute returned by +#: the lsb_release command, for use by the :func:`distro.id` method. +#: +#: * Key: Value as returned by the lsb_release command, translated to lower +#: case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_LSB_ID = { + 'enterpriseenterprise': 'oracle', # Oracle Enterprise Linux + 'redhatenterpriseworkstation': 'rhel', # RHEL 6, 7 Workstation + 'redhatenterpriseserver': 'rhel', # RHEL 6, 7 Server +} + +#: Translation table for normalizing the distro ID derived from the file name +#: of distro release files, for use by the :func:`distro.id` method. +#: +#: * Key: Value as derived from the file name of a distro release file, +#: translated to lower case, with blanks translated to underscores. +#: +#: * Value: Normalized value. +NORMALIZED_DISTRO_ID = { + 'redhat': 'rhel', # RHEL 6.x, 7.x +} + +# Pattern for content of distro release file (reversed) +_DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile( + r'(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)') + +# Pattern for base file name of distro release file +_DISTRO_RELEASE_BASENAME_PATTERN = re.compile( + r'(\w+)[-_](release|version)$') + +# Base file names to be ignored when searching for distro release file +_DISTRO_RELEASE_IGNORE_BASENAMES = ( + 'debian_version', + 'lsb-release', + 'oem-release', + _OS_RELEASE_BASENAME, + 'system-release' +) + + +def linux_distribution(full_distribution_name=True): + """ + Return information about the current Linux distribution as a tuple + ``(id_name, version, codename)`` with items as follows: + + * ``id_name``: If *full_distribution_name* is false, the result of + :func:`distro.id`. Otherwise, the result of :func:`distro.name`. + + * ``version``: The result of :func:`distro.version`. + + * ``codename``: The result of :func:`distro.codename`. + + The interface of this function is compatible with the original + :py:func:`platform.linux_distribution` function, supporting a subset of + its parameters. + + The data it returns may not exactly be the same, because it uses more data + sources than the original function, and that may lead to different data if + the Linux distribution is not consistent across multiple data sources it + provides (there are indeed such distributions ...). + + Another reason for differences is the fact that the :func:`distro.id` + method normalizes the distro ID string to a reliable machine-readable value + for a number of popular Linux distributions. + """ + return _distro.linux_distribution(full_distribution_name) + + +def id(): + """ + Return the distro ID of the current Linux distribution, as a + machine-readable string. + + For a number of Linux distributions, the returned distro ID value is + *reliable*, in the sense that it is documented and that it does not change + across releases of the distribution. + + This package maintains the following reliable distro ID values: + + ============== ========================================= + Distro ID Distribution + ============== ========================================= + "ubuntu" Ubuntu + "debian" Debian + "rhel" RedHat Enterprise Linux + "centos" CentOS + "fedora" Fedora + "sles" SUSE Linux Enterprise Server + "opensuse" openSUSE + "amazon" Amazon Linux + "arch" Arch Linux + "cloudlinux" CloudLinux OS + "exherbo" Exherbo Linux + "gentoo" GenToo Linux + "ibm_powerkvm" IBM PowerKVM + "kvmibm" KVM for IBM z Systems + "linuxmint" Linux Mint + "mageia" Mageia + "mandriva" Mandriva Linux + "parallels" Parallels + "pidora" Pidora + "raspbian" Raspbian + "oracle" Oracle Linux (and Oracle Enterprise Linux) + "scientific" Scientific Linux + "slackware" Slackware + "xenserver" XenServer + ============== ========================================= + + If you have a need to get distros for reliable IDs added into this set, + or if you find that the :func:`distro.id` function returns a different + distro ID for one of the listed distros, please create an issue in the + `distro issue tracker`_. + + **Lookup hierarchy and transformations:** + + First, the ID is obtained from the following sources, in the specified + order. The first available and non-empty value is used: + + * the value of the "ID" attribute of the os-release file, + + * the value of the "Distributor ID" attribute returned by the lsb_release + command, + + * the first part of the file name of the distro release file, + + The so determined ID value then passes the following transformations, + before it is returned by this method: + + * it is translated to lower case, + + * blanks (which should not be there anyway) are translated to underscores, + + * a normalization of the ID is performed, based upon + `normalization tables`_. The purpose of this normalization is to ensure + that the ID is as reliable as possible, even across incompatible changes + in the Linux distributions. A common reason for an incompatible change is + the addition of an os-release file, or the addition of the lsb_release + command, with ID values that differ from what was previously determined + from the distro release file name. + """ + return _distro.id() + + +def name(pretty=False): + """ + Return the name of the current Linux distribution, as a human-readable + string. + + If *pretty* is false, the name is returned without version or codename. + (e.g. "CentOS Linux") + + If *pretty* is true, the version and codename are appended. + (e.g. "CentOS Linux 7.1.1503 (Core)") + + **Lookup hierarchy:** + + The name is obtained from the following sources, in the specified order. + The first available and non-empty value is used: + + * If *pretty* is false: + + - the value of the "NAME" attribute of the os-release file, + + - the value of the "Distributor ID" attribute returned by the lsb_release + command, + + - the value of the "<name>" field of the distro release file. + + * If *pretty* is true: + + - the value of the "PRETTY_NAME" attribute of the os-release file, + + - the value of the "Description" attribute returned by the lsb_release + command, + + - the value of the "<name>" field of the distro release file, appended + with the value of the pretty version ("<version_id>" and "<codename>" + fields) of the distro release file, if available. + """ + return _distro.name(pretty) + + +def version(pretty=False, best=False): + """ + Return the version of the current Linux distribution, as a human-readable + string. + + If *pretty* is false, the version is returned without codename (e.g. + "7.0"). + + If *pretty* is true, the codename in parenthesis is appended, if the + codename is non-empty (e.g. "7.0 (Maipo)"). + + Some distributions provide version numbers with different precisions in + the different sources of distribution information. Examining the different + sources in a fixed priority order does not always yield the most precise + version (e.g. for Debian 8.2, or CentOS 7.1). + + The *best* parameter can be used to control the approach for the returned + version: + + If *best* is false, the first non-empty version number in priority order of + the examined sources is returned. + + If *best* is true, the most precise version number out of all examined + sources is returned. + + **Lookup hierarchy:** + + In all cases, the version number is obtained from the following sources. + If *best* is false, this order represents the priority order: + + * the value of the "VERSION_ID" attribute of the os-release file, + * the value of the "Release" attribute returned by the lsb_release + command, + * the version number parsed from the "<version_id>" field of the first line + of the distro release file, + * the version number parsed from the "PRETTY_NAME" attribute of the + os-release file, if it follows the format of the distro release files. + * the version number parsed from the "Description" attribute returned by + the lsb_release command, if it follows the format of the distro release + files. + """ + return _distro.version(pretty, best) + + +def version_parts(best=False): + """ + Return the version of the current Linux distribution as a tuple + ``(major, minor, build_number)`` with items as follows: + + * ``major``: The result of :func:`distro.major_version`. + + * ``minor``: The result of :func:`distro.minor_version`. + + * ``build_number``: The result of :func:`distro.build_number`. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.version_parts(best) + + +def major_version(best=False): + """ + Return the major version of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The major version is the first + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.major_version(best) + + +def minor_version(best=False): + """ + Return the minor version of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The minor version is the second + part of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.minor_version(best) + + +def build_number(best=False): + """ + Return the build number of the current Linux distribution, as a string, + if provided. + Otherwise, the empty string is returned. The build number is the third part + of the dot-separated version string. + + For a description of the *best* parameter, see the :func:`distro.version` + method. + """ + return _distro.build_number(best) + + +def like(): + """ + Return a space-separated list of distro IDs of distributions that are + closely related to the current Linux distribution in regards to packaging + and programming interfaces, for example distributions the current + distribution is a derivative from. + + **Lookup hierarchy:** + + This information item is only provided by the os-release file. + For details, see the description of the "ID_LIKE" attribute in the + `os-release man page + <http://www.freedesktop.org/software/systemd/man/os-release.html>`_. + """ + return _distro.like() + + +def codename(): + """ + Return the codename for the release of the current Linux distribution, + as a string. + + If the distribution does not have a codename, an empty string is returned. + + Note that the returned codename is not always really a codename. For + example, openSUSE returns "x86_64". This function does not handle such + cases in any special way and just returns the string it finds, if any. + + **Lookup hierarchy:** + + * the codename within the "VERSION" attribute of the os-release file, if + provided, + + * the value of the "Codename" attribute returned by the lsb_release + command, + + * the value of the "<codename>" field of the distro release file. + """ + return _distro.codename() + + +def info(pretty=False, best=False): + """ + Return certain machine-readable information items about the current Linux + distribution in a dictionary, as shown in the following example: + + .. sourcecode:: python + + { + 'id': 'rhel', + 'version': '7.0', + 'version_parts': { + 'major': '7', + 'minor': '0', + 'build_number': '' + }, + 'like': 'fedora', + 'codename': 'Maipo' + } + + The dictionary structure and keys are always the same, regardless of which + information items are available in the underlying data sources. The values + for the various keys are as follows: + + * ``id``: The result of :func:`distro.id`. + + * ``version``: The result of :func:`distro.version`. + + * ``version_parts -> major``: The result of :func:`distro.major_version`. + + * ``version_parts -> minor``: The result of :func:`distro.minor_version`. + + * ``version_parts -> build_number``: The result of + :func:`distro.build_number`. + + * ``like``: The result of :func:`distro.like`. + + * ``codename``: The result of :func:`distro.codename`. + + For a description of the *pretty* and *best* parameters, see the + :func:`distro.version` method. + """ + return _distro.info(pretty, best) + + +def os_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the os-release file data source of the current Linux distribution. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_info() + + +def lsb_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the lsb_release command data source of the current Linux distribution. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_info() + + +def distro_release_info(): + """ + Return a dictionary containing key-value pairs for the information items + from the distro release file data source of the current Linux distribution. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_info() + + +def os_release_attr(attribute): + """ + Return a single named information item from the os-release file data source + of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `os-release file`_ for details about these information items. + """ + return _distro.os_release_attr(attribute) + + +def lsb_release_attr(attribute): + """ + Return a single named information item from the lsb_release command output + data source of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `lsb_release command output`_ for details about these information + items. + """ + return _distro.lsb_release_attr(attribute) + + +def distro_release_attr(attribute): + """ + Return a single named information item from the distro release file + data source of the current Linux distribution. + + Parameters: + + * ``attribute`` (string): Key of the information item. + + Returns: + + * (string): Value of the information item, if the item exists. + The empty string, if the item does not exist. + + See `distro release file`_ for details about these information items. + """ + return _distro.distro_release_attr(attribute) + + +class cached_property(object): + """A version of @property which caches the value. On access, it calls the + underlying function and sets the value in `__dict__` so future accesses + will not re-call the property. + """ + def __init__(self, f): + self._fname = f.__name__ + self._f = f + + def __get__(self, obj, owner): + assert obj is not None, 'call {} on an instance'.format(self._fname) + ret = obj.__dict__[self._fname] = self._f(obj) + return ret + + +class LinuxDistribution(object): + """ + Provides information about a Linux distribution. + + This package creates a private module-global instance of this class with + default initialization arguments, that is used by the + `consolidated accessor functions`_ and `single source accessor functions`_. + By using default initialization arguments, that module-global instance + returns data about the current Linux distribution (i.e. the distro this + package runs on). + + Normally, it is not necessary to create additional instances of this class. + However, in situations where control is needed over the exact data sources + that are used, instances of this class can be created with a specific + distro release file, or a specific os-release file, or without invoking the + lsb_release command. + """ + + def __init__(self, + include_lsb=True, + os_release_file='', + distro_release_file=''): + """ + The initialization method of this class gathers information from the + available data sources, and stores that in private instance attributes. + Subsequent access to the information items uses these private instance + attributes, so that the data sources are read only once. + + Parameters: + + * ``include_lsb`` (bool): Controls whether the + `lsb_release command output`_ is included as a data source. + + If the lsb_release command is not available in the program execution + path, the data source for the lsb_release command will be empty. + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is to be used as a data source. + + An empty string (the default) will cause the default path name to + be used (see `os-release file`_ for details). + + If the specified or defaulted os-release file does not exist, the + data source for the os-release file will be empty. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is to be used as a data source. + + An empty string (the default) will cause a default search algorithm + to be used (see `distro release file`_ for details). + + If the specified distro release file does not exist, or if no default + distro release file can be found, the data source for the distro + release file will be empty. + + Public instance attributes: + + * ``os_release_file`` (string): The path name of the + `os-release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``distro_release_file`` (string): The path name of the + `distro release file`_ that is actually used as a data source. The + empty string if no distro release file is used as a data source. + + * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter. + This controls whether the lsb information will be loaded. + + Raises: + + * :py:exc:`IOError`: Some I/O issue with an os-release file or distro + release file. + + * :py:exc:`subprocess.CalledProcessError`: The lsb_release command had + some issue (other than not being available in the program execution + path). + + * :py:exc:`UnicodeError`: A data source has unexpected characters or + uses an unexpected encoding. + """ + self.os_release_file = os_release_file or \ + os.path.join(_UNIXCONFDIR, _OS_RELEASE_BASENAME) + self.distro_release_file = distro_release_file or '' # updated later + self.include_lsb = include_lsb + + def __repr__(self): + """Return repr of all info + """ + return \ + "LinuxDistribution(" \ + "os_release_file={self.os_release_file!r}, " \ + "distro_release_file={self.distro_release_file!r}, " \ + "include_lsb={self.include_lsb!r}, " \ + "_os_release_info={self._os_release_info!r}, " \ + "_lsb_release_info={self._lsb_release_info!r}, " \ + "_distro_release_info={self._distro_release_info!r})".format( + self=self) + + def linux_distribution(self, full_distribution_name=True): + """ + Return information about the Linux distribution that is compatible + with Python's :func:`platform.linux_distribution`, supporting a subset + of its parameters. + + For details, see :func:`distro.linux_distribution`. + """ + return ( + self.name() if full_distribution_name else self.id(), + self.version(), + self.codename() + ) + + def id(self): + """Return the distro ID of the Linux distribution, as a string. + + For details, see :func:`distro.id`. + """ + def normalize(distro_id, table): + distro_id = distro_id.lower().replace(' ', '_') + return table.get(distro_id, distro_id) + + distro_id = self.os_release_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_OS_ID) + + distro_id = self.lsb_release_attr('distributor_id') + if distro_id: + return normalize(distro_id, NORMALIZED_LSB_ID) + + distro_id = self.distro_release_attr('id') + if distro_id: + return normalize(distro_id, NORMALIZED_DISTRO_ID) + + return '' + + def name(self, pretty=False): + """ + Return the name of the Linux distribution, as a string. + + For details, see :func:`distro.name`. + """ + name = self.os_release_attr('name') \ + or self.lsb_release_attr('distributor_id') \ + or self.distro_release_attr('name') + if pretty: + name = self.os_release_attr('pretty_name') \ + or self.lsb_release_attr('description') + if not name: + name = self.distro_release_attr('name') + version = self.version(pretty=True) + if version: + name = name + ' ' + version + return name or '' + + def version(self, pretty=False, best=False): + """ + Return the version of the Linux distribution, as a string. + + For details, see :func:`distro.version`. + """ + versions = [ + self.os_release_attr('version_id'), + self.lsb_release_attr('release'), + self.distro_release_attr('version_id'), + self._parse_distro_release_content( + self.os_release_attr('pretty_name')).get('version_id', ''), + self._parse_distro_release_content( + self.lsb_release_attr('description')).get('version_id', '') + ] + version = '' + if best: + # This algorithm uses the last version in priority order that has + # the best precision. If the versions are not in conflict, that + # does not matter; otherwise, using the last one instead of the + # first one might be considered a surprise. + for v in versions: + if v.count(".") > version.count(".") or version == '': + version = v + else: + for v in versions: + if v != '': + version = v + break + if pretty and version and self.codename(): + version = u'{0} ({1})'.format(version, self.codename()) + return version + + def version_parts(self, best=False): + """ + Return the version of the Linux distribution, as a tuple of version + numbers. + + For details, see :func:`distro.version_parts`. + """ + version_str = self.version(best=best) + if version_str: + version_regex = re.compile(r'(\d+)\.?(\d+)?\.?(\d+)?') + matches = version_regex.match(version_str) + if matches: + major, minor, build_number = matches.groups() + return major, minor or '', build_number or '' + return '', '', '' + + def major_version(self, best=False): + """ + Return the major version number of the current distribution. + + For details, see :func:`distro.major_version`. + """ + return self.version_parts(best)[0] + + def minor_version(self, best=False): + """ + Return the minor version number of the Linux distribution. + + For details, see :func:`distro.minor_version`. + """ + return self.version_parts(best)[1] + + def build_number(self, best=False): + """ + Return the build number of the Linux distribution. + + For details, see :func:`distro.build_number`. + """ + return self.version_parts(best)[2] + + def like(self): + """ + Return the IDs of distributions that are like the Linux distribution. + + For details, see :func:`distro.like`. + """ + return self.os_release_attr('id_like') or '' + + def codename(self): + """ + Return the codename of the Linux distribution. + + For details, see :func:`distro.codename`. + """ + return self.os_release_attr('codename') \ + or self.lsb_release_attr('codename') \ + or self.distro_release_attr('codename') \ + or '' + + def info(self, pretty=False, best=False): + """ + Return certain machine-readable information about the Linux + distribution. + + For details, see :func:`distro.info`. + """ + return dict( + id=self.id(), + version=self.version(pretty, best), + version_parts=dict( + major=self.major_version(best), + minor=self.minor_version(best), + build_number=self.build_number(best) + ), + like=self.like(), + codename=self.codename(), + ) + + def os_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the os-release file data source of the Linux distribution. + + For details, see :func:`distro.os_release_info`. + """ + return self._os_release_info + + def lsb_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the lsb_release command data source of the Linux + distribution. + + For details, see :func:`distro.lsb_release_info`. + """ + return self._lsb_release_info + + def distro_release_info(self): + """ + Return a dictionary containing key-value pairs for the information + items from the distro release file data source of the Linux + distribution. + + For details, see :func:`distro.distro_release_info`. + """ + return self._distro_release_info + + def os_release_attr(self, attribute): + """ + Return a single named information item from the os-release file data + source of the Linux distribution. + + For details, see :func:`distro.os_release_attr`. + """ + return self._os_release_info.get(attribute, '') + + def lsb_release_attr(self, attribute): + """ + Return a single named information item from the lsb_release command + output data source of the Linux distribution. + + For details, see :func:`distro.lsb_release_attr`. + """ + return self._lsb_release_info.get(attribute, '') + + def distro_release_attr(self, attribute): + """ + Return a single named information item from the distro release file + data source of the Linux distribution. + + For details, see :func:`distro.distro_release_attr`. + """ + return self._distro_release_info.get(attribute, '') + + @cached_property + def _os_release_info(self): + """ + Get the information items from the specified os-release file. + + Returns: + A dictionary containing all information items. + """ + if os.path.isfile(self.os_release_file): + with open(self.os_release_file) as release_file: + return self._parse_os_release_content(release_file) + return {} + + @staticmethod + def _parse_os_release_content(lines): + """ + Parse the lines of an os-release file. + + Parameters: + + * lines: Iterable through the lines in the os-release file. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + lexer = shlex.shlex(lines, posix=True) + lexer.whitespace_split = True + + # The shlex module defines its `wordchars` variable using literals, + # making it dependent on the encoding of the Python source file. + # In Python 2.6 and 2.7, the shlex source file is encoded in + # 'iso-8859-1', and the `wordchars` variable is defined as a byte + # string. This causes a UnicodeDecodeError to be raised when the + # parsed content is a unicode object. The following fix resolves that + # (... but it should be fixed in shlex...): + if sys.version_info[0] == 2 and isinstance(lexer.wordchars, bytes): + lexer.wordchars = lexer.wordchars.decode('iso-8859-1') + + tokens = list(lexer) + for token in tokens: + # At this point, all shell-like parsing has been done (i.e. + # comments processed, quotes and backslash escape sequences + # processed, multi-line values assembled, trailing newlines + # stripped, etc.), so the tokens are now either: + # * variable assignments: var=value + # * commands or their arguments (not allowed in os-release) + if '=' in token: + k, v = token.split('=', 1) + if isinstance(v, bytes): + v = v.decode('utf-8') + props[k.lower()] = v + if k == 'VERSION': + # this handles cases in which the codename is in + # the `(CODENAME)` (rhel, centos, fedora) format + # or in the `, CODENAME` format (Ubuntu). + codename = re.search(r'(\(\D+\))|,(\s+)?\D+', v) + if codename: + codename = codename.group() + codename = codename.strip('()') + codename = codename.strip(',') + codename = codename.strip() + # codename appears within paranthese. + props['codename'] = codename + else: + props['codename'] = '' + else: + # Ignore any tokens that are not variable assignments + pass + return props + + @cached_property + def _lsb_release_info(self): + """ + Get the information items from the lsb_release command output. + + Returns: + A dictionary containing all information items. + """ + if not self.include_lsb: + return {} + with open(os.devnull, 'w') as devnull: + try: + cmd = ('lsb_release', '-a') + stdout = subprocess.check_output(cmd, stderr=devnull) + except OSError: # Command not found + return {} + content = stdout.decode(sys.getfilesystemencoding()).splitlines() + return self._parse_lsb_release_content(content) + + @staticmethod + def _parse_lsb_release_content(lines): + """ + Parse the output of the lsb_release command. + + Parameters: + + * lines: Iterable through the lines of the lsb_release output. + Each line must be a unicode string or a UTF-8 encoded byte + string. + + Returns: + A dictionary containing all information items. + """ + props = {} + for line in lines: + kv = line.strip('\n').split(':', 1) + if len(kv) != 2: + # Ignore lines without colon. + continue + k, v = kv + props.update({k.replace(' ', '_').lower(): v.strip()}) + return props + + @cached_property + def _distro_release_info(self): + """ + Get the information items from the specified distro release file. + + Returns: + A dictionary containing all information items. + """ + if self.distro_release_file: + # If it was specified, we use it and parse what we can, even if + # its file name or content does not match the expected pattern. + distro_info = self._parse_distro_release_file( + self.distro_release_file) + basename = os.path.basename(self.distro_release_file) + # The file name pattern for user-specified distro release files + # is somewhat more tolerant (compared to when searching for the + # file), because we want to use what was specified as best as + # possible. + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match: + distro_info['id'] = match.group(1) + return distro_info + else: + try: + basenames = os.listdir(_UNIXCONFDIR) + # We sort for repeatability in cases where there are multiple + # distro specific files; e.g. CentOS, Oracle, Enterprise all + # containing `redhat-release` on top of their own. + basenames.sort() + except OSError: + # This may occur when /etc is not readable but we can't be + # sure about the *-release files. Check common entries of + # /etc for information. If they turn out to not be there the + # error is handled in `_parse_distro_release_file()`. + basenames = ['SuSE-release', + 'arch-release', + 'base-release', + 'centos-release', + 'fedora-release', + 'gentoo-release', + 'mageia-release', + 'mandrake-release', + 'mandriva-release', + 'mandrivalinux-release', + 'manjaro-release', + 'oracle-release', + 'redhat-release', + 'sl-release', + 'slackware-version'] + for basename in basenames: + if basename in _DISTRO_RELEASE_IGNORE_BASENAMES: + continue + match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename) + if match: + filepath = os.path.join(_UNIXCONFDIR, basename) + distro_info = self._parse_distro_release_file(filepath) + if 'name' in distro_info: + # The name is always present if the pattern matches + self.distro_release_file = filepath + distro_info['id'] = match.group(1) + return distro_info + return {} + + def _parse_distro_release_file(self, filepath): + """ + Parse a distro release file. + + Parameters: + + * filepath: Path name of the distro release file. + + Returns: + A dictionary containing all information items. + """ + try: + with open(filepath) as fp: + # Only parse the first line. For instance, on SLES there + # are multiple lines. We don't want them... + return self._parse_distro_release_content(fp.readline()) + except (OSError, IOError): + # Ignore not being able to read a specific, seemingly version + # related file. + # See https://github.com/nir0s/distro/issues/162 + return {} + + @staticmethod + def _parse_distro_release_content(line): + """ + Parse a line from a distro release file. + + Parameters: + * line: Line from the distro release file. Must be a unicode string + or a UTF-8 encoded byte string. + + Returns: + A dictionary containing all information items. + """ + if isinstance(line, bytes): + line = line.decode('utf-8') + matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match( + line.strip()[::-1]) + distro_info = {} + if matches: + # regexp ensures non-None + distro_info['name'] = matches.group(3)[::-1] + if matches.group(2): + distro_info['version_id'] = matches.group(2)[::-1] + if matches.group(1): + distro_info['codename'] = matches.group(1)[::-1] + elif line: + distro_info['name'] = line.strip() + return distro_info + + +_distro = LinuxDistribution() + + +def main(): + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + logger.addHandler(logging.StreamHandler(sys.stdout)) + + parser = argparse.ArgumentParser(description="Linux distro info tool") + parser.add_argument( + '--json', + '-j', + help="Output in machine readable format", + action="store_true") + args = parser.parse_args() + + if args.json: + logger.info(json.dumps(info(), indent=4, sort_keys=True)) + else: + logger.info('Name: %s', name(pretty=True)) + distribution_version = version(pretty=True) + logger.info('Version: %s', distribution_version) + distribution_codename = codename() + logger.info('Codename: %s', distribution_codename) + + +if __name__ == '__main__': + main() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py new file mode 100755 index 0000000..0b54002 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/__init__.py @@ -0,0 +1,35 @@ +""" +HTML parsing library based on the `WHATWG HTML specification +<https://whatwg.org/html>`_. The parser is designed to be compatible with +existing HTML found in the wild and implements well-defined error recovery that +is largely compatible with modern desktop web browsers. + +Example usage:: + + from pip._vendor import html5lib + with open("my_document.html", "rb") as f: + tree = html5lib.parse(f) + +For convenience, this module re-exports the following names: + +* :func:`~.html5parser.parse` +* :func:`~.html5parser.parseFragment` +* :class:`~.html5parser.HTMLParser` +* :func:`~.treebuilders.getTreeBuilder` +* :func:`~.treewalkers.getTreeWalker` +* :func:`~.serializer.serialize` +""" + +from __future__ import absolute_import, division, unicode_literals + +from .html5parser import HTMLParser, parse, parseFragment +from .treebuilders import getTreeBuilder +from .treewalkers import getTreeWalker +from .serializer import serialize + +__all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder", + "getTreeWalker", "serialize"] + +# this has to be at the top level, see how setup.py parses this +#: Distribution version number. +__version__ = "1.0.1" diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py new file mode 100755 index 0000000..68f9b1e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_ihatexml.py @@ -0,0 +1,288 @@ +from __future__ import absolute_import, division, unicode_literals + +import re +import warnings + +from .constants import DataLossWarning + +baseChar = """ +[#x0041-#x005A] | [#x0061-#x007A] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | +[#x00F8-#x00FF] | [#x0100-#x0131] | [#x0134-#x013E] | [#x0141-#x0148] | +[#x014A-#x017E] | [#x0180-#x01C3] | [#x01CD-#x01F0] | [#x01F4-#x01F5] | +[#x01FA-#x0217] | [#x0250-#x02A8] | [#x02BB-#x02C1] | #x0386 | +[#x0388-#x038A] | #x038C | [#x038E-#x03A1] | [#x03A3-#x03CE] | +[#x03D0-#x03D6] | #x03DA | #x03DC | #x03DE | #x03E0 | [#x03E2-#x03F3] | +[#x0401-#x040C] | [#x040E-#x044F] | [#x0451-#x045C] | [#x045E-#x0481] | +[#x0490-#x04C4] | [#x04C7-#x04C8] | [#x04CB-#x04CC] | [#x04D0-#x04EB] | +[#x04EE-#x04F5] | [#x04F8-#x04F9] | [#x0531-#x0556] | #x0559 | +[#x0561-#x0586] | [#x05D0-#x05EA] | [#x05F0-#x05F2] | [#x0621-#x063A] | +[#x0641-#x064A] | [#x0671-#x06B7] | [#x06BA-#x06BE] | [#x06C0-#x06CE] | +[#x06D0-#x06D3] | #x06D5 | [#x06E5-#x06E6] | [#x0905-#x0939] | #x093D | +[#x0958-#x0961] | [#x0985-#x098C] | [#x098F-#x0990] | [#x0993-#x09A8] | +[#x09AA-#x09B0] | #x09B2 | [#x09B6-#x09B9] | [#x09DC-#x09DD] | +[#x09DF-#x09E1] | [#x09F0-#x09F1] | [#x0A05-#x0A0A] | [#x0A0F-#x0A10] | +[#x0A13-#x0A28] | [#x0A2A-#x0A30] | [#x0A32-#x0A33] | [#x0A35-#x0A36] | +[#x0A38-#x0A39] | [#x0A59-#x0A5C] | #x0A5E | [#x0A72-#x0A74] | +[#x0A85-#x0A8B] | #x0A8D | [#x0A8F-#x0A91] | [#x0A93-#x0AA8] | +[#x0AAA-#x0AB0] | [#x0AB2-#x0AB3] | [#x0AB5-#x0AB9] | #x0ABD | #x0AE0 | +[#x0B05-#x0B0C] | [#x0B0F-#x0B10] | [#x0B13-#x0B28] | [#x0B2A-#x0B30] | +[#x0B32-#x0B33] | [#x0B36-#x0B39] | #x0B3D | [#x0B5C-#x0B5D] | +[#x0B5F-#x0B61] | [#x0B85-#x0B8A] | [#x0B8E-#x0B90] | [#x0B92-#x0B95] | +[#x0B99-#x0B9A] | #x0B9C | [#x0B9E-#x0B9F] | [#x0BA3-#x0BA4] | +[#x0BA8-#x0BAA] | [#x0BAE-#x0BB5] | [#x0BB7-#x0BB9] | [#x0C05-#x0C0C] | +[#x0C0E-#x0C10] | [#x0C12-#x0C28] | [#x0C2A-#x0C33] | [#x0C35-#x0C39] | +[#x0C60-#x0C61] | [#x0C85-#x0C8C] | [#x0C8E-#x0C90] | [#x0C92-#x0CA8] | +[#x0CAA-#x0CB3] | [#x0CB5-#x0CB9] | #x0CDE | [#x0CE0-#x0CE1] | +[#x0D05-#x0D0C] | [#x0D0E-#x0D10] | [#x0D12-#x0D28] | [#x0D2A-#x0D39] | +[#x0D60-#x0D61] | [#x0E01-#x0E2E] | #x0E30 | [#x0E32-#x0E33] | +[#x0E40-#x0E45] | [#x0E81-#x0E82] | #x0E84 | [#x0E87-#x0E88] | #x0E8A | +#x0E8D | [#x0E94-#x0E97] | [#x0E99-#x0E9F] | [#x0EA1-#x0EA3] | #x0EA5 | +#x0EA7 | [#x0EAA-#x0EAB] | [#x0EAD-#x0EAE] | #x0EB0 | [#x0EB2-#x0EB3] | +#x0EBD | [#x0EC0-#x0EC4] | [#x0F40-#x0F47] | [#x0F49-#x0F69] | +[#x10A0-#x10C5] | [#x10D0-#x10F6] | #x1100 | [#x1102-#x1103] | +[#x1105-#x1107] | #x1109 | [#x110B-#x110C] | [#x110E-#x1112] | #x113C | +#x113E | #x1140 | #x114C | #x114E | #x1150 | [#x1154-#x1155] | #x1159 | +[#x115F-#x1161] | #x1163 | #x1165 | #x1167 | #x1169 | [#x116D-#x116E] | +[#x1172-#x1173] | #x1175 | #x119E | #x11A8 | #x11AB | [#x11AE-#x11AF] | +[#x11B7-#x11B8] | #x11BA | [#x11BC-#x11C2] | #x11EB | #x11F0 | #x11F9 | +[#x1E00-#x1E9B] | [#x1EA0-#x1EF9] | [#x1F00-#x1F15] | [#x1F18-#x1F1D] | +[#x1F20-#x1F45] | [#x1F48-#x1F4D] | [#x1F50-#x1F57] | #x1F59 | #x1F5B | +#x1F5D | [#x1F5F-#x1F7D] | [#x1F80-#x1FB4] | [#x1FB6-#x1FBC] | #x1FBE | +[#x1FC2-#x1FC4] | [#x1FC6-#x1FCC] | [#x1FD0-#x1FD3] | [#x1FD6-#x1FDB] | +[#x1FE0-#x1FEC] | [#x1FF2-#x1FF4] | [#x1FF6-#x1FFC] | #x2126 | +[#x212A-#x212B] | #x212E | [#x2180-#x2182] | [#x3041-#x3094] | +[#x30A1-#x30FA] | [#x3105-#x312C] | [#xAC00-#xD7A3]""" + +ideographic = """[#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]""" + +combiningCharacter = """ +[#x0300-#x0345] | [#x0360-#x0361] | [#x0483-#x0486] | [#x0591-#x05A1] | +[#x05A3-#x05B9] | [#x05BB-#x05BD] | #x05BF | [#x05C1-#x05C2] | #x05C4 | +[#x064B-#x0652] | #x0670 | [#x06D6-#x06DC] | [#x06DD-#x06DF] | +[#x06E0-#x06E4] | [#x06E7-#x06E8] | [#x06EA-#x06ED] | [#x0901-#x0903] | +#x093C | [#x093E-#x094C] | #x094D | [#x0951-#x0954] | [#x0962-#x0963] | +[#x0981-#x0983] | #x09BC | #x09BE | #x09BF | [#x09C0-#x09C4] | +[#x09C7-#x09C8] | [#x09CB-#x09CD] | #x09D7 | [#x09E2-#x09E3] | #x0A02 | +#x0A3C | #x0A3E | #x0A3F | [#x0A40-#x0A42] | [#x0A47-#x0A48] | +[#x0A4B-#x0A4D] | [#x0A70-#x0A71] | [#x0A81-#x0A83] | #x0ABC | +[#x0ABE-#x0AC5] | [#x0AC7-#x0AC9] | [#x0ACB-#x0ACD] | [#x0B01-#x0B03] | +#x0B3C | [#x0B3E-#x0B43] | [#x0B47-#x0B48] | [#x0B4B-#x0B4D] | +[#x0B56-#x0B57] | [#x0B82-#x0B83] | [#x0BBE-#x0BC2] | [#x0BC6-#x0BC8] | +[#x0BCA-#x0BCD] | #x0BD7 | [#x0C01-#x0C03] | [#x0C3E-#x0C44] | +[#x0C46-#x0C48] | [#x0C4A-#x0C4D] | [#x0C55-#x0C56] | [#x0C82-#x0C83] | +[#x0CBE-#x0CC4] | [#x0CC6-#x0CC8] | [#x0CCA-#x0CCD] | [#x0CD5-#x0CD6] | +[#x0D02-#x0D03] | [#x0D3E-#x0D43] | [#x0D46-#x0D48] | [#x0D4A-#x0D4D] | +#x0D57 | #x0E31 | [#x0E34-#x0E3A] | [#x0E47-#x0E4E] | #x0EB1 | +[#x0EB4-#x0EB9] | [#x0EBB-#x0EBC] | [#x0EC8-#x0ECD] | [#x0F18-#x0F19] | +#x0F35 | #x0F37 | #x0F39 | #x0F3E | #x0F3F | [#x0F71-#x0F84] | +[#x0F86-#x0F8B] | [#x0F90-#x0F95] | #x0F97 | [#x0F99-#x0FAD] | +[#x0FB1-#x0FB7] | #x0FB9 | [#x20D0-#x20DC] | #x20E1 | [#x302A-#x302F] | +#x3099 | #x309A""" + +digit = """ +[#x0030-#x0039] | [#x0660-#x0669] | [#x06F0-#x06F9] | [#x0966-#x096F] | +[#x09E6-#x09EF] | [#x0A66-#x0A6F] | [#x0AE6-#x0AEF] | [#x0B66-#x0B6F] | +[#x0BE7-#x0BEF] | [#x0C66-#x0C6F] | [#x0CE6-#x0CEF] | [#x0D66-#x0D6F] | +[#x0E50-#x0E59] | [#x0ED0-#x0ED9] | [#x0F20-#x0F29]""" + +extender = """ +#x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | #x0E46 | #x0EC6 | #x3005 | +#[#x3031-#x3035] | [#x309D-#x309E] | [#x30FC-#x30FE]""" + +letter = " | ".join([baseChar, ideographic]) + +# Without the +name = " | ".join([letter, digit, ".", "-", "_", combiningCharacter, + extender]) +nameFirst = " | ".join([letter, "_"]) + +reChar = re.compile(r"#x([\d|A-F]{4,4})") +reCharRange = re.compile(r"\[#x([\d|A-F]{4,4})-#x([\d|A-F]{4,4})\]") + + +def charStringToList(chars): + charRanges = [item.strip() for item in chars.split(" | ")] + rv = [] + for item in charRanges: + foundMatch = False + for regexp in (reChar, reCharRange): + match = regexp.match(item) + if match is not None: + rv.append([hexToInt(item) for item in match.groups()]) + if len(rv[-1]) == 1: + rv[-1] = rv[-1] * 2 + foundMatch = True + break + if not foundMatch: + assert len(item) == 1 + + rv.append([ord(item)] * 2) + rv = normaliseCharList(rv) + return rv + + +def normaliseCharList(charList): + charList = sorted(charList) + for item in charList: + assert item[1] >= item[0] + rv = [] + i = 0 + while i < len(charList): + j = 1 + rv.append(charList[i]) + while i + j < len(charList) and charList[i + j][0] <= rv[-1][1] + 1: + rv[-1][1] = charList[i + j][1] + j += 1 + i += j + return rv + +# We don't really support characters above the BMP :( +max_unicode = int("FFFF", 16) + + +def missingRanges(charList): + rv = [] + if charList[0] != 0: + rv.append([0, charList[0][0] - 1]) + for i, item in enumerate(charList[:-1]): + rv.append([item[1] + 1, charList[i + 1][0] - 1]) + if charList[-1][1] != max_unicode: + rv.append([charList[-1][1] + 1, max_unicode]) + return rv + + +def listToRegexpStr(charList): + rv = [] + for item in charList: + if item[0] == item[1]: + rv.append(escapeRegexp(chr(item[0]))) + else: + rv.append(escapeRegexp(chr(item[0])) + "-" + + escapeRegexp(chr(item[1]))) + return "[%s]" % "".join(rv) + + +def hexToInt(hex_str): + return int(hex_str, 16) + + +def escapeRegexp(string): + specialCharacters = (".", "^", "$", "*", "+", "?", "{", "}", + "[", "]", "|", "(", ")", "-") + for char in specialCharacters: + string = string.replace(char, "\\" + char) + + return string + +# output from the above +nonXmlNameBMPRegexp = re.compile('[\x00-,/:-@\\[-\\^`\\{-\xb6\xb8-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u02cf\u02d2-\u02ff\u0346-\u035f\u0362-\u0385\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482\u0487-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u0590\u05a2\u05ba\u05be\u05c0\u05c3\u05c5-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u063f\u0653-\u065f\u066a-\u066f\u06b8-\u06b9\u06bf\u06cf\u06d4\u06e9\u06ee-\u06ef\u06fa-\u0900\u0904\u093a-\u093b\u094e-\u0950\u0955-\u0957\u0964-\u0965\u0970-\u0980\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09bb\u09bd\u09c5-\u09c6\u09c9-\u09ca\u09ce-\u09d6\u09d8-\u09db\u09de\u09e4-\u09e5\u09f2-\u0a01\u0a03-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a3b\u0a3d\u0a43-\u0a46\u0a49-\u0a4a\u0a4e-\u0a58\u0a5d\u0a5f-\u0a65\u0a75-\u0a80\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abb\u0ac6\u0aca\u0ace-\u0adf\u0ae1-\u0ae5\u0af0-\u0b00\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3b\u0b44-\u0b46\u0b49-\u0b4a\u0b4e-\u0b55\u0b58-\u0b5b\u0b5e\u0b62-\u0b65\u0b70-\u0b81\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0bbd\u0bc3-\u0bc5\u0bc9\u0bce-\u0bd6\u0bd8-\u0be6\u0bf0-\u0c00\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c3d\u0c45\u0c49\u0c4e-\u0c54\u0c57-\u0c5f\u0c62-\u0c65\u0c70-\u0c81\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cbd\u0cc5\u0cc9\u0cce-\u0cd4\u0cd7-\u0cdd\u0cdf\u0ce2-\u0ce5\u0cf0-\u0d01\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d3d\u0d44-\u0d45\u0d49\u0d4e-\u0d56\u0d58-\u0d5f\u0d62-\u0d65\u0d70-\u0e00\u0e2f\u0e3b-\u0e3f\u0e4f\u0e5a-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eba\u0ebe-\u0ebf\u0ec5\u0ec7\u0ece-\u0ecf\u0eda-\u0f17\u0f1a-\u0f1f\u0f2a-\u0f34\u0f36\u0f38\u0f3a-\u0f3d\u0f48\u0f6a-\u0f70\u0f85\u0f8c-\u0f8f\u0f96\u0f98\u0fae-\u0fb0\u0fb8\u0fba-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u20cf\u20dd-\u20e0\u20e2-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3004\u3006\u3008-\u3020\u3030\u3036-\u3040\u3095-\u3098\u309b-\u309c\u309f-\u30a0\u30fb\u30ff-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa + +nonXmlNameFirstBMPRegexp = re.compile('[\x00-@\\[-\\^`\\{-\xbf\xd7\xf7\u0132-\u0133\u013f-\u0140\u0149\u017f\u01c4-\u01cc\u01f1-\u01f3\u01f6-\u01f9\u0218-\u024f\u02a9-\u02ba\u02c2-\u0385\u0387\u038b\u038d\u03a2\u03cf\u03d7-\u03d9\u03db\u03dd\u03df\u03e1\u03f4-\u0400\u040d\u0450\u045d\u0482-\u048f\u04c5-\u04c6\u04c9-\u04ca\u04cd-\u04cf\u04ec-\u04ed\u04f6-\u04f7\u04fa-\u0530\u0557-\u0558\u055a-\u0560\u0587-\u05cf\u05eb-\u05ef\u05f3-\u0620\u063b-\u0640\u064b-\u0670\u06b8-\u06b9\u06bf\u06cf\u06d4\u06d6-\u06e4\u06e7-\u0904\u093a-\u093c\u093e-\u0957\u0962-\u0984\u098d-\u098e\u0991-\u0992\u09a9\u09b1\u09b3-\u09b5\u09ba-\u09db\u09de\u09e2-\u09ef\u09f2-\u0a04\u0a0b-\u0a0e\u0a11-\u0a12\u0a29\u0a31\u0a34\u0a37\u0a3a-\u0a58\u0a5d\u0a5f-\u0a71\u0a75-\u0a84\u0a8c\u0a8e\u0a92\u0aa9\u0ab1\u0ab4\u0aba-\u0abc\u0abe-\u0adf\u0ae1-\u0b04\u0b0d-\u0b0e\u0b11-\u0b12\u0b29\u0b31\u0b34-\u0b35\u0b3a-\u0b3c\u0b3e-\u0b5b\u0b5e\u0b62-\u0b84\u0b8b-\u0b8d\u0b91\u0b96-\u0b98\u0b9b\u0b9d\u0ba0-\u0ba2\u0ba5-\u0ba7\u0bab-\u0bad\u0bb6\u0bba-\u0c04\u0c0d\u0c11\u0c29\u0c34\u0c3a-\u0c5f\u0c62-\u0c84\u0c8d\u0c91\u0ca9\u0cb4\u0cba-\u0cdd\u0cdf\u0ce2-\u0d04\u0d0d\u0d11\u0d29\u0d3a-\u0d5f\u0d62-\u0e00\u0e2f\u0e31\u0e34-\u0e3f\u0e46-\u0e80\u0e83\u0e85-\u0e86\u0e89\u0e8b-\u0e8c\u0e8e-\u0e93\u0e98\u0ea0\u0ea4\u0ea6\u0ea8-\u0ea9\u0eac\u0eaf\u0eb1\u0eb4-\u0ebc\u0ebe-\u0ebf\u0ec5-\u0f3f\u0f48\u0f6a-\u109f\u10c6-\u10cf\u10f7-\u10ff\u1101\u1104\u1108\u110a\u110d\u1113-\u113b\u113d\u113f\u1141-\u114b\u114d\u114f\u1151-\u1153\u1156-\u1158\u115a-\u115e\u1162\u1164\u1166\u1168\u116a-\u116c\u116f-\u1171\u1174\u1176-\u119d\u119f-\u11a7\u11a9-\u11aa\u11ac-\u11ad\u11b0-\u11b6\u11b9\u11bb\u11c3-\u11ea\u11ec-\u11ef\u11f1-\u11f8\u11fa-\u1dff\u1e9c-\u1e9f\u1efa-\u1eff\u1f16-\u1f17\u1f1e-\u1f1f\u1f46-\u1f47\u1f4e-\u1f4f\u1f58\u1f5a\u1f5c\u1f5e\u1f7e-\u1f7f\u1fb5\u1fbd\u1fbf-\u1fc1\u1fc5\u1fcd-\u1fcf\u1fd4-\u1fd5\u1fdc-\u1fdf\u1fed-\u1ff1\u1ff5\u1ffd-\u2125\u2127-\u2129\u212c-\u212d\u212f-\u217f\u2183-\u3006\u3008-\u3020\u302a-\u3040\u3095-\u30a0\u30fb-\u3104\u312d-\u4dff\u9fa6-\uabff\ud7a4-\uffff]') # noqa + +# Simpler things +nonPubidCharRegexp = re.compile("[^\x20\x0D\x0Aa-zA-Z0-9\\-'()+,./:=?;!*#@$_%]") + + +class InfosetFilter(object): + replacementRegexp = re.compile(r"U[\dA-F]{5,5}") + + def __init__(self, + dropXmlnsLocalName=False, + dropXmlnsAttrNs=False, + preventDoubleDashComments=False, + preventDashAtCommentEnd=False, + replaceFormFeedCharacters=True, + preventSingleQuotePubid=False): + + self.dropXmlnsLocalName = dropXmlnsLocalName + self.dropXmlnsAttrNs = dropXmlnsAttrNs + + self.preventDoubleDashComments = preventDoubleDashComments + self.preventDashAtCommentEnd = preventDashAtCommentEnd + + self.replaceFormFeedCharacters = replaceFormFeedCharacters + + self.preventSingleQuotePubid = preventSingleQuotePubid + + self.replaceCache = {} + + def coerceAttribute(self, name, namespace=None): + if self.dropXmlnsLocalName and name.startswith("xmlns:"): + warnings.warn("Attributes cannot begin with xmlns", DataLossWarning) + return None + elif (self.dropXmlnsAttrNs and + namespace == "http://www.w3.org/2000/xmlns/"): + warnings.warn("Attributes cannot be in the xml namespace", DataLossWarning) + return None + else: + return self.toXmlName(name) + + def coerceElement(self, name): + return self.toXmlName(name) + + def coerceComment(self, data): + if self.preventDoubleDashComments: + while "--" in data: + warnings.warn("Comments cannot contain adjacent dashes", DataLossWarning) + data = data.replace("--", "- -") + if data.endswith("-"): + warnings.warn("Comments cannot end in a dash", DataLossWarning) + data += " " + return data + + def coerceCharacters(self, data): + if self.replaceFormFeedCharacters: + for _ in range(data.count("\x0C")): + warnings.warn("Text cannot contain U+000C", DataLossWarning) + data = data.replace("\x0C", " ") + # Other non-xml characters + return data + + def coercePubid(self, data): + dataOutput = data + for char in nonPubidCharRegexp.findall(data): + warnings.warn("Coercing non-XML pubid", DataLossWarning) + replacement = self.getReplacementCharacter(char) + dataOutput = dataOutput.replace(char, replacement) + if self.preventSingleQuotePubid and dataOutput.find("'") >= 0: + warnings.warn("Pubid cannot contain single quote", DataLossWarning) + dataOutput = dataOutput.replace("'", self.getReplacementCharacter("'")) + return dataOutput + + def toXmlName(self, name): + nameFirst = name[0] + nameRest = name[1:] + m = nonXmlNameFirstBMPRegexp.match(nameFirst) + if m: + warnings.warn("Coercing non-XML name", DataLossWarning) + nameFirstOutput = self.getReplacementCharacter(nameFirst) + else: + nameFirstOutput = nameFirst + + nameRestOutput = nameRest + replaceChars = set(nonXmlNameBMPRegexp.findall(nameRest)) + for char in replaceChars: + warnings.warn("Coercing non-XML name", DataLossWarning) + replacement = self.getReplacementCharacter(char) + nameRestOutput = nameRestOutput.replace(char, replacement) + return nameFirstOutput + nameRestOutput + + def getReplacementCharacter(self, char): + if char in self.replaceCache: + replacement = self.replaceCache[char] + else: + replacement = self.escapeChar(char) + return replacement + + def fromXmlName(self, name): + for item in set(self.replacementRegexp.findall(name)): + name = name.replace(item, self.unescapeChar(item)) + return name + + def escapeChar(self, char): + replacement = "U%05X" % ord(char) + self.replaceCache[char] = replacement + return replacement + + def unescapeChar(self, charcode): + return chr(int(charcode[1:], 16)) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py new file mode 100755 index 0000000..21c6bbc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_inputstream.py @@ -0,0 +1,923 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import text_type, binary_type +from pip._vendor.six.moves import http_client, urllib + +import codecs +import re + +from pip._vendor import webencodings + +from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase +from .constants import _ReparseException +from . import _utils + +from io import StringIO + +try: + from io import BytesIO +except ImportError: + BytesIO = StringIO + +# Non-unicode versions of constants for use in the pre-parser +spaceCharactersBytes = frozenset([item.encode("ascii") for item in spaceCharacters]) +asciiLettersBytes = frozenset([item.encode("ascii") for item in asciiLetters]) +asciiUppercaseBytes = frozenset([item.encode("ascii") for item in asciiUppercase]) +spacesAngleBrackets = spaceCharactersBytes | frozenset([b">", b"<"]) + + +invalid_unicode_no_surrogate = "[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uFDD0-\uFDEF\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]" # noqa + +if _utils.supports_lone_surrogates: + # Use one extra step of indirection and create surrogates with + # eval. Not using this indirection would introduce an illegal + # unicode literal on platforms not supporting such lone + # surrogates. + assert invalid_unicode_no_surrogate[-1] == "]" and invalid_unicode_no_surrogate.count("]") == 1 + invalid_unicode_re = re.compile(invalid_unicode_no_surrogate[:-1] + + eval('"\\uD800-\\uDFFF"') + # pylint:disable=eval-used + "]") +else: + invalid_unicode_re = re.compile(invalid_unicode_no_surrogate) + +non_bmp_invalid_codepoints = set([0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, + 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF, + 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE, + 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, + 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, + 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, + 0x10FFFE, 0x10FFFF]) + +ascii_punctuation_re = re.compile("[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005C\u005B-\u0060\u007B-\u007E]") + +# Cache for charsUntil() +charsUntilRegEx = {} + + +class BufferedStream(object): + """Buffering for streams that do not have buffering of their own + + The buffer is implemented as a list of chunks on the assumption that + joining many strings will be slow since it is O(n**2) + """ + + def __init__(self, stream): + self.stream = stream + self.buffer = [] + self.position = [-1, 0] # chunk number, offset + + def tell(self): + pos = 0 + for chunk in self.buffer[:self.position[0]]: + pos += len(chunk) + pos += self.position[1] + return pos + + def seek(self, pos): + assert pos <= self._bufferedBytes() + offset = pos + i = 0 + while len(self.buffer[i]) < offset: + offset -= len(self.buffer[i]) + i += 1 + self.position = [i, offset] + + def read(self, bytes): + if not self.buffer: + return self._readStream(bytes) + elif (self.position[0] == len(self.buffer) and + self.position[1] == len(self.buffer[-1])): + return self._readStream(bytes) + else: + return self._readFromBuffer(bytes) + + def _bufferedBytes(self): + return sum([len(item) for item in self.buffer]) + + def _readStream(self, bytes): + data = self.stream.read(bytes) + self.buffer.append(data) + self.position[0] += 1 + self.position[1] = len(data) + return data + + def _readFromBuffer(self, bytes): + remainingBytes = bytes + rv = [] + bufferIndex = self.position[0] + bufferOffset = self.position[1] + while bufferIndex < len(self.buffer) and remainingBytes != 0: + assert remainingBytes > 0 + bufferedData = self.buffer[bufferIndex] + + if remainingBytes <= len(bufferedData) - bufferOffset: + bytesToRead = remainingBytes + self.position = [bufferIndex, bufferOffset + bytesToRead] + else: + bytesToRead = len(bufferedData) - bufferOffset + self.position = [bufferIndex, len(bufferedData)] + bufferIndex += 1 + rv.append(bufferedData[bufferOffset:bufferOffset + bytesToRead]) + remainingBytes -= bytesToRead + + bufferOffset = 0 + + if remainingBytes: + rv.append(self._readStream(remainingBytes)) + + return b"".join(rv) + + +def HTMLInputStream(source, **kwargs): + # Work around Python bug #20007: read(0) closes the connection. + # http://bugs.python.org/issue20007 + if (isinstance(source, http_client.HTTPResponse) or + # Also check for addinfourl wrapping HTTPResponse + (isinstance(source, urllib.response.addbase) and + isinstance(source.fp, http_client.HTTPResponse))): + isUnicode = False + elif hasattr(source, "read"): + isUnicode = isinstance(source.read(0), text_type) + else: + isUnicode = isinstance(source, text_type) + + if isUnicode: + encodings = [x for x in kwargs if x.endswith("_encoding")] + if encodings: + raise TypeError("Cannot set an encoding with a unicode input, set %r" % encodings) + + return HTMLUnicodeInputStream(source, **kwargs) + else: + return HTMLBinaryInputStream(source, **kwargs) + + +class HTMLUnicodeInputStream(object): + """Provides a unicode stream of characters to the HTMLTokenizer. + + This class takes care of character encoding and removing or replacing + incorrect byte-sequences and also provides column and line tracking. + + """ + + _defaultChunkSize = 10240 + + def __init__(self, source): + """Initialises the HTMLInputStream. + + HTMLInputStream(source, [encoding]) -> Normalized stream from source + for use by html5lib. + + source can be either a file-object, local filename or a string. + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + """ + + if not _utils.supports_lone_surrogates: + # Such platforms will have already checked for such + # surrogate errors, so no need to do this checking. + self.reportCharacterErrors = None + elif len("\U0010FFFF") == 1: + self.reportCharacterErrors = self.characterErrorsUCS4 + else: + self.reportCharacterErrors = self.characterErrorsUCS2 + + # List of where new lines occur + self.newLines = [0] + + self.charEncoding = (lookupEncoding("utf-8"), "certain") + self.dataStream = self.openStream(source) + + self.reset() + + def reset(self): + self.chunk = "" + self.chunkSize = 0 + self.chunkOffset = 0 + self.errors = [] + + # number of (complete) lines in previous chunks + self.prevNumLines = 0 + # number of columns in the last line of the previous chunk + self.prevNumCols = 0 + + # Deal with CR LF and surrogates split over chunk boundaries + self._bufferedCharacter = None + + def openStream(self, source): + """Produces a file object from source. + + source can be either a file object, local filename or a string. + + """ + # Already a file object + if hasattr(source, 'read'): + stream = source + else: + stream = StringIO(source) + + return stream + + def _position(self, offset): + chunk = self.chunk + nLines = chunk.count('\n', 0, offset) + positionLine = self.prevNumLines + nLines + lastLinePos = chunk.rfind('\n', 0, offset) + if lastLinePos == -1: + positionColumn = self.prevNumCols + offset + else: + positionColumn = offset - (lastLinePos + 1) + return (positionLine, positionColumn) + + def position(self): + """Returns (line, col) of the current position in the stream.""" + line, col = self._position(self.chunkOffset) + return (line + 1, col) + + def char(self): + """ Read one character from the stream or queue if available. Return + EOF when EOF is reached. + """ + # Read a new chunk from the input stream if necessary + if self.chunkOffset >= self.chunkSize: + if not self.readChunk(): + return EOF + + chunkOffset = self.chunkOffset + char = self.chunk[chunkOffset] + self.chunkOffset = chunkOffset + 1 + + return char + + def readChunk(self, chunkSize=None): + if chunkSize is None: + chunkSize = self._defaultChunkSize + + self.prevNumLines, self.prevNumCols = self._position(self.chunkSize) + + self.chunk = "" + self.chunkSize = 0 + self.chunkOffset = 0 + + data = self.dataStream.read(chunkSize) + + # Deal with CR LF and surrogates broken across chunks + if self._bufferedCharacter: + data = self._bufferedCharacter + data + self._bufferedCharacter = None + elif not data: + # We have no more data, bye-bye stream + return False + + if len(data) > 1: + lastv = ord(data[-1]) + if lastv == 0x0D or 0xD800 <= lastv <= 0xDBFF: + self._bufferedCharacter = data[-1] + data = data[:-1] + + if self.reportCharacterErrors: + self.reportCharacterErrors(data) + + # Replace invalid characters + data = data.replace("\r\n", "\n") + data = data.replace("\r", "\n") + + self.chunk = data + self.chunkSize = len(data) + + return True + + def characterErrorsUCS4(self, data): + for _ in range(len(invalid_unicode_re.findall(data))): + self.errors.append("invalid-codepoint") + + def characterErrorsUCS2(self, data): + # Someone picked the wrong compile option + # You lose + skip = False + for match in invalid_unicode_re.finditer(data): + if skip: + continue + codepoint = ord(match.group()) + pos = match.start() + # Pretty sure there should be endianness issues here + if _utils.isSurrogatePair(data[pos:pos + 2]): + # We have a surrogate pair! + char_val = _utils.surrogatePairToCodepoint(data[pos:pos + 2]) + if char_val in non_bmp_invalid_codepoints: + self.errors.append("invalid-codepoint") + skip = True + elif (codepoint >= 0xD800 and codepoint <= 0xDFFF and + pos == len(data) - 1): + self.errors.append("invalid-codepoint") + else: + skip = False + self.errors.append("invalid-codepoint") + + def charsUntil(self, characters, opposite=False): + """ Returns a string of characters from the stream up to but not + including any character in 'characters' or EOF. 'characters' must be + a container that supports the 'in' method and iteration over its + characters. + """ + + # Use a cache of regexps to find the required characters + try: + chars = charsUntilRegEx[(characters, opposite)] + except KeyError: + if __debug__: + for c in characters: + assert(ord(c) < 128) + regex = "".join(["\\x%02x" % ord(c) for c in characters]) + if not opposite: + regex = "^%s" % regex + chars = charsUntilRegEx[(characters, opposite)] = re.compile("[%s]+" % regex) + + rv = [] + + while True: + # Find the longest matching prefix + m = chars.match(self.chunk, self.chunkOffset) + if m is None: + # If nothing matched, and it wasn't because we ran out of chunk, + # then stop + if self.chunkOffset != self.chunkSize: + break + else: + end = m.end() + # If not the whole chunk matched, return everything + # up to the part that didn't match + if end != self.chunkSize: + rv.append(self.chunk[self.chunkOffset:end]) + self.chunkOffset = end + break + # If the whole remainder of the chunk matched, + # use it all and read the next chunk + rv.append(self.chunk[self.chunkOffset:]) + if not self.readChunk(): + # Reached EOF + break + + r = "".join(rv) + return r + + def unget(self, char): + # Only one character is allowed to be ungotten at once - it must + # be consumed again before any further call to unget + if char is not None: + if self.chunkOffset == 0: + # unget is called quite rarely, so it's a good idea to do + # more work here if it saves a bit of work in the frequently + # called char and charsUntil. + # So, just prepend the ungotten character onto the current + # chunk: + self.chunk = char + self.chunk + self.chunkSize += 1 + else: + self.chunkOffset -= 1 + assert self.chunk[self.chunkOffset] == char + + +class HTMLBinaryInputStream(HTMLUnicodeInputStream): + """Provides a unicode stream of characters to the HTMLTokenizer. + + This class takes care of character encoding and removing or replacing + incorrect byte-sequences and also provides column and line tracking. + + """ + + def __init__(self, source, override_encoding=None, transport_encoding=None, + same_origin_parent_encoding=None, likely_encoding=None, + default_encoding="windows-1252", useChardet=True): + """Initialises the HTMLInputStream. + + HTMLInputStream(source, [encoding]) -> Normalized stream from source + for use by html5lib. + + source can be either a file-object, local filename or a string. + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + """ + # Raw Stream - for unicode objects this will encode to utf-8 and set + # self.charEncoding as appropriate + self.rawStream = self.openStream(source) + + HTMLUnicodeInputStream.__init__(self, self.rawStream) + + # Encoding Information + # Number of bytes to use when looking for a meta element with + # encoding information + self.numBytesMeta = 1024 + # Number of bytes to use when using detecting encoding using chardet + self.numBytesChardet = 100 + # Things from args + self.override_encoding = override_encoding + self.transport_encoding = transport_encoding + self.same_origin_parent_encoding = same_origin_parent_encoding + self.likely_encoding = likely_encoding + self.default_encoding = default_encoding + + # Determine encoding + self.charEncoding = self.determineEncoding(useChardet) + assert self.charEncoding[0] is not None + + # Call superclass + self.reset() + + def reset(self): + self.dataStream = self.charEncoding[0].codec_info.streamreader(self.rawStream, 'replace') + HTMLUnicodeInputStream.reset(self) + + def openStream(self, source): + """Produces a file object from source. + + source can be either a file object, local filename or a string. + + """ + # Already a file object + if hasattr(source, 'read'): + stream = source + else: + stream = BytesIO(source) + + try: + stream.seek(stream.tell()) + except: # pylint:disable=bare-except + stream = BufferedStream(stream) + + return stream + + def determineEncoding(self, chardet=True): + # BOMs take precedence over everything + # This will also read past the BOM if present + charEncoding = self.detectBOM(), "certain" + if charEncoding[0] is not None: + return charEncoding + + # If we've been overriden, we've been overriden + charEncoding = lookupEncoding(self.override_encoding), "certain" + if charEncoding[0] is not None: + return charEncoding + + # Now check the transport layer + charEncoding = lookupEncoding(self.transport_encoding), "certain" + if charEncoding[0] is not None: + return charEncoding + + # Look for meta elements with encoding information + charEncoding = self.detectEncodingMeta(), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Parent document encoding + charEncoding = lookupEncoding(self.same_origin_parent_encoding), "tentative" + if charEncoding[0] is not None and not charEncoding[0].name.startswith("utf-16"): + return charEncoding + + # "likely" encoding + charEncoding = lookupEncoding(self.likely_encoding), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Guess with chardet, if available + if chardet: + try: + from pip._vendor.chardet.universaldetector import UniversalDetector + except ImportError: + pass + else: + buffers = [] + detector = UniversalDetector() + while not detector.done: + buffer = self.rawStream.read(self.numBytesChardet) + assert isinstance(buffer, bytes) + if not buffer: + break + buffers.append(buffer) + detector.feed(buffer) + detector.close() + encoding = lookupEncoding(detector.result['encoding']) + self.rawStream.seek(0) + if encoding is not None: + return encoding, "tentative" + + # Try the default encoding + charEncoding = lookupEncoding(self.default_encoding), "tentative" + if charEncoding[0] is not None: + return charEncoding + + # Fallback to html5lib's default if even that hasn't worked + return lookupEncoding("windows-1252"), "tentative" + + def changeEncoding(self, newEncoding): + assert self.charEncoding[1] != "certain" + newEncoding = lookupEncoding(newEncoding) + if newEncoding is None: + return + if newEncoding.name in ("utf-16be", "utf-16le"): + newEncoding = lookupEncoding("utf-8") + assert newEncoding is not None + elif newEncoding == self.charEncoding[0]: + self.charEncoding = (self.charEncoding[0], "certain") + else: + self.rawStream.seek(0) + self.charEncoding = (newEncoding, "certain") + self.reset() + raise _ReparseException("Encoding changed from %s to %s" % (self.charEncoding[0], newEncoding)) + + def detectBOM(self): + """Attempts to detect at BOM at the start of the stream. If + an encoding can be determined from the BOM return the name of the + encoding otherwise return None""" + bomDict = { + codecs.BOM_UTF8: 'utf-8', + codecs.BOM_UTF16_LE: 'utf-16le', codecs.BOM_UTF16_BE: 'utf-16be', + codecs.BOM_UTF32_LE: 'utf-32le', codecs.BOM_UTF32_BE: 'utf-32be' + } + + # Go to beginning of file and read in 4 bytes + string = self.rawStream.read(4) + assert isinstance(string, bytes) + + # Try detecting the BOM using bytes from the string + encoding = bomDict.get(string[:3]) # UTF-8 + seek = 3 + if not encoding: + # Need to detect UTF-32 before UTF-16 + encoding = bomDict.get(string) # UTF-32 + seek = 4 + if not encoding: + encoding = bomDict.get(string[:2]) # UTF-16 + seek = 2 + + # Set the read position past the BOM if one was found, otherwise + # set it to the start of the stream + if encoding: + self.rawStream.seek(seek) + return lookupEncoding(encoding) + else: + self.rawStream.seek(0) + return None + + def detectEncodingMeta(self): + """Report the encoding declared by the meta element + """ + buffer = self.rawStream.read(self.numBytesMeta) + assert isinstance(buffer, bytes) + parser = EncodingParser(buffer) + self.rawStream.seek(0) + encoding = parser.getEncoding() + + if encoding is not None and encoding.name in ("utf-16be", "utf-16le"): + encoding = lookupEncoding("utf-8") + + return encoding + + +class EncodingBytes(bytes): + """String-like object with an associated position and various extra methods + If the position is ever greater than the string length then an exception is + raised""" + def __new__(self, value): + assert isinstance(value, bytes) + return bytes.__new__(self, value.lower()) + + def __init__(self, value): + # pylint:disable=unused-argument + self._position = -1 + + def __iter__(self): + return self + + def __next__(self): + p = self._position = self._position + 1 + if p >= len(self): + raise StopIteration + elif p < 0: + raise TypeError + return self[p:p + 1] + + def next(self): + # Py2 compat + return self.__next__() + + def previous(self): + p = self._position + if p >= len(self): + raise StopIteration + elif p < 0: + raise TypeError + self._position = p = p - 1 + return self[p:p + 1] + + def setPosition(self, position): + if self._position >= len(self): + raise StopIteration + self._position = position + + def getPosition(self): + if self._position >= len(self): + raise StopIteration + if self._position >= 0: + return self._position + else: + return None + + position = property(getPosition, setPosition) + + def getCurrentByte(self): + return self[self.position:self.position + 1] + + currentByte = property(getCurrentByte) + + def skip(self, chars=spaceCharactersBytes): + """Skip past a list of characters""" + p = self.position # use property for the error-checking + while p < len(self): + c = self[p:p + 1] + if c not in chars: + self._position = p + return c + p += 1 + self._position = p + return None + + def skipUntil(self, chars): + p = self.position + while p < len(self): + c = self[p:p + 1] + if c in chars: + self._position = p + return c + p += 1 + self._position = p + return None + + def matchBytes(self, bytes): + """Look for a sequence of bytes at the start of a string. If the bytes + are found return True and advance the position to the byte after the + match. Otherwise return False and leave the position alone""" + p = self.position + data = self[p:p + len(bytes)] + rv = data.startswith(bytes) + if rv: + self.position += len(bytes) + return rv + + def jumpTo(self, bytes): + """Look for the next sequence of bytes matching a given sequence. If + a match is found advance the position to the last byte of the match""" + newPosition = self[self.position:].find(bytes) + if newPosition > -1: + # XXX: This is ugly, but I can't see a nicer way to fix this. + if self._position == -1: + self._position = 0 + self._position += (newPosition + len(bytes) - 1) + return True + else: + raise StopIteration + + +class EncodingParser(object): + """Mini parser for detecting character encoding from meta elements""" + + def __init__(self, data): + """string - the data to work on for encoding detection""" + self.data = EncodingBytes(data) + self.encoding = None + + def getEncoding(self): + methodDispatch = ( + (b"<!--", self.handleComment), + (b"<meta", self.handleMeta), + (b"</", self.handlePossibleEndTag), + (b"<!", self.handleOther), + (b"<?", self.handleOther), + (b"<", self.handlePossibleStartTag)) + for _ in self.data: + keepParsing = True + for key, method in methodDispatch: + if self.data.matchBytes(key): + try: + keepParsing = method() + break + except StopIteration: + keepParsing = False + break + if not keepParsing: + break + + return self.encoding + + def handleComment(self): + """Skip over comments""" + return self.data.jumpTo(b"-->") + + def handleMeta(self): + if self.data.currentByte not in spaceCharactersBytes: + # if we have <meta not followed by a space so just keep going + return True + # We have a valid meta element we want to search for attributes + hasPragma = False + pendingEncoding = None + while True: + # Try to find the next attribute after the current position + attr = self.getAttribute() + if attr is None: + return True + else: + if attr[0] == b"http-equiv": + hasPragma = attr[1] == b"content-type" + if hasPragma and pendingEncoding is not None: + self.encoding = pendingEncoding + return False + elif attr[0] == b"charset": + tentativeEncoding = attr[1] + codec = lookupEncoding(tentativeEncoding) + if codec is not None: + self.encoding = codec + return False + elif attr[0] == b"content": + contentParser = ContentAttrParser(EncodingBytes(attr[1])) + tentativeEncoding = contentParser.parse() + if tentativeEncoding is not None: + codec = lookupEncoding(tentativeEncoding) + if codec is not None: + if hasPragma: + self.encoding = codec + return False + else: + pendingEncoding = codec + + def handlePossibleStartTag(self): + return self.handlePossibleTag(False) + + def handlePossibleEndTag(self): + next(self.data) + return self.handlePossibleTag(True) + + def handlePossibleTag(self, endTag): + data = self.data + if data.currentByte not in asciiLettersBytes: + # If the next byte is not an ascii letter either ignore this + # fragment (possible start tag case) or treat it according to + # handleOther + if endTag: + data.previous() + self.handleOther() + return True + + c = data.skipUntil(spacesAngleBrackets) + if c == b"<": + # return to the first step in the overall "two step" algorithm + # reprocessing the < byte + data.previous() + else: + # Read all attributes + attr = self.getAttribute() + while attr is not None: + attr = self.getAttribute() + return True + + def handleOther(self): + return self.data.jumpTo(b">") + + def getAttribute(self): + """Return a name,value pair for the next attribute in the stream, + if one is found, or None""" + data = self.data + # Step 1 (skip chars) + c = data.skip(spaceCharactersBytes | frozenset([b"/"])) + assert c is None or len(c) == 1 + # Step 2 + if c in (b">", None): + return None + # Step 3 + attrName = [] + attrValue = [] + # Step 4 attribute name + while True: + if c == b"=" and attrName: + break + elif c in spaceCharactersBytes: + # Step 6! + c = data.skip() + break + elif c in (b"/", b">"): + return b"".join(attrName), b"" + elif c in asciiUppercaseBytes: + attrName.append(c.lower()) + elif c is None: + return None + else: + attrName.append(c) + # Step 5 + c = next(data) + # Step 7 + if c != b"=": + data.previous() + return b"".join(attrName), b"" + # Step 8 + next(data) + # Step 9 + c = data.skip() + # Step 10 + if c in (b"'", b'"'): + # 10.1 + quoteChar = c + while True: + # 10.2 + c = next(data) + # 10.3 + if c == quoteChar: + next(data) + return b"".join(attrName), b"".join(attrValue) + # 10.4 + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + # 10.5 + else: + attrValue.append(c) + elif c == b">": + return b"".join(attrName), b"" + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + elif c is None: + return None + else: + attrValue.append(c) + # Step 11 + while True: + c = next(data) + if c in spacesAngleBrackets: + return b"".join(attrName), b"".join(attrValue) + elif c in asciiUppercaseBytes: + attrValue.append(c.lower()) + elif c is None: + return None + else: + attrValue.append(c) + + +class ContentAttrParser(object): + def __init__(self, data): + assert isinstance(data, bytes) + self.data = data + + def parse(self): + try: + # Check if the attr name is charset + # otherwise return + self.data.jumpTo(b"charset") + self.data.position += 1 + self.data.skip() + if not self.data.currentByte == b"=": + # If there is no = sign keep looking for attrs + return None + self.data.position += 1 + self.data.skip() + # Look for an encoding between matching quote marks + if self.data.currentByte in (b'"', b"'"): + quoteMark = self.data.currentByte + self.data.position += 1 + oldPosition = self.data.position + if self.data.jumpTo(quoteMark): + return self.data[oldPosition:self.data.position] + else: + return None + else: + # Unquoted value + oldPosition = self.data.position + try: + self.data.skipUntil(spaceCharactersBytes) + return self.data[oldPosition:self.data.position] + except StopIteration: + # Return the whole remaining value + return self.data[oldPosition:] + except StopIteration: + return None + + +def lookupEncoding(encoding): + """Return the python codec name corresponding to an encoding or None if the + string doesn't correspond to a valid encoding.""" + if isinstance(encoding, binary_type): + try: + encoding = encoding.decode("ascii") + except UnicodeDecodeError: + return None + + if encoding is not None: + try: + return webencodings.lookup(encoding) + except AttributeError: + return None + else: + return None diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py new file mode 100755 index 0000000..ef1ccf8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_tokenizer.py @@ -0,0 +1,1721 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import unichr as chr + +from collections import deque + +from .constants import spaceCharacters +from .constants import entities +from .constants import asciiLetters, asciiUpper2Lower +from .constants import digits, hexDigits, EOF +from .constants import tokenTypes, tagTokenTypes +from .constants import replacementCharacters + +from ._inputstream import HTMLInputStream + +from ._trie import Trie + +entitiesTrie = Trie(entities) + + +class HTMLTokenizer(object): + """ This class takes care of tokenizing HTML. + + * self.currentToken + Holds the token that is currently being processed. + + * self.state + Holds a reference to the method to be invoked... XXX + + * self.stream + Points to HTMLInputStream object. + """ + + def __init__(self, stream, parser=None, **kwargs): + + self.stream = HTMLInputStream(stream, **kwargs) + self.parser = parser + + # Setup the initial tokenizer state + self.escapeFlag = False + self.lastFourChars = [] + self.state = self.dataState + self.escape = False + + # The current token being created + self.currentToken = None + super(HTMLTokenizer, self).__init__() + + def __iter__(self): + """ This is where the magic happens. + + We do our usually processing through the states and when we have a token + to return we yield the token which pauses processing until the next token + is requested. + """ + self.tokenQueue = deque([]) + # Start processing. When EOF is reached self.state will return False + # instead of True and the loop will terminate. + while self.state(): + while self.stream.errors: + yield {"type": tokenTypes["ParseError"], "data": self.stream.errors.pop(0)} + while self.tokenQueue: + yield self.tokenQueue.popleft() + + def consumeNumberEntity(self, isHex): + """This function returns either U+FFFD or the character based on the + decimal or hexadecimal representation. It also discards ";" if present. + If not present self.tokenQueue.append({"type": tokenTypes["ParseError"]}) is invoked. + """ + + allowed = digits + radix = 10 + if isHex: + allowed = hexDigits + radix = 16 + + charStack = [] + + # Consume all the characters that are in range while making sure we + # don't hit an EOF. + c = self.stream.char() + while c in allowed and c is not EOF: + charStack.append(c) + c = self.stream.char() + + # Convert the set of characters consumed to an int. + charAsInt = int("".join(charStack), radix) + + # Certain characters get replaced with others + if charAsInt in replacementCharacters: + char = replacementCharacters[charAsInt] + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + elif ((0xD800 <= charAsInt <= 0xDFFF) or + (charAsInt > 0x10FFFF)): + char = "\uFFFD" + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + else: + # Should speed up this check somehow (e.g. move the set to a constant) + if ((0x0001 <= charAsInt <= 0x0008) or + (0x000E <= charAsInt <= 0x001F) or + (0x007F <= charAsInt <= 0x009F) or + (0xFDD0 <= charAsInt <= 0xFDEF) or + charAsInt in frozenset([0x000B, 0xFFFE, 0xFFFF, 0x1FFFE, + 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, + 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, + 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, + 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, + 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE, + 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, + 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, + 0xFFFFF, 0x10FFFE, 0x10FFFF])): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "illegal-codepoint-for-numeric-entity", + "datavars": {"charAsInt": charAsInt}}) + try: + # Try/except needed as UCS-2 Python builds' unichar only works + # within the BMP. + char = chr(charAsInt) + except ValueError: + v = charAsInt - 0x10000 + char = chr(0xD800 | (v >> 10)) + chr(0xDC00 | (v & 0x3FF)) + + # Discard the ; if present. Otherwise, put it back on the queue and + # invoke parseError on parser. + if c != ";": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "numeric-entity-without-semicolon"}) + self.stream.unget(c) + + return char + + def consumeEntity(self, allowedChar=None, fromAttribute=False): + # Initialise to the default output for when no entity is matched + output = "&" + + charStack = [self.stream.char()] + if (charStack[0] in spaceCharacters or charStack[0] in (EOF, "<", "&") or + (allowedChar is not None and allowedChar == charStack[0])): + self.stream.unget(charStack[0]) + + elif charStack[0] == "#": + # Read the next character to see if it's hex or decimal + hex = False + charStack.append(self.stream.char()) + if charStack[-1] in ("x", "X"): + hex = True + charStack.append(self.stream.char()) + + # charStack[-1] should be the first digit + if (hex and charStack[-1] in hexDigits) \ + or (not hex and charStack[-1] in digits): + # At least one digit found, so consume the whole number + self.stream.unget(charStack[-1]) + output = self.consumeNumberEntity(hex) + else: + # No digits found + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "expected-numeric-entity"}) + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + + else: + # At this point in the process might have named entity. Entities + # are stored in the global variable "entities". + # + # Consume characters and compare to these to a substring of the + # entity names in the list until the substring no longer matches. + while (charStack[-1] is not EOF): + if not entitiesTrie.has_keys_with_prefix("".join(charStack)): + break + charStack.append(self.stream.char()) + + # At this point we have a string that starts with some characters + # that may match an entity + # Try to find the longest entity the string will match to take care + # of ¬i for instance. + try: + entityName = entitiesTrie.longest_prefix("".join(charStack[:-1])) + entityLength = len(entityName) + except KeyError: + entityName = None + + if entityName is not None: + if entityName[-1] != ";": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "named-entity-without-semicolon"}) + if (entityName[-1] != ";" and fromAttribute and + (charStack[entityLength] in asciiLetters or + charStack[entityLength] in digits or + charStack[entityLength] == "=")): + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + else: + output = entities[entityName] + self.stream.unget(charStack.pop()) + output += "".join(charStack[entityLength:]) + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-named-entity"}) + self.stream.unget(charStack.pop()) + output = "&" + "".join(charStack) + + if fromAttribute: + self.currentToken["data"][-1][1] += output + else: + if output in spaceCharacters: + tokenType = "SpaceCharacters" + else: + tokenType = "Characters" + self.tokenQueue.append({"type": tokenTypes[tokenType], "data": output}) + + def processEntityInAttribute(self, allowedChar): + """This method replaces the need for "entityInAttributeValueState". + """ + self.consumeEntity(allowedChar=allowedChar, fromAttribute=True) + + def emitCurrentToken(self): + """This method is a generic handler for emitting the tags. It also sets + the state to "data" because that's what's needed after a token has been + emitted. + """ + token = self.currentToken + # Add token to the queue to be yielded + if (token["type"] in tagTokenTypes): + token["name"] = token["name"].translate(asciiUpper2Lower) + if token["type"] == tokenTypes["EndTag"]: + if token["data"]: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "attributes-in-end-tag"}) + if token["selfClosing"]: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "self-closing-flag-on-end-tag"}) + self.tokenQueue.append(token) + self.state = self.dataState + + # Below are the various tokenizer states worked out. + def dataState(self): + data = self.stream.char() + if data == "&": + self.state = self.entityDataState + elif data == "<": + self.state = self.tagOpenState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\u0000"}) + elif data is EOF: + # Tokenization ends. + return False + elif data in spaceCharacters: + # Directly after emitting a token you switch back to the "data + # state". At that point spaceCharacters are important so they are + # emitted separately. + self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": + data + self.stream.charsUntil(spaceCharacters, True)}) + # No need to update lastFourChars here, since the first space will + # have already been appended to lastFourChars and will have broken + # any <!-- or --> sequences + else: + chars = self.stream.charsUntil(("&", "<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def entityDataState(self): + self.consumeEntity() + self.state = self.dataState + return True + + def rcdataState(self): + data = self.stream.char() + if data == "&": + self.state = self.characterReferenceInRcdata + elif data == "<": + self.state = self.rcdataLessThanSignState + elif data == EOF: + # Tokenization ends. + return False + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data in spaceCharacters: + # Directly after emitting a token you switch back to the "data + # state". At that point spaceCharacters are important so they are + # emitted separately. + self.tokenQueue.append({"type": tokenTypes["SpaceCharacters"], "data": + data + self.stream.charsUntil(spaceCharacters, True)}) + # No need to update lastFourChars here, since the first space will + # have already been appended to lastFourChars and will have broken + # any <!-- or --> sequences + else: + chars = self.stream.charsUntil(("&", "<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def characterReferenceInRcdata(self): + self.consumeEntity() + self.state = self.rcdataState + return True + + def rawtextState(self): + data = self.stream.char() + if data == "<": + self.state = self.rawtextLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + # Tokenization ends. + return False + else: + chars = self.stream.charsUntil(("<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def scriptDataState(self): + data = self.stream.char() + if data == "<": + self.state = self.scriptDataLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + # Tokenization ends. + return False + else: + chars = self.stream.charsUntil(("<", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def plaintextState(self): + data = self.stream.char() + if data == EOF: + # Tokenization ends. + return False + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + self.stream.charsUntil("\u0000")}) + return True + + def tagOpenState(self): + data = self.stream.char() + if data == "!": + self.state = self.markupDeclarationOpenState + elif data == "/": + self.state = self.closeTagOpenState + elif data in asciiLetters: + self.currentToken = {"type": tokenTypes["StartTag"], + "name": data, "data": [], + "selfClosing": False, + "selfClosingAcknowledged": False} + self.state = self.tagNameState + elif data == ">": + # XXX In theory it could be something besides a tag name. But + # do we really care? + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name-but-got-right-bracket"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<>"}) + self.state = self.dataState + elif data == "?": + # XXX In theory it could be something besides a tag name. But + # do we really care? + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name-but-got-question-mark"}) + self.stream.unget(data) + self.state = self.bogusCommentState + else: + # XXX + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-tag-name"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.dataState + return True + + def closeTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.currentToken = {"type": tokenTypes["EndTag"], "name": data, + "data": [], "selfClosing": False} + self.state = self.tagNameState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-right-bracket"}) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-eof"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.state = self.dataState + else: + # XXX data can be _'_... + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-closing-tag-but-got-char", + "datavars": {"data": data}}) + self.stream.unget(data) + self.state = self.bogusCommentState + return True + + def tagNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == ">": + self.emitCurrentToken() + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-tag-name"}) + self.state = self.dataState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] += "\uFFFD" + else: + self.currentToken["name"] += data + # (Don't use charsUntil here, because tag names are + # very short and it's faster to not do anything fancy) + return True + + def rcdataLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.rcdataEndTagOpenState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rcdataEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.rcdataEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rcdataEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.rcdataState + return True + + def rawtextLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.rawtextEndTagOpenState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def rawtextEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.rawtextEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def rawtextEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.rawtextState + return True + + def scriptDataLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.scriptDataEndTagOpenState + elif data == "!": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<!"}) + self.state = self.scriptDataEscapeStartState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer += data + self.state = self.scriptDataEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapeStartState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapeStartDashState + else: + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapeStartDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashDashState + else: + self.stream.unget(data) + self.state = self.scriptDataState + return True + + def scriptDataEscapedState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashState + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + self.state = self.dataState + else: + chars = self.stream.charsUntil(("<", "-", "\u0000")) + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": + data + chars}) + return True + + def scriptDataEscapedDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataEscapedDashDashState + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataEscapedState + elif data == EOF: + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedDashDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + elif data == "<": + self.state = self.scriptDataEscapedLessThanSignState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) + self.state = self.scriptDataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataEscapedState + elif data == EOF: + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.temporaryBuffer = "" + self.state = self.scriptDataEscapedEndTagOpenState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<" + data}) + self.temporaryBuffer = data + self.state = self.scriptDataDoubleEscapeStartState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedEndTagOpenState(self): + data = self.stream.char() + if data in asciiLetters: + self.temporaryBuffer = data + self.state = self.scriptDataEscapedEndTagNameState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "</"}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataEscapedEndTagNameState(self): + appropriate = self.currentToken and self.currentToken["name"].lower() == self.temporaryBuffer.lower() + data = self.stream.char() + if data in spaceCharacters and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.beforeAttributeNameState + elif data == "/" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.state = self.selfClosingStartTagState + elif data == ">" and appropriate: + self.currentToken = {"type": tokenTypes["EndTag"], + "name": self.temporaryBuffer, + "data": [], "selfClosing": False} + self.emitCurrentToken() + self.state = self.dataState + elif data in asciiLetters: + self.temporaryBuffer += data + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "</" + self.temporaryBuffer}) + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataDoubleEscapeStartState(self): + data = self.stream.char() + if data in (spaceCharacters | frozenset(("/", ">"))): + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + if self.temporaryBuffer.lower() == "script": + self.state = self.scriptDataDoubleEscapedState + else: + self.state = self.scriptDataEscapedState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.temporaryBuffer += data + else: + self.stream.unget(data) + self.state = self.scriptDataEscapedState + return True + + def scriptDataDoubleEscapedState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataDoubleEscapedDashState + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + return True + + def scriptDataDoubleEscapedDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + self.state = self.scriptDataDoubleEscapedDashDashState + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataDoubleEscapedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapedDashDashState(self): + data = self.stream.char() + if data == "-": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "-"}) + elif data == "<": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "<"}) + self.state = self.scriptDataDoubleEscapedLessThanSignState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": ">"}) + self.state = self.scriptDataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": "\uFFFD"}) + self.state = self.scriptDataDoubleEscapedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-script-in-script"}) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapedLessThanSignState(self): + data = self.stream.char() + if data == "/": + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": "/"}) + self.temporaryBuffer = "" + self.state = self.scriptDataDoubleEscapeEndState + else: + self.stream.unget(data) + self.state = self.scriptDataDoubleEscapedState + return True + + def scriptDataDoubleEscapeEndState(self): + data = self.stream.char() + if data in (spaceCharacters | frozenset(("/", ">"))): + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + if self.temporaryBuffer.lower() == "script": + self.state = self.scriptDataEscapedState + else: + self.state = self.scriptDataDoubleEscapedState + elif data in asciiLetters: + self.tokenQueue.append({"type": tokenTypes["Characters"], "data": data}) + self.temporaryBuffer += data + else: + self.stream.unget(data) + self.state = self.scriptDataDoubleEscapedState + return True + + def beforeAttributeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data in asciiLetters: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == ">": + self.emitCurrentToken() + elif data == "/": + self.state = self.selfClosingStartTagState + elif data in ("'", '"', "=", "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "invalid-character-in-attribute-name"}) + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"].append(["\uFFFD", ""]) + self.state = self.attributeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-name-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + return True + + def attributeNameState(self): + data = self.stream.char() + leavingThisState = True + emitToken = False + if data == "=": + self.state = self.beforeAttributeValueState + elif data in asciiLetters: + self.currentToken["data"][-1][0] += data +\ + self.stream.charsUntil(asciiLetters, True) + leavingThisState = False + elif data == ">": + # XXX If we emit here the attributes are converted to a dict + # without being checked and when the code below runs we error + # because data is a dict not a list + emitToken = True + elif data in spaceCharacters: + self.state = self.afterAttributeNameState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][0] += "\uFFFD" + leavingThisState = False + elif data in ("'", '"', "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "invalid-character-in-attribute-name"}) + self.currentToken["data"][-1][0] += data + leavingThisState = False + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "eof-in-attribute-name"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][0] += data + leavingThisState = False + + if leavingThisState: + # Attributes are not dropped at this stage. That happens when the + # start tag token is emitted so values can still be safely appended + # to attributes, but we do want to report the parse error in time. + self.currentToken["data"][-1][0] = ( + self.currentToken["data"][-1][0].translate(asciiUpper2Lower)) + for name, _ in self.currentToken["data"][:-1]: + if self.currentToken["data"][-1][0] == name: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "duplicate-attribute"}) + break + # XXX Fix for above XXX + if emitToken: + self.emitCurrentToken() + return True + + def afterAttributeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data == "=": + self.state = self.beforeAttributeValueState + elif data == ">": + self.emitCurrentToken() + elif data in asciiLetters: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data == "/": + self.state = self.selfClosingStartTagState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"].append(["\uFFFD", ""]) + self.state = self.attributeNameState + elif data in ("'", '"', "<"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "invalid-character-after-attribute-name"}) + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-end-of-tag-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"].append([data, ""]) + self.state = self.attributeNameState + return True + + def beforeAttributeValueState(self): + data = self.stream.char() + if data in spaceCharacters: + self.stream.charsUntil(spaceCharacters, True) + elif data == "\"": + self.state = self.attributeValueDoubleQuotedState + elif data == "&": + self.state = self.attributeValueUnQuotedState + self.stream.unget(data) + elif data == "'": + self.state = self.attributeValueSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-value-but-got-right-bracket"}) + self.emitCurrentToken() + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + self.state = self.attributeValueUnQuotedState + elif data in ("=", "<", "`"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "equals-in-unquoted-attribute-value"}) + self.currentToken["data"][-1][1] += data + self.state = self.attributeValueUnQuotedState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-attribute-value-but-got-eof"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data + self.state = self.attributeValueUnQuotedState + return True + + def attributeValueDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterAttributeValueState + elif data == "&": + self.processEntityInAttribute('"') + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-double-quote"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data +\ + self.stream.charsUntil(("\"", "&", "\u0000")) + return True + + def attributeValueSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterAttributeValueState + elif data == "&": + self.processEntityInAttribute("'") + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-single-quote"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data +\ + self.stream.charsUntil(("'", "&", "\u0000")) + return True + + def attributeValueUnQuotedState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == "&": + self.processEntityInAttribute(">") + elif data == ">": + self.emitCurrentToken() + elif data in ('"', "'", "=", "<", "`"): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-in-unquoted-attribute-value"}) + self.currentToken["data"][-1][1] += data + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"][-1][1] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-attribute-value-no-quotes"}) + self.state = self.dataState + else: + self.currentToken["data"][-1][1] += data + self.stream.charsUntil( + frozenset(("&", ">", '"', "'", "=", "<", "`", "\u0000")) | spaceCharacters) + return True + + def afterAttributeValueState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeAttributeNameState + elif data == ">": + self.emitCurrentToken() + elif data == "/": + self.state = self.selfClosingStartTagState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-EOF-after-attribute-value"}) + self.stream.unget(data) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-after-attribute-value"}) + self.stream.unget(data) + self.state = self.beforeAttributeNameState + return True + + def selfClosingStartTagState(self): + data = self.stream.char() + if data == ">": + self.currentToken["selfClosing"] = True + self.emitCurrentToken() + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": + "unexpected-EOF-after-solidus-in-tag"}) + self.stream.unget(data) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-character-after-solidus-in-tag"}) + self.stream.unget(data) + self.state = self.beforeAttributeNameState + return True + + def bogusCommentState(self): + # Make a new comment token and give it as value all the characters + # until the first > or EOF (charsUntil checks for EOF automatically) + # and emit it. + data = self.stream.charsUntil(">") + data = data.replace("\u0000", "\uFFFD") + self.tokenQueue.append( + {"type": tokenTypes["Comment"], "data": data}) + + # Eat the character directly after the bogus comment which is either a + # ">" or an EOF. + self.stream.char() + self.state = self.dataState + return True + + def markupDeclarationOpenState(self): + charStack = [self.stream.char()] + if charStack[-1] == "-": + charStack.append(self.stream.char()) + if charStack[-1] == "-": + self.currentToken = {"type": tokenTypes["Comment"], "data": ""} + self.state = self.commentStartState + return True + elif charStack[-1] in ('d', 'D'): + matched = True + for expected in (('o', 'O'), ('c', 'C'), ('t', 'T'), + ('y', 'Y'), ('p', 'P'), ('e', 'E')): + charStack.append(self.stream.char()) + if charStack[-1] not in expected: + matched = False + break + if matched: + self.currentToken = {"type": tokenTypes["Doctype"], + "name": "", + "publicId": None, "systemId": None, + "correct": True} + self.state = self.doctypeState + return True + elif (charStack[-1] == "[" and + self.parser is not None and + self.parser.tree.openElements and + self.parser.tree.openElements[-1].namespace != self.parser.tree.defaultNamespace): + matched = True + for expected in ["C", "D", "A", "T", "A", "["]: + charStack.append(self.stream.char()) + if charStack[-1] != expected: + matched = False + break + if matched: + self.state = self.cdataSectionState + return True + + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-dashes-or-doctype"}) + + while charStack: + self.stream.unget(charStack.pop()) + self.state = self.bogusCommentState + return True + + def commentStartState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentStartDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "incorrect-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += data + self.state = self.commentState + return True + + def commentStartDashState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "-\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "incorrect-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "-" + data + self.state = self.commentState + return True + + def commentState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "\uFFFD" + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "eof-in-comment"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += data + \ + self.stream.charsUntil(("-", "\u0000")) + return True + + def commentEndDashState(self): + data = self.stream.char() + if data == "-": + self.state = self.commentEndState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "-\uFFFD" + self.state = self.commentState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-end-dash"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "-" + data + self.state = self.commentState + return True + + def commentEndState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "--\uFFFD" + self.state = self.commentState + elif data == "!": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-bang-after-double-dash-in-comment"}) + self.state = self.commentEndBangState + elif data == "-": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-dash-after-double-dash-in-comment"}) + self.currentToken["data"] += data + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-double-dash"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + # XXX + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-comment"}) + self.currentToken["data"] += "--" + data + self.state = self.commentState + return True + + def commentEndBangState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "-": + self.currentToken["data"] += "--!" + self.state = self.commentEndDashState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["data"] += "--!\uFFFD" + self.state = self.commentState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-comment-end-bang-state"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["data"] += "--!" + data + self.state = self.commentState + return True + + def doctypeState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-eof"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "need-space-after-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypeNameState + return True + + def beforeDoctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-right-bracket"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] = "\uFFFD" + self.state = self.doctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-doctype-name-but-got-eof"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["name"] = data + self.state = self.doctypeNameState + return True + + def doctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.state = self.afterDoctypeNameState + elif data == ">": + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["name"] += "\uFFFD" + self.state = self.doctypeNameState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype-name"}) + self.currentToken["correct"] = False + self.currentToken["name"] = self.currentToken["name"].translate(asciiUpper2Lower) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["name"] += data + return True + + def afterDoctypeNameState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.currentToken["correct"] = False + self.stream.unget(data) + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + if data in ("p", "P"): + matched = True + for expected in (("u", "U"), ("b", "B"), ("l", "L"), + ("i", "I"), ("c", "C")): + data = self.stream.char() + if data not in expected: + matched = False + break + if matched: + self.state = self.afterDoctypePublicKeywordState + return True + elif data in ("s", "S"): + matched = True + for expected in (("y", "Y"), ("s", "S"), ("t", "T"), + ("e", "E"), ("m", "M")): + data = self.stream.char() + if data not in expected: + matched = False + break + if matched: + self.state = self.afterDoctypeSystemKeywordState + return True + + # All the characters read before the current 'data' will be + # [a-zA-Z], so they're garbage in the bogus doctype and can be + # discarded; only the latest character might be '>' or EOF + # and needs to be ungetted + self.stream.unget(data) + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "expected-space-or-right-bracket-in-doctype", "datavars": + {"data": data}}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + + return True + + def afterDoctypePublicKeywordState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypePublicIdentifierState + elif data in ("'", '"'): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypePublicIdentifierState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.stream.unget(data) + self.state = self.beforeDoctypePublicIdentifierState + return True + + def beforeDoctypePublicIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == "\"": + self.currentToken["publicId"] = "" + self.state = self.doctypePublicIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["publicId"] = "" + self.state = self.doctypePublicIdentifierSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def doctypePublicIdentifierDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterDoctypePublicIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["publicId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["publicId"] += data + return True + + def doctypePublicIdentifierSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterDoctypePublicIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["publicId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["publicId"] += data + return True + + def afterDoctypePublicIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.betweenDoctypePublicAndSystemIdentifiersState + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == '"': + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def betweenDoctypePublicAndSystemIdentifiersState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data == '"': + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data == EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def afterDoctypeSystemKeywordState(self): + data = self.stream.char() + if data in spaceCharacters: + self.state = self.beforeDoctypeSystemIdentifierState + elif data in ("'", '"'): + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.stream.unget(data) + self.state = self.beforeDoctypeSystemIdentifierState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.stream.unget(data) + self.state = self.beforeDoctypeSystemIdentifierState + return True + + def beforeDoctypeSystemIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == "\"": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierDoubleQuotedState + elif data == "'": + self.currentToken["systemId"] = "" + self.state = self.doctypeSystemIdentifierSingleQuotedState + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.currentToken["correct"] = False + self.state = self.bogusDoctypeState + return True + + def doctypeSystemIdentifierDoubleQuotedState(self): + data = self.stream.char() + if data == "\"": + self.state = self.afterDoctypeSystemIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["systemId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["systemId"] += data + return True + + def doctypeSystemIdentifierSingleQuotedState(self): + data = self.stream.char() + if data == "'": + self.state = self.afterDoctypeSystemIdentifierState + elif data == "\u0000": + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + self.currentToken["systemId"] += "\uFFFD" + elif data == ">": + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-end-of-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.currentToken["systemId"] += data + return True + + def afterDoctypeSystemIdentifierState(self): + data = self.stream.char() + if data in spaceCharacters: + pass + elif data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "eof-in-doctype"}) + self.currentToken["correct"] = False + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + self.tokenQueue.append({"type": tokenTypes["ParseError"], "data": + "unexpected-char-in-doctype"}) + self.state = self.bogusDoctypeState + return True + + def bogusDoctypeState(self): + data = self.stream.char() + if data == ">": + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + elif data is EOF: + # XXX EMIT + self.stream.unget(data) + self.tokenQueue.append(self.currentToken) + self.state = self.dataState + else: + pass + return True + + def cdataSectionState(self): + data = [] + while True: + data.append(self.stream.charsUntil("]")) + data.append(self.stream.charsUntil(">")) + char = self.stream.char() + if char == EOF: + break + else: + assert char == ">" + if data[-1][-2:] == "]]": + data[-1] = data[-1][:-2] + break + else: + data.append(char) + + data = "".join(data) # pylint:disable=redefined-variable-type + # Deal with null here rather than in the parser + nullCount = data.count("\u0000") + if nullCount > 0: + for _ in range(nullCount): + self.tokenQueue.append({"type": tokenTypes["ParseError"], + "data": "invalid-codepoint"}) + data = data.replace("\u0000", "\uFFFD") + if data: + self.tokenQueue.append({"type": tokenTypes["Characters"], + "data": data}) + self.state = self.dataState + return True diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py new file mode 100755 index 0000000..ccc70bd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/__init__.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, unicode_literals + +from .py import Trie as PyTrie + +Trie = PyTrie + +# pylint:disable=wrong-import-position +try: + from .datrie import Trie as DATrie +except ImportError: + pass +else: + Trie = DATrie +# pylint:enable=wrong-import-position diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py new file mode 100755 index 0000000..ecfff32 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/_base.py @@ -0,0 +1,37 @@ +from __future__ import absolute_import, division, unicode_literals + +from collections import Mapping + + +class Trie(Mapping): + """Abstract base class for tries""" + + def keys(self, prefix=None): + # pylint:disable=arguments-differ + keys = super(Trie, self).keys() + + if prefix is None: + return set(keys) + + return {x for x in keys if x.startswith(prefix)} + + def has_keys_with_prefix(self, prefix): + for key in self.keys(): + if key.startswith(prefix): + return True + + return False + + def longest_prefix(self, prefix): + if prefix in self: + return prefix + + for i in range(1, len(prefix) + 1): + if prefix[:-i] in self: + return prefix[:-i] + + raise KeyError(prefix) + + def longest_prefix_item(self, prefix): + lprefix = self.longest_prefix(prefix) + return (lprefix, self[lprefix]) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py new file mode 100755 index 0000000..cb1af60 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/datrie.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import, division, unicode_literals + +from datrie import Trie as DATrie +from pip._vendor.six import text_type + +from ._base import Trie as ABCTrie + + +class Trie(ABCTrie): + def __init__(self, data): + chars = set() + for key in data.keys(): + if not isinstance(key, text_type): + raise TypeError("All keys must be strings") + for char in key: + chars.add(char) + + self._data = DATrie("".join(chars)) + for key, value in data.items(): + self._data[key] = value + + def __contains__(self, key): + return key in self._data + + def __len__(self): + return len(self._data) + + def __iter__(self): + raise NotImplementedError() + + def __getitem__(self, key): + return self._data[key] + + def keys(self, prefix=None): + return self._data.keys(prefix) + + def has_keys_with_prefix(self, prefix): + return self._data.has_keys_with_prefix(prefix) + + def longest_prefix(self, prefix): + return self._data.longest_prefix(prefix) + + def longest_prefix_item(self, prefix): + return self._data.longest_prefix_item(prefix) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py new file mode 100755 index 0000000..5531263 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_trie/py.py @@ -0,0 +1,67 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from bisect import bisect_left + +from ._base import Trie as ABCTrie + + +class Trie(ABCTrie): + def __init__(self, data): + if not all(isinstance(x, text_type) for x in data.keys()): + raise TypeError("All keys must be strings") + + self._data = data + self._keys = sorted(data.keys()) + self._cachestr = "" + self._cachepoints = (0, len(data)) + + def __contains__(self, key): + return key in self._data + + def __len__(self): + return len(self._data) + + def __iter__(self): + return iter(self._data) + + def __getitem__(self, key): + return self._data[key] + + def keys(self, prefix=None): + if prefix is None or prefix == "" or not self._keys: + return set(self._keys) + + if prefix.startswith(self._cachestr): + lo, hi = self._cachepoints + start = i = bisect_left(self._keys, prefix, lo, hi) + else: + start = i = bisect_left(self._keys, prefix) + + keys = set() + if start == len(self._keys): + return keys + + while self._keys[i].startswith(prefix): + keys.add(self._keys[i]) + i += 1 + + self._cachestr = prefix + self._cachepoints = (start, i) + + return keys + + def has_keys_with_prefix(self, prefix): + if prefix in self._data: + return True + + if prefix.startswith(self._cachestr): + lo, hi = self._cachepoints + i = bisect_left(self._keys, prefix, lo, hi) + else: + i = bisect_left(self._keys, prefix) + + if i == len(self._keys): + return False + + return self._keys[i].startswith(prefix) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py new file mode 100755 index 0000000..a559fa0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/_utils.py @@ -0,0 +1,124 @@ +from __future__ import absolute_import, division, unicode_literals + +from types import ModuleType + +from pip._vendor.six import text_type + +try: + import xml.etree.cElementTree as default_etree +except ImportError: + import xml.etree.ElementTree as default_etree + + +__all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair", + "surrogatePairToCodepoint", "moduleFactoryFactory", + "supports_lone_surrogates"] + + +# Platforms not supporting lone surrogates (\uD800-\uDFFF) should be +# caught by the below test. In general this would be any platform +# using UTF-16 as its encoding of unicode strings, such as +# Jython. This is because UTF-16 itself is based on the use of such +# surrogates, and there is no mechanism to further escape such +# escapes. +try: + _x = eval('"\\uD800"') # pylint:disable=eval-used + if not isinstance(_x, text_type): + # We need this with u"" because of http://bugs.jython.org/issue2039 + _x = eval('u"\\uD800"') # pylint:disable=eval-used + assert isinstance(_x, text_type) +except: # pylint:disable=bare-except + supports_lone_surrogates = False +else: + supports_lone_surrogates = True + + +class MethodDispatcher(dict): + """Dict with 2 special properties: + + On initiation, keys that are lists, sets or tuples are converted to + multiple keys so accessing any one of the items in the original + list-like object returns the matching value + + md = MethodDispatcher({("foo", "bar"):"baz"}) + md["foo"] == "baz" + + A default value which can be set through the default attribute. + """ + + def __init__(self, items=()): + # Using _dictEntries instead of directly assigning to self is about + # twice as fast. Please do careful performance testing before changing + # anything here. + _dictEntries = [] + for name, value in items: + if isinstance(name, (list, tuple, frozenset, set)): + for item in name: + _dictEntries.append((item, value)) + else: + _dictEntries.append((name, value)) + dict.__init__(self, _dictEntries) + assert len(self) == len(_dictEntries) + self.default = None + + def __getitem__(self, key): + return dict.get(self, key, self.default) + + +# Some utility functions to deal with weirdness around UCS2 vs UCS4 +# python builds + +def isSurrogatePair(data): + return (len(data) == 2 and + ord(data[0]) >= 0xD800 and ord(data[0]) <= 0xDBFF and + ord(data[1]) >= 0xDC00 and ord(data[1]) <= 0xDFFF) + + +def surrogatePairToCodepoint(data): + char_val = (0x10000 + (ord(data[0]) - 0xD800) * 0x400 + + (ord(data[1]) - 0xDC00)) + return char_val + +# Module Factory Factory (no, this isn't Java, I know) +# Here to stop this being duplicated all over the place. + + +def moduleFactoryFactory(factory): + moduleCache = {} + + def moduleFactory(baseModule, *args, **kwargs): + if isinstance(ModuleType.__name__, type("")): + name = "_%s_factory" % baseModule.__name__ + else: + name = b"_%s_factory" % baseModule.__name__ + + kwargs_tuple = tuple(kwargs.items()) + + try: + return moduleCache[name][args][kwargs_tuple] + except KeyError: + mod = ModuleType(name) + objs = factory(baseModule, *args, **kwargs) + mod.__dict__.update(objs) + if "name" not in moduleCache: + moduleCache[name] = {} + if "args" not in moduleCache[name]: + moduleCache[name][args] = {} + if "kwargs" not in moduleCache[name][args]: + moduleCache[name][args][kwargs_tuple] = {} + moduleCache[name][args][kwargs_tuple] = mod + return mod + + return moduleFactory + + +def memoize(func): + cache = {} + + def wrapped(*args, **kwargs): + key = (tuple(args), tuple(kwargs.items())) + if key not in cache: + cache[key] = func(*args, **kwargs) + return cache[key] + + return wrapped diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py new file mode 100755 index 0000000..bca155e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/constants.py @@ -0,0 +1,2947 @@ +from __future__ import absolute_import, division, unicode_literals + +import string + +EOF = None + +E = { + "null-character": + "Null character in input stream, replaced with U+FFFD.", + "invalid-codepoint": + "Invalid codepoint in stream.", + "incorrectly-placed-solidus": + "Solidus (/) incorrectly placed in tag.", + "incorrect-cr-newline-entity": + "Incorrect CR newline entity, replaced with LF.", + "illegal-windows-1252-entity": + "Entity used with illegal number (windows-1252 reference).", + "cant-convert-numeric-entity": + "Numeric entity couldn't be converted to character " + "(codepoint U+%(charAsInt)08x).", + "illegal-codepoint-for-numeric-entity": + "Numeric entity represents an illegal codepoint: " + "U+%(charAsInt)08x.", + "numeric-entity-without-semicolon": + "Numeric entity didn't end with ';'.", + "expected-numeric-entity-but-got-eof": + "Numeric entity expected. Got end of file instead.", + "expected-numeric-entity": + "Numeric entity expected but none found.", + "named-entity-without-semicolon": + "Named entity didn't end with ';'.", + "expected-named-entity": + "Named entity expected. Got none.", + "attributes-in-end-tag": + "End tag contains unexpected attributes.", + 'self-closing-flag-on-end-tag': + "End tag contains unexpected self-closing flag.", + "expected-tag-name-but-got-right-bracket": + "Expected tag name. Got '>' instead.", + "expected-tag-name-but-got-question-mark": + "Expected tag name. Got '?' instead. (HTML doesn't " + "support processing instructions.)", + "expected-tag-name": + "Expected tag name. Got something else instead", + "expected-closing-tag-but-got-right-bracket": + "Expected closing tag. Got '>' instead. Ignoring '</>'.", + "expected-closing-tag-but-got-eof": + "Expected closing tag. Unexpected end of file.", + "expected-closing-tag-but-got-char": + "Expected closing tag. Unexpected character '%(data)s' found.", + "eof-in-tag-name": + "Unexpected end of file in the tag name.", + "expected-attribute-name-but-got-eof": + "Unexpected end of file. Expected attribute name instead.", + "eof-in-attribute-name": + "Unexpected end of file in attribute name.", + "invalid-character-in-attribute-name": + "Invalid character in attribute name", + "duplicate-attribute": + "Dropped duplicate attribute on tag.", + "expected-end-of-tag-name-but-got-eof": + "Unexpected end of file. Expected = or end of tag.", + "expected-attribute-value-but-got-eof": + "Unexpected end of file. Expected attribute value.", + "expected-attribute-value-but-got-right-bracket": + "Expected attribute value. Got '>' instead.", + 'equals-in-unquoted-attribute-value': + "Unexpected = in unquoted attribute", + 'unexpected-character-in-unquoted-attribute-value': + "Unexpected character in unquoted attribute", + "invalid-character-after-attribute-name": + "Unexpected character after attribute name.", + "unexpected-character-after-attribute-value": + "Unexpected character after attribute value.", + "eof-in-attribute-value-double-quote": + "Unexpected end of file in attribute value (\").", + "eof-in-attribute-value-single-quote": + "Unexpected end of file in attribute value (').", + "eof-in-attribute-value-no-quotes": + "Unexpected end of file in attribute value.", + "unexpected-EOF-after-solidus-in-tag": + "Unexpected end of file in tag. Expected >", + "unexpected-character-after-solidus-in-tag": + "Unexpected character after / in tag. Expected >", + "expected-dashes-or-doctype": + "Expected '--' or 'DOCTYPE'. Not found.", + "unexpected-bang-after-double-dash-in-comment": + "Unexpected ! after -- in comment", + "unexpected-space-after-double-dash-in-comment": + "Unexpected space after -- in comment", + "incorrect-comment": + "Incorrect comment.", + "eof-in-comment": + "Unexpected end of file in comment.", + "eof-in-comment-end-dash": + "Unexpected end of file in comment (-)", + "unexpected-dash-after-double-dash-in-comment": + "Unexpected '-' after '--' found in comment.", + "eof-in-comment-double-dash": + "Unexpected end of file in comment (--).", + "eof-in-comment-end-space-state": + "Unexpected end of file in comment.", + "eof-in-comment-end-bang-state": + "Unexpected end of file in comment.", + "unexpected-char-in-comment": + "Unexpected character in comment found.", + "need-space-after-doctype": + "No space after literal string 'DOCTYPE'.", + "expected-doctype-name-but-got-right-bracket": + "Unexpected > character. Expected DOCTYPE name.", + "expected-doctype-name-but-got-eof": + "Unexpected end of file. Expected DOCTYPE name.", + "eof-in-doctype-name": + "Unexpected end of file in DOCTYPE name.", + "eof-in-doctype": + "Unexpected end of file in DOCTYPE.", + "expected-space-or-right-bracket-in-doctype": + "Expected space or '>'. Got '%(data)s'", + "unexpected-end-of-doctype": + "Unexpected end of DOCTYPE.", + "unexpected-char-in-doctype": + "Unexpected character in DOCTYPE.", + "eof-in-innerhtml": + "XXX innerHTML EOF", + "unexpected-doctype": + "Unexpected DOCTYPE. Ignored.", + "non-html-root": + "html needs to be the first start tag.", + "expected-doctype-but-got-eof": + "Unexpected End of file. Expected DOCTYPE.", + "unknown-doctype": + "Erroneous DOCTYPE.", + "expected-doctype-but-got-chars": + "Unexpected non-space characters. Expected DOCTYPE.", + "expected-doctype-but-got-start-tag": + "Unexpected start tag (%(name)s). Expected DOCTYPE.", + "expected-doctype-but-got-end-tag": + "Unexpected end tag (%(name)s). Expected DOCTYPE.", + "end-tag-after-implied-root": + "Unexpected end tag (%(name)s) after the (implied) root element.", + "expected-named-closing-tag-but-got-eof": + "Unexpected end of file. Expected end tag (%(name)s).", + "two-heads-are-not-better-than-one": + "Unexpected start tag head in existing head. Ignored.", + "unexpected-end-tag": + "Unexpected end tag (%(name)s). Ignored.", + "unexpected-start-tag-out-of-my-head": + "Unexpected start tag (%(name)s) that can be in head. Moved.", + "unexpected-start-tag": + "Unexpected start tag (%(name)s).", + "missing-end-tag": + "Missing end tag (%(name)s).", + "missing-end-tags": + "Missing end tags (%(name)s).", + "unexpected-start-tag-implies-end-tag": + "Unexpected start tag (%(startName)s) " + "implies end tag (%(endName)s).", + "unexpected-start-tag-treated-as": + "Unexpected start tag (%(originalName)s). Treated as %(newName)s.", + "deprecated-tag": + "Unexpected start tag %(name)s. Don't use it!", + "unexpected-start-tag-ignored": + "Unexpected start tag %(name)s. Ignored.", + "expected-one-end-tag-but-got-another": + "Unexpected end tag (%(gotName)s). " + "Missing end tag (%(expectedName)s).", + "end-tag-too-early": + "End tag (%(name)s) seen too early. Expected other end tag.", + "end-tag-too-early-named": + "Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s).", + "end-tag-too-early-ignored": + "End tag (%(name)s) seen too early. Ignored.", + "adoption-agency-1.1": + "End tag (%(name)s) violates step 1, " + "paragraph 1 of the adoption agency algorithm.", + "adoption-agency-1.2": + "End tag (%(name)s) violates step 1, " + "paragraph 2 of the adoption agency algorithm.", + "adoption-agency-1.3": + "End tag (%(name)s) violates step 1, " + "paragraph 3 of the adoption agency algorithm.", + "adoption-agency-4.4": + "End tag (%(name)s) violates step 4, " + "paragraph 4 of the adoption agency algorithm.", + "unexpected-end-tag-treated-as": + "Unexpected end tag (%(originalName)s). Treated as %(newName)s.", + "no-end-tag": + "This element (%(name)s) has no end tag.", + "unexpected-implied-end-tag-in-table": + "Unexpected implied end tag (%(name)s) in the table phase.", + "unexpected-implied-end-tag-in-table-body": + "Unexpected implied end tag (%(name)s) in the table body phase.", + "unexpected-char-implies-table-voodoo": + "Unexpected non-space characters in " + "table context caused voodoo mode.", + "unexpected-hidden-input-in-table": + "Unexpected input with type hidden in table context.", + "unexpected-form-in-table": + "Unexpected form in table context.", + "unexpected-start-tag-implies-table-voodoo": + "Unexpected start tag (%(name)s) in " + "table context caused voodoo mode.", + "unexpected-end-tag-implies-table-voodoo": + "Unexpected end tag (%(name)s) in " + "table context caused voodoo mode.", + "unexpected-cell-in-table-body": + "Unexpected table cell start tag (%(name)s) " + "in the table body phase.", + "unexpected-cell-end-tag": + "Got table cell end tag (%(name)s) " + "while required end tags are missing.", + "unexpected-end-tag-in-table-body": + "Unexpected end tag (%(name)s) in the table body phase. Ignored.", + "unexpected-implied-end-tag-in-table-row": + "Unexpected implied end tag (%(name)s) in the table row phase.", + "unexpected-end-tag-in-table-row": + "Unexpected end tag (%(name)s) in the table row phase. Ignored.", + "unexpected-select-in-select": + "Unexpected select start tag in the select phase " + "treated as select end tag.", + "unexpected-input-in-select": + "Unexpected input start tag in the select phase.", + "unexpected-start-tag-in-select": + "Unexpected start tag token (%(name)s in the select phase. " + "Ignored.", + "unexpected-end-tag-in-select": + "Unexpected end tag (%(name)s) in the select phase. Ignored.", + "unexpected-table-element-start-tag-in-select-in-table": + "Unexpected table element start tag (%(name)s) in the select in table phase.", + "unexpected-table-element-end-tag-in-select-in-table": + "Unexpected table element end tag (%(name)s) in the select in table phase.", + "unexpected-char-after-body": + "Unexpected non-space characters in the after body phase.", + "unexpected-start-tag-after-body": + "Unexpected start tag token (%(name)s)" + " in the after body phase.", + "unexpected-end-tag-after-body": + "Unexpected end tag token (%(name)s)" + " in the after body phase.", + "unexpected-char-in-frameset": + "Unexpected characters in the frameset phase. Characters ignored.", + "unexpected-start-tag-in-frameset": + "Unexpected start tag token (%(name)s)" + " in the frameset phase. Ignored.", + "unexpected-frameset-in-frameset-innerhtml": + "Unexpected end tag token (frameset) " + "in the frameset phase (innerHTML).", + "unexpected-end-tag-in-frameset": + "Unexpected end tag token (%(name)s)" + " in the frameset phase. Ignored.", + "unexpected-char-after-frameset": + "Unexpected non-space characters in the " + "after frameset phase. Ignored.", + "unexpected-start-tag-after-frameset": + "Unexpected start tag (%(name)s)" + " in the after frameset phase. Ignored.", + "unexpected-end-tag-after-frameset": + "Unexpected end tag (%(name)s)" + " in the after frameset phase. Ignored.", + "unexpected-end-tag-after-body-innerhtml": + "Unexpected end tag after body(innerHtml)", + "expected-eof-but-got-char": + "Unexpected non-space characters. Expected end of file.", + "expected-eof-but-got-start-tag": + "Unexpected start tag (%(name)s)" + ". Expected end of file.", + "expected-eof-but-got-end-tag": + "Unexpected end tag (%(name)s)" + ". Expected end of file.", + "eof-in-table": + "Unexpected end of file. Expected table content.", + "eof-in-select": + "Unexpected end of file. Expected select content.", + "eof-in-frameset": + "Unexpected end of file. Expected frameset content.", + "eof-in-script-in-script": + "Unexpected end of file. Expected script content.", + "eof-in-foreign-lands": + "Unexpected end of file. Expected foreign content", + "non-void-element-with-trailing-solidus": + "Trailing solidus not allowed on element %(name)s", + "unexpected-html-element-in-foreign-content": + "Element %(name)s not allowed in a non-html context", + "unexpected-end-tag-before-html": + "Unexpected end tag (%(name)s) before html.", + "unexpected-inhead-noscript-tag": + "Element %(name)s not allowed in a inhead-noscript context", + "eof-in-head-noscript": + "Unexpected end of file. Expected inhead-noscript content", + "char-in-head-noscript": + "Unexpected non-space character. Expected inhead-noscript content", + "XXX-undefined-error": + "Undefined error (this sucks and should be fixed)", +} + +namespaces = { + "html": "http://www.w3.org/1999/xhtml", + "mathml": "http://www.w3.org/1998/Math/MathML", + "svg": "http://www.w3.org/2000/svg", + "xlink": "http://www.w3.org/1999/xlink", + "xml": "http://www.w3.org/XML/1998/namespace", + "xmlns": "http://www.w3.org/2000/xmlns/" +} + +scopingElements = frozenset([ + (namespaces["html"], "applet"), + (namespaces["html"], "caption"), + (namespaces["html"], "html"), + (namespaces["html"], "marquee"), + (namespaces["html"], "object"), + (namespaces["html"], "table"), + (namespaces["html"], "td"), + (namespaces["html"], "th"), + (namespaces["mathml"], "mi"), + (namespaces["mathml"], "mo"), + (namespaces["mathml"], "mn"), + (namespaces["mathml"], "ms"), + (namespaces["mathml"], "mtext"), + (namespaces["mathml"], "annotation-xml"), + (namespaces["svg"], "foreignObject"), + (namespaces["svg"], "desc"), + (namespaces["svg"], "title"), +]) + +formattingElements = frozenset([ + (namespaces["html"], "a"), + (namespaces["html"], "b"), + (namespaces["html"], "big"), + (namespaces["html"], "code"), + (namespaces["html"], "em"), + (namespaces["html"], "font"), + (namespaces["html"], "i"), + (namespaces["html"], "nobr"), + (namespaces["html"], "s"), + (namespaces["html"], "small"), + (namespaces["html"], "strike"), + (namespaces["html"], "strong"), + (namespaces["html"], "tt"), + (namespaces["html"], "u") +]) + +specialElements = frozenset([ + (namespaces["html"], "address"), + (namespaces["html"], "applet"), + (namespaces["html"], "area"), + (namespaces["html"], "article"), + (namespaces["html"], "aside"), + (namespaces["html"], "base"), + (namespaces["html"], "basefont"), + (namespaces["html"], "bgsound"), + (namespaces["html"], "blockquote"), + (namespaces["html"], "body"), + (namespaces["html"], "br"), + (namespaces["html"], "button"), + (namespaces["html"], "caption"), + (namespaces["html"], "center"), + (namespaces["html"], "col"), + (namespaces["html"], "colgroup"), + (namespaces["html"], "command"), + (namespaces["html"], "dd"), + (namespaces["html"], "details"), + (namespaces["html"], "dir"), + (namespaces["html"], "div"), + (namespaces["html"], "dl"), + (namespaces["html"], "dt"), + (namespaces["html"], "embed"), + (namespaces["html"], "fieldset"), + (namespaces["html"], "figure"), + (namespaces["html"], "footer"), + (namespaces["html"], "form"), + (namespaces["html"], "frame"), + (namespaces["html"], "frameset"), + (namespaces["html"], "h1"), + (namespaces["html"], "h2"), + (namespaces["html"], "h3"), + (namespaces["html"], "h4"), + (namespaces["html"], "h5"), + (namespaces["html"], "h6"), + (namespaces["html"], "head"), + (namespaces["html"], "header"), + (namespaces["html"], "hr"), + (namespaces["html"], "html"), + (namespaces["html"], "iframe"), + # Note that image is commented out in the spec as "this isn't an + # element that can end up on the stack, so it doesn't matter," + (namespaces["html"], "image"), + (namespaces["html"], "img"), + (namespaces["html"], "input"), + (namespaces["html"], "isindex"), + (namespaces["html"], "li"), + (namespaces["html"], "link"), + (namespaces["html"], "listing"), + (namespaces["html"], "marquee"), + (namespaces["html"], "menu"), + (namespaces["html"], "meta"), + (namespaces["html"], "nav"), + (namespaces["html"], "noembed"), + (namespaces["html"], "noframes"), + (namespaces["html"], "noscript"), + (namespaces["html"], "object"), + (namespaces["html"], "ol"), + (namespaces["html"], "p"), + (namespaces["html"], "param"), + (namespaces["html"], "plaintext"), + (namespaces["html"], "pre"), + (namespaces["html"], "script"), + (namespaces["html"], "section"), + (namespaces["html"], "select"), + (namespaces["html"], "style"), + (namespaces["html"], "table"), + (namespaces["html"], "tbody"), + (namespaces["html"], "td"), + (namespaces["html"], "textarea"), + (namespaces["html"], "tfoot"), + (namespaces["html"], "th"), + (namespaces["html"], "thead"), + (namespaces["html"], "title"), + (namespaces["html"], "tr"), + (namespaces["html"], "ul"), + (namespaces["html"], "wbr"), + (namespaces["html"], "xmp"), + (namespaces["svg"], "foreignObject") +]) + +htmlIntegrationPointElements = frozenset([ + (namespaces["mathml"], "annotation-xml"), + (namespaces["svg"], "foreignObject"), + (namespaces["svg"], "desc"), + (namespaces["svg"], "title") +]) + +mathmlTextIntegrationPointElements = frozenset([ + (namespaces["mathml"], "mi"), + (namespaces["mathml"], "mo"), + (namespaces["mathml"], "mn"), + (namespaces["mathml"], "ms"), + (namespaces["mathml"], "mtext") +]) + +adjustSVGAttributes = { + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "contentscripttype": "contentScriptType", + "contentstyletype": "contentStyleType", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "externalresourcesrequired": "externalResourcesRequired", + "filterres": "filterRes", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan" +} + +adjustMathMLAttributes = {"definitionurl": "definitionURL"} + +adjustForeignAttributes = { + "xlink:actuate": ("xlink", "actuate", namespaces["xlink"]), + "xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]), + "xlink:href": ("xlink", "href", namespaces["xlink"]), + "xlink:role": ("xlink", "role", namespaces["xlink"]), + "xlink:show": ("xlink", "show", namespaces["xlink"]), + "xlink:title": ("xlink", "title", namespaces["xlink"]), + "xlink:type": ("xlink", "type", namespaces["xlink"]), + "xml:base": ("xml", "base", namespaces["xml"]), + "xml:lang": ("xml", "lang", namespaces["xml"]), + "xml:space": ("xml", "space", namespaces["xml"]), + "xmlns": (None, "xmlns", namespaces["xmlns"]), + "xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"]) +} + +unadjustForeignAttributes = dict([((ns, local), qname) for qname, (prefix, local, ns) in + adjustForeignAttributes.items()]) + +spaceCharacters = frozenset([ + "\t", + "\n", + "\u000C", + " ", + "\r" +]) + +tableInsertModeElements = frozenset([ + "table", + "tbody", + "tfoot", + "thead", + "tr" +]) + +asciiLowercase = frozenset(string.ascii_lowercase) +asciiUppercase = frozenset(string.ascii_uppercase) +asciiLetters = frozenset(string.ascii_letters) +digits = frozenset(string.digits) +hexDigits = frozenset(string.hexdigits) + +asciiUpper2Lower = dict([(ord(c), ord(c.lower())) + for c in string.ascii_uppercase]) + +# Heading elements need to be ordered +headingElements = ( + "h1", + "h2", + "h3", + "h4", + "h5", + "h6" +) + +voidElements = frozenset([ + "base", + "command", + "event-source", + "link", + "meta", + "hr", + "br", + "img", + "embed", + "param", + "area", + "col", + "input", + "source", + "track" +]) + +cdataElements = frozenset(['title', 'textarea']) + +rcdataElements = frozenset([ + 'style', + 'script', + 'xmp', + 'iframe', + 'noembed', + 'noframes', + 'noscript' +]) + +booleanAttributes = { + "": frozenset(["irrelevant", "itemscope"]), + "style": frozenset(["scoped"]), + "img": frozenset(["ismap"]), + "audio": frozenset(["autoplay", "controls"]), + "video": frozenset(["autoplay", "controls"]), + "script": frozenset(["defer", "async"]), + "details": frozenset(["open"]), + "datagrid": frozenset(["multiple", "disabled"]), + "command": frozenset(["hidden", "disabled", "checked", "default"]), + "hr": frozenset(["noshade"]), + "menu": frozenset(["autosubmit"]), + "fieldset": frozenset(["disabled", "readonly"]), + "option": frozenset(["disabled", "readonly", "selected"]), + "optgroup": frozenset(["disabled", "readonly"]), + "button": frozenset(["disabled", "autofocus"]), + "input": frozenset(["disabled", "readonly", "required", "autofocus", "checked", "ismap"]), + "select": frozenset(["disabled", "readonly", "autofocus", "multiple"]), + "output": frozenset(["disabled", "readonly"]), + "iframe": frozenset(["seamless"]), +} + +# entitiesWindows1252 has to be _ordered_ and needs to have an index. It +# therefore can't be a frozenset. +entitiesWindows1252 = ( + 8364, # 0x80 0x20AC EURO SIGN + 65533, # 0x81 UNDEFINED + 8218, # 0x82 0x201A SINGLE LOW-9 QUOTATION MARK + 402, # 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK + 8222, # 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK + 8230, # 0x85 0x2026 HORIZONTAL ELLIPSIS + 8224, # 0x86 0x2020 DAGGER + 8225, # 0x87 0x2021 DOUBLE DAGGER + 710, # 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT + 8240, # 0x89 0x2030 PER MILLE SIGN + 352, # 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON + 8249, # 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 338, # 0x8C 0x0152 LATIN CAPITAL LIGATURE OE + 65533, # 0x8D UNDEFINED + 381, # 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON + 65533, # 0x8F UNDEFINED + 65533, # 0x90 UNDEFINED + 8216, # 0x91 0x2018 LEFT SINGLE QUOTATION MARK + 8217, # 0x92 0x2019 RIGHT SINGLE QUOTATION MARK + 8220, # 0x93 0x201C LEFT DOUBLE QUOTATION MARK + 8221, # 0x94 0x201D RIGHT DOUBLE QUOTATION MARK + 8226, # 0x95 0x2022 BULLET + 8211, # 0x96 0x2013 EN DASH + 8212, # 0x97 0x2014 EM DASH + 732, # 0x98 0x02DC SMALL TILDE + 8482, # 0x99 0x2122 TRADE MARK SIGN + 353, # 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON + 8250, # 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 339, # 0x9C 0x0153 LATIN SMALL LIGATURE OE + 65533, # 0x9D UNDEFINED + 382, # 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON + 376 # 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS +) + +xmlEntities = frozenset(['lt;', 'gt;', 'amp;', 'apos;', 'quot;']) + +entities = { + "AElig": "\xc6", + "AElig;": "\xc6", + "AMP": "&", + "AMP;": "&", + "Aacute": "\xc1", + "Aacute;": "\xc1", + "Abreve;": "\u0102", + "Acirc": "\xc2", + "Acirc;": "\xc2", + "Acy;": "\u0410", + "Afr;": "\U0001d504", + "Agrave": "\xc0", + "Agrave;": "\xc0", + "Alpha;": "\u0391", + "Amacr;": "\u0100", + "And;": "\u2a53", + "Aogon;": "\u0104", + "Aopf;": "\U0001d538", + "ApplyFunction;": "\u2061", + "Aring": "\xc5", + "Aring;": "\xc5", + "Ascr;": "\U0001d49c", + "Assign;": "\u2254", + "Atilde": "\xc3", + "Atilde;": "\xc3", + "Auml": "\xc4", + "Auml;": "\xc4", + "Backslash;": "\u2216", + "Barv;": "\u2ae7", + "Barwed;": "\u2306", + "Bcy;": "\u0411", + "Because;": "\u2235", + "Bernoullis;": "\u212c", + "Beta;": "\u0392", + "Bfr;": "\U0001d505", + "Bopf;": "\U0001d539", + "Breve;": "\u02d8", + "Bscr;": "\u212c", + "Bumpeq;": "\u224e", + "CHcy;": "\u0427", + "COPY": "\xa9", + "COPY;": "\xa9", + "Cacute;": "\u0106", + "Cap;": "\u22d2", + "CapitalDifferentialD;": "\u2145", + "Cayleys;": "\u212d", + "Ccaron;": "\u010c", + "Ccedil": "\xc7", + "Ccedil;": "\xc7", + "Ccirc;": "\u0108", + "Cconint;": "\u2230", + "Cdot;": "\u010a", + "Cedilla;": "\xb8", + "CenterDot;": "\xb7", + "Cfr;": "\u212d", + "Chi;": "\u03a7", + "CircleDot;": "\u2299", + "CircleMinus;": "\u2296", + "CirclePlus;": "\u2295", + "CircleTimes;": "\u2297", + "ClockwiseContourIntegral;": "\u2232", + "CloseCurlyDoubleQuote;": "\u201d", + "CloseCurlyQuote;": "\u2019", + "Colon;": "\u2237", + "Colone;": "\u2a74", + "Congruent;": "\u2261", + "Conint;": "\u222f", + "ContourIntegral;": "\u222e", + "Copf;": "\u2102", + "Coproduct;": "\u2210", + "CounterClockwiseContourIntegral;": "\u2233", + "Cross;": "\u2a2f", + "Cscr;": "\U0001d49e", + "Cup;": "\u22d3", + "CupCap;": "\u224d", + "DD;": "\u2145", + "DDotrahd;": "\u2911", + "DJcy;": "\u0402", + "DScy;": "\u0405", + "DZcy;": "\u040f", + "Dagger;": "\u2021", + "Darr;": "\u21a1", + "Dashv;": "\u2ae4", + "Dcaron;": "\u010e", + "Dcy;": "\u0414", + "Del;": "\u2207", + "Delta;": "\u0394", + "Dfr;": "\U0001d507", + "DiacriticalAcute;": "\xb4", + "DiacriticalDot;": "\u02d9", + "DiacriticalDoubleAcute;": "\u02dd", + "DiacriticalGrave;": "`", + "DiacriticalTilde;": "\u02dc", + "Diamond;": "\u22c4", + "DifferentialD;": "\u2146", + "Dopf;": "\U0001d53b", + "Dot;": "\xa8", + "DotDot;": "\u20dc", + "DotEqual;": "\u2250", + "DoubleContourIntegral;": "\u222f", + "DoubleDot;": "\xa8", + "DoubleDownArrow;": "\u21d3", + "DoubleLeftArrow;": "\u21d0", + "DoubleLeftRightArrow;": "\u21d4", + "DoubleLeftTee;": "\u2ae4", + "DoubleLongLeftArrow;": "\u27f8", + "DoubleLongLeftRightArrow;": "\u27fa", + "DoubleLongRightArrow;": "\u27f9", + "DoubleRightArrow;": "\u21d2", + "DoubleRightTee;": "\u22a8", + "DoubleUpArrow;": "\u21d1", + "DoubleUpDownArrow;": "\u21d5", + "DoubleVerticalBar;": "\u2225", + "DownArrow;": "\u2193", + "DownArrowBar;": "\u2913", + "DownArrowUpArrow;": "\u21f5", + "DownBreve;": "\u0311", + "DownLeftRightVector;": "\u2950", + "DownLeftTeeVector;": "\u295e", + "DownLeftVector;": "\u21bd", + "DownLeftVectorBar;": "\u2956", + "DownRightTeeVector;": "\u295f", + "DownRightVector;": "\u21c1", + "DownRightVectorBar;": "\u2957", + "DownTee;": "\u22a4", + "DownTeeArrow;": "\u21a7", + "Downarrow;": "\u21d3", + "Dscr;": "\U0001d49f", + "Dstrok;": "\u0110", + "ENG;": "\u014a", + "ETH": "\xd0", + "ETH;": "\xd0", + "Eacute": "\xc9", + "Eacute;": "\xc9", + "Ecaron;": "\u011a", + "Ecirc": "\xca", + "Ecirc;": "\xca", + "Ecy;": "\u042d", + "Edot;": "\u0116", + "Efr;": "\U0001d508", + "Egrave": "\xc8", + "Egrave;": "\xc8", + "Element;": "\u2208", + "Emacr;": "\u0112", + "EmptySmallSquare;": "\u25fb", + "EmptyVerySmallSquare;": "\u25ab", + "Eogon;": "\u0118", + "Eopf;": "\U0001d53c", + "Epsilon;": "\u0395", + "Equal;": "\u2a75", + "EqualTilde;": "\u2242", + "Equilibrium;": "\u21cc", + "Escr;": "\u2130", + "Esim;": "\u2a73", + "Eta;": "\u0397", + "Euml": "\xcb", + "Euml;": "\xcb", + "Exists;": "\u2203", + "ExponentialE;": "\u2147", + "Fcy;": "\u0424", + "Ffr;": "\U0001d509", + "FilledSmallSquare;": "\u25fc", + "FilledVerySmallSquare;": "\u25aa", + "Fopf;": "\U0001d53d", + "ForAll;": "\u2200", + "Fouriertrf;": "\u2131", + "Fscr;": "\u2131", + "GJcy;": "\u0403", + "GT": ">", + "GT;": ">", + "Gamma;": "\u0393", + "Gammad;": "\u03dc", + "Gbreve;": "\u011e", + "Gcedil;": "\u0122", + "Gcirc;": "\u011c", + "Gcy;": "\u0413", + "Gdot;": "\u0120", + "Gfr;": "\U0001d50a", + "Gg;": "\u22d9", + "Gopf;": "\U0001d53e", + "GreaterEqual;": "\u2265", + "GreaterEqualLess;": "\u22db", + "GreaterFullEqual;": "\u2267", + "GreaterGreater;": "\u2aa2", + "GreaterLess;": "\u2277", + "GreaterSlantEqual;": "\u2a7e", + "GreaterTilde;": "\u2273", + "Gscr;": "\U0001d4a2", + "Gt;": "\u226b", + "HARDcy;": "\u042a", + "Hacek;": "\u02c7", + "Hat;": "^", + "Hcirc;": "\u0124", + "Hfr;": "\u210c", + "HilbertSpace;": "\u210b", + "Hopf;": "\u210d", + "HorizontalLine;": "\u2500", + "Hscr;": "\u210b", + "Hstrok;": "\u0126", + "HumpDownHump;": "\u224e", + "HumpEqual;": "\u224f", + "IEcy;": "\u0415", + "IJlig;": "\u0132", + "IOcy;": "\u0401", + "Iacute": "\xcd", + "Iacute;": "\xcd", + "Icirc": "\xce", + "Icirc;": "\xce", + "Icy;": "\u0418", + "Idot;": "\u0130", + "Ifr;": "\u2111", + "Igrave": "\xcc", + "Igrave;": "\xcc", + "Im;": "\u2111", + "Imacr;": "\u012a", + "ImaginaryI;": "\u2148", + "Implies;": "\u21d2", + "Int;": "\u222c", + "Integral;": "\u222b", + "Intersection;": "\u22c2", + "InvisibleComma;": "\u2063", + "InvisibleTimes;": "\u2062", + "Iogon;": "\u012e", + "Iopf;": "\U0001d540", + "Iota;": "\u0399", + "Iscr;": "\u2110", + "Itilde;": "\u0128", + "Iukcy;": "\u0406", + "Iuml": "\xcf", + "Iuml;": "\xcf", + "Jcirc;": "\u0134", + "Jcy;": "\u0419", + "Jfr;": "\U0001d50d", + "Jopf;": "\U0001d541", + "Jscr;": "\U0001d4a5", + "Jsercy;": "\u0408", + "Jukcy;": "\u0404", + "KHcy;": "\u0425", + "KJcy;": "\u040c", + "Kappa;": "\u039a", + "Kcedil;": "\u0136", + "Kcy;": "\u041a", + "Kfr;": "\U0001d50e", + "Kopf;": "\U0001d542", + "Kscr;": "\U0001d4a6", + "LJcy;": "\u0409", + "LT": "<", + "LT;": "<", + "Lacute;": "\u0139", + "Lambda;": "\u039b", + "Lang;": "\u27ea", + "Laplacetrf;": "\u2112", + "Larr;": "\u219e", + "Lcaron;": "\u013d", + "Lcedil;": "\u013b", + "Lcy;": "\u041b", + "LeftAngleBracket;": "\u27e8", + "LeftArrow;": "\u2190", + "LeftArrowBar;": "\u21e4", + "LeftArrowRightArrow;": "\u21c6", + "LeftCeiling;": "\u2308", + "LeftDoubleBracket;": "\u27e6", + "LeftDownTeeVector;": "\u2961", + "LeftDownVector;": "\u21c3", + "LeftDownVectorBar;": "\u2959", + "LeftFloor;": "\u230a", + "LeftRightArrow;": "\u2194", + "LeftRightVector;": "\u294e", + "LeftTee;": "\u22a3", + "LeftTeeArrow;": "\u21a4", + "LeftTeeVector;": "\u295a", + "LeftTriangle;": "\u22b2", + "LeftTriangleBar;": "\u29cf", + "LeftTriangleEqual;": "\u22b4", + "LeftUpDownVector;": "\u2951", + "LeftUpTeeVector;": "\u2960", + "LeftUpVector;": "\u21bf", + "LeftUpVectorBar;": "\u2958", + "LeftVector;": "\u21bc", + "LeftVectorBar;": "\u2952", + "Leftarrow;": "\u21d0", + "Leftrightarrow;": "\u21d4", + "LessEqualGreater;": "\u22da", + "LessFullEqual;": "\u2266", + "LessGreater;": "\u2276", + "LessLess;": "\u2aa1", + "LessSlantEqual;": "\u2a7d", + "LessTilde;": "\u2272", + "Lfr;": "\U0001d50f", + "Ll;": "\u22d8", + "Lleftarrow;": "\u21da", + "Lmidot;": "\u013f", + "LongLeftArrow;": "\u27f5", + "LongLeftRightArrow;": "\u27f7", + "LongRightArrow;": "\u27f6", + "Longleftarrow;": "\u27f8", + "Longleftrightarrow;": "\u27fa", + "Longrightarrow;": "\u27f9", + "Lopf;": "\U0001d543", + "LowerLeftArrow;": "\u2199", + "LowerRightArrow;": "\u2198", + "Lscr;": "\u2112", + "Lsh;": "\u21b0", + "Lstrok;": "\u0141", + "Lt;": "\u226a", + "Map;": "\u2905", + "Mcy;": "\u041c", + "MediumSpace;": "\u205f", + "Mellintrf;": "\u2133", + "Mfr;": "\U0001d510", + "MinusPlus;": "\u2213", + "Mopf;": "\U0001d544", + "Mscr;": "\u2133", + "Mu;": "\u039c", + "NJcy;": "\u040a", + "Nacute;": "\u0143", + "Ncaron;": "\u0147", + "Ncedil;": "\u0145", + "Ncy;": "\u041d", + "NegativeMediumSpace;": "\u200b", + "NegativeThickSpace;": "\u200b", + "NegativeThinSpace;": "\u200b", + "NegativeVeryThinSpace;": "\u200b", + "NestedGreaterGreater;": "\u226b", + "NestedLessLess;": "\u226a", + "NewLine;": "\n", + "Nfr;": "\U0001d511", + "NoBreak;": "\u2060", + "NonBreakingSpace;": "\xa0", + "Nopf;": "\u2115", + "Not;": "\u2aec", + "NotCongruent;": "\u2262", + "NotCupCap;": "\u226d", + "NotDoubleVerticalBar;": "\u2226", + "NotElement;": "\u2209", + "NotEqual;": "\u2260", + "NotEqualTilde;": "\u2242\u0338", + "NotExists;": "\u2204", + "NotGreater;": "\u226f", + "NotGreaterEqual;": "\u2271", + "NotGreaterFullEqual;": "\u2267\u0338", + "NotGreaterGreater;": "\u226b\u0338", + "NotGreaterLess;": "\u2279", + "NotGreaterSlantEqual;": "\u2a7e\u0338", + "NotGreaterTilde;": "\u2275", + "NotHumpDownHump;": "\u224e\u0338", + "NotHumpEqual;": "\u224f\u0338", + "NotLeftTriangle;": "\u22ea", + "NotLeftTriangleBar;": "\u29cf\u0338", + "NotLeftTriangleEqual;": "\u22ec", + "NotLess;": "\u226e", + "NotLessEqual;": "\u2270", + "NotLessGreater;": "\u2278", + "NotLessLess;": "\u226a\u0338", + "NotLessSlantEqual;": "\u2a7d\u0338", + "NotLessTilde;": "\u2274", + "NotNestedGreaterGreater;": "\u2aa2\u0338", + "NotNestedLessLess;": "\u2aa1\u0338", + "NotPrecedes;": "\u2280", + "NotPrecedesEqual;": "\u2aaf\u0338", + "NotPrecedesSlantEqual;": "\u22e0", + "NotReverseElement;": "\u220c", + "NotRightTriangle;": "\u22eb", + "NotRightTriangleBar;": "\u29d0\u0338", + "NotRightTriangleEqual;": "\u22ed", + "NotSquareSubset;": "\u228f\u0338", + "NotSquareSubsetEqual;": "\u22e2", + "NotSquareSuperset;": "\u2290\u0338", + "NotSquareSupersetEqual;": "\u22e3", + "NotSubset;": "\u2282\u20d2", + "NotSubsetEqual;": "\u2288", + "NotSucceeds;": "\u2281", + "NotSucceedsEqual;": "\u2ab0\u0338", + "NotSucceedsSlantEqual;": "\u22e1", + "NotSucceedsTilde;": "\u227f\u0338", + "NotSuperset;": "\u2283\u20d2", + "NotSupersetEqual;": "\u2289", + "NotTilde;": "\u2241", + "NotTildeEqual;": "\u2244", + "NotTildeFullEqual;": "\u2247", + "NotTildeTilde;": "\u2249", + "NotVerticalBar;": "\u2224", + "Nscr;": "\U0001d4a9", + "Ntilde": "\xd1", + "Ntilde;": "\xd1", + "Nu;": "\u039d", + "OElig;": "\u0152", + "Oacute": "\xd3", + "Oacute;": "\xd3", + "Ocirc": "\xd4", + "Ocirc;": "\xd4", + "Ocy;": "\u041e", + "Odblac;": "\u0150", + "Ofr;": "\U0001d512", + "Ograve": "\xd2", + "Ograve;": "\xd2", + "Omacr;": "\u014c", + "Omega;": "\u03a9", + "Omicron;": "\u039f", + "Oopf;": "\U0001d546", + "OpenCurlyDoubleQuote;": "\u201c", + "OpenCurlyQuote;": "\u2018", + "Or;": "\u2a54", + "Oscr;": "\U0001d4aa", + "Oslash": "\xd8", + "Oslash;": "\xd8", + "Otilde": "\xd5", + "Otilde;": "\xd5", + "Otimes;": "\u2a37", + "Ouml": "\xd6", + "Ouml;": "\xd6", + "OverBar;": "\u203e", + "OverBrace;": "\u23de", + "OverBracket;": "\u23b4", + "OverParenthesis;": "\u23dc", + "PartialD;": "\u2202", + "Pcy;": "\u041f", + "Pfr;": "\U0001d513", + "Phi;": "\u03a6", + "Pi;": "\u03a0", + "PlusMinus;": "\xb1", + "Poincareplane;": "\u210c", + "Popf;": "\u2119", + "Pr;": "\u2abb", + "Precedes;": "\u227a", + "PrecedesEqual;": "\u2aaf", + "PrecedesSlantEqual;": "\u227c", + "PrecedesTilde;": "\u227e", + "Prime;": "\u2033", + "Product;": "\u220f", + "Proportion;": "\u2237", + "Proportional;": "\u221d", + "Pscr;": "\U0001d4ab", + "Psi;": "\u03a8", + "QUOT": "\"", + "QUOT;": "\"", + "Qfr;": "\U0001d514", + "Qopf;": "\u211a", + "Qscr;": "\U0001d4ac", + "RBarr;": "\u2910", + "REG": "\xae", + "REG;": "\xae", + "Racute;": "\u0154", + "Rang;": "\u27eb", + "Rarr;": "\u21a0", + "Rarrtl;": "\u2916", + "Rcaron;": "\u0158", + "Rcedil;": "\u0156", + "Rcy;": "\u0420", + "Re;": "\u211c", + "ReverseElement;": "\u220b", + "ReverseEquilibrium;": "\u21cb", + "ReverseUpEquilibrium;": "\u296f", + "Rfr;": "\u211c", + "Rho;": "\u03a1", + "RightAngleBracket;": "\u27e9", + "RightArrow;": "\u2192", + "RightArrowBar;": "\u21e5", + "RightArrowLeftArrow;": "\u21c4", + "RightCeiling;": "\u2309", + "RightDoubleBracket;": "\u27e7", + "RightDownTeeVector;": "\u295d", + "RightDownVector;": "\u21c2", + "RightDownVectorBar;": "\u2955", + "RightFloor;": "\u230b", + "RightTee;": "\u22a2", + "RightTeeArrow;": "\u21a6", + "RightTeeVector;": "\u295b", + "RightTriangle;": "\u22b3", + "RightTriangleBar;": "\u29d0", + "RightTriangleEqual;": "\u22b5", + "RightUpDownVector;": "\u294f", + "RightUpTeeVector;": "\u295c", + "RightUpVector;": "\u21be", + "RightUpVectorBar;": "\u2954", + "RightVector;": "\u21c0", + "RightVectorBar;": "\u2953", + "Rightarrow;": "\u21d2", + "Ropf;": "\u211d", + "RoundImplies;": "\u2970", + "Rrightarrow;": "\u21db", + "Rscr;": "\u211b", + "Rsh;": "\u21b1", + "RuleDelayed;": "\u29f4", + "SHCHcy;": "\u0429", + "SHcy;": "\u0428", + "SOFTcy;": "\u042c", + "Sacute;": "\u015a", + "Sc;": "\u2abc", + "Scaron;": "\u0160", + "Scedil;": "\u015e", + "Scirc;": "\u015c", + "Scy;": "\u0421", + "Sfr;": "\U0001d516", + "ShortDownArrow;": "\u2193", + "ShortLeftArrow;": "\u2190", + "ShortRightArrow;": "\u2192", + "ShortUpArrow;": "\u2191", + "Sigma;": "\u03a3", + "SmallCircle;": "\u2218", + "Sopf;": "\U0001d54a", + "Sqrt;": "\u221a", + "Square;": "\u25a1", + "SquareIntersection;": "\u2293", + "SquareSubset;": "\u228f", + "SquareSubsetEqual;": "\u2291", + "SquareSuperset;": "\u2290", + "SquareSupersetEqual;": "\u2292", + "SquareUnion;": "\u2294", + "Sscr;": "\U0001d4ae", + "Star;": "\u22c6", + "Sub;": "\u22d0", + "Subset;": "\u22d0", + "SubsetEqual;": "\u2286", + "Succeeds;": "\u227b", + "SucceedsEqual;": "\u2ab0", + "SucceedsSlantEqual;": "\u227d", + "SucceedsTilde;": "\u227f", + "SuchThat;": "\u220b", + "Sum;": "\u2211", + "Sup;": "\u22d1", + "Superset;": "\u2283", + "SupersetEqual;": "\u2287", + "Supset;": "\u22d1", + "THORN": "\xde", + "THORN;": "\xde", + "TRADE;": "\u2122", + "TSHcy;": "\u040b", + "TScy;": "\u0426", + "Tab;": "\t", + "Tau;": "\u03a4", + "Tcaron;": "\u0164", + "Tcedil;": "\u0162", + "Tcy;": "\u0422", + "Tfr;": "\U0001d517", + "Therefore;": "\u2234", + "Theta;": "\u0398", + "ThickSpace;": "\u205f\u200a", + "ThinSpace;": "\u2009", + "Tilde;": "\u223c", + "TildeEqual;": "\u2243", + "TildeFullEqual;": "\u2245", + "TildeTilde;": "\u2248", + "Topf;": "\U0001d54b", + "TripleDot;": "\u20db", + "Tscr;": "\U0001d4af", + "Tstrok;": "\u0166", + "Uacute": "\xda", + "Uacute;": "\xda", + "Uarr;": "\u219f", + "Uarrocir;": "\u2949", + "Ubrcy;": "\u040e", + "Ubreve;": "\u016c", + "Ucirc": "\xdb", + "Ucirc;": "\xdb", + "Ucy;": "\u0423", + "Udblac;": "\u0170", + "Ufr;": "\U0001d518", + "Ugrave": "\xd9", + "Ugrave;": "\xd9", + "Umacr;": "\u016a", + "UnderBar;": "_", + "UnderBrace;": "\u23df", + "UnderBracket;": "\u23b5", + "UnderParenthesis;": "\u23dd", + "Union;": "\u22c3", + "UnionPlus;": "\u228e", + "Uogon;": "\u0172", + "Uopf;": "\U0001d54c", + "UpArrow;": "\u2191", + "UpArrowBar;": "\u2912", + "UpArrowDownArrow;": "\u21c5", + "UpDownArrow;": "\u2195", + "UpEquilibrium;": "\u296e", + "UpTee;": "\u22a5", + "UpTeeArrow;": "\u21a5", + "Uparrow;": "\u21d1", + "Updownarrow;": "\u21d5", + "UpperLeftArrow;": "\u2196", + "UpperRightArrow;": "\u2197", + "Upsi;": "\u03d2", + "Upsilon;": "\u03a5", + "Uring;": "\u016e", + "Uscr;": "\U0001d4b0", + "Utilde;": "\u0168", + "Uuml": "\xdc", + "Uuml;": "\xdc", + "VDash;": "\u22ab", + "Vbar;": "\u2aeb", + "Vcy;": "\u0412", + "Vdash;": "\u22a9", + "Vdashl;": "\u2ae6", + "Vee;": "\u22c1", + "Verbar;": "\u2016", + "Vert;": "\u2016", + "VerticalBar;": "\u2223", + "VerticalLine;": "|", + "VerticalSeparator;": "\u2758", + "VerticalTilde;": "\u2240", + "VeryThinSpace;": "\u200a", + "Vfr;": "\U0001d519", + "Vopf;": "\U0001d54d", + "Vscr;": "\U0001d4b1", + "Vvdash;": "\u22aa", + "Wcirc;": "\u0174", + "Wedge;": "\u22c0", + "Wfr;": "\U0001d51a", + "Wopf;": "\U0001d54e", + "Wscr;": "\U0001d4b2", + "Xfr;": "\U0001d51b", + "Xi;": "\u039e", + "Xopf;": "\U0001d54f", + "Xscr;": "\U0001d4b3", + "YAcy;": "\u042f", + "YIcy;": "\u0407", + "YUcy;": "\u042e", + "Yacute": "\xdd", + "Yacute;": "\xdd", + "Ycirc;": "\u0176", + "Ycy;": "\u042b", + "Yfr;": "\U0001d51c", + "Yopf;": "\U0001d550", + "Yscr;": "\U0001d4b4", + "Yuml;": "\u0178", + "ZHcy;": "\u0416", + "Zacute;": "\u0179", + "Zcaron;": "\u017d", + "Zcy;": "\u0417", + "Zdot;": "\u017b", + "ZeroWidthSpace;": "\u200b", + "Zeta;": "\u0396", + "Zfr;": "\u2128", + "Zopf;": "\u2124", + "Zscr;": "\U0001d4b5", + "aacute": "\xe1", + "aacute;": "\xe1", + "abreve;": "\u0103", + "ac;": "\u223e", + "acE;": "\u223e\u0333", + "acd;": "\u223f", + "acirc": "\xe2", + "acirc;": "\xe2", + "acute": "\xb4", + "acute;": "\xb4", + "acy;": "\u0430", + "aelig": "\xe6", + "aelig;": "\xe6", + "af;": "\u2061", + "afr;": "\U0001d51e", + "agrave": "\xe0", + "agrave;": "\xe0", + "alefsym;": "\u2135", + "aleph;": "\u2135", + "alpha;": "\u03b1", + "amacr;": "\u0101", + "amalg;": "\u2a3f", + "amp": "&", + "amp;": "&", + "and;": "\u2227", + "andand;": "\u2a55", + "andd;": "\u2a5c", + "andslope;": "\u2a58", + "andv;": "\u2a5a", + "ang;": "\u2220", + "ange;": "\u29a4", + "angle;": "\u2220", + "angmsd;": "\u2221", + "angmsdaa;": "\u29a8", + "angmsdab;": "\u29a9", + "angmsdac;": "\u29aa", + "angmsdad;": "\u29ab", + "angmsdae;": "\u29ac", + "angmsdaf;": "\u29ad", + "angmsdag;": "\u29ae", + "angmsdah;": "\u29af", + "angrt;": "\u221f", + "angrtvb;": "\u22be", + "angrtvbd;": "\u299d", + "angsph;": "\u2222", + "angst;": "\xc5", + "angzarr;": "\u237c", + "aogon;": "\u0105", + "aopf;": "\U0001d552", + "ap;": "\u2248", + "apE;": "\u2a70", + "apacir;": "\u2a6f", + "ape;": "\u224a", + "apid;": "\u224b", + "apos;": "'", + "approx;": "\u2248", + "approxeq;": "\u224a", + "aring": "\xe5", + "aring;": "\xe5", + "ascr;": "\U0001d4b6", + "ast;": "*", + "asymp;": "\u2248", + "asympeq;": "\u224d", + "atilde": "\xe3", + "atilde;": "\xe3", + "auml": "\xe4", + "auml;": "\xe4", + "awconint;": "\u2233", + "awint;": "\u2a11", + "bNot;": "\u2aed", + "backcong;": "\u224c", + "backepsilon;": "\u03f6", + "backprime;": "\u2035", + "backsim;": "\u223d", + "backsimeq;": "\u22cd", + "barvee;": "\u22bd", + "barwed;": "\u2305", + "barwedge;": "\u2305", + "bbrk;": "\u23b5", + "bbrktbrk;": "\u23b6", + "bcong;": "\u224c", + "bcy;": "\u0431", + "bdquo;": "\u201e", + "becaus;": "\u2235", + "because;": "\u2235", + "bemptyv;": "\u29b0", + "bepsi;": "\u03f6", + "bernou;": "\u212c", + "beta;": "\u03b2", + "beth;": "\u2136", + "between;": "\u226c", + "bfr;": "\U0001d51f", + "bigcap;": "\u22c2", + "bigcirc;": "\u25ef", + "bigcup;": "\u22c3", + "bigodot;": "\u2a00", + "bigoplus;": "\u2a01", + "bigotimes;": "\u2a02", + "bigsqcup;": "\u2a06", + "bigstar;": "\u2605", + "bigtriangledown;": "\u25bd", + "bigtriangleup;": "\u25b3", + "biguplus;": "\u2a04", + "bigvee;": "\u22c1", + "bigwedge;": "\u22c0", + "bkarow;": "\u290d", + "blacklozenge;": "\u29eb", + "blacksquare;": "\u25aa", + "blacktriangle;": "\u25b4", + "blacktriangledown;": "\u25be", + "blacktriangleleft;": "\u25c2", + "blacktriangleright;": "\u25b8", + "blank;": "\u2423", + "blk12;": "\u2592", + "blk14;": "\u2591", + "blk34;": "\u2593", + "block;": "\u2588", + "bne;": "=\u20e5", + "bnequiv;": "\u2261\u20e5", + "bnot;": "\u2310", + "bopf;": "\U0001d553", + "bot;": "\u22a5", + "bottom;": "\u22a5", + "bowtie;": "\u22c8", + "boxDL;": "\u2557", + "boxDR;": "\u2554", + "boxDl;": "\u2556", + "boxDr;": "\u2553", + "boxH;": "\u2550", + "boxHD;": "\u2566", + "boxHU;": "\u2569", + "boxHd;": "\u2564", + "boxHu;": "\u2567", + "boxUL;": "\u255d", + "boxUR;": "\u255a", + "boxUl;": "\u255c", + "boxUr;": "\u2559", + "boxV;": "\u2551", + "boxVH;": "\u256c", + "boxVL;": "\u2563", + "boxVR;": "\u2560", + "boxVh;": "\u256b", + "boxVl;": "\u2562", + "boxVr;": "\u255f", + "boxbox;": "\u29c9", + "boxdL;": "\u2555", + "boxdR;": "\u2552", + "boxdl;": "\u2510", + "boxdr;": "\u250c", + "boxh;": "\u2500", + "boxhD;": "\u2565", + "boxhU;": "\u2568", + "boxhd;": "\u252c", + "boxhu;": "\u2534", + "boxminus;": "\u229f", + "boxplus;": "\u229e", + "boxtimes;": "\u22a0", + "boxuL;": "\u255b", + "boxuR;": "\u2558", + "boxul;": "\u2518", + "boxur;": "\u2514", + "boxv;": "\u2502", + "boxvH;": "\u256a", + "boxvL;": "\u2561", + "boxvR;": "\u255e", + "boxvh;": "\u253c", + "boxvl;": "\u2524", + "boxvr;": "\u251c", + "bprime;": "\u2035", + "breve;": "\u02d8", + "brvbar": "\xa6", + "brvbar;": "\xa6", + "bscr;": "\U0001d4b7", + "bsemi;": "\u204f", + "bsim;": "\u223d", + "bsime;": "\u22cd", + "bsol;": "\\", + "bsolb;": "\u29c5", + "bsolhsub;": "\u27c8", + "bull;": "\u2022", + "bullet;": "\u2022", + "bump;": "\u224e", + "bumpE;": "\u2aae", + "bumpe;": "\u224f", + "bumpeq;": "\u224f", + "cacute;": "\u0107", + "cap;": "\u2229", + "capand;": "\u2a44", + "capbrcup;": "\u2a49", + "capcap;": "\u2a4b", + "capcup;": "\u2a47", + "capdot;": "\u2a40", + "caps;": "\u2229\ufe00", + "caret;": "\u2041", + "caron;": "\u02c7", + "ccaps;": "\u2a4d", + "ccaron;": "\u010d", + "ccedil": "\xe7", + "ccedil;": "\xe7", + "ccirc;": "\u0109", + "ccups;": "\u2a4c", + "ccupssm;": "\u2a50", + "cdot;": "\u010b", + "cedil": "\xb8", + "cedil;": "\xb8", + "cemptyv;": "\u29b2", + "cent": "\xa2", + "cent;": "\xa2", + "centerdot;": "\xb7", + "cfr;": "\U0001d520", + "chcy;": "\u0447", + "check;": "\u2713", + "checkmark;": "\u2713", + "chi;": "\u03c7", + "cir;": "\u25cb", + "cirE;": "\u29c3", + "circ;": "\u02c6", + "circeq;": "\u2257", + "circlearrowleft;": "\u21ba", + "circlearrowright;": "\u21bb", + "circledR;": "\xae", + "circledS;": "\u24c8", + "circledast;": "\u229b", + "circledcirc;": "\u229a", + "circleddash;": "\u229d", + "cire;": "\u2257", + "cirfnint;": "\u2a10", + "cirmid;": "\u2aef", + "cirscir;": "\u29c2", + "clubs;": "\u2663", + "clubsuit;": "\u2663", + "colon;": ":", + "colone;": "\u2254", + "coloneq;": "\u2254", + "comma;": ",", + "commat;": "@", + "comp;": "\u2201", + "compfn;": "\u2218", + "complement;": "\u2201", + "complexes;": "\u2102", + "cong;": "\u2245", + "congdot;": "\u2a6d", + "conint;": "\u222e", + "copf;": "\U0001d554", + "coprod;": "\u2210", + "copy": "\xa9", + "copy;": "\xa9", + "copysr;": "\u2117", + "crarr;": "\u21b5", + "cross;": "\u2717", + "cscr;": "\U0001d4b8", + "csub;": "\u2acf", + "csube;": "\u2ad1", + "csup;": "\u2ad0", + "csupe;": "\u2ad2", + "ctdot;": "\u22ef", + "cudarrl;": "\u2938", + "cudarrr;": "\u2935", + "cuepr;": "\u22de", + "cuesc;": "\u22df", + "cularr;": "\u21b6", + "cularrp;": "\u293d", + "cup;": "\u222a", + "cupbrcap;": "\u2a48", + "cupcap;": "\u2a46", + "cupcup;": "\u2a4a", + "cupdot;": "\u228d", + "cupor;": "\u2a45", + "cups;": "\u222a\ufe00", + "curarr;": "\u21b7", + "curarrm;": "\u293c", + "curlyeqprec;": "\u22de", + "curlyeqsucc;": "\u22df", + "curlyvee;": "\u22ce", + "curlywedge;": "\u22cf", + "curren": "\xa4", + "curren;": "\xa4", + "curvearrowleft;": "\u21b6", + "curvearrowright;": "\u21b7", + "cuvee;": "\u22ce", + "cuwed;": "\u22cf", + "cwconint;": "\u2232", + "cwint;": "\u2231", + "cylcty;": "\u232d", + "dArr;": "\u21d3", + "dHar;": "\u2965", + "dagger;": "\u2020", + "daleth;": "\u2138", + "darr;": "\u2193", + "dash;": "\u2010", + "dashv;": "\u22a3", + "dbkarow;": "\u290f", + "dblac;": "\u02dd", + "dcaron;": "\u010f", + "dcy;": "\u0434", + "dd;": "\u2146", + "ddagger;": "\u2021", + "ddarr;": "\u21ca", + "ddotseq;": "\u2a77", + "deg": "\xb0", + "deg;": "\xb0", + "delta;": "\u03b4", + "demptyv;": "\u29b1", + "dfisht;": "\u297f", + "dfr;": "\U0001d521", + "dharl;": "\u21c3", + "dharr;": "\u21c2", + "diam;": "\u22c4", + "diamond;": "\u22c4", + "diamondsuit;": "\u2666", + "diams;": "\u2666", + "die;": "\xa8", + "digamma;": "\u03dd", + "disin;": "\u22f2", + "div;": "\xf7", + "divide": "\xf7", + "divide;": "\xf7", + "divideontimes;": "\u22c7", + "divonx;": "\u22c7", + "djcy;": "\u0452", + "dlcorn;": "\u231e", + "dlcrop;": "\u230d", + "dollar;": "$", + "dopf;": "\U0001d555", + "dot;": "\u02d9", + "doteq;": "\u2250", + "doteqdot;": "\u2251", + "dotminus;": "\u2238", + "dotplus;": "\u2214", + "dotsquare;": "\u22a1", + "doublebarwedge;": "\u2306", + "downarrow;": "\u2193", + "downdownarrows;": "\u21ca", + "downharpoonleft;": "\u21c3", + "downharpoonright;": "\u21c2", + "drbkarow;": "\u2910", + "drcorn;": "\u231f", + "drcrop;": "\u230c", + "dscr;": "\U0001d4b9", + "dscy;": "\u0455", + "dsol;": "\u29f6", + "dstrok;": "\u0111", + "dtdot;": "\u22f1", + "dtri;": "\u25bf", + "dtrif;": "\u25be", + "duarr;": "\u21f5", + "duhar;": "\u296f", + "dwangle;": "\u29a6", + "dzcy;": "\u045f", + "dzigrarr;": "\u27ff", + "eDDot;": "\u2a77", + "eDot;": "\u2251", + "eacute": "\xe9", + "eacute;": "\xe9", + "easter;": "\u2a6e", + "ecaron;": "\u011b", + "ecir;": "\u2256", + "ecirc": "\xea", + "ecirc;": "\xea", + "ecolon;": "\u2255", + "ecy;": "\u044d", + "edot;": "\u0117", + "ee;": "\u2147", + "efDot;": "\u2252", + "efr;": "\U0001d522", + "eg;": "\u2a9a", + "egrave": "\xe8", + "egrave;": "\xe8", + "egs;": "\u2a96", + "egsdot;": "\u2a98", + "el;": "\u2a99", + "elinters;": "\u23e7", + "ell;": "\u2113", + "els;": "\u2a95", + "elsdot;": "\u2a97", + "emacr;": "\u0113", + "empty;": "\u2205", + "emptyset;": "\u2205", + "emptyv;": "\u2205", + "emsp13;": "\u2004", + "emsp14;": "\u2005", + "emsp;": "\u2003", + "eng;": "\u014b", + "ensp;": "\u2002", + "eogon;": "\u0119", + "eopf;": "\U0001d556", + "epar;": "\u22d5", + "eparsl;": "\u29e3", + "eplus;": "\u2a71", + "epsi;": "\u03b5", + "epsilon;": "\u03b5", + "epsiv;": "\u03f5", + "eqcirc;": "\u2256", + "eqcolon;": "\u2255", + "eqsim;": "\u2242", + "eqslantgtr;": "\u2a96", + "eqslantless;": "\u2a95", + "equals;": "=", + "equest;": "\u225f", + "equiv;": "\u2261", + "equivDD;": "\u2a78", + "eqvparsl;": "\u29e5", + "erDot;": "\u2253", + "erarr;": "\u2971", + "escr;": "\u212f", + "esdot;": "\u2250", + "esim;": "\u2242", + "eta;": "\u03b7", + "eth": "\xf0", + "eth;": "\xf0", + "euml": "\xeb", + "euml;": "\xeb", + "euro;": "\u20ac", + "excl;": "!", + "exist;": "\u2203", + "expectation;": "\u2130", + "exponentiale;": "\u2147", + "fallingdotseq;": "\u2252", + "fcy;": "\u0444", + "female;": "\u2640", + "ffilig;": "\ufb03", + "fflig;": "\ufb00", + "ffllig;": "\ufb04", + "ffr;": "\U0001d523", + "filig;": "\ufb01", + "fjlig;": "fj", + "flat;": "\u266d", + "fllig;": "\ufb02", + "fltns;": "\u25b1", + "fnof;": "\u0192", + "fopf;": "\U0001d557", + "forall;": "\u2200", + "fork;": "\u22d4", + "forkv;": "\u2ad9", + "fpartint;": "\u2a0d", + "frac12": "\xbd", + "frac12;": "\xbd", + "frac13;": "\u2153", + "frac14": "\xbc", + "frac14;": "\xbc", + "frac15;": "\u2155", + "frac16;": "\u2159", + "frac18;": "\u215b", + "frac23;": "\u2154", + "frac25;": "\u2156", + "frac34": "\xbe", + "frac34;": "\xbe", + "frac35;": "\u2157", + "frac38;": "\u215c", + "frac45;": "\u2158", + "frac56;": "\u215a", + "frac58;": "\u215d", + "frac78;": "\u215e", + "frasl;": "\u2044", + "frown;": "\u2322", + "fscr;": "\U0001d4bb", + "gE;": "\u2267", + "gEl;": "\u2a8c", + "gacute;": "\u01f5", + "gamma;": "\u03b3", + "gammad;": "\u03dd", + "gap;": "\u2a86", + "gbreve;": "\u011f", + "gcirc;": "\u011d", + "gcy;": "\u0433", + "gdot;": "\u0121", + "ge;": "\u2265", + "gel;": "\u22db", + "geq;": "\u2265", + "geqq;": "\u2267", + "geqslant;": "\u2a7e", + "ges;": "\u2a7e", + "gescc;": "\u2aa9", + "gesdot;": "\u2a80", + "gesdoto;": "\u2a82", + "gesdotol;": "\u2a84", + "gesl;": "\u22db\ufe00", + "gesles;": "\u2a94", + "gfr;": "\U0001d524", + "gg;": "\u226b", + "ggg;": "\u22d9", + "gimel;": "\u2137", + "gjcy;": "\u0453", + "gl;": "\u2277", + "glE;": "\u2a92", + "gla;": "\u2aa5", + "glj;": "\u2aa4", + "gnE;": "\u2269", + "gnap;": "\u2a8a", + "gnapprox;": "\u2a8a", + "gne;": "\u2a88", + "gneq;": "\u2a88", + "gneqq;": "\u2269", + "gnsim;": "\u22e7", + "gopf;": "\U0001d558", + "grave;": "`", + "gscr;": "\u210a", + "gsim;": "\u2273", + "gsime;": "\u2a8e", + "gsiml;": "\u2a90", + "gt": ">", + "gt;": ">", + "gtcc;": "\u2aa7", + "gtcir;": "\u2a7a", + "gtdot;": "\u22d7", + "gtlPar;": "\u2995", + "gtquest;": "\u2a7c", + "gtrapprox;": "\u2a86", + "gtrarr;": "\u2978", + "gtrdot;": "\u22d7", + "gtreqless;": "\u22db", + "gtreqqless;": "\u2a8c", + "gtrless;": "\u2277", + "gtrsim;": "\u2273", + "gvertneqq;": "\u2269\ufe00", + "gvnE;": "\u2269\ufe00", + "hArr;": "\u21d4", + "hairsp;": "\u200a", + "half;": "\xbd", + "hamilt;": "\u210b", + "hardcy;": "\u044a", + "harr;": "\u2194", + "harrcir;": "\u2948", + "harrw;": "\u21ad", + "hbar;": "\u210f", + "hcirc;": "\u0125", + "hearts;": "\u2665", + "heartsuit;": "\u2665", + "hellip;": "\u2026", + "hercon;": "\u22b9", + "hfr;": "\U0001d525", + "hksearow;": "\u2925", + "hkswarow;": "\u2926", + "hoarr;": "\u21ff", + "homtht;": "\u223b", + "hookleftarrow;": "\u21a9", + "hookrightarrow;": "\u21aa", + "hopf;": "\U0001d559", + "horbar;": "\u2015", + "hscr;": "\U0001d4bd", + "hslash;": "\u210f", + "hstrok;": "\u0127", + "hybull;": "\u2043", + "hyphen;": "\u2010", + "iacute": "\xed", + "iacute;": "\xed", + "ic;": "\u2063", + "icirc": "\xee", + "icirc;": "\xee", + "icy;": "\u0438", + "iecy;": "\u0435", + "iexcl": "\xa1", + "iexcl;": "\xa1", + "iff;": "\u21d4", + "ifr;": "\U0001d526", + "igrave": "\xec", + "igrave;": "\xec", + "ii;": "\u2148", + "iiiint;": "\u2a0c", + "iiint;": "\u222d", + "iinfin;": "\u29dc", + "iiota;": "\u2129", + "ijlig;": "\u0133", + "imacr;": "\u012b", + "image;": "\u2111", + "imagline;": "\u2110", + "imagpart;": "\u2111", + "imath;": "\u0131", + "imof;": "\u22b7", + "imped;": "\u01b5", + "in;": "\u2208", + "incare;": "\u2105", + "infin;": "\u221e", + "infintie;": "\u29dd", + "inodot;": "\u0131", + "int;": "\u222b", + "intcal;": "\u22ba", + "integers;": "\u2124", + "intercal;": "\u22ba", + "intlarhk;": "\u2a17", + "intprod;": "\u2a3c", + "iocy;": "\u0451", + "iogon;": "\u012f", + "iopf;": "\U0001d55a", + "iota;": "\u03b9", + "iprod;": "\u2a3c", + "iquest": "\xbf", + "iquest;": "\xbf", + "iscr;": "\U0001d4be", + "isin;": "\u2208", + "isinE;": "\u22f9", + "isindot;": "\u22f5", + "isins;": "\u22f4", + "isinsv;": "\u22f3", + "isinv;": "\u2208", + "it;": "\u2062", + "itilde;": "\u0129", + "iukcy;": "\u0456", + "iuml": "\xef", + "iuml;": "\xef", + "jcirc;": "\u0135", + "jcy;": "\u0439", + "jfr;": "\U0001d527", + "jmath;": "\u0237", + "jopf;": "\U0001d55b", + "jscr;": "\U0001d4bf", + "jsercy;": "\u0458", + "jukcy;": "\u0454", + "kappa;": "\u03ba", + "kappav;": "\u03f0", + "kcedil;": "\u0137", + "kcy;": "\u043a", + "kfr;": "\U0001d528", + "kgreen;": "\u0138", + "khcy;": "\u0445", + "kjcy;": "\u045c", + "kopf;": "\U0001d55c", + "kscr;": "\U0001d4c0", + "lAarr;": "\u21da", + "lArr;": "\u21d0", + "lAtail;": "\u291b", + "lBarr;": "\u290e", + "lE;": "\u2266", + "lEg;": "\u2a8b", + "lHar;": "\u2962", + "lacute;": "\u013a", + "laemptyv;": "\u29b4", + "lagran;": "\u2112", + "lambda;": "\u03bb", + "lang;": "\u27e8", + "langd;": "\u2991", + "langle;": "\u27e8", + "lap;": "\u2a85", + "laquo": "\xab", + "laquo;": "\xab", + "larr;": "\u2190", + "larrb;": "\u21e4", + "larrbfs;": "\u291f", + "larrfs;": "\u291d", + "larrhk;": "\u21a9", + "larrlp;": "\u21ab", + "larrpl;": "\u2939", + "larrsim;": "\u2973", + "larrtl;": "\u21a2", + "lat;": "\u2aab", + "latail;": "\u2919", + "late;": "\u2aad", + "lates;": "\u2aad\ufe00", + "lbarr;": "\u290c", + "lbbrk;": "\u2772", + "lbrace;": "{", + "lbrack;": "[", + "lbrke;": "\u298b", + "lbrksld;": "\u298f", + "lbrkslu;": "\u298d", + "lcaron;": "\u013e", + "lcedil;": "\u013c", + "lceil;": "\u2308", + "lcub;": "{", + "lcy;": "\u043b", + "ldca;": "\u2936", + "ldquo;": "\u201c", + "ldquor;": "\u201e", + "ldrdhar;": "\u2967", + "ldrushar;": "\u294b", + "ldsh;": "\u21b2", + "le;": "\u2264", + "leftarrow;": "\u2190", + "leftarrowtail;": "\u21a2", + "leftharpoondown;": "\u21bd", + "leftharpoonup;": "\u21bc", + "leftleftarrows;": "\u21c7", + "leftrightarrow;": "\u2194", + "leftrightarrows;": "\u21c6", + "leftrightharpoons;": "\u21cb", + "leftrightsquigarrow;": "\u21ad", + "leftthreetimes;": "\u22cb", + "leg;": "\u22da", + "leq;": "\u2264", + "leqq;": "\u2266", + "leqslant;": "\u2a7d", + "les;": "\u2a7d", + "lescc;": "\u2aa8", + "lesdot;": "\u2a7f", + "lesdoto;": "\u2a81", + "lesdotor;": "\u2a83", + "lesg;": "\u22da\ufe00", + "lesges;": "\u2a93", + "lessapprox;": "\u2a85", + "lessdot;": "\u22d6", + "lesseqgtr;": "\u22da", + "lesseqqgtr;": "\u2a8b", + "lessgtr;": "\u2276", + "lesssim;": "\u2272", + "lfisht;": "\u297c", + "lfloor;": "\u230a", + "lfr;": "\U0001d529", + "lg;": "\u2276", + "lgE;": "\u2a91", + "lhard;": "\u21bd", + "lharu;": "\u21bc", + "lharul;": "\u296a", + "lhblk;": "\u2584", + "ljcy;": "\u0459", + "ll;": "\u226a", + "llarr;": "\u21c7", + "llcorner;": "\u231e", + "llhard;": "\u296b", + "lltri;": "\u25fa", + "lmidot;": "\u0140", + "lmoust;": "\u23b0", + "lmoustache;": "\u23b0", + "lnE;": "\u2268", + "lnap;": "\u2a89", + "lnapprox;": "\u2a89", + "lne;": "\u2a87", + "lneq;": "\u2a87", + "lneqq;": "\u2268", + "lnsim;": "\u22e6", + "loang;": "\u27ec", + "loarr;": "\u21fd", + "lobrk;": "\u27e6", + "longleftarrow;": "\u27f5", + "longleftrightarrow;": "\u27f7", + "longmapsto;": "\u27fc", + "longrightarrow;": "\u27f6", + "looparrowleft;": "\u21ab", + "looparrowright;": "\u21ac", + "lopar;": "\u2985", + "lopf;": "\U0001d55d", + "loplus;": "\u2a2d", + "lotimes;": "\u2a34", + "lowast;": "\u2217", + "lowbar;": "_", + "loz;": "\u25ca", + "lozenge;": "\u25ca", + "lozf;": "\u29eb", + "lpar;": "(", + "lparlt;": "\u2993", + "lrarr;": "\u21c6", + "lrcorner;": "\u231f", + "lrhar;": "\u21cb", + "lrhard;": "\u296d", + "lrm;": "\u200e", + "lrtri;": "\u22bf", + "lsaquo;": "\u2039", + "lscr;": "\U0001d4c1", + "lsh;": "\u21b0", + "lsim;": "\u2272", + "lsime;": "\u2a8d", + "lsimg;": "\u2a8f", + "lsqb;": "[", + "lsquo;": "\u2018", + "lsquor;": "\u201a", + "lstrok;": "\u0142", + "lt": "<", + "lt;": "<", + "ltcc;": "\u2aa6", + "ltcir;": "\u2a79", + "ltdot;": "\u22d6", + "lthree;": "\u22cb", + "ltimes;": "\u22c9", + "ltlarr;": "\u2976", + "ltquest;": "\u2a7b", + "ltrPar;": "\u2996", + "ltri;": "\u25c3", + "ltrie;": "\u22b4", + "ltrif;": "\u25c2", + "lurdshar;": "\u294a", + "luruhar;": "\u2966", + "lvertneqq;": "\u2268\ufe00", + "lvnE;": "\u2268\ufe00", + "mDDot;": "\u223a", + "macr": "\xaf", + "macr;": "\xaf", + "male;": "\u2642", + "malt;": "\u2720", + "maltese;": "\u2720", + "map;": "\u21a6", + "mapsto;": "\u21a6", + "mapstodown;": "\u21a7", + "mapstoleft;": "\u21a4", + "mapstoup;": "\u21a5", + "marker;": "\u25ae", + "mcomma;": "\u2a29", + "mcy;": "\u043c", + "mdash;": "\u2014", + "measuredangle;": "\u2221", + "mfr;": "\U0001d52a", + "mho;": "\u2127", + "micro": "\xb5", + "micro;": "\xb5", + "mid;": "\u2223", + "midast;": "*", + "midcir;": "\u2af0", + "middot": "\xb7", + "middot;": "\xb7", + "minus;": "\u2212", + "minusb;": "\u229f", + "minusd;": "\u2238", + "minusdu;": "\u2a2a", + "mlcp;": "\u2adb", + "mldr;": "\u2026", + "mnplus;": "\u2213", + "models;": "\u22a7", + "mopf;": "\U0001d55e", + "mp;": "\u2213", + "mscr;": "\U0001d4c2", + "mstpos;": "\u223e", + "mu;": "\u03bc", + "multimap;": "\u22b8", + "mumap;": "\u22b8", + "nGg;": "\u22d9\u0338", + "nGt;": "\u226b\u20d2", + "nGtv;": "\u226b\u0338", + "nLeftarrow;": "\u21cd", + "nLeftrightarrow;": "\u21ce", + "nLl;": "\u22d8\u0338", + "nLt;": "\u226a\u20d2", + "nLtv;": "\u226a\u0338", + "nRightarrow;": "\u21cf", + "nVDash;": "\u22af", + "nVdash;": "\u22ae", + "nabla;": "\u2207", + "nacute;": "\u0144", + "nang;": "\u2220\u20d2", + "nap;": "\u2249", + "napE;": "\u2a70\u0338", + "napid;": "\u224b\u0338", + "napos;": "\u0149", + "napprox;": "\u2249", + "natur;": "\u266e", + "natural;": "\u266e", + "naturals;": "\u2115", + "nbsp": "\xa0", + "nbsp;": "\xa0", + "nbump;": "\u224e\u0338", + "nbumpe;": "\u224f\u0338", + "ncap;": "\u2a43", + "ncaron;": "\u0148", + "ncedil;": "\u0146", + "ncong;": "\u2247", + "ncongdot;": "\u2a6d\u0338", + "ncup;": "\u2a42", + "ncy;": "\u043d", + "ndash;": "\u2013", + "ne;": "\u2260", + "neArr;": "\u21d7", + "nearhk;": "\u2924", + "nearr;": "\u2197", + "nearrow;": "\u2197", + "nedot;": "\u2250\u0338", + "nequiv;": "\u2262", + "nesear;": "\u2928", + "nesim;": "\u2242\u0338", + "nexist;": "\u2204", + "nexists;": "\u2204", + "nfr;": "\U0001d52b", + "ngE;": "\u2267\u0338", + "nge;": "\u2271", + "ngeq;": "\u2271", + "ngeqq;": "\u2267\u0338", + "ngeqslant;": "\u2a7e\u0338", + "nges;": "\u2a7e\u0338", + "ngsim;": "\u2275", + "ngt;": "\u226f", + "ngtr;": "\u226f", + "nhArr;": "\u21ce", + "nharr;": "\u21ae", + "nhpar;": "\u2af2", + "ni;": "\u220b", + "nis;": "\u22fc", + "nisd;": "\u22fa", + "niv;": "\u220b", + "njcy;": "\u045a", + "nlArr;": "\u21cd", + "nlE;": "\u2266\u0338", + "nlarr;": "\u219a", + "nldr;": "\u2025", + "nle;": "\u2270", + "nleftarrow;": "\u219a", + "nleftrightarrow;": "\u21ae", + "nleq;": "\u2270", + "nleqq;": "\u2266\u0338", + "nleqslant;": "\u2a7d\u0338", + "nles;": "\u2a7d\u0338", + "nless;": "\u226e", + "nlsim;": "\u2274", + "nlt;": "\u226e", + "nltri;": "\u22ea", + "nltrie;": "\u22ec", + "nmid;": "\u2224", + "nopf;": "\U0001d55f", + "not": "\xac", + "not;": "\xac", + "notin;": "\u2209", + "notinE;": "\u22f9\u0338", + "notindot;": "\u22f5\u0338", + "notinva;": "\u2209", + "notinvb;": "\u22f7", + "notinvc;": "\u22f6", + "notni;": "\u220c", + "notniva;": "\u220c", + "notnivb;": "\u22fe", + "notnivc;": "\u22fd", + "npar;": "\u2226", + "nparallel;": "\u2226", + "nparsl;": "\u2afd\u20e5", + "npart;": "\u2202\u0338", + "npolint;": "\u2a14", + "npr;": "\u2280", + "nprcue;": "\u22e0", + "npre;": "\u2aaf\u0338", + "nprec;": "\u2280", + "npreceq;": "\u2aaf\u0338", + "nrArr;": "\u21cf", + "nrarr;": "\u219b", + "nrarrc;": "\u2933\u0338", + "nrarrw;": "\u219d\u0338", + "nrightarrow;": "\u219b", + "nrtri;": "\u22eb", + "nrtrie;": "\u22ed", + "nsc;": "\u2281", + "nsccue;": "\u22e1", + "nsce;": "\u2ab0\u0338", + "nscr;": "\U0001d4c3", + "nshortmid;": "\u2224", + "nshortparallel;": "\u2226", + "nsim;": "\u2241", + "nsime;": "\u2244", + "nsimeq;": "\u2244", + "nsmid;": "\u2224", + "nspar;": "\u2226", + "nsqsube;": "\u22e2", + "nsqsupe;": "\u22e3", + "nsub;": "\u2284", + "nsubE;": "\u2ac5\u0338", + "nsube;": "\u2288", + "nsubset;": "\u2282\u20d2", + "nsubseteq;": "\u2288", + "nsubseteqq;": "\u2ac5\u0338", + "nsucc;": "\u2281", + "nsucceq;": "\u2ab0\u0338", + "nsup;": "\u2285", + "nsupE;": "\u2ac6\u0338", + "nsupe;": "\u2289", + "nsupset;": "\u2283\u20d2", + "nsupseteq;": "\u2289", + "nsupseteqq;": "\u2ac6\u0338", + "ntgl;": "\u2279", + "ntilde": "\xf1", + "ntilde;": "\xf1", + "ntlg;": "\u2278", + "ntriangleleft;": "\u22ea", + "ntrianglelefteq;": "\u22ec", + "ntriangleright;": "\u22eb", + "ntrianglerighteq;": "\u22ed", + "nu;": "\u03bd", + "num;": "#", + "numero;": "\u2116", + "numsp;": "\u2007", + "nvDash;": "\u22ad", + "nvHarr;": "\u2904", + "nvap;": "\u224d\u20d2", + "nvdash;": "\u22ac", + "nvge;": "\u2265\u20d2", + "nvgt;": ">\u20d2", + "nvinfin;": "\u29de", + "nvlArr;": "\u2902", + "nvle;": "\u2264\u20d2", + "nvlt;": "<\u20d2", + "nvltrie;": "\u22b4\u20d2", + "nvrArr;": "\u2903", + "nvrtrie;": "\u22b5\u20d2", + "nvsim;": "\u223c\u20d2", + "nwArr;": "\u21d6", + "nwarhk;": "\u2923", + "nwarr;": "\u2196", + "nwarrow;": "\u2196", + "nwnear;": "\u2927", + "oS;": "\u24c8", + "oacute": "\xf3", + "oacute;": "\xf3", + "oast;": "\u229b", + "ocir;": "\u229a", + "ocirc": "\xf4", + "ocirc;": "\xf4", + "ocy;": "\u043e", + "odash;": "\u229d", + "odblac;": "\u0151", + "odiv;": "\u2a38", + "odot;": "\u2299", + "odsold;": "\u29bc", + "oelig;": "\u0153", + "ofcir;": "\u29bf", + "ofr;": "\U0001d52c", + "ogon;": "\u02db", + "ograve": "\xf2", + "ograve;": "\xf2", + "ogt;": "\u29c1", + "ohbar;": "\u29b5", + "ohm;": "\u03a9", + "oint;": "\u222e", + "olarr;": "\u21ba", + "olcir;": "\u29be", + "olcross;": "\u29bb", + "oline;": "\u203e", + "olt;": "\u29c0", + "omacr;": "\u014d", + "omega;": "\u03c9", + "omicron;": "\u03bf", + "omid;": "\u29b6", + "ominus;": "\u2296", + "oopf;": "\U0001d560", + "opar;": "\u29b7", + "operp;": "\u29b9", + "oplus;": "\u2295", + "or;": "\u2228", + "orarr;": "\u21bb", + "ord;": "\u2a5d", + "order;": "\u2134", + "orderof;": "\u2134", + "ordf": "\xaa", + "ordf;": "\xaa", + "ordm": "\xba", + "ordm;": "\xba", + "origof;": "\u22b6", + "oror;": "\u2a56", + "orslope;": "\u2a57", + "orv;": "\u2a5b", + "oscr;": "\u2134", + "oslash": "\xf8", + "oslash;": "\xf8", + "osol;": "\u2298", + "otilde": "\xf5", + "otilde;": "\xf5", + "otimes;": "\u2297", + "otimesas;": "\u2a36", + "ouml": "\xf6", + "ouml;": "\xf6", + "ovbar;": "\u233d", + "par;": "\u2225", + "para": "\xb6", + "para;": "\xb6", + "parallel;": "\u2225", + "parsim;": "\u2af3", + "parsl;": "\u2afd", + "part;": "\u2202", + "pcy;": "\u043f", + "percnt;": "%", + "period;": ".", + "permil;": "\u2030", + "perp;": "\u22a5", + "pertenk;": "\u2031", + "pfr;": "\U0001d52d", + "phi;": "\u03c6", + "phiv;": "\u03d5", + "phmmat;": "\u2133", + "phone;": "\u260e", + "pi;": "\u03c0", + "pitchfork;": "\u22d4", + "piv;": "\u03d6", + "planck;": "\u210f", + "planckh;": "\u210e", + "plankv;": "\u210f", + "plus;": "+", + "plusacir;": "\u2a23", + "plusb;": "\u229e", + "pluscir;": "\u2a22", + "plusdo;": "\u2214", + "plusdu;": "\u2a25", + "pluse;": "\u2a72", + "plusmn": "\xb1", + "plusmn;": "\xb1", + "plussim;": "\u2a26", + "plustwo;": "\u2a27", + "pm;": "\xb1", + "pointint;": "\u2a15", + "popf;": "\U0001d561", + "pound": "\xa3", + "pound;": "\xa3", + "pr;": "\u227a", + "prE;": "\u2ab3", + "prap;": "\u2ab7", + "prcue;": "\u227c", + "pre;": "\u2aaf", + "prec;": "\u227a", + "precapprox;": "\u2ab7", + "preccurlyeq;": "\u227c", + "preceq;": "\u2aaf", + "precnapprox;": "\u2ab9", + "precneqq;": "\u2ab5", + "precnsim;": "\u22e8", + "precsim;": "\u227e", + "prime;": "\u2032", + "primes;": "\u2119", + "prnE;": "\u2ab5", + "prnap;": "\u2ab9", + "prnsim;": "\u22e8", + "prod;": "\u220f", + "profalar;": "\u232e", + "profline;": "\u2312", + "profsurf;": "\u2313", + "prop;": "\u221d", + "propto;": "\u221d", + "prsim;": "\u227e", + "prurel;": "\u22b0", + "pscr;": "\U0001d4c5", + "psi;": "\u03c8", + "puncsp;": "\u2008", + "qfr;": "\U0001d52e", + "qint;": "\u2a0c", + "qopf;": "\U0001d562", + "qprime;": "\u2057", + "qscr;": "\U0001d4c6", + "quaternions;": "\u210d", + "quatint;": "\u2a16", + "quest;": "?", + "questeq;": "\u225f", + "quot": "\"", + "quot;": "\"", + "rAarr;": "\u21db", + "rArr;": "\u21d2", + "rAtail;": "\u291c", + "rBarr;": "\u290f", + "rHar;": "\u2964", + "race;": "\u223d\u0331", + "racute;": "\u0155", + "radic;": "\u221a", + "raemptyv;": "\u29b3", + "rang;": "\u27e9", + "rangd;": "\u2992", + "range;": "\u29a5", + "rangle;": "\u27e9", + "raquo": "\xbb", + "raquo;": "\xbb", + "rarr;": "\u2192", + "rarrap;": "\u2975", + "rarrb;": "\u21e5", + "rarrbfs;": "\u2920", + "rarrc;": "\u2933", + "rarrfs;": "\u291e", + "rarrhk;": "\u21aa", + "rarrlp;": "\u21ac", + "rarrpl;": "\u2945", + "rarrsim;": "\u2974", + "rarrtl;": "\u21a3", + "rarrw;": "\u219d", + "ratail;": "\u291a", + "ratio;": "\u2236", + "rationals;": "\u211a", + "rbarr;": "\u290d", + "rbbrk;": "\u2773", + "rbrace;": "}", + "rbrack;": "]", + "rbrke;": "\u298c", + "rbrksld;": "\u298e", + "rbrkslu;": "\u2990", + "rcaron;": "\u0159", + "rcedil;": "\u0157", + "rceil;": "\u2309", + "rcub;": "}", + "rcy;": "\u0440", + "rdca;": "\u2937", + "rdldhar;": "\u2969", + "rdquo;": "\u201d", + "rdquor;": "\u201d", + "rdsh;": "\u21b3", + "real;": "\u211c", + "realine;": "\u211b", + "realpart;": "\u211c", + "reals;": "\u211d", + "rect;": "\u25ad", + "reg": "\xae", + "reg;": "\xae", + "rfisht;": "\u297d", + "rfloor;": "\u230b", + "rfr;": "\U0001d52f", + "rhard;": "\u21c1", + "rharu;": "\u21c0", + "rharul;": "\u296c", + "rho;": "\u03c1", + "rhov;": "\u03f1", + "rightarrow;": "\u2192", + "rightarrowtail;": "\u21a3", + "rightharpoondown;": "\u21c1", + "rightharpoonup;": "\u21c0", + "rightleftarrows;": "\u21c4", + "rightleftharpoons;": "\u21cc", + "rightrightarrows;": "\u21c9", + "rightsquigarrow;": "\u219d", + "rightthreetimes;": "\u22cc", + "ring;": "\u02da", + "risingdotseq;": "\u2253", + "rlarr;": "\u21c4", + "rlhar;": "\u21cc", + "rlm;": "\u200f", + "rmoust;": "\u23b1", + "rmoustache;": "\u23b1", + "rnmid;": "\u2aee", + "roang;": "\u27ed", + "roarr;": "\u21fe", + "robrk;": "\u27e7", + "ropar;": "\u2986", + "ropf;": "\U0001d563", + "roplus;": "\u2a2e", + "rotimes;": "\u2a35", + "rpar;": ")", + "rpargt;": "\u2994", + "rppolint;": "\u2a12", + "rrarr;": "\u21c9", + "rsaquo;": "\u203a", + "rscr;": "\U0001d4c7", + "rsh;": "\u21b1", + "rsqb;": "]", + "rsquo;": "\u2019", + "rsquor;": "\u2019", + "rthree;": "\u22cc", + "rtimes;": "\u22ca", + "rtri;": "\u25b9", + "rtrie;": "\u22b5", + "rtrif;": "\u25b8", + "rtriltri;": "\u29ce", + "ruluhar;": "\u2968", + "rx;": "\u211e", + "sacute;": "\u015b", + "sbquo;": "\u201a", + "sc;": "\u227b", + "scE;": "\u2ab4", + "scap;": "\u2ab8", + "scaron;": "\u0161", + "sccue;": "\u227d", + "sce;": "\u2ab0", + "scedil;": "\u015f", + "scirc;": "\u015d", + "scnE;": "\u2ab6", + "scnap;": "\u2aba", + "scnsim;": "\u22e9", + "scpolint;": "\u2a13", + "scsim;": "\u227f", + "scy;": "\u0441", + "sdot;": "\u22c5", + "sdotb;": "\u22a1", + "sdote;": "\u2a66", + "seArr;": "\u21d8", + "searhk;": "\u2925", + "searr;": "\u2198", + "searrow;": "\u2198", + "sect": "\xa7", + "sect;": "\xa7", + "semi;": ";", + "seswar;": "\u2929", + "setminus;": "\u2216", + "setmn;": "\u2216", + "sext;": "\u2736", + "sfr;": "\U0001d530", + "sfrown;": "\u2322", + "sharp;": "\u266f", + "shchcy;": "\u0449", + "shcy;": "\u0448", + "shortmid;": "\u2223", + "shortparallel;": "\u2225", + "shy": "\xad", + "shy;": "\xad", + "sigma;": "\u03c3", + "sigmaf;": "\u03c2", + "sigmav;": "\u03c2", + "sim;": "\u223c", + "simdot;": "\u2a6a", + "sime;": "\u2243", + "simeq;": "\u2243", + "simg;": "\u2a9e", + "simgE;": "\u2aa0", + "siml;": "\u2a9d", + "simlE;": "\u2a9f", + "simne;": "\u2246", + "simplus;": "\u2a24", + "simrarr;": "\u2972", + "slarr;": "\u2190", + "smallsetminus;": "\u2216", + "smashp;": "\u2a33", + "smeparsl;": "\u29e4", + "smid;": "\u2223", + "smile;": "\u2323", + "smt;": "\u2aaa", + "smte;": "\u2aac", + "smtes;": "\u2aac\ufe00", + "softcy;": "\u044c", + "sol;": "/", + "solb;": "\u29c4", + "solbar;": "\u233f", + "sopf;": "\U0001d564", + "spades;": "\u2660", + "spadesuit;": "\u2660", + "spar;": "\u2225", + "sqcap;": "\u2293", + "sqcaps;": "\u2293\ufe00", + "sqcup;": "\u2294", + "sqcups;": "\u2294\ufe00", + "sqsub;": "\u228f", + "sqsube;": "\u2291", + "sqsubset;": "\u228f", + "sqsubseteq;": "\u2291", + "sqsup;": "\u2290", + "sqsupe;": "\u2292", + "sqsupset;": "\u2290", + "sqsupseteq;": "\u2292", + "squ;": "\u25a1", + "square;": "\u25a1", + "squarf;": "\u25aa", + "squf;": "\u25aa", + "srarr;": "\u2192", + "sscr;": "\U0001d4c8", + "ssetmn;": "\u2216", + "ssmile;": "\u2323", + "sstarf;": "\u22c6", + "star;": "\u2606", + "starf;": "\u2605", + "straightepsilon;": "\u03f5", + "straightphi;": "\u03d5", + "strns;": "\xaf", + "sub;": "\u2282", + "subE;": "\u2ac5", + "subdot;": "\u2abd", + "sube;": "\u2286", + "subedot;": "\u2ac3", + "submult;": "\u2ac1", + "subnE;": "\u2acb", + "subne;": "\u228a", + "subplus;": "\u2abf", + "subrarr;": "\u2979", + "subset;": "\u2282", + "subseteq;": "\u2286", + "subseteqq;": "\u2ac5", + "subsetneq;": "\u228a", + "subsetneqq;": "\u2acb", + "subsim;": "\u2ac7", + "subsub;": "\u2ad5", + "subsup;": "\u2ad3", + "succ;": "\u227b", + "succapprox;": "\u2ab8", + "succcurlyeq;": "\u227d", + "succeq;": "\u2ab0", + "succnapprox;": "\u2aba", + "succneqq;": "\u2ab6", + "succnsim;": "\u22e9", + "succsim;": "\u227f", + "sum;": "\u2211", + "sung;": "\u266a", + "sup1": "\xb9", + "sup1;": "\xb9", + "sup2": "\xb2", + "sup2;": "\xb2", + "sup3": "\xb3", + "sup3;": "\xb3", + "sup;": "\u2283", + "supE;": "\u2ac6", + "supdot;": "\u2abe", + "supdsub;": "\u2ad8", + "supe;": "\u2287", + "supedot;": "\u2ac4", + "suphsol;": "\u27c9", + "suphsub;": "\u2ad7", + "suplarr;": "\u297b", + "supmult;": "\u2ac2", + "supnE;": "\u2acc", + "supne;": "\u228b", + "supplus;": "\u2ac0", + "supset;": "\u2283", + "supseteq;": "\u2287", + "supseteqq;": "\u2ac6", + "supsetneq;": "\u228b", + "supsetneqq;": "\u2acc", + "supsim;": "\u2ac8", + "supsub;": "\u2ad4", + "supsup;": "\u2ad6", + "swArr;": "\u21d9", + "swarhk;": "\u2926", + "swarr;": "\u2199", + "swarrow;": "\u2199", + "swnwar;": "\u292a", + "szlig": "\xdf", + "szlig;": "\xdf", + "target;": "\u2316", + "tau;": "\u03c4", + "tbrk;": "\u23b4", + "tcaron;": "\u0165", + "tcedil;": "\u0163", + "tcy;": "\u0442", + "tdot;": "\u20db", + "telrec;": "\u2315", + "tfr;": "\U0001d531", + "there4;": "\u2234", + "therefore;": "\u2234", + "theta;": "\u03b8", + "thetasym;": "\u03d1", + "thetav;": "\u03d1", + "thickapprox;": "\u2248", + "thicksim;": "\u223c", + "thinsp;": "\u2009", + "thkap;": "\u2248", + "thksim;": "\u223c", + "thorn": "\xfe", + "thorn;": "\xfe", + "tilde;": "\u02dc", + "times": "\xd7", + "times;": "\xd7", + "timesb;": "\u22a0", + "timesbar;": "\u2a31", + "timesd;": "\u2a30", + "tint;": "\u222d", + "toea;": "\u2928", + "top;": "\u22a4", + "topbot;": "\u2336", + "topcir;": "\u2af1", + "topf;": "\U0001d565", + "topfork;": "\u2ada", + "tosa;": "\u2929", + "tprime;": "\u2034", + "trade;": "\u2122", + "triangle;": "\u25b5", + "triangledown;": "\u25bf", + "triangleleft;": "\u25c3", + "trianglelefteq;": "\u22b4", + "triangleq;": "\u225c", + "triangleright;": "\u25b9", + "trianglerighteq;": "\u22b5", + "tridot;": "\u25ec", + "trie;": "\u225c", + "triminus;": "\u2a3a", + "triplus;": "\u2a39", + "trisb;": "\u29cd", + "tritime;": "\u2a3b", + "trpezium;": "\u23e2", + "tscr;": "\U0001d4c9", + "tscy;": "\u0446", + "tshcy;": "\u045b", + "tstrok;": "\u0167", + "twixt;": "\u226c", + "twoheadleftarrow;": "\u219e", + "twoheadrightarrow;": "\u21a0", + "uArr;": "\u21d1", + "uHar;": "\u2963", + "uacute": "\xfa", + "uacute;": "\xfa", + "uarr;": "\u2191", + "ubrcy;": "\u045e", + "ubreve;": "\u016d", + "ucirc": "\xfb", + "ucirc;": "\xfb", + "ucy;": "\u0443", + "udarr;": "\u21c5", + "udblac;": "\u0171", + "udhar;": "\u296e", + "ufisht;": "\u297e", + "ufr;": "\U0001d532", + "ugrave": "\xf9", + "ugrave;": "\xf9", + "uharl;": "\u21bf", + "uharr;": "\u21be", + "uhblk;": "\u2580", + "ulcorn;": "\u231c", + "ulcorner;": "\u231c", + "ulcrop;": "\u230f", + "ultri;": "\u25f8", + "umacr;": "\u016b", + "uml": "\xa8", + "uml;": "\xa8", + "uogon;": "\u0173", + "uopf;": "\U0001d566", + "uparrow;": "\u2191", + "updownarrow;": "\u2195", + "upharpoonleft;": "\u21bf", + "upharpoonright;": "\u21be", + "uplus;": "\u228e", + "upsi;": "\u03c5", + "upsih;": "\u03d2", + "upsilon;": "\u03c5", + "upuparrows;": "\u21c8", + "urcorn;": "\u231d", + "urcorner;": "\u231d", + "urcrop;": "\u230e", + "uring;": "\u016f", + "urtri;": "\u25f9", + "uscr;": "\U0001d4ca", + "utdot;": "\u22f0", + "utilde;": "\u0169", + "utri;": "\u25b5", + "utrif;": "\u25b4", + "uuarr;": "\u21c8", + "uuml": "\xfc", + "uuml;": "\xfc", + "uwangle;": "\u29a7", + "vArr;": "\u21d5", + "vBar;": "\u2ae8", + "vBarv;": "\u2ae9", + "vDash;": "\u22a8", + "vangrt;": "\u299c", + "varepsilon;": "\u03f5", + "varkappa;": "\u03f0", + "varnothing;": "\u2205", + "varphi;": "\u03d5", + "varpi;": "\u03d6", + "varpropto;": "\u221d", + "varr;": "\u2195", + "varrho;": "\u03f1", + "varsigma;": "\u03c2", + "varsubsetneq;": "\u228a\ufe00", + "varsubsetneqq;": "\u2acb\ufe00", + "varsupsetneq;": "\u228b\ufe00", + "varsupsetneqq;": "\u2acc\ufe00", + "vartheta;": "\u03d1", + "vartriangleleft;": "\u22b2", + "vartriangleright;": "\u22b3", + "vcy;": "\u0432", + "vdash;": "\u22a2", + "vee;": "\u2228", + "veebar;": "\u22bb", + "veeeq;": "\u225a", + "vellip;": "\u22ee", + "verbar;": "|", + "vert;": "|", + "vfr;": "\U0001d533", + "vltri;": "\u22b2", + "vnsub;": "\u2282\u20d2", + "vnsup;": "\u2283\u20d2", + "vopf;": "\U0001d567", + "vprop;": "\u221d", + "vrtri;": "\u22b3", + "vscr;": "\U0001d4cb", + "vsubnE;": "\u2acb\ufe00", + "vsubne;": "\u228a\ufe00", + "vsupnE;": "\u2acc\ufe00", + "vsupne;": "\u228b\ufe00", + "vzigzag;": "\u299a", + "wcirc;": "\u0175", + "wedbar;": "\u2a5f", + "wedge;": "\u2227", + "wedgeq;": "\u2259", + "weierp;": "\u2118", + "wfr;": "\U0001d534", + "wopf;": "\U0001d568", + "wp;": "\u2118", + "wr;": "\u2240", + "wreath;": "\u2240", + "wscr;": "\U0001d4cc", + "xcap;": "\u22c2", + "xcirc;": "\u25ef", + "xcup;": "\u22c3", + "xdtri;": "\u25bd", + "xfr;": "\U0001d535", + "xhArr;": "\u27fa", + "xharr;": "\u27f7", + "xi;": "\u03be", + "xlArr;": "\u27f8", + "xlarr;": "\u27f5", + "xmap;": "\u27fc", + "xnis;": "\u22fb", + "xodot;": "\u2a00", + "xopf;": "\U0001d569", + "xoplus;": "\u2a01", + "xotime;": "\u2a02", + "xrArr;": "\u27f9", + "xrarr;": "\u27f6", + "xscr;": "\U0001d4cd", + "xsqcup;": "\u2a06", + "xuplus;": "\u2a04", + "xutri;": "\u25b3", + "xvee;": "\u22c1", + "xwedge;": "\u22c0", + "yacute": "\xfd", + "yacute;": "\xfd", + "yacy;": "\u044f", + "ycirc;": "\u0177", + "ycy;": "\u044b", + "yen": "\xa5", + "yen;": "\xa5", + "yfr;": "\U0001d536", + "yicy;": "\u0457", + "yopf;": "\U0001d56a", + "yscr;": "\U0001d4ce", + "yucy;": "\u044e", + "yuml": "\xff", + "yuml;": "\xff", + "zacute;": "\u017a", + "zcaron;": "\u017e", + "zcy;": "\u0437", + "zdot;": "\u017c", + "zeetrf;": "\u2128", + "zeta;": "\u03b6", + "zfr;": "\U0001d537", + "zhcy;": "\u0436", + "zigrarr;": "\u21dd", + "zopf;": "\U0001d56b", + "zscr;": "\U0001d4cf", + "zwj;": "\u200d", + "zwnj;": "\u200c", +} + +replacementCharacters = { + 0x0: "\uFFFD", + 0x0d: "\u000D", + 0x80: "\u20AC", + 0x81: "\u0081", + 0x82: "\u201A", + 0x83: "\u0192", + 0x84: "\u201E", + 0x85: "\u2026", + 0x86: "\u2020", + 0x87: "\u2021", + 0x88: "\u02C6", + 0x89: "\u2030", + 0x8A: "\u0160", + 0x8B: "\u2039", + 0x8C: "\u0152", + 0x8D: "\u008D", + 0x8E: "\u017D", + 0x8F: "\u008F", + 0x90: "\u0090", + 0x91: "\u2018", + 0x92: "\u2019", + 0x93: "\u201C", + 0x94: "\u201D", + 0x95: "\u2022", + 0x96: "\u2013", + 0x97: "\u2014", + 0x98: "\u02DC", + 0x99: "\u2122", + 0x9A: "\u0161", + 0x9B: "\u203A", + 0x9C: "\u0153", + 0x9D: "\u009D", + 0x9E: "\u017E", + 0x9F: "\u0178", +} + +tokenTypes = { + "Doctype": 0, + "Characters": 1, + "SpaceCharacters": 2, + "StartTag": 3, + "EndTag": 4, + "EmptyTag": 5, + "Comment": 6, + "ParseError": 7 +} + +tagTokenTypes = frozenset([tokenTypes["StartTag"], tokenTypes["EndTag"], + tokenTypes["EmptyTag"]]) + + +prefixes = dict([(v, k) for k, v in namespaces.items()]) +prefixes["http://www.w3.org/1998/Math/MathML"] = "math" + + +class DataLossWarning(UserWarning): + """Raised when the current tree is unable to represent the input data""" + pass + + +class _ReparseException(Exception): + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py new file mode 100755 index 0000000..d9e234a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/alphabeticalattributes.py @@ -0,0 +1,29 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + +from collections import OrderedDict + + +def _attr_key(attr): + """Return an appropriate key for an attribute for sorting + + Attributes have a namespace that can be either ``None`` or a string. We + can't compare the two because they're different types, so we convert + ``None`` to an empty string first. + + """ + return (attr[0][0] or ''), attr[0][1] + + +class Filter(base.Filter): + """Alphabetizes attributes for elements""" + def __iter__(self): + for token in base.Filter.__iter__(self): + if token["type"] in ("StartTag", "EmptyTag"): + attrs = OrderedDict() + for name, value in sorted(token["data"].items(), + key=_attr_key): + attrs[name] = value + token["data"] = attrs + yield token diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py new file mode 100755 index 0000000..f5aa523 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/base.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, unicode_literals + + +class Filter(object): + def __init__(self, source): + self.source = source + + def __iter__(self): + return iter(self.source) + + def __getattr__(self, name): + return getattr(self.source, name) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py new file mode 100755 index 0000000..2f8ec4f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/inject_meta_charset.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + + +class Filter(base.Filter): + """Injects ``<meta charset=ENCODING>`` tag into head of document""" + def __init__(self, source, encoding): + """Creates a Filter + + :arg source: the source token stream + + :arg encoding: the encoding to set + + """ + base.Filter.__init__(self, source) + self.encoding = encoding + + def __iter__(self): + state = "pre_head" + meta_found = (self.encoding is None) + pending = [] + + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag": + if token["name"].lower() == "head": + state = "in_head" + + elif type == "EmptyTag": + if token["name"].lower() == "meta": + # replace charset with actual encoding + has_http_equiv_content_type = False + for (namespace, name), value in token["data"].items(): + if namespace is not None: + continue + elif name.lower() == 'charset': + token["data"][(namespace, name)] = self.encoding + meta_found = True + break + elif name == 'http-equiv' and value.lower() == 'content-type': + has_http_equiv_content_type = True + else: + if has_http_equiv_content_type and (None, "content") in token["data"]: + token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding + meta_found = True + + elif token["name"].lower() == "head" and not meta_found: + # insert meta into empty head + yield {"type": "StartTag", "name": "head", + "data": token["data"]} + yield {"type": "EmptyTag", "name": "meta", + "data": {(None, "charset"): self.encoding}} + yield {"type": "EndTag", "name": "head"} + meta_found = True + continue + + elif type == "EndTag": + if token["name"].lower() == "head" and pending: + # insert meta into head (if necessary) and flush pending queue + yield pending.pop(0) + if not meta_found: + yield {"type": "EmptyTag", "name": "meta", + "data": {(None, "charset"): self.encoding}} + while pending: + yield pending.pop(0) + meta_found = True + state = "post_head" + + if state == "in_head": + pending.append(token) + else: + yield token diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py new file mode 100755 index 0000000..b5bbd97 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/lint.py @@ -0,0 +1,93 @@ +from __future__ import absolute_import, division, unicode_literals + +from pip._vendor.six import text_type + +from . import base +from ..constants import namespaces, voidElements + +from ..constants import spaceCharacters +spaceCharacters = "".join(spaceCharacters) + + +class Filter(base.Filter): + """Lints the token stream for errors + + If it finds any errors, it'll raise an ``AssertionError``. + + """ + def __init__(self, source, require_matching_tags=True): + """Creates a Filter + + :arg source: the source token stream + + :arg require_matching_tags: whether or not to require matching tags + + """ + super(Filter, self).__init__(source) + self.require_matching_tags = require_matching_tags + + def __iter__(self): + open_elements = [] + for token in base.Filter.__iter__(self): + type = token["type"] + if type in ("StartTag", "EmptyTag"): + namespace = token["namespace"] + name = token["name"] + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + assert isinstance(token["data"], dict) + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + assert type == "EmptyTag" + else: + assert type == "StartTag" + if type == "StartTag" and self.require_matching_tags: + open_elements.append((namespace, name)) + for (namespace, name), value in token["data"].items(): + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + assert isinstance(value, text_type) + + elif type == "EndTag": + namespace = token["namespace"] + name = token["name"] + assert namespace is None or isinstance(namespace, text_type) + assert namespace != "" + assert isinstance(name, text_type) + assert name != "" + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + assert False, "Void element reported as EndTag token: %(tag)s" % {"tag": name} + elif self.require_matching_tags: + start = open_elements.pop() + assert start == (namespace, name) + + elif type == "Comment": + data = token["data"] + assert isinstance(data, text_type) + + elif type in ("Characters", "SpaceCharacters"): + data = token["data"] + assert isinstance(data, text_type) + assert data != "" + if type == "SpaceCharacters": + assert data.strip(spaceCharacters) == "" + + elif type == "Doctype": + name = token["name"] + assert name is None or isinstance(name, text_type) + assert token["publicId"] is None or isinstance(name, text_type) + assert token["systemId"] is None or isinstance(name, text_type) + + elif type == "Entity": + assert isinstance(token["name"], text_type) + + elif type == "SerializerError": + assert isinstance(token["data"], text_type) + + else: + assert False, "Unknown token type: %(type)s" % {"type": type} + + yield token diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py new file mode 100755 index 0000000..c8d5e54 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/optionaltags.py @@ -0,0 +1,207 @@ +from __future__ import absolute_import, division, unicode_literals + +from . import base + + +class Filter(base.Filter): + """Removes optional tags from the token stream""" + def slider(self): + previous1 = previous2 = None + for token in self.source: + if previous1 is not None: + yield previous2, previous1, token + previous2 = previous1 + previous1 = token + if previous1 is not None: + yield previous2, previous1, None + + def __iter__(self): + for previous, token, next in self.slider(): + type = token["type"] + if type == "StartTag": + if (token["data"] or + not self.is_optional_start(token["name"], previous, next)): + yield token + elif type == "EndTag": + if not self.is_optional_end(token["name"], next): + yield token + else: + yield token + + def is_optional_start(self, tagname, previous, next): + type = next and next["type"] or None + if tagname in 'html': + # An html element's start tag may be omitted if the first thing + # inside the html element is not a space character or a comment. + return type not in ("Comment", "SpaceCharacters") + elif tagname == 'head': + # A head element's start tag may be omitted if the first thing + # inside the head element is an element. + # XXX: we also omit the start tag if the head element is empty + if type in ("StartTag", "EmptyTag"): + return True + elif type == "EndTag": + return next["name"] == "head" + elif tagname == 'body': + # A body element's start tag may be omitted if the first thing + # inside the body element is not a space character or a comment, + # except if the first thing inside the body element is a script + # or style element and the node immediately preceding the body + # element is a head element whose end tag has been omitted. + if type in ("Comment", "SpaceCharacters"): + return False + elif type == "StartTag": + # XXX: we do not look at the preceding event, so we never omit + # the body element's start tag if it's followed by a script or + # a style element. + return next["name"] not in ('script', 'style') + else: + return True + elif tagname == 'colgroup': + # A colgroup element's start tag may be omitted if the first thing + # inside the colgroup element is a col element, and if the element + # is not immediately preceded by another colgroup element whose + # end tag has been omitted. + if type in ("StartTag", "EmptyTag"): + # XXX: we do not look at the preceding event, so instead we never + # omit the colgroup element's end tag when it is immediately + # followed by another colgroup element. See is_optional_end. + return next["name"] == "col" + else: + return False + elif tagname == 'tbody': + # A tbody element's start tag may be omitted if the first thing + # inside the tbody element is a tr element, and if the element is + # not immediately preceded by a tbody, thead, or tfoot element + # whose end tag has been omitted. + if type == "StartTag": + # omit the thead and tfoot elements' end tag when they are + # immediately followed by a tbody element. See is_optional_end. + if previous and previous['type'] == 'EndTag' and \ + previous['name'] in ('tbody', 'thead', 'tfoot'): + return False + return next["name"] == 'tr' + else: + return False + return False + + def is_optional_end(self, tagname, next): + type = next and next["type"] or None + if tagname in ('html', 'head', 'body'): + # An html element's end tag may be omitted if the html element + # is not immediately followed by a space character or a comment. + return type not in ("Comment", "SpaceCharacters") + elif tagname in ('li', 'optgroup', 'tr'): + # A li element's end tag may be omitted if the li element is + # immediately followed by another li element or if there is + # no more content in the parent element. + # An optgroup element's end tag may be omitted if the optgroup + # element is immediately followed by another optgroup element, + # or if there is no more content in the parent element. + # A tr element's end tag may be omitted if the tr element is + # immediately followed by another tr element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] == tagname + else: + return type == "EndTag" or type is None + elif tagname in ('dt', 'dd'): + # A dt element's end tag may be omitted if the dt element is + # immediately followed by another dt element or a dd element. + # A dd element's end tag may be omitted if the dd element is + # immediately followed by another dd element or a dt element, + # or if there is no more content in the parent element. + if type == "StartTag": + return next["name"] in ('dt', 'dd') + elif tagname == 'dd': + return type == "EndTag" or type is None + else: + return False + elif tagname == 'p': + # A p element's end tag may be omitted if the p element is + # immediately followed by an address, article, aside, + # blockquote, datagrid, dialog, dir, div, dl, fieldset, + # footer, form, h1, h2, h3, h4, h5, h6, header, hr, menu, + # nav, ol, p, pre, section, table, or ul, element, or if + # there is no more content in the parent element. + if type in ("StartTag", "EmptyTag"): + return next["name"] in ('address', 'article', 'aside', + 'blockquote', 'datagrid', 'dialog', + 'dir', 'div', 'dl', 'fieldset', 'footer', + 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'header', 'hr', 'menu', 'nav', 'ol', + 'p', 'pre', 'section', 'table', 'ul') + else: + return type == "EndTag" or type is None + elif tagname == 'option': + # An option element's end tag may be omitted if the option + # element is immediately followed by another option element, + # or if it is immediately followed by an <code>optgroup</code> + # element, or if there is no more content in the parent + # element. + if type == "StartTag": + return next["name"] in ('option', 'optgroup') + else: + return type == "EndTag" or type is None + elif tagname in ('rt', 'rp'): + # An rt element's end tag may be omitted if the rt element is + # immediately followed by an rt or rp element, or if there is + # no more content in the parent element. + # An rp element's end tag may be omitted if the rp element is + # immediately followed by an rt or rp element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] in ('rt', 'rp') + else: + return type == "EndTag" or type is None + elif tagname == 'colgroup': + # A colgroup element's end tag may be omitted if the colgroup + # element is not immediately followed by a space character or + # a comment. + if type in ("Comment", "SpaceCharacters"): + return False + elif type == "StartTag": + # XXX: we also look for an immediately following colgroup + # element. See is_optional_start. + return next["name"] != 'colgroup' + else: + return True + elif tagname in ('thead', 'tbody'): + # A thead element's end tag may be omitted if the thead element + # is immediately followed by a tbody or tfoot element. + # A tbody element's end tag may be omitted if the tbody element + # is immediately followed by a tbody or tfoot element, or if + # there is no more content in the parent element. + # A tfoot element's end tag may be omitted if the tfoot element + # is immediately followed by a tbody element, or if there is no + # more content in the parent element. + # XXX: we never omit the end tag when the following element is + # a tbody. See is_optional_start. + if type == "StartTag": + return next["name"] in ['tbody', 'tfoot'] + elif tagname == 'tbody': + return type == "EndTag" or type is None + else: + return False + elif tagname == 'tfoot': + # A tfoot element's end tag may be omitted if the tfoot element + # is immediately followed by a tbody element, or if there is no + # more content in the parent element. + # XXX: we never omit the end tag when the following element is + # a tbody. See is_optional_start. + if type == "StartTag": + return next["name"] == 'tbody' + else: + return type == "EndTag" or type is None + elif tagname in ('td', 'th'): + # A td element's end tag may be omitted if the td element is + # immediately followed by a td or th element, or if there is + # no more content in the parent element. + # A th element's end tag may be omitted if the th element is + # immediately followed by a td or th element, or if there is + # no more content in the parent element. + if type == "StartTag": + return next["name"] in ('td', 'th') + else: + return type == "EndTag" or type is None + return False diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py new file mode 100755 index 0000000..c3199a5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/sanitizer.py @@ -0,0 +1,896 @@ +from __future__ import absolute_import, division, unicode_literals + +import re +from xml.sax.saxutils import escape, unescape + +from pip._vendor.six.moves import urllib_parse as urlparse + +from . import base +from ..constants import namespaces, prefixes + +__all__ = ["Filter"] + + +allowed_elements = frozenset(( + (namespaces['html'], 'a'), + (namespaces['html'], 'abbr'), + (namespaces['html'], 'acronym'), + (namespaces['html'], 'address'), + (namespaces['html'], 'area'), + (namespaces['html'], 'article'), + (namespaces['html'], 'aside'), + (namespaces['html'], 'audio'), + (namespaces['html'], 'b'), + (namespaces['html'], 'big'), + (namespaces['html'], 'blockquote'), + (namespaces['html'], 'br'), + (namespaces['html'], 'button'), + (namespaces['html'], 'canvas'), + (namespaces['html'], 'caption'), + (namespaces['html'], 'center'), + (namespaces['html'], 'cite'), + (namespaces['html'], 'code'), + (namespaces['html'], 'col'), + (namespaces['html'], 'colgroup'), + (namespaces['html'], 'command'), + (namespaces['html'], 'datagrid'), + (namespaces['html'], 'datalist'), + (namespaces['html'], 'dd'), + (namespaces['html'], 'del'), + (namespaces['html'], 'details'), + (namespaces['html'], 'dfn'), + (namespaces['html'], 'dialog'), + (namespaces['html'], 'dir'), + (namespaces['html'], 'div'), + (namespaces['html'], 'dl'), + (namespaces['html'], 'dt'), + (namespaces['html'], 'em'), + (namespaces['html'], 'event-source'), + (namespaces['html'], 'fieldset'), + (namespaces['html'], 'figcaption'), + (namespaces['html'], 'figure'), + (namespaces['html'], 'footer'), + (namespaces['html'], 'font'), + (namespaces['html'], 'form'), + (namespaces['html'], 'header'), + (namespaces['html'], 'h1'), + (namespaces['html'], 'h2'), + (namespaces['html'], 'h3'), + (namespaces['html'], 'h4'), + (namespaces['html'], 'h5'), + (namespaces['html'], 'h6'), + (namespaces['html'], 'hr'), + (namespaces['html'], 'i'), + (namespaces['html'], 'img'), + (namespaces['html'], 'input'), + (namespaces['html'], 'ins'), + (namespaces['html'], 'keygen'), + (namespaces['html'], 'kbd'), + (namespaces['html'], 'label'), + (namespaces['html'], 'legend'), + (namespaces['html'], 'li'), + (namespaces['html'], 'm'), + (namespaces['html'], 'map'), + (namespaces['html'], 'menu'), + (namespaces['html'], 'meter'), + (namespaces['html'], 'multicol'), + (namespaces['html'], 'nav'), + (namespaces['html'], 'nextid'), + (namespaces['html'], 'ol'), + (namespaces['html'], 'output'), + (namespaces['html'], 'optgroup'), + (namespaces['html'], 'option'), + (namespaces['html'], 'p'), + (namespaces['html'], 'pre'), + (namespaces['html'], 'progress'), + (namespaces['html'], 'q'), + (namespaces['html'], 's'), + (namespaces['html'], 'samp'), + (namespaces['html'], 'section'), + (namespaces['html'], 'select'), + (namespaces['html'], 'small'), + (namespaces['html'], 'sound'), + (namespaces['html'], 'source'), + (namespaces['html'], 'spacer'), + (namespaces['html'], 'span'), + (namespaces['html'], 'strike'), + (namespaces['html'], 'strong'), + (namespaces['html'], 'sub'), + (namespaces['html'], 'sup'), + (namespaces['html'], 'table'), + (namespaces['html'], 'tbody'), + (namespaces['html'], 'td'), + (namespaces['html'], 'textarea'), + (namespaces['html'], 'time'), + (namespaces['html'], 'tfoot'), + (namespaces['html'], 'th'), + (namespaces['html'], 'thead'), + (namespaces['html'], 'tr'), + (namespaces['html'], 'tt'), + (namespaces['html'], 'u'), + (namespaces['html'], 'ul'), + (namespaces['html'], 'var'), + (namespaces['html'], 'video'), + (namespaces['mathml'], 'maction'), + (namespaces['mathml'], 'math'), + (namespaces['mathml'], 'merror'), + (namespaces['mathml'], 'mfrac'), + (namespaces['mathml'], 'mi'), + (namespaces['mathml'], 'mmultiscripts'), + (namespaces['mathml'], 'mn'), + (namespaces['mathml'], 'mo'), + (namespaces['mathml'], 'mover'), + (namespaces['mathml'], 'mpadded'), + (namespaces['mathml'], 'mphantom'), + (namespaces['mathml'], 'mprescripts'), + (namespaces['mathml'], 'mroot'), + (namespaces['mathml'], 'mrow'), + (namespaces['mathml'], 'mspace'), + (namespaces['mathml'], 'msqrt'), + (namespaces['mathml'], 'mstyle'), + (namespaces['mathml'], 'msub'), + (namespaces['mathml'], 'msubsup'), + (namespaces['mathml'], 'msup'), + (namespaces['mathml'], 'mtable'), + (namespaces['mathml'], 'mtd'), + (namespaces['mathml'], 'mtext'), + (namespaces['mathml'], 'mtr'), + (namespaces['mathml'], 'munder'), + (namespaces['mathml'], 'munderover'), + (namespaces['mathml'], 'none'), + (namespaces['svg'], 'a'), + (namespaces['svg'], 'animate'), + (namespaces['svg'], 'animateColor'), + (namespaces['svg'], 'animateMotion'), + (namespaces['svg'], 'animateTransform'), + (namespaces['svg'], 'clipPath'), + (namespaces['svg'], 'circle'), + (namespaces['svg'], 'defs'), + (namespaces['svg'], 'desc'), + (namespaces['svg'], 'ellipse'), + (namespaces['svg'], 'font-face'), + (namespaces['svg'], 'font-face-name'), + (namespaces['svg'], 'font-face-src'), + (namespaces['svg'], 'g'), + (namespaces['svg'], 'glyph'), + (namespaces['svg'], 'hkern'), + (namespaces['svg'], 'linearGradient'), + (namespaces['svg'], 'line'), + (namespaces['svg'], 'marker'), + (namespaces['svg'], 'metadata'), + (namespaces['svg'], 'missing-glyph'), + (namespaces['svg'], 'mpath'), + (namespaces['svg'], 'path'), + (namespaces['svg'], 'polygon'), + (namespaces['svg'], 'polyline'), + (namespaces['svg'], 'radialGradient'), + (namespaces['svg'], 'rect'), + (namespaces['svg'], 'set'), + (namespaces['svg'], 'stop'), + (namespaces['svg'], 'svg'), + (namespaces['svg'], 'switch'), + (namespaces['svg'], 'text'), + (namespaces['svg'], 'title'), + (namespaces['svg'], 'tspan'), + (namespaces['svg'], 'use'), +)) + +allowed_attributes = frozenset(( + # HTML attributes + (None, 'abbr'), + (None, 'accept'), + (None, 'accept-charset'), + (None, 'accesskey'), + (None, 'action'), + (None, 'align'), + (None, 'alt'), + (None, 'autocomplete'), + (None, 'autofocus'), + (None, 'axis'), + (None, 'background'), + (None, 'balance'), + (None, 'bgcolor'), + (None, 'bgproperties'), + (None, 'border'), + (None, 'bordercolor'), + (None, 'bordercolordark'), + (None, 'bordercolorlight'), + (None, 'bottompadding'), + (None, 'cellpadding'), + (None, 'cellspacing'), + (None, 'ch'), + (None, 'challenge'), + (None, 'char'), + (None, 'charoff'), + (None, 'choff'), + (None, 'charset'), + (None, 'checked'), + (None, 'cite'), + (None, 'class'), + (None, 'clear'), + (None, 'color'), + (None, 'cols'), + (None, 'colspan'), + (None, 'compact'), + (None, 'contenteditable'), + (None, 'controls'), + (None, 'coords'), + (None, 'data'), + (None, 'datafld'), + (None, 'datapagesize'), + (None, 'datasrc'), + (None, 'datetime'), + (None, 'default'), + (None, 'delay'), + (None, 'dir'), + (None, 'disabled'), + (None, 'draggable'), + (None, 'dynsrc'), + (None, 'enctype'), + (None, 'end'), + (None, 'face'), + (None, 'for'), + (None, 'form'), + (None, 'frame'), + (None, 'galleryimg'), + (None, 'gutter'), + (None, 'headers'), + (None, 'height'), + (None, 'hidefocus'), + (None, 'hidden'), + (None, 'high'), + (None, 'href'), + (None, 'hreflang'), + (None, 'hspace'), + (None, 'icon'), + (None, 'id'), + (None, 'inputmode'), + (None, 'ismap'), + (None, 'keytype'), + (None, 'label'), + (None, 'leftspacing'), + (None, 'lang'), + (None, 'list'), + (None, 'longdesc'), + (None, 'loop'), + (None, 'loopcount'), + (None, 'loopend'), + (None, 'loopstart'), + (None, 'low'), + (None, 'lowsrc'), + (None, 'max'), + (None, 'maxlength'), + (None, 'media'), + (None, 'method'), + (None, 'min'), + (None, 'multiple'), + (None, 'name'), + (None, 'nohref'), + (None, 'noshade'), + (None, 'nowrap'), + (None, 'open'), + (None, 'optimum'), + (None, 'pattern'), + (None, 'ping'), + (None, 'point-size'), + (None, 'poster'), + (None, 'pqg'), + (None, 'preload'), + (None, 'prompt'), + (None, 'radiogroup'), + (None, 'readonly'), + (None, 'rel'), + (None, 'repeat-max'), + (None, 'repeat-min'), + (None, 'replace'), + (None, 'required'), + (None, 'rev'), + (None, 'rightspacing'), + (None, 'rows'), + (None, 'rowspan'), + (None, 'rules'), + (None, 'scope'), + (None, 'selected'), + (None, 'shape'), + (None, 'size'), + (None, 'span'), + (None, 'src'), + (None, 'start'), + (None, 'step'), + (None, 'style'), + (None, 'summary'), + (None, 'suppress'), + (None, 'tabindex'), + (None, 'target'), + (None, 'template'), + (None, 'title'), + (None, 'toppadding'), + (None, 'type'), + (None, 'unselectable'), + (None, 'usemap'), + (None, 'urn'), + (None, 'valign'), + (None, 'value'), + (None, 'variable'), + (None, 'volume'), + (None, 'vspace'), + (None, 'vrml'), + (None, 'width'), + (None, 'wrap'), + (namespaces['xml'], 'lang'), + # MathML attributes + (None, 'actiontype'), + (None, 'align'), + (None, 'columnalign'), + (None, 'columnalign'), + (None, 'columnalign'), + (None, 'columnlines'), + (None, 'columnspacing'), + (None, 'columnspan'), + (None, 'depth'), + (None, 'display'), + (None, 'displaystyle'), + (None, 'equalcolumns'), + (None, 'equalrows'), + (None, 'fence'), + (None, 'fontstyle'), + (None, 'fontweight'), + (None, 'frame'), + (None, 'height'), + (None, 'linethickness'), + (None, 'lspace'), + (None, 'mathbackground'), + (None, 'mathcolor'), + (None, 'mathvariant'), + (None, 'mathvariant'), + (None, 'maxsize'), + (None, 'minsize'), + (None, 'other'), + (None, 'rowalign'), + (None, 'rowalign'), + (None, 'rowalign'), + (None, 'rowlines'), + (None, 'rowspacing'), + (None, 'rowspan'), + (None, 'rspace'), + (None, 'scriptlevel'), + (None, 'selection'), + (None, 'separator'), + (None, 'stretchy'), + (None, 'width'), + (None, 'width'), + (namespaces['xlink'], 'href'), + (namespaces['xlink'], 'show'), + (namespaces['xlink'], 'type'), + # SVG attributes + (None, 'accent-height'), + (None, 'accumulate'), + (None, 'additive'), + (None, 'alphabetic'), + (None, 'arabic-form'), + (None, 'ascent'), + (None, 'attributeName'), + (None, 'attributeType'), + (None, 'baseProfile'), + (None, 'bbox'), + (None, 'begin'), + (None, 'by'), + (None, 'calcMode'), + (None, 'cap-height'), + (None, 'class'), + (None, 'clip-path'), + (None, 'color'), + (None, 'color-rendering'), + (None, 'content'), + (None, 'cx'), + (None, 'cy'), + (None, 'd'), + (None, 'dx'), + (None, 'dy'), + (None, 'descent'), + (None, 'display'), + (None, 'dur'), + (None, 'end'), + (None, 'fill'), + (None, 'fill-opacity'), + (None, 'fill-rule'), + (None, 'font-family'), + (None, 'font-size'), + (None, 'font-stretch'), + (None, 'font-style'), + (None, 'font-variant'), + (None, 'font-weight'), + (None, 'from'), + (None, 'fx'), + (None, 'fy'), + (None, 'g1'), + (None, 'g2'), + (None, 'glyph-name'), + (None, 'gradientUnits'), + (None, 'hanging'), + (None, 'height'), + (None, 'horiz-adv-x'), + (None, 'horiz-origin-x'), + (None, 'id'), + (None, 'ideographic'), + (None, 'k'), + (None, 'keyPoints'), + (None, 'keySplines'), + (None, 'keyTimes'), + (None, 'lang'), + (None, 'marker-end'), + (None, 'marker-mid'), + (None, 'marker-start'), + (None, 'markerHeight'), + (None, 'markerUnits'), + (None, 'markerWidth'), + (None, 'mathematical'), + (None, 'max'), + (None, 'min'), + (None, 'name'), + (None, 'offset'), + (None, 'opacity'), + (None, 'orient'), + (None, 'origin'), + (None, 'overline-position'), + (None, 'overline-thickness'), + (None, 'panose-1'), + (None, 'path'), + (None, 'pathLength'), + (None, 'points'), + (None, 'preserveAspectRatio'), + (None, 'r'), + (None, 'refX'), + (None, 'refY'), + (None, 'repeatCount'), + (None, 'repeatDur'), + (None, 'requiredExtensions'), + (None, 'requiredFeatures'), + (None, 'restart'), + (None, 'rotate'), + (None, 'rx'), + (None, 'ry'), + (None, 'slope'), + (None, 'stemh'), + (None, 'stemv'), + (None, 'stop-color'), + (None, 'stop-opacity'), + (None, 'strikethrough-position'), + (None, 'strikethrough-thickness'), + (None, 'stroke'), + (None, 'stroke-dasharray'), + (None, 'stroke-dashoffset'), + (None, 'stroke-linecap'), + (None, 'stroke-linejoin'), + (None, 'stroke-miterlimit'), + (None, 'stroke-opacity'), + (None, 'stroke-width'), + (None, 'systemLanguage'), + (None, 'target'), + (None, 'text-anchor'), + (None, 'to'), + (None, 'transform'), + (None, 'type'), + (None, 'u1'), + (None, 'u2'), + (None, 'underline-position'), + (None, 'underline-thickness'), + (None, 'unicode'), + (None, 'unicode-range'), + (None, 'units-per-em'), + (None, 'values'), + (None, 'version'), + (None, 'viewBox'), + (None, 'visibility'), + (None, 'width'), + (None, 'widths'), + (None, 'x'), + (None, 'x-height'), + (None, 'x1'), + (None, 'x2'), + (namespaces['xlink'], 'actuate'), + (namespaces['xlink'], 'arcrole'), + (namespaces['xlink'], 'href'), + (namespaces['xlink'], 'role'), + (namespaces['xlink'], 'show'), + (namespaces['xlink'], 'title'), + (namespaces['xlink'], 'type'), + (namespaces['xml'], 'base'), + (namespaces['xml'], 'lang'), + (namespaces['xml'], 'space'), + (None, 'y'), + (None, 'y1'), + (None, 'y2'), + (None, 'zoomAndPan'), +)) + +attr_val_is_uri = frozenset(( + (None, 'href'), + (None, 'src'), + (None, 'cite'), + (None, 'action'), + (None, 'longdesc'), + (None, 'poster'), + (None, 'background'), + (None, 'datasrc'), + (None, 'dynsrc'), + (None, 'lowsrc'), + (None, 'ping'), + (namespaces['xlink'], 'href'), + (namespaces['xml'], 'base'), +)) + +svg_attr_val_allows_ref = frozenset(( + (None, 'clip-path'), + (None, 'color-profile'), + (None, 'cursor'), + (None, 'fill'), + (None, 'filter'), + (None, 'marker'), + (None, 'marker-start'), + (None, 'marker-mid'), + (None, 'marker-end'), + (None, 'mask'), + (None, 'stroke'), +)) + +svg_allow_local_href = frozenset(( + (None, 'altGlyph'), + (None, 'animate'), + (None, 'animateColor'), + (None, 'animateMotion'), + (None, 'animateTransform'), + (None, 'cursor'), + (None, 'feImage'), + (None, 'filter'), + (None, 'linearGradient'), + (None, 'pattern'), + (None, 'radialGradient'), + (None, 'textpath'), + (None, 'tref'), + (None, 'set'), + (None, 'use') +)) + +allowed_css_properties = frozenset(( + 'azimuth', + 'background-color', + 'border-bottom-color', + 'border-collapse', + 'border-color', + 'border-left-color', + 'border-right-color', + 'border-top-color', + 'clear', + 'color', + 'cursor', + 'direction', + 'display', + 'elevation', + 'float', + 'font', + 'font-family', + 'font-size', + 'font-style', + 'font-variant', + 'font-weight', + 'height', + 'letter-spacing', + 'line-height', + 'overflow', + 'pause', + 'pause-after', + 'pause-before', + 'pitch', + 'pitch-range', + 'richness', + 'speak', + 'speak-header', + 'speak-numeral', + 'speak-punctuation', + 'speech-rate', + 'stress', + 'text-align', + 'text-decoration', + 'text-indent', + 'unicode-bidi', + 'vertical-align', + 'voice-family', + 'volume', + 'white-space', + 'width', +)) + +allowed_css_keywords = frozenset(( + 'auto', + 'aqua', + 'black', + 'block', + 'blue', + 'bold', + 'both', + 'bottom', + 'brown', + 'center', + 'collapse', + 'dashed', + 'dotted', + 'fuchsia', + 'gray', + 'green', + '!important', + 'italic', + 'left', + 'lime', + 'maroon', + 'medium', + 'none', + 'navy', + 'normal', + 'nowrap', + 'olive', + 'pointer', + 'purple', + 'red', + 'right', + 'solid', + 'silver', + 'teal', + 'top', + 'transparent', + 'underline', + 'white', + 'yellow', +)) + +allowed_svg_properties = frozenset(( + 'fill', + 'fill-opacity', + 'fill-rule', + 'stroke', + 'stroke-width', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-opacity', +)) + +allowed_protocols = frozenset(( + 'ed2k', + 'ftp', + 'http', + 'https', + 'irc', + 'mailto', + 'news', + 'gopher', + 'nntp', + 'telnet', + 'webcal', + 'xmpp', + 'callto', + 'feed', + 'urn', + 'aim', + 'rsync', + 'tag', + 'ssh', + 'sftp', + 'rtsp', + 'afs', + 'data', +)) + +allowed_content_types = frozenset(( + 'image/png', + 'image/jpeg', + 'image/gif', + 'image/webp', + 'image/bmp', + 'text/plain', +)) + + +data_content_type = re.compile(r''' + ^ + # Match a content type <application>/<type> + (?P<content_type>[-a-zA-Z0-9.]+/[-a-zA-Z0-9.]+) + # Match any character set and encoding + (?:(?:;charset=(?:[-a-zA-Z0-9]+)(?:;(?:base64))?) + |(?:;(?:base64))?(?:;charset=(?:[-a-zA-Z0-9]+))?) + # Assume the rest is data + ,.* + $ + ''', + re.VERBOSE) + + +class Filter(base.Filter): + """Sanitizes token stream of XHTML+MathML+SVG and of inline style attributes""" + def __init__(self, + source, + allowed_elements=allowed_elements, + allowed_attributes=allowed_attributes, + allowed_css_properties=allowed_css_properties, + allowed_css_keywords=allowed_css_keywords, + allowed_svg_properties=allowed_svg_properties, + allowed_protocols=allowed_protocols, + allowed_content_types=allowed_content_types, + attr_val_is_uri=attr_val_is_uri, + svg_attr_val_allows_ref=svg_attr_val_allows_ref, + svg_allow_local_href=svg_allow_local_href): + """Creates a Filter + + :arg allowed_elements: set of elements to allow--everything else will + be escaped + + :arg allowed_attributes: set of attributes to allow in + elements--everything else will be stripped + + :arg allowed_css_properties: set of CSS properties to allow--everything + else will be stripped + + :arg allowed_css_keywords: set of CSS keywords to allow--everything + else will be stripped + + :arg allowed_svg_properties: set of SVG properties to allow--everything + else will be removed + + :arg allowed_protocols: set of allowed protocols for URIs + + :arg allowed_content_types: set of allowed content types for ``data`` URIs. + + :arg attr_val_is_uri: set of attributes that have URI values--values + that have a scheme not listed in ``allowed_protocols`` are removed + + :arg svg_attr_val_allows_ref: set of SVG attributes that can have + references + + :arg svg_allow_local_href: set of SVG elements that can have local + hrefs--these are removed + + """ + super(Filter, self).__init__(source) + self.allowed_elements = allowed_elements + self.allowed_attributes = allowed_attributes + self.allowed_css_properties = allowed_css_properties + self.allowed_css_keywords = allowed_css_keywords + self.allowed_svg_properties = allowed_svg_properties + self.allowed_protocols = allowed_protocols + self.allowed_content_types = allowed_content_types + self.attr_val_is_uri = attr_val_is_uri + self.svg_attr_val_allows_ref = svg_attr_val_allows_ref + self.svg_allow_local_href = svg_allow_local_href + + def __iter__(self): + for token in base.Filter.__iter__(self): + token = self.sanitize_token(token) + if token: + yield token + + # Sanitize the +html+, escaping all elements not in ALLOWED_ELEMENTS, and + # stripping out all attributes not in ALLOWED_ATTRIBUTES. Style attributes + # are parsed, and a restricted set, specified by ALLOWED_CSS_PROPERTIES and + # ALLOWED_CSS_KEYWORDS, are allowed through. attributes in ATTR_VAL_IS_URI + # are scanned, and only URI schemes specified in ALLOWED_PROTOCOLS are + # allowed. + # + # sanitize_html('<script> do_nasty_stuff() </script>') + # => <script> do_nasty_stuff() </script> + # sanitize_html('<a href="javascript: sucker();">Click here for $100</a>') + # => <a>Click here for $100</a> + def sanitize_token(self, token): + + # accommodate filters which use token_type differently + token_type = token["type"] + if token_type in ("StartTag", "EndTag", "EmptyTag"): + name = token["name"] + namespace = token["namespace"] + if ((namespace, name) in self.allowed_elements or + (namespace is None and + (namespaces["html"], name) in self.allowed_elements)): + return self.allowed_token(token) + else: + return self.disallowed_token(token) + elif token_type == "Comment": + pass + else: + return token + + def allowed_token(self, token): + if "data" in token: + attrs = token["data"] + attr_names = set(attrs.keys()) + + # Remove forbidden attributes + for to_remove in (attr_names - self.allowed_attributes): + del token["data"][to_remove] + attr_names.remove(to_remove) + + # Remove attributes with disallowed URL values + for attr in (attr_names & self.attr_val_is_uri): + assert attr in attrs + # I don't have a clue where this regexp comes from or why it matches those + # characters, nor why we call unescape. I just know it's always been here. + # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all + # this will do is remove *more* than it otherwise would. + val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\\s]+", '', + unescape(attrs[attr])).lower() + # remove replacement characters from unescaped characters + val_unescaped = val_unescaped.replace("\ufffd", "") + try: + uri = urlparse.urlparse(val_unescaped) + except ValueError: + uri = None + del attrs[attr] + if uri and uri.scheme: + if uri.scheme not in self.allowed_protocols: + del attrs[attr] + if uri.scheme == 'data': + m = data_content_type.match(uri.path) + if not m: + del attrs[attr] + elif m.group('content_type') not in self.allowed_content_types: + del attrs[attr] + + for attr in self.svg_attr_val_allows_ref: + if attr in attrs: + attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', + ' ', + unescape(attrs[attr])) + if (token["name"] in self.svg_allow_local_href and + (namespaces['xlink'], 'href') in attrs and re.search(r'^\s*[^#\s].*', + attrs[(namespaces['xlink'], 'href')])): + del attrs[(namespaces['xlink'], 'href')] + if (None, 'style') in attrs: + attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) + token["data"] = attrs + return token + + def disallowed_token(self, token): + token_type = token["type"] + if token_type == "EndTag": + token["data"] = "</%s>" % token["name"] + elif token["data"]: + assert token_type in ("StartTag", "EmptyTag") + attrs = [] + for (ns, name), v in token["data"].items(): + attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) + token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) + else: + token["data"] = "<%s>" % token["name"] + if token.get("selfClosing"): + token["data"] = token["data"][:-1] + "/>" + + token["type"] = "Characters" + + del token["name"] + return token + + def sanitize_css(self, style): + # disallow urls + style = re.compile(r'url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) + + # gauntlet + if not re.match(r"""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): + return '' + if not re.match(r"^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): + return '' + + clean = [] + for prop, value in re.findall(r"([-\w]+)\s*:\s*([^:;]*)", style): + if not value: + continue + if prop.lower() in self.allowed_css_properties: + clean.append(prop + ': ' + value + ';') + elif prop.split('-')[0].lower() in ['background', 'border', 'margin', + 'padding']: + for keyword in value.split(): + if keyword not in self.allowed_css_keywords and \ + not re.match(r"^(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa + break + else: + clean.append(prop + ': ' + value + ';') + elif prop.lower() in self.allowed_svg_properties: + clean.append(prop + ': ' + value + ';') + + return ' '.join(clean) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py new file mode 100755 index 0000000..24bb0de --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/filters/whitespace.py @@ -0,0 +1,38 @@ +from __future__ import absolute_import, division, unicode_literals + +import re + +from . import base +from ..constants import rcdataElements, spaceCharacters +spaceCharacters = "".join(spaceCharacters) + +SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) + + +class Filter(base.Filter): + """Collapses whitespace except in pre, textarea, and script elements""" + spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) + + def __iter__(self): + preserve = 0 + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag" \ + and (preserve or token["name"] in self.spacePreserveElements): + preserve += 1 + + elif type == "EndTag" and preserve: + preserve -= 1 + + elif not preserve and type == "SpaceCharacters" and token["data"]: + # Test on token["data"] above to not introduce spaces where there were not + token["data"] = " " + + elif not preserve and type == "Characters": + token["data"] = collapse_spaces(token["data"]) + + yield token + + +def collapse_spaces(text): + return SPACES_REGEX.sub(' ', text) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py new file mode 100755 index 0000000..b185971 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/html5parser.py @@ -0,0 +1,2791 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import with_metaclass, viewkeys + +import types +from collections import OrderedDict + +from . import _inputstream +from . import _tokenizer + +from . import treebuilders +from .treebuilders.base import Marker + +from . import _utils +from .constants import ( + spaceCharacters, asciiUpper2Lower, + specialElements, headingElements, cdataElements, rcdataElements, + tokenTypes, tagTokenTypes, + namespaces, + htmlIntegrationPointElements, mathmlTextIntegrationPointElements, + adjustForeignAttributes as adjustForeignAttributesMap, + adjustMathMLAttributes, adjustSVGAttributes, + E, + _ReparseException +) + + +def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML document as a string or file-like object into a tree + + :arg doc: the document to parse as a string or file-like object + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import parse + >>> parse('<html><body><p>This is a doc</p></body></html>') + <Element u'{http://www.w3.org/1999/xhtml}html' at 0x7feac4909db0> + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parse(doc, **kwargs) + + +def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML fragment as a string or file-like object into a tree + + :arg doc: the fragment to parse as a string or file-like object + + :arg container: the container context to parse the fragment in + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import parseFragment + >>> parseFragment('<b>this is a fragment</b>') + <Element u'DOCUMENT_FRAGMENT' at 0x7feac484b090> + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parseFragment(doc, container=container, **kwargs) + + +def method_decorator_metaclass(function): + class Decorated(type): + def __new__(meta, classname, bases, classDict): + for attributeName, attribute in classDict.items(): + if isinstance(attribute, types.FunctionType): + attribute = function(attribute) + + classDict[attributeName] = attribute + return type.__new__(meta, classname, bases, classDict) + return Decorated + + +class HTMLParser(object): + """HTML parser + + Generates a tree structure from a stream of (possibly malformed) HTML. + + """ + + def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): + """ + :arg tree: a treebuilder class controlling the type of tree that will be + returned. Built in treebuilders can be accessed through + html5lib.treebuilders.getTreeBuilder(treeType) + + :arg strict: raise an exception when a parse error is encountered + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :arg debug: whether or not to enable debug mode which logs things + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() # generates parser with etree builder + >>> parser = HTMLParser('lxml', strict=True) # generates parser with lxml builder which is strict + + """ + + # Raise an exception on the first error encountered + self.strict = strict + + if tree is None: + tree = treebuilders.getTreeBuilder("etree") + self.tree = tree(namespaceHTMLElements) + self.errors = [] + + self.phases = dict([(name, cls(self, self.tree)) for name, cls in + getPhases(debug).items()]) + + def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): + + self.innerHTMLMode = innerHTML + self.container = container + self.scripting = scripting + self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) + self.reset() + + try: + self.mainLoop() + except _ReparseException: + self.reset() + self.mainLoop() + + def reset(self): + self.tree.reset() + self.firstStartTag = False + self.errors = [] + self.log = [] # only used with debug mode + # "quirks" / "limited quirks" / "no quirks" + self.compatMode = "no quirks" + + if self.innerHTMLMode: + self.innerHTML = self.container.lower() + + if self.innerHTML in cdataElements: + self.tokenizer.state = self.tokenizer.rcdataState + elif self.innerHTML in rcdataElements: + self.tokenizer.state = self.tokenizer.rawtextState + elif self.innerHTML == 'plaintext': + self.tokenizer.state = self.tokenizer.plaintextState + else: + # state already is data state + # self.tokenizer.state = self.tokenizer.dataState + pass + self.phase = self.phases["beforeHtml"] + self.phase.insertHtmlElement() + self.resetInsertionMode() + else: + self.innerHTML = False # pylint:disable=redefined-variable-type + self.phase = self.phases["initial"] + + self.lastPhase = None + + self.beforeRCDataPhase = None + + self.framesetOK = True + + @property + def documentEncoding(self): + """Name of the character encoding that was used to decode the input stream, or + :obj:`None` if that is not determined yet + + """ + if not hasattr(self, 'tokenizer'): + return None + return self.tokenizer.stream.charEncoding[0].name + + def isHTMLIntegrationPoint(self, element): + if (element.name == "annotation-xml" and + element.namespace == namespaces["mathml"]): + return ("encoding" in element.attributes and + element.attributes["encoding"].translate( + asciiUpper2Lower) in + ("text/html", "application/xhtml+xml")) + else: + return (element.namespace, element.name) in htmlIntegrationPointElements + + def isMathMLTextIntegrationPoint(self, element): + return (element.namespace, element.name) in mathmlTextIntegrationPointElements + + def mainLoop(self): + CharactersToken = tokenTypes["Characters"] + SpaceCharactersToken = tokenTypes["SpaceCharacters"] + StartTagToken = tokenTypes["StartTag"] + EndTagToken = tokenTypes["EndTag"] + CommentToken = tokenTypes["Comment"] + DoctypeToken = tokenTypes["Doctype"] + ParseErrorToken = tokenTypes["ParseError"] + + for token in self.normalizedTokens(): + prev_token = None + new_token = token + while new_token is not None: + prev_token = new_token + currentNode = self.tree.openElements[-1] if self.tree.openElements else None + currentNodeNamespace = currentNode.namespace if currentNode else None + currentNodeName = currentNode.name if currentNode else None + + type = new_token["type"] + + if type == ParseErrorToken: + self.parseError(new_token["data"], new_token.get("datavars", {})) + new_token = None + else: + if (len(self.tree.openElements) == 0 or + currentNodeNamespace == self.tree.defaultNamespace or + (self.isMathMLTextIntegrationPoint(currentNode) and + ((type == StartTagToken and + token["name"] not in frozenset(["mglyph", "malignmark"])) or + type in (CharactersToken, SpaceCharactersToken))) or + (currentNodeNamespace == namespaces["mathml"] and + currentNodeName == "annotation-xml" and + type == StartTagToken and + token["name"] == "svg") or + (self.isHTMLIntegrationPoint(currentNode) and + type in (StartTagToken, CharactersToken, SpaceCharactersToken))): + phase = self.phase + else: + phase = self.phases["inForeignContent"] + + if type == CharactersToken: + new_token = phase.processCharacters(new_token) + elif type == SpaceCharactersToken: + new_token = phase.processSpaceCharacters(new_token) + elif type == StartTagToken: + new_token = phase.processStartTag(new_token) + elif type == EndTagToken: + new_token = phase.processEndTag(new_token) + elif type == CommentToken: + new_token = phase.processComment(new_token) + elif type == DoctypeToken: + new_token = phase.processDoctype(new_token) + + if (type == StartTagToken and prev_token["selfClosing"] and + not prev_token["selfClosingAcknowledged"]): + self.parseError("non-void-element-with-trailing-solidus", + {"name": prev_token["name"]}) + + # When the loop finishes it's EOF + reprocess = True + phases = [] + while reprocess: + phases.append(self.phase) + reprocess = self.phase.processEOF() + if reprocess: + assert self.phase not in phases + + def normalizedTokens(self): + for token in self.tokenizer: + yield self.normalizeToken(token) + + def parse(self, stream, *args, **kwargs): + """Parse a HTML document into a well-formed tree + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element). + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parse('<html><body><p>This is a doc</p></body></html>') + <Element u'{http://www.w3.org/1999/xhtml}html' at 0x7feac4909db0> + + """ + self._parse(stream, False, None, *args, **kwargs) + return self.tree.getDocument() + + def parseFragment(self, stream, *args, **kwargs): + """Parse a HTML fragment into a well-formed tree fragment + + :arg container: name of the element we're setting the innerHTML + property if set to None, default to 'div' + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parseFragment('<b>this is a fragment</b>') + <Element u'DOCUMENT_FRAGMENT' at 0x7feac484b090> + + """ + self._parse(stream, True, *args, **kwargs) + return self.tree.getFragment() + + def parseError(self, errorcode="XXX-undefined-error", datavars=None): + # XXX The idea is to make errorcode mandatory. + if datavars is None: + datavars = {} + self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) + if self.strict: + raise ParseError(E[errorcode] % datavars) + + def normalizeToken(self, token): + # HTML5 specific normalizations to the token stream + if token["type"] == tokenTypes["StartTag"]: + raw = token["data"] + token["data"] = OrderedDict(raw) + if len(raw) > len(token["data"]): + # we had some duplicated attribute, fix so first wins + token["data"].update(raw[::-1]) + + return token + + def adjustMathMLAttributes(self, token): + adjust_attributes(token, adjustMathMLAttributes) + + def adjustSVGAttributes(self, token): + adjust_attributes(token, adjustSVGAttributes) + + def adjustForeignAttributes(self, token): + adjust_attributes(token, adjustForeignAttributesMap) + + def reparseTokenNormal(self, token): + # pylint:disable=unused-argument + self.parser.phase() + + def resetInsertionMode(self): + # The name of this method is mostly historical. (It's also used in the + # specification.) + last = False + newModes = { + "select": "inSelect", + "td": "inCell", + "th": "inCell", + "tr": "inRow", + "tbody": "inTableBody", + "thead": "inTableBody", + "tfoot": "inTableBody", + "caption": "inCaption", + "colgroup": "inColumnGroup", + "table": "inTable", + "head": "inBody", + "body": "inBody", + "frameset": "inFrameset", + "html": "beforeHead" + } + for node in self.tree.openElements[::-1]: + nodeName = node.name + new_phase = None + if node == self.tree.openElements[0]: + assert self.innerHTML + last = True + nodeName = self.innerHTML + # Check for conditions that should only happen in the innerHTML + # case + if nodeName in ("select", "colgroup", "head", "html"): + assert self.innerHTML + + if not last and node.namespace != self.tree.defaultNamespace: + continue + + if nodeName in newModes: + new_phase = self.phases[newModes[nodeName]] + break + elif last: + new_phase = self.phases["inBody"] + break + + self.phase = new_phase + + def parseRCDataRawtext(self, token, contentType): + # Generic RCDATA/RAWTEXT Parsing algorithm + assert contentType in ("RAWTEXT", "RCDATA") + + self.tree.insertElement(token) + + if contentType == "RAWTEXT": + self.tokenizer.state = self.tokenizer.rawtextState + else: + self.tokenizer.state = self.tokenizer.rcdataState + + self.originalPhase = self.phase + + self.phase = self.phases["text"] + + +@_utils.memoize +def getPhases(debug): + def log(function): + """Logger that records which phase processes each token""" + type_names = dict((value, key) for key, value in + tokenTypes.items()) + + def wrapped(self, *args, **kwargs): + if function.__name__.startswith("process") and len(args) > 0: + token = args[0] + try: + info = {"type": type_names[token['type']]} + except: + raise + if token['type'] in tagTokenTypes: + info["name"] = token['name'] + + self.parser.log.append((self.parser.tokenizer.state.__name__, + self.parser.phase.__class__.__name__, + self.__class__.__name__, + function.__name__, + info)) + return function(self, *args, **kwargs) + else: + return function(self, *args, **kwargs) + return wrapped + + def getMetaclass(use_metaclass, metaclass_func): + if use_metaclass: + return method_decorator_metaclass(metaclass_func) + else: + return type + + # pylint:disable=unused-argument + class Phase(with_metaclass(getMetaclass(debug, log))): + """Base class for helper object that implements each phase of processing + """ + + def __init__(self, parser, tree): + self.parser = parser + self.tree = tree + + def processEOF(self): + raise NotImplementedError + + def processComment(self, token): + # For most phases the following is correct. Where it's not it will be + # overridden. + self.tree.insertComment(token, self.tree.openElements[-1]) + + def processDoctype(self, token): + self.parser.parseError("unexpected-doctype") + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processSpaceCharacters(self, token): + self.tree.insertText(token["data"]) + + def processStartTag(self, token): + return self.startTagHandler[token["name"]](token) + + def startTagHtml(self, token): + if not self.parser.firstStartTag and token["name"] == "html": + self.parser.parseError("non-html-root") + # XXX Need a check here to see if the first start tag token emitted is + # this token... If it's not, invoke self.parser.parseError(). + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[0].attributes: + self.tree.openElements[0].attributes[attr] = value + self.parser.firstStartTag = False + + def processEndTag(self, token): + return self.endTagHandler[token["name"]](token) + + class InitialPhase(Phase): + def processSpaceCharacters(self, token): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + correct = token["correct"] + + if (name != "html" or publicId is not None or + systemId is not None and systemId != "about:legacy-compat"): + self.parser.parseError("unknown-doctype") + + if publicId is None: + publicId = "" + + self.tree.insertDoctype(token) + + if publicId != "": + publicId = publicId.translate(asciiUpper2Lower) + + if (not correct or token["name"] != "html" or + publicId.startswith( + ("+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//")) or + publicId in ("-//w3o//dtd w3 html strict 3.0//en//", + "-/w3c/dtd html 4.0 transitional/en", + "html") or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is None or + systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): + self.parser.compatMode = "quirks" + elif (publicId.startswith( + ("-//w3c//dtd xhtml 1.0 frameset//", + "-//w3c//dtd xhtml 1.0 transitional//")) or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is not None): + self.parser.compatMode = "limited quirks" + + self.parser.phase = self.parser.phases["beforeHtml"] + + def anythingElse(self): + self.parser.compatMode = "quirks" + self.parser.phase = self.parser.phases["beforeHtml"] + + def processCharacters(self, token): + self.parser.parseError("expected-doctype-but-got-chars") + self.anythingElse() + return token + + def processStartTag(self, token): + self.parser.parseError("expected-doctype-but-got-start-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEndTag(self, token): + self.parser.parseError("expected-doctype-but-got-end-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEOF(self): + self.parser.parseError("expected-doctype-but-got-eof") + self.anythingElse() + return True + + class BeforeHtmlPhase(Phase): + # helper methods + def insertHtmlElement(self): + self.tree.insertRoot(impliedTagToken("html", "StartTag")) + self.parser.phase = self.parser.phases["beforeHead"] + + # other + def processEOF(self): + self.insertHtmlElement() + return True + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.insertHtmlElement() + return token + + def processStartTag(self, token): + if token["name"] == "html": + self.parser.firstStartTag = True + self.insertHtmlElement() + return token + + def processEndTag(self, token): + if token["name"] not in ("head", "body", "html", "br"): + self.parser.parseError("unexpected-end-tag-before-html", + {"name": token["name"]}) + else: + self.insertHtmlElement() + return token + + class BeforeHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("head", "body", "html", "br"), self.endTagImplyHead) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.startTagHead(impliedTagToken("head", "StartTag")) + return True + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.tree.insertElement(token) + self.tree.headPointer = self.tree.openElements[-1] + self.parser.phase = self.parser.phases["inHead"] + + def startTagOther(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagImplyHead(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagOther(self, token): + self.parser.parseError("end-tag-after-implied-root", + {"name": token["name"]}) + + class InHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("title", self.startTagTitle), + (("noframes", "style"), self.startTagNoFramesStyle), + ("noscript", self.startTagNoscript), + ("script", self.startTagScript), + (("base", "basefont", "bgsound", "command", "link"), + self.startTagBaseLinkCommand), + ("meta", self.startTagMeta), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("head", self.endTagHead), + (("br", "html", "body"), self.endTagHtmlBodyBr) + ]) + self.endTagHandler.default = self.endTagOther + + # the real thing + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.parser.parseError("two-heads-are-not-better-than-one") + + def startTagBaseLinkCommand(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMeta(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + attributes = token["data"] + if self.parser.tokenizer.stream.charEncoding[1] == "tentative": + if "charset" in attributes: + self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) + elif ("content" in attributes and + "http-equiv" in attributes and + attributes["http-equiv"].lower() == "content-type"): + # Encoding it as UTF-8 here is a hack, as really we should pass + # the abstract Unicode string, and just use the + # ContentAttrParser on that, but using UTF-8 allows all chars + # to be encoded and as a ASCII-superset works. + data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) + parser = _inputstream.ContentAttrParser(data) + codec = parser.parse() + self.parser.tokenizer.stream.changeEncoding(codec) + + def startTagTitle(self, token): + self.parser.parseRCDataRawtext(token, "RCDATA") + + def startTagNoFramesStyle(self, token): + # Need to decide whether to implement the scripting-disabled case + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagNoscript(self, token): + if self.parser.scripting: + self.parser.parseRCDataRawtext(token, "RAWTEXT") + else: + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inHeadNoscript"] + + def startTagScript(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState + self.parser.originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["text"] + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHead(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "head", "Expected head got %s" % node.name + self.parser.phase = self.parser.phases["afterHead"] + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.endTagHead(impliedTagToken("head")) + + class InHeadNoscriptPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("basefont", "bgsound", "link", "meta", "noframes", "style"), self.startTagBaseLinkCommand), + (("head", "noscript"), self.startTagHeadNoscript), + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("noscript", self.endTagNoscript), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.parser.parseError("eof-in-head-noscript") + self.anythingElse() + return True + + def processComment(self, token): + return self.parser.phases["inHead"].processComment(token) + + def processCharacters(self, token): + self.parser.parseError("char-in-head-noscript") + self.anythingElse() + return token + + def processSpaceCharacters(self, token): + return self.parser.phases["inHead"].processSpaceCharacters(token) + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBaseLinkCommand(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagHeadNoscript(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagNoscript(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "noscript", "Expected noscript got %s" % node.name + self.parser.phase = self.parser.phases["inHead"] + + def endTagBr(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + # Caller must raise parse error first! + self.endTagNoscript(impliedTagToken("noscript")) + + class AfterHeadPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", + "style", "title"), + self.startTagFromHead), + ("head", self.startTagHead) + ]) + self.startTagHandler.default = self.startTagOther + self.endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), + self.endTagHtmlBodyBr)]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBody(self, token): + self.parser.framesetOK = False + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inBody"] + + def startTagFrameset(self, token): + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagFromHead(self, token): + self.parser.parseError("unexpected-start-tag-out-of-my-head", + {"name": token["name"]}) + self.tree.openElements.append(self.tree.headPointer) + self.parser.phases["inHead"].processStartTag(token) + for node in self.tree.openElements[::-1]: + if node.name == "head": + self.tree.openElements.remove(node) + break + + def startTagHead(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.tree.insertElement(impliedTagToken("body", "StartTag")) + self.parser.phase = self.parser.phases["inBody"] + self.parser.framesetOK = True + + class InBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody + # the really-really-really-very crazy mode + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + # Set this to the default handler + self.processSpaceCharacters = self.processSpaceCharactersNonPre + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("base", "basefont", "bgsound", "command", "link", "meta", + "script", "style", "title"), + self.startTagProcessInHead), + ("body", self.startTagBody), + ("frameset", self.startTagFrameset), + (("address", "article", "aside", "blockquote", "center", "details", + "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p", + "section", "summary", "ul"), + self.startTagCloseP), + (headingElements, self.startTagHeading), + (("pre", "listing"), self.startTagPreListing), + ("form", self.startTagForm), + (("li", "dd", "dt"), self.startTagListItem), + ("plaintext", self.startTagPlaintext), + ("a", self.startTagA), + (("b", "big", "code", "em", "font", "i", "s", "small", "strike", + "strong", "tt", "u"), self.startTagFormatting), + ("nobr", self.startTagNobr), + ("button", self.startTagButton), + (("applet", "marquee", "object"), self.startTagAppletMarqueeObject), + ("xmp", self.startTagXmp), + ("table", self.startTagTable), + (("area", "br", "embed", "img", "keygen", "wbr"), + self.startTagVoidFormatting), + (("param", "source", "track"), self.startTagParamSource), + ("input", self.startTagInput), + ("hr", self.startTagHr), + ("image", self.startTagImage), + ("isindex", self.startTagIsIndex), + ("textarea", self.startTagTextarea), + ("iframe", self.startTagIFrame), + ("noscript", self.startTagNoscript), + (("noembed", "noframes"), self.startTagRawtext), + ("select", self.startTagSelect), + (("rp", "rt"), self.startTagRpRt), + (("option", "optgroup"), self.startTagOpt), + (("math"), self.startTagMath), + (("svg"), self.startTagSvg), + (("caption", "col", "colgroup", "frame", "head", + "tbody", "td", "tfoot", "th", "thead", + "tr"), self.startTagMisplaced) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("body", self.endTagBody), + ("html", self.endTagHtml), + (("address", "article", "aside", "blockquote", "button", "center", + "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", + "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre", + "section", "summary", "ul"), self.endTagBlock), + ("form", self.endTagForm), + ("p", self.endTagP), + (("dd", "dt", "li"), self.endTagListItem), + (headingElements, self.endTagHeading), + (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", + "strike", "strong", "tt", "u"), self.endTagFormatting), + (("applet", "marquee", "object"), self.endTagAppletMarqueeObject), + ("br", self.endTagBr), + ]) + self.endTagHandler.default = self.endTagOther + + def isMatchingFormattingElement(self, node1, node2): + return (node1.name == node2.name and + node1.namespace == node2.namespace and + node1.attributes == node2.attributes) + + # helper + def addFormattingElement(self, token): + self.tree.insertElement(token) + element = self.tree.openElements[-1] + + matchingElements = [] + for node in self.tree.activeFormattingElements[::-1]: + if node is Marker: + break + elif self.isMatchingFormattingElement(node, element): + matchingElements.append(node) + + assert len(matchingElements) <= 3 + if len(matchingElements) == 3: + self.tree.activeFormattingElements.remove(matchingElements[-1]) + self.tree.activeFormattingElements.append(element) + + # the real deal + def processEOF(self): + allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", + "tfoot", "th", "thead", "tr", "body", + "html")) + for node in self.tree.openElements[::-1]: + if node.name not in allowed_elements: + self.parser.parseError("expected-closing-tag-but-got-eof") + break + # Stop parsing + + def processSpaceCharactersDropNewline(self, token): + # Sometimes (start of <pre>, <listing>, and <textarea> blocks) we + # want to drop leading newlines + data = token["data"] + self.processSpaceCharacters = self.processSpaceCharactersNonPre + if (data.startswith("\n") and + self.tree.openElements[-1].name in ("pre", "listing", "textarea") and + not self.tree.openElements[-1].hasContent()): + data = data[1:] + if data: + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(data) + + def processCharacters(self, token): + if token["data"] == "\u0000": + # The tokenizer should always emit null on its own + return + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(token["data"]) + # This must be bad for performance + if (self.parser.framesetOK and + any([char not in spaceCharacters + for char in token["data"]])): + self.parser.framesetOK = False + + def processSpaceCharactersNonPre(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertText(token["data"]) + + def startTagProcessInHead(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagBody(self, token): + self.parser.parseError("unexpected-start-tag", {"name": "body"}) + if (len(self.tree.openElements) == 1 or + self.tree.openElements[1].name != "body"): + assert self.parser.innerHTML + else: + self.parser.framesetOK = False + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[1].attributes: + self.tree.openElements[1].attributes[attr] = value + + def startTagFrameset(self, token): + self.parser.parseError("unexpected-start-tag", {"name": "frameset"}) + if (len(self.tree.openElements) == 1 or self.tree.openElements[1].name != "body"): + assert self.parser.innerHTML + elif not self.parser.framesetOK: + pass + else: + if self.tree.openElements[1].parent: + self.tree.openElements[1].parent.removeChild(self.tree.openElements[1]) + while self.tree.openElements[-1].name != "html": + self.tree.openElements.pop() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagCloseP(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + + def startTagPreListing(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.framesetOK = False + self.processSpaceCharacters = self.processSpaceCharactersDropNewline + + def startTagForm(self, token): + if self.tree.formPointer: + self.parser.parseError("unexpected-start-tag", {"name": "form"}) + else: + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.tree.formPointer = self.tree.openElements[-1] + + def startTagListItem(self, token): + self.parser.framesetOK = False + + stopNamesMap = {"li": ["li"], + "dt": ["dt", "dd"], + "dd": ["dt", "dd"]} + stopNames = stopNamesMap[token["name"]] + for node in reversed(self.tree.openElements): + if node.name in stopNames: + self.parser.phase.processEndTag( + impliedTagToken(node.name, "EndTag")) + break + if (node.nameTuple in specialElements and + node.name not in ("address", "div", "p")): + break + + if self.tree.elementInScope("p", variant="button"): + self.parser.phase.processEndTag( + impliedTagToken("p", "EndTag")) + + self.tree.insertElement(token) + + def startTagPlaintext(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.plaintextState + + def startTagHeading(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + if self.tree.openElements[-1].name in headingElements: + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagA(self, token): + afeAElement = self.tree.elementInActiveFormattingElements("a") + if afeAElement: + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "a", "endName": "a"}) + self.endTagFormatting(impliedTagToken("a")) + if afeAElement in self.tree.openElements: + self.tree.openElements.remove(afeAElement) + if afeAElement in self.tree.activeFormattingElements: + self.tree.activeFormattingElements.remove(afeAElement) + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagFormatting(self, token): + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagNobr(self, token): + self.tree.reconstructActiveFormattingElements() + if self.tree.elementInScope("nobr"): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "nobr", "endName": "nobr"}) + self.processEndTag(impliedTagToken("nobr")) + # XXX Need tests that trigger the following + self.tree.reconstructActiveFormattingElements() + self.addFormattingElement(token) + + def startTagButton(self, token): + if self.tree.elementInScope("button"): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "button", "endName": "button"}) + self.processEndTag(impliedTagToken("button")) + return token + else: + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.parser.framesetOK = False + + def startTagAppletMarqueeObject(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.tree.activeFormattingElements.append(Marker) + self.parser.framesetOK = False + + def startTagXmp(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.reconstructActiveFormattingElements() + self.parser.framesetOK = False + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagTable(self, token): + if self.parser.compatMode != "quirks": + if self.tree.elementInScope("p", variant="button"): + self.processEndTag(impliedTagToken("p")) + self.tree.insertElement(token) + self.parser.framesetOK = False + self.parser.phase = self.parser.phases["inTable"] + + def startTagVoidFormatting(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + self.parser.framesetOK = False + + def startTagInput(self, token): + framesetOK = self.parser.framesetOK + self.startTagVoidFormatting(token) + if ("type" in token["data"] and + token["data"]["type"].translate(asciiUpper2Lower) == "hidden"): + # input type=hidden doesn't change framesetOK + self.parser.framesetOK = framesetOK + + def startTagParamSource(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagHr(self, token): + if self.tree.elementInScope("p", variant="button"): + self.endTagP(impliedTagToken("p")) + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + self.parser.framesetOK = False + + def startTagImage(self, token): + # No really... + self.parser.parseError("unexpected-start-tag-treated-as", + {"originalName": "image", "newName": "img"}) + self.processStartTag(impliedTagToken("img", "StartTag", + attributes=token["data"], + selfClosing=token["selfClosing"])) + + def startTagIsIndex(self, token): + self.parser.parseError("deprecated-tag", {"name": "isindex"}) + if self.tree.formPointer: + return + form_attrs = {} + if "action" in token["data"]: + form_attrs["action"] = token["data"]["action"] + self.processStartTag(impliedTagToken("form", "StartTag", + attributes=form_attrs)) + self.processStartTag(impliedTagToken("hr", "StartTag")) + self.processStartTag(impliedTagToken("label", "StartTag")) + # XXX Localization ... + if "prompt" in token["data"]: + prompt = token["data"]["prompt"] + else: + prompt = "This is a searchable index. Enter search keywords: " + self.processCharacters( + {"type": tokenTypes["Characters"], "data": prompt}) + attributes = token["data"].copy() + if "action" in attributes: + del attributes["action"] + if "prompt" in attributes: + del attributes["prompt"] + attributes["name"] = "isindex" + self.processStartTag(impliedTagToken("input", "StartTag", + attributes=attributes, + selfClosing=token["selfClosing"])) + self.processEndTag(impliedTagToken("label")) + self.processStartTag(impliedTagToken("hr", "StartTag")) + self.processEndTag(impliedTagToken("form")) + + def startTagTextarea(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.rcdataState + self.processSpaceCharacters = self.processSpaceCharactersDropNewline + self.parser.framesetOK = False + + def startTagIFrame(self, token): + self.parser.framesetOK = False + self.startTagRawtext(token) + + def startTagNoscript(self, token): + if self.parser.scripting: + self.startTagRawtext(token) + else: + self.startTagOther(token) + + def startTagRawtext(self, token): + """iframe, noembed noframes, noscript(if scripting enabled)""" + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagOpt(self, token): + if self.tree.openElements[-1].name == "option": + self.parser.phase.processEndTag(impliedTagToken("option")) + self.tree.reconstructActiveFormattingElements() + self.parser.tree.insertElement(token) + + def startTagSelect(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + self.parser.framesetOK = False + if self.parser.phase in (self.parser.phases["inTable"], + self.parser.phases["inCaption"], + self.parser.phases["inColumnGroup"], + self.parser.phases["inTableBody"], + self.parser.phases["inRow"], + self.parser.phases["inCell"]): + self.parser.phase = self.parser.phases["inSelectInTable"] + else: + self.parser.phase = self.parser.phases["inSelect"] + + def startTagRpRt(self, token): + if self.tree.elementInScope("ruby"): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "ruby": + self.parser.parseError() + self.tree.insertElement(token) + + def startTagMath(self, token): + self.tree.reconstructActiveFormattingElements() + self.parser.adjustMathMLAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = namespaces["mathml"] + self.tree.insertElement(token) + # Need to get the parse error right for the case where the token + # has a namespace not equal to the xmlns attribute + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagSvg(self, token): + self.tree.reconstructActiveFormattingElements() + self.parser.adjustSVGAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = namespaces["svg"] + self.tree.insertElement(token) + # Need to get the parse error right for the case where the token + # has a namespace not equal to the xmlns attribute + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMisplaced(self, token): + """ Elements that should be children of other elements that have a + different insertion mode; here they are ignored + "caption", "col", "colgroup", "frame", "frameset", "head", + "option", "optgroup", "tbody", "td", "tfoot", "th", "thead", + "tr", "noscript" + """ + self.parser.parseError("unexpected-start-tag-ignored", {"name": token["name"]}) + + def startTagOther(self, token): + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(token) + + def endTagP(self, token): + if not self.tree.elementInScope("p", variant="button"): + self.startTagCloseP(impliedTagToken("p", "StartTag")) + self.parser.parseError("unexpected-end-tag", {"name": "p"}) + self.endTagP(impliedTagToken("p", "EndTag")) + else: + self.tree.generateImpliedEndTags("p") + if self.tree.openElements[-1].name != "p": + self.parser.parseError("unexpected-end-tag", {"name": "p"}) + node = self.tree.openElements.pop() + while node.name != "p": + node = self.tree.openElements.pop() + + def endTagBody(self, token): + if not self.tree.elementInScope("body"): + self.parser.parseError() + return + elif self.tree.openElements[-1].name != "body": + for node in self.tree.openElements[2:]: + if node.name not in frozenset(("dd", "dt", "li", "optgroup", + "option", "p", "rp", "rt", + "tbody", "td", "tfoot", + "th", "thead", "tr", "body", + "html")): + # Not sure this is the correct name for the parse error + self.parser.parseError( + "expected-one-end-tag-but-got-another", + {"gotName": "body", "expectedName": node.name}) + break + self.parser.phase = self.parser.phases["afterBody"] + + def endTagHtml(self, token): + # We repeat the test for the body end tag token being ignored here + if self.tree.elementInScope("body"): + self.endTagBody(impliedTagToken("body")) + return token + + def endTagBlock(self, token): + # Put us back in the right whitespace handling mode + if token["name"] == "pre": + self.processSpaceCharacters = self.processSpaceCharactersNonPre + inScope = self.tree.elementInScope(token["name"]) + if inScope: + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + if inScope: + node = self.tree.openElements.pop() + while node.name != token["name"]: + node = self.tree.openElements.pop() + + def endTagForm(self, token): + node = self.tree.formPointer + self.tree.formPointer = None + if node is None or not self.tree.elementInScope(node): + self.parser.parseError("unexpected-end-tag", + {"name": "form"}) + else: + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1] != node: + self.parser.parseError("end-tag-too-early-ignored", + {"name": "form"}) + self.tree.openElements.remove(node) + + def endTagListItem(self, token): + if token["name"] == "li": + variant = "list" + else: + variant = None + if not self.tree.elementInScope(token["name"], variant=variant): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + else: + self.tree.generateImpliedEndTags(exclude=token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError( + "end-tag-too-early", + {"name": token["name"]}) + node = self.tree.openElements.pop() + while node.name != token["name"]: + node = self.tree.openElements.pop() + + def endTagHeading(self, token): + for item in headingElements: + if self.tree.elementInScope(item): + self.tree.generateImpliedEndTags() + break + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + + for item in headingElements: + if self.tree.elementInScope(item): + item = self.tree.openElements.pop() + while item.name not in headingElements: + item = self.tree.openElements.pop() + break + + def endTagFormatting(self, token): + """The much-feared adoption agency algorithm""" + # http://svn.whatwg.org/webapps/complete.html#adoptionAgency revision 7867 + # XXX Better parseError messages appreciated. + + # Step 1 + outerLoopCounter = 0 + + # Step 2 + while outerLoopCounter < 8: + + # Step 3 + outerLoopCounter += 1 + + # Step 4: + + # Let the formatting element be the last element in + # the list of active formatting elements that: + # - is between the end of the list and the last scope + # marker in the list, if any, or the start of the list + # otherwise, and + # - has the same tag name as the token. + formattingElement = self.tree.elementInActiveFormattingElements( + token["name"]) + if (not formattingElement or + (formattingElement in self.tree.openElements and + not self.tree.elementInScope(formattingElement.name))): + # If there is no such node, then abort these steps + # and instead act as described in the "any other + # end tag" entry below. + self.endTagOther(token) + return + + # Otherwise, if there is such a node, but that node is + # not in the stack of open elements, then this is a + # parse error; remove the element from the list, and + # abort these steps. + elif formattingElement not in self.tree.openElements: + self.parser.parseError("adoption-agency-1.2", {"name": token["name"]}) + self.tree.activeFormattingElements.remove(formattingElement) + return + + # Otherwise, if there is such a node, and that node is + # also in the stack of open elements, but the element + # is not in scope, then this is a parse error; ignore + # the token, and abort these steps. + elif not self.tree.elementInScope(formattingElement.name): + self.parser.parseError("adoption-agency-4.4", {"name": token["name"]}) + return + + # Otherwise, there is a formatting element and that + # element is in the stack and is in scope. If the + # element is not the current node, this is a parse + # error. In any case, proceed with the algorithm as + # written in the following steps. + else: + if formattingElement != self.tree.openElements[-1]: + self.parser.parseError("adoption-agency-1.3", {"name": token["name"]}) + + # Step 5: + + # Let the furthest block be the topmost node in the + # stack of open elements that is lower in the stack + # than the formatting element, and is an element in + # the special category. There might not be one. + afeIndex = self.tree.openElements.index(formattingElement) + furthestBlock = None + for element in self.tree.openElements[afeIndex:]: + if element.nameTuple in specialElements: + furthestBlock = element + break + + # Step 6: + + # If there is no furthest block, then the UA must + # first pop all the nodes from the bottom of the stack + # of open elements, from the current node up to and + # including the formatting element, then remove the + # formatting element from the list of active + # formatting elements, and finally abort these steps. + if furthestBlock is None: + element = self.tree.openElements.pop() + while element != formattingElement: + element = self.tree.openElements.pop() + self.tree.activeFormattingElements.remove(element) + return + + # Step 7 + commonAncestor = self.tree.openElements[afeIndex - 1] + + # Step 8: + # The bookmark is supposed to help us identify where to reinsert + # nodes in step 15. We have to ensure that we reinsert nodes after + # the node before the active formatting element. Note the bookmark + # can move in step 9.7 + bookmark = self.tree.activeFormattingElements.index(formattingElement) + + # Step 9 + lastNode = node = furthestBlock + innerLoopCounter = 0 + + index = self.tree.openElements.index(node) + while innerLoopCounter < 3: + innerLoopCounter += 1 + # Node is element before node in open elements + index -= 1 + node = self.tree.openElements[index] + if node not in self.tree.activeFormattingElements: + self.tree.openElements.remove(node) + continue + # Step 9.6 + if node == formattingElement: + break + # Step 9.7 + if lastNode == furthestBlock: + bookmark = self.tree.activeFormattingElements.index(node) + 1 + # Step 9.8 + clone = node.cloneNode() + # Replace node with clone + self.tree.activeFormattingElements[ + self.tree.activeFormattingElements.index(node)] = clone + self.tree.openElements[ + self.tree.openElements.index(node)] = clone + node = clone + # Step 9.9 + # Remove lastNode from its parents, if any + if lastNode.parent: + lastNode.parent.removeChild(lastNode) + node.appendChild(lastNode) + # Step 9.10 + lastNode = node + + # Step 10 + # Foster parent lastNode if commonAncestor is a + # table, tbody, tfoot, thead, or tr we need to foster + # parent the lastNode + if lastNode.parent: + lastNode.parent.removeChild(lastNode) + + if commonAncestor.name in frozenset(("table", "tbody", "tfoot", "thead", "tr")): + parent, insertBefore = self.tree.getTableMisnestedNodePosition() + parent.insertBefore(lastNode, insertBefore) + else: + commonAncestor.appendChild(lastNode) + + # Step 11 + clone = formattingElement.cloneNode() + + # Step 12 + furthestBlock.reparentChildren(clone) + + # Step 13 + furthestBlock.appendChild(clone) + + # Step 14 + self.tree.activeFormattingElements.remove(formattingElement) + self.tree.activeFormattingElements.insert(bookmark, clone) + + # Step 15 + self.tree.openElements.remove(formattingElement) + self.tree.openElements.insert( + self.tree.openElements.index(furthestBlock) + 1, clone) + + def endTagAppletMarqueeObject(self, token): + if self.tree.elementInScope(token["name"]): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("end-tag-too-early", {"name": token["name"]}) + + if self.tree.elementInScope(token["name"]): + element = self.tree.openElements.pop() + while element.name != token["name"]: + element = self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + + def endTagBr(self, token): + self.parser.parseError("unexpected-end-tag-treated-as", + {"originalName": "br", "newName": "br element"}) + self.tree.reconstructActiveFormattingElements() + self.tree.insertElement(impliedTagToken("br", "StartTag")) + self.tree.openElements.pop() + + def endTagOther(self, token): + for node in self.tree.openElements[::-1]: + if node.name == token["name"]: + self.tree.generateImpliedEndTags(exclude=token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + while self.tree.openElements.pop() != node: + pass + break + else: + if node.nameTuple in specialElements: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + break + + class TextPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([]) + self.startTagHandler.default = self.startTagOther + self.endTagHandler = _utils.MethodDispatcher([ + ("script", self.endTagScript)]) + self.endTagHandler.default = self.endTagOther + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processEOF(self): + self.parser.parseError("expected-named-closing-tag-but-got-eof", + {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + self.parser.phase = self.parser.originalPhase + return True + + def startTagOther(self, token): + assert False, "Tried to process start tag %s in RCDATA/RAWTEXT mode" % token['name'] + + def endTagScript(self, token): + node = self.tree.openElements.pop() + assert node.name == "script" + self.parser.phase = self.parser.originalPhase + # The rest of this method is all stuff that only happens if + # document.write works + + def endTagOther(self, token): + self.tree.openElements.pop() + self.parser.phase = self.parser.originalPhase + + class InTablePhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-table + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("caption", self.startTagCaption), + ("colgroup", self.startTagColgroup), + ("col", self.startTagCol), + (("tbody", "tfoot", "thead"), self.startTagRowGroup), + (("td", "th", "tr"), self.startTagImplyTbody), + ("table", self.startTagTable), + (("style", "script"), self.startTagStyleScript), + ("input", self.startTagInput), + ("form", self.startTagForm) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("table", self.endTagTable), + (("body", "caption", "col", "colgroup", "html", "tbody", "td", + "tfoot", "th", "thead", "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods + def clearStackToTableContext(self): + # "clear the stack back to a table context" + while self.tree.openElements[-1].name not in ("table", "html"): + # self.parser.parseError("unexpected-implied-end-tag-in-table", + # {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + # When the current node is <html> it's an innerHTML case + + # processing methods + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-table") + else: + assert self.parser.innerHTML + # Stop parsing + + def processSpaceCharacters(self, token): + originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["inTableText"] + self.parser.phase.originalPhase = originalPhase + self.parser.phase.processSpaceCharacters(token) + + def processCharacters(self, token): + originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["inTableText"] + self.parser.phase.originalPhase = originalPhase + self.parser.phase.processCharacters(token) + + def insertText(self, token): + # If we get here there must be at least one non-whitespace character + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processCharacters(token) + self.tree.insertFromTable = False + + def startTagCaption(self, token): + self.clearStackToTableContext() + self.tree.activeFormattingElements.append(Marker) + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inCaption"] + + def startTagColgroup(self, token): + self.clearStackToTableContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inColumnGroup"] + + def startTagCol(self, token): + self.startTagColgroup(impliedTagToken("colgroup", "StartTag")) + return token + + def startTagRowGroup(self, token): + self.clearStackToTableContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inTableBody"] + + def startTagImplyTbody(self, token): + self.startTagRowGroup(impliedTagToken("tbody", "StartTag")) + return token + + def startTagTable(self, token): + self.parser.parseError("unexpected-start-tag-implies-end-tag", + {"startName": "table", "endName": "table"}) + self.parser.phase.processEndTag(impliedTagToken("table")) + if not self.parser.innerHTML: + return token + + def startTagStyleScript(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagInput(self, token): + if ("type" in token["data"] and + token["data"]["type"].translate(asciiUpper2Lower) == "hidden"): + self.parser.parseError("unexpected-hidden-input-in-table") + self.tree.insertElement(token) + # XXX associate with form + self.tree.openElements.pop() + else: + self.startTagOther(token) + + def startTagForm(self, token): + self.parser.parseError("unexpected-form-in-table") + if self.tree.formPointer is None: + self.tree.insertElement(token) + self.tree.formPointer = self.tree.openElements[-1] + self.tree.openElements.pop() + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-implies-table-voodoo", {"name": token["name"]}) + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processStartTag(token) + self.tree.insertFromTable = False + + def endTagTable(self, token): + if self.tree.elementInScope("table", variant="table"): + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "table": + self.parser.parseError("end-tag-too-early-named", + {"gotName": "table", + "expectedName": self.tree.openElements[-1].name}) + while self.tree.openElements[-1].name != "table": + self.tree.openElements.pop() + self.tree.openElements.pop() + self.parser.resetInsertionMode() + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-implies-table-voodoo", {"name": token["name"]}) + # Do the table magic! + self.tree.insertFromTable = True + self.parser.phases["inBody"].processEndTag(token) + self.tree.insertFromTable = False + + class InTableTextPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.originalPhase = None + self.characterTokens = [] + + def flushCharacters(self): + data = "".join([item["data"] for item in self.characterTokens]) + if any([item not in spaceCharacters for item in data]): + token = {"type": tokenTypes["Characters"], "data": data} + self.parser.phases["inTable"].insertText(token) + elif data: + self.tree.insertText(data) + self.characterTokens = [] + + def processComment(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + def processEOF(self): + self.flushCharacters() + self.parser.phase = self.originalPhase + return True + + def processCharacters(self, token): + if token["data"] == "\u0000": + return + self.characterTokens.append(token) + + def processSpaceCharacters(self, token): + # pretty sure we should never reach here + self.characterTokens.append(token) + # assert False + + def processStartTag(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + def processEndTag(self, token): + self.flushCharacters() + self.parser.phase = self.originalPhase + return token + + class InCaptionPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-caption + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.startTagTableElement) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("caption", self.endTagCaption), + ("table", self.endTagTable), + (("body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + def ignoreEndTagCaption(self): + return not self.tree.elementInScope("caption", variant="table") + + def processEOF(self): + self.parser.phases["inBody"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inBody"].processCharacters(token) + + def startTagTableElement(self, token): + self.parser.parseError() + # XXX Have to duplicate logic here to find out if the tag is ignored + ignoreEndTag = self.ignoreEndTagCaption() + self.parser.phase.processEndTag(impliedTagToken("caption")) + if not ignoreEndTag: + return token + + def startTagOther(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def endTagCaption(self, token): + if not self.ignoreEndTagCaption(): + # AT this code is quite similar to endTagTable in "InTable" + self.tree.generateImpliedEndTags() + if self.tree.openElements[-1].name != "caption": + self.parser.parseError("expected-one-end-tag-but-got-another", + {"gotName": "caption", + "expectedName": self.tree.openElements[-1].name}) + while self.tree.openElements[-1].name != "caption": + self.tree.openElements.pop() + self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + self.parser.phase = self.parser.phases["inTable"] + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagTable(self, token): + self.parser.parseError() + ignoreEndTag = self.ignoreEndTagCaption() + self.parser.phase.processEndTag(impliedTagToken("caption")) + if not ignoreEndTag: + return token + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inBody"].processEndTag(token) + + class InColumnGroupPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-column + + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("col", self.startTagCol) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("colgroup", self.endTagColgroup), + ("col", self.endTagCol) + ]) + self.endTagHandler.default = self.endTagOther + + def ignoreEndTagColgroup(self): + return self.tree.openElements[-1].name == "html" + + def processEOF(self): + if self.tree.openElements[-1].name == "html": + assert self.parser.innerHTML + return + else: + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return True + + def processCharacters(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + def startTagCol(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagOther(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + def endTagColgroup(self, token): + if self.ignoreEndTagColgroup(): + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + else: + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTable"] + + def endTagCol(self, token): + self.parser.parseError("no-end-tag", {"name": "col"}) + + def endTagOther(self, token): + ignoreEndTag = self.ignoreEndTagColgroup() + self.endTagColgroup(impliedTagToken("colgroup")) + if not ignoreEndTag: + return token + + class InTableBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-table0 + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("tr", self.startTagTr), + (("td", "th"), self.startTagTableCell), + (("caption", "col", "colgroup", "tbody", "tfoot", "thead"), + self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("tbody", "tfoot", "thead"), self.endTagTableRowGroup), + ("table", self.endTagTable), + (("body", "caption", "col", "colgroup", "html", "td", "th", + "tr"), self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods + def clearStackToTableBodyContext(self): + while self.tree.openElements[-1].name not in ("tbody", "tfoot", + "thead", "html"): + # self.parser.parseError("unexpected-implied-end-tag-in-table", + # {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + if self.tree.openElements[-1].name == "html": + assert self.parser.innerHTML + + # the rest + def processEOF(self): + self.parser.phases["inTable"].processEOF() + + def processSpaceCharacters(self, token): + return self.parser.phases["inTable"].processSpaceCharacters(token) + + def processCharacters(self, token): + return self.parser.phases["inTable"].processCharacters(token) + + def startTagTr(self, token): + self.clearStackToTableBodyContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inRow"] + + def startTagTableCell(self, token): + self.parser.parseError("unexpected-cell-in-table-body", + {"name": token["name"]}) + self.startTagTr(impliedTagToken("tr", "StartTag")) + return token + + def startTagTableOther(self, token): + # XXX AT Any ideas on how to share this with endTagTable? + if (self.tree.elementInScope("tbody", variant="table") or + self.tree.elementInScope("thead", variant="table") or + self.tree.elementInScope("tfoot", variant="table")): + self.clearStackToTableBodyContext() + self.endTagTableRowGroup( + impliedTagToken(self.tree.openElements[-1].name)) + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def startTagOther(self, token): + return self.parser.phases["inTable"].processStartTag(token) + + def endTagTableRowGroup(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.clearStackToTableBodyContext() + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTable"] + else: + self.parser.parseError("unexpected-end-tag-in-table-body", + {"name": token["name"]}) + + def endTagTable(self, token): + if (self.tree.elementInScope("tbody", variant="table") or + self.tree.elementInScope("thead", variant="table") or + self.tree.elementInScope("tfoot", variant="table")): + self.clearStackToTableBodyContext() + self.endTagTableRowGroup( + impliedTagToken(self.tree.openElements[-1].name)) + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag-in-table-body", + {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inTable"].processEndTag(token) + + class InRowPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-row + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("td", "th"), self.startTagTableCell), + (("caption", "col", "colgroup", "tbody", "tfoot", "thead", + "tr"), self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("tr", self.endTagTr), + ("table", self.endTagTable), + (("tbody", "tfoot", "thead"), self.endTagTableRowGroup), + (("body", "caption", "col", "colgroup", "html", "td", "th"), + self.endTagIgnore) + ]) + self.endTagHandler.default = self.endTagOther + + # helper methods (XXX unify this with other table helper methods) + def clearStackToTableRowContext(self): + while self.tree.openElements[-1].name not in ("tr", "html"): + self.parser.parseError("unexpected-implied-end-tag-in-table-row", + {"name": self.tree.openElements[-1].name}) + self.tree.openElements.pop() + + def ignoreEndTagTr(self): + return not self.tree.elementInScope("tr", variant="table") + + # the rest + def processEOF(self): + self.parser.phases["inTable"].processEOF() + + def processSpaceCharacters(self, token): + return self.parser.phases["inTable"].processSpaceCharacters(token) + + def processCharacters(self, token): + return self.parser.phases["inTable"].processCharacters(token) + + def startTagTableCell(self, token): + self.clearStackToTableRowContext() + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inCell"] + self.tree.activeFormattingElements.append(Marker) + + def startTagTableOther(self, token): + ignoreEndTag = self.ignoreEndTagTr() + self.endTagTr(impliedTagToken("tr")) + # XXX how are we sure it's always ignored in the innerHTML case? + if not ignoreEndTag: + return token + + def startTagOther(self, token): + return self.parser.phases["inTable"].processStartTag(token) + + def endTagTr(self, token): + if not self.ignoreEndTagTr(): + self.clearStackToTableRowContext() + self.tree.openElements.pop() + self.parser.phase = self.parser.phases["inTableBody"] + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagTable(self, token): + ignoreEndTag = self.ignoreEndTagTr() + self.endTagTr(impliedTagToken("tr")) + # Reprocess the current tag if the tr end tag was not ignored + # XXX how are we sure it's always ignored in the innerHTML case? + if not ignoreEndTag: + return token + + def endTagTableRowGroup(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.endTagTr(impliedTagToken("tr")) + return token + else: + self.parser.parseError() + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag-in-table-row", + {"name": token["name"]}) + + def endTagOther(self, token): + return self.parser.phases["inTable"].processEndTag(token) + + class InCellPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-cell + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th", + "thead", "tr"), self.startTagTableOther) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("td", "th"), self.endTagTableCell), + (("body", "caption", "col", "colgroup", "html"), self.endTagIgnore), + (("table", "tbody", "tfoot", "thead", "tr"), self.endTagImply) + ]) + self.endTagHandler.default = self.endTagOther + + # helper + def closeCell(self): + if self.tree.elementInScope("td", variant="table"): + self.endTagTableCell(impliedTagToken("td")) + elif self.tree.elementInScope("th", variant="table"): + self.endTagTableCell(impliedTagToken("th")) + + # the rest + def processEOF(self): + self.parser.phases["inBody"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inBody"].processCharacters(token) + + def startTagTableOther(self, token): + if (self.tree.elementInScope("td", variant="table") or + self.tree.elementInScope("th", variant="table")): + self.closeCell() + return token + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def startTagOther(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def endTagTableCell(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.tree.generateImpliedEndTags(token["name"]) + if self.tree.openElements[-1].name != token["name"]: + self.parser.parseError("unexpected-cell-end-tag", + {"name": token["name"]}) + while True: + node = self.tree.openElements.pop() + if node.name == token["name"]: + break + else: + self.tree.openElements.pop() + self.tree.clearActiveFormattingElements() + self.parser.phase = self.parser.phases["inRow"] + else: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagIgnore(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def endTagImply(self, token): + if self.tree.elementInScope(token["name"], variant="table"): + self.closeCell() + return token + else: + # sometimes innerHTML case + self.parser.parseError() + + def endTagOther(self, token): + return self.parser.phases["inBody"].processEndTag(token) + + class InSelectPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("option", self.startTagOption), + ("optgroup", self.startTagOptgroup), + ("select", self.startTagSelect), + (("input", "keygen", "textarea"), self.startTagInput), + ("script", self.startTagScript) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("option", self.endTagOption), + ("optgroup", self.endTagOptgroup), + ("select", self.endTagSelect) + ]) + self.endTagHandler.default = self.endTagOther + + # http://www.whatwg.org/specs/web-apps/current-work/#in-select + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-select") + else: + assert self.parser.innerHTML + + def processCharacters(self, token): + if token["data"] == "\u0000": + return + self.tree.insertText(token["data"]) + + def startTagOption(self, token): + # We need to imply </option> if <option> is the current node. + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagOptgroup(self, token): + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + if self.tree.openElements[-1].name == "optgroup": + self.tree.openElements.pop() + self.tree.insertElement(token) + + def startTagSelect(self, token): + self.parser.parseError("unexpected-select-in-select") + self.endTagSelect(impliedTagToken("select")) + + def startTagInput(self, token): + self.parser.parseError("unexpected-input-in-select") + if self.tree.elementInScope("select", variant="select"): + self.endTagSelect(impliedTagToken("select")) + return token + else: + assert self.parser.innerHTML + + def startTagScript(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-in-select", + {"name": token["name"]}) + + def endTagOption(self, token): + if self.tree.openElements[-1].name == "option": + self.tree.openElements.pop() + else: + self.parser.parseError("unexpected-end-tag-in-select", + {"name": "option"}) + + def endTagOptgroup(self, token): + # </optgroup> implicitly closes <option> + if (self.tree.openElements[-1].name == "option" and + self.tree.openElements[-2].name == "optgroup"): + self.tree.openElements.pop() + # It also closes </optgroup> + if self.tree.openElements[-1].name == "optgroup": + self.tree.openElements.pop() + # But nothing else + else: + self.parser.parseError("unexpected-end-tag-in-select", + {"name": "optgroup"}) + + def endTagSelect(self, token): + if self.tree.elementInScope("select", variant="select"): + node = self.tree.openElements.pop() + while node.name != "select": + node = self.tree.openElements.pop() + self.parser.resetInsertionMode() + else: + # innerHTML case + assert self.parser.innerHTML + self.parser.parseError() + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-in-select", + {"name": token["name"]}) + + class InSelectInTablePhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"), + self.startTagTable) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"), + self.endTagTable) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + self.parser.phases["inSelect"].processEOF() + + def processCharacters(self, token): + return self.parser.phases["inSelect"].processCharacters(token) + + def startTagTable(self, token): + self.parser.parseError("unexpected-table-element-start-tag-in-select-in-table", {"name": token["name"]}) + self.endTagOther(impliedTagToken("select")) + return token + + def startTagOther(self, token): + return self.parser.phases["inSelect"].processStartTag(token) + + def endTagTable(self, token): + self.parser.parseError("unexpected-table-element-end-tag-in-select-in-table", {"name": token["name"]}) + if self.tree.elementInScope(token["name"], variant="table"): + self.endTagOther(impliedTagToken("select")) + return token + + def endTagOther(self, token): + return self.parser.phases["inSelect"].processEndTag(token) + + class InForeignContentPhase(Phase): + breakoutElements = frozenset(["b", "big", "blockquote", "body", "br", + "center", "code", "dd", "div", "dl", "dt", + "em", "embed", "h1", "h2", "h3", + "h4", "h5", "h6", "head", "hr", "i", "img", + "li", "listing", "menu", "meta", "nobr", + "ol", "p", "pre", "ruby", "s", "small", + "span", "strong", "strike", "sub", "sup", + "table", "tt", "u", "ul", "var"]) + + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + def adjustSVGTagNames(self, token): + replacements = {"altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath"} + + if token["name"] in replacements: + token["name"] = replacements[token["name"]] + + def processCharacters(self, token): + if token["data"] == "\u0000": + token["data"] = "\uFFFD" + elif (self.parser.framesetOK and + any(char not in spaceCharacters for char in token["data"])): + self.parser.framesetOK = False + Phase.processCharacters(self, token) + + def processStartTag(self, token): + currentNode = self.tree.openElements[-1] + if (token["name"] in self.breakoutElements or + (token["name"] == "font" and + set(token["data"].keys()) & set(["color", "face", "size"]))): + self.parser.parseError("unexpected-html-element-in-foreign-content", + {"name": token["name"]}) + while (self.tree.openElements[-1].namespace != + self.tree.defaultNamespace and + not self.parser.isHTMLIntegrationPoint(self.tree.openElements[-1]) and + not self.parser.isMathMLTextIntegrationPoint(self.tree.openElements[-1])): + self.tree.openElements.pop() + return token + + else: + if currentNode.namespace == namespaces["mathml"]: + self.parser.adjustMathMLAttributes(token) + elif currentNode.namespace == namespaces["svg"]: + self.adjustSVGTagNames(token) + self.parser.adjustSVGAttributes(token) + self.parser.adjustForeignAttributes(token) + token["namespace"] = currentNode.namespace + self.tree.insertElement(token) + if token["selfClosing"]: + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def processEndTag(self, token): + nodeIndex = len(self.tree.openElements) - 1 + node = self.tree.openElements[-1] + if node.name.translate(asciiUpper2Lower) != token["name"]: + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + while True: + if node.name.translate(asciiUpper2Lower) == token["name"]: + # XXX this isn't in the spec but it seems necessary + if self.parser.phase == self.parser.phases["inTableText"]: + self.parser.phase.flushCharacters() + self.parser.phase = self.parser.phase.originalPhase + while self.tree.openElements.pop() != node: + assert self.tree.openElements + new_token = None + break + nodeIndex -= 1 + + node = self.tree.openElements[nodeIndex] + if node.namespace != self.tree.defaultNamespace: + continue + else: + new_token = self.parser.phase.processEndTag(token) + break + return new_token + + class AfterBodyPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([("html", self.endTagHtml)]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + # Stop parsing + pass + + def processComment(self, token): + # This is needed because data is to be appended to the <html> element + # here and not to whatever is currently open. + self.tree.insertComment(token, self.tree.openElements[0]) + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-after-body") + self.parser.phase = self.parser.phases["inBody"] + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-after-body", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + def endTagHtml(self, name): + if self.parser.innerHTML: + self.parser.parseError("unexpected-end-tag-after-body-innerhtml") + else: + self.parser.phase = self.parser.phases["afterAfterBody"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-after-body", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + class InFramesetPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#in-frameset + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("frameset", self.startTagFrameset), + ("frame", self.startTagFrame), + ("noframes", self.startTagNoframes) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("frameset", self.endTagFrameset) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + if self.tree.openElements[-1].name != "html": + self.parser.parseError("eof-in-frameset") + else: + assert self.parser.innerHTML + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-in-frameset") + + def startTagFrameset(self, token): + self.tree.insertElement(token) + + def startTagFrame(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + + def startTagNoframes(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-in-frameset", + {"name": token["name"]}) + + def endTagFrameset(self, token): + if self.tree.openElements[-1].name == "html": + # innerHTML case + self.parser.parseError("unexpected-frameset-in-frameset-innerhtml") + else: + self.tree.openElements.pop() + if (not self.parser.innerHTML and + self.tree.openElements[-1].name != "frameset"): + # If we're not in innerHTML mode and the current node is not a + # "frameset" element (anymore) then switch. + self.parser.phase = self.parser.phases["afterFrameset"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-in-frameset", + {"name": token["name"]}) + + class AfterFramesetPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#after3 + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("noframes", self.startTagNoframes) + ]) + self.startTagHandler.default = self.startTagOther + + self.endTagHandler = _utils.MethodDispatcher([ + ("html", self.endTagHtml) + ]) + self.endTagHandler.default = self.endTagOther + + def processEOF(self): + # Stop parsing + pass + + def processCharacters(self, token): + self.parser.parseError("unexpected-char-after-frameset") + + def startTagNoframes(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("unexpected-start-tag-after-frameset", + {"name": token["name"]}) + + def endTagHtml(self, token): + self.parser.phase = self.parser.phases["afterAfterFrameset"] + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag-after-frameset", + {"name": token["name"]}) + + class AfterAfterBodyPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml) + ]) + self.startTagHandler.default = self.startTagOther + + def processEOF(self): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + return self.parser.phases["inBody"].processSpaceCharacters(token) + + def processCharacters(self, token): + self.parser.parseError("expected-eof-but-got-char") + self.parser.phase = self.parser.phases["inBody"] + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("expected-eof-but-got-start-tag", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + def processEndTag(self, token): + self.parser.parseError("expected-eof-but-got-end-tag", + {"name": token["name"]}) + self.parser.phase = self.parser.phases["inBody"] + return token + + class AfterAfterFramesetPhase(Phase): + def __init__(self, parser, tree): + Phase.__init__(self, parser, tree) + + self.startTagHandler = _utils.MethodDispatcher([ + ("html", self.startTagHtml), + ("noframes", self.startTagNoFrames) + ]) + self.startTagHandler.default = self.startTagOther + + def processEOF(self): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + return self.parser.phases["inBody"].processSpaceCharacters(token) + + def processCharacters(self, token): + self.parser.parseError("expected-eof-but-got-char") + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagNoFrames(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagOther(self, token): + self.parser.parseError("expected-eof-but-got-start-tag", + {"name": token["name"]}) + + def processEndTag(self, token): + self.parser.parseError("expected-eof-but-got-end-tag", + {"name": token["name"]}) + # pylint:enable=unused-argument + + return { + "initial": InitialPhase, + "beforeHtml": BeforeHtmlPhase, + "beforeHead": BeforeHeadPhase, + "inHead": InHeadPhase, + "inHeadNoscript": InHeadNoscriptPhase, + "afterHead": AfterHeadPhase, + "inBody": InBodyPhase, + "text": TextPhase, + "inTable": InTablePhase, + "inTableText": InTableTextPhase, + "inCaption": InCaptionPhase, + "inColumnGroup": InColumnGroupPhase, + "inTableBody": InTableBodyPhase, + "inRow": InRowPhase, + "inCell": InCellPhase, + "inSelect": InSelectPhase, + "inSelectInTable": InSelectInTablePhase, + "inForeignContent": InForeignContentPhase, + "afterBody": AfterBodyPhase, + "inFrameset": InFramesetPhase, + "afterFrameset": AfterFramesetPhase, + "afterAfterBody": AfterAfterBodyPhase, + "afterAfterFrameset": AfterAfterFramesetPhase, + # XXX after after frameset + } + + +def adjust_attributes(token, replacements): + needs_adjustment = viewkeys(token['data']) & viewkeys(replacements) + if needs_adjustment: + token['data'] = OrderedDict((replacements.get(k, k), v) + for k, v in token['data'].items()) + + +def impliedTagToken(name, type="EndTag", attributes=None, + selfClosing=False): + if attributes is None: + attributes = {} + return {"type": tokenTypes[type], "name": name, "data": attributes, + "selfClosing": selfClosing} + + +class ParseError(Exception): + """Error in parsed document""" + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py new file mode 100755 index 0000000..641323e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/serializer.py @@ -0,0 +1,409 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +import re + +from codecs import register_error, xmlcharrefreplace_errors + +from .constants import voidElements, booleanAttributes, spaceCharacters +from .constants import rcdataElements, entities, xmlEntities +from . import treewalkers, _utils +from xml.sax.saxutils import escape + +_quoteAttributeSpecChars = "".join(spaceCharacters) + "\"'=<>`" +_quoteAttributeSpec = re.compile("[" + _quoteAttributeSpecChars + "]") +_quoteAttributeLegacy = re.compile("[" + _quoteAttributeSpecChars + + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n" + "\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15" + "\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x2f\x60\xa0\u1680\u180e\u180f\u2000" + "\u2001\u2002\u2003\u2004\u2005\u2006\u2007" + "\u2008\u2009\u200a\u2028\u2029\u202f\u205f" + "\u3000]") + + +_encode_entity_map = {} +_is_ucs4 = len("\U0010FFFF") == 1 +for k, v in list(entities.items()): + # skip multi-character entities + if ((_is_ucs4 and len(v) > 1) or + (not _is_ucs4 and len(v) > 2)): + continue + if v != "&": + if len(v) == 2: + v = _utils.surrogatePairToCodepoint(v) + else: + v = ord(v) + if v not in _encode_entity_map or k.islower(): + # prefer < over < and similarly for &, >, etc. + _encode_entity_map[v] = k + + +def htmlentityreplace_errors(exc): + if isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)): + res = [] + codepoints = [] + skip = False + for i, c in enumerate(exc.object[exc.start:exc.end]): + if skip: + skip = False + continue + index = i + exc.start + if _utils.isSurrogatePair(exc.object[index:min([exc.end, index + 2])]): + codepoint = _utils.surrogatePairToCodepoint(exc.object[index:index + 2]) + skip = True + else: + codepoint = ord(c) + codepoints.append(codepoint) + for cp in codepoints: + e = _encode_entity_map.get(cp) + if e: + res.append("&") + res.append(e) + if not e.endswith(";"): + res.append(";") + else: + res.append("&#x%s;" % (hex(cp)[2:])) + return ("".join(res), exc.end) + else: + return xmlcharrefreplace_errors(exc) + + +register_error("htmlentityreplace", htmlentityreplace_errors) + + +def serialize(input, tree="etree", encoding=None, **serializer_opts): + """Serializes the input token stream using the specified treewalker + + :arg input: the token stream to serialize + + :arg tree: the treewalker to use + + :arg encoding: the encoding to use + + :arg serializer_opts: any options to pass to the + :py:class:`html5lib.serializer.HTMLSerializer` that gets created + + :returns: the tree serialized as a string + + Example: + + >>> from html5lib.html5parser import parse + >>> from html5lib.serializer import serialize + >>> token_stream = parse('<html><body><p>Hi!</p></body></html>') + >>> serialize(token_stream, omit_optional_tags=False) + '<html><head></head><body><p>Hi!</p></body></html>' + + """ + # XXX: Should we cache this? + walker = treewalkers.getTreeWalker(tree) + s = HTMLSerializer(**serializer_opts) + return s.render(walker(input), encoding) + + +class HTMLSerializer(object): + + # attribute quoting options + quote_attr_values = "legacy" # be secure by default + quote_char = '"' + use_best_quote_char = True + + # tag syntax options + omit_optional_tags = True + minimize_boolean_attributes = True + use_trailing_solidus = False + space_before_trailing_solidus = True + + # escaping options + escape_lt_in_attrs = False + escape_rcdata = False + resolve_entities = True + + # miscellaneous options + alphabetical_attributes = False + inject_meta_charset = True + strip_whitespace = False + sanitize = False + + options = ("quote_attr_values", "quote_char", "use_best_quote_char", + "omit_optional_tags", "minimize_boolean_attributes", + "use_trailing_solidus", "space_before_trailing_solidus", + "escape_lt_in_attrs", "escape_rcdata", "resolve_entities", + "alphabetical_attributes", "inject_meta_charset", + "strip_whitespace", "sanitize") + + def __init__(self, **kwargs): + """Initialize HTMLSerializer + + :arg inject_meta_charset: Whether or not to inject the meta charset. + + Defaults to ``True``. + + :arg quote_attr_values: Whether to quote attribute values that don't + require quoting per legacy browser behavior (``"legacy"``), when + required by the standard (``"spec"``), or always (``"always"``). + + Defaults to ``"legacy"``. + + :arg quote_char: Use given quote character for attribute quoting. + + Defaults to ``"`` which will use double quotes unless attribute + value contains a double quote, in which case single quotes are + used. + + :arg escape_lt_in_attrs: Whether or not to escape ``<`` in attribute + values. + + Defaults to ``False``. + + :arg escape_rcdata: Whether to escape characters that need to be + escaped within normal elements within rcdata elements such as + style. + + Defaults to ``False``. + + :arg resolve_entities: Whether to resolve named character entities that + appear in the source tree. The XML predefined entities < > + & " ' are unaffected by this setting. + + Defaults to ``True``. + + :arg strip_whitespace: Whether to remove semantically meaningless + whitespace. (This compresses all whitespace to a single space + except within ``pre``.) + + Defaults to ``False``. + + :arg minimize_boolean_attributes: Shortens boolean attributes to give + just the attribute value, for example:: + + <input disabled="disabled"> + + becomes:: + + <input disabled> + + Defaults to ``True``. + + :arg use_trailing_solidus: Includes a close-tag slash at the end of the + start tag of void elements (empty elements whose end tag is + forbidden). E.g. ``<hr/>``. + + Defaults to ``False``. + + :arg space_before_trailing_solidus: Places a space immediately before + the closing slash in a tag using a trailing solidus. E.g. + ``<hr />``. Requires ``use_trailing_solidus=True``. + + Defaults to ``True``. + + :arg sanitize: Strip all unsafe or unknown constructs from output. + See :py:class:`html5lib.filters.sanitizer.Filter`. + + Defaults to ``False``. + + :arg omit_optional_tags: Omit start/end tags that are optional. + + Defaults to ``True``. + + :arg alphabetical_attributes: Reorder attributes to be in alphabetical order. + + Defaults to ``False``. + + """ + unexpected_args = frozenset(kwargs) - frozenset(self.options) + if len(unexpected_args) > 0: + raise TypeError("__init__() got an unexpected keyword argument '%s'" % next(iter(unexpected_args))) + if 'quote_char' in kwargs: + self.use_best_quote_char = False + for attr in self.options: + setattr(self, attr, kwargs.get(attr, getattr(self, attr))) + self.errors = [] + self.strict = False + + def encode(self, string): + assert(isinstance(string, text_type)) + if self.encoding: + return string.encode(self.encoding, "htmlentityreplace") + else: + return string + + def encodeStrict(self, string): + assert(isinstance(string, text_type)) + if self.encoding: + return string.encode(self.encoding, "strict") + else: + return string + + def serialize(self, treewalker, encoding=None): + # pylint:disable=too-many-nested-blocks + self.encoding = encoding + in_cdata = False + self.errors = [] + + if encoding and self.inject_meta_charset: + from .filters.inject_meta_charset import Filter + treewalker = Filter(treewalker, encoding) + # Alphabetical attributes is here under the assumption that none of + # the later filters add or change order of attributes; it needs to be + # before the sanitizer so escaped elements come out correctly + if self.alphabetical_attributes: + from .filters.alphabeticalattributes import Filter + treewalker = Filter(treewalker) + # WhitespaceFilter should be used before OptionalTagFilter + # for maximum efficiently of this latter filter + if self.strip_whitespace: + from .filters.whitespace import Filter + treewalker = Filter(treewalker) + if self.sanitize: + from .filters.sanitizer import Filter + treewalker = Filter(treewalker) + if self.omit_optional_tags: + from .filters.optionaltags import Filter + treewalker = Filter(treewalker) + + for token in treewalker: + type = token["type"] + if type == "Doctype": + doctype = "<!DOCTYPE %s" % token["name"] + + if token["publicId"]: + doctype += ' PUBLIC "%s"' % token["publicId"] + elif token["systemId"]: + doctype += " SYSTEM" + if token["systemId"]: + if token["systemId"].find('"') >= 0: + if token["systemId"].find("'") >= 0: + self.serializeError("System identifer contains both single and double quote characters") + quote_char = "'" + else: + quote_char = '"' + doctype += " %s%s%s" % (quote_char, token["systemId"], quote_char) + + doctype += ">" + yield self.encodeStrict(doctype) + + elif type in ("Characters", "SpaceCharacters"): + if type == "SpaceCharacters" or in_cdata: + if in_cdata and token["data"].find("</") >= 0: + self.serializeError("Unexpected </ in CDATA") + yield self.encode(token["data"]) + else: + yield self.encode(escape(token["data"])) + + elif type in ("StartTag", "EmptyTag"): + name = token["name"] + yield self.encodeStrict("<%s" % name) + if name in rcdataElements and not self.escape_rcdata: + in_cdata = True + elif in_cdata: + self.serializeError("Unexpected child element of a CDATA element") + for (_, attr_name), attr_value in token["data"].items(): + # TODO: Add namespace support here + k = attr_name + v = attr_value + yield self.encodeStrict(' ') + + yield self.encodeStrict(k) + if not self.minimize_boolean_attributes or \ + (k not in booleanAttributes.get(name, tuple()) and + k not in booleanAttributes.get("", tuple())): + yield self.encodeStrict("=") + if self.quote_attr_values == "always" or len(v) == 0: + quote_attr = True + elif self.quote_attr_values == "spec": + quote_attr = _quoteAttributeSpec.search(v) is not None + elif self.quote_attr_values == "legacy": + quote_attr = _quoteAttributeLegacy.search(v) is not None + else: + raise ValueError("quote_attr_values must be one of: " + "'always', 'spec', or 'legacy'") + v = v.replace("&", "&") + if self.escape_lt_in_attrs: + v = v.replace("<", "<") + if quote_attr: + quote_char = self.quote_char + if self.use_best_quote_char: + if "'" in v and '"' not in v: + quote_char = '"' + elif '"' in v and "'" not in v: + quote_char = "'" + if quote_char == "'": + v = v.replace("'", "'") + else: + v = v.replace('"', """) + yield self.encodeStrict(quote_char) + yield self.encode(v) + yield self.encodeStrict(quote_char) + else: + yield self.encode(v) + if name in voidElements and self.use_trailing_solidus: + if self.space_before_trailing_solidus: + yield self.encodeStrict(" /") + else: + yield self.encodeStrict("/") + yield self.encode(">") + + elif type == "EndTag": + name = token["name"] + if name in rcdataElements: + in_cdata = False + elif in_cdata: + self.serializeError("Unexpected child element of a CDATA element") + yield self.encodeStrict("</%s>" % name) + + elif type == "Comment": + data = token["data"] + if data.find("--") >= 0: + self.serializeError("Comment contains --") + yield self.encodeStrict("<!--%s-->" % token["data"]) + + elif type == "Entity": + name = token["name"] + key = name + ";" + if key not in entities: + self.serializeError("Entity %s not recognized" % name) + if self.resolve_entities and key not in xmlEntities: + data = entities[key] + else: + data = "&%s;" % name + yield self.encodeStrict(data) + + else: + self.serializeError(token["data"]) + + def render(self, treewalker, encoding=None): + """Serializes the stream from the treewalker into a string + + :arg treewalker: the treewalker to serialize + + :arg encoding: the string encoding to use + + :returns: the serialized tree + + Example: + + >>> from html5lib import parse, getTreeWalker + >>> from html5lib.serializer import HTMLSerializer + >>> token_stream = parse('<html><body>Hi!</body></html>') + >>> walker = getTreeWalker('etree') + >>> serializer = HTMLSerializer(omit_optional_tags=False) + >>> serializer.render(walker(token_stream)) + '<html><head></head><body>Hi!</body></html>' + + """ + if encoding: + return b"".join(list(self.serialize(treewalker, encoding))) + else: + return "".join(list(self.serialize(treewalker))) + + def serializeError(self, data="XXX ERROR MESSAGE NEEDED"): + # XXX The idea is to make data mandatory. + self.errors.append(data) + if self.strict: + raise SerializeError + + +class SerializeError(Exception): + """Error in serialized tree""" + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py new file mode 100755 index 0000000..8767fb0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/__init__.py @@ -0,0 +1,30 @@ +"""Tree adapters let you convert from one tree structure to another + +Example: + +.. code-block:: python + + from pip._vendor import html5lib + from pip._vendor.html5lib.treeadapters import genshi + + doc = '<html><body>Hi!</body></html>' + treebuilder = html5lib.getTreeBuilder('etree') + parser = html5lib.HTMLParser(tree=treebuilder) + tree = parser.parse(doc) + TreeWalker = html5lib.getTreeWalker('etree') + + genshi_tree = genshi.to_genshi(TreeWalker(tree)) + +""" +from __future__ import absolute_import, division, unicode_literals + +from . import sax + +__all__ = ["sax"] + +try: + from . import genshi # noqa +except ImportError: + pass +else: + __all__.append("genshi") diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py new file mode 100755 index 0000000..73c70c6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/genshi.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import, division, unicode_literals + +from genshi.core import QName, Attrs +from genshi.core import START, END, TEXT, COMMENT, DOCTYPE + + +def to_genshi(walker): + """Convert a tree to a genshi tree + + :arg walker: the treewalker to use to walk the tree to convert it + + :returns: generator of genshi nodes + + """ + text = [] + for token in walker: + type = token["type"] + if type in ("Characters", "SpaceCharacters"): + text.append(token["data"]) + elif text: + yield TEXT, "".join(text), (None, -1, -1) + text = [] + + if type in ("StartTag", "EmptyTag"): + if token["namespace"]: + name = "{%s}%s" % (token["namespace"], token["name"]) + else: + name = token["name"] + attrs = Attrs([(QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value) + for attr, value in token["data"].items()]) + yield (START, (QName(name), attrs), (None, -1, -1)) + if type == "EmptyTag": + type = "EndTag" + + if type == "EndTag": + if token["namespace"]: + name = "{%s}%s" % (token["namespace"], token["name"]) + else: + name = token["name"] + + yield END, QName(name), (None, -1, -1) + + elif type == "Comment": + yield COMMENT, token["data"], (None, -1, -1) + + elif type == "Doctype": + yield DOCTYPE, (token["name"], token["publicId"], + token["systemId"]), (None, -1, -1) + + else: + pass # FIXME: What to do? + + if text: + yield TEXT, "".join(text), (None, -1, -1) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py new file mode 100755 index 0000000..1f06d13 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treeadapters/sax.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.sax.xmlreader import AttributesNSImpl + +from ..constants import adjustForeignAttributes, unadjustForeignAttributes + +prefix_mapping = {} +for prefix, localName, namespace in adjustForeignAttributes.values(): + if prefix is not None: + prefix_mapping[prefix] = namespace + + +def to_sax(walker, handler): + """Call SAX-like content handler based on treewalker walker + + :arg walker: the treewalker to use to walk the tree to convert it + + :arg handler: SAX handler to use + + """ + handler.startDocument() + for prefix, namespace in prefix_mapping.items(): + handler.startPrefixMapping(prefix, namespace) + + for token in walker: + type = token["type"] + if type == "Doctype": + continue + elif type in ("StartTag", "EmptyTag"): + attrs = AttributesNSImpl(token["data"], + unadjustForeignAttributes) + handler.startElementNS((token["namespace"], token["name"]), + token["name"], + attrs) + if type == "EmptyTag": + handler.endElementNS((token["namespace"], token["name"]), + token["name"]) + elif type == "EndTag": + handler.endElementNS((token["namespace"], token["name"]), + token["name"]) + elif type in ("Characters", "SpaceCharacters"): + handler.characters(token["data"]) + elif type == "Comment": + pass + else: + assert False, "Unknown token type" + + for prefix, namespace in prefix_mapping.items(): + handler.endPrefixMapping(prefix) + handler.endDocument() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py new file mode 100755 index 0000000..2ce5c87 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/__init__.py @@ -0,0 +1,88 @@ +"""A collection of modules for building different kinds of trees from HTML +documents. + +To create a treebuilder for a new type of tree, you need to do +implement several things: + +1. A set of classes for various types of elements: Document, Doctype, Comment, + Element. These must implement the interface of ``base.treebuilders.Node`` + (although comment nodes have a different signature for their constructor, + see ``treebuilders.etree.Comment``) Textual content may also be implemented + as another node type, or not, as your tree implementation requires. + +2. A treebuilder object (called ``TreeBuilder`` by convention) that inherits + from ``treebuilders.base.TreeBuilder``. This has 4 required attributes: + + * ``documentClass`` - the class to use for the bottommost node of a document + * ``elementClass`` - the class to use for HTML Elements + * ``commentClass`` - the class to use for comments + * ``doctypeClass`` - the class to use for doctypes + + It also has one required method: + + * ``getDocument`` - Returns the root node of the complete document tree + +3. If you wish to run the unit tests, you must also create a ``testSerializer`` + method on your treebuilder which accepts a node and returns a string + containing Node and its children serialized according to the format used in + the unittests + +""" + +from __future__ import absolute_import, division, unicode_literals + +from .._utils import default_etree + +treeBuilderCache = {} + + +def getTreeBuilder(treeType, implementation=None, **kwargs): + """Get a TreeBuilder class for various types of trees with built-in support + + :arg treeType: the name of the tree type required (case-insensitive). Supported + values are: + + * "dom" - A generic builder for DOM implementations, defaulting to a + xml.dom.minidom based implementation. + * "etree" - A generic builder for tree implementations exposing an + ElementTree-like interface, defaulting to xml.etree.cElementTree if + available and xml.etree.ElementTree if not. + * "lxml" - A etree-based builder for lxml.etree, handling limitations + of lxml's implementation. + + :arg implementation: (Currently applies to the "etree" and "dom" tree + types). A module implementing the tree type e.g. xml.etree.ElementTree + or xml.etree.cElementTree. + + :arg kwargs: Any additional options to pass to the TreeBuilder when + creating it. + + Example: + + >>> from html5lib.treebuilders import getTreeBuilder + >>> builder = getTreeBuilder('etree') + + """ + + treeType = treeType.lower() + if treeType not in treeBuilderCache: + if treeType == "dom": + from . import dom + # Come up with a sane default (pref. from the stdlib) + if implementation is None: + from xml.dom import minidom + implementation = minidom + # NEVER cache here, caching is done in the dom submodule + return dom.getDomModule(implementation, **kwargs).TreeBuilder + elif treeType == "lxml": + from . import etree_lxml + treeBuilderCache[treeType] = etree_lxml.TreeBuilder + elif treeType == "etree": + from . import etree + if implementation is None: + implementation = default_etree + # NEVER cache here, caching is done in the etree submodule + return etree.getETreeModule(implementation, **kwargs).TreeBuilder + else: + raise ValueError("""Unrecognised treebuilder "%s" """ % treeType) + return treeBuilderCache.get(treeType) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py new file mode 100755 index 0000000..ed32fcb --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/base.py @@ -0,0 +1,417 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from ..constants import scopingElements, tableInsertModeElements, namespaces + +# The scope markers are inserted when entering object elements, +# marquees, table cells, and table captions, and are used to prevent formatting +# from "leaking" into tables, object elements, and marquees. +Marker = None + +listElementsMap = { + None: (frozenset(scopingElements), False), + "button": (frozenset(scopingElements | set([(namespaces["html"], "button")])), False), + "list": (frozenset(scopingElements | set([(namespaces["html"], "ol"), + (namespaces["html"], "ul")])), False), + "table": (frozenset([(namespaces["html"], "html"), + (namespaces["html"], "table")]), False), + "select": (frozenset([(namespaces["html"], "optgroup"), + (namespaces["html"], "option")]), True) +} + + +class Node(object): + """Represents an item in the tree""" + def __init__(self, name): + """Creates a Node + + :arg name: The tag name associated with the node + + """ + # The tag name assocaited with the node + self.name = name + # The parent of the current node (or None for the document node) + self.parent = None + # The value of the current node (applies to text nodes and comments) + self.value = None + # A dict holding name -> value pairs for attributes of the node + self.attributes = {} + # A list of child nodes of the current node. This must include all + # elements but not necessarily other node types. + self.childNodes = [] + # A list of miscellaneous flags that can be set on the node. + self._flags = [] + + def __str__(self): + attributesStr = " ".join(["%s=\"%s\"" % (name, value) + for name, value in + self.attributes.items()]) + if attributesStr: + return "<%s %s>" % (self.name, attributesStr) + else: + return "<%s>" % (self.name) + + def __repr__(self): + return "<%s>" % (self.name) + + def appendChild(self, node): + """Insert node as a child of the current node + + :arg node: the node to insert + + """ + raise NotImplementedError + + def insertText(self, data, insertBefore=None): + """Insert data as text in the current node, positioned before the + start of node insertBefore or to the end of the node's text. + + :arg data: the data to insert + + :arg insertBefore: True if you want to insert the text before the node + and False if you want to insert it after the node + + """ + raise NotImplementedError + + def insertBefore(self, node, refNode): + """Insert node as a child of the current node, before refNode in the + list of child nodes. Raises ValueError if refNode is not a child of + the current node + + :arg node: the node to insert + + :arg refNode: the child node to insert the node before + + """ + raise NotImplementedError + + def removeChild(self, node): + """Remove node from the children of the current node + + :arg node: the child node to remove + + """ + raise NotImplementedError + + def reparentChildren(self, newParent): + """Move all the children of the current node to newParent. + This is needed so that trees that don't store text as nodes move the + text in the correct way + + :arg newParent: the node to move all this node's children to + + """ + # XXX - should this method be made more general? + for child in self.childNodes: + newParent.appendChild(child) + self.childNodes = [] + + def cloneNode(self): + """Return a shallow copy of the current node i.e. a node with the same + name and attributes but with no parent or child nodes + """ + raise NotImplementedError + + def hasContent(self): + """Return true if the node has children or text, false otherwise + """ + raise NotImplementedError + + +class ActiveFormattingElements(list): + def append(self, node): + equalCount = 0 + if node != Marker: + for element in self[::-1]: + if element == Marker: + break + if self.nodesEqual(element, node): + equalCount += 1 + if equalCount == 3: + self.remove(element) + break + list.append(self, node) + + def nodesEqual(self, node1, node2): + if not node1.nameTuple == node2.nameTuple: + return False + + if not node1.attributes == node2.attributes: + return False + + return True + + +class TreeBuilder(object): + """Base treebuilder implementation + + * documentClass - the class to use for the bottommost node of a document + * elementClass - the class to use for HTML Elements + * commentClass - the class to use for comments + * doctypeClass - the class to use for doctypes + + """ + # pylint:disable=not-callable + + # Document class + documentClass = None + + # The class to use for creating a node + elementClass = None + + # The class to use for creating comments + commentClass = None + + # The class to use for creating doctypes + doctypeClass = None + + # Fragment class + fragmentClass = None + + def __init__(self, namespaceHTMLElements): + """Create a TreeBuilder + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + """ + if namespaceHTMLElements: + self.defaultNamespace = "http://www.w3.org/1999/xhtml" + else: + self.defaultNamespace = None + self.reset() + + def reset(self): + self.openElements = [] + self.activeFormattingElements = ActiveFormattingElements() + + # XXX - rename these to headElement, formElement + self.headPointer = None + self.formPointer = None + + self.insertFromTable = False + + self.document = self.documentClass() + + def elementInScope(self, target, variant=None): + + # If we pass a node in we match that. if we pass a string + # match any node with that name + exactNode = hasattr(target, "nameTuple") + if not exactNode: + if isinstance(target, text_type): + target = (namespaces["html"], target) + assert isinstance(target, tuple) + + listElements, invert = listElementsMap[variant] + + for node in reversed(self.openElements): + if exactNode and node == target: + return True + elif not exactNode and node.nameTuple == target: + return True + elif (invert ^ (node.nameTuple in listElements)): + return False + + assert False # We should never reach this point + + def reconstructActiveFormattingElements(self): + # Within this algorithm the order of steps described in the + # specification is not quite the same as the order of steps in the + # code. It should still do the same though. + + # Step 1: stop the algorithm when there's nothing to do. + if not self.activeFormattingElements: + return + + # Step 2 and step 3: we start with the last element. So i is -1. + i = len(self.activeFormattingElements) - 1 + entry = self.activeFormattingElements[i] + if entry == Marker or entry in self.openElements: + return + + # Step 6 + while entry != Marker and entry not in self.openElements: + if i == 0: + # This will be reset to 0 below + i = -1 + break + i -= 1 + # Step 5: let entry be one earlier in the list. + entry = self.activeFormattingElements[i] + + while True: + # Step 7 + i += 1 + + # Step 8 + entry = self.activeFormattingElements[i] + clone = entry.cloneNode() # Mainly to get a new copy of the attributes + + # Step 9 + element = self.insertElement({"type": "StartTag", + "name": clone.name, + "namespace": clone.namespace, + "data": clone.attributes}) + + # Step 10 + self.activeFormattingElements[i] = element + + # Step 11 + if element == self.activeFormattingElements[-1]: + break + + def clearActiveFormattingElements(self): + entry = self.activeFormattingElements.pop() + while self.activeFormattingElements and entry != Marker: + entry = self.activeFormattingElements.pop() + + def elementInActiveFormattingElements(self, name): + """Check if an element exists between the end of the active + formatting elements and the last marker. If it does, return it, else + return false""" + + for item in self.activeFormattingElements[::-1]: + # Check for Marker first because if it's a Marker it doesn't have a + # name attribute. + if item == Marker: + break + elif item.name == name: + return item + return False + + def insertRoot(self, token): + element = self.createElement(token) + self.openElements.append(element) + self.document.appendChild(element) + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + doctype = self.doctypeClass(name, publicId, systemId) + self.document.appendChild(doctype) + + def insertComment(self, token, parent=None): + if parent is None: + parent = self.openElements[-1] + parent.appendChild(self.commentClass(token["data"])) + + def createElement(self, token): + """Create an element but don't insert it anywhere""" + name = token["name"] + namespace = token.get("namespace", self.defaultNamespace) + element = self.elementClass(name, namespace) + element.attributes = token["data"] + return element + + def _getInsertFromTable(self): + return self._insertFromTable + + def _setInsertFromTable(self, value): + """Switch the function used to insert an element from the + normal one to the misnested table one and back again""" + self._insertFromTable = value + if value: + self.insertElement = self.insertElementTable + else: + self.insertElement = self.insertElementNormal + + insertFromTable = property(_getInsertFromTable, _setInsertFromTable) + + def insertElementNormal(self, token): + name = token["name"] + assert isinstance(name, text_type), "Element %s not unicode" % name + namespace = token.get("namespace", self.defaultNamespace) + element = self.elementClass(name, namespace) + element.attributes = token["data"] + self.openElements[-1].appendChild(element) + self.openElements.append(element) + return element + + def insertElementTable(self, token): + """Create an element and insert it into the tree""" + element = self.createElement(token) + if self.openElements[-1].name not in tableInsertModeElements: + return self.insertElementNormal(token) + else: + # We should be in the InTable mode. This means we want to do + # special magic element rearranging + parent, insertBefore = self.getTableMisnestedNodePosition() + if insertBefore is None: + parent.appendChild(element) + else: + parent.insertBefore(element, insertBefore) + self.openElements.append(element) + return element + + def insertText(self, data, parent=None): + """Insert text data.""" + if parent is None: + parent = self.openElements[-1] + + if (not self.insertFromTable or (self.insertFromTable and + self.openElements[-1].name + not in tableInsertModeElements)): + parent.insertText(data) + else: + # We should be in the InTable mode. This means we want to do + # special magic element rearranging + parent, insertBefore = self.getTableMisnestedNodePosition() + parent.insertText(data, insertBefore) + + def getTableMisnestedNodePosition(self): + """Get the foster parent element, and sibling to insert before + (or None) when inserting a misnested table node""" + # The foster parent element is the one which comes before the most + # recently opened table element + # XXX - this is really inelegant + lastTable = None + fosterParent = None + insertBefore = None + for elm in self.openElements[::-1]: + if elm.name == "table": + lastTable = elm + break + if lastTable: + # XXX - we should really check that this parent is actually a + # node here + if lastTable.parent: + fosterParent = lastTable.parent + insertBefore = lastTable + else: + fosterParent = self.openElements[ + self.openElements.index(lastTable) - 1] + else: + fosterParent = self.openElements[0] + return fosterParent, insertBefore + + def generateImpliedEndTags(self, exclude=None): + name = self.openElements[-1].name + # XXX td, th and tr are not actually needed + if (name in frozenset(("dd", "dt", "li", "option", "optgroup", "p", "rp", "rt")) and + name != exclude): + self.openElements.pop() + # XXX This is not entirely what the specification says. We should + # investigate it more closely. + self.generateImpliedEndTags(exclude) + + def getDocument(self): + """Return the final tree""" + return self.document + + def getFragment(self): + """Return the final fragment""" + # assert self.innerHTML + fragment = self.fragmentClass() + self.openElements[0].reparentChildren(fragment) + return fragment + + def testSerializer(self, node): + """Serialize the subtree of node in the format required by unit tests + + :arg node: the node from which to start serializing + + """ + raise NotImplementedError diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py new file mode 100755 index 0000000..8117b2d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/dom.py @@ -0,0 +1,236 @@ +from __future__ import absolute_import, division, unicode_literals + + +from collections import MutableMapping +from xml.dom import minidom, Node +import weakref + +from . import base +from .. import constants +from ..constants import namespaces +from .._utils import moduleFactoryFactory + + +def getDomBuilder(DomImplementation): + Dom = DomImplementation + + class AttrList(MutableMapping): + def __init__(self, element): + self.element = element + + def __iter__(self): + return iter(self.element.attributes.keys()) + + def __setitem__(self, name, value): + if isinstance(name, tuple): + raise NotImplementedError + else: + attr = self.element.ownerDocument.createAttribute(name) + attr.value = value + self.element.attributes[name] = attr + + def __len__(self): + return len(self.element.attributes) + + def items(self): + return list(self.element.attributes.items()) + + def values(self): + return list(self.element.attributes.values()) + + def __getitem__(self, name): + if isinstance(name, tuple): + raise NotImplementedError + else: + return self.element.attributes[name].value + + def __delitem__(self, name): + if isinstance(name, tuple): + raise NotImplementedError + else: + del self.element.attributes[name] + + class NodeBuilder(base.Node): + def __init__(self, element): + base.Node.__init__(self, element.nodeName) + self.element = element + + namespace = property(lambda self: hasattr(self.element, "namespaceURI") and + self.element.namespaceURI or None) + + def appendChild(self, node): + node.parent = self + self.element.appendChild(node.element) + + def insertText(self, data, insertBefore=None): + text = self.element.ownerDocument.createTextNode(data) + if insertBefore: + self.element.insertBefore(text, insertBefore.element) + else: + self.element.appendChild(text) + + def insertBefore(self, node, refNode): + self.element.insertBefore(node.element, refNode.element) + node.parent = self + + def removeChild(self, node): + if node.element.parentNode == self.element: + self.element.removeChild(node.element) + node.parent = None + + def reparentChildren(self, newParent): + while self.element.hasChildNodes(): + child = self.element.firstChild + self.element.removeChild(child) + newParent.element.appendChild(child) + self.childNodes = [] + + def getAttributes(self): + return AttrList(self.element) + + def setAttributes(self, attributes): + if attributes: + for name, value in list(attributes.items()): + if isinstance(name, tuple): + if name[0] is not None: + qualifiedName = (name[0] + ":" + name[1]) + else: + qualifiedName = name[1] + self.element.setAttributeNS(name[2], qualifiedName, + value) + else: + self.element.setAttribute( + name, value) + attributes = property(getAttributes, setAttributes) + + def cloneNode(self): + return NodeBuilder(self.element.cloneNode(False)) + + def hasContent(self): + return self.element.hasChildNodes() + + def getNameTuple(self): + if self.namespace is None: + return namespaces["html"], self.name + else: + return self.namespace, self.name + + nameTuple = property(getNameTuple) + + class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable + def documentClass(self): + self.dom = Dom.getDOMImplementation().createDocument(None, None, None) + return weakref.proxy(self) + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + domimpl = Dom.getDOMImplementation() + doctype = domimpl.createDocumentType(name, publicId, systemId) + self.document.appendChild(NodeBuilder(doctype)) + if Dom == minidom: + doctype.ownerDocument = self.dom + + def elementClass(self, name, namespace=None): + if namespace is None and self.defaultNamespace is None: + node = self.dom.createElement(name) + else: + node = self.dom.createElementNS(namespace, name) + + return NodeBuilder(node) + + def commentClass(self, data): + return NodeBuilder(self.dom.createComment(data)) + + def fragmentClass(self): + return NodeBuilder(self.dom.createDocumentFragment()) + + def appendChild(self, node): + self.dom.appendChild(node.element) + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + return self.dom + + def getFragment(self): + return base.TreeBuilder.getFragment(self).element + + def insertText(self, data, parent=None): + data = data + if parent != self: + base.TreeBuilder.insertText(self, data, parent) + else: + # HACK: allow text nodes as children of the document node + if hasattr(self.dom, '_child_node_types'): + # pylint:disable=protected-access + if Node.TEXT_NODE not in self.dom._child_node_types: + self.dom._child_node_types = list(self.dom._child_node_types) + self.dom._child_node_types.append(Node.TEXT_NODE) + self.dom.appendChild(self.dom.createTextNode(data)) + + implementation = DomImplementation + name = None + + def testSerializer(element): + element.normalize() + rv = [] + + def serializeElement(element, indent=0): + if element.nodeType == Node.DOCUMENT_TYPE_NODE: + if element.name: + if element.publicId or element.systemId: + publicId = element.publicId or "" + systemId = element.systemId or "" + rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" % + (' ' * indent, element.name, publicId, systemId)) + else: + rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name)) + else: + rv.append("|%s<!DOCTYPE >" % (' ' * indent,)) + elif element.nodeType == Node.DOCUMENT_NODE: + rv.append("#document") + elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE: + rv.append("#document-fragment") + elif element.nodeType == Node.COMMENT_NODE: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue)) + elif element.nodeType == Node.TEXT_NODE: + rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue)) + else: + if (hasattr(element, "namespaceURI") and + element.namespaceURI is not None): + name = "%s %s" % (constants.prefixes[element.namespaceURI], + element.nodeName) + else: + name = element.nodeName + rv.append("|%s<%s>" % (' ' * indent, name)) + if element.hasAttributes(): + attributes = [] + for i in range(len(element.attributes)): + attr = element.attributes.item(i) + name = attr.nodeName + value = attr.value + ns = attr.namespaceURI + if ns: + name = "%s %s" % (constants.prefixes[ns], attr.localName) + else: + name = attr.nodeName + attributes.append((name, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + indent += 2 + for child in element.childNodes: + serializeElement(child, indent) + serializeElement(element, 0) + + return "\n".join(rv) + + return locals() + + +# The actual means to get a module! +getDomModule = moduleFactoryFactory(getDomBuilder) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py new file mode 100755 index 0000000..9a4aa95 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree.py @@ -0,0 +1,340 @@ +from __future__ import absolute_import, division, unicode_literals +# pylint:disable=protected-access + +from pip._vendor.six import text_type + +import re + +from . import base +from .. import _ihatexml +from .. import constants +from ..constants import namespaces +from .._utils import moduleFactoryFactory + +tag_regexp = re.compile("{([^}]*)}(.*)") + + +def getETreeBuilder(ElementTreeImplementation, fullTree=False): + ElementTree = ElementTreeImplementation + ElementTreeCommentType = ElementTree.Comment("asd").tag + + class Element(base.Node): + def __init__(self, name, namespace=None): + self._name = name + self._namespace = namespace + self._element = ElementTree.Element(self._getETreeTag(name, + namespace)) + if namespace is None: + self.nameTuple = namespaces["html"], self._name + else: + self.nameTuple = self._namespace, self._name + self.parent = None + self._childNodes = [] + self._flags = [] + + def _getETreeTag(self, name, namespace): + if namespace is None: + etree_tag = name + else: + etree_tag = "{%s}%s" % (namespace, name) + return etree_tag + + def _setName(self, name): + self._name = name + self._element.tag = self._getETreeTag(self._name, self._namespace) + + def _getName(self): + return self._name + + name = property(_getName, _setName) + + def _setNamespace(self, namespace): + self._namespace = namespace + self._element.tag = self._getETreeTag(self._name, self._namespace) + + def _getNamespace(self): + return self._namespace + + namespace = property(_getNamespace, _setNamespace) + + def _getAttributes(self): + return self._element.attrib + + def _setAttributes(self, attributes): + # Delete existing attributes first + # XXX - there may be a better way to do this... + for key in list(self._element.attrib.keys()): + del self._element.attrib[key] + for key, value in attributes.items(): + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], key[1]) + else: + name = key + self._element.set(name, value) + + attributes = property(_getAttributes, _setAttributes) + + def _getChildNodes(self): + return self._childNodes + + def _setChildNodes(self, value): + del self._element[:] + self._childNodes = [] + for element in value: + self.insertChild(element) + + childNodes = property(_getChildNodes, _setChildNodes) + + def hasContent(self): + """Return true if the node has children or text""" + return bool(self._element.text or len(self._element)) + + def appendChild(self, node): + self._childNodes.append(node) + self._element.append(node._element) + node.parent = self + + def insertBefore(self, node, refNode): + index = list(self._element).index(refNode._element) + self._element.insert(index, node._element) + node.parent = self + + def removeChild(self, node): + self._childNodes.remove(node) + self._element.remove(node._element) + node.parent = None + + def insertText(self, data, insertBefore=None): + if not(len(self._element)): + if not self._element.text: + self._element.text = "" + self._element.text += data + elif insertBefore is None: + # Insert the text as the tail of the last child element + if not self._element[-1].tail: + self._element[-1].tail = "" + self._element[-1].tail += data + else: + # Insert the text before the specified node + children = list(self._element) + index = children.index(insertBefore._element) + if index > 0: + if not self._element[index - 1].tail: + self._element[index - 1].tail = "" + self._element[index - 1].tail += data + else: + if not self._element.text: + self._element.text = "" + self._element.text += data + + def cloneNode(self): + element = type(self)(self.name, self.namespace) + for name, value in self.attributes.items(): + element.attributes[name] = value + return element + + def reparentChildren(self, newParent): + if newParent.childNodes: + newParent.childNodes[-1]._element.tail += self._element.text + else: + if not newParent._element.text: + newParent._element.text = "" + if self._element.text is not None: + newParent._element.text += self._element.text + self._element.text = "" + base.Node.reparentChildren(self, newParent) + + class Comment(Element): + def __init__(self, data): + # Use the superclass constructor to set all properties on the + # wrapper element + self._element = ElementTree.Comment(data) + self.parent = None + self._childNodes = [] + self._flags = [] + + def _getData(self): + return self._element.text + + def _setData(self, value): + self._element.text = value + + data = property(_getData, _setData) + + class DocumentType(Element): + def __init__(self, name, publicId, systemId): + Element.__init__(self, "<!DOCTYPE>") + self._element.text = name + self.publicId = publicId + self.systemId = systemId + + def _getPublicId(self): + return self._element.get("publicId", "") + + def _setPublicId(self, value): + if value is not None: + self._element.set("publicId", value) + + publicId = property(_getPublicId, _setPublicId) + + def _getSystemId(self): + return self._element.get("systemId", "") + + def _setSystemId(self, value): + if value is not None: + self._element.set("systemId", value) + + systemId = property(_getSystemId, _setSystemId) + + class Document(Element): + def __init__(self): + Element.__init__(self, "DOCUMENT_ROOT") + + class DocumentFragment(Element): + def __init__(self): + Element.__init__(self, "DOCUMENT_FRAGMENT") + + def testSerializer(element): + rv = [] + + def serializeElement(element, indent=0): + if not(hasattr(element, "tag")): + element = element.getroot() + if element.tag == "<!DOCTYPE>": + if element.get("publicId") or element.get("systemId"): + publicId = element.get("publicId") or "" + systemId = element.get("systemId") or "" + rv.append("""<!DOCTYPE %s "%s" "%s">""" % + (element.text, publicId, systemId)) + else: + rv.append("<!DOCTYPE %s>" % (element.text,)) + elif element.tag == "DOCUMENT_ROOT": + rv.append("#document") + if element.text is not None: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + if element.tail is not None: + raise TypeError("Document node cannot have tail") + if hasattr(element, "attrib") and len(element.attrib): + raise TypeError("Document node cannot have attributes") + elif element.tag == ElementTreeCommentType: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.text)) + else: + assert isinstance(element.tag, text_type), \ + "Expected unicode, got %s, %s" % (type(element.tag), element.tag) + nsmatch = tag_regexp.match(element.tag) + + if nsmatch is None: + name = element.tag + else: + ns, name = nsmatch.groups() + prefix = constants.prefixes[ns] + name = "%s %s" % (prefix, name) + rv.append("|%s<%s>" % (' ' * indent, name)) + + if hasattr(element, "attrib"): + attributes = [] + for name, value in element.attrib.items(): + nsmatch = tag_regexp.match(name) + if nsmatch is not None: + ns, name = nsmatch.groups() + prefix = constants.prefixes[ns] + attr_string = "%s %s" % (prefix, name) + else: + attr_string = name + attributes.append((attr_string, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + if element.text: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + indent += 2 + for child in element: + serializeElement(child, indent) + if element.tail: + rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail)) + serializeElement(element, 0) + + return "\n".join(rv) + + def tostring(element): # pylint:disable=unused-variable + """Serialize an element and its child nodes to a string""" + rv = [] + filter = _ihatexml.InfosetFilter() + + def serializeElement(element): + if isinstance(element, ElementTree.ElementTree): + element = element.getroot() + + if element.tag == "<!DOCTYPE>": + if element.get("publicId") or element.get("systemId"): + publicId = element.get("publicId") or "" + systemId = element.get("systemId") or "" + rv.append("""<!DOCTYPE %s PUBLIC "%s" "%s">""" % + (element.text, publicId, systemId)) + else: + rv.append("<!DOCTYPE %s>" % (element.text,)) + elif element.tag == "DOCUMENT_ROOT": + if element.text is not None: + rv.append(element.text) + if element.tail is not None: + raise TypeError("Document node cannot have tail") + if hasattr(element, "attrib") and len(element.attrib): + raise TypeError("Document node cannot have attributes") + + for child in element: + serializeElement(child) + + elif element.tag == ElementTreeCommentType: + rv.append("<!--%s-->" % (element.text,)) + else: + # This is assumed to be an ordinary element + if not element.attrib: + rv.append("<%s>" % (filter.fromXmlName(element.tag),)) + else: + attr = " ".join(["%s=\"%s\"" % ( + filter.fromXmlName(name), value) + for name, value in element.attrib.items()]) + rv.append("<%s %s>" % (element.tag, attr)) + if element.text: + rv.append(element.text) + + for child in element: + serializeElement(child) + + rv.append("</%s>" % (element.tag,)) + + if element.tail: + rv.append(element.tail) + + serializeElement(element) + + return "".join(rv) + + class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable + documentClass = Document + doctypeClass = DocumentType + elementClass = Element + commentClass = Comment + fragmentClass = DocumentFragment + implementation = ElementTreeImplementation + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + if fullTree: + return self.document._element + else: + if self.defaultNamespace is not None: + return self.document._element.find( + "{%s}html" % self.defaultNamespace) + else: + return self.document._element.find("html") + + def getFragment(self): + return base.TreeBuilder.getFragment(self)._element + + return locals() + + +getETreeModule = moduleFactoryFactory(getETreeBuilder) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py new file mode 100755 index 0000000..66a9ba3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treebuilders/etree_lxml.py @@ -0,0 +1,366 @@ +"""Module for supporting the lxml.etree library. The idea here is to use as much +of the native library as possible, without using fragile hacks like custom element +names that break between releases. The downside of this is that we cannot represent +all possible trees; specifically the following are known to cause problems: + +Text or comments as siblings of the root element +Docypes with no name + +When any of these things occur, we emit a DataLossWarning +""" + +from __future__ import absolute_import, division, unicode_literals +# pylint:disable=protected-access + +import warnings +import re +import sys + +from . import base +from ..constants import DataLossWarning +from .. import constants +from . import etree as etree_builders +from .. import _ihatexml + +import lxml.etree as etree + + +fullTree = True +tag_regexp = re.compile("{([^}]*)}(.*)") + +comment_type = etree.Comment("asd").tag + + +class DocumentType(object): + def __init__(self, name, publicId, systemId): + self.name = name + self.publicId = publicId + self.systemId = systemId + + +class Document(object): + def __init__(self): + self._elementTree = None + self._childNodes = [] + + def appendChild(self, element): + self._elementTree.getroot().addnext(element._element) + + def _getChildNodes(self): + return self._childNodes + + childNodes = property(_getChildNodes) + + +def testSerializer(element): + rv = [] + infosetFilter = _ihatexml.InfosetFilter(preventDoubleDashComments=True) + + def serializeElement(element, indent=0): + if not hasattr(element, "tag"): + if hasattr(element, "getroot"): + # Full tree case + rv.append("#document") + if element.docinfo.internalDTD: + if not (element.docinfo.public_id or + element.docinfo.system_url): + dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name + else: + dtd_str = """<!DOCTYPE %s "%s" "%s">""" % ( + element.docinfo.root_name, + element.docinfo.public_id, + element.docinfo.system_url) + rv.append("|%s%s" % (' ' * (indent + 2), dtd_str)) + next_element = element.getroot() + while next_element.getprevious() is not None: + next_element = next_element.getprevious() + while next_element is not None: + serializeElement(next_element, indent + 2) + next_element = next_element.getnext() + elif isinstance(element, str) or isinstance(element, bytes): + # Text in a fragment + assert isinstance(element, str) or sys.version_info[0] == 2 + rv.append("|%s\"%s\"" % (' ' * indent, element)) + else: + # Fragment case + rv.append("#document-fragment") + for next_element in element: + serializeElement(next_element, indent + 2) + elif element.tag == comment_type: + rv.append("|%s<!-- %s -->" % (' ' * indent, element.text)) + if hasattr(element, "tail") and element.tail: + rv.append("|%s\"%s\"" % (' ' * indent, element.tail)) + else: + assert isinstance(element, etree._Element) + nsmatch = etree_builders.tag_regexp.match(element.tag) + if nsmatch is not None: + ns = nsmatch.group(1) + tag = nsmatch.group(2) + prefix = constants.prefixes[ns] + rv.append("|%s<%s %s>" % (' ' * indent, prefix, + infosetFilter.fromXmlName(tag))) + else: + rv.append("|%s<%s>" % (' ' * indent, + infosetFilter.fromXmlName(element.tag))) + + if hasattr(element, "attrib"): + attributes = [] + for name, value in element.attrib.items(): + nsmatch = tag_regexp.match(name) + if nsmatch is not None: + ns, name = nsmatch.groups() + name = infosetFilter.fromXmlName(name) + prefix = constants.prefixes[ns] + attr_string = "%s %s" % (prefix, name) + else: + attr_string = infosetFilter.fromXmlName(name) + attributes.append((attr_string, value)) + + for name, value in sorted(attributes): + rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value)) + + if element.text: + rv.append("|%s\"%s\"" % (' ' * (indent + 2), element.text)) + indent += 2 + for child in element: + serializeElement(child, indent) + if hasattr(element, "tail") and element.tail: + rv.append("|%s\"%s\"" % (' ' * (indent - 2), element.tail)) + serializeElement(element, 0) + + return "\n".join(rv) + + +def tostring(element): + """Serialize an element and its child nodes to a string""" + rv = [] + + def serializeElement(element): + if not hasattr(element, "tag"): + if element.docinfo.internalDTD: + if element.docinfo.doctype: + dtd_str = element.docinfo.doctype + else: + dtd_str = "<!DOCTYPE %s>" % element.docinfo.root_name + rv.append(dtd_str) + serializeElement(element.getroot()) + + elif element.tag == comment_type: + rv.append("<!--%s-->" % (element.text,)) + + else: + # This is assumed to be an ordinary element + if not element.attrib: + rv.append("<%s>" % (element.tag,)) + else: + attr = " ".join(["%s=\"%s\"" % (name, value) + for name, value in element.attrib.items()]) + rv.append("<%s %s>" % (element.tag, attr)) + if element.text: + rv.append(element.text) + + for child in element: + serializeElement(child) + + rv.append("</%s>" % (element.tag,)) + + if hasattr(element, "tail") and element.tail: + rv.append(element.tail) + + serializeElement(element) + + return "".join(rv) + + +class TreeBuilder(base.TreeBuilder): + documentClass = Document + doctypeClass = DocumentType + elementClass = None + commentClass = None + fragmentClass = Document + implementation = etree + + def __init__(self, namespaceHTMLElements, fullTree=False): + builder = etree_builders.getETreeModule(etree, fullTree=fullTree) + infosetFilter = self.infosetFilter = _ihatexml.InfosetFilter(preventDoubleDashComments=True) + self.namespaceHTMLElements = namespaceHTMLElements + + class Attributes(dict): + def __init__(self, element, value=None): + if value is None: + value = {} + self._element = element + dict.__init__(self, value) # pylint:disable=non-parent-init-called + for key, value in self.items(): + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1])) + else: + name = infosetFilter.coerceAttribute(key) + self._element._element.attrib[name] = value + + def __setitem__(self, key, value): + dict.__setitem__(self, key, value) + if isinstance(key, tuple): + name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1])) + else: + name = infosetFilter.coerceAttribute(key) + self._element._element.attrib[name] = value + + class Element(builder.Element): + def __init__(self, name, namespace): + name = infosetFilter.coerceElement(name) + builder.Element.__init__(self, name, namespace=namespace) + self._attributes = Attributes(self) + + def _setName(self, name): + self._name = infosetFilter.coerceElement(name) + self._element.tag = self._getETreeTag( + self._name, self._namespace) + + def _getName(self): + return infosetFilter.fromXmlName(self._name) + + name = property(_getName, _setName) + + def _getAttributes(self): + return self._attributes + + def _setAttributes(self, attributes): + self._attributes = Attributes(self, attributes) + + attributes = property(_getAttributes, _setAttributes) + + def insertText(self, data, insertBefore=None): + data = infosetFilter.coerceCharacters(data) + builder.Element.insertText(self, data, insertBefore) + + def appendChild(self, child): + builder.Element.appendChild(self, child) + + class Comment(builder.Comment): + def __init__(self, data): + data = infosetFilter.coerceComment(data) + builder.Comment.__init__(self, data) + + def _setData(self, data): + data = infosetFilter.coerceComment(data) + self._element.text = data + + def _getData(self): + return self._element.text + + data = property(_getData, _setData) + + self.elementClass = Element + self.commentClass = Comment + # self.fragmentClass = builder.DocumentFragment + base.TreeBuilder.__init__(self, namespaceHTMLElements) + + def reset(self): + base.TreeBuilder.reset(self) + self.insertComment = self.insertCommentInitial + self.initial_comments = [] + self.doctype = None + + def testSerializer(self, element): + return testSerializer(element) + + def getDocument(self): + if fullTree: + return self.document._elementTree + else: + return self.document._elementTree.getroot() + + def getFragment(self): + fragment = [] + element = self.openElements[0]._element + if element.text: + fragment.append(element.text) + fragment.extend(list(element)) + if element.tail: + fragment.append(element.tail) + return fragment + + def insertDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + + if not name: + warnings.warn("lxml cannot represent empty doctype", DataLossWarning) + self.doctype = None + else: + coercedName = self.infosetFilter.coerceElement(name) + if coercedName != name: + warnings.warn("lxml cannot represent non-xml doctype", DataLossWarning) + + doctype = self.doctypeClass(coercedName, publicId, systemId) + self.doctype = doctype + + def insertCommentInitial(self, data, parent=None): + assert parent is None or parent is self.document + assert self.document._elementTree is None + self.initial_comments.append(data) + + def insertCommentMain(self, data, parent=None): + if (parent == self.document and + self.document._elementTree.getroot()[-1].tag == comment_type): + warnings.warn("lxml cannot represent adjacent comments beyond the root elements", DataLossWarning) + super(TreeBuilder, self).insertComment(data, parent) + + def insertRoot(self, token): + # Because of the way libxml2 works, it doesn't seem to be possible to + # alter information like the doctype after the tree has been parsed. + # Therefore we need to use the built-in parser to create our initial + # tree, after which we can add elements like normal + docStr = "" + if self.doctype: + assert self.doctype.name + docStr += "<!DOCTYPE %s" % self.doctype.name + if (self.doctype.publicId is not None or + self.doctype.systemId is not None): + docStr += (' PUBLIC "%s" ' % + (self.infosetFilter.coercePubid(self.doctype.publicId or ""))) + if self.doctype.systemId: + sysid = self.doctype.systemId + if sysid.find("'") >= 0 and sysid.find('"') >= 0: + warnings.warn("DOCTYPE system cannot contain single and double quotes", DataLossWarning) + sysid = sysid.replace("'", 'U00027') + if sysid.find("'") >= 0: + docStr += '"%s"' % sysid + else: + docStr += "'%s'" % sysid + else: + docStr += "''" + docStr += ">" + if self.doctype.name != token["name"]: + warnings.warn("lxml cannot represent doctype with a different name to the root element", DataLossWarning) + docStr += "<THIS_SHOULD_NEVER_APPEAR_PUBLICLY/>" + root = etree.fromstring(docStr) + + # Append the initial comments: + for comment_token in self.initial_comments: + comment = self.commentClass(comment_token["data"]) + root.addprevious(comment._element) + + # Create the root document and add the ElementTree to it + self.document = self.documentClass() + self.document._elementTree = root.getroottree() + + # Give the root element the right name + name = token["name"] + namespace = token.get("namespace", self.defaultNamespace) + if namespace is None: + etree_tag = name + else: + etree_tag = "{%s}%s" % (namespace, name) + root.tag = etree_tag + + # Add the root element to the internal child/open data structures + root_element = self.elementClass(name, namespace) + root_element._element = root + self.document._childNodes.append(root_element) + self.openElements.append(root_element) + + # Reset to the default insert comment function + self.insertComment = self.insertCommentMain diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py new file mode 100755 index 0000000..31a173d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/__init__.py @@ -0,0 +1,154 @@ +"""A collection of modules for iterating through different kinds of +tree, generating tokens identical to those produced by the tokenizer +module. + +To create a tree walker for a new type of tree, you need to do +implement a tree walker object (called TreeWalker by convention) that +implements a 'serialize' method taking a tree as sole argument and +returning an iterator generating tokens. +""" + +from __future__ import absolute_import, division, unicode_literals + +from .. import constants +from .._utils import default_etree + +__all__ = ["getTreeWalker", "pprint"] + +treeWalkerCache = {} + + +def getTreeWalker(treeType, implementation=None, **kwargs): + """Get a TreeWalker class for various types of tree with built-in support + + :arg str treeType: the name of the tree type required (case-insensitive). + Supported values are: + + * "dom": The xml.dom.minidom DOM implementation + * "etree": A generic walker for tree implementations exposing an + elementtree-like interface (known to work with ElementTree, + cElementTree and lxml.etree). + * "lxml": Optimized walker for lxml.etree + * "genshi": a Genshi stream + + :arg implementation: A module implementing the tree type e.g. + xml.etree.ElementTree or cElementTree (Currently applies to the "etree" + tree type only). + + :arg kwargs: keyword arguments passed to the etree walker--for other + walkers, this has no effect + + :returns: a TreeWalker class + + """ + + treeType = treeType.lower() + if treeType not in treeWalkerCache: + if treeType == "dom": + from . import dom + treeWalkerCache[treeType] = dom.TreeWalker + elif treeType == "genshi": + from . import genshi + treeWalkerCache[treeType] = genshi.TreeWalker + elif treeType == "lxml": + from . import etree_lxml + treeWalkerCache[treeType] = etree_lxml.TreeWalker + elif treeType == "etree": + from . import etree + if implementation is None: + implementation = default_etree + # XXX: NEVER cache here, caching is done in the etree submodule + return etree.getETreeModule(implementation, **kwargs).TreeWalker + return treeWalkerCache.get(treeType) + + +def concatenateCharacterTokens(tokens): + pendingCharacters = [] + for token in tokens: + type = token["type"] + if type in ("Characters", "SpaceCharacters"): + pendingCharacters.append(token["data"]) + else: + if pendingCharacters: + yield {"type": "Characters", "data": "".join(pendingCharacters)} + pendingCharacters = [] + yield token + if pendingCharacters: + yield {"type": "Characters", "data": "".join(pendingCharacters)} + + +def pprint(walker): + """Pretty printer for tree walkers + + Takes a TreeWalker instance and pretty prints the output of walking the tree. + + :arg walker: a TreeWalker instance + + """ + output = [] + indent = 0 + for token in concatenateCharacterTokens(walker): + type = token["type"] + if type in ("StartTag", "EmptyTag"): + # tag name + if token["namespace"] and token["namespace"] != constants.namespaces["html"]: + if token["namespace"] in constants.prefixes: + ns = constants.prefixes[token["namespace"]] + else: + ns = token["namespace"] + name = "%s %s" % (ns, token["name"]) + else: + name = token["name"] + output.append("%s<%s>" % (" " * indent, name)) + indent += 2 + # attributes (sorted for consistent ordering) + attrs = token["data"] + for (namespace, localname), value in sorted(attrs.items()): + if namespace: + if namespace in constants.prefixes: + ns = constants.prefixes[namespace] + else: + ns = namespace + name = "%s %s" % (ns, localname) + else: + name = localname + output.append("%s%s=\"%s\"" % (" " * indent, name, value)) + # self-closing + if type == "EmptyTag": + indent -= 2 + + elif type == "EndTag": + indent -= 2 + + elif type == "Comment": + output.append("%s<!-- %s -->" % (" " * indent, token["data"])) + + elif type == "Doctype": + if token["name"]: + if token["publicId"]: + output.append("""%s<!DOCTYPE %s "%s" "%s">""" % + (" " * indent, + token["name"], + token["publicId"], + token["systemId"] if token["systemId"] else "")) + elif token["systemId"]: + output.append("""%s<!DOCTYPE %s "" "%s">""" % + (" " * indent, + token["name"], + token["systemId"])) + else: + output.append("%s<!DOCTYPE %s>" % (" " * indent, + token["name"])) + else: + output.append("%s<!DOCTYPE >" % (" " * indent,)) + + elif type == "Characters": + output.append("%s\"%s\"" % (" " * indent, token["data"])) + + elif type == "SpaceCharacters": + assert False, "concatenateCharacterTokens should have got rid of all Space tokens" + + else: + raise ValueError("Unknown token type, %s" % type) + + return "\n".join(output) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py new file mode 100755 index 0000000..f82984b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/base.py @@ -0,0 +1,252 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.dom import Node +from ..constants import namespaces, voidElements, spaceCharacters + +__all__ = ["DOCUMENT", "DOCTYPE", "TEXT", "ELEMENT", "COMMENT", "ENTITY", "UNKNOWN", + "TreeWalker", "NonRecursiveTreeWalker"] + +DOCUMENT = Node.DOCUMENT_NODE +DOCTYPE = Node.DOCUMENT_TYPE_NODE +TEXT = Node.TEXT_NODE +ELEMENT = Node.ELEMENT_NODE +COMMENT = Node.COMMENT_NODE +ENTITY = Node.ENTITY_NODE +UNKNOWN = "<#UNKNOWN#>" + +spaceCharacters = "".join(spaceCharacters) + + +class TreeWalker(object): + """Walks a tree yielding tokens + + Tokens are dicts that all have a ``type`` field specifying the type of the + token. + + """ + def __init__(self, tree): + """Creates a TreeWalker + + :arg tree: the tree to walk + + """ + self.tree = tree + + def __iter__(self): + raise NotImplementedError + + def error(self, msg): + """Generates an error token with the given message + + :arg msg: the error message + + :returns: SerializeError token + + """ + return {"type": "SerializeError", "data": msg} + + def emptyTag(self, namespace, name, attrs, hasChildren=False): + """Generates an EmptyTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :arg attrs: the attributes of the element as a dict + + :arg hasChildren: whether or not to yield a SerializationError because + this tag shouldn't have children + + :returns: EmptyTag token + + """ + yield {"type": "EmptyTag", "name": name, + "namespace": namespace, + "data": attrs} + if hasChildren: + yield self.error("Void element has children") + + def startTag(self, namespace, name, attrs): + """Generates a StartTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :arg attrs: the attributes of the element as a dict + + :returns: StartTag token + + """ + return {"type": "StartTag", + "name": name, + "namespace": namespace, + "data": attrs} + + def endTag(self, namespace, name): + """Generates an EndTag token + + :arg namespace: the namespace of the token--can be ``None`` + + :arg name: the name of the element + + :returns: EndTag token + + """ + return {"type": "EndTag", + "name": name, + "namespace": namespace} + + def text(self, data): + """Generates SpaceCharacters and Characters tokens + + Depending on what's in the data, this generates one or more + ``SpaceCharacters`` and ``Characters`` tokens. + + For example: + + >>> from html5lib.treewalkers.base import TreeWalker + >>> # Give it an empty tree just so it instantiates + >>> walker = TreeWalker([]) + >>> list(walker.text('')) + [] + >>> list(walker.text(' ')) + [{u'data': ' ', u'type': u'SpaceCharacters'}] + >>> list(walker.text(' abc ')) # doctest: +NORMALIZE_WHITESPACE + [{u'data': ' ', u'type': u'SpaceCharacters'}, + {u'data': u'abc', u'type': u'Characters'}, + {u'data': u' ', u'type': u'SpaceCharacters'}] + + :arg data: the text data + + :returns: one or more ``SpaceCharacters`` and ``Characters`` tokens + + """ + data = data + middle = data.lstrip(spaceCharacters) + left = data[:len(data) - len(middle)] + if left: + yield {"type": "SpaceCharacters", "data": left} + data = middle + middle = data.rstrip(spaceCharacters) + right = data[len(middle):] + if middle: + yield {"type": "Characters", "data": middle} + if right: + yield {"type": "SpaceCharacters", "data": right} + + def comment(self, data): + """Generates a Comment token + + :arg data: the comment + + :returns: Comment token + + """ + return {"type": "Comment", "data": data} + + def doctype(self, name, publicId=None, systemId=None): + """Generates a Doctype token + + :arg name: + + :arg publicId: + + :arg systemId: + + :returns: the Doctype token + + """ + return {"type": "Doctype", + "name": name, + "publicId": publicId, + "systemId": systemId} + + def entity(self, name): + """Generates an Entity token + + :arg name: the entity name + + :returns: an Entity token + + """ + return {"type": "Entity", "name": name} + + def unknown(self, nodeType): + """Handles unknown node types""" + return self.error("Unknown node type: " + nodeType) + + +class NonRecursiveTreeWalker(TreeWalker): + def getNodeDetails(self, node): + raise NotImplementedError + + def getFirstChild(self, node): + raise NotImplementedError + + def getNextSibling(self, node): + raise NotImplementedError + + def getParentNode(self, node): + raise NotImplementedError + + def __iter__(self): + currentNode = self.tree + while currentNode is not None: + details = self.getNodeDetails(currentNode) + type, details = details[0], details[1:] + hasChildren = False + + if type == DOCTYPE: + yield self.doctype(*details) + + elif type == TEXT: + for token in self.text(*details): + yield token + + elif type == ELEMENT: + namespace, name, attributes, hasChildren = details + if (not namespace or namespace == namespaces["html"]) and name in voidElements: + for token in self.emptyTag(namespace, name, attributes, + hasChildren): + yield token + hasChildren = False + else: + yield self.startTag(namespace, name, attributes) + + elif type == COMMENT: + yield self.comment(details[0]) + + elif type == ENTITY: + yield self.entity(details[0]) + + elif type == DOCUMENT: + hasChildren = True + + else: + yield self.unknown(details[0]) + + if hasChildren: + firstChild = self.getFirstChild(currentNode) + else: + firstChild = None + + if firstChild is not None: + currentNode = firstChild + else: + while currentNode is not None: + details = self.getNodeDetails(currentNode) + type, details = details[0], details[1:] + if type == ELEMENT: + namespace, name, attributes, hasChildren = details + if (namespace and namespace != namespaces["html"]) or name not in voidElements: + yield self.endTag(namespace, name) + if self.tree is currentNode: + currentNode = None + break + nextSibling = self.getNextSibling(currentNode) + if nextSibling is not None: + currentNode = nextSibling + break + else: + currentNode = self.getParentNode(currentNode) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py new file mode 100755 index 0000000..b3e2753 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/dom.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import, division, unicode_literals + +from xml.dom import Node + +from . import base + + +class TreeWalker(base.NonRecursiveTreeWalker): + def getNodeDetails(self, node): + if node.nodeType == Node.DOCUMENT_TYPE_NODE: + return base.DOCTYPE, node.name, node.publicId, node.systemId + + elif node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): + return base.TEXT, node.nodeValue + + elif node.nodeType == Node.ELEMENT_NODE: + attrs = {} + for attr in list(node.attributes.keys()): + attr = node.getAttributeNode(attr) + if attr.namespaceURI: + attrs[(attr.namespaceURI, attr.localName)] = attr.value + else: + attrs[(None, attr.name)] = attr.value + return (base.ELEMENT, node.namespaceURI, node.nodeName, + attrs, node.hasChildNodes()) + + elif node.nodeType == Node.COMMENT_NODE: + return base.COMMENT, node.nodeValue + + elif node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE): + return (base.DOCUMENT,) + + else: + return base.UNKNOWN, node.nodeType + + def getFirstChild(self, node): + return node.firstChild + + def getNextSibling(self, node): + return node.nextSibling + + def getParentNode(self, node): + return node.parentNode diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py new file mode 100755 index 0000000..1a35add --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import, division, unicode_literals + +from collections import OrderedDict +import re + +from pip._vendor.six import string_types + +from . import base +from .._utils import moduleFactoryFactory + +tag_regexp = re.compile("{([^}]*)}(.*)") + + +def getETreeBuilder(ElementTreeImplementation): + ElementTree = ElementTreeImplementation + ElementTreeCommentType = ElementTree.Comment("asd").tag + + class TreeWalker(base.NonRecursiveTreeWalker): # pylint:disable=unused-variable + """Given the particular ElementTree representation, this implementation, + to avoid using recursion, returns "nodes" as tuples with the following + content: + + 1. The current element + + 2. The index of the element relative to its parent + + 3. A stack of ancestor elements + + 4. A flag "text", "tail" or None to indicate if the current node is a + text node; either the text or tail of the current element (1) + """ + def getNodeDetails(self, node): + if isinstance(node, tuple): # It might be the root Element + elt, _, _, flag = node + if flag in ("text", "tail"): + return base.TEXT, getattr(elt, flag) + else: + node = elt + + if not(hasattr(node, "tag")): + node = node.getroot() + + if node.tag in ("DOCUMENT_ROOT", "DOCUMENT_FRAGMENT"): + return (base.DOCUMENT,) + + elif node.tag == "<!DOCTYPE>": + return (base.DOCTYPE, node.text, + node.get("publicId"), node.get("systemId")) + + elif node.tag == ElementTreeCommentType: + return base.COMMENT, node.text + + else: + assert isinstance(node.tag, string_types), type(node.tag) + # This is assumed to be an ordinary element + match = tag_regexp.match(node.tag) + if match: + namespace, tag = match.groups() + else: + namespace = None + tag = node.tag + attrs = OrderedDict() + for name, value in list(node.attrib.items()): + match = tag_regexp.match(name) + if match: + attrs[(match.group(1), match.group(2))] = value + else: + attrs[(None, name)] = value + return (base.ELEMENT, namespace, tag, + attrs, len(node) or node.text) + + def getFirstChild(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + element, key, parents, flag = node, None, [], None + + if flag in ("text", "tail"): + return None + else: + if element.text: + return element, key, parents, "text" + elif len(element): + parents.append(element) + return element[0], 0, parents, None + else: + return None + + def getNextSibling(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + return None + + if flag == "text": + if len(element): + parents.append(element) + return element[0], 0, parents, None + else: + return None + else: + if element.tail and flag != "tail": + return element, key, parents, "tail" + elif key < len(parents[-1]) - 1: + return parents[-1][key + 1], key + 1, parents, None + else: + return None + + def getParentNode(self, node): + if isinstance(node, tuple): + element, key, parents, flag = node + else: + return None + + if flag == "text": + if not parents: + return element + else: + return element, key, parents, None + else: + parent = parents.pop() + if not parents: + return parent + else: + assert list(parents[-1]).count(parent) == 1 + return parent, list(parents[-1]).index(parent), parents, None + + return locals() + +getETreeModule = moduleFactoryFactory(getETreeBuilder) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py new file mode 100755 index 0000000..f6f395a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/etree_lxml.py @@ -0,0 +1,213 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import text_type + +from lxml import etree +from ..treebuilders.etree import tag_regexp + +from . import base + +from .. import _ihatexml + + +def ensure_str(s): + if s is None: + return None + elif isinstance(s, text_type): + return s + else: + return s.decode("ascii", "strict") + + +class Root(object): + def __init__(self, et): + self.elementtree = et + self.children = [] + + try: + if et.docinfo.internalDTD: + self.children.append(Doctype(self, + ensure_str(et.docinfo.root_name), + ensure_str(et.docinfo.public_id), + ensure_str(et.docinfo.system_url))) + except AttributeError: + pass + + try: + node = et.getroot() + except AttributeError: + node = et + + while node.getprevious() is not None: + node = node.getprevious() + while node is not None: + self.children.append(node) + node = node.getnext() + + self.text = None + self.tail = None + + def __getitem__(self, key): + return self.children[key] + + def getnext(self): + return None + + def __len__(self): + return 1 + + +class Doctype(object): + def __init__(self, root_node, name, public_id, system_id): + self.root_node = root_node + self.name = name + self.public_id = public_id + self.system_id = system_id + + self.text = None + self.tail = None + + def getnext(self): + return self.root_node.children[1] + + +class FragmentRoot(Root): + def __init__(self, children): + self.children = [FragmentWrapper(self, child) for child in children] + self.text = self.tail = None + + def getnext(self): + return None + + +class FragmentWrapper(object): + def __init__(self, fragment_root, obj): + self.root_node = fragment_root + self.obj = obj + if hasattr(self.obj, 'text'): + self.text = ensure_str(self.obj.text) + else: + self.text = None + if hasattr(self.obj, 'tail'): + self.tail = ensure_str(self.obj.tail) + else: + self.tail = None + + def __getattr__(self, name): + return getattr(self.obj, name) + + def getnext(self): + siblings = self.root_node.children + idx = siblings.index(self) + if idx < len(siblings) - 1: + return siblings[idx + 1] + else: + return None + + def __getitem__(self, key): + return self.obj[key] + + def __bool__(self): + return bool(self.obj) + + def getparent(self): + return None + + def __str__(self): + return str(self.obj) + + def __unicode__(self): + return str(self.obj) + + def __len__(self): + return len(self.obj) + + +class TreeWalker(base.NonRecursiveTreeWalker): + def __init__(self, tree): + # pylint:disable=redefined-variable-type + if isinstance(tree, list): + self.fragmentChildren = set(tree) + tree = FragmentRoot(tree) + else: + self.fragmentChildren = set() + tree = Root(tree) + base.NonRecursiveTreeWalker.__init__(self, tree) + self.filter = _ihatexml.InfosetFilter() + + def getNodeDetails(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + return base.TEXT, ensure_str(getattr(node, key)) + + elif isinstance(node, Root): + return (base.DOCUMENT,) + + elif isinstance(node, Doctype): + return base.DOCTYPE, node.name, node.public_id, node.system_id + + elif isinstance(node, FragmentWrapper) and not hasattr(node, "tag"): + return base.TEXT, ensure_str(node.obj) + + elif node.tag == etree.Comment: + return base.COMMENT, ensure_str(node.text) + + elif node.tag == etree.Entity: + return base.ENTITY, ensure_str(node.text)[1:-1] # strip &; + + else: + # This is assumed to be an ordinary element + match = tag_regexp.match(ensure_str(node.tag)) + if match: + namespace, tag = match.groups() + else: + namespace = None + tag = ensure_str(node.tag) + attrs = {} + for name, value in list(node.attrib.items()): + name = ensure_str(name) + value = ensure_str(value) + match = tag_regexp.match(name) + if match: + attrs[(match.group(1), match.group(2))] = value + else: + attrs[(None, name)] = value + return (base.ELEMENT, namespace, self.filter.fromXmlName(tag), + attrs, len(node) > 0 or node.text) + + def getFirstChild(self, node): + assert not isinstance(node, tuple), "Text nodes have no children" + + assert len(node) or node.text, "Node has no children" + if node.text: + return (node, "text") + else: + return node[0] + + def getNextSibling(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + if key == "text": + # XXX: we cannot use a "bool(node) and node[0] or None" construct here + # because node[0] might evaluate to False if it has no child element + if len(node): + return node[0] + else: + return None + else: # tail + return node.getnext() + + return (node, "tail") if node.tail else node.getnext() + + def getParentNode(self, node): + if isinstance(node, tuple): # Text node + node, key = node + assert key in ("text", "tail"), "Text nodes are text or tail, found %s" % key + if key == "text": + return node + # else: fallback to "normal" processing + elif node in self.fragmentChildren: + return None + + return node.getparent() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py new file mode 100755 index 0000000..42cd559 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/html5lib/treewalkers/genshi.py @@ -0,0 +1,69 @@ +from __future__ import absolute_import, division, unicode_literals + +from genshi.core import QName +from genshi.core import START, END, XML_NAMESPACE, DOCTYPE, TEXT +from genshi.core import START_NS, END_NS, START_CDATA, END_CDATA, PI, COMMENT + +from . import base + +from ..constants import voidElements, namespaces + + +class TreeWalker(base.TreeWalker): + def __iter__(self): + # Buffer the events so we can pass in the following one + previous = None + for event in self.tree: + if previous is not None: + for token in self.tokens(previous, event): + yield token + previous = event + + # Don't forget the final event! + if previous is not None: + for token in self.tokens(previous, None): + yield token + + def tokens(self, event, next): + kind, data, _ = event + if kind == START: + tag, attribs = data + name = tag.localname + namespace = tag.namespace + converted_attribs = {} + for k, v in attribs: + if isinstance(k, QName): + converted_attribs[(k.namespace, k.localname)] = v + else: + converted_attribs[(None, k)] = v + + if namespace == namespaces["html"] and name in voidElements: + for token in self.emptyTag(namespace, name, converted_attribs, + not next or next[0] != END or + next[1] != tag): + yield token + else: + yield self.startTag(namespace, name, converted_attribs) + + elif kind == END: + name = data.localname + namespace = data.namespace + if namespace != namespaces["html"] or name not in voidElements: + yield self.endTag(namespace, name) + + elif kind == COMMENT: + yield self.comment(data) + + elif kind == TEXT: + for token in self.text(data): + yield token + + elif kind == DOCTYPE: + yield self.doctype(*data) + + elif kind in (XML_NAMESPACE, DOCTYPE, START_NS, END_NS, + START_CDATA, END_CDATA, PI): + pass + + else: + yield self.unknown(kind) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py new file mode 100755 index 0000000..4ed56a1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/__init__.py @@ -0,0 +1,2 @@ +from .package_data import __version__ +from .core import * diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/codec.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/codec.py new file mode 100755 index 0000000..65b06e2 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/compat.py new file mode 100755 index 0000000..f4d3f6d --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py new file mode 100755 index 0000000..944ff98 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/core.py @@ -0,0 +1,387 @@ +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): + return unicodedata.combining(unichr(cp)) + +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 + break + 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']): + 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))) + 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') + try: + ulabel(label) + except IDNAError: + raise IDNAError('The label {0} is not a valid A-label'.format(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):] + 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 std3_rules and replacement is None)): + output += char + elif replacement is not None and (status == "M" or + (status == "3" and 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) + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if labels[-1] == '': + del labels[-1] + trailing_dot = True + for label in labels: + result.append(alabel(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'.') + while labels and not labels[0]: + del labels[0] + if not labels: + raise IDNAError('Empty domain') + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + result.append(ulabel(label)) + if trailing_dot: + result.append(u'') + return u'.'.join(result) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py new file mode 100755 index 0000000..c197a69 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/idnadata.py @@ -0,0 +1,1585 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "6.3.0" +scripts = { + 'Greek': ( + 0x37000000374, + 0x37500000378, + 0x37a0000037e, + 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, + 0x101400001018b, + 0x1d2000001d246, + ), + 'Han': ( + 0x2e8000002e9a, + 0x2e9b00002ef4, + 0x2f0000002fd6, + 0x300500003006, + 0x300700003008, + 0x30210000302a, + 0x30380000303c, + 0x340000004db6, + 0x4e0000009fcd, + 0xf9000000fa6e, + 0xfa700000fada, + 0x200000002a6d7, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2f8000002fa1e, + ), + 'Hebrew': ( + 0x591000005c8, + 0x5d0000005eb, + 0x5f0000005f5, + 0xfb1d0000fb37, + 0xfb380000fb3d, + 0xfb3e0000fb3f, + 0xfb400000fb42, + 0xfb430000fb45, + 0xfb460000fb50, + ), + 'Hiragana': ( + 0x304100003097, + 0x309d000030a0, + 0x1b0010001b002, + 0x1f2000001f201, + ), + 'Katakana': ( + 0x30a1000030fb, + 0x30fd00003100, + 0x31f000003200, + 0x32d0000032ff, + 0x330000003358, + 0xff660000ff70, + 0xff710000ff9e, + 0x1b0000001b001, + ), +} +joining_types = { + 0x600: 85, + 0x601: 85, + 0x602: 85, + 0x603: 85, + 0x604: 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, + 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: 68, + 0x848: 68, + 0x849: 82, + 0x84a: 68, + 0x84b: 68, + 0x84c: 68, + 0x84d: 68, + 0x84e: 68, + 0x84f: 82, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 85, + 0x857: 85, + 0x858: 85, + 0x8a0: 68, + 0x8a2: 68, + 0x8a3: 68, + 0x8a4: 68, + 0x8a5: 68, + 0x8a6: 68, + 0x8a7: 68, + 0x8a8: 68, + 0x8a9: 68, + 0x8aa: 82, + 0x8ab: 82, + 0x8ac: 82, + 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, + 0x1880: 85, + 0x1881: 85, + 0x1882: 85, + 0x1883: 85, + 0x1884: 85, + 0x1885: 85, + 0x1886: 85, + 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, + 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, +} +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, + 0x5590000055a, + 0x56100000587, + 0x591000005be, + 0x5bf000005c0, + 0x5c1000005c3, + 0x5c4000005c6, + 0x5c7000005c8, + 0x5d0000005eb, + 0x5f0000005f3, + 0x6100000061b, + 0x62000000640, + 0x64100000660, + 0x66e00000675, + 0x679000006d4, + 0x6d5000006dd, + 0x6df000006e9, + 0x6ea000006f0, + 0x6fa00000700, + 0x7100000074b, + 0x74d000007b2, + 0x7c0000007f6, + 0x8000000082e, + 0x8400000085c, + 0x8a0000008a1, + 0x8a2000008ad, + 0x8e4000008ff, + 0x90000000958, + 0x96000000964, + 0x96600000970, + 0x97100000978, + 0x97900000980, + 0x98100000984, + 0x9850000098d, + 0x98f00000991, + 0x993000009a9, + 0x9aa000009b1, + 0x9b2000009b3, + 0x9b6000009ba, + 0x9bc000009c5, + 0x9c7000009c9, + 0x9cb000009cf, + 0x9d7000009d8, + 0x9e0000009e4, + 0x9e6000009f2, + 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, + 0xb0100000b04, + 0xb0500000b0d, + 0xb0f00000b11, + 0xb1300000b29, + 0xb2a00000b31, + 0xb3200000b34, + 0xb3500000b3a, + 0xb3c00000b45, + 0xb4700000b49, + 0xb4b00000b4e, + 0xb5600000b58, + 0xb5f00000b64, + 0xb6600000b70, + 0xb7100000b72, + 0xb8200000b84, + 0xb8500000b8b, + 0xb8e00000b91, + 0xb9200000b96, + 0xb9900000b9b, + 0xb9c00000b9d, + 0xb9e00000ba0, + 0xba300000ba5, + 0xba800000bab, + 0xbae00000bba, + 0xbbe00000bc3, + 0xbc600000bc9, + 0xbca00000bce, + 0xbd000000bd1, + 0xbd700000bd8, + 0xbe600000bf0, + 0xc0100000c04, + 0xc0500000c0d, + 0xc0e00000c11, + 0xc1200000c29, + 0xc2a00000c34, + 0xc3500000c3a, + 0xc3d00000c45, + 0xc4600000c49, + 0xc4a00000c4e, + 0xc5500000c57, + 0xc5800000c5a, + 0xc6000000c64, + 0xc6600000c70, + 0xc8200000c84, + 0xc8500000c8d, + 0xc8e00000c91, + 0xc9200000ca9, + 0xcaa00000cb4, + 0xcb500000cba, + 0xcbc00000cc5, + 0xcc600000cc9, + 0xcca00000cce, + 0xcd500000cd7, + 0xcde00000cdf, + 0xce000000ce4, + 0xce600000cf0, + 0xcf100000cf3, + 0xd0200000d04, + 0xd0500000d0d, + 0xd0e00000d11, + 0xd1200000d3b, + 0xd3d00000d45, + 0xd4600000d49, + 0xd4a00000d4f, + 0xd5700000d58, + 0xd6000000d64, + 0xd6600000d70, + 0xd7a00000d80, + 0xd8200000d84, + 0xd8500000d97, + 0xd9a00000db2, + 0xdb300000dbc, + 0xdbd00000dbe, + 0xdc000000dc7, + 0xdca00000dcb, + 0xdcf00000dd5, + 0xdd600000dd7, + 0xdd800000de0, + 0xdf200000df4, + 0xe0100000e33, + 0xe3400000e3b, + 0xe4000000e4f, + 0xe5000000e5a, + 0xe8100000e83, + 0xe8400000e85, + 0xe8700000e89, + 0xe8a00000e8b, + 0xe8d00000e8e, + 0xe9400000e98, + 0xe9900000ea0, + 0xea100000ea4, + 0xea500000ea6, + 0xea700000ea8, + 0xeaa00000eac, + 0xead00000eb3, + 0xeb400000eba, + 0xebb00000ebe, + 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, + 0x13a0000013f5, + 0x14010000166d, + 0x166f00001680, + 0x16810000169b, + 0x16a0000016eb, + 0x17000000170d, + 0x170e00001715, + 0x172000001735, + 0x174000001754, + 0x17600000176d, + 0x176e00001771, + 0x177200001774, + 0x1780000017b4, + 0x17b6000017d4, + 0x17d7000017d8, + 0x17dc000017de, + 0x17e0000017ea, + 0x18100000181a, + 0x182000001878, + 0x1880000018ab, + 0x18b0000018f6, + 0x19000000191d, + 0x19200000192c, + 0x19300000193c, + 0x19460000196e, + 0x197000001975, + 0x1980000019ac, + 0x19b0000019ca, + 0x19d0000019da, + 0x1a0000001a1c, + 0x1a2000001a5f, + 0x1a6000001a7d, + 0x1a7f00001a8a, + 0x1a9000001a9a, + 0x1aa700001aa8, + 0x1b0000001b4c, + 0x1b5000001b5a, + 0x1b6b00001b74, + 0x1b8000001bf4, + 0x1c0000001c38, + 0x1c4000001c4a, + 0x1c4d00001c7e, + 0x1cd000001cd3, + 0x1cd400001cf7, + 0x1d0000001d2c, + 0x1d2f00001d30, + 0x1d3b00001d3c, + 0x1d4e00001d4f, + 0x1d6b00001d78, + 0x1d7900001d9b, + 0x1dc000001de7, + 0x1dfc00001e00, + 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, + 0x31050000312e, + 0x31a0000031bb, + 0x31f000003200, + 0x340000004db6, + 0x4e0000009fcd, + 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, + 0xa69f0000a6e6, + 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, + 0xa78e0000a78f, + 0xa7910000a792, + 0xa7930000a794, + 0xa7a10000a7a2, + 0xa7a30000a7a4, + 0xa7a50000a7a6, + 0xa7a70000a7a8, + 0xa7a90000a7aa, + 0xa7fa0000a828, + 0xa8400000a874, + 0xa8800000a8c5, + 0xa8d00000a8da, + 0xa8e00000a8f8, + 0xa8fb0000a8fc, + 0xa9000000a92e, + 0xa9300000a954, + 0xa9800000a9c1, + 0xa9cf0000a9da, + 0xaa000000aa37, + 0xaa400000aa4e, + 0xaa500000aa5a, + 0xaa600000aa77, + 0xaa7a0000aa7c, + 0xaa800000aac3, + 0xaadb0000aade, + 0xaae00000aaf0, + 0xaaf20000aaf7, + 0xab010000ab07, + 0xab090000ab0f, + 0xab110000ab17, + 0xab200000ab27, + 0xab280000ab2f, + 0xabc00000abeb, + 0xabec0000abee, + 0xabf00000abfa, + 0xac000000d7a4, + 0xfa0e0000fa10, + 0xfa110000fa12, + 0xfa130000fa15, + 0xfa1f0000fa20, + 0xfa210000fa22, + 0xfa230000fa25, + 0xfa270000fa2a, + 0xfb1e0000fb1f, + 0xfe200000fe27, + 0xfe730000fe74, + 0x100000001000c, + 0x1000d00010027, + 0x100280001003b, + 0x1003c0001003e, + 0x1003f0001004e, + 0x100500001005e, + 0x10080000100fb, + 0x101fd000101fe, + 0x102800001029d, + 0x102a0000102d1, + 0x103000001031f, + 0x1033000010341, + 0x103420001034a, + 0x103800001039e, + 0x103a0000103c4, + 0x103c8000103d0, + 0x104280001049e, + 0x104a0000104aa, + 0x1080000010806, + 0x1080800010809, + 0x1080a00010836, + 0x1083700010839, + 0x1083c0001083d, + 0x1083f00010856, + 0x1090000010916, + 0x109200001093a, + 0x10980000109b8, + 0x109be000109c0, + 0x10a0000010a04, + 0x10a0500010a07, + 0x10a0c00010a14, + 0x10a1500010a18, + 0x10a1900010a34, + 0x10a3800010a3b, + 0x10a3f00010a40, + 0x10a6000010a7d, + 0x10b0000010b36, + 0x10b4000010b56, + 0x10b6000010b73, + 0x10c0000010c49, + 0x1100000011047, + 0x1106600011070, + 0x11080000110bb, + 0x110d0000110e9, + 0x110f0000110fa, + 0x1110000011135, + 0x1113600011140, + 0x11180000111c5, + 0x111d0000111da, + 0x11680000116b8, + 0x116c0000116ca, + 0x120000001236f, + 0x130000001342f, + 0x1680000016a39, + 0x16f0000016f45, + 0x16f5000016f7f, + 0x16f8f00016fa0, + 0x1b0000001b002, + 0x200000002a6d7, + 0x2a7000002b735, + 0x2b7400002b81e, + ), + 'CONTEXTJ': ( + 0x200c0000200e, + ), + 'CONTEXTO': ( + 0xb7000000b8, + 0x37500000376, + 0x5f3000005f5, + 0x6600000066a, + 0x6f0000006fa, + 0x30fb000030fc, + ), +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/intranges.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/intranges.py new file mode 100755 index 0000000..8202be8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py new file mode 100755 index 0000000..3073271 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/package_data.py @@ -0,0 +1,2 @@ +__version__ = '2.6' + diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py new file mode 100755 index 0000000..fa1d66a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/idna/uts46data.py @@ -0,0 +1,7634 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "6.3.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, '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'ђ'), + (0x403, 'M', u'ѓ'), + ] + +def _seg_7(): + return [ + (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'), + (0x49E, 'M', u'ҟ'), + ] + +def _seg_8(): + return [ + (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'ԃ'), + (0x503, 'V'), + ] + +def _seg_9(): + return [ + (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, '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'), + (0x560, 'X'), + (0x561, 'V'), + (0x587, 'M', u'եւ'), + (0x588, 'X'), + (0x589, 'V'), + (0x58B, 'X'), + (0x58F, 'V'), + (0x590, 'X'), + (0x591, 'V'), + (0x5C8, 'X'), + (0x5D0, 'V'), + (0x5EB, 'X'), + (0x5F0, 'V'), + (0x5F5, 'X'), + (0x606, 'V'), + (0x61C, 'X'), + (0x61E, 'V'), + (0x675, 'M', u'اٴ'), + (0x676, 'M', u'وٴ'), + (0x677, 'M', u'ۇٴ'), + (0x678, 'M', u'يٴ'), + (0x679, 'V'), + (0x6DD, 'X'), + ] + +def _seg_10(): + return [ + (0x6DE, 'V'), + (0x70E, 'X'), + (0x710, 'V'), + (0x74B, 'X'), + (0x74D, 'V'), + (0x7B2, 'X'), + (0x7C0, 'V'), + (0x7FB, 'X'), + (0x800, 'V'), + (0x82E, 'X'), + (0x830, 'V'), + (0x83F, 'X'), + (0x840, 'V'), + (0x85C, 'X'), + (0x85E, 'V'), + (0x85F, 'X'), + (0x8A0, 'V'), + (0x8A1, 'X'), + (0x8A2, 'V'), + (0x8AD, 'X'), + (0x8E4, 'V'), + (0x8FF, 'X'), + (0x900, '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'), + (0x978, 'X'), + (0x979, 'V'), + (0x980, 'X'), + (0x981, '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'), + (0x9FC, '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'ਜ਼'), + (0xA5C, 'V'), + (0xA5D, 'X'), + (0xA5E, 'M', u'ਫ਼'), + (0xA5F, 'X'), + ] + +def _seg_11(): + return [ + (0xA66, 'V'), + (0xA76, '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'), + (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'), + (0xB56, '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'), + (0xC01, 'V'), + (0xC04, 'X'), + (0xC05, 'V'), + (0xC0D, 'X'), + (0xC0E, 'V'), + (0xC11, 'X'), + (0xC12, 'V'), + (0xC29, 'X'), + (0xC2A, 'V'), + (0xC34, 'X'), + (0xC35, 'V'), + ] + +def _seg_12(): + return [ + (0xC3A, 'X'), + (0xC3D, 'V'), + (0xC45, 'X'), + (0xC46, 'V'), + (0xC49, 'X'), + (0xC4A, 'V'), + (0xC4E, 'X'), + (0xC55, 'V'), + (0xC57, 'X'), + (0xC58, 'V'), + (0xC5A, 'X'), + (0xC60, 'V'), + (0xC64, 'X'), + (0xC66, 'V'), + (0xC70, 'X'), + (0xC78, 'V'), + (0xC80, 'X'), + (0xC82, 'V'), + (0xC84, 'X'), + (0xC85, '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'), + (0xD02, 'V'), + (0xD04, 'X'), + (0xD05, 'V'), + (0xD0D, 'X'), + (0xD0E, 'V'), + (0xD11, 'X'), + (0xD12, 'V'), + (0xD3B, 'X'), + (0xD3D, 'V'), + (0xD45, 'X'), + (0xD46, 'V'), + (0xD49, 'X'), + (0xD4A, 'V'), + (0xD4F, 'X'), + (0xD57, 'V'), + (0xD58, 'X'), + (0xD60, 'V'), + (0xD64, 'X'), + (0xD66, 'V'), + (0xD76, 'X'), + (0xD79, 'V'), + (0xD80, 'X'), + (0xD82, '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'), + (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'), + (0xE87, 'V'), + ] + +def _seg_13(): + return [ + (0xE89, 'X'), + (0xE8A, 'V'), + (0xE8B, 'X'), + (0xE8D, 'V'), + (0xE8E, 'X'), + (0xE94, 'V'), + (0xE98, 'X'), + (0xE99, 'V'), + (0xEA0, 'X'), + (0xEA1, 'V'), + (0xEA4, 'X'), + (0xEA5, 'V'), + (0xEA6, 'X'), + (0xEA7, 'V'), + (0xEA8, 'X'), + (0xEAA, 'V'), + (0xEAC, 'X'), + (0xEAD, 'V'), + (0xEB3, 'M', u'ໍາ'), + (0xEB4, 'V'), + (0xEBA, 'X'), + (0xEBB, 'V'), + (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'), + ] + +def _seg_14(): + return [ + (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'), + (0x1316, 'X'), + (0x1318, 'V'), + (0x135B, 'X'), + (0x135D, 'V'), + (0x137D, 'X'), + (0x1380, 'V'), + (0x139A, 'X'), + (0x13A0, 'V'), + (0x13F5, 'X'), + (0x1400, 'V'), + (0x1680, 'X'), + (0x1681, 'V'), + (0x169D, 'X'), + (0x16A0, 'V'), + (0x16F1, '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'), + (0x1878, 'X'), + (0x1880, 'V'), + (0x18AB, 'X'), + (0x18B0, 'V'), + (0x18F6, 'X'), + (0x1900, 'V'), + (0x191D, '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'), + ] + +def _seg_15(): + return [ + (0x1AA0, 'V'), + (0x1AAE, 'X'), + (0x1B00, 'V'), + (0x1B4C, 'X'), + (0x1B50, 'V'), + (0x1B7D, 'X'), + (0x1B80, 'V'), + (0x1BF4, 'X'), + (0x1BFC, 'V'), + (0x1C38, 'X'), + (0x1C3B, 'V'), + (0x1C4A, 'X'), + (0x1C4D, 'V'), + (0x1C80, 'X'), + (0x1CC0, 'V'), + (0x1CC8, 'X'), + (0x1CD0, 'V'), + (0x1CF7, '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'), + (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'ɭ'), + ] + +def _seg_16(): + return [ + (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'), + (0x1DE7, 'X'), + (0x1DFC, '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'ḡ'), + (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'ṋ'), + ] + +def _seg_17(): + return [ + (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'ẅ'), + (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'), + ] + +def _seg_18(): + return [ + (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'), + (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'ἥ'), + ] + +def _seg_19(): + return [ + (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'ἄι'), + (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'ὦι'), + ] + +def _seg_20(): + return [ + (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'ωι'), + (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'), + ] + +def _seg_21(): + return [ + (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'), + (0x20BB, 'X'), + (0x20D0, 'V'), + (0x20F1, 'X'), + (0x2100, '3', u'a/c'), + (0x2101, '3', u'a/s'), + (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'א'), + ] + +def _seg_22(): + return [ + (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'), + (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, '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'), + (0x23F4, 'X'), + (0x2400, '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'), + ] + +def _seg_23(): + return [ + (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'), + (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'), + ] + +def _seg_24(): + return [ + (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'), + (0x2700, 'X'), + (0x2701, 'V'), + (0x2A0C, 'M', u'∫∫∫∫'), + (0x2A0D, 'V'), + (0x2A74, '3', u'::='), + (0x2A75, '3', u'=='), + (0x2A76, '3', u'==='), + (0x2A77, 'V'), + (0x2ADC, 'M', u'⫝̸'), + (0x2ADD, 'V'), + (0x2B4D, 'X'), + (0x2B50, 'V'), + (0x2B5A, 'X'), + (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'ⱕ'), + (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'ⲃ'), + ] + +def _seg_25(): + return [ + (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'ⲿ'), + (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'ⳮ'), + ] + +def _seg_26(): + return [ + (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'), + (0x2E3C, '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'刀'), + (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'彐'), + ] + +def _seg_27(): + return [ + (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'竹'), + (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'身'), + ] + +def _seg_28(): + return [ + (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'.'), + (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'), + (0x312E, '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'ᄡ'), + ] + +def _seg_29(): + return [ + (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'ᅇ'), + (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'), + (0x31BB, 'X'), + (0x31C0, 'V'), + (0x31E4, 'X'), + (0x31F0, 'V'), + (0x3200, '3', u'(ᄀ)'), + (0x3201, '3', u'(ᄂ)'), + (0x3202, '3', u'(ᄃ)'), + (0x3203, '3', u'(ᄅ)'), + (0x3204, '3', u'(ᄆ)'), + ] + +def _seg_30(): + return [ + (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'(自)'), + (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'나'), + ] + +def _seg_31(): + return [ + (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'企'), + (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'エ'), + ] + +def _seg_32(): + return [ + (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, 'X'), + (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'ギニー'), + (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'ペソ'), + ] + +def _seg_33(): + return [ + (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'), + (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'), + ] + +def _seg_34(): + return [ + (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'), + (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'), + ] + +def _seg_35(): + return [ + (0x3400, 'V'), + (0x4DB6, 'X'), + (0x4DC0, 'V'), + (0x9FCD, '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'), + (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, 'X'), + (0xA69F, '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'), + ] + +def _seg_36(): + return [ + (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'ꝯ'), + (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'), + (0xA78F, 'X'), + (0xA790, 'M', u'ꞑ'), + (0xA791, 'V'), + (0xA792, 'M', u'ꞓ'), + (0xA793, 'V'), + (0xA794, 'X'), + (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, 'X'), + (0xA7F8, 'M', u'ħ'), + ] + +def _seg_37(): + return [ + (0xA7F9, 'M', u'œ'), + (0xA7FA, 'V'), + (0xA82C, 'X'), + (0xA830, 'V'), + (0xA83A, 'X'), + (0xA840, 'V'), + (0xA878, 'X'), + (0xA880, 'V'), + (0xA8C5, 'X'), + (0xA8CE, 'V'), + (0xA8DA, 'X'), + (0xA8E0, 'V'), + (0xA8FC, 'X'), + (0xA900, 'V'), + (0xA954, 'X'), + (0xA95F, 'V'), + (0xA97D, 'X'), + (0xA980, 'V'), + (0xA9CE, 'X'), + (0xA9CF, 'V'), + (0xA9DA, 'X'), + (0xA9DE, 'V'), + (0xA9E0, 'X'), + (0xAA00, 'V'), + (0xAA37, 'X'), + (0xAA40, 'V'), + (0xAA4E, 'X'), + (0xAA50, 'V'), + (0xAA5A, 'X'), + (0xAA5C, 'V'), + (0xAA7C, 'X'), + (0xAA80, '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'), + (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'來'), + ] + +def _seg_38(): + return [ + (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'漏'), + (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'撚'), + ] + +def _seg_39(): + return [ + (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'零'), + (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'淋'), + ] + +def _seg_40(): + return [ + (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'礼'), + (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'著'), + ] + +def _seg_41(): + return [ + (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'嬨'), + (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'醙'), + ] + +def _seg_42(): + return [ + (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'վն'), + (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'ڍ'), + ] + +def _seg_43(): + return [ + (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'ئۆ'), + (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'كي'), + ] + +def _seg_44(): + return [ + (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' ٍّ'), + (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'تح'), + ] + +def _seg_45(): + return [ + (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'قم'), + (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'صي'), + ] + +def _seg_46(): + return [ + (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'شخ'), + (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'محم'), + ] + +def _seg_47(): + return [ + (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'يحي'), + (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'), + (0xFE27, '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'》'), + ] + +def _seg_48(): + return [ + (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'='), + (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'"'), + ] + +def _seg_49(): + return [ + (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'), + (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'ヲ'), + ] + +def _seg_50(): + return [ + (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'ヌ'), + (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'ᅪ'), + ] + +def _seg_51(): + return [ + (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'), + (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'), + (0x1018B, 'X'), + (0x10190, 'V'), + (0x1019C, 'X'), + (0x101D0, 'V'), + (0x101FE, 'X'), + (0x10280, 'V'), + (0x1029D, 'X'), + (0x102A0, 'V'), + (0x102D1, 'X'), + (0x10300, 'V'), + (0x1031F, 'X'), + (0x10320, 'V'), + (0x10324, 'X'), + (0x10330, 'V'), + (0x1034B, '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'𐑅'), + ] + +def _seg_52(): + return [ + (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'), + (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'), + (0x10860, 'X'), + (0x10900, 'V'), + (0x1091C, 'X'), + (0x1091F, 'V'), + (0x1093A, 'X'), + (0x1093F, 'V'), + (0x10940, 'X'), + (0x10980, 'V'), + (0x109B8, 'X'), + (0x109BE, 'V'), + (0x109C0, 'X'), + (0x10A00, 'V'), + (0x10A04, 'X'), + (0x10A05, 'V'), + (0x10A07, 'X'), + (0x10A0C, 'V'), + (0x10A14, 'X'), + (0x10A15, 'V'), + (0x10A18, 'X'), + (0x10A19, 'V'), + (0x10A34, 'X'), + (0x10A38, 'V'), + (0x10A3B, 'X'), + (0x10A3F, 'V'), + (0x10A48, 'X'), + (0x10A50, 'V'), + (0x10A59, 'X'), + (0x10A60, 'V'), + (0x10A80, 'X'), + (0x10B00, 'V'), + (0x10B36, 'X'), + (0x10B39, 'V'), + (0x10B56, 'X'), + (0x10B58, 'V'), + (0x10B73, 'X'), + (0x10B78, 'V'), + (0x10B80, 'X'), + (0x10C00, 'V'), + (0x10C49, 'X'), + (0x10E60, 'V'), + (0x10E7F, 'X'), + (0x11000, 'V'), + (0x1104E, 'X'), + (0x11052, 'V'), + (0x11070, 'X'), + (0x11080, 'V'), + (0x110BD, 'X'), + (0x110BE, 'V'), + (0x110C2, 'X'), + (0x110D0, 'V'), + (0x110E9, 'X'), + (0x110F0, 'V'), + (0x110FA, 'X'), + (0x11100, 'V'), + (0x11135, 'X'), + (0x11136, 'V'), + (0x11144, 'X'), + (0x11180, 'V'), + (0x111C9, 'X'), + (0x111D0, 'V'), + (0x111DA, 'X'), + (0x11680, 'V'), + (0x116B8, 'X'), + (0x116C0, 'V'), + (0x116CA, 'X'), + (0x12000, 'V'), + (0x1236F, 'X'), + (0x12400, 'V'), + (0x12463, 'X'), + (0x12470, 'V'), + (0x12474, 'X'), + (0x13000, 'V'), + (0x1342F, 'X'), + ] + +def _seg_53(): + return [ + (0x16800, 'V'), + (0x16A39, 'X'), + (0x16F00, 'V'), + (0x16F45, 'X'), + (0x16F50, 'V'), + (0x16F7F, 'X'), + (0x16F8F, 'V'), + (0x16FA0, 'X'), + (0x1B000, 'V'), + (0x1B002, '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'), + (0x1D173, 'X'), + (0x1D17B, 'V'), + (0x1D1BB, 'M', u'𝆹𝅥'), + (0x1D1BC, 'M', u'𝆺𝅥'), + (0x1D1BD, 'M', u'𝆹𝅥𝅮'), + (0x1D1BE, 'M', u'𝆺𝅥𝅮'), + (0x1D1BF, 'M', u'𝆹𝅥𝅯'), + (0x1D1C0, 'M', u'𝆺𝅥𝅯'), + (0x1D1C1, 'V'), + (0x1D1DE, 'X'), + (0x1D200, 'V'), + (0x1D246, 'X'), + (0x1D300, 'V'), + (0x1D357, 'X'), + (0x1D360, 'V'), + (0x1D372, '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'), + ] + +def _seg_54(): + return [ + (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'), + (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'), + ] + +def _seg_55(): + return [ + (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'), + (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'), + ] + +def _seg_56(): + return [ + (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'), + (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'), + ] + +def _seg_57(): + return [ + (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'), + (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'), + ] + +def _seg_58(): + return [ + (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'), + (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'), + ] + +def _seg_59(): + return [ + (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'), + (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'), + ] + +def _seg_60(): + return [ + (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'ι'), + (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'ε'), + ] + +def _seg_61(): + return [ + (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'ε'), + (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'ρ'), + ] + +def _seg_62(): + return [ + (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'μ'), + (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'), + ] + +def _seg_63(): + return [ + (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'), + (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, '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'ق'), + ] + +def _seg_64(): + return [ + (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'ك'), + (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'), + ] + +def _seg_65(): + return [ + (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'), + (0x1F0BF, 'X'), + (0x1F0C1, 'V'), + (0x1F0D0, 'X'), + (0x1F0D1, 'V'), + (0x1F0E0, '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,'), + (0x1F109, '3', u'8,'), + (0x1F10A, '3', u'9,'), + (0x1F10B, 'X'), + (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, 'X'), + (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'), + ] + +def _seg_66(): + return [ + (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, 'X'), + (0x1F170, 'V'), + (0x1F190, 'M', u'dj'), + (0x1F191, 'V'), + (0x1F19B, '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'販'), + (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, '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'), + (0x1F300, 'V'), + (0x1F321, 'X'), + (0x1F330, 'V'), + (0x1F336, 'X'), + (0x1F337, 'V'), + (0x1F37D, 'X'), + (0x1F380, 'V'), + (0x1F394, 'X'), + (0x1F3A0, 'V'), + (0x1F3C5, 'X'), + (0x1F3C6, 'V'), + (0x1F3CB, 'X'), + (0x1F3E0, 'V'), + (0x1F3F1, 'X'), + (0x1F400, 'V'), + (0x1F43F, 'X'), + (0x1F440, 'V'), + ] + +def _seg_67(): + return [ + (0x1F441, 'X'), + (0x1F442, 'V'), + (0x1F4F8, 'X'), + (0x1F4F9, 'V'), + (0x1F4FD, 'X'), + (0x1F500, 'V'), + (0x1F53E, 'X'), + (0x1F540, 'V'), + (0x1F544, 'X'), + (0x1F550, 'V'), + (0x1F568, 'X'), + (0x1F5FB, 'V'), + (0x1F641, 'X'), + (0x1F645, 'V'), + (0x1F650, 'X'), + (0x1F680, 'V'), + (0x1F6C6, 'X'), + (0x1F700, 'V'), + (0x1F774, 'X'), + (0x20000, 'V'), + (0x2A6D7, 'X'), + (0x2A700, 'V'), + (0x2B735, 'X'), + (0x2B740, 'V'), + (0x2B81E, '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'圗'), + ] + +def _seg_68(): + return [ + (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'壷'), + (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'扝'), + ] + +def _seg_69(): + return [ + (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'㨮'), + (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'災'), + ] + +def _seg_70(): + return [ + (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'𤜵'), + (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'聰'), + ] + +def _seg_71(): + return [ + (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'辞'), + (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'郱'), + ] + +def _seg_72(): + return [ + (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'𨵷'), + (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'), + (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() +) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py new file mode 100755 index 0000000..6da8d93 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/ipaddress.py @@ -0,0 +1,2419 @@ +# Copyright 2007 Google Inc. +# Licensed to PSF under a Contributor Agreement. + +"""A fast, lightweight IPv4/IPv6 manipulation library in Python. + +This library is used to create/poke/manipulate IPv4 and IPv6 addresses +and networks. + +""" + +from __future__ import unicode_literals + + +import itertools +import struct + +__version__ = '1.0.19' + +# Compatibility functions +_compat_int_types = (int,) +try: + _compat_int_types = (int, long) +except NameError: + pass +try: + _compat_str = unicode +except NameError: + _compat_str = str + assert bytes != str +if b'\0'[0] == 0: # Python 3 semantics + def _compat_bytes_to_byte_vals(byt): + return byt +else: + def _compat_bytes_to_byte_vals(byt): + return [struct.unpack(b'!B', b)[0] for b in byt] +try: + _compat_int_from_byte_vals = int.from_bytes +except AttributeError: + def _compat_int_from_byte_vals(bytvals, endianess): + assert endianess == 'big' + res = 0 + for bv in bytvals: + assert isinstance(bv, _compat_int_types) + res = (res << 8) + bv + return res + + +def _compat_to_bytes(intval, length, endianess): + assert isinstance(intval, _compat_int_types) + assert endianess == 'big' + if length == 4: + if intval < 0 or intval >= 2 ** 32: + raise struct.error("integer out of range for 'I' format code") + return struct.pack(b'!I', intval) + elif length == 16: + if intval < 0 or intval >= 2 ** 128: + raise struct.error("integer out of range for 'QQ' format code") + return struct.pack(b'!QQ', intval >> 64, intval & 0xffffffffffffffff) + else: + raise NotImplementedError() + + +if hasattr(int, 'bit_length'): + # Not int.bit_length , since that won't work in 2.7 where long exists + def _compat_bit_length(i): + return i.bit_length() +else: + def _compat_bit_length(i): + for res in itertools.count(): + if i >> res == 0: + return res + + +def _compat_range(start, end, step=1): + assert step > 0 + i = start + while i < end: + yield i + i += step + + +class _TotalOrderingMixin(object): + __slots__ = () + + # Helper that derives the other comparison operations from + # __lt__ and __eq__ + # We avoid functools.total_ordering because it doesn't handle + # NotImplemented correctly yet (http://bugs.python.org/issue10042) + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not equal + + def __lt__(self, other): + raise NotImplementedError + + def __le__(self, other): + less = self.__lt__(other) + if less is NotImplemented or not less: + return self.__eq__(other) + return less + + def __gt__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + equal = self.__eq__(other) + if equal is NotImplemented: + return NotImplemented + return not (less or equal) + + def __ge__(self, other): + less = self.__lt__(other) + if less is NotImplemented: + return NotImplemented + return not less + + +IPV4LENGTH = 32 +IPV6LENGTH = 128 + + +class AddressValueError(ValueError): + """A Value Error related to the address.""" + + +class NetmaskValueError(ValueError): + """A Value Error related to the netmask.""" + + +def ip_address(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Address or IPv6Address object. + + Raises: + ValueError: if the *address* passed isn't either a v4 or a v6 + address + + """ + try: + return IPv4Address(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Address(address) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % + address) + + +def ip_network(address, strict=True): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP network. Either IPv4 or + IPv6 networks may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Network or IPv6Network object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. Or if the network has host bits set. + + """ + try: + return IPv4Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Network(address, strict) + except (AddressValueError, NetmaskValueError): + pass + + if isinstance(address, bytes): + raise AddressValueError( + '%r does not appear to be an IPv4 or IPv6 network. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?' % address) + + raise ValueError('%r does not appear to be an IPv4 or IPv6 network' % + address) + + +def ip_interface(address): + """Take an IP string/int and return an object of the correct type. + + Args: + address: A string or integer, the IP address. Either IPv4 or + IPv6 addresses may be supplied; integers less than 2**32 will + be considered to be IPv4 by default. + + Returns: + An IPv4Interface or IPv6Interface object. + + Raises: + ValueError: if the string passed isn't either a v4 or a v6 + address. + + Notes: + The IPv?Interface classes describe an Address on a particular + Network, so they're basically a combination of both the Address + and Network classes. + + """ + try: + return IPv4Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + try: + return IPv6Interface(address) + except (AddressValueError, NetmaskValueError): + pass + + raise ValueError('%r does not appear to be an IPv4 or IPv6 interface' % + address) + + +def v4_int_to_packed(address): + """Represent an address as 4 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv4 IP address. + + Returns: + The integer address packed as 4 bytes in network (big-endian) order. + + Raises: + ValueError: If the integer is negative or too large to be an + IPv4 IP address. + + """ + try: + return _compat_to_bytes(address, 4, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv4") + + +def v6_int_to_packed(address): + """Represent an address as 16 packed bytes in network (big-endian) order. + + Args: + address: An integer representation of an IPv6 IP address. + + Returns: + The integer address packed as 16 bytes in network (big-endian) order. + + """ + try: + return _compat_to_bytes(address, 16, 'big') + except (struct.error, OverflowError): + raise ValueError("Address negative or too large for IPv6") + + +def _split_optional_netmask(address): + """Helper to split the netmask and raise AddressValueError if needed""" + addr = _compat_str(address).split('/') + if len(addr) > 2: + raise AddressValueError("Only one '/' permitted in %r" % address) + return addr + + +def _find_address_range(addresses): + """Find a sequence of sorted deduplicated IPv#Address. + + Args: + addresses: a list of IPv#Address objects. + + Yields: + A tuple containing the first and last IP addresses in the sequence. + + """ + it = iter(addresses) + first = last = next(it) + for ip in it: + if ip._ip != last._ip + 1: + yield first, last + first = ip + last = ip + yield first, last + + +def _count_righthand_zero_bits(number, bits): + """Count the number of zero bits on the right hand side. + + Args: + number: an integer. + bits: maximum number of bits to count. + + Returns: + The number of zero bits on the right hand side of the number. + + """ + if number == 0: + return bits + return min(bits, _compat_bit_length(~number & (number - 1))) + + +def summarize_address_range(first, last): + """Summarize a network range given the first and last IP addresses. + + Example: + >>> list(summarize_address_range(IPv4Address('192.0.2.0'), + ... IPv4Address('192.0.2.130'))) + ... #doctest: +NORMALIZE_WHITESPACE + [IPv4Network('192.0.2.0/25'), IPv4Network('192.0.2.128/31'), + IPv4Network('192.0.2.130/32')] + + Args: + first: the first IPv4Address or IPv6Address in the range. + last: the last IPv4Address or IPv6Address in the range. + + Returns: + An iterator of the summarized IPv(4|6) network objects. + + Raise: + TypeError: + If the first and last objects are not IP addresses. + If the first and last objects are not the same version. + ValueError: + If the last object is not greater than the first. + If the version of the first address is not 4 or 6. + + """ + if (not (isinstance(first, _BaseAddress) and + isinstance(last, _BaseAddress))): + raise TypeError('first and last must be IP addresses, not networks') + if first.version != last.version: + raise TypeError("%s and %s are not of the same version" % ( + first, last)) + if first > last: + raise ValueError('last IP address must be greater than first') + + if first.version == 4: + ip = IPv4Network + elif first.version == 6: + ip = IPv6Network + else: + raise ValueError('unknown IP version') + + ip_bits = first._max_prefixlen + first_int = first._ip + last_int = last._ip + while first_int <= last_int: + nbits = min(_count_righthand_zero_bits(first_int, ip_bits), + _compat_bit_length(last_int - first_int + 1) - 1) + net = ip((first_int, ip_bits - nbits)) + yield net + first_int += 1 << nbits + if first_int - 1 == ip._ALL_ONES: + break + + +def _collapse_addresses_internal(addresses): + """Loops through the addresses, collapsing concurrent netblocks. + + Example: + + ip1 = IPv4Network('192.0.2.0/26') + ip2 = IPv4Network('192.0.2.64/26') + ip3 = IPv4Network('192.0.2.128/26') + ip4 = IPv4Network('192.0.2.192/26') + + _collapse_addresses_internal([ip1, ip2, ip3, ip4]) -> + [IPv4Network('192.0.2.0/24')] + + This shouldn't be called directly; it is called via + collapse_addresses([]). + + Args: + addresses: A list of IPv4Network's or IPv6Network's + + Returns: + A list of IPv4Network's or IPv6Network's depending on what we were + passed. + + """ + # First merge + to_merge = list(addresses) + subnets = {} + while to_merge: + net = to_merge.pop() + supernet = net.supernet() + existing = subnets.get(supernet) + if existing is None: + subnets[supernet] = net + elif existing != net: + # Merge consecutive subnets + del subnets[supernet] + to_merge.append(supernet) + # Then iterate over resulting networks, skipping subsumed subnets + last = None + for net in sorted(subnets.values()): + if last is not None: + # Since they are sorted, + # last.network_address <= net.network_address is a given. + if last.broadcast_address >= net.broadcast_address: + continue + yield net + last = net + + +def collapse_addresses(addresses): + """Collapse a list of IP objects. + + Example: + collapse_addresses([IPv4Network('192.0.2.0/25'), + IPv4Network('192.0.2.128/25')]) -> + [IPv4Network('192.0.2.0/24')] + + Args: + addresses: An iterator of IPv4Network or IPv6Network objects. + + Returns: + An iterator of the collapsed IPv(4|6)Network objects. + + Raises: + TypeError: If passed a list of mixed version objects. + + """ + addrs = [] + ips = [] + nets = [] + + # split IP addresses and networks + for ip in addresses: + if isinstance(ip, _BaseAddress): + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + ips.append(ip) + elif ip._prefixlen == ip._max_prefixlen: + if ips and ips[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, ips[-1])) + try: + ips.append(ip.ip) + except AttributeError: + ips.append(ip.network_address) + else: + if nets and nets[-1]._version != ip._version: + raise TypeError("%s and %s are not of the same version" % ( + ip, nets[-1])) + nets.append(ip) + + # sort and dedup + ips = sorted(set(ips)) + + # find consecutive address ranges in the sorted sequence and summarize them + if ips: + for first, last in _find_address_range(ips): + addrs.extend(summarize_address_range(first, last)) + + return _collapse_addresses_internal(addrs + nets) + + +def get_mixed_type_key(obj): + """Return a key suitable for sorting between networks and addresses. + + Address and Network objects are not sortable by default; they're + fundamentally different so the expression + + IPv4Address('192.0.2.0') <= IPv4Network('192.0.2.0/24') + + doesn't make any sense. There are some times however, where you may wish + to have ipaddress sort these for you anyway. If you need to do this, you + can use this function as the key= argument to sorted(). + + Args: + obj: either a Network or Address object. + Returns: + appropriate key. + + """ + if isinstance(obj, _BaseNetwork): + return obj._get_networks_key() + elif isinstance(obj, _BaseAddress): + return obj._get_address_key() + return NotImplemented + + +class _IPAddressBase(_TotalOrderingMixin): + + """The mother class.""" + + __slots__ = () + + @property + def exploded(self): + """Return the longhand version of the IP address as a string.""" + return self._explode_shorthand_ip_string() + + @property + def compressed(self): + """Return the shorthand version of the IP address as a string.""" + return _compat_str(self) + + @property + def reverse_pointer(self): + """The name of the reverse DNS pointer for the IP address, e.g.: + >>> ipaddress.ip_address("127.0.0.1").reverse_pointer + '1.0.0.127.in-addr.arpa' + >>> ipaddress.ip_address("2001:db8::1").reverse_pointer + '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa' + + """ + return self._reverse_pointer() + + @property + def version(self): + msg = '%200s has no version specified' % (type(self),) + raise NotImplementedError(msg) + + def _check_int_address(self, address): + if address < 0: + msg = "%d (< 0) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._version)) + if address > self._ALL_ONES: + msg = "%d (>= 2**%d) is not permitted as an IPv%d address" + raise AddressValueError(msg % (address, self._max_prefixlen, + self._version)) + + def _check_packed_address(self, address, expected_len): + address_len = len(address) + if address_len != expected_len: + msg = ( + '%r (len %d != %d) is not permitted as an IPv%d address. ' + 'Did you pass in a bytes (str in Python 2) instead of' + ' a unicode object?') + raise AddressValueError(msg % (address, address_len, + expected_len, self._version)) + + @classmethod + def _ip_int_from_prefix(cls, prefixlen): + """Turn the prefix length into a bitwise netmask + + Args: + prefixlen: An integer, the prefix length. + + Returns: + An integer. + + """ + return cls._ALL_ONES ^ (cls._ALL_ONES >> prefixlen) + + @classmethod + def _prefix_from_ip_int(cls, ip_int): + """Return prefix length from the bitwise netmask. + + Args: + ip_int: An integer, the netmask in expanded bitwise format + + Returns: + An integer, the prefix length. + + Raises: + ValueError: If the input intermingles zeroes & ones + """ + trailing_zeroes = _count_righthand_zero_bits(ip_int, + cls._max_prefixlen) + prefixlen = cls._max_prefixlen - trailing_zeroes + leading_ones = ip_int >> trailing_zeroes + all_ones = (1 << prefixlen) - 1 + if leading_ones != all_ones: + byteslen = cls._max_prefixlen // 8 + details = _compat_to_bytes(ip_int, byteslen, 'big') + msg = 'Netmask pattern %r mixes zeroes & ones' + raise ValueError(msg % details) + return prefixlen + + @classmethod + def _report_invalid_netmask(cls, netmask_str): + msg = '%r is not a valid netmask' % netmask_str + raise NetmaskValueError(msg) + + @classmethod + def _prefix_from_prefix_string(cls, prefixlen_str): + """Return prefix length from a numeric string + + Args: + prefixlen_str: The string to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask + """ + # int allows a leading +/- as well as surrounding whitespace, + # so we ensure that isn't the case + if not _BaseV4._DECIMAL_DIGITS.issuperset(prefixlen_str): + cls._report_invalid_netmask(prefixlen_str) + try: + prefixlen = int(prefixlen_str) + except ValueError: + cls._report_invalid_netmask(prefixlen_str) + if not (0 <= prefixlen <= cls._max_prefixlen): + cls._report_invalid_netmask(prefixlen_str) + return prefixlen + + @classmethod + def _prefix_from_ip_string(cls, ip_str): + """Turn a netmask/hostmask string into a prefix length + + Args: + ip_str: The netmask/hostmask to be converted + + Returns: + An integer, the prefix length. + + Raises: + NetmaskValueError: If the input is not a valid netmask/hostmask + """ + # Parse the netmask/hostmask like an IP address. + try: + ip_int = cls._ip_int_from_string(ip_str) + except AddressValueError: + cls._report_invalid_netmask(ip_str) + + # Try matching a netmask (this would be /1*0*/ as a bitwise regexp). + # Note that the two ambiguous cases (all-ones and all-zeroes) are + # treated as netmasks. + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + pass + + # Invert the bits, and try matching a /0+1+/ hostmask instead. + ip_int ^= cls._ALL_ONES + try: + return cls._prefix_from_ip_int(ip_int) + except ValueError: + cls._report_invalid_netmask(ip_str) + + def __reduce__(self): + return self.__class__, (_compat_str(self),) + + +class _BaseAddress(_IPAddressBase): + + """A generic IP object. + + This IP class contains the version independent methods which are + used by single IP addresses. + """ + + __slots__ = () + + def __int__(self): + return self._ip + + def __eq__(self, other): + try: + return (self._ip == other._ip and + self._version == other._version) + except AttributeError: + return NotImplemented + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseAddress): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self._ip != other._ip: + return self._ip < other._ip + return False + + # Shorthand for Integer addition and subtraction. This is not + # meant to ever support addition/subtraction of addresses. + def __add__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) + other) + + def __sub__(self, other): + if not isinstance(other, _compat_int_types): + return NotImplemented + return self.__class__(int(self) - other) + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return _compat_str(self._string_from_ip_int(self._ip)) + + def __hash__(self): + return hash(hex(int(self._ip))) + + def _get_address_key(self): + return (self._version, self) + + def __reduce__(self): + return self.__class__, (self._ip,) + + +class _BaseNetwork(_IPAddressBase): + + """A generic IP network object. + + This IP class contains the version independent methods which are + used by networks. + + """ + def __init__(self, address): + self._cache = {} + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, _compat_str(self)) + + def __str__(self): + return '%s/%d' % (self.network_address, self.prefixlen) + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the network + or broadcast addresses. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast): + yield self._address_class(x) + + def __iter__(self): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network, broadcast + 1): + yield self._address_class(x) + + def __getitem__(self, n): + network = int(self.network_address) + broadcast = int(self.broadcast_address) + if n >= 0: + if network + n > broadcast: + raise IndexError('address out of range') + return self._address_class(network + n) + else: + n += 1 + if broadcast + n < network: + raise IndexError('address out of range') + return self._address_class(broadcast + n) + + def __lt__(self, other): + if not isinstance(other, _IPAddressBase): + return NotImplemented + if not isinstance(other, _BaseNetwork): + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + if self._version != other._version: + raise TypeError('%s and %s are not of the same version' % ( + self, other)) + if self.network_address != other.network_address: + return self.network_address < other.network_address + if self.netmask != other.netmask: + return self.netmask < other.netmask + return False + + def __eq__(self, other): + try: + return (self._version == other._version and + self.network_address == other.network_address and + int(self.netmask) == int(other.netmask)) + except AttributeError: + return NotImplemented + + def __hash__(self): + return hash(int(self.network_address) ^ int(self.netmask)) + + def __contains__(self, other): + # always false if one is v4 and the other is v6. + if self._version != other._version: + return False + # dealing with another network. + if isinstance(other, _BaseNetwork): + return False + # dealing with another address + else: + # address + return (int(self.network_address) <= int(other._ip) <= + int(self.broadcast_address)) + + def overlaps(self, other): + """Tell if self is partly contained in other.""" + return self.network_address in other or ( + self.broadcast_address in other or ( + other.network_address in self or ( + other.broadcast_address in self))) + + @property + def broadcast_address(self): + x = self._cache.get('broadcast_address') + if x is None: + x = self._address_class(int(self.network_address) | + int(self.hostmask)) + self._cache['broadcast_address'] = x + return x + + @property + def hostmask(self): + x = self._cache.get('hostmask') + if x is None: + x = self._address_class(int(self.netmask) ^ self._ALL_ONES) + self._cache['hostmask'] = x + return x + + @property + def with_prefixlen(self): + return '%s/%d' % (self.network_address, self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self.network_address, self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self.network_address, self.hostmask) + + @property + def num_addresses(self): + """Number of hosts in the current subnet.""" + return int(self.broadcast_address) - int(self.network_address) + 1 + + @property + def _address_class(self): + # Returning bare address objects (rather than interfaces) allows for + # more consistent behaviour across the network address, broadcast + # address and individual host addresses. + msg = '%200s has no associated address class' % (type(self),) + raise NotImplementedError(msg) + + @property + def prefixlen(self): + return self._prefixlen + + def address_exclude(self, other): + """Remove an address from a larger block. + + For example: + + addr1 = ip_network('192.0.2.0/28') + addr2 = ip_network('192.0.2.1/32') + list(addr1.address_exclude(addr2)) = + [IPv4Network('192.0.2.0/32'), IPv4Network('192.0.2.2/31'), + IPv4Network('192.0.2.4/30'), IPv4Network('192.0.2.8/29')] + + or IPv6: + + addr1 = ip_network('2001:db8::1/32') + addr2 = ip_network('2001:db8::1/128') + list(addr1.address_exclude(addr2)) = + [ip_network('2001:db8::1/128'), + ip_network('2001:db8::2/127'), + ip_network('2001:db8::4/126'), + ip_network('2001:db8::8/125'), + ... + ip_network('2001:db8:8000::/33')] + + Args: + other: An IPv4Network or IPv6Network object of the same type. + + Returns: + An iterator of the IPv(4|6)Network objects which is self + minus other. + + Raises: + TypeError: If self and other are of differing address + versions, or if other is not a network object. + ValueError: If other is not completely contained by self. + + """ + if not self._version == other._version: + raise TypeError("%s and %s are not of the same version" % ( + self, other)) + + if not isinstance(other, _BaseNetwork): + raise TypeError("%s is not a network object" % other) + + if not other.subnet_of(self): + raise ValueError('%s not contained in %s' % (other, self)) + if other == self: + return + + # Make sure we're comparing the network of other. + other = other.__class__('%s/%s' % (other.network_address, + other.prefixlen)) + + s1, s2 = self.subnets() + while s1 != other and s2 != other: + if other.subnet_of(s1): + yield s2 + s1, s2 = s1.subnets() + elif other.subnet_of(s2): + yield s1 + s1, s2 = s2.subnets() + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + if s1 == other: + yield s2 + elif s2 == other: + yield s1 + else: + # If we got here, there's a bug somewhere. + raise AssertionError('Error performing exclusion: ' + 's1: %s s2: %s other: %s' % + (s1, s2, other)) + + def compare_networks(self, other): + """Compare two IP objects. + + This is only concerned about the comparison of the integer + representation of the network addresses. This means that the + host bits aren't considered at all in this method. If you want + to compare host bits, you can easily enough do a + 'HostA._ip < HostB._ip' + + Args: + other: An IP object. + + Returns: + If the IP versions of self and other are the same, returns: + + -1 if self < other: + eg: IPv4Network('192.0.2.0/25') < IPv4Network('192.0.2.128/25') + IPv6Network('2001:db8::1000/124') < + IPv6Network('2001:db8::2000/124') + 0 if self == other + eg: IPv4Network('192.0.2.0/24') == IPv4Network('192.0.2.0/24') + IPv6Network('2001:db8::1000/124') == + IPv6Network('2001:db8::1000/124') + 1 if self > other + eg: IPv4Network('192.0.2.128/25') > IPv4Network('192.0.2.0/25') + IPv6Network('2001:db8::2000/124') > + IPv6Network('2001:db8::1000/124') + + Raises: + TypeError if the IP versions are different. + + """ + # does this need to raise a ValueError? + if self._version != other._version: + raise TypeError('%s and %s are not of the same type' % ( + self, other)) + # self._version == other._version below here: + if self.network_address < other.network_address: + return -1 + if self.network_address > other.network_address: + return 1 + # self.network_address == other.network_address below here: + if self.netmask < other.netmask: + return -1 + if self.netmask > other.netmask: + return 1 + return 0 + + def _get_networks_key(self): + """Network-only key function. + + Returns an object that identifies this address' network and + netmask. This function is a suitable "key" argument for sorted() + and list.sort(). + + """ + return (self._version, self.network_address, self.netmask) + + def subnets(self, prefixlen_diff=1, new_prefix=None): + """The subnets which join to make the current subnet. + + In the case that self contains only one IP + (self._prefixlen == 32 for IPv4 or self._prefixlen == 128 + for IPv6), yield an iterator with just ourself. + + Args: + prefixlen_diff: An integer, the amount the prefix length + should be increased by. This should not be set if + new_prefix is also set. + new_prefix: The desired new prefix length. This must be a + larger number (smaller prefix) than the existing prefix. + This should not be set if prefixlen_diff is also set. + + Returns: + An iterator of IPv(4|6) objects. + + Raises: + ValueError: The prefixlen_diff is too small or too large. + OR + prefixlen_diff and new_prefix are both set or new_prefix + is a smaller number than the current prefix (smaller + number means a larger network) + + """ + if self._prefixlen == self._max_prefixlen: + yield self + return + + if new_prefix is not None: + if new_prefix < self._prefixlen: + raise ValueError('new prefix must be longer') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = new_prefix - self._prefixlen + + if prefixlen_diff < 0: + raise ValueError('prefix length diff must be > 0') + new_prefixlen = self._prefixlen + prefixlen_diff + + if new_prefixlen > self._max_prefixlen: + raise ValueError( + 'prefix length diff %d is invalid for netblock %s' % ( + new_prefixlen, self)) + + start = int(self.network_address) + end = int(self.broadcast_address) + 1 + step = (int(self.hostmask) + 1) >> prefixlen_diff + for new_addr in _compat_range(start, end, step): + current = self.__class__((new_addr, new_prefixlen)) + yield current + + def supernet(self, prefixlen_diff=1, new_prefix=None): + """The supernet containing the current network. + + Args: + prefixlen_diff: An integer, the amount the prefix length of + the network should be decreased by. For example, given a + /24 network and a prefixlen_diff of 3, a supernet with a + /21 netmask is returned. + + Returns: + An IPv4 network object. + + Raises: + ValueError: If self.prefixlen - prefixlen_diff < 0. I.e., you have + a negative prefix length. + OR + If prefixlen_diff and new_prefix are both set or new_prefix is a + larger number than the current prefix (larger number means a + smaller network) + + """ + if self._prefixlen == 0: + return self + + if new_prefix is not None: + if new_prefix > self._prefixlen: + raise ValueError('new prefix must be shorter') + if prefixlen_diff != 1: + raise ValueError('cannot set prefixlen_diff and new_prefix') + prefixlen_diff = self._prefixlen - new_prefix + + new_prefixlen = self.prefixlen - prefixlen_diff + if new_prefixlen < 0: + raise ValueError( + 'current prefixlen is %d, cannot have a prefixlen_diff of %d' % + (self.prefixlen, prefixlen_diff)) + return self.__class__(( + int(self.network_address) & (int(self.netmask) << prefixlen_diff), + new_prefixlen)) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return (self.network_address.is_multicast and + self.broadcast_address.is_multicast) + + @staticmethod + def _is_subnet_of(a, b): + try: + # Always false if one is v4 and the other is v6. + if a._version != b._version: + raise TypeError("%s and %s are not of the same version" (a, b)) + return (b.network_address <= a.network_address and + b.broadcast_address >= a.broadcast_address) + except AttributeError: + raise TypeError("Unable to test subnet containment " + "between %s and %s" % (a, b)) + + def subnet_of(self, other): + """Return True if this network is a subnet of other.""" + return self._is_subnet_of(self, other) + + def supernet_of(self, other): + """Return True if this network is a supernet of other.""" + return self._is_subnet_of(other, self) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return (self.network_address.is_reserved and + self.broadcast_address.is_reserved) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return (self.network_address.is_link_local and + self.broadcast_address.is_link_local) + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return (self.network_address.is_private and + self.broadcast_address.is_private) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry or iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return (self.network_address.is_unspecified and + self.broadcast_address.is_unspecified) + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return (self.network_address.is_loopback and + self.broadcast_address.is_loopback) + + +class _BaseV4(object): + + """Base IPv4 object. + + The following methods are used by IPv4 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 4 + # Equivalent to 255.255.255.255 or 32 bits of 1's. + _ALL_ONES = (2 ** IPV4LENGTH) - 1 + _DECIMAL_DIGITS = frozenset('0123456789') + + # the valid octets for host and netmasks. only useful for IPv4. + _valid_mask_octets = frozenset([255, 254, 252, 248, 240, 224, 192, 128, 0]) + + _max_prefixlen = IPV4LENGTH + # There are only a handful of valid v4 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + def _explode_shorthand_ip_string(self): + return _compat_str(self) + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + try: + # Check for a netmask in prefix length form + prefixlen = cls._prefix_from_prefix_string(arg) + except NetmaskValueError: + # Check for a netmask or hostmask in dotted-quad form. + # This may raise NetmaskValueError. + prefixlen = cls._prefix_from_ip_string(arg) + netmask = IPv4Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn the given IP string into an integer for comparison. + + Args: + ip_str: A string, the IP ip_str. + + Returns: + The IP ip_str as an integer. + + Raises: + AddressValueError: if ip_str isn't a valid IPv4 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + octets = ip_str.split('.') + if len(octets) != 4: + raise AddressValueError("Expected 4 octets in %r" % ip_str) + + try: + return _compat_int_from_byte_vals( + map(cls._parse_octet, octets), 'big') + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_octet(cls, octet_str): + """Convert a decimal octet into an integer. + + Args: + octet_str: A string, the number to parse. + + Returns: + The octet as an integer. + + Raises: + ValueError: if the octet isn't strictly a decimal from [0..255]. + + """ + if not octet_str: + raise ValueError("Empty octet not permitted") + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._DECIMAL_DIGITS.issuperset(octet_str): + msg = "Only decimal digits permitted in %r" + raise ValueError(msg % octet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(octet_str) > 3: + msg = "At most 3 characters permitted in %r" + raise ValueError(msg % octet_str) + # Convert to integer (we know digits are legal) + octet_int = int(octet_str, 10) + # Any octets that look like they *might* be written in octal, + # and which don't look exactly the same in both octal and + # decimal are rejected as ambiguous + if octet_int > 7 and octet_str[0] == '0': + msg = "Ambiguous (octal/decimal) value in %r not permitted" + raise ValueError(msg % octet_str) + if octet_int > 255: + raise ValueError("Octet %d (> 255) not permitted" % octet_int) + return octet_int + + @classmethod + def _string_from_ip_int(cls, ip_int): + """Turns a 32-bit integer into dotted decimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + The IP address as a string in dotted decimal notation. + + """ + return '.'.join(_compat_str(struct.unpack(b'!B', b)[0] + if isinstance(b, bytes) + else b) + for b in _compat_to_bytes(ip_int, 4, 'big')) + + def _is_hostmask(self, ip_str): + """Test if the IP string is a hostmask (rather than a netmask). + + Args: + ip_str: A string, the potential hostmask. + + Returns: + A boolean, True if the IP string is a hostmask. + + """ + bits = ip_str.split('.') + try: + parts = [x for x in map(int, bits) if x in self._valid_mask_octets] + except ValueError: + return False + if len(parts) != len(bits): + return False + if parts[0] < parts[-1]: + return True + return False + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv4 address. + + This implements the method described in RFC1035 3.5. + + """ + reverse_octets = _compat_str(self).split('.')[::-1] + return '.'.join(reverse_octets) + '.in-addr.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv4Address(_BaseV4, _BaseAddress): + + """Represent and manipulate single IPv4 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + + """ + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv4Address('192.0.2.1') == IPv4Address(3221225985). + or, more generally + IPv4Address(int(IPv4Address('192.0.2.1'))) == + IPv4Address('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 4) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v4_int_to_packed(self._ip) + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within the + reserved IPv4 Network range. + + """ + return self in self._constants._reserved_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv4-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + return ( + self not in self._constants._public_network and + not self.is_private) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is multicast. + See RFC 3171 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 5735 3. + + """ + return self == self._constants._unspecified_address + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback per RFC 3330. + + """ + return self in self._constants._loopback_network + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is link-local per RFC 3927. + + """ + return self in self._constants._linklocal_network + + +class IPv4Interface(IPv4Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv4Address.__init__(self, address) + self.network = IPv4Network(self._ip) + self._prefixlen = self._max_prefixlen + return + + if isinstance(address, tuple): + IPv4Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + + self.network = IPv4Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv4Address.__init__(self, addr[0]) + + self.network = IPv4Network(address, strict=False) + self._prefixlen = self.network._prefixlen + + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv4Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv4Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv4Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + +class IPv4Network(_BaseV4, _BaseNetwork): + + """This class represents and manipulates 32-bit IPv4 network + addresses.. + + Attributes: [examples for IPv4Network('192.0.2.0/27')] + .network_address: IPv4Address('192.0.2.0') + .hostmask: IPv4Address('0.0.0.31') + .broadcast_address: IPv4Address('192.0.2.32') + .netmask: IPv4Address('255.255.255.224') + .prefixlen: 27 + + """ + # Class to use when creating address objects + _address_class = IPv4Address + + def __init__(self, address, strict=True): + + """Instantiate a new IPv4 network object. + + Args: + address: A string or integer representing the IP [& network]. + '192.0.2.0/24' + '192.0.2.0/255.255.255.0' + '192.0.0.2/0.0.0.255' + are all functionally the same in IPv4. Similarly, + '192.0.2.1' + '192.0.2.1/255.255.255.255' + '192.0.2.1/32' + are also functionally equivalent. That is to say, failing to + provide a subnetmask will create an object with a mask of /32. + + If the mask (portion after the / in the argument) is given in + dotted quad form, it is treated as a netmask if it starts with a + non-zero field (e.g. /255.0.0.0 == /8) and as a hostmask if it + starts with a zero field (e.g. 0.255.255.255 == /8), with the + single exception of an all-zero mask which is treated as a + netmask == /0. If no mask is given, a default of /32 is used. + + Additionally, an integer can be passed, so + IPv4Network('192.0.2.1') == IPv4Network(3221225985) + or, more generally + IPv4Interface(int(IPv4Interface('192.0.2.1'))) == + IPv4Interface('192.0.2.1') + + Raises: + AddressValueError: If ipaddress isn't a valid IPv4 address. + NetmaskValueError: If the netmask isn't valid for + an IPv4 address. + ValueError: If strict is True and a network address is not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Constructing from a packed address or integer + if isinstance(address, (_compat_int_types, bytes)): + self.network_address = IPv4Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + # fixme: address/network test here. + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + # We weren't given an address[1] + arg = self._max_prefixlen + self.network_address = IPv4Address(address[0]) + self.netmask, self._prefixlen = self._make_netmask(arg) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv4Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + self.network_address = IPv4Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv4Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv4Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, True if the address is not reserved per + iana-ipv4-special-registry. + + """ + return (not (self.network_address in IPv4Network('100.64.0.0/10') and + self.broadcast_address in IPv4Network('100.64.0.0/10')) and + not self.is_private) + + +class _IPv4Constants(object): + + _linklocal_network = IPv4Network('169.254.0.0/16') + + _loopback_network = IPv4Network('127.0.0.0/8') + + _multicast_network = IPv4Network('224.0.0.0/4') + + _public_network = IPv4Network('100.64.0.0/10') + + _private_networks = [ + IPv4Network('0.0.0.0/8'), + IPv4Network('10.0.0.0/8'), + IPv4Network('127.0.0.0/8'), + IPv4Network('169.254.0.0/16'), + IPv4Network('172.16.0.0/12'), + IPv4Network('192.0.0.0/29'), + IPv4Network('192.0.0.170/31'), + IPv4Network('192.0.2.0/24'), + IPv4Network('192.168.0.0/16'), + IPv4Network('198.18.0.0/15'), + IPv4Network('198.51.100.0/24'), + IPv4Network('203.0.113.0/24'), + IPv4Network('240.0.0.0/4'), + IPv4Network('255.255.255.255/32'), + ] + + _reserved_network = IPv4Network('240.0.0.0/4') + + _unspecified_address = IPv4Address('0.0.0.0') + + +IPv4Address._constants = _IPv4Constants + + +class _BaseV6(object): + + """Base IPv6 object. + + The following methods are used by IPv6 objects in both single IP + addresses and networks. + + """ + + __slots__ = () + _version = 6 + _ALL_ONES = (2 ** IPV6LENGTH) - 1 + _HEXTET_COUNT = 8 + _HEX_DIGITS = frozenset('0123456789ABCDEFabcdef') + _max_prefixlen = IPV6LENGTH + + # There are only a bunch of valid v6 netmasks, so we cache them all + # when constructed (see _make_netmask()). + _netmask_cache = {} + + @classmethod + def _make_netmask(cls, arg): + """Make a (netmask, prefix_len) tuple from the given argument. + + Argument can be: + - an integer (the prefix length) + - a string representing the prefix length (e.g. "24") + - a string representing the prefix netmask (e.g. "255.255.255.0") + """ + if arg not in cls._netmask_cache: + if isinstance(arg, _compat_int_types): + prefixlen = arg + else: + prefixlen = cls._prefix_from_prefix_string(arg) + netmask = IPv6Address(cls._ip_int_from_prefix(prefixlen)) + cls._netmask_cache[arg] = netmask, prefixlen + return cls._netmask_cache[arg] + + @classmethod + def _ip_int_from_string(cls, ip_str): + """Turn an IPv6 ip_str into an integer. + + Args: + ip_str: A string, the IPv6 ip_str. + + Returns: + An int, the IPv6 address + + Raises: + AddressValueError: if ip_str isn't a valid IPv6 Address. + + """ + if not ip_str: + raise AddressValueError('Address cannot be empty') + + parts = ip_str.split(':') + + # An IPv6 address needs at least 2 colons (3 parts). + _min_parts = 3 + if len(parts) < _min_parts: + msg = "At least %d parts expected in %r" % (_min_parts, ip_str) + raise AddressValueError(msg) + + # If the address has an IPv4-style suffix, convert it to hexadecimal. + if '.' in parts[-1]: + try: + ipv4_int = IPv4Address(parts.pop())._ip + except AddressValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + parts.append('%x' % ((ipv4_int >> 16) & 0xFFFF)) + parts.append('%x' % (ipv4_int & 0xFFFF)) + + # An IPv6 address can't have more than 8 colons (9 parts). + # The extra colon comes from using the "::" notation for a single + # leading or trailing zero part. + _max_parts = cls._HEXTET_COUNT + 1 + if len(parts) > _max_parts: + msg = "At most %d colons permitted in %r" % ( + _max_parts - 1, ip_str) + raise AddressValueError(msg) + + # Disregarding the endpoints, find '::' with nothing in between. + # This indicates that a run of zeroes has been skipped. + skip_index = None + for i in _compat_range(1, len(parts) - 1): + if not parts[i]: + if skip_index is not None: + # Can't have more than one '::' + msg = "At most one '::' permitted in %r" % ip_str + raise AddressValueError(msg) + skip_index = i + + # parts_hi is the number of parts to copy from above/before the '::' + # parts_lo is the number of parts to copy from below/after the '::' + if skip_index is not None: + # If we found a '::', then check if it also covers the endpoints. + parts_hi = skip_index + parts_lo = len(parts) - skip_index - 1 + if not parts[0]: + parts_hi -= 1 + if parts_hi: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + parts_lo -= 1 + if parts_lo: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_skipped = cls._HEXTET_COUNT - (parts_hi + parts_lo) + if parts_skipped < 1: + msg = "Expected at most %d other parts with '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT - 1, ip_str)) + else: + # Otherwise, allocate the entire address to parts_hi. The + # endpoints could still be empty, but _parse_hextet() will check + # for that. + if len(parts) != cls._HEXTET_COUNT: + msg = "Exactly %d parts expected without '::' in %r" + raise AddressValueError(msg % (cls._HEXTET_COUNT, ip_str)) + if not parts[0]: + msg = "Leading ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # ^: requires ^:: + if not parts[-1]: + msg = "Trailing ':' only permitted as part of '::' in %r" + raise AddressValueError(msg % ip_str) # :$ requires ::$ + parts_hi = len(parts) + parts_lo = 0 + parts_skipped = 0 + + try: + # Now, parse the hextets into a 128-bit integer. + ip_int = 0 + for i in range(parts_hi): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + ip_int <<= 16 * parts_skipped + for i in range(-parts_lo, 0): + ip_int <<= 16 + ip_int |= cls._parse_hextet(parts[i]) + return ip_int + except ValueError as exc: + raise AddressValueError("%s in %r" % (exc, ip_str)) + + @classmethod + def _parse_hextet(cls, hextet_str): + """Convert an IPv6 hextet string into an integer. + + Args: + hextet_str: A string, the number to parse. + + Returns: + The hextet as an integer. + + Raises: + ValueError: if the input isn't strictly a hex number from + [0..FFFF]. + + """ + # Whitelist the characters, since int() allows a lot of bizarre stuff. + if not cls._HEX_DIGITS.issuperset(hextet_str): + raise ValueError("Only hex digits permitted in %r" % hextet_str) + # We do the length check second, since the invalid character error + # is likely to be more informative for the user + if len(hextet_str) > 4: + msg = "At most 4 characters permitted in %r" + raise ValueError(msg % hextet_str) + # Length check means we can skip checking the integer value + return int(hextet_str, 16) + + @classmethod + def _compress_hextets(cls, hextets): + """Compresses a list of hextets. + + Compresses a list of strings, replacing the longest continuous + sequence of "0" in the list with "" and adding empty strings at + the beginning or at the end of the string such that subsequently + calling ":".join(hextets) will produce the compressed version of + the IPv6 address. + + Args: + hextets: A list of strings, the hextets to compress. + + Returns: + A list of strings. + + """ + best_doublecolon_start = -1 + best_doublecolon_len = 0 + doublecolon_start = -1 + doublecolon_len = 0 + for index, hextet in enumerate(hextets): + if hextet == '0': + doublecolon_len += 1 + if doublecolon_start == -1: + # Start of a sequence of zeros. + doublecolon_start = index + if doublecolon_len > best_doublecolon_len: + # This is the longest sequence of zeros so far. + best_doublecolon_len = doublecolon_len + best_doublecolon_start = doublecolon_start + else: + doublecolon_len = 0 + doublecolon_start = -1 + + if best_doublecolon_len > 1: + best_doublecolon_end = (best_doublecolon_start + + best_doublecolon_len) + # For zeros at the end of the address. + if best_doublecolon_end == len(hextets): + hextets += [''] + hextets[best_doublecolon_start:best_doublecolon_end] = [''] + # For zeros at the beginning of the address. + if best_doublecolon_start == 0: + hextets = [''] + hextets + + return hextets + + @classmethod + def _string_from_ip_int(cls, ip_int=None): + """Turns a 128-bit integer into hexadecimal notation. + + Args: + ip_int: An integer, the IP address. + + Returns: + A string, the hexadecimal representation of the address. + + Raises: + ValueError: The address is bigger than 128 bits of all ones. + + """ + if ip_int is None: + ip_int = int(cls._ip) + + if ip_int > cls._ALL_ONES: + raise ValueError('IPv6 address is too large') + + hex_str = '%032x' % ip_int + hextets = ['%x' % int(hex_str[x:x + 4], 16) for x in range(0, 32, 4)] + + hextets = cls._compress_hextets(hextets) + return ':'.join(hextets) + + def _explode_shorthand_ip_string(self): + """Expand a shortened IPv6 address. + + Args: + ip_str: A string, the IPv6 address. + + Returns: + A string, the expanded IPv6 address. + + """ + if isinstance(self, IPv6Network): + ip_str = _compat_str(self.network_address) + elif isinstance(self, IPv6Interface): + ip_str = _compat_str(self.ip) + else: + ip_str = _compat_str(self) + + ip_int = self._ip_int_from_string(ip_str) + hex_str = '%032x' % ip_int + parts = [hex_str[x:x + 4] for x in range(0, 32, 4)] + if isinstance(self, (_BaseNetwork, IPv6Interface)): + return '%s/%d' % (':'.join(parts), self._prefixlen) + return ':'.join(parts) + + def _reverse_pointer(self): + """Return the reverse DNS pointer name for the IPv6 address. + + This implements the method described in RFC3596 2.5. + + """ + reverse_chars = self.exploded[::-1].replace(':', '') + return '.'.join(reverse_chars) + '.ip6.arpa' + + @property + def max_prefixlen(self): + return self._max_prefixlen + + @property + def version(self): + return self._version + + +class IPv6Address(_BaseV6, _BaseAddress): + + """Represent and manipulate single IPv6 Addresses.""" + + __slots__ = ('_ip', '__weakref__') + + def __init__(self, address): + """Instantiate a new IPv6 address object. + + Args: + address: A string or integer representing the IP + + Additionally, an integer can be passed, so + IPv6Address('2001:db8::') == + IPv6Address(42540766411282592856903984951653826560) + or, more generally + IPv6Address(int(IPv6Address('2001:db8::'))) == + IPv6Address('2001:db8::') + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + + """ + # Efficient constructor from integer. + if isinstance(address, _compat_int_types): + self._check_int_address(address) + self._ip = address + return + + # Constructing from a packed address + if isinstance(address, bytes): + self._check_packed_address(address, 16) + bvs = _compat_bytes_to_byte_vals(address) + self._ip = _compat_int_from_byte_vals(bvs, 'big') + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP string. + addr_str = _compat_str(address) + if '/' in addr_str: + raise AddressValueError("Unexpected '/' in %r" % address) + self._ip = self._ip_int_from_string(addr_str) + + @property + def packed(self): + """The binary representation of this address.""" + return v6_int_to_packed(self._ip) + + @property + def is_multicast(self): + """Test if the address is reserved for multicast use. + + Returns: + A boolean, True if the address is a multicast address. + See RFC 2373 2.7 for details. + + """ + return self in self._constants._multicast_network + + @property + def is_reserved(self): + """Test if the address is otherwise IETF reserved. + + Returns: + A boolean, True if the address is within one of the + reserved IPv6 Network ranges. + + """ + return any(self in x for x in self._constants._reserved_networks) + + @property + def is_link_local(self): + """Test if the address is reserved for link-local. + + Returns: + A boolean, True if the address is reserved per RFC 4291. + + """ + return self in self._constants._linklocal_network + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return self in self._constants._sitelocal_network + + @property + def is_private(self): + """Test if this address is allocated for private networks. + + Returns: + A boolean, True if the address is reserved per + iana-ipv6-special-registry. + + """ + return any(self in net for net in self._constants._private_networks) + + @property + def is_global(self): + """Test if this address is allocated for public networks. + + Returns: + A boolean, true if the address is not reserved per + iana-ipv6-special-registry. + + """ + return not self.is_private + + @property + def is_unspecified(self): + """Test if the address is unspecified. + + Returns: + A boolean, True if this is the unspecified address as defined in + RFC 2373 2.5.2. + + """ + return self._ip == 0 + + @property + def is_loopback(self): + """Test if the address is a loopback address. + + Returns: + A boolean, True if the address is a loopback address as defined in + RFC 2373 2.5.3. + + """ + return self._ip == 1 + + @property + def ipv4_mapped(self): + """Return the IPv4 mapped address. + + Returns: + If the IPv6 address is a v4 mapped address, return the + IPv4 mapped address. Return None otherwise. + + """ + if (self._ip >> 32) != 0xFFFF: + return None + return IPv4Address(self._ip & 0xFFFFFFFF) + + @property + def teredo(self): + """Tuple of embedded teredo IPs. + + Returns: + Tuple of the (server, client) IPs or None if the address + doesn't appear to be a teredo address (doesn't start with + 2001::/32) + + """ + if (self._ip >> 96) != 0x20010000: + return None + return (IPv4Address((self._ip >> 64) & 0xFFFFFFFF), + IPv4Address(~self._ip & 0xFFFFFFFF)) + + @property + def sixtofour(self): + """Return the IPv4 6to4 embedded address. + + Returns: + The IPv4 6to4-embedded address if present or None if the + address doesn't appear to contain a 6to4 embedded address. + + """ + if (self._ip >> 112) != 0x2002: + return None + return IPv4Address((self._ip >> 80) & 0xFFFFFFFF) + + +class IPv6Interface(IPv6Address): + + def __init__(self, address): + if isinstance(address, (bytes, _compat_int_types)): + IPv6Address.__init__(self, address) + self.network = IPv6Network(self._ip) + self._prefixlen = self._max_prefixlen + return + if isinstance(address, tuple): + IPv6Address.__init__(self, address[0]) + if len(address) > 1: + self._prefixlen = int(address[1]) + else: + self._prefixlen = self._max_prefixlen + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self.hostmask = self.network.hostmask + return + + addr = _split_optional_netmask(address) + IPv6Address.__init__(self, addr[0]) + self.network = IPv6Network(address, strict=False) + self.netmask = self.network.netmask + self._prefixlen = self.network._prefixlen + self.hostmask = self.network.hostmask + + def __str__(self): + return '%s/%d' % (self._string_from_ip_int(self._ip), + self.network.prefixlen) + + def __eq__(self, other): + address_equal = IPv6Address.__eq__(self, other) + if not address_equal or address_equal is NotImplemented: + return address_equal + try: + return self.network == other.network + except AttributeError: + # An interface with an associated network is NOT the + # same as an unassociated address. That's why the hash + # takes the extra info into account. + return False + + def __lt__(self, other): + address_less = IPv6Address.__lt__(self, other) + if address_less is NotImplemented: + return NotImplemented + try: + return (self.network < other.network or + self.network == other.network and address_less) + except AttributeError: + # We *do* allow addresses and interfaces to be sorted. The + # unassociated address is considered less than all interfaces. + return False + + def __hash__(self): + return self._ip ^ self._prefixlen ^ int(self.network.network_address) + + __reduce__ = _IPAddressBase.__reduce__ + + @property + def ip(self): + return IPv6Address(self._ip) + + @property + def with_prefixlen(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self._prefixlen) + + @property + def with_netmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.netmask) + + @property + def with_hostmask(self): + return '%s/%s' % (self._string_from_ip_int(self._ip), + self.hostmask) + + @property + def is_unspecified(self): + return self._ip == 0 and self.network.is_unspecified + + @property + def is_loopback(self): + return self._ip == 1 and self.network.is_loopback + + +class IPv6Network(_BaseV6, _BaseNetwork): + + """This class represents and manipulates 128-bit IPv6 networks. + + Attributes: [examples for IPv6('2001:db8::1000/124')] + .network_address: IPv6Address('2001:db8::1000') + .hostmask: IPv6Address('::f') + .broadcast_address: IPv6Address('2001:db8::100f') + .netmask: IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0') + .prefixlen: 124 + + """ + + # Class to use when creating address objects + _address_class = IPv6Address + + def __init__(self, address, strict=True): + """Instantiate a new IPv6 Network object. + + Args: + address: A string or integer representing the IPv6 network or the + IP and prefix/netmask. + '2001:db8::/128' + '2001:db8:0000:0000:0000:0000:0000:0000/128' + '2001:db8::' + are all functionally the same in IPv6. That is to say, + failing to provide a subnetmask will create an object with + a mask of /128. + + Additionally, an integer can be passed, so + IPv6Network('2001:db8::') == + IPv6Network(42540766411282592856903984951653826560) + or, more generally + IPv6Network(int(IPv6Network('2001:db8::'))) == + IPv6Network('2001:db8::') + + strict: A boolean. If true, ensure that we have been passed + A true network address, eg, 2001:db8::1000/124 and not an + IP address on a network, eg, 2001:db8::1/124. + + Raises: + AddressValueError: If address isn't a valid IPv6 address. + NetmaskValueError: If the netmask isn't valid for + an IPv6 address. + ValueError: If strict was True and a network address was not + supplied. + + """ + _BaseNetwork.__init__(self, address) + + # Efficient constructor from integer or packed address + if isinstance(address, (bytes, _compat_int_types)): + self.network_address = IPv6Address(address) + self.netmask, self._prefixlen = self._make_netmask( + self._max_prefixlen) + return + + if isinstance(address, tuple): + if len(address) > 1: + arg = address[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + self.network_address = IPv6Address(address[0]) + packed = int(self.network_address) + if packed & int(self.netmask) != packed: + if strict: + raise ValueError('%s has host bits set' % self) + else: + self.network_address = IPv6Address(packed & + int(self.netmask)) + return + + # Assume input argument to be string or any object representation + # which converts into a formatted IP prefix string. + addr = _split_optional_netmask(address) + + self.network_address = IPv6Address(self._ip_int_from_string(addr[0])) + + if len(addr) == 2: + arg = addr[1] + else: + arg = self._max_prefixlen + self.netmask, self._prefixlen = self._make_netmask(arg) + + if strict: + if (IPv6Address(int(self.network_address) & int(self.netmask)) != + self.network_address): + raise ValueError('%s has host bits set' % self) + self.network_address = IPv6Address(int(self.network_address) & + int(self.netmask)) + + if self._prefixlen == (self._max_prefixlen - 1): + self.hosts = self.__iter__ + + def hosts(self): + """Generate Iterator over usable hosts in a network. + + This is like __iter__ except it doesn't return the + Subnet-Router anycast address. + + """ + network = int(self.network_address) + broadcast = int(self.broadcast_address) + for x in _compat_range(network + 1, broadcast + 1): + yield self._address_class(x) + + @property + def is_site_local(self): + """Test if the address is reserved for site-local. + + Note that the site-local address space has been deprecated by RFC 3879. + Use is_private to test if this address is in the space of unique local + addresses as defined by RFC 4193. + + Returns: + A boolean, True if the address is reserved per RFC 3513 2.5.6. + + """ + return (self.network_address.is_site_local and + self.broadcast_address.is_site_local) + + +class _IPv6Constants(object): + + _linklocal_network = IPv6Network('fe80::/10') + + _multicast_network = IPv6Network('ff00::/8') + + _private_networks = [ + IPv6Network('::1/128'), + IPv6Network('::/128'), + IPv6Network('::ffff:0:0/96'), + IPv6Network('100::/64'), + IPv6Network('2001::/23'), + IPv6Network('2001:2::/48'), + IPv6Network('2001:db8::/32'), + IPv6Network('2001:10::/28'), + IPv6Network('fc00::/7'), + IPv6Network('fe80::/10'), + ] + + _reserved_networks = [ + IPv6Network('::/8'), IPv6Network('100::/8'), + IPv6Network('200::/7'), IPv6Network('400::/6'), + IPv6Network('800::/5'), IPv6Network('1000::/4'), + IPv6Network('4000::/3'), IPv6Network('6000::/3'), + IPv6Network('8000::/3'), IPv6Network('A000::/3'), + IPv6Network('C000::/3'), IPv6Network('E000::/4'), + IPv6Network('F000::/5'), IPv6Network('F800::/6'), + IPv6Network('FE00::/9'), + ] + + _sitelocal_network = IPv6Network('fec0::/10') + + +IPv6Address._constants = _IPv6Constants diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py new file mode 100755 index 0000000..228e051 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/__init__.py @@ -0,0 +1,347 @@ +# -*- coding: utf-8 -*- + +""" +lockfile.py - Platform-independent advisory file locks. + +Requires Python 2.5 unless you apply 2.4.diff +Locking is done on a per-thread basis instead of a per-process basis. + +Usage: + +>>> lock = LockFile('somefile') +>>> try: +... lock.acquire() +... except AlreadyLocked: +... print 'somefile', 'is locked already.' +... except LockFailed: +... print 'somefile', 'can\\'t be locked.' +... else: +... print 'got lock' +got lock +>>> print lock.is_locked() +True +>>> lock.release() + +>>> lock = LockFile('somefile') +>>> print lock.is_locked() +False +>>> with lock: +... print lock.is_locked() +True +>>> print lock.is_locked() +False + +>>> lock = LockFile('somefile') +>>> # It is okay to lock twice from the same thread... +>>> with lock: +... lock.acquire() +... +>>> # Though no counter is kept, so you can't unlock multiple times... +>>> print lock.is_locked() +False + +Exceptions: + + Error - base class for other exceptions + LockError - base class for all locking exceptions + AlreadyLocked - Another thread or process already holds the lock + LockFailed - Lock failed for some other reason + UnlockError - base class for all unlocking exceptions + AlreadyUnlocked - File was not locked. + NotMyLock - File was locked but not by the current thread/process +""" + +from __future__ import absolute_import + +import functools +import os +import socket +import threading +import warnings + +# Work with PEP8 and non-PEP8 versions of threading module. +if not hasattr(threading, "current_thread"): + threading.current_thread = threading.currentThread +if not hasattr(threading.Thread, "get_name"): + threading.Thread.get_name = threading.Thread.getName + +__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked', + 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock', + 'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock', + 'LockBase', 'locked'] + + +class Error(Exception): + """ + Base class for other exceptions. + + >>> try: + ... raise Error + ... except Exception: + ... pass + """ + pass + + +class LockError(Error): + """ + Base class for error arising from attempts to acquire the lock. + + >>> try: + ... raise LockError + ... except Error: + ... pass + """ + pass + + +class LockTimeout(LockError): + """Raised when lock creation fails within a user-defined period of time. + + >>> try: + ... raise LockTimeout + ... except LockError: + ... pass + """ + pass + + +class AlreadyLocked(LockError): + """Some other thread/process is locking the file. + + >>> try: + ... raise AlreadyLocked + ... except LockError: + ... pass + """ + pass + + +class LockFailed(LockError): + """Lock file creation failed for some other reason. + + >>> try: + ... raise LockFailed + ... except LockError: + ... pass + """ + pass + + +class UnlockError(Error): + """ + Base class for errors arising from attempts to release the lock. + + >>> try: + ... raise UnlockError + ... except Error: + ... pass + """ + pass + + +class NotLocked(UnlockError): + """Raised when an attempt is made to unlock an unlocked file. + + >>> try: + ... raise NotLocked + ... except UnlockError: + ... pass + """ + pass + + +class NotMyLock(UnlockError): + """Raised when an attempt is made to unlock a file someone else locked. + + >>> try: + ... raise NotMyLock + ... except UnlockError: + ... pass + """ + pass + + +class _SharedBase(object): + def __init__(self, path): + self.path = path + + def acquire(self, timeout=None): + """ + Acquire the lock. + + * If timeout is omitted (or None), wait forever trying to lock the + file. + + * If timeout > 0, try to acquire the lock for that many seconds. If + the lock period expires and the file is still locked, raise + LockTimeout. + + * If timeout <= 0, raise AlreadyLocked immediately if the file is + already locked. + """ + raise NotImplemented("implement in subclass") + + def release(self): + """ + Release the lock. + + If the file is not locked, raise NotLocked. + """ + raise NotImplemented("implement in subclass") + + def __enter__(self): + """ + Context manager support. + """ + self.acquire() + return self + + def __exit__(self, *_exc): + """ + Context manager support. + """ + self.release() + + def __repr__(self): + return "<%s: %r>" % (self.__class__.__name__, self.path) + + +class LockBase(_SharedBase): + """Base class for platform-specific lock classes.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = LockBase('somefile') + >>> lock = LockBase('somefile', threaded=False) + """ + super(LockBase, self).__init__(path) + self.lock_file = os.path.abspath(path) + ".lock" + self.hostname = socket.gethostname() + self.pid = os.getpid() + if threaded: + t = threading.current_thread() + # Thread objects in Python 2.4 and earlier do not have ident + # attrs. Worm around that. + ident = getattr(t, "ident", hash(t)) + self.tname = "-%x" % (ident & 0xffffffff) + else: + self.tname = "" + dirname = os.path.dirname(self.lock_file) + + # unique name is mostly about the current process, but must + # also contain the path -- otherwise, two adjacent locked + # files conflict (one file gets locked, creating lock-file and + # unique file, the other one gets locked, creating lock-file + # and overwriting the already existing lock-file, then one + # gets unlocked, deleting both lock-file and unique file, + # finally the last lock errors out upon releasing. + self.unique_name = os.path.join(dirname, + "%s%s.%s%s" % (self.hostname, + self.tname, + self.pid, + hash(self.path))) + self.timeout = timeout + + def is_locked(self): + """ + Tell whether or not the file is locked. + """ + raise NotImplemented("implement in subclass") + + def i_am_locking(self): + """ + Return True if this object is locking the file. + """ + raise NotImplemented("implement in subclass") + + def break_lock(self): + """ + Remove a lock. Useful if a locking thread failed to unlock. + """ + raise NotImplemented("implement in subclass") + + def __repr__(self): + return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, + self.path) + + +def _fl_helper(cls, mod, *args, **kwds): + warnings.warn("Import from %s module instead of lockfile package" % mod, + DeprecationWarning, stacklevel=2) + # This is a bit funky, but it's only for awhile. The way the unit tests + # are constructed this function winds up as an unbound method, so it + # actually takes three args, not two. We want to toss out self. + if not isinstance(args[0], str): + # We are testing, avoid the first arg + args = args[1:] + if len(args) == 1 and not kwds: + kwds["threaded"] = True + return cls(*args, **kwds) + + +def LinkFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import LinkLockFile from the + lockfile.linklockfile module. + """ + from . import linklockfile + return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", + *args, **kwds) + + +def MkdirFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import MkdirLockFile from the + lockfile.mkdirlockfile module. + """ + from . import mkdirlockfile + return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", + *args, **kwds) + + +def SQLiteFileLock(*args, **kwds): + """Factory function provided for backwards compatibility. + + Do not use in new code. Instead, import SQLiteLockFile from the + lockfile.mkdirlockfile module. + """ + from . import sqlitelockfile + return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", + *args, **kwds) + + +def locked(path, timeout=None): + """Decorator which enables locks for decorated function. + + Arguments: + - path: path for lockfile. + - timeout (optional): Timeout for acquiring lock. + + Usage: + @locked('/var/run/myname', timeout=0) + def myname(...): + ... + """ + def decor(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + lock = FileLock(path, timeout=timeout) + lock.acquire() + try: + return func(*args, **kwargs) + finally: + lock.release() + return wrapper + return decor + + +if hasattr(os, "link"): + from . import linklockfile as _llf + LockFile = _llf.LinkLockFile +else: + from . import mkdirlockfile as _mlf + LockFile = _mlf.MkdirLockFile + +FileLock = LockFile diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py new file mode 100755 index 0000000..11af0f3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/linklockfile.py @@ -0,0 +1,73 @@ +from __future__ import absolute_import + +import time +import os + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class LinkLockFile(LockBase): + """Lock access to a file using atomic property of link(2). + + >>> lock = LinkLockFile('somefile') + >>> lock = LinkLockFile('somefile', threaded=False) + """ + + def acquire(self, timeout=None): + try: + open(self.unique_name, "wb").close() + except IOError: + raise LockFailed("failed to create %s" % self.unique_name) + + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a hard link to it. + try: + os.link(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + nlinks = os.stat(self.unique_name).st_nlink + if nlinks == 2: + # The original link plus the one I created == 2. We're + # good to go. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + os.unlink(self.unique_name) + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout / 10 or 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name) and + os.stat(self.unique_name).st_nlink == 2) + + def break_lock(self): + if os.path.exists(self.lock_file): + os.unlink(self.lock_file) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py new file mode 100755 index 0000000..bd5a51e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/mkdirlockfile.py @@ -0,0 +1,84 @@ +from __future__ import absolute_import, division + +import time +import os +import sys +import errno + +from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class MkdirLockFile(LockBase): + """Lock file by creating a directory.""" + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = MkdirLockFile('somefile') + >>> lock = MkdirLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + # Lock file itself is a directory. Place the unique file name into + # it. + self.unique_name = os.path.join(self.lock_file, + "%s.%s%s" % (self.hostname, + self.tname, + self.pid)) + + def acquire(self, timeout=None): + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + else: + wait = max(0, timeout / 10) + + while True: + try: + os.mkdir(self.lock_file) + except OSError: + err = sys.exc_info()[1] + if err.errno == errno.EEXIST: + # Already locked. + if os.path.exists(self.unique_name): + # Already locked by me. + return + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock. + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(wait) + else: + # Couldn't create the lock for some other reason + raise LockFailed("failed to create %s" % self.lock_file) + else: + open(self.unique_name, "wb").close() + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not os.path.exists(self.unique_name): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.unique_name) + os.rmdir(self.lock_file) + + def is_locked(self): + return os.path.exists(self.lock_file) + + def i_am_locking(self): + return (self.is_locked() and + os.path.exists(self.unique_name)) + + def break_lock(self): + if os.path.exists(self.lock_file): + for name in os.listdir(self.lock_file): + os.unlink(os.path.join(self.lock_file, name)) + os.rmdir(self.lock_file) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py new file mode 100755 index 0000000..d776de5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/pidlockfile.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +# pidlockfile.py +# +# Copyright © 2008–2009 Ben Finney <ben+python@benfinney.id.au> +# +# This is free software: you may copy, modify, and/or distribute this work +# under the terms of the Python Software Foundation License, version 2 or +# later as published by the Python Software Foundation. +# No warranty expressed or implied. See the file LICENSE.PSF-2 for details. + +""" Lockfile behaviour implemented via Unix PID files. + """ + +from __future__ import absolute_import + +import errno +import os +import time + +from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, + LockTimeout) + + +class PIDLockFile(LockBase): + """ Lockfile implemented as a Unix PID file. + + The lock file is a normal file named by the attribute `path`. + A lock's PID file contains a single line of text, containing + the process ID (PID) of the process that acquired the lock. + + >>> lock = PIDLockFile('somefile') + >>> lock = PIDLockFile('somefile') + """ + + def __init__(self, path, threaded=False, timeout=None): + # pid lockfiles don't support threaded operation, so always force + # False as the threaded arg. + LockBase.__init__(self, path, False, timeout) + self.unique_name = self.path + + def read_pid(self): + """ Get the PID from the lock file. + """ + return read_pid_from_pidfile(self.path) + + def is_locked(self): + """ Test if the lock is currently held. + + The lock is held if the PID file for this lock exists. + + """ + return os.path.exists(self.path) + + def i_am_locking(self): + """ Test if the lock is held by the current process. + + Returns ``True`` if the current process ID matches the + number stored in the PID file. + """ + return self.is_locked() and os.getpid() == self.read_pid() + + def acquire(self, timeout=None): + """ Acquire the lock. + + Creates the PID file for this lock, or raises an error if + the lock could not be acquired. + """ + + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + try: + write_pid_to_pidfile(self.path) + except OSError as exc: + if exc.errno == errno.EEXIST: + # The lock creation failed. Maybe sleep a bit. + if time.time() > end_time: + if timeout is not None and timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout is not None and timeout / 10 or 0.1) + else: + raise LockFailed("failed to create %s" % self.path) + else: + return + + def release(self): + """ Release the lock. + + Removes the PID file to release the lock, or raises an + error if the current process does not hold the lock. + + """ + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + remove_existing_pidfile(self.path) + + def break_lock(self): + """ Break an existing lock. + + Removes the PID file if it already exists, otherwise does + nothing. + + """ + remove_existing_pidfile(self.path) + + +def read_pid_from_pidfile(pidfile_path): + """ Read the PID recorded in the named PID file. + + Read and return the numeric PID recorded as text in the named + PID file. If the PID file cannot be read, or if the content is + not a valid PID, return ``None``. + + """ + pid = None + try: + pidfile = open(pidfile_path, 'r') + except IOError: + pass + else: + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. + # + # Programs that read PID files should be somewhat flexible + # in what they accept; i.e., they should ignore extra + # whitespace, leading zeroes, absence of the trailing + # newline, or additional lines in the PID file. + + line = pidfile.readline().strip() + try: + pid = int(line) + except ValueError: + pass + pidfile.close() + + return pid + + +def write_pid_to_pidfile(pidfile_path): + """ Write the PID in the named PID file. + + Get the numeric process ID (“PID”) of the current process + and write it to the named file as a line of text. + + """ + open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) + open_mode = 0o644 + pidfile_fd = os.open(pidfile_path, open_flags, open_mode) + pidfile = os.fdopen(pidfile_fd, 'w') + + # According to the FHS 2.3 section on PID files in /var/run: + # + # The file must consist of the process identifier in + # ASCII-encoded decimal, followed by a newline character. For + # example, if crond was process number 25, /var/run/crond.pid + # would contain three characters: two, five, and newline. + + pid = os.getpid() + pidfile.write("%s\n" % pid) + pidfile.close() + + +def remove_existing_pidfile(pidfile_path): + """ Remove the named PID file if it exists. + + Removing a PID file that doesn't already exist puts us in the + desired state, so we ignore the condition if the file does not + exist. + + """ + try: + os.remove(pidfile_path) + except OSError as exc: + if exc.errno == errno.ENOENT: + pass + else: + raise diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py new file mode 100755 index 0000000..278dff4 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/sqlitelockfile.py @@ -0,0 +1,156 @@ +from __future__ import absolute_import, division + +import time +import os + +try: + unicode +except NameError: + unicode = str + +from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked + + +class SQLiteLockFile(LockBase): + "Demonstrate SQL-based locking." + + testdb = None + + def __init__(self, path, threaded=True, timeout=None): + """ + >>> lock = SQLiteLockFile('somefile') + >>> lock = SQLiteLockFile('somefile', threaded=False) + """ + LockBase.__init__(self, path, threaded, timeout) + self.lock_file = unicode(self.lock_file) + self.unique_name = unicode(self.unique_name) + + if SQLiteLockFile.testdb is None: + import tempfile + _fd, testdb = tempfile.mkstemp() + os.close(_fd) + os.unlink(testdb) + del _fd, tempfile + SQLiteLockFile.testdb = testdb + + import sqlite3 + self.connection = sqlite3.connect(SQLiteLockFile.testdb) + + c = self.connection.cursor() + try: + c.execute("create table locks" + "(" + " lock_file varchar(32)," + " unique_name varchar(32)" + ")") + except sqlite3.OperationalError: + pass + else: + self.connection.commit() + import atexit + atexit.register(os.unlink, SQLiteLockFile.testdb) + + def acquire(self, timeout=None): + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + if timeout is None: + wait = 0.1 + elif timeout <= 0: + wait = 0 + else: + wait = timeout / 10 + + cursor = self.connection.cursor() + + while True: + if not self.is_locked(): + # Not locked. Try to lock it. + cursor.execute("insert into locks" + " (lock_file, unique_name)" + " values" + " (?, ?)", + (self.lock_file, self.unique_name)) + self.connection.commit() + + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) > 1: + # Nope. Someone else got there. Remove our lock. + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + else: + # Yup. We're done, so go home. + return + else: + # Check to see if we are the only lock holder. + cursor.execute("select * from locks" + " where unique_name = ?", + (self.unique_name,)) + rows = cursor.fetchall() + if len(rows) == 1: + # We're the locker, so go home. + return + + # Maybe we should wait a bit longer. + if timeout is not None and time.time() > end_time: + if timeout > 0: + # No more waiting. + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + # Someone else has the lock and we are impatient.. + raise AlreadyLocked("%s is already locked" % self.path) + + # Well, okay. We'll give it a bit longer. + time.sleep(wait) + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + if not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me (by %s)" % + (self.unique_name, self._who_is_locking())) + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where unique_name = ?", + (self.unique_name,)) + self.connection.commit() + + def _who_is_locking(self): + cursor = self.connection.cursor() + cursor.execute("select unique_name from locks" + " where lock_file = ?", + (self.lock_file,)) + return cursor.fetchone()[0] + + def is_locked(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?", + (self.lock_file,)) + rows = cursor.fetchall() + return not not rows + + def i_am_locking(self): + cursor = self.connection.cursor() + cursor.execute("select * from locks" + " where lock_file = ?" + " and unique_name = ?", + (self.lock_file, self.unique_name)) + return not not cursor.fetchall() + + def break_lock(self): + cursor = self.connection.cursor() + cursor.execute("delete from locks" + " where lock_file = ?", + (self.lock_file,)) + self.connection.commit() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py new file mode 100755 index 0000000..93ff2b5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/lockfile/symlinklockfile.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import + +import os +import time + +from . import (LockBase, NotLocked, NotMyLock, LockTimeout, + AlreadyLocked) + + +class SymlinkLockFile(LockBase): + """Lock access to a file using symlink(2).""" + + def __init__(self, path, threaded=True, timeout=None): + # super(SymlinkLockFile).__init(...) + LockBase.__init__(self, path, threaded, timeout) + # split it back! + self.unique_name = os.path.split(self.unique_name)[1] + + def acquire(self, timeout=None): + # Hopefully unnecessary for symlink. + # try: + # open(self.unique_name, "wb").close() + # except IOError: + # raise LockFailed("failed to create %s" % self.unique_name) + timeout = timeout if timeout is not None else self.timeout + end_time = time.time() + if timeout is not None and timeout > 0: + end_time += timeout + + while True: + # Try and create a symbolic link to it. + try: + os.symlink(self.unique_name, self.lock_file) + except OSError: + # Link creation failed. Maybe we've double-locked? + if self.i_am_locking(): + # Linked to out unique name. Proceed. + return + else: + # Otherwise the lock creation failed. + if timeout is not None and time.time() > end_time: + if timeout > 0: + raise LockTimeout("Timeout waiting to acquire" + " lock for %s" % + self.path) + else: + raise AlreadyLocked("%s is already locked" % + self.path) + time.sleep(timeout / 10 if timeout is not None else 0.1) + else: + # Link creation succeeded. We're good to go. + return + + def release(self): + if not self.is_locked(): + raise NotLocked("%s is not locked" % self.path) + elif not self.i_am_locking(): + raise NotMyLock("%s is locked, but not by me" % self.path) + os.unlink(self.lock_file) + + def is_locked(self): + return os.path.islink(self.lock_file) + + def i_am_locking(self): + return (os.path.islink(self.lock_file) + and os.readlink(self.lock_file) == self.unique_name) + + def break_lock(self): + if os.path.islink(self.lock_file): # exists && link + os.unlink(self.lock_file) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py new file mode 100755 index 0000000..dda626a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/__init__.py @@ -0,0 +1,66 @@ +# coding: utf-8 +from pip._vendor.msgpack._version import version +from pip._vendor.msgpack.exceptions import * + +from collections import namedtuple + + +class ExtType(namedtuple('ExtType', 'code data')): + """ExtType represents ext type in msgpack.""" + def __new__(cls, code, data): + if not isinstance(code, int): + raise TypeError("code must be int") + if not isinstance(data, bytes): + raise TypeError("data must be bytes") + if not 0 <= code <= 127: + raise ValueError("code must be 0~127") + return super(ExtType, cls).__new__(cls, code, data) + + +import os +if os.environ.get('MSGPACK_PUREPYTHON'): + from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker +else: + try: + from pip._vendor.msgpack._packer import Packer + from pip._vendor.msgpack._unpacker import unpackb, Unpacker + except ImportError: + from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker + + +def pack(o, stream, **kwargs): + """ + Pack object `o` and write it to `stream` + + See :class:`Packer` for options. + """ + packer = Packer(**kwargs) + stream.write(packer.pack(o)) + + +def packb(o, **kwargs): + """ + Pack object `o` and return packed bytes + + See :class:`Packer` for options. + """ + return Packer(**kwargs).pack(o) + + +def unpack(stream, **kwargs): + """ + Unpack an object from `stream`. + + Raises `ExtraData` when `stream` contains extra bytes. + See :class:`Unpacker` for options. + """ + data = stream.read() + return unpackb(data, **kwargs) + + +# alias for compatibility to simplejson/marshal/pickle. +load = unpack +loads = unpackb + +dump = pack +dumps = packb diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py new file mode 100755 index 0000000..91d97cd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/_version.py @@ -0,0 +1 @@ +version = (0, 5, 6) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py new file mode 100755 index 0000000..e0b5133 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/exceptions.py @@ -0,0 +1,41 @@ +class UnpackException(Exception): + """Deprecated. Use Exception instead to catch all exception during unpacking.""" + + +class BufferFull(UnpackException): + pass + + +class OutOfData(UnpackException): + pass + + +class UnpackValueError(UnpackException, ValueError): + """Deprecated. Use ValueError instead.""" + + +class ExtraData(UnpackValueError): + def __init__(self, unpacked, extra): + self.unpacked = unpacked + self.extra = extra + + def __str__(self): + return "unpack(b) received extra data." + + +class PackException(Exception): + """Deprecated. Use Exception instead to catch all exception during packing.""" + + +class PackValueError(PackException, ValueError): + """PackValueError is raised when type of input data is supported but it's value is unsupported. + + Deprecated. Use ValueError instead. + """ + + +class PackOverflowError(PackValueError, OverflowError): + """PackOverflowError is raised when integer value is out of range of msgpack support [-2**31, 2**32). + + Deprecated. Use ValueError instead. + """ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py new file mode 100755 index 0000000..a1a9712 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/msgpack/fallback.py @@ -0,0 +1,977 @@ +"""Fallback pure Python implementation of msgpack""" + +import sys +import struct +import warnings + +if sys.version_info[0] == 3: + PY3 = True + int_types = int + Unicode = str + xrange = range + def dict_iteritems(d): + return d.items() +else: + PY3 = False + int_types = (int, long) + Unicode = unicode + def dict_iteritems(d): + return d.iteritems() + + +if hasattr(sys, 'pypy_version_info'): + # cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own + # StringBuilder is fastest. + from __pypy__ import newlist_hint + try: + from __pypy__.builders import BytesBuilder as StringBuilder + except ImportError: + from __pypy__.builders import StringBuilder + USING_STRINGBUILDER = True + class StringIO(object): + def __init__(self, s=b''): + if s: + self.builder = StringBuilder(len(s)) + self.builder.append(s) + else: + self.builder = StringBuilder() + def write(self, s): + if isinstance(s, memoryview): + s = s.tobytes() + elif isinstance(s, bytearray): + s = bytes(s) + self.builder.append(s) + def getvalue(self): + return self.builder.build() +else: + USING_STRINGBUILDER = False + from io import BytesIO as StringIO + newlist_hint = lambda size: [] + + +from pip._vendor.msgpack.exceptions import ( + BufferFull, + OutOfData, + UnpackValueError, + PackValueError, + PackOverflowError, + ExtraData) + +from pip._vendor.msgpack import ExtType + + +EX_SKIP = 0 +EX_CONSTRUCT = 1 +EX_READ_ARRAY_HEADER = 2 +EX_READ_MAP_HEADER = 3 + +TYPE_IMMEDIATE = 0 +TYPE_ARRAY = 1 +TYPE_MAP = 2 +TYPE_RAW = 3 +TYPE_BIN = 4 +TYPE_EXT = 5 + +DEFAULT_RECURSE_LIMIT = 511 + + +def _check_type_strict(obj, t, type=type, tuple=tuple): + if type(t) is tuple: + return type(obj) in t + else: + return type(obj) is t + + +def _get_data_from_buffer(obj): + try: + view = memoryview(obj) + except TypeError: + # try to use legacy buffer protocol if 2.7, otherwise re-raise + if not PY3: + view = memoryview(buffer(obj)) + warnings.warn("using old buffer interface to unpack %s; " + "this leads to unpacking errors if slicing is used and " + "will be removed in a future version" % type(obj), + RuntimeWarning) + else: + raise + if view.itemsize != 1: + raise ValueError("cannot unpack from multi-byte object") + return view + + +def unpack(stream, **kwargs): + warnings.warn( + "Direct calling implementation's unpack() is deprecated, Use msgpack.unpack() or unpackb() instead.", + PendingDeprecationWarning) + data = stream.read() + return unpackb(data, **kwargs) + + +def unpackb(packed, **kwargs): + """ + Unpack an object from `packed`. + + Raises `ExtraData` when `packed` contains extra bytes. + See :class:`Unpacker` for options. + """ + unpacker = Unpacker(None, **kwargs) + unpacker.feed(packed) + try: + ret = unpacker._unpack() + except OutOfData: + raise UnpackValueError("Data is not enough.") + if unpacker._got_extradata(): + raise ExtraData(ret, unpacker._get_extradata()) + return ret + + +class Unpacker(object): + """Streaming unpacker. + + arguments: + + :param file_like: + File-like object having `.read(n)` method. + If specified, unpacker reads serialized data from it and :meth:`feed()` is not usable. + + :param int read_size: + Used as `file_like.read(read_size)`. (default: `min(16*1024, max_buffer_size)`) + + :param bool use_list: + If true, unpack msgpack array to Python list. + Otherwise, unpack to Python tuple. (default: True) + + :param bool raw: + If true, unpack msgpack raw to Python bytes (default). + Otherwise, unpack to Python str (or unicode on Python 2) by decoding + with UTF-8 encoding (recommended). + Currently, the default is true, but it will be changed to false in + near future. So you must specify it explicitly for keeping backward + compatibility. + + *encoding* option which is deprecated overrides this option. + + :param callable object_hook: + When specified, it should be callable. + Unpacker calls it with a dict argument after unpacking msgpack map. + (See also simplejson) + + :param callable object_pairs_hook: + When specified, it should be callable. + Unpacker calls it with a list of key-value pairs after unpacking msgpack map. + (See also simplejson) + + :param str encoding: + Encoding used for decoding msgpack raw. + If it is None (default), msgpack raw is deserialized to Python bytes. + + :param str unicode_errors: + (deprecated) Used for decoding msgpack raw with *encoding*. + (default: `'strict'`) + + :param int max_buffer_size: + Limits size of data waiting unpacked. 0 means system's INT_MAX (default). + Raises `BufferFull` exception when it is insufficient. + You should set this parameter when unpacking data from untrusted source. + + :param int max_str_len: + Limits max length of str. (default: 2**31-1) + + :param int max_bin_len: + Limits max length of bin. (default: 2**31-1) + + :param int max_array_len: + Limits max length of array. (default: 2**31-1) + + :param int max_map_len: + Limits max length of map. (default: 2**31-1) + + + example of streaming deserialize from file-like object:: + + unpacker = Unpacker(file_like, raw=False) + for o in unpacker: + process(o) + + example of streaming deserialize from socket:: + + unpacker = Unpacker(raw=False) + while True: + buf = sock.recv(1024**2) + if not buf: + break + unpacker.feed(buf) + for o in unpacker: + process(o) + """ + + def __init__(self, file_like=None, read_size=0, use_list=True, raw=True, + object_hook=None, object_pairs_hook=None, list_hook=None, + encoding=None, unicode_errors=None, max_buffer_size=0, + ext_hook=ExtType, + max_str_len=2147483647, # 2**32-1 + max_bin_len=2147483647, + max_array_len=2147483647, + max_map_len=2147483647, + max_ext_len=2147483647): + + if encoding is not None: + warnings.warn( + "encoding is deprecated, Use raw=False instead.", + PendingDeprecationWarning) + + if unicode_errors is None: + unicode_errors = 'strict' + + if file_like is None: + self._feeding = True + else: + if not callable(file_like.read): + raise TypeError("`file_like.read` must be callable") + self.file_like = file_like + self._feeding = False + + #: array of bytes fed. + self._buffer = bytearray() + # Some very old pythons don't support `struct.unpack_from()` with a + # `bytearray`. So we wrap it in a `buffer()` there. + if sys.version_info < (2, 7, 6): + self._buffer_view = buffer(self._buffer) + else: + self._buffer_view = self._buffer + #: Which position we currently reads + self._buff_i = 0 + + # When Unpacker is used as an iterable, between the calls to next(), + # the buffer is not "consumed" completely, for efficiency sake. + # Instead, it is done sloppily. To make sure we raise BufferFull at + # the correct moments, we have to keep track of how sloppy we were. + # Furthermore, when the buffer is incomplete (that is: in the case + # we raise an OutOfData) we need to rollback the buffer to the correct + # state, which _buf_checkpoint records. + self._buf_checkpoint = 0 + + self._max_buffer_size = max_buffer_size or 2**31-1 + if read_size > self._max_buffer_size: + raise ValueError("read_size must be smaller than max_buffer_size") + self._read_size = read_size or min(self._max_buffer_size, 16*1024) + self._raw = bool(raw) + self._encoding = encoding + self._unicode_errors = unicode_errors + self._use_list = use_list + self._list_hook = list_hook + self._object_hook = object_hook + self._object_pairs_hook = object_pairs_hook + self._ext_hook = ext_hook + self._max_str_len = max_str_len + self._max_bin_len = max_bin_len + self._max_array_len = max_array_len + self._max_map_len = max_map_len + self._max_ext_len = max_ext_len + self._stream_offset = 0 + + if list_hook is not None and not callable(list_hook): + raise TypeError('`list_hook` is not callable') + if object_hook is not None and not callable(object_hook): + raise TypeError('`object_hook` is not callable') + if object_pairs_hook is not None and not callable(object_pairs_hook): + raise TypeError('`object_pairs_hook` is not callable') + if object_hook is not None and object_pairs_hook is not None: + raise TypeError("object_pairs_hook and object_hook are mutually " + "exclusive") + if not callable(ext_hook): + raise TypeError("`ext_hook` is not callable") + + def feed(self, next_bytes): + assert self._feeding + view = _get_data_from_buffer(next_bytes) + if (len(self._buffer) - self._buff_i + len(view) > self._max_buffer_size): + raise BufferFull + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[:self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + self._buffer += view + + def _consume(self): + """ Gets rid of the used parts of the buffer. """ + self._stream_offset += self._buff_i - self._buf_checkpoint + self._buf_checkpoint = self._buff_i + + def _got_extradata(self): + return self._buff_i < len(self._buffer) + + def _get_extradata(self): + return self._buffer[self._buff_i:] + + def read_bytes(self, n): + return self._read(n) + + def _read(self, n): + # (int) -> bytearray + self._reserve(n) + i = self._buff_i + self._buff_i = i+n + return self._buffer[i:i+n] + + def _reserve(self, n): + remain_bytes = len(self._buffer) - self._buff_i - n + + # Fast path: buffer has n bytes already + if remain_bytes >= 0: + return + + if self._feeding: + self._buff_i = self._buf_checkpoint + raise OutOfData + + # Strip buffer before checkpoint before reading file. + if self._buf_checkpoint > 0: + del self._buffer[:self._buf_checkpoint] + self._buff_i -= self._buf_checkpoint + self._buf_checkpoint = 0 + + # Read from file + remain_bytes = -remain_bytes + while remain_bytes > 0: + to_read_bytes = max(self._read_size, remain_bytes) + read_data = self.file_like.read(to_read_bytes) + if not read_data: + break + assert isinstance(read_data, bytes) + self._buffer += read_data + remain_bytes -= len(read_data) + + if len(self._buffer) < n + self._buff_i: + self._buff_i = 0 # rollback + raise OutOfData + + def _read_header(self, execute=EX_CONSTRUCT): + typ = TYPE_IMMEDIATE + n = 0 + obj = None + self._reserve(1) + b = self._buffer[self._buff_i] + self._buff_i += 1 + if b & 0b10000000 == 0: + obj = b + elif b & 0b11100000 == 0b11100000: + obj = -1 - (b ^ 0xff) + elif b & 0b11100000 == 0b10100000: + n = b & 0b00011111 + typ = TYPE_RAW + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b & 0b11110000 == 0b10010000: + n = b & 0b00001111 + typ = TYPE_ARRAY + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b & 0b11110000 == 0b10000000: + n = b & 0b00001111 + typ = TYPE_MAP + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + elif b == 0xc0: + obj = None + elif b == 0xc2: + obj = False + elif b == 0xc3: + obj = True + elif b == 0xc4: + typ = TYPE_BIN + self._reserve(1) + n = self._buffer[self._buff_i] + self._buff_i += 1 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc5: + typ = TYPE_BIN + self._reserve(2) + n = struct.unpack_from(">H", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc6: + typ = TYPE_BIN + self._reserve(4) + n = struct.unpack_from(">I", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + if n > self._max_bin_len: + raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len)) + obj = self._read(n) + elif b == 0xc7: # ext 8 + typ = TYPE_EXT + self._reserve(2) + L, n = struct.unpack_from('Bb', self._buffer_view, self._buff_i) + self._buff_i += 2 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xc8: # ext 16 + typ = TYPE_EXT + self._reserve(3) + L, n = struct.unpack_from('>Hb', self._buffer_view, self._buff_i) + self._buff_i += 3 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xc9: # ext 32 + typ = TYPE_EXT + self._reserve(5) + L, n = struct.unpack_from('>Ib', self._buffer_view, self._buff_i) + self._buff_i += 5 + if L > self._max_ext_len: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len)) + obj = self._read(L) + elif b == 0xca: + self._reserve(4) + obj = struct.unpack_from(">f", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xcb: + self._reserve(8) + obj = struct.unpack_from(">d", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xcc: + self._reserve(1) + obj = self._buffer[self._buff_i] + self._buff_i += 1 + elif b == 0xcd: + self._reserve(2) + obj = struct.unpack_from(">H", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + elif b == 0xce: + self._reserve(4) + obj = struct.unpack_from(">I", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xcf: + self._reserve(8) + obj = struct.unpack_from(">Q", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xd0: + self._reserve(1) + obj = struct.unpack_from("b", self._buffer_view, self._buff_i)[0] + self._buff_i += 1 + elif b == 0xd1: + self._reserve(2) + obj = struct.unpack_from(">h", self._buffer_view, self._buff_i)[0] + self._buff_i += 2 + elif b == 0xd2: + self._reserve(4) + obj = struct.unpack_from(">i", self._buffer_view, self._buff_i)[0] + self._buff_i += 4 + elif b == 0xd3: + self._reserve(8) + obj = struct.unpack_from(">q", self._buffer_view, self._buff_i)[0] + self._buff_i += 8 + elif b == 0xd4: # fixext 1 + typ = TYPE_EXT + if self._max_ext_len < 1: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (1, self._max_ext_len)) + self._reserve(2) + n, obj = struct.unpack_from("b1s", self._buffer_view, self._buff_i) + self._buff_i += 2 + elif b == 0xd5: # fixext 2 + typ = TYPE_EXT + if self._max_ext_len < 2: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (2, self._max_ext_len)) + self._reserve(3) + n, obj = struct.unpack_from("b2s", self._buffer_view, self._buff_i) + self._buff_i += 3 + elif b == 0xd6: # fixext 4 + typ = TYPE_EXT + if self._max_ext_len < 4: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (4, self._max_ext_len)) + self._reserve(5) + n, obj = struct.unpack_from("b4s", self._buffer_view, self._buff_i) + self._buff_i += 5 + elif b == 0xd7: # fixext 8 + typ = TYPE_EXT + if self._max_ext_len < 8: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (8, self._max_ext_len)) + self._reserve(9) + n, obj = struct.unpack_from("b8s", self._buffer_view, self._buff_i) + self._buff_i += 9 + elif b == 0xd8: # fixext 16 + typ = TYPE_EXT + if self._max_ext_len < 16: + raise UnpackValueError("%s exceeds max_ext_len(%s)" % (16, self._max_ext_len)) + self._reserve(17) + n, obj = struct.unpack_from("b16s", self._buffer_view, self._buff_i) + self._buff_i += 17 + elif b == 0xd9: + typ = TYPE_RAW + self._reserve(1) + n = self._buffer[self._buff_i] + self._buff_i += 1 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xda: + typ = TYPE_RAW + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xdb: + typ = TYPE_RAW + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_str_len: + raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len) + obj = self._read(n) + elif b == 0xdc: + typ = TYPE_ARRAY + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b == 0xdd: + typ = TYPE_ARRAY + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_array_len: + raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len) + elif b == 0xde: + self._reserve(2) + n, = struct.unpack_from(">H", self._buffer_view, self._buff_i) + self._buff_i += 2 + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + typ = TYPE_MAP + elif b == 0xdf: + self._reserve(4) + n, = struct.unpack_from(">I", self._buffer_view, self._buff_i) + self._buff_i += 4 + if n > self._max_map_len: + raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len) + typ = TYPE_MAP + else: + raise UnpackValueError("Unknown header: 0x%x" % b) + return typ, n, obj + + def _unpack(self, execute=EX_CONSTRUCT): + typ, n, obj = self._read_header(execute) + + if execute == EX_READ_ARRAY_HEADER: + if typ != TYPE_ARRAY: + raise UnpackValueError("Expected array") + return n + if execute == EX_READ_MAP_HEADER: + if typ != TYPE_MAP: + raise UnpackValueError("Expected map") + return n + # TODO should we eliminate the recursion? + if typ == TYPE_ARRAY: + if execute == EX_SKIP: + for i in xrange(n): + # TODO check whether we need to call `list_hook` + self._unpack(EX_SKIP) + return + ret = newlist_hint(n) + for i in xrange(n): + ret.append(self._unpack(EX_CONSTRUCT)) + if self._list_hook is not None: + ret = self._list_hook(ret) + # TODO is the interaction between `list_hook` and `use_list` ok? + return ret if self._use_list else tuple(ret) + if typ == TYPE_MAP: + if execute == EX_SKIP: + for i in xrange(n): + # TODO check whether we need to call hooks + self._unpack(EX_SKIP) + self._unpack(EX_SKIP) + return + if self._object_pairs_hook is not None: + ret = self._object_pairs_hook( + (self._unpack(EX_CONSTRUCT), + self._unpack(EX_CONSTRUCT)) + for _ in xrange(n)) + else: + ret = {} + for _ in xrange(n): + key = self._unpack(EX_CONSTRUCT) + ret[key] = self._unpack(EX_CONSTRUCT) + if self._object_hook is not None: + ret = self._object_hook(ret) + return ret + if execute == EX_SKIP: + return + if typ == TYPE_RAW: + if self._encoding is not None: + obj = obj.decode(self._encoding, self._unicode_errors) + elif self._raw: + obj = bytes(obj) + else: + obj = obj.decode('utf_8') + return obj + if typ == TYPE_EXT: + return self._ext_hook(n, bytes(obj)) + if typ == TYPE_BIN: + return bytes(obj) + assert typ == TYPE_IMMEDIATE + return obj + + def __iter__(self): + return self + + def __next__(self): + try: + ret = self._unpack(EX_CONSTRUCT) + self._consume() + return ret + except OutOfData: + self._consume() + raise StopIteration + + next = __next__ + + def skip(self, write_bytes=None): + self._unpack(EX_SKIP) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + + def unpack(self, write_bytes=None): + ret = self._unpack(EX_CONSTRUCT) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def read_array_header(self, write_bytes=None): + ret = self._unpack(EX_READ_ARRAY_HEADER) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def read_map_header(self, write_bytes=None): + ret = self._unpack(EX_READ_MAP_HEADER) + if write_bytes is not None: + warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning) + write_bytes(self._buffer[self._buf_checkpoint:self._buff_i]) + self._consume() + return ret + + def tell(self): + return self._stream_offset + + +class Packer(object): + """ + MessagePack Packer + + usage: + + packer = Packer() + astream.write(packer.pack(a)) + astream.write(packer.pack(b)) + + Packer's constructor has some keyword arguments: + + :param callable default: + Convert user type to builtin type that Packer supports. + See also simplejson's document. + + :param bool use_single_float: + Use single precision float type for float. (default: False) + + :param bool autoreset: + Reset buffer after each pack and return its content as `bytes`. (default: True). + If set this to false, use `bytes()` to get content and `.reset()` to clear buffer. + + :param bool use_bin_type: + Use bin type introduced in msgpack spec 2.0 for bytes. + It also enables str8 type for unicode. + + :param bool strict_types: + If set to true, types will be checked to be exact. Derived classes + from serializeable types will not be serialized and will be + treated as unsupported type and forwarded to default. + Additionally tuples will not be serialized as lists. + This is useful when trying to implement accurate serialization + for python types. + + :param str encoding: + (deprecated) Convert unicode to bytes with this encoding. (default: 'utf-8') + + :param str unicode_errors: + Error handler for encoding unicode. (default: 'strict') + """ + def __init__(self, default=None, encoding=None, unicode_errors=None, + use_single_float=False, autoreset=True, use_bin_type=False, + strict_types=False): + if encoding is None: + encoding = 'utf_8' + else: + warnings.warn( + "encoding is deprecated, Use raw=False instead.", + PendingDeprecationWarning) + + if unicode_errors is None: + unicode_errors = 'strict' + + self._strict_types = strict_types + self._use_float = use_single_float + self._autoreset = autoreset + self._use_bin_type = use_bin_type + self._encoding = encoding + self._unicode_errors = unicode_errors + self._buffer = StringIO() + if default is not None: + if not callable(default): + raise TypeError("default must be callable") + self._default = default + + def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, + check=isinstance, check_type_strict=_check_type_strict): + default_used = False + if self._strict_types: + check = check_type_strict + list_types = list + else: + list_types = (list, tuple) + while True: + if nest_limit < 0: + raise PackValueError("recursion limit exceeded") + if obj is None: + return self._buffer.write(b"\xc0") + if check(obj, bool): + if obj: + return self._buffer.write(b"\xc3") + return self._buffer.write(b"\xc2") + if check(obj, int_types): + if 0 <= obj < 0x80: + return self._buffer.write(struct.pack("B", obj)) + if -0x20 <= obj < 0: + return self._buffer.write(struct.pack("b", obj)) + if 0x80 <= obj <= 0xff: + return self._buffer.write(struct.pack("BB", 0xcc, obj)) + if -0x80 <= obj < 0: + return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) + if 0xff < obj <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xcd, obj)) + if -0x8000 <= obj < -0x80: + return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) + if 0xffff < obj <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xce, obj)) + if -0x80000000 <= obj < -0x8000: + return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) + if 0xffffffff < obj <= 0xffffffffffffffff: + return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) + if -0x8000000000000000 <= obj < -0x80000000: + return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = True + continue + raise PackOverflowError("Integer value out of range") + if check(obj, (bytes, bytearray)): + n = len(obj) + if n >= 2**32: + raise PackValueError("%s is too large" % type(obj).__name__) + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, Unicode): + if self._encoding is None: + raise TypeError( + "Can't encode unicode string: " + "no encoding is specified") + obj = obj.encode(self._encoding, self._unicode_errors) + n = len(obj) + if n >= 2**32: + raise PackValueError("String is too large") + self._pack_raw_header(n) + return self._buffer.write(obj) + if check(obj, memoryview): + n = len(obj) * obj.itemsize + if n >= 2**32: + raise PackValueError("Memoryview is too large") + self._pack_bin_header(n) + return self._buffer.write(obj) + if check(obj, float): + if self._use_float: + return self._buffer.write(struct.pack(">Bf", 0xca, obj)) + return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) + if check(obj, ExtType): + code = obj.code + data = obj.data + assert isinstance(code, int) + assert isinstance(data, bytes) + L = len(data) + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(struct.pack(">BB", 0xc7, L)) + elif L <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xc8, L)) + else: + self._buffer.write(struct.pack(">BI", 0xc9, L)) + self._buffer.write(struct.pack("b", code)) + self._buffer.write(data) + return + if check(obj, list_types): + n = len(obj) + self._pack_array_header(n) + for i in xrange(n): + self._pack(obj[i], nest_limit - 1) + return + if check(obj, dict): + return self._pack_map_pairs(len(obj), dict_iteritems(obj), + nest_limit - 1) + if not default_used and self._default is not None: + obj = self._default(obj) + default_used = 1 + continue + raise TypeError("Cannot serialize %r" % (obj, )) + + def pack(self, obj): + try: + self._pack(obj) + except: + self._buffer = StringIO() # force reset + raise + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_map_pairs(self, pairs): + self._pack_map_pairs(len(pairs), pairs) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_array_header(self, n): + if n >= 2**32: + raise PackValueError + self._pack_array_header(n) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_map_header(self, n): + if n >= 2**32: + raise PackValueError + self._pack_map_header(n) + ret = self._buffer.getvalue() + if self._autoreset: + self._buffer = StringIO() + elif USING_STRINGBUILDER: + self._buffer = StringIO(ret) + return ret + + def pack_ext_type(self, typecode, data): + if not isinstance(typecode, int): + raise TypeError("typecode must have int type.") + if not 0 <= typecode <= 127: + raise ValueError("typecode should be 0-127") + if not isinstance(data, bytes): + raise TypeError("data must have bytes type") + L = len(data) + if L > 0xffffffff: + raise PackValueError("Too large data") + if L == 1: + self._buffer.write(b'\xd4') + elif L == 2: + self._buffer.write(b'\xd5') + elif L == 4: + self._buffer.write(b'\xd6') + elif L == 8: + self._buffer.write(b'\xd7') + elif L == 16: + self._buffer.write(b'\xd8') + elif L <= 0xff: + self._buffer.write(b'\xc7' + struct.pack('B', L)) + elif L <= 0xffff: + self._buffer.write(b'\xc8' + struct.pack('>H', L)) + else: + self._buffer.write(b'\xc9' + struct.pack('>I', L)) + self._buffer.write(struct.pack('B', typecode)) + self._buffer.write(data) + + def _pack_array_header(self, n): + if n <= 0x0f: + return self._buffer.write(struct.pack('B', 0x90 + n)) + if n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xdc, n)) + if n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xdd, n)) + raise PackValueError("Array is too large") + + def _pack_map_header(self, n): + if n <= 0x0f: + return self._buffer.write(struct.pack('B', 0x80 + n)) + if n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xde, n)) + if n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xdf, n)) + raise PackValueError("Dict is too large") + + def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT): + self._pack_map_header(n) + for (k, v) in pairs: + self._pack(k, nest_limit - 1) + self._pack(v, nest_limit - 1) + + def _pack_raw_header(self, n): + if n <= 0x1f: + self._buffer.write(struct.pack('B', 0xa0 + n)) + elif self._use_bin_type and n <= 0xff: + self._buffer.write(struct.pack('>BB', 0xd9, n)) + elif n <= 0xffff: + self._buffer.write(struct.pack(">BH", 0xda, n)) + elif n <= 0xffffffff: + self._buffer.write(struct.pack(">BI", 0xdb, n)) + else: + raise PackValueError('Raw is too large') + + def _pack_bin_header(self, n): + if not self._use_bin_type: + return self._pack_raw_header(n) + elif n <= 0xff: + return self._buffer.write(struct.pack('>BB', 0xc4, n)) + elif n <= 0xffff: + return self._buffer.write(struct.pack(">BH", 0xc5, n)) + elif n <= 0xffffffff: + return self._buffer.write(struct.pack(">BI", 0xc6, n)) + else: + raise PackValueError('Bin is too large') + + def bytes(self): + return self._buffer.getvalue() + + def reset(self): + self._buffer = StringIO() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py new file mode 100755 index 0000000..bb79fb7 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__about__.py @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "17.1" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2014-2016 %s" % __author__ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py new file mode 100755 index 0000000..e520d35 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/__init__.py @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py new file mode 100755 index 0000000..6daa860 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_compat.py @@ -0,0 +1,30 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import sys + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = str, +else: + string_types = basestring, + + +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(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py new file mode 100755 index 0000000..3f0c27f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/_structures.py @@ -0,0 +1,70 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + + +class Infinity(object): + + def __repr__(self): + return "Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return False + + def __le__(self, other): + return False + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return True + + def __ge__(self, other): + return True + + def __neg__(self): + return NegativeInfinity + + +Infinity = Infinity() + + +class NegativeInfinity(object): + + def __repr__(self): + return "-Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return True + + def __le__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return False + + def __ge__(self, other): + return False + + def __neg__(self): + return Infinity + + +NegativeInfinity = NegativeInfinity() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py new file mode 100755 index 0000000..b4dc0b9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/markers.py @@ -0,0 +1,301 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import operator +import os +import platform +import sys + +from pip._vendor.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from pip._vendor.pyparsing import ZeroOrMore, Group, Forward, QuotedString +from pip._vendor.pyparsing import Literal as L # noqa + +from ._compat import string_types +from .specifiers import Specifier, InvalidSpecifier + + +__all__ = [ + "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName", + "Marker", "default_environment", +] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Node(object): + + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + def __repr__(self): + return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) + + def serialize(self): + raise NotImplementedError + + +class Variable(Node): + + def serialize(self): + return str(self) + + +class Value(Node): + + def serialize(self): + return '"{0}"'.format(self) + + +class Op(Node): + + def serialize(self): + return str(self) + + +VARIABLE = ( + L("implementation_version") | + L("platform_python_implementation") | + L("implementation_name") | + L("python_full_version") | + L("platform_release") | + L("platform_version") | + L("platform_machine") | + L("platform_system") | + L("python_version") | + L("sys_platform") | + L("os_name") | + L("os.name") | # PEP-345 + L("sys.platform") | # PEP-345 + L("platform.version") | # PEP-345 + L("platform.machine") | # PEP-345 + L("platform.python_implementation") | # PEP-345 + L("python_implementation") | # undocumented setuptools legacy + L("extra") +) +ALIASES = { + 'os.name': 'os_name', + 'sys.platform': 'sys_platform', + 'platform.version': 'platform_version', + 'platform.machine': 'platform_machine', + 'platform.python_implementation': 'platform_python_implementation', + 'python_implementation': 'platform_python_implementation' +} +VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) + +VERSION_CMP = ( + L("===") | + L("==") | + L(">=") | + L("<=") | + L("!=") | + L("~=") | + L(">") | + L("<") +) + +MARKER_OP = VERSION_CMP | L("not in") | L("in") +MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) + +MARKER_VALUE = QuotedString("'") | QuotedString('"') +MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) + +BOOLOP = L("and") | L("or") + +MARKER_VAR = VARIABLE | MARKER_VALUE + +MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) +MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) + +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() + +MARKER_EXPR = Forward() +MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) +MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) + +MARKER = stringStart + MARKER_EXPR + stringEnd + + +def _coerce_parse_result(results): + if isinstance(results, ParseResults): + return [_coerce_parse_result(i) for i in results] + else: + return results + + +def _format_marker(marker, first=True): + assert isinstance(marker, (list, tuple, string_types)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if (isinstance(marker, list) and len(marker) == 1 and + isinstance(marker[0], (list, tuple))): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs, op, rhs): + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs) + + oper = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison( + "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) + ) + + return oper(lhs, rhs) + + +_undefined = object() + + +def _get_env(environment, name): + value = environment.get(name, _undefined) + + if value is _undefined: + raise UndefinedEnvironmentName( + "{0!r} does not exist in evaluation environment.".format(name) + ) + + return value + + +def _evaluate_markers(markers, environment): + groups = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, string_types)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + lhs_value = _get_env(environment, lhs.value) + rhs_value = rhs.value + else: + lhs_value = lhs.value + rhs_value = _get_env(environment, rhs.value) + + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info): + version = '{0.major}.{0.minor}.{0.micro}'.format(info) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + +def default_environment(): + if hasattr(sys, 'implementation'): + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + iver = '0' + implementation_name = '' + + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": platform.python_version()[:3], + "sys_platform": sys.platform, + } + + +class Marker(object): + + def __init__(self, marker): + try: + self._markers = _coerce_parse_result(MARKER.parseString(marker)) + except ParseException as e: + err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( + marker, marker[e.loc:e.loc + 8]) + raise InvalidMarker(err_str) + + def __str__(self): + return _format_marker(self._markers) + + def __repr__(self): + return "<Marker({0!r})>".format(str(self)) + + def evaluate(self, environment=None): + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = default_environment() + if environment is not None: + current_environment.update(environment) + + return _evaluate_markers(self._markers, current_environment) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py new file mode 100755 index 0000000..98bc507 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/requirements.py @@ -0,0 +1,130 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import string +import re + +from pip._vendor.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from pip._vendor.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from pip._vendor.pyparsing import Literal as L # noqa +from pip._vendor.six.moves.urllib import parse as urlparse + +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r'[^ ]+')("url") +URL = (AT + URI) + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY +VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), + joinString=",", adjacent=False)("_raw_spec") +_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) +_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '') + +VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") +VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start:t._original_end]) +) +MARKER_SEPARATOR = SEMICOLON +MARKER = MARKER_SEPARATOR + MARKER_EXPR + +VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = \ + NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd +# pyparsing isn't thread safe during initialization, so we do it eagerly, see +# issue #104 +REQUIREMENT.parseString("x[]") + + +class Requirement(object): + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException as e: + raise InvalidRequirement( + "Invalid requirement, parse error at \"{0!r}\"".format( + requirement_string[e.loc:e.loc + 8])) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc): + raise InvalidRequirement("Invalid URL given") + self.url = req.url + else: + self.url = None + self.extras = set(req.extras.asList() if req.extras else []) + self.specifier = SpecifierSet(req.specifier) + self.marker = req.marker if req.marker else None + + def __str__(self): + parts = [self.name] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + return "<Requirement({0!r})>".format(str(self)) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py new file mode 100755 index 0000000..7d2fe4c --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/specifiers.py @@ -0,0 +1,774 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from .version import Version, LegacyVersion, parse + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): + + @abc.abstractmethod + def __str__(self): + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} + + def __init__(self, spec="", prereleases=None): + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format( + self.__class__.__name__, + str(self), + pre, + ) + + def __str__(self): + return "{0}{1}".format(*self._spec) + + def __hash__(self): + return hash(self._spec) + + def __eq__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec == other._spec + + def __ne__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + return getattr(self, "_compare_{0}".format(self._operators[op])) + + def _coerce_version(self, version): + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + return self._spec[0] + + @property + def version(self): + return self._spec[1] + + @property + def prereleases(self): + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + return self._get_operator(self.operator)(item, self.version) + + def filter(self, iterable, prereleases=None): + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if (parsed_version.is_prerelease and not + (prereleases or self.prereleases)): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P<operator>(==|!=|<=|>=|<|>)) + \s* + (?P<version> + [^,;\s)]* # Since this is a "legacy" specifier, and the version + # string can be just about anything, we match everything + # except for whitespace, a semi-colon for marker support, + # a closing paren since versions can be enclosed in + # them, and a comma since it's a version separator. + ) + """ + ) + + _regex = re.compile( + r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + return prospective > self._coerce_version(spec) + + +def _require_version_compare(fn): + @functools.wraps(fn) + def wrapped(self, prospective, spec): + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P<operator>(~=|==|!=|<=|>=|<|>|===)) + (?P<version> + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?<!==|!=|~=) # We have special cases for these + # operators so we want to make sure they + # don't match here. + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + ) + """ + ) + + _regex = re.compile( + r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "~=": "compatible", + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") and not + x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return (self._get_operator(">=")(prospective, spec) and + self._get_operator("==")(prospective, prefix)) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + prospective = Version(prospective.public) + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + prospective = prospective[:len(spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + spec, prospective = _pad_version(spec, prospective) + else: + # Convert our spec string into a Version + spec = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec.local: + prospective = Version(prospective.public) + + return prospective == spec + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + return prospective <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is techincally greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + result = [] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]):]) + right_split.append(right[len(right_split[0]):]) + + # Insert our padding + left_split.insert( + 1, + ["0"] * max(0, len(right_split[0]) - len(left_split[0])), + ) + right_split.insert( + 1, + ["0"] * max(0, len(left_split[0]) - len(right_split[0])), + ) + + return ( + list(itertools.chain(*left_split)), + list(itertools.chain(*right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + + def __init__(self, specifiers="", prereleases=None): + # Split on , to break each indidivual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<SpecifierSet({0!r}{1})>".format(str(self), pre) + + def __str__(self): + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + return hash(self._specs) + + def __and__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + return len(self._specs) + + def __iter__(self): + return iter(self._specs) + + @property + def prereleases(self): + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all( + s.contains(item, prereleases=prereleases) + for s in self._specs + ) + + def filter(self, iterable, prereleases=None): + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] + found_prereleases = [] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py new file mode 100755 index 0000000..5151f9f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/utils.py @@ -0,0 +1,63 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import re + +from .version import InvalidVersion, Version + + +_canonicalize_regex = re.compile(r"[-_.]+") + + +def canonicalize_name(name): + # This is taken from PEP 503. + return _canonicalize_regex.sub("-", name).lower() + + +def canonicalize_version(version): + """ + This is very similar to Version.__str__, but has one subtle differences + with the way it handles the release segment. + """ + + try: + version = Version(version) + except InvalidVersion: + # Legacy versions cannot be normalized + return version + + parts = [] + + # Epoch + if version.epoch != 0: + parts.append("{0}!".format(version.epoch)) + + # Release segment + # NB: This strips trailing '.0's to normalize + parts.append( + re.sub( + r'(\.0)+$', + '', + ".".join(str(x) for x in version.release) + ) + ) + + # Pre-release + if version.pre is not None: + parts.append("".join(str(x) for x in version.pre)) + + # Post-release + if version.post is not None: + parts.append(".post{0}".format(version.post)) + + # Development release + if version.dev is not None: + parts.append(".dev{0}".format(version.dev)) + + # Local version segment + if version.local is not None: + parts.append("+{0}".format(version.local)) + + return "".join(parts) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py new file mode 100755 index 0000000..a8affbd --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/packaging/version.py @@ -0,0 +1,441 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity + + +__all__ = [ + "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN" +] + + +_Version = collections.namedtuple( + "_Version", + ["epoch", "release", "dev", "pre", "post", "local"], +) + + +def parse(version): + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + + def __init__(self, version): + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + return self._version + + def __repr__(self): + return "<LegacyVersion({0})>".format(repr(str(self))) + + @property + def public(self): + return self._version + + @property + def base_version(self): + return self._version + + @property + def epoch(self): + return -1 + + @property + def release(self): + return None + + @property + def pre(self): + return None + + @property + def post(self): + return None + + @property + def dev(self): + return None + + @property + def local(self): + return None + + @property + def is_prerelease(self): + return False + + @property + def is_postrelease(self): + return False + + @property + def is_devrelease(self): + return False + + +_legacy_version_component_re = re.compile( + r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE, +) + +_legacy_version_replacement_map = { + "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@", +} + + +def _parse_version_parts(s): + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + while parts and parts[-1] == "*final-": + parts.pop() + + # remove trailing zeros from each series of numeric parts + while parts and parts[-1] == "00000000": + parts.pop() + + parts.append(part) + parts = tuple(parts) + + return epoch, parts + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P<epoch>[0-9]+)!)? # epoch + (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment + (?P<pre> # pre-release + [-_\.]? + (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) + [-_\.]? + (?P<pre_n>[0-9]+)? + )? + (?P<post> # post release + (?:-(?P<post_n1>[0-9]+)) + | + (?: + [-_\.]? + (?P<post_l>post|rev|r) + [-_\.]? + (?P<post_n2>[0-9]+)? + ) + )? + (?P<dev> # dev release + [-_\.]? + (?P<dev_l>dev) + [-_\.]? + (?P<dev_n>[0-9]+)? + )? + ) + (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version +""" + + +class Version(_BaseVersion): + + _regex = re.compile( + r"^\s*" + VERSION_PATTERN + r"\s*$", + re.VERBOSE | re.IGNORECASE, + ) + + def __init__(self, version): + # Validate the version and parse it into pieces + match = self._regex.search(version) + if not match: + raise InvalidVersion("Invalid version: '{0}'".format(version)) + + # Store the parsed out pieces of the version + self._version = _Version( + epoch=int(match.group("epoch")) if match.group("epoch") else 0, + release=tuple(int(i) for i in match.group("release").split(".")), + pre=_parse_letter_version( + match.group("pre_l"), + match.group("pre_n"), + ), + post=_parse_letter_version( + match.group("post_l"), + match.group("post_n1") or match.group("post_n2"), + ), + dev=_parse_letter_version( + match.group("dev_l"), + match.group("dev_n"), + ), + local=_parse_local_version(match.group("local")), + ) + + # Generate a key which will be used for sorting + self._key = _cmpkey( + self._version.epoch, + self._version.release, + self._version.pre, + self._version.post, + self._version.dev, + self._version.local, + ) + + def __repr__(self): + return "<Version({0})>".format(repr(str(self))) + + def __str__(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + # Pre-release + if self.pre is not None: + parts.append("".join(str(x) for x in self.pre)) + + # Post-release + if self.post is not None: + parts.append(".post{0}".format(self.post)) + + # Development release + if self.dev is not None: + parts.append(".dev{0}".format(self.dev)) + + # Local version segment + if self.local is not None: + parts.append("+{0}".format(self.local)) + + return "".join(parts) + + @property + def epoch(self): + return self._version.epoch + + @property + def release(self): + return self._version.release + + @property + def pre(self): + return self._version.pre + + @property + def post(self): + return self._version.post[1] if self._version.post else None + + @property + def dev(self): + return self._version.dev[1] if self._version.dev else None + + @property + def local(self): + if self._version.local: + return ".".join(str(x) for x in self._version.local) + else: + return None + + @property + def public(self): + return str(self).split("+", 1)[0] + + @property + def base_version(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + return "".join(parts) + + @property + def is_prerelease(self): + return self.dev is not None or self.pre is not None + + @property + def is_postrelease(self): + return self.post is not None + + @property + def is_devrelease(self): + return self.dev is not None + + +def _parse_letter_version(letter, number): + if letter: + # We consider there to be an implicit 0 in a pre-release if there is + # not a numeral associated with it. + if number is None: + number = 0 + + # We normalize any letters to their lower case form + letter = letter.lower() + + # We consider some words to be alternate spellings of other words and + # in those cases we want to normalize the spellings to our preferred + # spelling. + if letter == "alpha": + letter = "a" + elif letter == "beta": + letter = "b" + elif letter in ["c", "pre", "preview"]: + letter = "rc" + elif letter in ["rev", "r"]: + letter = "post" + + return letter, int(number) + if not letter and number: + # We assume if we are given a number, but we are not given a letter + # then this is using the implicit post release syntax (e.g. 1.0-1) + letter = "post" + + return letter, int(number) + + +_local_version_separators = re.compile(r"[\._-]") + + +def _parse_local_version(local): + """ + Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). + """ + if local is not None: + return tuple( + part.lower() if not part.isdigit() else int(part) + for part in _local_version_separators.split(local) + ) + + +def _cmpkey(epoch, release, pre, post, dev, local): + # When we compare a release version, we want to compare it with all of the + # trailing zeros removed. So we'll use a reverse the list, drop all the now + # leading zeros until we come to something non zero, then take the rest + # re-reverse it back into the correct order and make it a tuple and use + # that for our sorting key. + release = tuple( + reversed(list( + itertools.dropwhile( + lambda x: x == 0, + reversed(release), + ) + )) + ) + + # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. + # We'll do this by abusing the pre segment, but we _only_ want to do this + # if there is not a pre or a post segment. If we have one of those then + # the normal sorting rules will handle this case correctly. + if pre is None and post is None and dev is not None: + pre = -Infinity + # Versions without a pre-release (except as noted above) should sort after + # those with one. + elif pre is None: + pre = Infinity + + # Versions without a post segment should sort before those with one. + if post is None: + post = -Infinity + + # Versions without a development segment should sort after those with one. + if dev is None: + dev = Infinity + + if local is None: + # Versions without a local segment should sort before those with one. + local = -Infinity + else: + # Versions with a local segment need that segment parsed to implement + # the sorting rules in PEP440. + # - Alpha numeric segments sort before numeric segments + # - Alpha numeric segments sort lexicographically + # - Numeric segments sort numerically + # - Shorter versions sort before longer versions when the prefixes + # match exactly + local = tuple( + (i, "") if isinstance(i, int) else (-Infinity, i) + for i in local + ) + + return epoch, release, pre, post, dev, local diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py new file mode 100755 index 0000000..6e1fb52 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/__init__.py @@ -0,0 +1,3125 @@ +# coding: utf-8 +""" +Package resource API +-------------------- + +A resource is a logical file contained within a package, or a logical +subdirectory thereof. The package resource API expects resource names +to have their path parts separated with ``/``, *not* whatever the local +path separator is. Do not use os.path operations to manipulate resource +names being passed into the API. + +The package resource API is designed to work with normal filesystem packages, +.egg files, and unpacked .egg files. It can also work in a limited way with +.zip files and with custom PEP 302 loaders that support the ``get_data()`` +method. +""" + +from __future__ import absolute_import + +import sys +import os +import io +import time +import re +import types +import zipfile +import zipimport +import warnings +import stat +import functools +import pkgutil +import operator +import platform +import collections +import plistlib +import email.parser +import errno +import tempfile +import textwrap +import itertools +import inspect +from pkgutil import get_importer + +try: + import _imp +except ImportError: + # Python 3.2 compatibility + import imp as _imp + +from pip._vendor import six +from pip._vendor.six.moves import urllib, map, filter + +# capture these to bypass sandboxing +from os import utime +try: + from os import mkdir, rename, unlink + WRITE_SUPPORT = True +except ImportError: + # no write support, probably under GAE + WRITE_SUPPORT = False + +from os import open as os_open +from os.path import isdir, split + +try: + import importlib.machinery as importlib_machinery + # access attribute to force import under delayed import mechanisms. + importlib_machinery.__name__ +except ImportError: + importlib_machinery = None + +from . import py31compat +from pip._vendor import appdirs +from pip._vendor import packaging +__import__('pip._vendor.packaging.version') +__import__('pip._vendor.packaging.specifiers') +__import__('pip._vendor.packaging.requirements') +__import__('pip._vendor.packaging.markers') + + +if (3, 0) < sys.version_info < (3, 3): + raise RuntimeError("Python 3.3 or later is required") + +if six.PY2: + # Those builtin exceptions are only defined in Python 3 + PermissionError = None + NotADirectoryError = None + +# declare some globals that will be defined later to +# satisfy the linters. +require = None +working_set = None +add_activation_listener = None +resources_stream = None +cleanup_resources = None +resource_dir = None +resource_stream = None +set_extraction_path = None +resource_isdir = None +resource_string = None +iter_entry_points = None +resource_listdir = None +resource_filename = None +resource_exists = None +_distribution_finders = None +_namespace_handlers = None +_namespace_packages = None + + +class PEP440Warning(RuntimeWarning): + """ + Used when there is an issue with a version or specifier not complying with + PEP 440. + """ + + +def parse_version(v): + try: + return packaging.version.Version(v) + except packaging.version.InvalidVersion: + return packaging.version.LegacyVersion(v) + + +_state_vars = {} + + +def _declare_state(vartype, **kw): + globals().update(kw) + _state_vars.update(dict.fromkeys(kw, vartype)) + + +def __getstate__(): + state = {} + g = globals() + for k, v in _state_vars.items(): + state[k] = g['_sget_' + v](g[k]) + return state + + +def __setstate__(state): + g = globals() + for k, v in state.items(): + g['_sset_' + _state_vars[k]](k, g[k], v) + return state + + +def _sget_dict(val): + return val.copy() + + +def _sset_dict(key, ob, state): + ob.clear() + ob.update(state) + + +def _sget_object(val): + return val.__getstate__() + + +def _sset_object(key, ob, state): + ob.__setstate__(state) + + +_sget_none = _sset_none = lambda *args: None + + +def get_supported_platform(): + """Return this platform's maximum compatible version. + + distutils.util.get_platform() normally reports the minimum version + of Mac OS X that would be required to *use* extensions produced by + distutils. But what we want when checking compatibility is to know the + version of Mac OS X that we are *running*. To allow usage of packages that + explicitly require a newer version of Mac OS X, we must also know the + current version of the OS. + + If this condition occurs for any other platform with a version in its + platform strings, this function should be extended accordingly. + """ + plat = get_build_platform() + m = macosVersionString.match(plat) + if m is not None and sys.platform == "darwin": + try: + plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) + except ValueError: + # not Mac OS X + pass + return plat + + +__all__ = [ + # Basic resource access and distribution/entry point discovery + 'require', 'run_script', 'get_provider', 'get_distribution', + 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'iter_entry_points', + 'resource_string', 'resource_stream', 'resource_filename', + 'resource_listdir', 'resource_exists', 'resource_isdir', + + # Environmental control + 'declare_namespace', 'working_set', 'add_activation_listener', + 'find_distributions', 'set_extraction_path', 'cleanup_resources', + 'get_default_cache', + + # Primary implementation classes + 'Environment', 'WorkingSet', 'ResourceManager', + 'Distribution', 'Requirement', 'EntryPoint', + + # Exceptions + 'ResolutionError', 'VersionConflict', 'DistributionNotFound', + 'UnknownExtra', 'ExtractionError', + + # Warnings + 'PEP440Warning', + + # Parsing functions and string utilities + 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', + 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', + + # filesystem utilities + 'ensure_directory', 'normalize_path', + + # Distribution "precedence" constants + 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', + + # "Provider" interfaces, implementations, and registration/lookup APIs + 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', + 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', + 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', + 'register_finder', 'register_namespace_handler', 'register_loader_type', + 'fixup_namespace_packages', 'get_importer', + + # Deprecated/backward compatibility only + 'run_main', 'AvailableDistributions', +] + + +class ResolutionError(Exception): + """Abstract base for dependency resolution errors""" + + def __repr__(self): + return self.__class__.__name__ + repr(self.args) + + +class VersionConflict(ResolutionError): + """ + An already-installed version conflicts with the requested version. + + Should be initialized with the installed Distribution and the requested + Requirement. + """ + + _template = "{self.dist} is installed but {self.req} is required" + + @property + def dist(self): + return self.args[0] + + @property + def req(self): + return self.args[1] + + def report(self): + return self._template.format(**locals()) + + def with_context(self, required_by): + """ + If required_by is non-empty, return a version of self that is a + ContextualVersionConflict. + """ + if not required_by: + return self + args = self.args + (required_by,) + return ContextualVersionConflict(*args) + + +class ContextualVersionConflict(VersionConflict): + """ + A VersionConflict that accepts a third parameter, the set of the + requirements that required the installed Distribution. + """ + + _template = VersionConflict._template + ' by {self.required_by}' + + @property + def required_by(self): + return self.args[2] + + +class DistributionNotFound(ResolutionError): + """A requested distribution was not found""" + + _template = ("The '{self.req}' distribution was not found " + "and is required by {self.requirers_str}") + + @property + def req(self): + return self.args[0] + + @property + def requirers(self): + return self.args[1] + + @property + def requirers_str(self): + if not self.requirers: + return 'the application' + return ', '.join(self.requirers) + + def report(self): + return self._template.format(**locals()) + + def __str__(self): + return self.report() + + +class UnknownExtra(ResolutionError): + """Distribution doesn't have an "extra feature" of the given name""" + + +_provider_factories = {} + +PY_MAJOR = sys.version[:3] +EGG_DIST = 3 +BINARY_DIST = 2 +SOURCE_DIST = 1 +CHECKOUT_DIST = 0 +DEVELOP_DIST = -1 + + +def register_loader_type(loader_type, provider_factory): + """Register `provider_factory` to make providers for `loader_type` + + `loader_type` is the type or class of a PEP 302 ``module.__loader__``, + and `provider_factory` is a function that, passed a *module* object, + returns an ``IResourceProvider`` for that module. + """ + _provider_factories[loader_type] = provider_factory + + +def get_provider(moduleOrReq): + """Return an IResourceProvider for the named module or requirement""" + if isinstance(moduleOrReq, Requirement): + return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] + try: + module = sys.modules[moduleOrReq] + except KeyError: + __import__(moduleOrReq) + module = sys.modules[moduleOrReq] + loader = getattr(module, '__loader__', None) + return _find_adapter(_provider_factories, loader)(module) + + +def _macosx_vers(_cache=[]): + if not _cache: + version = platform.mac_ver()[0] + # fallback for MacPorts + if version == '': + plist = '/System/Library/CoreServices/SystemVersion.plist' + if os.path.exists(plist): + if hasattr(plistlib, 'readPlist'): + plist_content = plistlib.readPlist(plist) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] + + _cache.append(version.split('.')) + return _cache[0] + + +def _macosx_arch(machine): + return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) + + +def get_build_platform(): + """Return this platform's string for platform-specific distributions + + XXX Currently this is the same as ``distutils.util.get_platform()``, but it + needs some hacks for Linux and Mac OS X. + """ + try: + # Python 2.7 or >=3.2 + from sysconfig import get_platform + except ImportError: + from distutils.util import get_platform + + plat = get_platform() + if sys.platform == "darwin" and not plat.startswith('macosx-'): + try: + version = _macosx_vers() + machine = os.uname()[4].replace(" ", "_") + return "macosx-%d.%d-%s" % ( + int(version[0]), int(version[1]), + _macosx_arch(machine), + ) + except ValueError: + # if someone is running a non-Mac darwin system, this will fall + # through to the default implementation + pass + return plat + + +macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") +darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") +# XXX backward compat +get_platform = get_build_platform + + +def compatible_platforms(provided, required): + """Can code for the `provided` platform run on the `required` platform? + + Returns true if either platform is ``None``, or the platforms are equal. + + XXX Needs compatibility checks for Linux and other unixy OSes. + """ + if provided is None or required is None or provided == required: + # easy case + return True + + # Mac OS X special cases + reqMac = macosVersionString.match(required) + if reqMac: + provMac = macosVersionString.match(provided) + + # is this a Mac package? + if not provMac: + # this is backwards compatibility for packages built before + # setuptools 0.6. All packages built after this point will + # use the new macosx designation. + provDarwin = darwinVersionString.match(provided) + if provDarwin: + dversion = int(provDarwin.group(1)) + macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) + if dversion == 7 and macosversion >= "10.3" or \ + dversion == 8 and macosversion >= "10.4": + return True + # egg isn't macosx or legacy darwin + return False + + # are they the same major version and machine type? + if provMac.group(1) != reqMac.group(1) or \ + provMac.group(3) != reqMac.group(3): + return False + + # is the required OS major update >= the provided one? + if int(provMac.group(2)) > int(reqMac.group(2)): + return False + + return True + + # XXX Linux and other platforms' special cases should go here + return False + + +def run_script(dist_spec, script_name): + """Locate distribution `dist_spec` and run its `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + require(dist_spec)[0].run_script(script_name, ns) + + +# backward compatibility +run_main = run_script + + +def get_distribution(dist): + """Return a current distribution object for a Requirement or string""" + if isinstance(dist, six.string_types): + dist = Requirement.parse(dist) + if isinstance(dist, Requirement): + dist = get_provider(dist) + if not isinstance(dist, Distribution): + raise TypeError("Expected string, Requirement, or Distribution", dist) + return dist + + +def load_entry_point(dist, group, name): + """Return `name` entry point of `group` for `dist` or raise ImportError""" + return get_distribution(dist).load_entry_point(group, name) + + +def get_entry_map(dist, group=None): + """Return the entry point map for `group`, or the full entry map""" + return get_distribution(dist).get_entry_map(group) + + +def get_entry_info(dist, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return get_distribution(dist).get_entry_info(group, name) + + +class IMetadataProvider: + def has_metadata(name): + """Does the package's distribution contain the named metadata?""" + + def get_metadata(name): + """The named metadata resource as a string""" + + def get_metadata_lines(name): + """Yield named metadata resource as list of non-blank non-comment lines + + Leading and trailing whitespace is stripped from each line, and lines + with ``#`` as the first non-blank character are omitted.""" + + def metadata_isdir(name): + """Is the named metadata a directory? (like ``os.path.isdir()``)""" + + def metadata_listdir(name): + """List of metadata names in the directory (like ``os.listdir()``)""" + + def run_script(script_name, namespace): + """Execute the named script in the supplied namespace dictionary""" + + +class IResourceProvider(IMetadataProvider): + """An object that provides access to package resources""" + + def get_resource_filename(manager, resource_name): + """Return a true filesystem path for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_stream(manager, resource_name): + """Return a readable file-like object for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_string(manager, resource_name): + """Return a string containing the contents of `resource_name` + + `manager` must be an ``IResourceManager``""" + + def has_resource(resource_name): + """Does the package contain the named resource?""" + + def resource_isdir(resource_name): + """Is the named resource a directory? (like ``os.path.isdir()``)""" + + def resource_listdir(resource_name): + """List of resource names in the directory (like ``os.listdir()``)""" + + +class WorkingSet(object): + """A collection of active distributions on sys.path (or a similar list)""" + + def __init__(self, entries=None): + """Create working set from list of path entries (default=sys.path)""" + self.entries = [] + self.entry_keys = {} + self.by_key = {} + self.callbacks = [] + + if entries is None: + entries = sys.path + + for entry in entries: + self.add_entry(entry) + + @classmethod + def _build_master(cls): + """ + Prepare the master working set. + """ + ws = cls() + try: + from __main__ import __requires__ + except ImportError: + # The main program does not list any requirements + return ws + + # ensure the requirements are met + try: + ws.require(__requires__) + except VersionConflict: + return cls._build_from_requirements(__requires__) + + return ws + + @classmethod + def _build_from_requirements(cls, req_spec): + """ + Build a working set from a requirement spec. Rewrites sys.path. + """ + # try it without defaults already on sys.path + # by starting with an empty path + ws = cls([]) + reqs = parse_requirements(req_spec) + dists = ws.resolve(reqs, Environment()) + for dist in dists: + ws.add(dist) + + # add any missing entries from sys.path + for entry in sys.path: + if entry not in ws.entries: + ws.add_entry(entry) + + # then copy back to sys.path + sys.path[:] = ws.entries + return ws + + def add_entry(self, entry): + """Add a path item to ``.entries``, finding any distributions on it + + ``find_distributions(entry, True)`` is used to find distributions + corresponding to the path entry, and they are added. `entry` is + always appended to ``.entries``, even if it is already present. + (This is because ``sys.path`` can contain the same value more than + once, and the ``.entries`` of the ``sys.path`` WorkingSet should always + equal ``sys.path``.) + """ + self.entry_keys.setdefault(entry, []) + self.entries.append(entry) + for dist in find_distributions(entry, True): + self.add(dist, entry, False) + + def __contains__(self, dist): + """True if `dist` is the active distribution for its project""" + return self.by_key.get(dist.key) == dist + + def find(self, req): + """Find a distribution matching requirement `req` + + If there is an active distribution for the requested project, this + returns it as long as it meets the version requirement specified by + `req`. But, if there is an active distribution for the project and it + does *not* meet the `req` requirement, ``VersionConflict`` is raised. + If there is no active distribution for the requested project, ``None`` + is returned. + """ + dist = self.by_key.get(req.key) + if dist is not None and dist not in req: + # XXX add more info + raise VersionConflict(dist, req) + return dist + + def iter_entry_points(self, group, name=None): + """Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set, otherwise only ones matching + both `group` and `name` are yielded (in distribution order). + """ + for dist in self: + entries = dist.get_entry_map(group) + if name is None: + for ep in entries.values(): + yield ep + elif name in entries: + yield entries[name] + + def run_script(self, requires, script_name): + """Locate distribution for `requires` and run `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + self.require(requires)[0].run_script(script_name, ns) + + def __iter__(self): + """Yield distributions for non-duplicate projects in the working set + + The yield order is the order in which the items' path entries were + added to the working set. + """ + seen = {} + for item in self.entries: + if item not in self.entry_keys: + # workaround a cache issue + continue + + for key in self.entry_keys[item]: + if key not in seen: + seen[key] = 1 + yield self.by_key[key] + + def add(self, dist, entry=None, insert=True, replace=False): + """Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to the ``.location`` of `dist`. + On exit from this routine, `entry` is added to the end of the working + set's ``.entries`` (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution in the set, unless `replace=True`. + If it's added, any callbacks registered with the ``subscribe()`` method + will be called. + """ + if insert: + dist.insert_on(self.entries, entry, replace=replace) + + if entry is None: + entry = dist.location + keys = self.entry_keys.setdefault(entry, []) + keys2 = self.entry_keys.setdefault(dist.location, []) + if not replace and dist.key in self.by_key: + # ignore hidden distros + return + + self.by_key[dist.key] = dist + if dist.key not in keys: + keys.append(dist.key) + if dist.key not in keys2: + keys2.append(dist.key) + self._added_new(dist) + + def resolve(self, requirements, env=None, installer=None, + replace_conflicting=False, extras=None): + """List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, it defaults to all distributions available within any + entry or distribution in the working set. `installer`, if supplied, + will be invoked with each requirement that cannot be met by an + already-installed distribution; it should return a ``Distribution`` or + ``None``. + + Unless `replace_conflicting=True`, raises a VersionConflict exception + if + any requirements are found on the path that have the correct name but + the wrong version. Otherwise, if an `installer` is supplied it will be + invoked to obtain the correct version of the requirement and activate + it. + + `extras` is a list of the extras to be used with these requirements. + This is important because extra requirements may look like `my_req; + extra = "my_extra"`, which would otherwise be interpreted as a purely + optional requirement. Instead, we want to be able to assert that these + requirements are truly required. + """ + + # set up the stack + requirements = list(requirements)[::-1] + # set of processed requirements + processed = {} + # key -> dist + best = {} + to_activate = [] + + req_extras = _ReqExtras() + + # Mapping of requirement to set of distributions that required it; + # useful for reporting info about conflicts. + required_by = collections.defaultdict(set) + + while requirements: + # process dependencies breadth-first + req = requirements.pop(0) + if req in processed: + # Ignore cyclic or redundant dependencies + continue + + if not req_extras.markers_pass(req, extras): + continue + + dist = best.get(req.key) + if dist is None: + # Find the best distribution and add it to the map + dist = self.by_key.get(req.key) + if dist is None or (dist not in req and replace_conflicting): + ws = self + if env is None: + if dist is None: + env = Environment(self.entries) + else: + # Use an empty environment and workingset to avoid + # any further conflicts with the conflicting + # distribution + env = Environment([]) + ws = WorkingSet([]) + dist = best[req.key] = env.best_match( + req, ws, installer, + replace_conflicting=replace_conflicting + ) + if dist is None: + requirers = required_by.get(req, None) + raise DistributionNotFound(req, requirers) + to_activate.append(dist) + if dist not in req: + # Oops, the "best" so far conflicts with a dependency + dependent_req = required_by[req] + raise VersionConflict(dist, req).with_context(dependent_req) + + # push the new requirements onto the stack + new_requirements = dist.requires(req.extras)[::-1] + requirements.extend(new_requirements) + + # Register the new requirements needed by req + for new_requirement in new_requirements: + required_by[new_requirement].add(req.project_name) + req_extras[new_requirement] = req.extras + + processed[req] = True + + # return list of distros to activate + return to_activate + + def find_plugins( + self, plugin_env, full_env=None, installer=None, fallback=True): + """Find all activatable distributions in `plugin_env` + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + # add plugins+libs to sys.path + map(working_set.add, distributions) + # display errors + print('Could not load', errors) + + The `plugin_env` should be an ``Environment`` instance that contains + only distributions that are in the project's "plugin directory" or + directories. The `full_env`, if supplied, should be an ``Environment`` + contains all currently-available distributions. If `full_env` is not + supplied, one is created automatically from the ``WorkingSet`` this + method is called on, which will typically mean that every directory on + ``sys.path`` will be scanned for distributions. + + `installer` is a standard installer callback as used by the + ``resolve()`` method. The `fallback` flag indicates whether we should + attempt to resolve older versions of a plugin if the newest version + cannot be resolved. + + This method returns a 2-tuple: (`distributions`, `error_info`), where + `distributions` is a list of the distributions found in `plugin_env` + that were loadable, along with any other distributions that are needed + to resolve their dependencies. `error_info` is a dictionary mapping + unloadable plugin distributions to an exception instance describing the + error that occurred. Usually this will be a ``DistributionNotFound`` or + ``VersionConflict`` instance. + """ + + plugin_projects = list(plugin_env) + # scan project names in alphabetic order + plugin_projects.sort() + + error_info = {} + distributions = {} + + if full_env is None: + env = Environment(self.entries) + env += plugin_env + else: + env = full_env + plugin_env + + shadow_set = self.__class__([]) + # put all our entries in shadow_set + list(map(shadow_set.add, self)) + + for project_name in plugin_projects: + + for dist in plugin_env[project_name]: + + req = [dist.as_requirement()] + + try: + resolvees = shadow_set.resolve(req, env, installer) + + except ResolutionError as v: + # save error info + error_info[dist] = v + if fallback: + # try the next older version of project + continue + else: + # give up on this project, keep going + break + + else: + list(map(shadow_set.add, resolvees)) + distributions.update(dict.fromkeys(resolvees)) + + # success, no need to try any more versions of this project + break + + distributions = list(distributions) + distributions.sort() + + return distributions, error_info + + def require(self, *requirements): + """Ensure that distributions matching `requirements` are activated + + `requirements` must be a string or a (possibly-nested) sequence + thereof, specifying the distributions and versions required. The + return value is a sequence of the distributions that needed to be + activated to fulfill the requirements; all relevant distributions are + included, even if they were already activated in this working set. + """ + needed = self.resolve(parse_requirements(requirements)) + + for dist in needed: + self.add(dist) + + return needed + + def subscribe(self, callback, existing=True): + """Invoke `callback` for all distributions + + If `existing=True` (default), + call on all existing ones, as well. + """ + if callback in self.callbacks: + return + self.callbacks.append(callback) + if not existing: + return + for dist in self: + callback(dist) + + def _added_new(self, dist): + for callback in self.callbacks: + callback(dist) + + def __getstate__(self): + return ( + self.entries[:], self.entry_keys.copy(), self.by_key.copy(), + self.callbacks[:] + ) + + def __setstate__(self, e_k_b_c): + entries, keys, by_key, callbacks = e_k_b_c + self.entries = entries[:] + self.entry_keys = keys.copy() + self.by_key = by_key.copy() + self.callbacks = callbacks[:] + + +class _ReqExtras(dict): + """ + Map each requirement to the extras that demanded it. + """ + + def markers_pass(self, req, extras=None): + """ + Evaluate markers for req against each extra that + demanded it. + + Return False if the req has a marker and fails + evaluation. Otherwise, return True. + """ + extra_evals = ( + req.marker.evaluate({'extra': extra}) + for extra in self.get(req, ()) + (extras or (None,)) + ) + return not req.marker or any(extra_evals) + + +class Environment(object): + """Searchable snapshot of distributions on a search path""" + + def __init__( + self, search_path=None, platform=get_supported_platform(), + python=PY_MAJOR): + """Snapshot distributions available on a search path + + Any distributions found on `search_path` are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. + + `platform` is an optional string specifying the name of the platform + that platform-specific distributions must be compatible with. If + unspecified, it defaults to the current platform. `python` is an + optional string naming the desired version of Python (e.g. ``'3.3'``); + it defaults to the current version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to map *all* distributions, not just those compatible with the + running platform or Python version. + """ + self._distmap = {} + self.platform = platform + self.python = python + self.scan(search_path) + + def can_add(self, dist): + """Is distribution `dist` acceptable for this environment? + + The distribution must match the platform and python version + requirements specified when this environment was created, or False + is returned. + """ + py_compat = ( + self.python is None + or dist.py_version is None + or dist.py_version == self.python + ) + return py_compat and compatible_platforms(dist.platform, self.platform) + + def remove(self, dist): + """Remove `dist` from the environment""" + self._distmap[dist.key].remove(dist) + + def scan(self, search_path=None): + """Scan `search_path` for distributions usable in this environment + + Any distributions found are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. + """ + if search_path is None: + search_path = sys.path + + for item in search_path: + for dist in find_distributions(item): + self.add(dist) + + def __getitem__(self, project_name): + """Return a newest-to-oldest list of distributions for `project_name` + + Uses case-insensitive `project_name` comparison, assuming all the + project's distributions use their project's name converted to all + lowercase as their key. + + """ + distribution_key = project_name.lower() + return self._distmap.get(distribution_key, []) + + def add(self, dist): + """Add `dist` if we ``can_add()`` it and it has not already been added + """ + if self.can_add(dist) and dist.has_version(): + dists = self._distmap.setdefault(dist.key, []) + if dist not in dists: + dists.append(dist) + dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) + + def best_match( + self, req, working_set, installer=None, replace_conflicting=False): + """Find distribution best matching `req` and usable on `working_set` + + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution + isn't active, this method returns the newest distribution in the + environment that meets the ``Requirement`` in `req`. If no suitable + distribution is found, and `installer` is supplied, then the result of + calling the environment's ``obtain(req, installer)`` method will be + returned. + """ + try: + dist = working_set.find(req) + except VersionConflict: + if not replace_conflicting: + raise + dist = None + if dist is not None: + return dist + for dist in self[req.key]: + if dist in req: + return dist + # try to download/install + return self.obtain(req, installer) + + def obtain(self, requirement, installer=None): + """Obtain a distribution matching `requirement` (e.g. via download) + + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument.""" + if installer is not None: + return installer(requirement) + + def __iter__(self): + """Yield the unique project names of the available distributions""" + for key in self._distmap.keys(): + if self[key]: + yield key + + def __iadd__(self, other): + """In-place addition of a distribution or environment""" + if isinstance(other, Distribution): + self.add(other) + elif isinstance(other, Environment): + for project in other: + for dist in other[project]: + self.add(dist) + else: + raise TypeError("Can't add %r to environment" % (other,)) + return self + + def __add__(self, other): + """Add an environment or distribution to an environment""" + new = self.__class__([], platform=None, python=None) + for env in self, other: + new += env + return new + + +# XXX backward compatibility +AvailableDistributions = Environment + + +class ExtractionError(RuntimeError): + """An error occurred extracting a resource + + The following attributes are available from instances of this exception: + + manager + The resource manager that raised this exception + + cache_path + The base directory for resource extraction + + original_error + The exception instance that caused extraction to fail + """ + + +class ResourceManager: + """Manage resource extraction and packages""" + extraction_path = None + + def __init__(self): + self.cached_files = {} + + def resource_exists(self, package_or_requirement, resource_name): + """Does the named resource exist?""" + return get_provider(package_or_requirement).has_resource(resource_name) + + def resource_isdir(self, package_or_requirement, resource_name): + """Is the named resource an existing directory?""" + return get_provider(package_or_requirement).resource_isdir( + resource_name + ) + + def resource_filename(self, package_or_requirement, resource_name): + """Return a true filesystem path for specified resource""" + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name + ) + + def resource_stream(self, package_or_requirement, resource_name): + """Return a readable file-like object for specified resource""" + return get_provider(package_or_requirement).get_resource_stream( + self, resource_name + ) + + def resource_string(self, package_or_requirement, resource_name): + """Return specified resource as a string""" + return get_provider(package_or_requirement).get_resource_string( + self, resource_name + ) + + def resource_listdir(self, package_or_requirement, resource_name): + """List the contents of the named resource directory""" + return get_provider(package_or_requirement).resource_listdir( + resource_name + ) + + def extraction_error(self): + """Give an error message for problems extracting file(s)""" + + old_exc = sys.exc_info()[1] + cache_path = self.extraction_path or get_default_cache() + + tmpl = textwrap.dedent(""" + Can't extract file(s) to egg cache + + The following error occurred while trying to extract file(s) + to the Python egg cache: + + {old_exc} + + The Python egg cache directory is currently set to: + + {cache_path} + + Perhaps your account does not have write access to this directory? + You can change the cache directory by setting the PYTHON_EGG_CACHE + environment variable to point to an accessible directory. + """).lstrip() + err = ExtractionError(tmpl.format(**locals())) + err.manager = self + err.cache_path = cache_path + err.original_error = old_exc + raise err + + def get_cache_path(self, archive_name, names=()): + """Return absolute location in cache for `archive_name` and `names` + + The parent directory of the resulting path will be created if it does + not already exist. `archive_name` should be the base filename of the + enclosing egg (which may not be the name of the enclosing zipfile!), + including its ".egg" extension. `names`, if provided, should be a + sequence of path name parts "under" the egg's extraction location. + + This method should only be called by resource providers that need to + obtain an extraction location, and only for names they intend to + extract, as it tracks the generated names for possible cleanup later. + """ + extract_path = self.extraction_path or get_default_cache() + target_path = os.path.join(extract_path, archive_name + '-tmp', *names) + try: + _bypass_ensure_directory(target_path) + except Exception: + self.extraction_error() + + self._warn_unsafe_extraction_path(extract_path) + + self.cached_files[target_path] = 1 + return target_path + + @staticmethod + def _warn_unsafe_extraction_path(path): + """ + If the default extraction path is overridden and set to an insecure + location, such as /tmp, it opens up an opportunity for an attacker to + replace an extracted file with an unauthorized payload. Warn the user + if a known insecure location is used. + + See Distribute #375 for more details. + """ + if os.name == 'nt' and not path.startswith(os.environ['windir']): + # On Windows, permissions are generally restrictive by default + # and temp directories are not writable by other users, so + # bypass the warning. + return + mode = os.stat(path).st_mode + if mode & stat.S_IWOTH or mode & stat.S_IWGRP: + msg = ( + "%s is writable by group/others and vulnerable to attack " + "when " + "used with get_resource_filename. Consider a more secure " + "location (set with .set_extraction_path or the " + "PYTHON_EGG_CACHE environment variable)." % path + ) + warnings.warn(msg, UserWarning) + + def postprocess(self, tempname, filename): + """Perform any platform-specific postprocessing of `tempname` + + This is where Mac header rewrites should be done; other platforms don't + have anything special they should do. + + Resource providers should call this method ONLY after successfully + extracting a compressed resource. They must NOT call it on resources + that are already in the filesystem. + + `tempname` is the current (temporary) name of the file, and `filename` + is the name it will be renamed to by the caller after this routine + returns. + """ + + if os.name == 'posix': + # Make the resource executable + mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 + os.chmod(tempname, mode) + + def set_extraction_path(self, path): + """Set the base path where resources will be extracted to, if needed. + + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which + is based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + + Resources are extracted to subdirectories of this path based upon + information given by the ``IResourceProvider``. You may set this to a + temporary directory, but then you must call ``cleanup_resources()`` to + delete the extracted files when done. There is no guarantee that + ``cleanup_resources()`` will be able to remove all extracted files. + + (Note: you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``.) + """ + if self.cached_files: + raise ValueError( + "Can't change extraction path, files already extracted" + ) + + self.extraction_path = path + + def cleanup_resources(self, force=False): + """ + Delete all extracted resource files and directories, returning a list + of the file and directory names that could not be successfully removed. + This function does not have any concurrency protection, so it should + generally only be called when the extraction path is a temporary + directory exclusive to a single process. This method is not + automatically called; you must call it explicitly or register it as an + ``atexit`` function if you wish to ensure cleanup of a temporary + directory used for extractions. + """ + # XXX + + +def get_default_cache(): + """ + Return the ``PYTHON_EGG_CACHE`` environment variable + or a platform-relevant user cache dir for an app + named "Python-Eggs". + """ + return ( + os.environ.get('PYTHON_EGG_CACHE') + or appdirs.user_cache_dir(appname='Python-Eggs') + ) + + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """ + Convert an arbitrary string to a standard version string + """ + try: + # normalize the version + return str(packaging.version.Version(version)) + except packaging.version.InvalidVersion: + version = version.replace(' ', '.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def safe_extra(extra): + """Convert an arbitrary string to a standard 'extra' name + + Any runs of non-alphanumeric characters are replaced with a single '_', + and the result is always lowercased. + """ + return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower() + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-', '_') + + +def invalid_marker(text): + """ + Validate text as a PEP 508 environment marker; return an exception + if invalid or False otherwise. + """ + try: + evaluate_marker(text) + except SyntaxError as e: + e.filename = None + e.lineno = None + return e + return False + + +def evaluate_marker(text, extra=None): + """ + Evaluate a PEP 508 environment marker. + Return a boolean indicating the marker result in this environment. + Raise SyntaxError if marker is invalid. + + This implementation uses the 'pyparsing' module. + """ + try: + marker = packaging.markers.Marker(text) + return marker.evaluate() + except packaging.markers.InvalidMarker as e: + raise SyntaxError(e) + + +class NullProvider: + """Try to implement resources and metadata for arbitrary PEP 302 loaders""" + + egg_name = None + egg_info = None + loader = None + + def __init__(self, module): + self.loader = getattr(module, '__loader__', None) + self.module_path = os.path.dirname(getattr(module, '__file__', '')) + + def get_resource_filename(self, manager, resource_name): + return self._fn(self.module_path, resource_name) + + def get_resource_stream(self, manager, resource_name): + return io.BytesIO(self.get_resource_string(manager, resource_name)) + + def get_resource_string(self, manager, resource_name): + return self._get(self._fn(self.module_path, resource_name)) + + def has_resource(self, resource_name): + return self._has(self._fn(self.module_path, resource_name)) + + def has_metadata(self, name): + return self.egg_info and self._has(self._fn(self.egg_info, name)) + + def get_metadata(self, name): + if not self.egg_info: + return "" + value = self._get(self._fn(self.egg_info, name)) + return value.decode('utf-8') if six.PY3 else value + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + def resource_isdir(self, resource_name): + return self._isdir(self._fn(self.module_path, resource_name)) + + def metadata_isdir(self, name): + return self.egg_info and self._isdir(self._fn(self.egg_info, name)) + + def resource_listdir(self, resource_name): + return self._listdir(self._fn(self.module_path, resource_name)) + + def metadata_listdir(self, name): + if self.egg_info: + return self._listdir(self._fn(self.egg_info, name)) + return [] + + def run_script(self, script_name, namespace): + script = 'scripts/' + script_name + if not self.has_metadata(script): + raise ResolutionError( + "Script {script!r} not found in metadata at {self.egg_info!r}" + .format(**locals()), + ) + script_text = self.get_metadata(script).replace('\r\n', '\n') + script_text = script_text.replace('\r', '\n') + script_filename = self._fn(self.egg_info, script) + namespace['__file__'] = script_filename + if os.path.exists(script_filename): + source = open(script_filename).read() + code = compile(source, script_filename, 'exec') + exec(code, namespace, namespace) + else: + from linecache import cache + cache[script_filename] = ( + len(script_text), 0, script_text.split('\n'), script_filename + ) + script_code = compile(script_text, script_filename, 'exec') + exec(script_code, namespace, namespace) + + def _has(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _isdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _listdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _fn(self, base, resource_name): + if resource_name: + return os.path.join(base, *resource_name.split('/')) + return base + + def _get(self, path): + if hasattr(self.loader, 'get_data'): + return self.loader.get_data(path) + raise NotImplementedError( + "Can't perform this operation for loaders without 'get_data()'" + ) + + +register_loader_type(object, NullProvider) + + +class EggProvider(NullProvider): + """Provider based on a virtual filesystem""" + + def __init__(self, module): + NullProvider.__init__(self, module) + self._setup_prefix() + + def _setup_prefix(self): + # we assume here that our metadata may be nested inside a "basket" + # of multiple eggs; that's why we use module_path instead of .archive + path = self.module_path + old = None + while path != old: + if _is_egg_path(path): + self.egg_name = os.path.basename(path) + self.egg_info = os.path.join(path, 'EGG-INFO') + self.egg_root = path + break + old = path + path, base = os.path.split(path) + + +class DefaultProvider(EggProvider): + """Provides access to package resources in the filesystem""" + + def _has(self, path): + return os.path.exists(path) + + def _isdir(self, path): + return os.path.isdir(path) + + def _listdir(self, path): + return os.listdir(path) + + def get_resource_stream(self, manager, resource_name): + return open(self._fn(self.module_path, resource_name), 'rb') + + def _get(self, path): + with open(path, 'rb') as stream: + return stream.read() + + @classmethod + def _register(cls): + loader_cls = getattr( + importlib_machinery, + 'SourceFileLoader', + type(None), + ) + register_loader_type(loader_cls, cls) + + +DefaultProvider._register() + + +class EmptyProvider(NullProvider): + """Provider that returns nothing for all requests""" + + module_path = None + + _isdir = _has = lambda self, path: False + + def _get(self, path): + return '' + + def _listdir(self, path): + return [] + + def __init__(self): + pass + + +empty_provider = EmptyProvider() + + +class ZipManifests(dict): + """ + zip manifest builder + """ + + @classmethod + def build(cls, path): + """ + Build a dictionary similar to the zipimport directory + caches, except instead of tuples, store ZipInfo objects. + + Use a platform-specific path separator (os.sep) for the path keys + for compatibility with pypy on Windows. + """ + with zipfile.ZipFile(path) as zfile: + items = ( + ( + name.replace('/', os.sep), + zfile.getinfo(name), + ) + for name in zfile.namelist() + ) + return dict(items) + + load = build + + +class MemoizedZipManifests(ZipManifests): + """ + Memoized zipfile manifests. + """ + manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') + + def load(self, path): + """ + Load a manifest at path or return a suitable manifest already loaded. + """ + path = os.path.normpath(path) + mtime = os.stat(path).st_mtime + + if path not in self or self[path].mtime != mtime: + manifest = self.build(path) + self[path] = self.manifest_mod(manifest, mtime) + + return self[path].manifest + + +class ZipProvider(EggProvider): + """Resource support for zips and eggs""" + + eagers = None + _zip_manifests = MemoizedZipManifests() + + def __init__(self, module): + EggProvider.__init__(self, module) + self.zip_pre = self.loader.archive + os.sep + + def _zipinfo_name(self, fspath): + # Convert a virtual filename (full path to file) into a zipfile subpath + # usable with the zipimport directory cache for our target archive + fspath = fspath.rstrip(os.sep) + if fspath == self.loader.archive: + return '' + if fspath.startswith(self.zip_pre): + return fspath[len(self.zip_pre):] + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.zip_pre) + ) + + def _parts(self, zip_path): + # Convert a zipfile subpath into an egg-relative path part list. + # pseudo-fs path + fspath = self.zip_pre + zip_path + if fspath.startswith(self.egg_root + os.sep): + return fspath[len(self.egg_root) + 1:].split(os.sep) + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.egg_root) + ) + + @property + def zipinfo(self): + return self._zip_manifests.load(self.loader.archive) + + def get_resource_filename(self, manager, resource_name): + if not self.egg_name: + raise NotImplementedError( + "resource_filename() only supported for .egg, not .zip" + ) + # no need to lock for extraction, since we use temp names + zip_path = self._resource_to_zip(resource_name) + eagers = self._get_eager_resources() + if '/'.join(self._parts(zip_path)) in eagers: + for name in eagers: + self._extract_resource(manager, self._eager_to_zip(name)) + return self._extract_resource(manager, zip_path) + + @staticmethod + def _get_date_and_size(zip_stat): + size = zip_stat.file_size + # ymdhms+wday, yday, dst + date_time = zip_stat.date_time + (0, 0, -1) + # 1980 offset already done + timestamp = time.mktime(date_time) + return timestamp, size + + def _extract_resource(self, manager, zip_path): + + if zip_path in self._index(): + for name in self._index()[zip_path]: + last = self._extract_resource( + manager, os.path.join(zip_path, name) + ) + # return the extracted directory name + return os.path.dirname(last) + + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + + if not WRITE_SUPPORT: + raise IOError('"os.rename" and "os.unlink" are not supported ' + 'on this platform') + try: + + real_path = manager.get_cache_path( + self.egg_name, self._parts(zip_path) + ) + + if self._is_current(real_path, zip_path): + return real_path + + outf, tmpnam = _mkstemp( + ".$extract", + dir=os.path.dirname(real_path), + ) + os.write(outf, self.loader.get_data(zip_path)) + os.close(outf) + utime(tmpnam, (timestamp, timestamp)) + manager.postprocess(tmpnam, real_path) + + try: + rename(tmpnam, real_path) + + except os.error: + if os.path.isfile(real_path): + if self._is_current(real_path, zip_path): + # the file became current since it was checked above, + # so proceed. + return real_path + # Windows, del old file and retry + elif os.name == 'nt': + unlink(real_path) + rename(tmpnam, real_path) + return real_path + raise + + except os.error: + # report a user-friendly error + manager.extraction_error() + + return real_path + + def _is_current(self, file_path, zip_path): + """ + Return True if the file_path is current for this zip_path + """ + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + if not os.path.isfile(file_path): + return False + stat = os.stat(file_path) + if stat.st_size != size or stat.st_mtime != timestamp: + return False + # check that the contents match + zip_contents = self.loader.get_data(zip_path) + with open(file_path, 'rb') as f: + file_contents = f.read() + return zip_contents == file_contents + + def _get_eager_resources(self): + if self.eagers is None: + eagers = [] + for name in ('native_libs.txt', 'eager_resources.txt'): + if self.has_metadata(name): + eagers.extend(self.get_metadata_lines(name)) + self.eagers = eagers + return self.eagers + + def _index(self): + try: + return self._dirindex + except AttributeError: + ind = {} + for path in self.zipinfo: + parts = path.split(os.sep) + while parts: + parent = os.sep.join(parts[:-1]) + if parent in ind: + ind[parent].append(parts[-1]) + break + else: + ind[parent] = [parts.pop()] + self._dirindex = ind + return ind + + def _has(self, fspath): + zip_path = self._zipinfo_name(fspath) + return zip_path in self.zipinfo or zip_path in self._index() + + def _isdir(self, fspath): + return self._zipinfo_name(fspath) in self._index() + + def _listdir(self, fspath): + return list(self._index().get(self._zipinfo_name(fspath), ())) + + def _eager_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.egg_root, resource_name)) + + def _resource_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.module_path, resource_name)) + + +register_loader_type(zipimport.zipimporter, ZipProvider) + + +class FileMetadata(EmptyProvider): + """Metadata handler for standalone PKG-INFO files + + Usage:: + + metadata = FileMetadata("/path/to/PKG-INFO") + + This provider rejects all data and metadata requests except for PKG-INFO, + which is treated as existing, and will be the contents of the file at + the provided location. + """ + + def __init__(self, path): + self.path = path + + def has_metadata(self, name): + return name == 'PKG-INFO' and os.path.isfile(self.path) + + def get_metadata(self, name): + if name != 'PKG-INFO': + raise KeyError("No metadata except PKG-INFO is available") + + with io.open(self.path, encoding='utf-8', errors="replace") as f: + metadata = f.read() + self._warn_on_replacement(metadata) + return metadata + + def _warn_on_replacement(self, metadata): + # Python 2.7 compat for: replacement_char = '�' + replacement_char = b'\xef\xbf\xbd'.decode('utf-8') + if replacement_char in metadata: + tmpl = "{self.path} could not be properly decoded in UTF-8" + msg = tmpl.format(**locals()) + warnings.warn(msg) + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + +class PathMetadata(DefaultProvider): + """Metadata provider for egg directories + + Usage:: + + # Development eggs: + + egg_info = "/path/to/PackageName.egg-info" + base_dir = os.path.dirname(egg_info) + metadata = PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + dist = Distribution(basedir, project_name=dist_name, metadata=metadata) + + # Unpacked egg directories: + + egg_path = "/path/to/PackageName-ver-pyver-etc.egg" + metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) + dist = Distribution.from_filename(egg_path, metadata=metadata) + """ + + def __init__(self, path, egg_info): + self.module_path = path + self.egg_info = egg_info + + +class EggMetadata(ZipProvider): + """Metadata provider for .egg files""" + + def __init__(self, importer): + """Create a metadata provider from a zipimporter""" + + self.zip_pre = importer.archive + os.sep + self.loader = importer + if importer.prefix: + self.module_path = os.path.join(importer.archive, importer.prefix) + else: + self.module_path = importer.archive + self._setup_prefix() + + +_declare_state('dict', _distribution_finders={}) + + +def register_finder(importer_type, distribution_finder): + """Register `distribution_finder` to find distributions in sys.path items + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `distribution_finder` is a callable that, passed a path + item and the importer instance, yields ``Distribution`` instances found on + that path item. See ``pkg_resources.find_on_path`` for an example.""" + _distribution_finders[importer_type] = distribution_finder + + +def find_distributions(path_item, only=False): + """Yield distributions accessible via `path_item`""" + importer = get_importer(path_item) + finder = _find_adapter(_distribution_finders, importer) + return finder(importer, path_item, only) + + +def find_eggs_in_zip(importer, path_item, only=False): + """ + Find eggs in zip files; possibly multiple nested eggs. + """ + if importer.archive.endswith('.whl'): + # wheels are not supported with this finder + # they don't have PKG-INFO metadata, and won't ever contain eggs + return + metadata = EggMetadata(importer) + if metadata.has_metadata('PKG-INFO'): + yield Distribution.from_filename(path_item, metadata=metadata) + if only: + # don't yield nested distros + return + for subitem in metadata.resource_listdir('/'): + if _is_egg_path(subitem): + subpath = os.path.join(path_item, subitem) + dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath) + for dist in dists: + yield dist + elif subitem.lower().endswith('.dist-info'): + subpath = os.path.join(path_item, subitem) + submeta = EggMetadata(zipimport.zipimporter(subpath)) + submeta.egg_info = subpath + yield Distribution.from_location(path_item, subitem, submeta) + + +register_finder(zipimport.zipimporter, find_eggs_in_zip) + + +def find_nothing(importer, path_item, only=False): + return () + + +register_finder(object, find_nothing) + + +def _by_version_descending(names): + """ + Given a list of filenames, return them in descending order + by version number. + + >>> names = 'bar', 'foo', 'Python-2.7.10.egg', 'Python-2.7.2.egg' + >>> _by_version_descending(names) + ['Python-2.7.10.egg', 'Python-2.7.2.egg', 'foo', 'bar'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.egg', 'Setuptools-1.2.3b1.egg'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.post1.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg'] + """ + def _by_version(name): + """ + Parse each component of the filename + """ + name, ext = os.path.splitext(name) + parts = itertools.chain(name.split('-'), [ext]) + return [packaging.version.parse(part) for part in parts] + + return sorted(names, key=_by_version, reverse=True) + + +def find_on_path(importer, path_item, only=False): + """Yield distributions accessible on a sys.path directory""" + path_item = _normalize_cached(path_item) + + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item, 'EGG-INFO') + ) + ) + return + + entries = safe_listdir(path_item) + + # for performance, before sorting by version, + # screen entries for only those that will yield + # distributions + filtered = ( + entry + for entry in entries + if dist_factory(path_item, entry, only) + ) + + # scan for .egg and .egg-info in directory + path_item_entries = _by_version_descending(filtered) + for entry in path_item_entries: + fullpath = os.path.join(path_item, entry) + factory = dist_factory(path_item, entry, only) + for dist in factory(fullpath): + yield dist + + +def dist_factory(path_item, entry, only): + """ + Return a dist_factory for a path_item and entry + """ + lower = entry.lower() + is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info'))) + return ( + distributions_from_metadata + if is_meta else + find_distributions + if not only and _is_egg_path(entry) else + resolve_egg_link + if not only and lower.endswith('.egg-link') else + NoDists() + ) + + +class NoDists: + """ + >>> bool(NoDists()) + False + + >>> list(NoDists()('anything')) + [] + """ + def __bool__(self): + return False + if six.PY2: + __nonzero__ = __bool__ + + def __call__(self, fullpath): + return iter(()) + + +def safe_listdir(path): + """ + Attempt to list contents of path, but suppress some exceptions. + """ + try: + return os.listdir(path) + except (PermissionError, NotADirectoryError): + pass + except OSError as e: + # Ignore the directory if does not exist, not a directory or + # permission denied + ignorable = ( + e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) + # Python 2 on Windows needs to be handled this way :( + or getattr(e, "winerror", None) == 267 + ) + if not ignorable: + raise + return () + + +def distributions_from_metadata(path): + root = os.path.dirname(path) + if os.path.isdir(path): + if len(os.listdir(path)) == 0: + # empty metadata dir; skip + return + metadata = PathMetadata(root, path) + else: + metadata = FileMetadata(path) + entry = os.path.basename(path) + yield Distribution.from_location( + root, entry, metadata, precedence=DEVELOP_DIST, + ) + + +def non_empty_lines(path): + """ + Yield non-empty lines from file at path + """ + with open(path) as f: + for line in f: + line = line.strip() + if line: + yield line + + +def resolve_egg_link(path): + """ + Given a path to an .egg-link, resolve distributions + present in the referenced path. + """ + referenced_paths = non_empty_lines(path) + resolved_paths = ( + os.path.join(os.path.dirname(path), ref) + for ref in referenced_paths + ) + dist_groups = map(find_distributions, resolved_paths) + return next(dist_groups, ()) + + +register_finder(pkgutil.ImpImporter, find_on_path) + +if hasattr(importlib_machinery, 'FileFinder'): + register_finder(importlib_machinery.FileFinder, find_on_path) + +_declare_state('dict', _namespace_handlers={}) +_declare_state('dict', _namespace_packages={}) + + +def register_namespace_handler(importer_type, namespace_handler): + """Register `namespace_handler` to declare namespace packages + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `namespace_handler` is a callable like this:: + + def namespace_handler(importer, path_entry, moduleName, module): + # return a path_entry to use for child packages + + Namespace handlers are only called if the importer object has already + agreed that it can handle the relevant path item, and they should only + return a subpath if the module __path__ does not already contain an + equivalent subpath. For an example namespace handler, see + ``pkg_resources.file_ns_handler``. + """ + _namespace_handlers[importer_type] = namespace_handler + + +def _handle_ns(packageName, path_item): + """Ensure that named package includes a subpath of path_item (if needed)""" + + importer = get_importer(path_item) + if importer is None: + return None + loader = importer.find_module(packageName) + if loader is None: + return None + module = sys.modules.get(packageName) + if module is None: + module = sys.modules[packageName] = types.ModuleType(packageName) + module.__path__ = [] + _set_parent_ns(packageName) + elif not hasattr(module, '__path__'): + raise TypeError("Not a package:", packageName) + handler = _find_adapter(_namespace_handlers, importer) + subpath = handler(importer, path_item, packageName, module) + if subpath is not None: + path = module.__path__ + path.append(subpath) + loader.load_module(packageName) + _rebuild_mod_path(path, packageName, module) + return subpath + + +def _rebuild_mod_path(orig_path, package_name, module): + """ + Rebuild module.__path__ ensuring that all entries are ordered + corresponding to their sys.path order + """ + sys_path = [_normalize_cached(p) for p in sys.path] + + def safe_sys_path_index(entry): + """ + Workaround for #520 and #513. + """ + try: + return sys_path.index(entry) + except ValueError: + return float('inf') + + def position_in_sys_path(path): + """ + Return the ordinal of the path based on its position in sys.path + """ + path_parts = path.split(os.sep) + module_parts = package_name.count('.') + 1 + parts = path_parts[:-module_parts] + return safe_sys_path_index(_normalize_cached(os.sep.join(parts))) + + if not isinstance(orig_path, list): + # Is this behavior useful when module.__path__ is not a list? + return + + orig_path.sort(key=position_in_sys_path) + module.__path__[:] = [_normalize_cached(p) for p in orig_path] + + +def declare_namespace(packageName): + """Declare that package 'packageName' is a namespace package""" + + _imp.acquire_lock() + try: + if packageName in _namespace_packages: + return + + path, parent = sys.path, None + if '.' in packageName: + parent = '.'.join(packageName.split('.')[:-1]) + declare_namespace(parent) + if parent not in _namespace_packages: + __import__(parent) + try: + path = sys.modules[parent].__path__ + except AttributeError: + raise TypeError("Not a package:", parent) + + # Track what packages are namespaces, so when new path items are added, + # they can be updated + _namespace_packages.setdefault(parent, []).append(packageName) + _namespace_packages.setdefault(packageName, []) + + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + + finally: + _imp.release_lock() + + +def fixup_namespace_packages(path_item, parent=None): + """Ensure that previously-declared namespace packages include path_item""" + _imp.acquire_lock() + try: + for package in _namespace_packages.get(parent, ()): + subpath = _handle_ns(package, path_item) + if subpath: + fixup_namespace_packages(subpath, package) + finally: + _imp.release_lock() + + +def file_ns_handler(importer, path_item, packageName, module): + """Compute an ns-package subpath for a filesystem or zipfile importer""" + + subpath = os.path.join(path_item, packageName.split('.')[-1]) + normalized = _normalize_cached(subpath) + for item in module.__path__: + if _normalize_cached(item) == normalized: + break + else: + # Only return the path if it's not already there + return subpath + + +register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) +register_namespace_handler(zipimport.zipimporter, file_ns_handler) + +if hasattr(importlib_machinery, 'FileFinder'): + register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) + + +def null_ns_handler(importer, path_item, packageName, module): + return None + + +register_namespace_handler(object, null_ns_handler) + + +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(filename)) + + +def _normalize_cached(filename, _cache={}): + try: + return _cache[filename] + except KeyError: + _cache[filename] = result = normalize_path(filename) + return result + + +def _is_egg_path(path): + """ + Determine if given path appears to be an egg. + """ + return path.lower().endswith('.egg') + + +def _is_unpacked_egg(path): + """ + Determine if given path appears to be an unpacked egg. + """ + return ( + _is_egg_path(path) and + os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO')) + ) + + +def _set_parent_ns(packageName): + parts = packageName.split('.') + name = parts.pop() + if parts: + parent = '.'.join(parts) + setattr(sys.modules[parent], name, sys.modules[packageName]) + + +def yield_lines(strs): + """Yield non-empty/non-comment lines of a string or sequence""" + if isinstance(strs, six.string_types): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + + +MODULE = re.compile(r"\w+(\.\w+)*$").match +EGG_NAME = re.compile( + r""" + (?P<name>[^-]+) ( + -(?P<ver>[^-]+) ( + -py(?P<pyver>[^-]+) ( + -(?P<plat>.+) + )? + )? + )? + """, + re.VERBOSE | re.IGNORECASE, +).match + + +class EntryPoint(object): + """Object representing an advertised importable object""" + + def __init__(self, name, module_name, attrs=(), extras=(), dist=None): + if not MODULE(module_name): + raise ValueError("Invalid module name", module_name) + self.name = name + self.module_name = module_name + self.attrs = tuple(attrs) + self.extras = tuple(extras) + self.dist = dist + + def __str__(self): + s = "%s = %s" % (self.name, self.module_name) + if self.attrs: + s += ':' + '.'.join(self.attrs) + if self.extras: + s += ' [%s]' % ','.join(self.extras) + return s + + def __repr__(self): + return "EntryPoint.parse(%r)" % str(self) + + def load(self, require=True, *args, **kwargs): + """ + Require packages for this EntryPoint, then resolve it. + """ + if not require or args or kwargs: + warnings.warn( + "Parameters to load are deprecated. Call .resolve and " + ".require separately.", + DeprecationWarning, + stacklevel=2, + ) + if require: + self.require(*args, **kwargs) + return self.resolve() + + def resolve(self): + """ + Resolve the entry point from its module and attrs. + """ + module = __import__(self.module_name, fromlist=['__name__'], level=0) + try: + return functools.reduce(getattr, self.attrs, module) + except AttributeError as exc: + raise ImportError(str(exc)) + + def require(self, env=None, installer=None): + if self.extras and not self.dist: + raise UnknownExtra("Can't require() without a distribution", self) + + # Get the requirements for this entry point with all its extras and + # then resolve them. We have to pass `extras` along when resolving so + # that the working set knows what extras we want. Otherwise, for + # dist-info distributions, the working set will assume that the + # requirements for that extra are purely optional and skip over them. + reqs = self.dist.requires(self.extras) + items = working_set.resolve(reqs, env, installer, extras=self.extras) + list(map(working_set.add, items)) + + pattern = re.compile( + r'\s*' + r'(?P<name>.+?)\s*' + r'=\s*' + r'(?P<module>[\w.]+)\s*' + r'(:\s*(?P<attr>[\w.]+))?\s*' + r'(?P<extras>\[.*\])?\s*$' + ) + + @classmethod + def parse(cls, src, dist=None): + """Parse a single entry point from string `src` + + Entry point syntax follows the form:: + + name = some.module:some.attr [extra1, extra2] + + The entry name and module name are required, but the ``:attrs`` and + ``[extras]`` parts are optional + """ + m = cls.pattern.match(src) + if not m: + msg = "EntryPoint must be in 'name=module:attrs [extras]' format" + raise ValueError(msg, src) + res = m.groupdict() + extras = cls._parse_extras(res['extras']) + attrs = res['attr'].split('.') if res['attr'] else () + return cls(res['name'], res['module'], attrs, extras, dist) + + @classmethod + def _parse_extras(cls, extras_spec): + if not extras_spec: + return () + req = Requirement.parse('x' + extras_spec) + if req.specs: + raise ValueError() + return req.extras + + @classmethod + def parse_group(cls, group, lines, dist=None): + """Parse an entry point group""" + if not MODULE(group): + raise ValueError("Invalid group name", group) + this = {} + for line in yield_lines(lines): + ep = cls.parse(line, dist) + if ep.name in this: + raise ValueError("Duplicate entry point", group, ep.name) + this[ep.name] = ep + return this + + @classmethod + def parse_map(cls, data, dist=None): + """Parse a map of entry point groups""" + if isinstance(data, dict): + data = data.items() + else: + data = split_sections(data) + maps = {} + for group, lines in data: + if group is None: + if not lines: + continue + raise ValueError("Entry points must be listed in groups") + group = group.strip() + if group in maps: + raise ValueError("Duplicate group name", group) + maps[group] = cls.parse_group(group, lines, dist) + return maps + + +def _remove_md5_fragment(location): + if not location: + return '' + parsed = urllib.parse.urlparse(location) + if parsed[-1].startswith('md5='): + return urllib.parse.urlunparse(parsed[:-1] + ('',)) + return location + + +def _version_from_file(lines): + """ + Given an iterable of lines from a Metadata file, return + the value of the Version field, if present, or None otherwise. + """ + def is_version_line(line): + return line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) + line = next(iter(version_lines), '') + _, _, value = line.partition(':') + return safe_version(value.strip()) or None + + +class Distribution(object): + """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' + + def __init__( + self, location=None, metadata=None, project_name=None, + version=None, py_version=PY_MAJOR, platform=None, + precedence=EGG_DIST): + self.project_name = safe_name(project_name or 'Unknown') + if version is not None: + self._version = safe_version(version) + self.py_version = py_version + self.platform = platform + self.location = location + self.precedence = precedence + self._provider = metadata or empty_provider + + @classmethod + def from_location(cls, location, basename, metadata=None, **kw): + project_name, version, py_version, platform = [None] * 4 + basename, ext = os.path.splitext(basename) + if ext.lower() in _distributionImpl: + cls = _distributionImpl[ext.lower()] + + match = EGG_NAME(basename) + if match: + project_name, version, py_version, platform = match.group( + 'name', 'ver', 'pyver', 'plat' + ) + return cls( + location, metadata, project_name=project_name, version=version, + py_version=py_version, platform=platform, **kw + )._reload_version() + + def _reload_version(self): + return self + + @property + def hashcmp(self): + return ( + self.parsed_version, + self.precedence, + self.key, + _remove_md5_fragment(self.location), + self.py_version or '', + self.platform or '', + ) + + def __hash__(self): + return hash(self.hashcmp) + + def __lt__(self, other): + return self.hashcmp < other.hashcmp + + def __le__(self, other): + return self.hashcmp <= other.hashcmp + + def __gt__(self, other): + return self.hashcmp > other.hashcmp + + def __ge__(self, other): + return self.hashcmp >= other.hashcmp + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # It's not a Distribution, so they are not equal + return False + return self.hashcmp == other.hashcmp + + def __ne__(self, other): + return not self == other + + # These properties have to be lazy so that we don't have to load any + # metadata until/unless it's actually needed. (i.e., some distributions + # may not know their name or version without loading PKG-INFO) + + @property + def key(self): + try: + return self._key + except AttributeError: + self._key = key = self.project_name.lower() + return key + + @property + def parsed_version(self): + if not hasattr(self, "_parsed_version"): + self._parsed_version = parse_version(self.version) + + return self._parsed_version + + def _warn_legacy_version(self): + LV = packaging.version.LegacyVersion + is_legacy = isinstance(self._parsed_version, LV) + if not is_legacy: + return + + # While an empty version is technically a legacy version and + # is not a valid PEP 440 version, it's also unlikely to + # actually come from someone and instead it is more likely that + # it comes from setuptools attempting to parse a filename and + # including it in the list. So for that we'll gate this warning + # on if the version is anything at all or not. + if not self.version: + return + + tmpl = textwrap.dedent(""" + '{project_name} ({version})' is being parsed as a legacy, + non PEP 440, + version. You may find odd behavior and sort order. + In particular it will be sorted as less than 0.0. It + is recommended to migrate to PEP 440 compatible + versions. + """).strip().replace('\n', ' ') + + warnings.warn(tmpl.format(**vars(self)), PEP440Warning) + + @property + def version(self): + try: + return self._version + except AttributeError: + version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if version is None: + tmpl = "Missing 'Version:' header and/or %s file" + raise ValueError(tmpl % self.PKG_INFO, self) + return version + + @property + def _dep_map(self): + """ + A map of extra to its list of (direct) requirements + for this distribution, including the null extra. + """ + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._filter_extras(self._build_dep_map()) + return self.__dep_map + + @staticmethod + def _filter_extras(dm): + """ + Given a mapping of extras to dependencies, strip off + environment markers and filter out any dependencies + not matching the markers. + """ + for extra in list(filter(None, dm)): + new_extra = extra + reqs = dm.pop(extra) + new_extra, _, marker = extra.partition(':') + fails_marker = marker and ( + invalid_marker(marker) + or not evaluate_marker(marker) + ) + if fails_marker: + reqs = [] + new_extra = safe_extra(new_extra) or None + + dm.setdefault(new_extra, []).extend(reqs) + return dm + + def _build_dep_map(self): + dm = {} + for name in 'requires.txt', 'depends.txt': + for extra, reqs in split_sections(self._get_metadata(name)): + dm.setdefault(extra, []).extend(parse_requirements(reqs)) + return dm + + def requires(self, extras=()): + """List of Requirements needed for this distro if `extras` are used""" + dm = self._dep_map + deps = [] + deps.extend(dm.get(None, ())) + for ext in extras: + try: + deps.extend(dm[safe_extra(ext)]) + except KeyError: + raise UnknownExtra( + "%s has no such extra feature %r" % (self, ext) + ) + return deps + + def _get_metadata(self, name): + if self.has_metadata(name): + for line in self.get_metadata_lines(name): + yield line + + def activate(self, path=None, replace=False): + """Ensure distribution is importable on `path` (default=sys.path)""" + if path is None: + path = sys.path + self.insert_on(path, replace=replace) + if path is sys.path: + fixup_namespace_packages(self.location) + for pkg in self._get_metadata('namespace_packages.txt'): + if pkg in sys.modules: + declare_namespace(pkg) + + def egg_name(self): + """Return what this distribution's standard .egg filename should be""" + filename = "%s-%s-py%s" % ( + to_filename(self.project_name), to_filename(self.version), + self.py_version or PY_MAJOR + ) + + if self.platform: + filename += '-' + self.platform + return filename + + def __repr__(self): + if self.location: + return "%s (%s)" % (self, self.location) + else: + return str(self) + + def __str__(self): + try: + version = getattr(self, 'version', None) + except ValueError: + version = None + version = version or "[unknown version]" + return "%s %s" % (self.project_name, version) + + def __getattr__(self, attr): + """Delegate all unrecognized public attributes to .metadata provider""" + if attr.startswith('_'): + raise AttributeError(attr) + return getattr(self._provider, attr) + + @classmethod + def from_filename(cls, filename, metadata=None, **kw): + return cls.from_location( + _normalize_cached(filename), os.path.basename(filename), metadata, + **kw + ) + + def as_requirement(self): + """Return a ``Requirement`` that matches this distribution exactly""" + if isinstance(self.parsed_version, packaging.version.Version): + spec = "%s==%s" % (self.project_name, self.parsed_version) + else: + spec = "%s===%s" % (self.project_name, self.parsed_version) + + return Requirement.parse(spec) + + def load_entry_point(self, group, name): + """Return the `name` entry point of `group` or raise ImportError""" + ep = self.get_entry_info(group, name) + if ep is None: + raise ImportError("Entry point %r not found" % ((group, name),)) + return ep.load() + + def get_entry_map(self, group=None): + """Return the entry point map for `group`, or the full entry map""" + try: + ep_map = self._ep_map + except AttributeError: + ep_map = self._ep_map = EntryPoint.parse_map( + self._get_metadata('entry_points.txt'), self + ) + if group is not None: + return ep_map.get(group, {}) + return ep_map + + def get_entry_info(self, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return self.get_entry_map(group).get(name) + + def insert_on(self, path, loc=None, replace=False): + """Ensure self.location is on path + + If replace=False (default): + - If location is already in path anywhere, do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent. + - Else: add to the end of path. + If replace=True: + - If location is already on path anywhere (not eggs) + or higher priority than its parent (eggs) + do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent, + removing any lower-priority entries. + - Else: add it to the front of path. + """ + + loc = loc or self.location + if not loc: + return + + nloc = _normalize_cached(loc) + bdir = os.path.dirname(nloc) + npath = [(p and _normalize_cached(p) or p) for p in path] + + for p, item in enumerate(npath): + if item == nloc: + if replace: + break + else: + # don't modify path (even removing duplicates) if + # found and not replace + return + elif item == bdir and self.precedence == EGG_DIST: + # if it's an .egg, give it precedence over its directory + # UNLESS it's already been added to sys.path and replace=False + if (not replace) and nloc in npath[p:]: + return + if path is sys.path: + self.check_version_conflict() + path.insert(p, loc) + npath.insert(p, nloc) + break + else: + if path is sys.path: + self.check_version_conflict() + if replace: + path.insert(0, loc) + else: + path.append(loc) + return + + # p is the spot where we found or inserted loc; now remove duplicates + while True: + try: + np = npath.index(nloc, p + 1) + except ValueError: + break + else: + del npath[np], path[np] + # ha! + p = np + + return + + def check_version_conflict(self): + if self.key == 'setuptools': + # ignore the inevitable setuptools self-conflicts :( + return + + nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt')) + loc = normalize_path(self.location) + for modname in self._get_metadata('top_level.txt'): + if (modname not in sys.modules or modname in nsp + or modname in _namespace_packages): + continue + if modname in ('pkg_resources', 'setuptools', 'site'): + continue + fn = getattr(sys.modules[modname], '__file__', None) + if fn and (normalize_path(fn).startswith(loc) or + fn.startswith(self.location)): + continue + issue_warning( + "Module %s was already imported from %s, but %s is being added" + " to sys.path" % (modname, fn, self.location), + ) + + def has_version(self): + try: + self.version + except ValueError: + issue_warning("Unbuilt egg for " + repr(self)) + return False + return True + + def clone(self, **kw): + """Copy this distribution, substituting in any changed keyword args""" + names = 'project_name version py_version platform location precedence' + for attr in names.split(): + kw.setdefault(attr, getattr(self, attr, None)) + kw.setdefault('metadata', self._provider) + return self.__class__(**kw) + + @property + def extras(self): + return [dep for dep in self._dep_map if dep] + + +class EggInfoDistribution(Distribution): + def _reload_version(self): + """ + Packages installed by distutils (e.g. numpy or scipy), + which uses an old safe_version, and so + their version numbers can get mangled when + converted to filenames (e.g., 1.11.0.dev0+2329eae to + 1.11.0.dev0_2329eae). These distributions will not be + parsed properly + downstream by Distribution and safe_version, so + take an extra step and try to get the version number from + the metadata file itself instead of the filename. + """ + md_version = _version_from_file(self._get_metadata(self.PKG_INFO)) + if md_version: + self._version = md_version + return self + + +class DistInfoDistribution(Distribution): + """ + Wrap an actual or potential sys.path entry + w/metadata, .dist-info style. + """ + PKG_INFO = 'METADATA' + EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") + + @property + def _parsed_pkg_info(self): + """Parse and cache metadata""" + try: + return self._pkg_info + except AttributeError: + metadata = self.get_metadata(self.PKG_INFO) + self._pkg_info = email.parser.Parser().parsestr(metadata) + return self._pkg_info + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._compute_dependencies() + return self.__dep_map + + def _compute_dependencies(self): + """Recompute this distribution's dependencies.""" + dm = self.__dep_map = {None: []} + + reqs = [] + # Including any condition expressions + for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: + reqs.extend(parse_requirements(req)) + + def reqs_for_extra(extra): + for req in reqs: + if not req.marker or req.marker.evaluate({'extra': extra}): + yield req + + common = frozenset(reqs_for_extra(None)) + dm[None].extend(common) + + for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: + s_extra = safe_extra(extra.strip()) + dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common) + + return dm + + +_distributionImpl = { + '.egg': Distribution, + '.egg-info': EggInfoDistribution, + '.dist-info': DistInfoDistribution, +} + + +def issue_warning(*args, **kw): + level = 1 + g = globals() + try: + # find the first stack frame that is *not* code in + # the pkg_resources module, to use for the warning + while sys._getframe(level).f_globals is g: + level += 1 + except ValueError: + pass + warnings.warn(stacklevel=level + 1, *args, **kw) + + +class RequirementParseError(ValueError): + def __str__(self): + return ' '.join(self.args) + + +def parse_requirements(strs): + """Yield ``Requirement`` objects for each specification in `strs` + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + # create a steppable iterator, so we can handle \-continuations + lines = iter(yield_lines(strs)) + + for line in lines: + # Drop comments -- a hash without a space may be in a URL. + if ' #' in line: + line = line[:line.find(' #')] + # If there is a line continuation, drop it, and append the next line. + if line.endswith('\\'): + line = line[:-2].strip() + try: + line += next(lines) + except StopIteration: + return + yield Requirement(line) + + +class Requirement(packaging.requirements.Requirement): + def __init__(self, requirement_string): + """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" + try: + super(Requirement, self).__init__(requirement_string) + except packaging.requirements.InvalidRequirement as e: + raise RequirementParseError(str(e)) + self.unsafe_name = self.name + project_name = safe_name(self.name) + self.project_name, self.key = project_name, project_name.lower() + self.specs = [ + (spec.operator, spec.version) for spec in self.specifier] + self.extras = tuple(map(safe_extra, self.extras)) + self.hashCmp = ( + self.key, + self.specifier, + frozenset(self.extras), + str(self.marker) if self.marker else None, + ) + self.__hash = hash(self.hashCmp) + + def __eq__(self, other): + return ( + isinstance(other, Requirement) and + self.hashCmp == other.hashCmp + ) + + def __ne__(self, other): + return not self == other + + def __contains__(self, item): + if isinstance(item, Distribution): + if item.key != self.key: + return False + + item = item.version + + # Allow prereleases always in order to match the previous behavior of + # this method. In the future this should be smarter and follow PEP 440 + # more accurately. + return self.specifier.contains(item, prereleases=True) + + def __hash__(self): + return self.__hash + + def __repr__(self): + return "Requirement.parse(%r)" % str(self) + + @staticmethod + def parse(s): + req, = parse_requirements(s) + return req + + +def _always_object(classes): + """ + Ensure object appears in the mro even + for old-style classes. + """ + if object not in classes: + return classes + (object,) + return classes + + +def _find_adapter(registry, ob): + """Return an adapter factory for `ob` from `registry`""" + types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob)))) + for t in types: + if t in registry: + return registry[t] + + +def ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + py31compat.makedirs(dirname, exist_ok=True) + + +def _bypass_ensure_directory(path): + """Sandbox-bypassing version of ensure_directory()""" + if not WRITE_SUPPORT: + raise IOError('"os.mkdir" not supported on this platform.') + dirname, filename = split(path) + if dirname and filename and not isdir(dirname): + _bypass_ensure_directory(dirname) + mkdir(dirname, 0o755) + + +def split_sections(s): + """Split a string or iterable thereof into (section, content) pairs + + Each ``section`` is a stripped version of the section header ("[section]") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any such lines before the first section + header, they're returned in a first ``section`` of ``None``. + """ + section = None + content = [] + for line in yield_lines(s): + if line.startswith("["): + if line.endswith("]"): + if section or content: + yield section, content + section = line[1:-1].strip() + content = [] + else: + raise ValueError("Invalid section heading", line) + else: + content.append(line) + + # wrap up last segment + yield section, content + + +def _mkstemp(*args, **kw): + old_open = os.open + try: + # temporarily bypass sandboxing + os.open = os_open + return tempfile.mkstemp(*args, **kw) + finally: + # and then put it back + os.open = old_open + + +# Silence the PEP440Warning by default, so that end users don't get hit by it +# randomly just because they use pkg_resources. We want to append the rule +# because we want earlier uses of filterwarnings to take precedence over this +# one. +warnings.filterwarnings("ignore", category=PEP440Warning, append=True) + + +# from jaraco.functools 1.3 +def _call_aside(f, *args, **kwargs): + f(*args, **kwargs) + return f + + +@_call_aside +def _initialize(g=globals()): + "Set up global resource manager (deliberately not state-saved)" + manager = ResourceManager() + g['_manager'] = manager + g.update( + (name, getattr(manager, name)) + for name in dir(manager) + if not name.startswith('_') + ) + + +@_call_aside +def _initialize_master_working_set(): + """ + Prepare the master working set and make the ``require()`` + API available. + + This function has explicit effects on the global state + of pkg_resources. It is intended to be invoked once at + the initialization of this module. + + Invocation by other packages is unsupported and done + at their own risk. + """ + working_set = WorkingSet._build_master() + _declare_state('object', working_set=working_set) + + require = working_set.require + iter_entry_points = working_set.iter_entry_points + add_activation_listener = working_set.subscribe + run_script = working_set.run_script + # backward compatibility + run_main = run_script + # Activate all distributions already on sys.path with replace=False and + # ensure that all distributions added to the working set in the future + # (e.g. by calling ``require()``) will get activated as well, + # with higher priority (replace=True). + tuple( + dist.activate(replace=False) + for dist in working_set + ) + add_activation_listener( + lambda dist: dist.activate(replace=True), + existing=False, + ) + working_set.entries = [] + # match order + list(map(working_set.add_entry, sys.path)) + globals().update(locals()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py new file mode 100755 index 0000000..3e1c152 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pkg_resources/py31compat.py @@ -0,0 +1,22 @@ +import os +import errno +import sys + + +def _makedirs_31(path, exist_ok=False): + try: + os.makedirs(path) + except OSError as exc: + if not exist_ok or exc.errno != errno.EEXIST: + raise + + +# rely on compatibility behavior until mode considerations +# and exists_ok considerations are disentangled. +# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663 +needs_makedirs = ( + sys.version_info < (3, 2, 5) or + (3, 3) <= sys.version_info < (3, 3, 6) or + (3, 4) <= sys.version_info < (3, 4, 1) +) +makedirs = _makedirs_31 if needs_makedirs else os.makedirs diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py new file mode 100755 index 0000000..4aa97fc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/__init__.py @@ -0,0 +1,127 @@ +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import division + +from collections import deque +from datetime import timedelta +from math import ceil +from sys import stderr +from time import time + + +__version__ = '1.3' + + +class Infinite(object): + file = stderr + sma_window = 10 # Simple Moving Average window + + def __init__(self, *args, **kwargs): + self.index = 0 + self.start_ts = time() + self.avg = 0 + self._ts = self.start_ts + self._xput = deque(maxlen=self.sma_window) + for key, val in kwargs.items(): + setattr(self, key, val) + + def __getitem__(self, key): + if key.startswith('_'): + return None + return getattr(self, key, None) + + @property + def elapsed(self): + return int(time() - self.start_ts) + + @property + def elapsed_td(self): + return timedelta(seconds=self.elapsed) + + def update_avg(self, n, dt): + if n > 0: + self._xput.append(dt / n) + self.avg = sum(self._xput) / len(self._xput) + + def update(self): + pass + + def start(self): + pass + + def finish(self): + pass + + def next(self, n=1): + now = time() + dt = now - self._ts + self.update_avg(n, dt) + self._ts = now + self.index = self.index + n + self.update() + + def iter(self, it): + try: + for x in it: + yield x + self.next() + finally: + self.finish() + + +class Progress(Infinite): + def __init__(self, *args, **kwargs): + super(Progress, self).__init__(*args, **kwargs) + self.max = kwargs.get('max', 100) + + @property + def eta(self): + return int(ceil(self.avg * self.remaining)) + + @property + def eta_td(self): + return timedelta(seconds=self.eta) + + @property + def percent(self): + return self.progress * 100 + + @property + def progress(self): + return min(1, self.index / self.max) + + @property + def remaining(self): + return max(self.max - self.index, 0) + + def start(self): + self.update() + + def goto(self, index): + incr = index - self.index + self.next(incr) + + def iter(self, it): + try: + self.max = len(it) + except TypeError: + pass + + try: + for x in it: + yield x + self.next() + finally: + self.finish() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py new file mode 100755 index 0000000..3fdd703 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/bar.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Progress +from .helpers import WritelnMixin + + +class Bar(WritelnMixin, Progress): + width = 32 + message = '' + suffix = '%(index)d/%(max)d' + bar_prefix = ' |' + bar_suffix = '| ' + empty_fill = ' ' + fill = '#' + hide_cursor = True + + def update(self): + filled_length = int(self.width * self.progress) + empty_length = self.width - filled_length + + message = self.message % self + bar = self.fill * filled_length + empty = self.empty_fill * empty_length + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, empty, self.bar_suffix, + suffix]) + self.writeln(line) + + +class ChargingBar(Bar): + suffix = '%(percent)d%%' + bar_prefix = ' ' + bar_suffix = ' ' + empty_fill = '∙' + fill = '█' + + +class FillingSquaresBar(ChargingBar): + empty_fill = '▢' + fill = '▣' + + +class FillingCirclesBar(ChargingBar): + empty_fill = '◯' + fill = '◉' + + +class IncrementalBar(Bar): + phases = (' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█') + + def update(self): + nphases = len(self.phases) + filled_len = self.width * self.progress + nfull = int(filled_len) # Number of full chars + phase = int((filled_len - nfull) * nphases) # Phase of last char + nempty = self.width - nfull # Number of empty chars + + message = self.message % self + bar = self.phases[-1] * nfull + current = self.phases[phase] if phase > 0 else '' + empty = self.empty_fill * max(0, nempty - len(current)) + suffix = self.suffix % self + line = ''.join([message, self.bar_prefix, bar, current, empty, + self.bar_suffix, suffix]) + self.writeln(line) + + +class PixelBar(IncrementalBar): + phases = ('⡀', '⡄', '⡆', '⡇', '⣇', '⣧', '⣷', '⣿') + + +class ShadyBar(IncrementalBar): + phases = (' ', '░', '▒', '▓', '█') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py new file mode 100755 index 0000000..e993a51 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/counter.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Infinite, Progress +from .helpers import WriteMixin + + +class Counter(WriteMixin, Infinite): + message = '' + hide_cursor = True + + def update(self): + self.write(str(self.index)) + + +class Countdown(WriteMixin, Progress): + hide_cursor = True + + def update(self): + self.write(str(self.remaining)) + + +class Stack(WriteMixin, Progress): + phases = (' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█') + hide_cursor = True + + def update(self): + nphases = len(self.phases) + i = min(nphases - 1, int(self.progress * nphases)) + self.write(self.phases[i]) + + +class Pie(Stack): + phases = ('○', '◔', '◑', '◕', '●') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py new file mode 100755 index 0000000..96c8800 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/helpers.py @@ -0,0 +1,91 @@ +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import print_function + + +HIDE_CURSOR = '\x1b[?25l' +SHOW_CURSOR = '\x1b[?25h' + + +class WriteMixin(object): + hide_cursor = False + + def __init__(self, message=None, **kwargs): + super(WriteMixin, self).__init__(**kwargs) + self._width = 0 + if message: + self.message = message + + if self.file.isatty(): + if self.hide_cursor: + print(HIDE_CURSOR, end='', file=self.file) + print(self.message, end='', file=self.file) + self.file.flush() + + def write(self, s): + if self.file.isatty(): + b = '\b' * self._width + c = s.ljust(self._width) + print(b + c, end='', file=self.file) + self._width = max(self._width, len(s)) + self.file.flush() + + def finish(self): + if self.file.isatty() and self.hide_cursor: + print(SHOW_CURSOR, end='', file=self.file) + + +class WritelnMixin(object): + hide_cursor = False + + def __init__(self, message=None, **kwargs): + super(WritelnMixin, self).__init__(**kwargs) + if message: + self.message = message + + if self.file.isatty() and self.hide_cursor: + print(HIDE_CURSOR, end='', file=self.file) + + def clearln(self): + if self.file.isatty(): + print('\r\x1b[K', end='', file=self.file) + + def writeln(self, line): + if self.file.isatty(): + self.clearln() + print(line, end='', file=self.file) + self.file.flush() + + def finish(self): + if self.file.isatty(): + print(file=self.file) + if self.hide_cursor: + print(SHOW_CURSOR, end='', file=self.file) + + +from signal import signal, SIGINT +from sys import exit + + +class SigIntMixin(object): + """Registers a signal handler that calls finish on SIGINT""" + + def __init__(self, *args, **kwargs): + super(SigIntMixin, self).__init__(*args, **kwargs) + signal(SIGINT, self._sigint_handler) + + def _sigint_handler(self, signum, frame): + self.finish() + exit(0) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py new file mode 100755 index 0000000..d67c679 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/progress/spinner.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 Giorgos Verigakis <verigak@gmail.com> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from __future__ import unicode_literals +from . import Infinite +from .helpers import WriteMixin + + +class Spinner(WriteMixin, Infinite): + message = '' + phases = ('-', '\\', '|', '/') + hide_cursor = True + + def update(self): + i = self.index % len(self.phases) + self.write(self.phases[i]) + + +class PieSpinner(Spinner): + phases = ['◷', '◶', '◵', '◴'] + + +class MoonSpinner(Spinner): + phases = ['◑', '◒', '◐', '◓'] + + +class LineSpinner(Spinner): + phases = ['⎺', '⎻', '⎼', '⎽', '⎼', '⎻'] + +class PixelSpinner(Spinner): + phases = ['⣾','⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽'] diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py new file mode 100755 index 0000000..d362e08 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pyparsing.py @@ -0,0 +1,5720 @@ +# module pyparsing.py +# +# Copyright (c) 2003-2016 Paul T. McGuire +# +# 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. +# + +__doc__ = \ +""" +pyparsing module - Classes and methods to define and execute parsing grammars + +The pyparsing module is an alternative approach to creating and executing simple grammars, +vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you +don't need to learn a new syntax for defining grammars or matching expressions - the parsing module +provides a library of classes that you use to construct the grammar directly in Python. + +Here is a program to parse "Hello, World!" (or any greeting of the form +C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements +(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to +L{Literal} expressions):: + + from pip._vendor.pyparsing import Word, alphas + + # define grammar of a greeting + greet = Word(alphas) + "," + Word(alphas) + "!" + + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + +The program outputs the following:: + + Hello, World! -> ['Hello', ',', 'World', '!'] + +The Python representation of the grammar is quite readable, owing to the self-explanatory +class names, and the use of '+', '|' and '^' operators. + +The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an +object with named attributes. + +The pyparsing module handles some of the problems that are typically vexing when writing text parsers: + - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) + - quoted strings + - embedded comments +""" + +__version__ = "2.2.0" +__versionTime__ = "06 Mar 2017 02:06 UTC" +__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" + +import string +from weakref import ref as wkref +import copy +import sys +import warnings +import re +import sre_constants +import collections +import pprint +import traceback +import types +from datetime import datetime + +try: + from _thread import RLock +except ImportError: + from threading import RLock + +try: + from collections import OrderedDict as _OrderedDict +except ImportError: + try: + from ordereddict import OrderedDict as _OrderedDict + except ImportError: + _OrderedDict = None + +#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) + +__all__ = [ +'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', +'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', +'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', +'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', +'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', +'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', +'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', +'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', +'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', +'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', +'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', +'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', +'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', +'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', +'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', +'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', +'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', +'CloseMatch', 'tokenMap', 'pyparsing_common', +] + +system_version = tuple(sys.version_info)[:3] +PY_3 = system_version[0] == 3 +if PY_3: + _MAX_INT = sys.maxsize + basestring = str + unichr = chr + _ustr = str + + # build list of single arg builtins, that can be used as parse actions + singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] + +else: + _MAX_INT = sys.maxint + range = xrange + + def _ustr(obj): + """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries + str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It + then < returns the unicode object | encodes it with the default encoding | ... >. + """ + if isinstance(obj,unicode): + return obj + + try: + # If this works, then _ustr(obj) has the same behaviour as str(obj), so + # it won't break any existing code. + return str(obj) + + except UnicodeEncodeError: + # Else encode it + ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') + xmlcharref = Regex(r'&#\d+;') + xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) + return xmlcharref.transformString(ret) + + # build list of single arg builtins, tolerant of Python version, that can be used as parse actions + singleArgBuiltins = [] + import __builtin__ + for fname in "sum len sorted reversed list tuple set any all min max".split(): + try: + singleArgBuiltins.append(getattr(__builtin__,fname)) + except AttributeError: + continue + +_generatorType = type((y for y in range(1))) + +def _xml_escape(data): + """Escape &, <, >, ", ', etc. in a string of data.""" + + # ampersand must be replaced first + from_symbols = '&><"\'' + to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) + for from_,to_ in zip(from_symbols, to_symbols): + data = data.replace(from_, to_) + return data + +class _Constants(object): + pass + +alphas = string.ascii_uppercase + string.ascii_lowercase +nums = "0123456789" +hexnums = nums + "ABCDEFabcdef" +alphanums = alphas + nums +_bslash = chr(92) +printables = "".join(c for c in string.printable if c not in string.whitespace) + +class ParseBaseException(Exception): + """base exception class for all parsing runtime exceptions""" + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, pstr, loc=0, msg=None, elem=None ): + self.loc = loc + if msg is None: + self.msg = pstr + self.pstr = "" + else: + self.msg = msg + self.pstr = pstr + self.parserElement = elem + self.args = (pstr, loc, msg) + + @classmethod + def _from_exception(cls, pe): + """ + internal factory method to simplify creating one type of ParseException + from another - avoids having __init__ signature conflicts among subclasses + """ + return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) + + def __getattr__( self, aname ): + """supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + """ + if( aname == "lineno" ): + return lineno( self.loc, self.pstr ) + elif( aname in ("col", "column") ): + return col( self.loc, self.pstr ) + elif( aname == "line" ): + return line( self.loc, self.pstr ) + else: + raise AttributeError(aname) + + def __str__( self ): + return "%s (at char %d), (line:%d, col:%d)" % \ + ( self.msg, self.loc, self.lineno, self.column ) + def __repr__( self ): + return _ustr(self) + def markInputline( self, markerString = ">!<" ): + """Extracts the exception line from the input string, and marks + the location of the exception with a special symbol. + """ + line_str = self.line + line_column = self.column - 1 + if markerString: + line_str = "".join((line_str[:line_column], + markerString, line_str[line_column:])) + return line_str.strip() + def __dir__(self): + return "lineno col line".split() + dir(type(self)) + +class ParseException(ParseBaseException): + """ + Exception thrown when parse expressions don't match class; + supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + + Example:: + try: + Word(nums).setName("integer").parseString("ABC") + except ParseException as pe: + print(pe) + print("column: {}".format(pe.col)) + + prints:: + Expected integer (at char 0), (line:1, col:1) + column: 1 + """ + pass + +class ParseFatalException(ParseBaseException): + """user-throwable exception thrown when inconsistent parse content + is found; stops all parsing immediately""" + pass + +class ParseSyntaxException(ParseFatalException): + """just like L{ParseFatalException}, but thrown internally when an + L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop + immediately because an unbacktrackable syntax error has been found""" + pass + +#~ class ReparseException(ParseBaseException): + #~ """Experimental class - parse actions can raise this exception to cause + #~ pyparsing to reparse the input string: + #~ - with a modified input string, and/or + #~ - with a modified start location + #~ Set the values of the ReparseException in the constructor, and raise the + #~ exception in a parse action to cause pyparsing to use the new string/location. + #~ Setting the values as None causes no change to be made. + #~ """ + #~ def __init_( self, newstring, restartLoc ): + #~ self.newParseText = newstring + #~ self.reparseLoc = restartLoc + +class RecursiveGrammarException(Exception): + """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" + def __init__( self, parseElementList ): + self.parseElementTrace = parseElementList + + def __str__( self ): + return "RecursiveGrammarException: %s" % self.parseElementTrace + +class _ParseResultsWithOffset(object): + def __init__(self,p1,p2): + self.tup = (p1,p2) + def __getitem__(self,i): + return self.tup[i] + def __repr__(self): + return repr(self.tup[0]) + def setOffset(self,i): + self.tup = (self.tup[0],i) + +class ParseResults(object): + """ + Structured parse results, to provide multiple means of access to the parsed data: + - as a list (C{len(results)}) + - by list index (C{results[0], results[1]}, etc.) + - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName}) + + Example:: + integer = Word(nums) + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + # equivalent form: + # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + # parseString returns a ParseResults object + result = date_str.parseString("1999/12/31") + + def test(s, fn=repr): + print("%s -> %s" % (s, fn(eval(s)))) + test("list(result)") + test("result[0]") + test("result['month']") + test("result.day") + test("'month' in result") + test("'minutes' in result") + test("result.dump()", str) + prints:: + list(result) -> ['1999', '/', '12', '/', '31'] + result[0] -> '1999' + result['month'] -> '12' + result.day -> '31' + 'month' in result -> True + 'minutes' in result -> False + result.dump() -> ['1999', '/', '12', '/', '31'] + - day: 31 + - month: 12 + - year: 1999 + """ + def __new__(cls, toklist=None, name=None, asList=True, modal=True ): + if isinstance(toklist, cls): + return toklist + retobj = object.__new__(cls) + retobj.__doinit = True + return retobj + + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): + if self.__doinit: + self.__doinit = False + self.__name = None + self.__parent = None + self.__accumNames = {} + self.__asList = asList + self.__modal = modal + if toklist is None: + toklist = [] + if isinstance(toklist, list): + self.__toklist = toklist[:] + elif isinstance(toklist, _generatorType): + self.__toklist = list(toklist) + else: + self.__toklist = [toklist] + self.__tokdict = dict() + + if name is not None and name: + if not modal: + self.__accumNames[name] = 0 + if isinstance(name,int): + name = _ustr(name) # will always return a str, but use _ustr for consistency + self.__name = name + if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): + if isinstance(toklist,basestring): + toklist = [ toklist ] + if asList: + if isinstance(toklist,ParseResults): + self[name] = _ParseResultsWithOffset(toklist.copy(),0) + else: + self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) + self[name].__name = name + else: + try: + self[name] = toklist[0] + except (KeyError,TypeError,IndexError): + self[name] = toklist + + def __getitem__( self, i ): + if isinstance( i, (int,slice) ): + return self.__toklist[i] + else: + if i not in self.__accumNames: + return self.__tokdict[i][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[i] ]) + + def __setitem__( self, k, v, isinstance=isinstance ): + if isinstance(v,_ParseResultsWithOffset): + self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] + sub = v[0] + elif isinstance(k,(int,slice)): + self.__toklist[k] = v + sub = v + else: + self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] + sub = v + if isinstance(sub,ParseResults): + sub.__parent = wkref(self) + + def __delitem__( self, i ): + if isinstance(i,(int,slice)): + mylen = len( self.__toklist ) + del self.__toklist[i] + + # convert int to slice + if isinstance(i, int): + if i < 0: + i += mylen + i = slice(i, i+1) + # get removed indices + removed = list(range(*i.indices(mylen))) + removed.reverse() + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for j in removed: + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) + else: + del self.__tokdict[i] + + def __contains__( self, k ): + return k in self.__tokdict + + def __len__( self ): return len( self.__toklist ) + def __bool__(self): return ( not not self.__toklist ) + __nonzero__ = __bool__ + def __iter__( self ): return iter( self.__toklist ) + def __reversed__( self ): return iter( self.__toklist[::-1] ) + def _iterkeys( self ): + if hasattr(self.__tokdict, "iterkeys"): + return self.__tokdict.iterkeys() + else: + return iter(self.__tokdict) + + def _itervalues( self ): + return (self[k] for k in self._iterkeys()) + + def _iteritems( self ): + return ((k, self[k]) for k in self._iterkeys()) + + if PY_3: + keys = _iterkeys + """Returns an iterator of all named result keys (Python 3.x only).""" + + values = _itervalues + """Returns an iterator of all named result values (Python 3.x only).""" + + items = _iteritems + """Returns an iterator of all named result key-value tuples (Python 3.x only).""" + + else: + iterkeys = _iterkeys + """Returns an iterator of all named result keys (Python 2.x only).""" + + itervalues = _itervalues + """Returns an iterator of all named result values (Python 2.x only).""" + + iteritems = _iteritems + """Returns an iterator of all named result key-value tuples (Python 2.x only).""" + + def keys( self ): + """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iterkeys()) + + def values( self ): + """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.itervalues()) + + def items( self ): + """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iteritems()) + + def haskeys( self ): + """Since keys() returns an iterator, this method is helpful in bypassing + code that looks for the existence of any defined results names.""" + return bool(self.__tokdict) + + def pop( self, *args, **kwargs): + """ + Removes and returns item at specified index (default=C{last}). + Supports both C{list} and C{dict} semantics for C{pop()}. If passed no + argument or an integer argument, it will use C{list} semantics + and pop tokens from the list of parsed tokens. If passed a + non-integer argument (most likely a string), it will use C{dict} + semantics and pop the corresponding value from any defined + results names. A second default return value argument is + supported, just as in C{dict.pop()}. + + Example:: + def remove_first(tokens): + tokens.pop(0) + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] + + label = Word(alphas) + patt = label("LABEL") + OneOrMore(Word(nums)) + print(patt.parseString("AAB 123 321").dump()) + + # Use pop() in a parse action to remove named result (note that corresponding value is not + # removed from list form of results) + def remove_LABEL(tokens): + tokens.pop("LABEL") + return tokens + patt.addParseAction(remove_LABEL) + print(patt.parseString("AAB 123 321").dump()) + prints:: + ['AAB', '123', '321'] + - LABEL: AAB + + ['AAB', '123', '321'] + """ + if not args: + args = [-1] + for k,v in kwargs.items(): + if k == 'default': + args = (args[0], v) + else: + raise TypeError("pop() got an unexpected keyword argument '%s'" % k) + if (isinstance(args[0], int) or + len(args) == 1 or + args[0] in self): + index = args[0] + ret = self[index] + del self[index] + return ret + else: + defaultvalue = args[1] + return defaultvalue + + def get(self, key, defaultValue=None): + """ + Returns named result matching the given key, or if there is no + such name, then returns the given C{defaultValue} or C{None} if no + C{defaultValue} is specified. + + Similar to C{dict.get()}. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString("1999/12/31") + print(result.get("year")) # -> '1999' + print(result.get("hour", "not specified")) # -> 'not specified' + print(result.get("hour")) # -> None + """ + if key in self: + return self[key] + else: + return defaultValue + + def insert( self, index, insStr ): + """ + Inserts new element at location index in the list of parsed tokens. + + Similar to C{list.insert()}. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to insert the parse location in the front of the parsed results + def insert_locn(locn, tokens): + tokens.insert(0, locn) + print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] + """ + self.__toklist.insert(index, insStr) + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) + + def append( self, item ): + """ + Add single element to end of ParseResults list of elements. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to compute the sum of the parsed integers, and add it to the end + def append_sum(tokens): + tokens.append(sum(map(int, tokens))) + print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] + """ + self.__toklist.append(item) + + def extend( self, itemseq ): + """ + Add sequence of elements to end of ParseResults list of elements. + + Example:: + patt = OneOrMore(Word(alphas)) + + # use a parse action to append the reverse of the matched strings, to make a palindrome + def make_palindrome(tokens): + tokens.extend(reversed([t[::-1] for t in tokens])) + return ''.join(tokens) + print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' + """ + if isinstance(itemseq, ParseResults): + self += itemseq + else: + self.__toklist.extend(itemseq) + + def clear( self ): + """ + Clear all elements and results names. + """ + del self.__toklist[:] + self.__tokdict.clear() + + def __getattr__( self, name ): + try: + return self[name] + except KeyError: + return "" + + if name in self.__tokdict: + if name not in self.__accumNames: + return self.__tokdict[name][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[name] ]) + else: + return "" + + def __add__( self, other ): + ret = self.copy() + ret += other + return ret + + def __iadd__( self, other ): + if other.__tokdict: + offset = len(self.__toklist) + addoffset = lambda a: offset if a<0 else a+offset + otheritems = other.__tokdict.items() + otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) + for (k,vlist) in otheritems for v in vlist] + for k,v in otherdictitems: + self[k] = v + if isinstance(v[0],ParseResults): + v[0].__parent = wkref(self) + + self.__toklist += other.__toklist + self.__accumNames.update( other.__accumNames ) + return self + + def __radd__(self, other): + if isinstance(other,int) and other == 0: + # useful for merging many ParseResults using sum() builtin + return self.copy() + else: + # this may raise a TypeError - so be it + return other + self + + def __repr__( self ): + return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) + + def __str__( self ): + return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' + + def _asStringList( self, sep='' ): + out = [] + for item in self.__toklist: + if out and sep: + out.append(sep) + if isinstance( item, ParseResults ): + out += item._asStringList() + else: + out.append( _ustr(item) ) + return out + + def asList( self ): + """ + Returns the parse results as a nested list of matching tokens, all converted to strings. + + Example:: + patt = OneOrMore(Word(alphas)) + result = patt.parseString("sldkj lsdkj sldkj") + # even though the result prints in string-like form, it is actually a pyparsing ParseResults + print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] + + # Use asList() to create an actual list + result_list = result.asList() + print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] + """ + return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] + + def asDict( self ): + """ + Returns the named parse results as a nested dictionary. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) + + result_dict = result.asDict() + print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} + + # even though a ParseResults supports dict-like access, sometime you just need to have a dict + import json + print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable + print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} + """ + if PY_3: + item_fn = self.items + else: + item_fn = self.iteritems + + def toItem(obj): + if isinstance(obj, ParseResults): + if obj.haskeys(): + return obj.asDict() + else: + return [toItem(v) for v in obj] + else: + return obj + + return dict((k,toItem(v)) for k,v in item_fn()) + + def copy( self ): + """ + Returns a new copy of a C{ParseResults} object. + """ + ret = ParseResults( self.__toklist ) + ret.__tokdict = self.__tokdict.copy() + ret.__parent = self.__parent + ret.__accumNames.update( self.__accumNames ) + ret.__name = self.__name + return ret + + def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): + """ + (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. + """ + nl = "\n" + out = [] + namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() + for v in vlist) + nextLevelIndent = indent + " " + + # collapse out indents if formatting is not desired + if not formatted: + indent = "" + nextLevelIndent = "" + nl = "" + + selfTag = None + if doctag is not None: + selfTag = doctag + else: + if self.__name: + selfTag = self.__name + + if not selfTag: + if namedItemsOnly: + return "" + else: + selfTag = "ITEM" + + out += [ nl, indent, "<", selfTag, ">" ] + + for i,res in enumerate(self.__toklist): + if isinstance(res,ParseResults): + if i in namedItems: + out += [ res.asXML(namedItems[i], + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + out += [ res.asXML(None, + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + # individual token, see if there is a name for it + resTag = None + if i in namedItems: + resTag = namedItems[i] + if not resTag: + if namedItemsOnly: + continue + else: + resTag = "ITEM" + xmlBodyText = _xml_escape(_ustr(res)) + out += [ nl, nextLevelIndent, "<", resTag, ">", + xmlBodyText, + "</", resTag, ">" ] + + out += [ nl, indent, "</", selfTag, ">" ] + return "".join(out) + + def __lookup(self,sub): + for k,vlist in self.__tokdict.items(): + for v,loc in vlist: + if sub is v: + return k + return None + + def getName(self): + r""" + Returns the results name for this token expression. Useful when several + different expressions might match at a particular location. + + Example:: + integer = Word(nums) + ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") + house_number_expr = Suppress('#') + Word(nums, alphanums) + user_data = (Group(house_number_expr)("house_number") + | Group(ssn_expr)("ssn") + | Group(integer)("age")) + user_info = OneOrMore(user_data) + + result = user_info.parseString("22 111-22-3333 #221B") + for item in result: + print(item.getName(), ':', item[0]) + prints:: + age : 22 + ssn : 111-22-3333 + house_number : 221B + """ + if self.__name: + return self.__name + elif self.__parent: + par = self.__parent() + if par: + return par.__lookup(self) + else: + return None + elif (len(self) == 1 and + len(self.__tokdict) == 1 and + next(iter(self.__tokdict.values()))[0][1] in (0,-1)): + return next(iter(self.__tokdict.keys())) + else: + return None + + def dump(self, indent='', depth=0, full=True): + """ + Diagnostic method for listing out the contents of a C{ParseResults}. + Accepts an optional C{indent} argument so that this string can be embedded + in a nested display of other data. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(result.dump()) + prints:: + ['12', '/', '31', '/', '1999'] + - day: 1999 + - month: 31 + - year: 12 + """ + out = [] + NL = '\n' + out.append( indent+_ustr(self.asList()) ) + if full: + if self.haskeys(): + items = sorted((str(k), v) for k,v in self.items()) + for k,v in items: + if out: + out.append(NL) + out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) + if isinstance(v,ParseResults): + if v: + out.append( v.dump(indent,depth+1) ) + else: + out.append(_ustr(v)) + else: + out.append(repr(v)) + elif any(isinstance(vv,ParseResults) for vv in self): + v = self + for i,vv in enumerate(v): + if isinstance(vv,ParseResults): + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) + else: + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) + + return "".join(out) + + def pprint(self, *args, **kwargs): + """ + Pretty-printer for parsed results as a list, using the C{pprint} module. + Accepts additional positional or keyword args as defined for the + C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) + + Example:: + ident = Word(alphas, alphanums) + num = Word(nums) + func = Forward() + term = ident | num | Group('(' + func + ')') + func <<= ident + Group(Optional(delimitedList(term))) + result = func.parseString("fna a,b,(fnb c,d,200),100") + result.pprint(width=40) + prints:: + ['fna', + ['a', + 'b', + ['(', 'fnb', ['c', 'd', '200'], ')'], + '100']] + """ + pprint.pprint(self.asList(), *args, **kwargs) + + # add support for pickle protocol + def __getstate__(self): + return ( self.__toklist, + ( self.__tokdict.copy(), + self.__parent is not None and self.__parent() or None, + self.__accumNames, + self.__name ) ) + + def __setstate__(self,state): + self.__toklist = state[0] + (self.__tokdict, + par, + inAccumNames, + self.__name) = state[1] + self.__accumNames = {} + self.__accumNames.update(inAccumNames) + if par is not None: + self.__parent = wkref(par) + else: + self.__parent = None + + def __getnewargs__(self): + return self.__toklist, self.__name, self.__asList, self.__modal + + def __dir__(self): + return (dir(type(self)) + list(self.keys())) + +collections.MutableMapping.register(ParseResults) + +def col (loc,strg): + """Returns current column within a string, counting newlines as line separators. + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + s = strg + return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) + +def lineno(loc,strg): + """Returns current line number within a string, counting newlines as line separators. + The first line is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + return strg.count("\n",0,loc) + 1 + +def line( loc, strg ): + """Returns the line of text containing loc within a string, counting newlines as line separators. + """ + lastCR = strg.rfind("\n", 0, loc) + nextCR = strg.find("\n", loc) + if nextCR >= 0: + return strg[lastCR+1:nextCR] + else: + return strg[lastCR+1:] + +def _defaultStartDebugAction( instring, loc, expr ): + print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) + +def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): + print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) + +def _defaultExceptionDebugAction( instring, loc, expr, exc ): + print ("Exception raised:" + _ustr(exc)) + +def nullDebugAction(*args): + """'Do-nothing' debug action, to suppress debugging output during parsing.""" + pass + +# Only works on Python 3.x - nonlocal is toxic to Python 2 installs +#~ 'decorator to trim function calls to match the arity of the target' +#~ def _trim_arity(func, maxargs=3): + #~ if func in singleArgBuiltins: + #~ return lambda s,l,t: func(t) + #~ limit = 0 + #~ foundArity = False + #~ def wrapper(*args): + #~ nonlocal limit,foundArity + #~ while 1: + #~ try: + #~ ret = func(*args[limit:]) + #~ foundArity = True + #~ return ret + #~ except TypeError: + #~ if limit == maxargs or foundArity: + #~ raise + #~ limit += 1 + #~ continue + #~ return wrapper + +# this version is Python 2.x-3.x cross-compatible +'decorator to trim function calls to match the arity of the target' +def _trim_arity(func, maxargs=2): + if func in singleArgBuiltins: + return lambda s,l,t: func(t) + limit = [0] + foundArity = [False] + + # traceback return data structure changed in Py3.5 - normalize back to plain tuples + if system_version[:2] >= (3,5): + def extract_stack(limit=0): + # special handling for Python 3.5.0 - extra deep call stack by 1 + offset = -3 if system_version == (3,5,0) else -2 + frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] + return [(frame_summary.filename, frame_summary.lineno)] + def extract_tb(tb, limit=0): + frames = traceback.extract_tb(tb, limit=limit) + frame_summary = frames[-1] + return [(frame_summary.filename, frame_summary.lineno)] + else: + extract_stack = traceback.extract_stack + extract_tb = traceback.extract_tb + + # synthesize what would be returned by traceback.extract_stack at the call to + # user's parse action 'func', so that we don't incur call penalty at parse time + + LINE_DIFF = 6 + # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND + # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! + this_line = extract_stack(limit=2)[-1] + pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) + + def wrapper(*args): + while 1: + try: + ret = func(*args[limit[0]:]) + foundArity[0] = True + return ret + except TypeError: + # re-raise TypeErrors if they did not come from our arity testing + if foundArity[0]: + raise + else: + try: + tb = sys.exc_info()[-1] + if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth: + raise + finally: + del tb + + if limit[0] <= maxargs: + limit[0] += 1 + continue + raise + + # copy func name to wrapper for sensible debug output + func_name = "<parse action>" + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + wrapper.__name__ = func_name + + return wrapper + +class ParserElement(object): + """Abstract base level parser element class.""" + DEFAULT_WHITE_CHARS = " \n\t\r" + verbose_stacktrace = False + + @staticmethod + def setDefaultWhitespaceChars( chars ): + r""" + Overrides the default whitespace chars + + Example:: + # default whitespace chars are space, <TAB> and newline + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] + + # change to just treat newline as significant + ParserElement.setDefaultWhitespaceChars(" \t") + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] + """ + ParserElement.DEFAULT_WHITE_CHARS = chars + + @staticmethod + def inlineLiteralsUsing(cls): + """ + Set class to be used for inclusion of string literals into a parser. + + Example:: + # default literal class used is Literal + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + + # change to Suppress + ParserElement.inlineLiteralsUsing(Suppress) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] + """ + ParserElement._literalStringClass = cls + + def __init__( self, savelist=False ): + self.parseAction = list() + self.failAction = None + #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall + self.strRepr = None + self.resultsName = None + self.saveAsList = savelist + self.skipWhitespace = True + self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + self.copyDefaultWhiteChars = True + self.mayReturnEmpty = False # used when checking for left-recursion + self.keepTabs = False + self.ignoreExprs = list() + self.debug = False + self.streamlined = False + self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index + self.errmsg = "" + self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) + self.debugActions = ( None, None, None ) #custom debug actions + self.re = None + self.callPreparse = True # used to avoid redundant calls to preParse + self.callDuringTry = False + + def copy( self ): + """ + Make a copy of this C{ParserElement}. Useful for defining different parse actions + for the same parsing pattern, using copies of the original parse element. + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") + integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + + print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) + prints:: + [5120, 100, 655360, 268435456] + Equivalent form of C{expr.copy()} is just C{expr()}:: + integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + """ + cpy = copy.copy( self ) + cpy.parseAction = self.parseAction[:] + cpy.ignoreExprs = self.ignoreExprs[:] + if self.copyDefaultWhiteChars: + cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + return cpy + + def setName( self, name ): + """ + Define name for this expression, makes debugging and exception messages clearer. + + Example:: + Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) + Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) + """ + self.name = name + self.errmsg = "Expected " + self.name + if hasattr(self,"exception"): + self.exception.msg = self.errmsg + return self + + def setResultsName( self, name, listAllMatches=False ): + """ + Define name for referencing matching tokens as a nested attribute + of the returned parse results. + NOTE: this returns a *copy* of the original C{ParserElement} object; + this is so that the client can define a basic element, such as an + integer, and reference it in multiple places with different names. + + You can also set results names using the abbreviated syntax, + C{expr("name")} in place of C{expr.setResultsName("name")} - + see L{I{__call__}<__call__>}. + + Example:: + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + + # equivalent form: + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + """ + newself = self.copy() + if name.endswith("*"): + name = name[:-1] + listAllMatches=True + newself.resultsName = name + newself.modalResults = not listAllMatches + return newself + + def setBreak(self,breakFlag = True): + """Method to invoke the Python pdb debugger when this element is + about to be parsed. Set C{breakFlag} to True to enable, False to + disable. + """ + if breakFlag: + _parseMethod = self._parse + def breaker(instring, loc, doActions=True, callPreParse=True): + import pdb + pdb.set_trace() + return _parseMethod( instring, loc, doActions, callPreParse ) + breaker._originalParseMethod = _parseMethod + self._parse = breaker + else: + if hasattr(self._parse,"_originalParseMethod"): + self._parse = self._parse._originalParseMethod + return self + + def setParseAction( self, *fns, **kwargs ): + """ + Define one or more actions to perform when successfully matching parse element definition. + Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, + C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: + - s = the original string being parsed (see note below) + - loc = the location of the matching substring + - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object + If the functions in fns modify the tokens, they can return them as the return + value from fn, and the modified list of tokens will replace the original. + Otherwise, fn does not need to return any value. + + Optional keyword arguments: + - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{parseString}<parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + + Example:: + integer = Word(nums) + date_str = integer + '/' + integer + '/' + integer + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + # use parse action to convert to ints at parse time + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + date_str = integer + '/' + integer + '/' + integer + + # note that integer fields are now ints, not strings + date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] + """ + self.parseAction = list(map(_trim_arity, list(fns))) + self.callDuringTry = kwargs.get("callDuringTry", False) + return self + + def addParseAction( self, *fns, **kwargs ): + """ + Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}. + + See examples in L{I{copy}<copy>}. + """ + self.parseAction += list(map(_trim_arity, list(fns))) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def addCondition(self, *fns, **kwargs): + """Add a boolean predicate function to expression's list of parse actions. See + L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, + functions passed to C{addCondition} need to return boolean success/fail of the condition. + + Optional keyword arguments: + - message = define a custom message to be used in the raised exception + - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + year_int = integer.copy() + year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") + date_str = year_int + '/' + integer + '/' + integer + + result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) + """ + msg = kwargs.get("message", "failed user-defined condition") + exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException + for fn in fns: + def pa(s,l,t): + if not bool(_trim_arity(fn)(s,l,t)): + raise exc_type(s,l,msg) + self.parseAction.append(pa) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def setFailAction( self, fn ): + """Define action to perform if parsing fails at this expression. + Fail acton fn is a callable function that takes the arguments + C{fn(s,loc,expr,err)} where: + - s = string being parsed + - loc = location where expression match was attempted and failed + - expr = the parse expression that failed + - err = the exception thrown + The function returns no value. It may throw C{L{ParseFatalException}} + if it is desired to stop parsing immediately.""" + self.failAction = fn + return self + + def _skipIgnorables( self, instring, loc ): + exprsFound = True + while exprsFound: + exprsFound = False + for e in self.ignoreExprs: + try: + while 1: + loc,dummy = e._parse( instring, loc ) + exprsFound = True + except ParseException: + pass + return loc + + def preParse( self, instring, loc ): + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + + if self.skipWhitespace: + wt = self.whiteChars + instrlen = len(instring) + while loc < instrlen and instring[loc] in wt: + loc += 1 + + return loc + + def parseImpl( self, instring, loc, doActions=True ): + return loc, [] + + def postParse( self, instring, loc, tokenlist ): + return tokenlist + + #~ @profile + def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): + debugging = ( self.debug ) #and doActions ) + + if debugging or self.failAction: + #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) + if (self.debugActions[0] ): + self.debugActions[0]( instring, loc, self ) + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + try: + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + except ParseBaseException as err: + #~ print ("Exception raised:", err) + if self.debugActions[2]: + self.debugActions[2]( instring, tokensStart, self, err ) + if self.failAction: + self.failAction( instring, tokensStart, self, err ) + raise + else: + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + if self.mayIndexError or loc >= len(instring): + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + else: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + + tokens = self.postParse( instring, loc, tokens ) + + retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) + if self.parseAction and (doActions or self.callDuringTry): + if debugging: + try: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + except ParseBaseException as err: + #~ print "Exception raised in user parse action:", err + if (self.debugActions[2] ): + self.debugActions[2]( instring, tokensStart, self, err ) + raise + else: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + + if debugging: + #~ print ("Matched",self,"->",retTokens.asList()) + if (self.debugActions[1] ): + self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) + + return loc, retTokens + + def tryParse( self, instring, loc ): + try: + return self._parse( instring, loc, doActions=False )[0] + except ParseFatalException: + raise ParseException( instring, loc, self.errmsg, self) + + def canParseNext(self, instring, loc): + try: + self.tryParse(instring, loc) + except (ParseException, IndexError): + return False + else: + return True + + class _UnboundedCache(object): + def __init__(self): + cache = {} + self.not_in_cache = not_in_cache = object() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + if _OrderedDict is not None: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = _OrderedDict() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(cache) > size: + try: + cache.popitem(False) + except KeyError: + pass + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + else: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = {} + key_fifo = collections.deque([], size) + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(key_fifo) > size: + cache.pop(key_fifo.popleft(), None) + key_fifo.append(key) + + def clear(self): + cache.clear() + key_fifo.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + # argument cache for optimizing repeated calls when backtracking through recursive expressions + packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail + packrat_cache_lock = RLock() + packrat_cache_stats = [0, 0] + + # this method gets repeatedly called during backtracking with the same arguments - + # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression + def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): + HIT, MISS = 0, 1 + lookup = (self, instring, loc, callPreParse, doActions) + with ParserElement.packrat_cache_lock: + cache = ParserElement.packrat_cache + value = cache.get(lookup) + if value is cache.not_in_cache: + ParserElement.packrat_cache_stats[MISS] += 1 + try: + value = self._parseNoCache(instring, loc, doActions, callPreParse) + except ParseBaseException as pe: + # cache a copy of the exception, without the traceback + cache.set(lookup, pe.__class__(*pe.args)) + raise + else: + cache.set(lookup, (value[0], value[1].copy())) + return value + else: + ParserElement.packrat_cache_stats[HIT] += 1 + if isinstance(value, Exception): + raise value + return (value[0], value[1].copy()) + + _parse = _parseNoCache + + @staticmethod + def resetCache(): + ParserElement.packrat_cache.clear() + ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) + + _packratEnabled = False + @staticmethod + def enablePackrat(cache_size_limit=128): + """Enables "packrat" parsing, which adds memoizing to the parsing logic. + Repeated parse attempts at the same string location (which happens + often in many complex grammars) can immediately return a cached value, + instead of re-executing parsing/validating code. Memoizing is done of + both valid results and parsing exceptions. + + Parameters: + - cache_size_limit - (default=C{128}) - if an integer value is provided + will limit the size of the packrat cache; if None is passed, then + the cache size will be unbounded; if 0 is passed, the cache will + be effectively disabled. + + This speedup may break existing programs that use parse actions that + have side-effects. For this reason, packrat parsing is disabled when + you first import pyparsing. To activate the packrat feature, your + program must call the class method C{ParserElement.enablePackrat()}. If + your program uses C{psyco} to "compile as you go", you must call + C{enablePackrat} before calling C{psyco.full()}. If you do not do this, + Python will crash. For best results, call C{enablePackrat()} immediately + after importing pyparsing. + + Example:: + from pip._vendor import pyparsing + pyparsing.ParserElement.enablePackrat() + """ + if not ParserElement._packratEnabled: + ParserElement._packratEnabled = True + if cache_size_limit is None: + ParserElement.packrat_cache = ParserElement._UnboundedCache() + else: + ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) + ParserElement._parse = ParserElement._parseCache + + def parseString( self, instring, parseAll=False ): + """ + Execute the parse expression with the given string. + This is the main interface to the client code, once the complete + expression has been built. + + If you want the grammar to require that the entire input string be + successfully parsed, then set C{parseAll} to True (equivalent to ending + the grammar with C{L{StringEnd()}}). + + Note: C{parseString} implicitly calls C{expandtabs()} on the input string, + in order to report proper column numbers in parse actions. + If the input string contains tabs and + the grammar uses parse actions that use the C{loc} argument to index into the + string being parsed, you can ensure you have a consistent view of the input + string by: + - calling C{parseWithTabs} on your grammar before calling C{parseString} + (see L{I{parseWithTabs}<parseWithTabs>}) + - define your parse action using the full C{(s,loc,toks)} signature, and + reference the input string using the parse action's C{s} argument + - explictly expand the tabs in your input string before calling + C{parseString} + + Example:: + Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] + Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text + """ + ParserElement.resetCache() + if not self.streamlined: + self.streamline() + #~ self.saveAsList = True + for e in self.ignoreExprs: + e.streamline() + if not self.keepTabs: + instring = instring.expandtabs() + try: + loc, tokens = self._parse( instring, 0 ) + if parseAll: + loc = self.preParse( instring, loc ) + se = Empty() + StringEnd() + se._parse( instring, loc ) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + else: + return tokens + + def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): + """ + Scan the input string for expression matches. Each match will return the + matching tokens, start location, and end location. May be called with optional + C{maxMatches} argument, to clip scanning after 'n' matches are found. If + C{overlap} is specified, then overlapping matches will be reported. + + Note that the start and end locations are reported relative to the string + being parsed. See L{I{parseString}<parseString>} for more information on parsing + strings with embedded tabs. + + Example:: + source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" + print(source) + for tokens,start,end in Word(alphas).scanString(source): + print(' '*start + '^'*(end-start)) + print(' '*start + tokens[0]) + + prints:: + + sldjf123lsdjjkf345sldkjf879lkjsfd987 + ^^^^^ + sldjf + ^^^^^^^ + lsdjjkf + ^^^^^^ + sldkjf + ^^^^^^ + lkjsfd + """ + if not self.streamlined: + self.streamline() + for e in self.ignoreExprs: + e.streamline() + + if not self.keepTabs: + instring = _ustr(instring).expandtabs() + instrlen = len(instring) + loc = 0 + preparseFn = self.preParse + parseFn = self._parse + ParserElement.resetCache() + matches = 0 + try: + while loc <= instrlen and matches < maxMatches: + try: + preloc = preparseFn( instring, loc ) + nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) + except ParseException: + loc = preloc+1 + else: + if nextLoc > loc: + matches += 1 + yield tokens, preloc, nextLoc + if overlap: + nextloc = preparseFn( instring, loc ) + if nextloc > loc: + loc = nextLoc + else: + loc += 1 + else: + loc = nextLoc + else: + loc = preloc+1 + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def transformString( self, instring ): + """ + Extension to C{L{scanString}}, to modify matching text with modified tokens that may + be returned from a parse action. To use C{transformString}, define a grammar and + attach a parse action to it that modifies the returned token list. + Invoking C{transformString()} on a target string will then scan for matches, + and replace the matched text patterns according to the logic in the parse + action. C{transformString()} returns the resulting transformed string. + + Example:: + wd = Word(alphas) + wd.setParseAction(lambda toks: toks[0].title()) + + print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) + Prints:: + Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. + """ + out = [] + lastE = 0 + # force preservation of <TAB>s, to minimize unwanted transformation of string, and to + # keep string locs straight between transformString and scanString + self.keepTabs = True + try: + for t,s,e in self.scanString( instring ): + out.append( instring[lastE:s] ) + if t: + if isinstance(t,ParseResults): + out += t.asList() + elif isinstance(t,list): + out += t + else: + out.append(t) + lastE = e + out.append(instring[lastE:]) + out = [o for o in out if o] + return "".join(map(_ustr,_flatten(out))) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def searchString( self, instring, maxMatches=_MAX_INT ): + """ + Another extension to C{L{scanString}}, simplifying the access to the tokens found + to match the given parse expression. May be called with optional + C{maxMatches} argument, to clip searching after 'n' matches are found. + + Example:: + # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters + cap_word = Word(alphas.upper(), alphas.lower()) + + print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) + + # the sum() builtin can be used to merge results into a single ParseResults object + print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))) + prints:: + [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] + ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] + """ + try: + return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): + """ + Generator method to split a string using the given expression as a separator. + May be called with optional C{maxsplit} argument, to limit the number of splits; + and the optional C{includeSeparators} argument (default=C{False}), if the separating + matching text should be included in the split results. + + Example:: + punc = oneOf(list(".,;:/-!?")) + print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) + prints:: + ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] + """ + splits = 0 + last = 0 + for t,s,e in self.scanString(instring, maxMatches=maxsplit): + yield instring[last:s] + if includeSeparators: + yield t[0] + last = e + yield instring[last:] + + def __add__(self, other ): + """ + Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement + converts them to L{Literal}s by default. + + Example:: + greet = Word(alphas) + "," + Word(alphas) + "!" + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + Prints:: + Hello, World! -> ['Hello', ',', 'World', '!'] + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return And( [ self, other ] ) + + def __radd__(self, other ): + """ + Implementation of + operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other + self + + def __sub__(self, other): + """ + Implementation of - operator, returns C{L{And}} with error stop + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return self + And._ErrorStop() + other + + def __rsub__(self, other ): + """ + Implementation of - operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other - self + + def __mul__(self,other): + """ + Implementation of * operator, allows use of C{expr * 3} in place of + C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer + tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples + may also include C{None} as in: + - C{expr*(n,None)} or C{expr*(n,)} is equivalent + to C{expr*n + L{ZeroOrMore}(expr)} + (read as "at least n instances of C{expr}") + - C{expr*(None,n)} is equivalent to C{expr*(0,n)} + (read as "0 to n instances of C{expr}") + - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} + - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} + + Note that C{expr*(None,n)} does not raise an exception if + more than n exprs exist in the input stream; that is, + C{expr*(None,n)} does not enforce a maximum number of expr + occurrences. If this behavior is desired, then write + C{expr*(None,n) + ~expr} + """ + if isinstance(other,int): + minElements, optElements = other,0 + elif isinstance(other,tuple): + other = (other + (None, None))[:2] + if other[0] is None: + other = (0, other[1]) + if isinstance(other[0],int) and other[1] is None: + if other[0] == 0: + return ZeroOrMore(self) + if other[0] == 1: + return OneOrMore(self) + else: + return self*other[0] + ZeroOrMore(self) + elif isinstance(other[0],int) and isinstance(other[1],int): + minElements, optElements = other + optElements -= minElements + else: + raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) + else: + raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) + + if minElements < 0: + raise ValueError("cannot multiply ParserElement by negative value") + if optElements < 0: + raise ValueError("second tuple value must be greater or equal to first tuple value") + if minElements == optElements == 0: + raise ValueError("cannot multiply ParserElement by 0 or (0,0)") + + if (optElements): + def makeOptionalList(n): + if n>1: + return Optional(self + makeOptionalList(n-1)) + else: + return Optional(self) + if minElements: + if minElements == 1: + ret = self + makeOptionalList(optElements) + else: + ret = And([self]*minElements) + makeOptionalList(optElements) + else: + ret = makeOptionalList(optElements) + else: + if minElements == 1: + ret = self + else: + ret = And([self]*minElements) + return ret + + def __rmul__(self, other): + return self.__mul__(other) + + def __or__(self, other ): + """ + Implementation of | operator - returns C{L{MatchFirst}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return MatchFirst( [ self, other ] ) + + def __ror__(self, other ): + """ + Implementation of | operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other | self + + def __xor__(self, other ): + """ + Implementation of ^ operator - returns C{L{Or}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Or( [ self, other ] ) + + def __rxor__(self, other ): + """ + Implementation of ^ operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other ^ self + + def __and__(self, other ): + """ + Implementation of & operator - returns C{L{Each}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Each( [ self, other ] ) + + def __rand__(self, other ): + """ + Implementation of & operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other & self + + def __invert__( self ): + """ + Implementation of ~ operator - returns C{L{NotAny}} + """ + return NotAny( self ) + + def __call__(self, name=None): + """ + Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. + + If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be + passed as C{True}. + + If C{name} is omitted, same as calling C{L{copy}}. + + Example:: + # these are equivalent + userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") + userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") + """ + if name is not None: + return self.setResultsName(name) + else: + return self.copy() + + def suppress( self ): + """ + Suppresses the output of this C{ParserElement}; useful to keep punctuation from + cluttering up returned output. + """ + return Suppress( self ) + + def leaveWhitespace( self ): + """ + Disables the skipping of whitespace before matching the characters in the + C{ParserElement}'s defined pattern. This is normally only used internally by + the pyparsing module, but may be needed in some whitespace-sensitive grammars. + """ + self.skipWhitespace = False + return self + + def setWhitespaceChars( self, chars ): + """ + Overrides the default whitespace chars + """ + self.skipWhitespace = True + self.whiteChars = chars + self.copyDefaultWhiteChars = False + return self + + def parseWithTabs( self ): + """ + Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string. + Must be called before C{parseString} when the input grammar contains elements that + match C{<TAB>} characters. + """ + self.keepTabs = True + return self + + def ignore( self, other ): + """ + Define expression to be ignored (e.g., comments) while doing pattern + matching; may be called repeatedly, to define multiple comment or other + ignorable patterns. + + Example:: + patt = OneOrMore(Word(alphas)) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] + + patt.ignore(cStyleComment) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] + """ + if isinstance(other, basestring): + other = Suppress(other) + + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + self.ignoreExprs.append(other) + else: + self.ignoreExprs.append( Suppress( other.copy() ) ) + return self + + def setDebugActions( self, startAction, successAction, exceptionAction ): + """ + Enable display of debugging messages while doing pattern matching. + """ + self.debugActions = (startAction or _defaultStartDebugAction, + successAction or _defaultSuccessDebugAction, + exceptionAction or _defaultExceptionDebugAction) + self.debug = True + return self + + def setDebug( self, flag=True ): + """ + Enable display of debugging messages while doing pattern matching. + Set C{flag} to True to enable, False to disable. + + Example:: + wd = Word(alphas).setName("alphaword") + integer = Word(nums).setName("numword") + term = wd | integer + + # turn on debugging for wd + wd.setDebug() + + OneOrMore(term).parseString("abc 123 xyz 890") + + prints:: + Match alphaword at loc 0(1,1) + Matched alphaword -> ['abc'] + Match alphaword at loc 3(1,4) + Exception raised:Expected alphaword (at char 4), (line:1, col:5) + Match alphaword at loc 7(1,8) + Matched alphaword -> ['xyz'] + Match alphaword at loc 11(1,12) + Exception raised:Expected alphaword (at char 12), (line:1, col:13) + Match alphaword at loc 15(1,16) + Exception raised:Expected alphaword (at char 15), (line:1, col:16) + + The output shown is that produced by the default debug actions - custom debug actions can be + specified using L{setDebugActions}. Prior to attempting + to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"} + is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"} + message is shown. Also note the use of L{setName} to assign a human-readable name to the expression, + which makes debugging and exception messages easier to understand - for instance, the default + name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. + """ + if flag: + self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) + else: + self.debug = False + return self + + def __str__( self ): + return self.name + + def __repr__( self ): + return _ustr(self) + + def streamline( self ): + self.streamlined = True + self.strRepr = None + return self + + def checkRecursion( self, parseElementList ): + pass + + def validate( self, validateTrace=[] ): + """ + Check defined expressions for valid structure, check for infinite recursive definitions. + """ + self.checkRecursion( [] ) + + def parseFile( self, file_or_filename, parseAll=False ): + """ + Execute the parse expression on the given file or filename. + If a filename is specified (instead of a file object), + the entire file is opened, read, and closed before parsing. + """ + try: + file_contents = file_or_filename.read() + except AttributeError: + with open(file_or_filename, "r") as f: + file_contents = f.read() + try: + return self.parseString(file_contents, parseAll) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def __eq__(self,other): + if isinstance(other, ParserElement): + return self is other or vars(self) == vars(other) + elif isinstance(other, basestring): + return self.matches(other) + else: + return super(ParserElement,self)==other + + def __ne__(self,other): + return not (self == other) + + def __hash__(self): + return hash(id(self)) + + def __req__(self,other): + return self == other + + def __rne__(self,other): + return not (self == other) + + def matches(self, testString, parseAll=True): + """ + Method for quick testing of a parser against a test string. Good for simple + inline microtests of sub expressions while building up larger parser. + + Parameters: + - testString - to test against this expression for a match + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + + Example:: + expr = Word(nums) + assert expr.matches("100") + """ + try: + self.parseString(_ustr(testString), parseAll=parseAll) + return True + except ParseBaseException: + return False + + def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): + """ + Execute the parse expression on a series of test strings, showing each + test, the parsed results or where the parse failed. Quick and easy way to + run a parse expression against a list of sample strings. + + Parameters: + - tests - a list of separate test strings, or a multiline string of test strings + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + - comment - (default=C{'#'}) - expression for indicating embedded comments in the test + string; pass None to disable comment filtering + - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; + if False, only dump nested list + - printResults - (default=C{True}) prints test output to stdout + - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing + + Returns: a (success, results) tuple, where success indicates that all tests succeeded + (or failed if C{failureTests} is True), and the results contain a list of lines of each + test's output + + Example:: + number_expr = pyparsing_common.number.copy() + + result = number_expr.runTests(''' + # unsigned integer + 100 + # negative integer + -100 + # float with scientific notation + 6.02e23 + # integer with scientific notation + 1e-12 + ''') + print("Success" if result[0] else "Failed!") + + result = number_expr.runTests(''' + # stray character + 100Z + # missing leading digit before '.' + -.100 + # too many '.' + 3.14.159 + ''', failureTests=True) + print("Success" if result[0] else "Failed!") + prints:: + # unsigned integer + 100 + [100] + + # negative integer + -100 + [-100] + + # float with scientific notation + 6.02e23 + [6.02e+23] + + # integer with scientific notation + 1e-12 + [1e-12] + + Success + + # stray character + 100Z + ^ + FAIL: Expected end of text (at char 3), (line:1, col:4) + + # missing leading digit before '.' + -.100 + ^ + FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) + + # too many '.' + 3.14.159 + ^ + FAIL: Expected end of text (at char 4), (line:1, col:5) + + Success + + Each test string must be on a single line. If you want to test a string that spans multiple + lines, create a test like this:: + + expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") + + (Note that this is a raw string literal, you must include the leading 'r'.) + """ + if isinstance(tests, basestring): + tests = list(map(str.strip, tests.rstrip().splitlines())) + if isinstance(comment, basestring): + comment = Literal(comment) + allResults = [] + comments = [] + success = True + for t in tests: + if comment is not None and comment.matches(t, False) or comments and not t: + comments.append(t) + continue + if not t: + continue + out = ['\n'.join(comments), t] + comments = [] + try: + t = t.replace(r'\n','\n') + result = self.parseString(t, parseAll=parseAll) + out.append(result.dump(full=fullDump)) + success = success and not failureTests + except ParseBaseException as pe: + fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" + if '\n' in t: + out.append(line(pe.loc, t)) + out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) + else: + out.append(' '*pe.loc + '^' + fatal) + out.append("FAIL: " + str(pe)) + success = success and failureTests + result = pe + except Exception as exc: + out.append("FAIL-EXCEPTION: " + str(exc)) + success = success and failureTests + result = exc + + if printResults: + if fullDump: + out.append('') + print('\n'.join(out)) + + allResults.append((t, result)) + + return success, allResults + + +class Token(ParserElement): + """ + Abstract C{ParserElement} subclass, for defining atomic matching patterns. + """ + def __init__( self ): + super(Token,self).__init__( savelist=False ) + + +class Empty(Token): + """ + An empty token, will always match. + """ + def __init__( self ): + super(Empty,self).__init__() + self.name = "Empty" + self.mayReturnEmpty = True + self.mayIndexError = False + + +class NoMatch(Token): + """ + A token that will never match. + """ + def __init__( self ): + super(NoMatch,self).__init__() + self.name = "NoMatch" + self.mayReturnEmpty = True + self.mayIndexError = False + self.errmsg = "Unmatchable token" + + def parseImpl( self, instring, loc, doActions=True ): + raise ParseException(instring, loc, self.errmsg, self) + + +class Literal(Token): + """ + Token to exactly match a specified string. + + Example:: + Literal('blah').parseString('blah') # -> ['blah'] + Literal('blah').parseString('blahfooblah') # -> ['blah'] + Literal('blah').parseString('bla') # -> Exception: Expected "blah" + + For case-insensitive matching, use L{CaselessLiteral}. + + For keyword matching (force word break before and after the matched string), + use L{Keyword} or L{CaselessKeyword}. + """ + def __init__( self, matchString ): + super(Literal,self).__init__() + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Literal; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.__class__ = Empty + self.name = '"%s"' % _ustr(self.match) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + + # Performance tuning: this routine gets called a *lot* + # if this is a single character match string and the first character matches, + # short-circuit as quickly as possible, and avoid calling startswith + #~ @profile + def parseImpl( self, instring, loc, doActions=True ): + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) +_L = Literal +ParserElement._literalStringClass = Literal + +class Keyword(Token): + """ + Token to exactly match a specified string as a keyword, that is, it must be + immediately followed by a non-keyword character. Compare with C{L{Literal}}: + - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. + - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} + Accepts two optional constructor arguments in addition to the keyword string: + - C{identChars} is a string of characters that would be valid identifier characters, + defaulting to all alphanumerics + "_" and "$" + - C{caseless} allows case-insensitive matching, default is C{False}. + + Example:: + Keyword("start").parseString("start") # -> ['start'] + Keyword("start").parseString("starting") # -> Exception + + For case-insensitive matching, use L{CaselessKeyword}. + """ + DEFAULT_KEYWORD_CHARS = alphanums+"_$" + + def __init__( self, matchString, identChars=None, caseless=False ): + super(Keyword,self).__init__() + if identChars is None: + identChars = Keyword.DEFAULT_KEYWORD_CHARS + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Keyword; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.name = '"%s"' % self.match + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + self.caseless = caseless + if caseless: + self.caselessmatch = matchString.upper() + identChars = identChars.upper() + self.identChars = set(identChars) + + def parseImpl( self, instring, loc, doActions=True ): + if self.caseless: + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and + (loc == 0 or instring[loc-1].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + else: + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and + (loc == 0 or instring[loc-1] not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + + def copy(self): + c = super(Keyword,self).copy() + c.identChars = Keyword.DEFAULT_KEYWORD_CHARS + return c + + @staticmethod + def setDefaultKeywordChars( chars ): + """Overrides the default Keyword chars + """ + Keyword.DEFAULT_KEYWORD_CHARS = chars + +class CaselessLiteral(Literal): + """ + Token to match a specified string, ignoring case of letters. + Note: the matched results will always be in the case of the given + match string, NOT the case of the input text. + + Example:: + OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] + + (Contrast with example for L{CaselessKeyword}.) + """ + def __init__( self, matchString ): + super(CaselessLiteral,self).__init__( matchString.upper() ) + # Preserve the defining literal. + self.returnString = matchString + self.name = "'%s'" % self.returnString + self.errmsg = "Expected " + self.name + + def parseImpl( self, instring, loc, doActions=True ): + if instring[ loc:loc+self.matchLen ].upper() == self.match: + return loc+self.matchLen, self.returnString + raise ParseException(instring, loc, self.errmsg, self) + +class CaselessKeyword(Keyword): + """ + Caseless version of L{Keyword}. + + Example:: + OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] + + (Contrast with example for L{CaselessLiteral}.) + """ + def __init__( self, matchString, identChars=None ): + super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) + + def parseImpl( self, instring, loc, doActions=True ): + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + +class CloseMatch(Token): + """ + A variation on L{Literal} which matches "close" matches, that is, + strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: + - C{match_string} - string to be matched + - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match + + The results from a successful parse will contain the matched text from the input string and the following named results: + - C{mismatches} - a list of the positions within the match_string where mismatches were found + - C{original} - the original match_string used to compare against the input string + + If C{mismatches} is an empty list, then the match was an exact match. + + Example:: + patt = CloseMatch("ATCATCGAATGGA") + patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) + patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) + + # exact match + patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) + + # close match allowing up to 2 mismatches + patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) + patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) + """ + def __init__(self, match_string, maxMismatches=1): + super(CloseMatch,self).__init__() + self.name = match_string + self.match_string = match_string + self.maxMismatches = maxMismatches + self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) + self.mayIndexError = False + self.mayReturnEmpty = False + + def parseImpl( self, instring, loc, doActions=True ): + start = loc + instrlen = len(instring) + maxloc = start + len(self.match_string) + + if maxloc <= instrlen: + match_string = self.match_string + match_stringloc = 0 + mismatches = [] + maxMismatches = self.maxMismatches + + for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): + src,mat = s_m + if src != mat: + mismatches.append(match_stringloc) + if len(mismatches) > maxMismatches: + break + else: + loc = match_stringloc + 1 + results = ParseResults([instring[start:loc]]) + results['original'] = self.match_string + results['mismatches'] = mismatches + return loc, results + + raise ParseException(instring, loc, self.errmsg, self) + + +class Word(Token): + """ + Token for matching words composed of allowed character sets. + Defined with string containing all allowed initial characters, + an optional string containing allowed body characters (if omitted, + defaults to the initial character set), and an optional minimum, + maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. An optional + C{excludeChars} parameter can list characters that might be found in + the input C{bodyChars} string; useful to define a word of all printables + except for one or two characters, for instance. + + L{srange} is useful for defining custom character set strings for defining + C{Word} expressions, using range notation from regular expression character sets. + + A common mistake is to use C{Word} to match a specific literal string, as in + C{Word("Address")}. Remember that C{Word} uses the string argument to define + I{sets} of matchable characters. This expression would match "Add", "AAA", + "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. + To match an exact literal string, use L{Literal} or L{Keyword}. + + pyparsing includes helper strings for building Words: + - L{alphas} + - L{nums} + - L{alphanums} + - L{hexnums} + - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) + - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) + - L{printables} (any non-whitespace character) + + Example:: + # a word composed of digits + integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) + + # a word with a leading capital, and zero or more lowercase + capital_word = Word(alphas.upper(), alphas.lower()) + + # hostnames are alphanumeric, with leading alpha, and '-' + hostname = Word(alphas, alphanums+'-') + + # roman numeral (not a strict parser, accepts invalid mix of characters) + roman = Word("IVXLCDM") + + # any string of non-whitespace characters, except for ',' + csv_value = Word(printables, excludeChars=",") + """ + def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): + super(Word,self).__init__() + if excludeChars: + initChars = ''.join(c for c in initChars if c not in excludeChars) + if bodyChars: + bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) + self.initCharsOrig = initChars + self.initChars = set(initChars) + if bodyChars : + self.bodyCharsOrig = bodyChars + self.bodyChars = set(bodyChars) + else: + self.bodyCharsOrig = initChars + self.bodyChars = set(initChars) + + self.maxSpecified = max > 0 + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.asKeyword = asKeyword + + if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): + if self.bodyCharsOrig == self.initCharsOrig: + self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) + elif len(self.initCharsOrig) == 1: + self.reString = "%s[%s]*" % \ + (re.escape(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + else: + self.reString = "[%s][%s]*" % \ + (_escapeRegexRangeChars(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + if self.asKeyword: + self.reString = r"\b"+self.reString+r"\b" + try: + self.re = re.compile( self.reString ) + except Exception: + self.re = None + + def parseImpl( self, instring, loc, doActions=True ): + if self.re: + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + return loc, result.group() + + if not(instring[ loc ] in self.initChars): + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + instrlen = len(instring) + bodychars = self.bodyChars + maxloc = start + self.maxLen + maxloc = min( maxloc, instrlen ) + while loc < maxloc and instring[loc] in bodychars: + loc += 1 + + throwException = False + if loc - start < self.minLen: + throwException = True + if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: + throwException = True + if self.asKeyword: + if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars): + throwException = True + + if throwException: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(Word,self).__str__() + except Exception: + pass + + + if self.strRepr is None: + + def charsAsStr(s): + if len(s)>4: + return s[:4]+"..." + else: + return s + + if ( self.initCharsOrig != self.bodyCharsOrig ): + self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) + else: + self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) + + return self.strRepr + + +class Regex(Token): + r""" + Token for matching strings that match a given regular expression. + Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. + If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as + named parse results. + + Example:: + realnum = Regex(r"[+-]?\d+\.\d*") + date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)') + # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression + roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") + """ + compiledREtype = type(re.compile("[A-Z]")) + def __init__( self, pattern, flags=0): + """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" + super(Regex,self).__init__() + + if isinstance(pattern, basestring): + if not pattern: + warnings.warn("null string passed to Regex; use Empty() instead", + SyntaxWarning, stacklevel=2) + + self.pattern = pattern + self.flags = flags + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % pattern, + SyntaxWarning, stacklevel=2) + raise + + elif isinstance(pattern, Regex.compiledREtype): + self.re = pattern + self.pattern = \ + self.reString = str(pattern) + self.flags = flags + + else: + raise ValueError("Regex may only be constructed with a string or a compiled RE object") + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + d = result.groupdict() + ret = ParseResults(result.group()) + if d: + for k in d: + ret[k] = d[k] + return loc,ret + + def __str__( self ): + try: + return super(Regex,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "Re:(%s)" % repr(self.pattern) + + return self.strRepr + + +class QuotedString(Token): + r""" + Token for matching strings that are delimited by quoting characters. + + Defined with the following parameters: + - quoteChar - string of one or more characters defining the quote delimiting string + - escChar - character to escape quotes, typically backslash (default=C{None}) + - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) + - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) + - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) + - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) + - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) + + Example:: + qs = QuotedString('"') + print(qs.searchString('lsjdf "This is the quote" sldjf')) + complex_qs = QuotedString('{{', endQuoteChar='}}') + print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) + sql_qs = QuotedString('"', escQuote='""') + print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) + prints:: + [['This is the quote']] + [['This is the "quote"']] + [['This is the quote with "embedded" quotes']] + """ + def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): + super(QuotedString,self).__init__() + + # remove white space from quote chars - wont work anyway + quoteChar = quoteChar.strip() + if not quoteChar: + warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + if endQuoteChar is None: + endQuoteChar = quoteChar + else: + endQuoteChar = endQuoteChar.strip() + if not endQuoteChar: + warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + self.quoteChar = quoteChar + self.quoteCharLen = len(quoteChar) + self.firstQuoteChar = quoteChar[0] + self.endQuoteChar = endQuoteChar + self.endQuoteCharLen = len(endQuoteChar) + self.escChar = escChar + self.escQuote = escQuote + self.unquoteResults = unquoteResults + self.convertWhitespaceEscapes = convertWhitespaceEscapes + + if multiline: + self.flags = re.MULTILINE | re.DOTALL + self.pattern = r'%s(?:[^%s%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + else: + self.flags = 0 + self.pattern = r'%s(?:[^%s\n\r%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + if len(self.endQuoteChar) > 1: + self.pattern += ( + '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), + _escapeRegexRangeChars(self.endQuoteChar[i])) + for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' + ) + if escQuote: + self.pattern += (r'|(?:%s)' % re.escape(escQuote)) + if escChar: + self.pattern += (r'|(?:%s.)' % re.escape(escChar)) + self.escCharReplacePattern = re.escape(self.escChar)+"(.)" + self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, + SyntaxWarning, stacklevel=2) + raise + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + ret = result.group() + + if self.unquoteResults: + + # strip off quotes + ret = ret[self.quoteCharLen:-self.endQuoteCharLen] + + if isinstance(ret,basestring): + # replace escaped whitespace + if '\\' in ret and self.convertWhitespaceEscapes: + ws_map = { + r'\t' : '\t', + r'\n' : '\n', + r'\f' : '\f', + r'\r' : '\r', + } + for wslit,wschar in ws_map.items(): + ret = ret.replace(wslit, wschar) + + # replace escaped characters + if self.escChar: + ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) + + # replace escaped quotes + if self.escQuote: + ret = ret.replace(self.escQuote, self.endQuoteChar) + + return loc, ret + + def __str__( self ): + try: + return super(QuotedString,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) + + return self.strRepr + + +class CharsNotIn(Token): + """ + Token for matching words composed of characters I{not} in a given set (will + include whitespace in matched characters if not listed in the provided exclusion set - see example). + Defined with string containing all disallowed characters, and an optional + minimum, maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. + + Example:: + # define a comma-separated-value as anything that is not a ',' + csv_value = CharsNotIn(',') + print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) + prints:: + ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] + """ + def __init__( self, notChars, min=1, max=0, exact=0 ): + super(CharsNotIn,self).__init__() + self.skipWhitespace = False + self.notChars = notChars + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = ( self.minLen == 0 ) + self.mayIndexError = False + + def parseImpl( self, instring, loc, doActions=True ): + if instring[loc] in self.notChars: + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + notchars = self.notChars + maxlen = min( start+self.maxLen, len(instring) ) + while loc < maxlen and \ + (instring[loc] not in notchars): + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(CharsNotIn, self).__str__() + except Exception: + pass + + if self.strRepr is None: + if len(self.notChars) > 4: + self.strRepr = "!W:(%s...)" % self.notChars[:4] + else: + self.strRepr = "!W:(%s)" % self.notChars + + return self.strRepr + +class White(Token): + """ + Special matching class for matching whitespace. Normally, whitespace is ignored + by pyparsing grammars. This class is included when some whitespace structures + are significant. Define with a string containing the whitespace characters to be + matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, + as defined for the C{L{Word}} class. + """ + whiteStrs = { + " " : "<SPC>", + "\t": "<TAB>", + "\n": "<LF>", + "\r": "<CR>", + "\f": "<FF>", + } + def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): + super(White,self).__init__() + self.matchWhite = ws + self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) + #~ self.leaveWhitespace() + self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) + self.mayReturnEmpty = True + self.errmsg = "Expected " + self.name + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + def parseImpl( self, instring, loc, doActions=True ): + if not(instring[ loc ] in self.matchWhite): + raise ParseException(instring, loc, self.errmsg, self) + start = loc + loc += 1 + maxloc = start + self.maxLen + maxloc = min( maxloc, len(instring) ) + while loc < maxloc and instring[loc] in self.matchWhite: + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + +class _PositionToken(Token): + def __init__( self ): + super(_PositionToken,self).__init__() + self.name=self.__class__.__name__ + self.mayReturnEmpty = True + self.mayIndexError = False + +class GoToColumn(_PositionToken): + """ + Token to advance to a specific column of input text; useful for tabular report scraping. + """ + def __init__( self, colno ): + super(GoToColumn,self).__init__() + self.col = colno + + def preParse( self, instring, loc ): + if col(loc,instring) != self.col: + instrlen = len(instring) + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : + loc += 1 + return loc + + def parseImpl( self, instring, loc, doActions=True ): + thiscol = col( loc, instring ) + if thiscol > self.col: + raise ParseException( instring, loc, "Text not in expected column", self ) + newloc = loc + self.col - thiscol + ret = instring[ loc: newloc ] + return newloc, ret + + +class LineStart(_PositionToken): + """ + Matches if current position is at the beginning of a line within the parse string + + Example:: + + test = '''\ + AAA this line + AAA and this line + AAA but not this one + B AAA and definitely not this one + ''' + + for t in (LineStart() + 'AAA' + restOfLine).searchString(test): + print(t) + + Prints:: + ['AAA', ' this line'] + ['AAA', ' and this line'] + + """ + def __init__( self ): + super(LineStart,self).__init__() + self.errmsg = "Expected start of line" + + def parseImpl( self, instring, loc, doActions=True ): + if col(loc, instring) == 1: + return loc, [] + raise ParseException(instring, loc, self.errmsg, self) + +class LineEnd(_PositionToken): + """ + Matches if current position is at the end of a line within the parse string + """ + def __init__( self ): + super(LineEnd,self).__init__() + self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) + self.errmsg = "Expected end of line" + + def parseImpl( self, instring, loc, doActions=True ): + if loc<len(instring): + if instring[loc] == "\n": + return loc+1, "\n" + else: + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class StringStart(_PositionToken): + """ + Matches if current position is at the beginning of the parse string + """ + def __init__( self ): + super(StringStart,self).__init__() + self.errmsg = "Expected start of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc != 0: + # see if entire string up to here is just whitespace and ignoreables + if loc != self.preParse( instring, 0 ): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class StringEnd(_PositionToken): + """ + Matches if current position is at the end of the parse string + """ + def __init__( self ): + super(StringEnd,self).__init__() + self.errmsg = "Expected end of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc < len(instring): + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + elif loc > len(instring): + return loc, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class WordStart(_PositionToken): + """ + Matches if the current position is at the beginning of a Word, and + is not preceded by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of + the string being parsed, or at the beginning of a line. + """ + def __init__(self, wordChars = printables): + super(WordStart,self).__init__() + self.wordChars = set(wordChars) + self.errmsg = "Not at the start of a word" + + def parseImpl(self, instring, loc, doActions=True ): + if loc != 0: + if (instring[loc-1] in self.wordChars or + instring[loc] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class WordEnd(_PositionToken): + """ + Matches if the current position is at the end of a Word, and + is not followed by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of + the string being parsed, or at the end of a line. + """ + def __init__(self, wordChars = printables): + super(WordEnd,self).__init__() + self.wordChars = set(wordChars) + self.skipWhitespace = False + self.errmsg = "Not at the end of a word" + + def parseImpl(self, instring, loc, doActions=True ): + instrlen = len(instring) + if instrlen>0 and loc<instrlen: + if (instring[loc] in self.wordChars or + instring[loc-1] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + +class ParseExpression(ParserElement): + """ + Abstract subclass of ParserElement, for combining and post-processing parsed tokens. + """ + def __init__( self, exprs, savelist = False ): + super(ParseExpression,self).__init__(savelist) + if isinstance( exprs, _generatorType ): + exprs = list(exprs) + + if isinstance( exprs, basestring ): + self.exprs = [ ParserElement._literalStringClass( exprs ) ] + elif isinstance( exprs, collections.Iterable ): + exprs = list(exprs) + # if sequence of strings provided, wrap with Literal + if all(isinstance(expr, basestring) for expr in exprs): + exprs = map(ParserElement._literalStringClass, exprs) + self.exprs = list(exprs) + else: + try: + self.exprs = list( exprs ) + except TypeError: + self.exprs = [ exprs ] + self.callPreparse = False + + def __getitem__( self, i ): + return self.exprs[i] + + def append( self, other ): + self.exprs.append( other ) + self.strRepr = None + return self + + def leaveWhitespace( self ): + """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on + all contained expressions.""" + self.skipWhitespace = False + self.exprs = [ e.copy() for e in self.exprs ] + for e in self.exprs: + e.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + else: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + return self + + def __str__( self ): + try: + return super(ParseExpression,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) + return self.strRepr + + def streamline( self ): + super(ParseExpression,self).streamline() + + for e in self.exprs: + e.streamline() + + # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) + # but only if there are no parse actions or resultsNames on the nested And's + # (likewise for Or's and MatchFirst's) + if ( len(self.exprs) == 2 ): + other = self.exprs[0] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = other.exprs[:] + [ self.exprs[1] ] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + other = self.exprs[-1] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = self.exprs[:-1] + other.exprs[:] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + self.errmsg = "Expected " + _ustr(self) + + return self + + def setResultsName( self, name, listAllMatches=False ): + ret = super(ParseExpression,self).setResultsName(name,listAllMatches) + return ret + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + for e in self.exprs: + e.validate(tmp) + self.checkRecursion( [] ) + + def copy(self): + ret = super(ParseExpression,self).copy() + ret.exprs = [e.copy() for e in self.exprs] + return ret + +class And(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found in the given order. + Expressions may be separated by whitespace. + May be constructed using the C{'+'} operator. + May also be constructed using the C{'-'} operator, which will suppress backtracking. + + Example:: + integer = Word(nums) + name_expr = OneOrMore(Word(alphas)) + + expr = And([integer("id"),name_expr("name"),integer("age")]) + # more easily written as: + expr = integer("id") + name_expr("name") + integer("age") + """ + + class _ErrorStop(Empty): + def __init__(self, *args, **kwargs): + super(And._ErrorStop,self).__init__(*args, **kwargs) + self.name = '-' + self.leaveWhitespace() + + def __init__( self, exprs, savelist = True ): + super(And,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.setWhitespaceChars( self.exprs[0].whiteChars ) + self.skipWhitespace = self.exprs[0].skipWhitespace + self.callPreparse = True + + def parseImpl( self, instring, loc, doActions=True ): + # pass False as last arg to _parse for first element, since we already + # pre-parsed the string as part of our And pre-parsing + loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) + errorStop = False + for e in self.exprs[1:]: + if isinstance(e, And._ErrorStop): + errorStop = True + continue + if errorStop: + try: + loc, exprtokens = e._parse( instring, loc, doActions ) + except ParseSyntaxException: + raise + except ParseBaseException as pe: + pe.__traceback__ = None + raise ParseSyntaxException._from_exception(pe) + except IndexError: + raise ParseSyntaxException(instring, len(instring), self.errmsg, self) + else: + loc, exprtokens = e._parse( instring, loc, doActions ) + if exprtokens or exprtokens.haskeys(): + resultlist += exprtokens + return loc, resultlist + + def __iadd__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #And( [ self, other ] ) + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + if not e.mayReturnEmpty: + break + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + +class Or(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the expression that matches the longest string will be used. + May be constructed using the C{'^'} operator. + + Example:: + # construct Or using '^' operator + + number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) + prints:: + [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(Or,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + matches = [] + for e in self.exprs: + try: + loc2 = e.tryParse( instring, loc ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + else: + # save match among all matches, to retry longest to shortest + matches.append((loc2, e)) + + if matches: + matches.sort(key=lambda x: -x[0]) + for _,e in matches: + try: + return e._parse( instring, loc, doActions ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + + def __ixor__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #Or( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class MatchFirst(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the first one listed is the one that will match. + May be constructed using the C{'|'} operator. + + Example:: + # construct MatchFirst using '|' operator + + # watch the order of expressions to match + number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] + + # put more selective expression first + number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) + print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(MatchFirst,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + for e in self.exprs: + try: + ret = e._parse( instring, loc, doActions ) + return ret + except ParseException as err: + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + + # only got here if no expression matched, raise exception for match that made it the furthest + else: + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + def __ior__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #MatchFirst( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class Each(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found, but in any order. + Expressions may be separated by whitespace. + May be constructed using the C{'&'} operator. + + Example:: + color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") + shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") + integer = Word(nums) + shape_attr = "shape:" + shape_type("shape") + posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") + color_attr = "color:" + color("color") + size_attr = "size:" + integer("size") + + # use Each (using operator '&') to accept attributes in any order + # (shape and posn are required, color and size are optional) + shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) + + shape_spec.runTests(''' + shape: SQUARE color: BLACK posn: 100, 120 + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + color:GREEN size:20 shape:TRIANGLE posn:20,40 + ''' + ) + prints:: + shape: SQUARE color: BLACK posn: 100, 120 + ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] + - color: BLACK + - posn: ['100', ',', '120'] + - x: 100 + - y: 120 + - shape: SQUARE + + + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] + - color: BLUE + - posn: ['50', ',', '80'] + - x: 50 + - y: 80 + - shape: CIRCLE + - size: 50 + + + color: GREEN size: 20 shape: TRIANGLE posn: 20,40 + ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] + - color: GREEN + - posn: ['20', ',', '40'] + - x: 20 + - y: 40 + - shape: TRIANGLE + - size: 20 + """ + def __init__( self, exprs, savelist = True ): + super(Each,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.skipWhitespace = True + self.initExprGroups = True + + def parseImpl( self, instring, loc, doActions=True ): + if self.initExprGroups: + self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) + opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] + opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] + self.optionals = opt1 + opt2 + self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] + self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] + self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] + self.required += self.multirequired + self.initExprGroups = False + tmpLoc = loc + tmpReqd = self.required[:] + tmpOpt = self.optionals[:] + matchOrder = [] + + keepMatching = True + while keepMatching: + tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired + failed = [] + for e in tmpExprs: + try: + tmpLoc = e.tryParse( instring, tmpLoc ) + except ParseException: + failed.append(e) + else: + matchOrder.append(self.opt1map.get(id(e),e)) + if e in tmpReqd: + tmpReqd.remove(e) + elif e in tmpOpt: + tmpOpt.remove(e) + if len(failed) == len(tmpExprs): + keepMatching = False + + if tmpReqd: + missing = ", ".join(_ustr(e) for e in tmpReqd) + raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) + + # add any unmatched Optionals, in case they have default values defined + matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] + + resultlist = [] + for e in matchOrder: + loc,results = e._parse(instring,loc,doActions) + resultlist.append(results) + + finalResults = sum(resultlist, ParseResults([])) + return loc, finalResults + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class ParseElementEnhance(ParserElement): + """ + Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. + """ + def __init__( self, expr, savelist=False ): + super(ParseElementEnhance,self).__init__(savelist) + if isinstance( expr, basestring ): + if issubclass(ParserElement._literalStringClass, Token): + expr = ParserElement._literalStringClass(expr) + else: + expr = ParserElement._literalStringClass(Literal(expr)) + self.expr = expr + self.strRepr = None + if expr is not None: + self.mayIndexError = expr.mayIndexError + self.mayReturnEmpty = expr.mayReturnEmpty + self.setWhitespaceChars( expr.whiteChars ) + self.skipWhitespace = expr.skipWhitespace + self.saveAsList = expr.saveAsList + self.callPreparse = expr.callPreparse + self.ignoreExprs.extend(expr.ignoreExprs) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr is not None: + return self.expr._parse( instring, loc, doActions, callPreParse=False ) + else: + raise ParseException("",loc,self.errmsg,self) + + def leaveWhitespace( self ): + self.skipWhitespace = False + self.expr = self.expr.copy() + if self.expr is not None: + self.expr.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + else: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + return self + + def streamline( self ): + super(ParseElementEnhance,self).streamline() + if self.expr is not None: + self.expr.streamline() + return self + + def checkRecursion( self, parseElementList ): + if self in parseElementList: + raise RecursiveGrammarException( parseElementList+[self] ) + subRecCheckList = parseElementList[:] + [ self ] + if self.expr is not None: + self.expr.checkRecursion( subRecCheckList ) + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion( [] ) + + def __str__( self ): + try: + return super(ParseElementEnhance,self).__str__() + except Exception: + pass + + if self.strRepr is None and self.expr is not None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) + return self.strRepr + + +class FollowedBy(ParseElementEnhance): + """ + Lookahead matching of the given parse expression. C{FollowedBy} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression matches at the current + position. C{FollowedBy} always returns a null token list. + + Example:: + # use FollowedBy to match a label only if it is followed by a ':' + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() + prints:: + [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] + """ + def __init__( self, expr ): + super(FollowedBy,self).__init__(expr) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + self.expr.tryParse( instring, loc ) + return loc, [] + + +class NotAny(ParseElementEnhance): + """ + Lookahead to disallow matching with the given parse expression. C{NotAny} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression does I{not} match at the current + position. Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny} + always returns a null token list. May be constructed using the '~' operator. + + Example:: + + """ + def __init__( self, expr ): + super(NotAny,self).__init__(expr) + #~ self.leaveWhitespace() + self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + self.mayReturnEmpty = True + self.errmsg = "Found unwanted token, "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr.canParseNext(instring, loc): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "~{" + _ustr(self.expr) + "}" + + return self.strRepr + +class _MultipleMatch(ParseElementEnhance): + def __init__( self, expr, stopOn=None): + super(_MultipleMatch, self).__init__(expr) + self.saveAsList = True + ender = stopOn + if isinstance(ender, basestring): + ender = ParserElement._literalStringClass(ender) + self.not_ender = ~ender if ender is not None else None + + def parseImpl( self, instring, loc, doActions=True ): + self_expr_parse = self.expr._parse + self_skip_ignorables = self._skipIgnorables + check_ender = self.not_ender is not None + if check_ender: + try_not_ender = self.not_ender.tryParse + + # must be at least one (but first see if we are the stopOn sentinel; + # if so, fail) + if check_ender: + try_not_ender(instring, loc) + loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) + try: + hasIgnoreExprs = (not not self.ignoreExprs) + while 1: + if check_ender: + try_not_ender(instring, loc) + if hasIgnoreExprs: + preloc = self_skip_ignorables( instring, loc ) + else: + preloc = loc + loc, tmptokens = self_expr_parse( instring, preloc, doActions ) + if tmptokens or tmptokens.haskeys(): + tokens += tmptokens + except (ParseException,IndexError): + pass + + return loc, tokens + +class OneOrMore(_MultipleMatch): + """ + Repetition of one or more of the given expression. + + Parameters: + - expr - expression that must match one or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: BLACK" + OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] + + # use stopOn attribute for OneOrMore to avoid reading label string as part of the data + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] + + # could also be written as + (attr_expr * (1,)).parseString(text).pprint() + """ + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + _ustr(self.expr) + "}..." + + return self.strRepr + +class ZeroOrMore(_MultipleMatch): + """ + Optional repetition of zero or more of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example: similar to L{OneOrMore} + """ + def __init__( self, expr, stopOn=None): + super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) + except (ParseException,IndexError): + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]..." + + return self.strRepr + +class _NullToken(object): + def __bool__(self): + return False + __nonzero__ = __bool__ + def __str__(self): + return "" + +_optionalNotMatched = _NullToken() +class Optional(ParseElementEnhance): + """ + Optional matching of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - default (optional) - value to be returned if the optional expression is not found. + + Example:: + # US postal code can be a 5-digit zip, plus optional 4-digit qualifier + zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) + zip.runTests(''' + # traditional ZIP code + 12345 + + # ZIP+4 form + 12101-0001 + + # invalid ZIP + 98765- + ''') + prints:: + # traditional ZIP code + 12345 + ['12345'] + + # ZIP+4 form + 12101-0001 + ['12101-0001'] + + # invalid ZIP + 98765- + ^ + FAIL: Expected end of text (at char 5), (line:1, col:6) + """ + def __init__( self, expr, default=_optionalNotMatched ): + super(Optional,self).__init__( expr, savelist=False ) + self.saveAsList = self.expr.saveAsList + self.defaultValue = default + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) + except (ParseException,IndexError): + if self.defaultValue is not _optionalNotMatched: + if self.expr.resultsName: + tokens = ParseResults([ self.defaultValue ]) + tokens[self.expr.resultsName] = self.defaultValue + else: + tokens = [ self.defaultValue ] + else: + tokens = [] + return loc, tokens + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]" + + return self.strRepr + +class SkipTo(ParseElementEnhance): + """ + Token for skipping over all undefined text until the matched expression is found. + + Parameters: + - expr - target expression marking the end of the data to be skipped + - include - (default=C{False}) if True, the target expression is also parsed + (the skipped text and target expression are returned as a 2-element list). + - ignore - (default=C{None}) used to define grammars (typically quoted strings and + comments) that might contain false matches to the target expression + - failOn - (default=C{None}) define expressions that are not allowed to be + included in the skipped test; if found before the target expression is found, + the SkipTo is not a match + + Example:: + report = ''' + Outstanding Issues Report - 1 Jan 2000 + + # | Severity | Description | Days Open + -----+----------+-------------------------------------------+----------- + 101 | Critical | Intermittent system crash | 6 + 94 | Cosmetic | Spelling error on Login ('log|n') | 14 + 79 | Minor | System slow when running too many reports | 47 + ''' + integer = Word(nums) + SEP = Suppress('|') + # use SkipTo to simply match everything up until the next SEP + # - ignore quoted strings, so that a '|' character inside a quoted string does not match + # - parse action will call token.strip() for each matched token, i.e., the description body + string_data = SkipTo(SEP, ignore=quotedString) + string_data.setParseAction(tokenMap(str.strip)) + ticket_expr = (integer("issue_num") + SEP + + string_data("sev") + SEP + + string_data("desc") + SEP + + integer("days_open")) + + for tkt in ticket_expr.searchString(report): + print tkt.dump() + prints:: + ['101', 'Critical', 'Intermittent system crash', '6'] + - days_open: 6 + - desc: Intermittent system crash + - issue_num: 101 + - sev: Critical + ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] + - days_open: 14 + - desc: Spelling error on Login ('log|n') + - issue_num: 94 + - sev: Cosmetic + ['79', 'Minor', 'System slow when running too many reports', '47'] + - days_open: 47 + - desc: System slow when running too many reports + - issue_num: 79 + - sev: Minor + """ + def __init__( self, other, include=False, ignore=None, failOn=None ): + super( SkipTo, self ).__init__( other ) + self.ignoreExpr = ignore + self.mayReturnEmpty = True + self.mayIndexError = False + self.includeMatch = include + self.asList = False + if isinstance(failOn, basestring): + self.failOn = ParserElement._literalStringClass(failOn) + else: + self.failOn = failOn + self.errmsg = "No match found for "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + startloc = loc + instrlen = len(instring) + expr = self.expr + expr_parse = self.expr._parse + self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None + self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None + + tmploc = loc + while tmploc <= instrlen: + if self_failOn_canParseNext is not None: + # break if failOn expression matches + if self_failOn_canParseNext(instring, tmploc): + break + + if self_ignoreExpr_tryParse is not None: + # advance past ignore expressions + while 1: + try: + tmploc = self_ignoreExpr_tryParse(instring, tmploc) + except ParseBaseException: + break + + try: + expr_parse(instring, tmploc, doActions=False, callPreParse=False) + except (ParseException, IndexError): + # no match, advance loc in string + tmploc += 1 + else: + # matched skipto expr, done + break + + else: + # ran off the end of the input string without matching skipto expr, fail + raise ParseException(instring, loc, self.errmsg, self) + + # build up return values + loc = tmploc + skiptext = instring[startloc:loc] + skipresult = ParseResults(skiptext) + + if self.includeMatch: + loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) + skipresult += mat + + return loc, skipresult + +class Forward(ParseElementEnhance): + """ + Forward declaration of an expression to be defined later - + used for recursive grammars, such as algebraic infix notation. + When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. + + Note: take care when assigning to C{Forward} not to overlook precedence of operators. + Specifically, '|' has a lower precedence than '<<', so that:: + fwdExpr << a | b | c + will actually be evaluated as:: + (fwdExpr << a) | b | c + thereby leaving b and c out as parseable alternatives. It is recommended that you + explicitly group the values inserted into the C{Forward}:: + fwdExpr << (a | b | c) + Converting to use the '<<=' operator instead will avoid this problem. + + See L{ParseResults.pprint} for an example of a recursive parser created using + C{Forward}. + """ + def __init__( self, other=None ): + super(Forward,self).__init__( other, savelist=False ) + + def __lshift__( self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass(other) + self.expr = other + self.strRepr = None + self.mayIndexError = self.expr.mayIndexError + self.mayReturnEmpty = self.expr.mayReturnEmpty + self.setWhitespaceChars( self.expr.whiteChars ) + self.skipWhitespace = self.expr.skipWhitespace + self.saveAsList = self.expr.saveAsList + self.ignoreExprs.extend(self.expr.ignoreExprs) + return self + + def __ilshift__(self, other): + return self << other + + def leaveWhitespace( self ): + self.skipWhitespace = False + return self + + def streamline( self ): + if not self.streamlined: + self.streamlined = True + if self.expr is not None: + self.expr.streamline() + return self + + def validate( self, validateTrace=[] ): + if self not in validateTrace: + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion([]) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + return self.__class__.__name__ + ": ..." + + # stubbed out for now - creates awful memory and perf issues + self._revertClass = self.__class__ + self.__class__ = _ForwardNoRecurse + try: + if self.expr is not None: + retString = _ustr(self.expr) + else: + retString = "None" + finally: + self.__class__ = self._revertClass + return self.__class__.__name__ + ": " + retString + + def copy(self): + if self.expr is not None: + return super(Forward,self).copy() + else: + ret = Forward() + ret <<= self + return ret + +class _ForwardNoRecurse(Forward): + def __str__( self ): + return "..." + +class TokenConverter(ParseElementEnhance): + """ + Abstract subclass of C{ParseExpression}, for converting parsed results. + """ + def __init__( self, expr, savelist=False ): + super(TokenConverter,self).__init__( expr )#, savelist ) + self.saveAsList = False + +class Combine(TokenConverter): + """ + Converter to concatenate all matching tokens to a single string. + By default, the matching patterns must also be contiguous in the input string; + this can be disabled by specifying C{'adjacent=False'} in the constructor. + + Example:: + real = Word(nums) + '.' + Word(nums) + print(real.parseString('3.1416')) # -> ['3', '.', '1416'] + # will also erroneously match the following + print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] + + real = Combine(Word(nums) + '.' + Word(nums)) + print(real.parseString('3.1416')) # -> ['3.1416'] + # no match when there are internal spaces + print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) + """ + def __init__( self, expr, joinString="", adjacent=True ): + super(Combine,self).__init__( expr ) + # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself + if adjacent: + self.leaveWhitespace() + self.adjacent = adjacent + self.skipWhitespace = True + self.joinString = joinString + self.callPreparse = True + + def ignore( self, other ): + if self.adjacent: + ParserElement.ignore(self, other) + else: + super( Combine, self).ignore( other ) + return self + + def postParse( self, instring, loc, tokenlist ): + retToks = tokenlist.copy() + del retToks[:] + retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) + + if self.resultsName and retToks.haskeys(): + return [ retToks ] + else: + return retToks + +class Group(TokenConverter): + """ + Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. + + Example:: + ident = Word(alphas) + num = Word(nums) + term = ident | num + func = ident + Optional(delimitedList(term)) + print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] + + func = ident + Group(Optional(delimitedList(term))) + print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] + """ + def __init__( self, expr ): + super(Group,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + return [ tokenlist ] + +class Dict(TokenConverter): + """ + Converter to return a repetitive expression as a list, but also as a dictionary. + Each element can also be referenced using the first token in the expression as its key. + Useful for tabular report scraping when the first column can be used as a item key. + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + # print attributes as plain groups + print(OneOrMore(attr_expr).parseString(text).dump()) + + # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names + result = Dict(OneOrMore(Group(attr_expr))).parseString(text) + print(result.dump()) + + # access named fields as dict entries, or output as dict + print(result['shape']) + print(result.asDict()) + prints:: + ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] + + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} + See more examples at L{ParseResults} of accessing fields by results name. + """ + def __init__( self, expr ): + super(Dict,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + for i,tok in enumerate(tokenlist): + if len(tok) == 0: + continue + ikey = tok[0] + if isinstance(ikey,int): + ikey = _ustr(tok[0]).strip() + if len(tok)==1: + tokenlist[ikey] = _ParseResultsWithOffset("",i) + elif len(tok)==2 and not isinstance(tok[1],ParseResults): + tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) + else: + dictvalue = tok.copy() #ParseResults(i) + del dictvalue[0] + if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) + else: + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) + + if self.resultsName: + return [ tokenlist ] + else: + return tokenlist + + +class Suppress(TokenConverter): + """ + Converter for ignoring the results of a parsed expression. + + Example:: + source = "a, b, c,d" + wd = Word(alphas) + wd_list1 = wd + ZeroOrMore(',' + wd) + print(wd_list1.parseString(source)) + + # often, delimiters that are useful during parsing are just in the + # way afterward - use Suppress to keep them out of the parsed output + wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) + print(wd_list2.parseString(source)) + prints:: + ['a', ',', 'b', ',', 'c', ',', 'd'] + ['a', 'b', 'c', 'd'] + (See also L{delimitedList}.) + """ + def postParse( self, instring, loc, tokenlist ): + return [] + + def suppress( self ): + return self + + +class OnlyOnce(object): + """ + Wrapper for parse actions, to ensure they are only called once. + """ + def __init__(self, methodCall): + self.callable = _trim_arity(methodCall) + self.called = False + def __call__(self,s,l,t): + if not self.called: + results = self.callable(s,l,t) + self.called = True + return results + raise ParseException(s,l,"") + def reset(self): + self.called = False + +def traceParseAction(f): + """ + Decorator for debugging parse actions. + + When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} + When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. + + Example:: + wd = Word(alphas) + + @traceParseAction + def remove_duplicate_chars(tokens): + return ''.join(sorted(set(''.join(tokens))) + + wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) + print(wds.parseString("slkdjs sld sldd sdlf sdljf")) + prints:: + >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) + <<leaving remove_duplicate_chars (ret: 'dfjkls') + ['dfjkls'] + """ + f = _trim_arity(f) + def z(*paArgs): + thisFunc = f.__name__ + s,l,t = paArgs[-3:] + if len(paArgs)>3: + thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc + sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) + try: + ret = f(*paArgs) + except Exception as exc: + sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) ) + raise + sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) ) + return ret + try: + z.__name__ = f.__name__ + except AttributeError: + pass + return z + +# +# global helpers +# +def delimitedList( expr, delim=",", combine=False ): + """ + Helper to define a delimited list of expressions - the delimiter defaults to ','. + By default, the list elements and delimiters can have intervening whitespace, and + comments, but this can be overridden by passing C{combine=True} in the constructor. + If C{combine} is set to C{True}, the matching tokens are returned as a single token + string, with the delimiters included; otherwise, the matching tokens are returned + as a list of tokens, with the delimiters suppressed. + + Example:: + delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc'] + delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] + """ + dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." + if combine: + return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) + else: + return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) + +def countedArray( expr, intExpr=None ): + """ + Helper to define a counted list of expressions. + This helper defines a pattern of the form:: + integer expr expr expr... + where the leading integer tells how many expr expressions follow. + The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. + + If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. + + Example:: + countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] + + # in this parser, the leading integer value is given in binary, + # '10' indicating that 2 values are in the array + binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2)) + countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] + """ + arrayExpr = Forward() + def countFieldParseAction(s,l,t): + n = t[0] + arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) + return [] + if intExpr is None: + intExpr = Word(nums).setParseAction(lambda t:int(t[0])) + else: + intExpr = intExpr.copy() + intExpr.setName("arrayLen") + intExpr.addParseAction(countFieldParseAction, callDuringTry=True) + return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') + +def _flatten(L): + ret = [] + for i in L: + if isinstance(i,list): + ret.extend(_flatten(i)) + else: + ret.append(i) + return ret + +def matchPreviousLiteral(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousLiteral(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches a + previous literal, will also match the leading C{"1:1"} in C{"1:10"}. + If this is not desired, use C{matchPreviousExpr}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + def copyTokenToRepeater(s,l,t): + if t: + if len(t) == 1: + rep << t[0] + else: + # flatten t tokens + tflat = _flatten(t.asList()) + rep << And(Literal(tt) for tt in tflat) + else: + rep << Empty() + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def matchPreviousExpr(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousExpr(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches by + expressions, will I{not} match the leading C{"1:1"} in C{"1:10"}; + the expressions are evaluated first, and then compared, so + C{"1"} is compared with C{"10"}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + e2 = expr.copy() + rep <<= e2 + def copyTokenToRepeater(s,l,t): + matchTokens = _flatten(t.asList()) + def mustMatchTheseTokens(s,l,t): + theseTokens = _flatten(t.asList()) + if theseTokens != matchTokens: + raise ParseException("",0,"") + rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def _escapeRegexRangeChars(s): + #~ escape these chars: ^-] + for c in r"\^-]": + s = s.replace(c,_bslash+c) + s = s.replace("\n",r"\n") + s = s.replace("\t",r"\t") + return _ustr(s) + +def oneOf( strs, caseless=False, useRegex=True ): + """ + Helper to quickly define a set of alternative Literals, and makes sure to do + longest-first testing when there is a conflict, regardless of the input order, + but returns a C{L{MatchFirst}} for best performance. + + Parameters: + - strs - a string of space-delimited literals, or a collection of string literals + - caseless - (default=C{False}) - treat all literals as caseless + - useRegex - (default=C{True}) - as an optimization, will generate a Regex + object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or + if creating a C{Regex} raises an exception) + + Example:: + comp_oper = oneOf("< = > <= >= !=") + var = Word(alphas) + number = Word(nums) + term = var | number + comparison_expr = term + comp_oper + term + print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) + prints:: + [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] + """ + if caseless: + isequal = ( lambda a,b: a.upper() == b.upper() ) + masks = ( lambda a,b: b.upper().startswith(a.upper()) ) + parseElementClass = CaselessLiteral + else: + isequal = ( lambda a,b: a == b ) + masks = ( lambda a,b: b.startswith(a) ) + parseElementClass = Literal + + symbols = [] + if isinstance(strs,basestring): + symbols = strs.split() + elif isinstance(strs, collections.Iterable): + symbols = list(strs) + else: + warnings.warn("Invalid argument to oneOf, expected string or iterable", + SyntaxWarning, stacklevel=2) + if not symbols: + return NoMatch() + + i = 0 + while i < len(symbols)-1: + cur = symbols[i] + for j,other in enumerate(symbols[i+1:]): + if ( isequal(other, cur) ): + del symbols[i+j+1] + break + elif ( masks(cur, other) ): + del symbols[i+j+1] + symbols.insert(i,other) + cur = other + break + else: + i += 1 + + if not caseless and useRegex: + #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) + try: + if len(symbols)==len("".join(symbols)): + return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) + else: + return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) + except Exception: + warnings.warn("Exception creating Regex for oneOf, building MatchFirst", + SyntaxWarning, stacklevel=2) + + + # last resort, just use MatchFirst + return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) + +def dictOf( key, value ): + """ + Helper to easily and clearly define a dictionary by specifying the respective patterns + for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens + in the proper order. The key pattern can include delimiting markers or punctuation, + as long as they are suppressed, thereby leaving the significant key text. The value + pattern can include named results, so that the C{Dict} results can include named token + fields. + + Example:: + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + print(OneOrMore(attr_expr).parseString(text).dump()) + + attr_label = label + attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) + + # similar to Dict, but simpler call format + result = dictOf(attr_label, attr_value).parseString(text) + print(result.dump()) + print(result['shape']) + print(result.shape) # object attribute access works too + print(result.asDict()) + prints:: + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + SQUARE + {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} + """ + return Dict( ZeroOrMore( Group ( key + value ) ) ) + +def originalTextFor(expr, asString=True): + """ + Helper to return the original, untokenized text for a given expression. Useful to + restore the parsed fields of an HTML start tag into the raw tag text itself, or to + revert separate tokens with intervening whitespace back to the original matching + input text. By default, returns astring containing the original parsed text. + + If the optional C{asString} argument is passed as C{False}, then the return value is a + C{L{ParseResults}} containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if + the expression passed to C{L{originalTextFor}} contains expressions with defined + results names, you must set C{asString} to C{False} if you want to preserve those + results name values. + + Example:: + src = "this is test <b> bold <i>text</i> </b> normal text " + for tag in ("b","i"): + opener,closer = makeHTMLTags(tag) + patt = originalTextFor(opener + SkipTo(closer) + closer) + print(patt.searchString(src)[0]) + prints:: + ['<b> bold <i>text</i> </b>'] + ['<i>text</i>'] + """ + locMarker = Empty().setParseAction(lambda s,loc,t: loc) + endlocMarker = locMarker.copy() + endlocMarker.callPreparse = False + matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") + if asString: + extractText = lambda s,l,t: s[t._original_start:t._original_end] + else: + def extractText(s,l,t): + t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] + matchExpr.setParseAction(extractText) + matchExpr.ignoreExprs = expr.ignoreExprs + return matchExpr + +def ungroup(expr): + """ + Helper to undo pyparsing's default grouping of And expressions, even + if all but one are non-empty. + """ + return TokenConverter(expr).setParseAction(lambda t:t[0]) + +def locatedExpr(expr): + """ + Helper to decorate a returned token with its starting and ending locations in the input string. + This helper adds the following results names: + - locn_start = location where matched expression begins + - locn_end = location where matched expression ends + - value = the actual parsed results + + Be careful if the input text contains C{<TAB>} characters, you may want to call + C{L{ParserElement.parseWithTabs}} + + Example:: + wd = Word(alphas) + for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): + print(match) + prints:: + [[0, 'ljsdf', 5]] + [[8, 'lksdjjf', 15]] + [[18, 'lkkjj', 23]] + """ + locator = Empty().setParseAction(lambda s,l,t: l) + return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) + + +# convenience constants for positional expressions +empty = Empty().setName("empty") +lineStart = LineStart().setName("lineStart") +lineEnd = LineEnd().setName("lineEnd") +stringStart = StringStart().setName("stringStart") +stringEnd = StringEnd().setName("stringEnd") + +_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) +_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) +_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) +_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(printables, excludeChars=r'\]', exact=1) | Regex(r"\w", re.UNICODE) +_charRange = Group(_singleChar + Suppress("-") + _singleChar) +_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" + +def srange(s): + r""" + Helper to easily define string ranges for use in Word construction. Borrows + syntax from regexp '[]' string range definitions:: + srange("[0-9]") -> "0123456789" + srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" + srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" + The input string must be enclosed in []'s, and the returned string is the expanded + character set joined into a single string. + The values enclosed in the []'s may be: + - a single character + - an escaped character with a leading backslash (such as C{\-} or C{\]}) + - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) + (C{\0x##} is also supported for backwards compatibility) + - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) + - a range of any of the above, separated by a dash (C{'a-z'}, etc.) + - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) + """ + _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) + try: + return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) + except Exception: + return "" + +def matchOnlyAtCol(n): + """ + Helper method for defining parse actions that require matching at a specific + column in the input text. + """ + def verifyCol(strg,locn,toks): + if col(locn,strg) != n: + raise ParseException(strg,locn,"matched token not at column %d" % n) + return verifyCol + +def replaceWith(replStr): + """ + Helper method for common parse actions that simply return a literal value. Especially + useful when used with C{L{transformString<ParserElement.transformString>}()}. + + Example:: + num = Word(nums).setParseAction(lambda toks: int(toks[0])) + na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) + term = na | num + + OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] + """ + return lambda s,l,t: [replStr] + +def removeQuotes(s,l,t): + """ + Helper parse action for removing quotation marks from parsed quoted strings. + + Example:: + # by default, quotation marks are included in parsed results + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] + + # use removeQuotes to strip quotation marks from parsed results + quotedString.setParseAction(removeQuotes) + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] + """ + return t[0][1:-1] + +def tokenMap(func, *args): + """ + Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional + args are passed, they are forwarded to the given function as additional arguments after + the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the + parsed data to an integer using base 16. + + Example (compare the last to example in L{ParserElement.transformString}:: + hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) + hex_ints.runTests(''' + 00 11 22 aa FF 0a 0d 1a + ''') + + upperword = Word(alphas).setParseAction(tokenMap(str.upper)) + OneOrMore(upperword).runTests(''' + my kingdom for a horse + ''') + + wd = Word(alphas).setParseAction(tokenMap(str.title)) + OneOrMore(wd).setParseAction(' '.join).runTests(''' + now is the winter of our discontent made glorious summer by this sun of york + ''') + prints:: + 00 11 22 aa FF 0a 0d 1a + [0, 17, 34, 170, 255, 10, 13, 26] + + my kingdom for a horse + ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] + + now is the winter of our discontent made glorious summer by this sun of york + ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] + """ + def pa(s,l,t): + return [func(tokn, *args) for tokn in t] + + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + pa.__name__ = func_name + + return pa + +upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) +"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" + +downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) +"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" + +def _makeTags(tagStr, xml): + """Internal helper to construct opening and closing tag expressions, given a tag name""" + if isinstance(tagStr,basestring): + resname = tagStr + tagStr = Keyword(tagStr, caseless=not xml) + else: + resname = tagStr.name + + tagAttrName = Word(alphas,alphanums+"_-:") + if (xml): + tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + else: + printablesLessRAbrack = "".join(c for c in printables if c not in ">") + tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ + Optional( Suppress("=") + tagAttrValue ) ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + closeTag = Combine(_L("</") + tagStr + ">") + + openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) + closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname) + openTag.tag = resname + closeTag.tag = resname + return openTag, closeTag + +def makeHTMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches + tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. + + Example:: + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple + a,a_end = makeHTMLTags("A") + link_expr = a + SkipTo(a_end)("link_text") + a_end + + for link in link_expr.searchString(text): + # attributes in the <A> tag (like "href" shown here) are also accessible as named results + print(link.link_text, '->', link.href) + prints:: + pyparsing -> http://pyparsing.wikispaces.com + """ + return _makeTags( tagStr, False ) + +def makeXMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for XML, given a tag name. Matches + tags only in the given upper/lower case. + + Example: similar to L{makeHTMLTags} + """ + return _makeTags( tagStr, True ) + +def withAttribute(*args,**attrDict): + """ + Helper to create a validating parse action to be used with start tags created + with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag + with a required attribute value, to avoid false matches on common tags such as + C{<TD>} or C{<DIV>}. + + Call C{withAttribute} with a series of attribute names and values. Specify the list + of filter attributes names and values as: + - keyword arguments, as in C{(align="right")}, or + - as an explicit dict with C{**} operator, when an attribute name is also a Python + reserved word, as in C{**{"class":"Customer", "align":"right"}} + - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) + For attribute names with a namespace prefix, you must use the second form. Attribute + names are matched insensitive to upper/lower case. + + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. + + To verify that the attribute exists, but without specifying a value, pass + C{withAttribute.ANY_VALUE} as the value. + + Example:: + html = ''' + <div> + Some text + <div type="grid">1 4 0 1 0</div> + <div type="graph">1,3 2,3 1,1</div> + <div>this has no type</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + + # only match div tag having a type attribute with value "grid" + div_grid = div().setParseAction(withAttribute(type="grid")) + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + # construct a match with any div tag having a type attribute, regardless of the value + div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + if args: + attrs = args[:] + else: + attrs = attrDict.items() + attrs = [(k,v) for k,v in attrs] + def pa(s,l,tokens): + for attrName,attrValue in attrs: + if attrName not in tokens: + raise ParseException(s,l,"no matching attribute " + attrName) + if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: + raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % + (attrName, tokens[attrName], attrValue)) + return pa +withAttribute.ANY_VALUE = object() + +def withClass(classname, namespace=''): + """ + Simplified version of C{L{withAttribute}} when matching on a div class - made + difficult because C{class} is a reserved word in Python. + + Example:: + html = ''' + <div> + Some text + <div class="grid">1 4 0 1 0</div> + <div class="graph">1,3 2,3 1,1</div> + <div>this <div> has no class</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + div_grid = div().setParseAction(withClass("grid")) + + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + classattr = "%s:class" % namespace if namespace else "class" + return withAttribute(**{classattr : classname}) + +opAssoc = _Constants() +opAssoc.LEFT = object() +opAssoc.RIGHT = object() + +def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + """ + Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary or + binary, left- or right-associative. Parse actions can also be attached + to operator expressions. The generated parser will also recognize the use + of parentheses to override operator precedences (see example below). + + Note: if you define a deep operator list, you may see performance issues + when using infixNotation. See L{ParserElement.enablePackrat} for a + mechanism to potentially improve your parser performance. + + Parameters: + - baseExpr - expression representing the most basic element for the nested + - opList - list of tuples, one for each operator precedence level in the + expression grammar; each tuple is of the form + (opExpr, numTerms, rightLeftAssoc, parseAction), where: + - opExpr is the pyparsing expression for the operator; + may also be a string, which will be converted to a Literal; + if numTerms is 3, opExpr is a tuple of two expressions, for the + two operators separating the 3 terms + - numTerms is the number of terms for this operator (must + be 1, 2, or 3) + - rightLeftAssoc is the indicator whether the operator is + right or left associative, using the pyparsing-defined + constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. + - parseAction is the parse action to be associated with + expressions matching this operator expression (the + parse action tuple member may be omitted); if the parse action + is passed a tuple or list of functions, this is equivalent to + calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) + - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) + - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) + + Example:: + # simple example of four-function arithmetic with ints and variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infixNotation(integer | varname, + [ + ('-', 1, opAssoc.RIGHT), + (oneOf('* /'), 2, opAssoc.LEFT), + (oneOf('+ -'), 2, opAssoc.LEFT), + ]) + + arith_expr.runTests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', fullDump=False) + prints:: + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + ret = Forward() + lastExpr = baseExpr | ( lpar + ret + rpar ) + for i,operDef in enumerate(opList): + opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr + if arity == 3: + if opExpr is None or len(opExpr) != 2: + raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + opExpr1, opExpr2 = opExpr + thisExpr = Forward().setName(termName) + if rightLeftAssoc == opAssoc.LEFT: + if arity == 1: + matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + else: + matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ + Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + elif rightLeftAssoc == opAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Optional): + opExpr = Optional(opExpr) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + else: + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ + Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + else: + raise ValueError("operator must indicate right or left associativity") + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.setParseAction(*pa) + else: + matchExpr.setParseAction(pa) + thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + lastExpr = thisExpr + ret <<= lastExpr + return ret + +operatorPrecedence = infixNotation +"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" + +dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") +sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") +quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + +def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): + """ + Helper method for defining nested lists enclosed in opening and closing + delimiters ("(" and ")" are the default). + + Parameters: + - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression + - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression + - content - expression for items within the nested lists (default=C{None}) + - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) + + If an expression is not provided for the content argument, the nested + expression will capture all whitespace-delimited content between delimiters + as a list of separate values. + + Use the C{ignoreExpr} argument to define expressions that may contain + opening or closing characters that should not be treated as opening + or closing characters for nesting, such as quotedString or a comment + expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. + The default is L{quotedString}, but if no expressions are to be ignored, + then pass C{None} for this argument. + + Example:: + data_type = oneOf("void int short long char float double") + decl_data_type = Combine(data_type + Optional(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR,RPAR = map(Suppress, "()") + + code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(cStyleComment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.searchString(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + prints:: + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener,basestring) and isinstance(closer,basestring): + if len(opener) == 1 and len(closer)==1: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t:t[0].strip())) + else: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + ~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + raise ValueError("opening and closing arguments must be strings if no content expression is given") + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + else: + ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) + ret.setName('nested %s%s expression' % (opener,closer)) + return ret + +def indentedBlock(blockStatementExpr, indentStack, indent=True): + """ + Helper method for defining space-delimited indentation blocks, such as + those used to define block statements in Python source code. + + Parameters: + - blockStatementExpr - expression defining syntax of statement that + is repeated within the indented block + - indentStack - list created by caller to manage indentation stack + (multiple statementWithIndentedBlock expressions within a single grammar + should share a common indentStack) + - indent - boolean indicating whether block must be indented beyond the + the current level; set to False for block of left-most statements + (default=C{True}) + + A valid block must contain at least one C{blockStatement}. + + Example:: + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group( funcDecl + func_body ) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << ( funcDef | assignment | identifier ) + + module_body = OneOrMore(stmt) + + parseTree = module_body.parseString(data) + parseTree.pprint() + prints:: + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + def checkPeerIndent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseFatalException(s,l,"illegal nesting") + raise ParseException(s,l,"not a peer entry") + + def checkSubIndent(s,l,t): + curCol = col(l,s) + if curCol > indentStack[-1]: + indentStack.append( curCol ) + else: + raise ParseException(s,l,"not a subentry") + + def checkUnindent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s,l,"not an unindent") + indentStack.pop() + + NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) + INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') + PEER = Empty().setParseAction(checkPeerIndent).setName('') + UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') + if indent: + smExpr = Group( Optional(NL) + + #~ FollowedBy(blockStatementExpr) + + INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + else: + smExpr = Group( Optional(NL) + + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.setName('indented block') + +alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") +punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") + +anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) +commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +def replaceHTMLEntity(t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +"Comment of the form C{/* ... */}" + +htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment") +"Comment of the form C{<!-- ... -->}" + +restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") +dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") +"Comment of the form C{// ... (to end of line)}" + +cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" + +javaStyleComment = cppStyleComment +"Same as C{L{cppStyleComment}}" + +pythonStyleComment = Regex(r"#.*").setName("Python style comment") +"Comment of the form C{# ... (to end of line)}" + +_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + + Optional( Word(" \t") + + ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") +commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. + This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" + +# some other useful expressions - using lower-case class name since we are really using this as a namespace +class pyparsing_common: + """ + Here are some common low-level expressions that may be useful in jump-starting parser development: + - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>}) + - common L{programming identifiers<identifier>} + - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>}) + - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>} + - L{UUID<uuid>} + - L{comma-separated list<comma_separated_list>} + Parse actions: + - C{L{convertToInteger}} + - C{L{convertToFloat}} + - C{L{convertToDate}} + - C{L{convertToDatetime}} + - C{L{stripHTMLTags}} + - C{L{upcaseTokens}} + - C{L{downcaseTokens}} + + Example:: + pyparsing_common.number.runTests(''' + # any int or real number, returned as the appropriate type + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.fnumber.runTests(''' + # any int or real number, returned as float + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.hex_integer.runTests(''' + # hex numbers + 100 + FF + ''') + + pyparsing_common.fraction.runTests(''' + # fractions + 1/2 + -3/4 + ''') + + pyparsing_common.mixed_integer.runTests(''' + # mixed fractions + 1 + 1/2 + -3/4 + 1-3/4 + ''') + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(''' + # uuid + 12345678-1234-5678-1234-567812345678 + ''') + prints:: + # any int or real number, returned as the appropriate type + 100 + [100] + + -100 + [-100] + + +100 + [100] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # any int or real number, returned as float + 100 + [100.0] + + -100 + [-100.0] + + +100 + [100.0] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # hex numbers + 100 + [256] + + FF + [255] + + # fractions + 1/2 + [0.5] + + -3/4 + [-0.75] + + # mixed fractions + 1 + [1] + + 1/2 + [0.5] + + -3/4 + [-0.75] + + 1-3/4 + [1.75] + + # uuid + 12345678-1234-5678-1234-567812345678 + [UUID('12345678-1234-5678-1234-567812345678')] + """ + + convertToInteger = tokenMap(int) + """ + Parse action for converting parsed integers to Python int + """ + + convertToFloat = tokenMap(float) + """ + Parse action for converting parsed numbers to Python float + """ + + integer = Word(nums).setName("integer").setParseAction(convertToInteger) + """expression that parses an unsigned integer, returns an int""" + + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + """expression that parses a hexadecimal integer, returns an int""" + + signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + """expression that parses an integer with optional leading sign, returns an int""" + + fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + """fractional expression of an integer divided by an integer, returns a float""" + fraction.addParseAction(lambda t: t[0]/t[-1]) + + mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" + mixed_integer.addParseAction(sum) + + real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) + """expression that parses a floating point number and returns a float""" + + sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + """expression that parses a floating point number with optional scientific notation and returns a float""" + + # streamlining this expression makes the docs nicer-looking + number = (sci_real | real | signed_integer).streamline() + """any numeric expression, returns the corresponding Python type""" + + fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + """any int or real number, returned as float""" + + identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" + + ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + "IPv4 address (C{0.0.0.0 - 255.255.255.255})" + + _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") + _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") + _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") + ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + "IPv6 address (long, short, or mixed form)" + + mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" + + @staticmethod + def convertToDate(fmt="%Y-%m-%d"): + """ + Helper to create a parse action for converting parsed date string to Python datetime.date + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) + + Example:: + date_expr = pyparsing_common.iso8601_date.copy() + date_expr.setParseAction(pyparsing_common.convertToDate()) + print(date_expr.parseString("1999-12-31")) + prints:: + [datetime.date(1999, 12, 31)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt).date() + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + @staticmethod + def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): + """ + Helper to create a parse action for converting parsed datetime string to Python datetime.datetime + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) + + Example:: + dt_expr = pyparsing_common.iso8601_datetime.copy() + dt_expr.setParseAction(pyparsing_common.convertToDatetime()) + print(dt_expr.parseString("1999-12-31T23:59:59.999")) + prints:: + [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt) + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date") + "ISO8601 date (C{yyyy-mm-dd})" + + iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" + + uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") + "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" + + _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod + def stripHTMLTags(s, l, tokens): + """ + Parse action to remove HTML tags from web page HTML source + + Example:: + # strip HTML links from normal text + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + td,td_end = makeHTMLTags("TD") + table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end + + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' + """ + return pyparsing_common._html_stripper.transformString(tokens[0]) + + _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') + + Optional( White(" \t") ) ) ).streamline().setName("commaItem") + comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" + + upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) + """Parse action to convert tokens to upper case.""" + + downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) + """Parse action to convert tokens to lower case.""" + + +if __name__ == "__main__": + + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") + + ident = Word(alphas, alphanums + "_$") + + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnNameList = Group(delimitedList(columnName)).setName("columns") + columnSpec = ('*' | columnNameList) + + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + + # demo runTests method, including embedded comments in test string + simpleSQL.runTests(""" + # '*' as column list and dotted table name + select * from SYS.XYZZY + + # caseless match on "SELECT", and casts back to "select" + SELECT * from XYZZY, ABC + + # list of column names, and mixed case SELECT keyword + Select AA,BB,CC from Sys.dual + + # multiple tables + Select A, B, C from Sys.dual, Table2 + + # invalid SELECT keyword - should fail + Xelect A, B, C from Sys.dual + + # incomplete command - should fail + Select + + # invalid column name - should fail + Select ^^^ frox Sys.dual + + """) + + pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + # any int or real number, returned as float + pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + pyparsing_common.hex_integer.runTests(""" + 100 + FF + """) + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(""" + 12345678-1234-5678-1234-567812345678 + """) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py new file mode 100755 index 0000000..222a196 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/__init__.py @@ -0,0 +1,3 @@ +from .core import TomlError +from .parser import load, loads +from .writer import dump, dumps diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py new file mode 100755 index 0000000..0fcada4 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/core.py @@ -0,0 +1,13 @@ +class TomlError(RuntimeError): + def __init__(self, message, line, col, filename): + RuntimeError.__init__(self, message, line, col, filename) + self.message = message + self.line = line + self.col = col + self.filename = filename + + def __str__(self): + return '{}({}, {}): {}'.format(self.filename, self.line, self.col, self.message) + + def __repr__(self): + return 'TomlError({!r}, {!r}, {!r}, {!r})'.format(self.message, self.line, self.col, self.filename) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py new file mode 100755 index 0000000..c416ed5 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/parser.py @@ -0,0 +1,374 @@ +import string, re, sys, datetime +from .core import TomlError + +if sys.version_info[0] == 2: + _chr = unichr +else: + _chr = chr + +def load(fin, translate=lambda t, x, v: v): + return loads(fin.read(), translate=translate, filename=getattr(fin, 'name', repr(fin))) + +def loads(s, filename='<string>', translate=lambda t, x, v: v): + if isinstance(s, bytes): + s = s.decode('utf-8') + + s = s.replace('\r\n', '\n') + + root = {} + tables = {} + scope = root + + src = _Source(s, filename=filename) + ast = _p_toml(src) + + def error(msg): + raise TomlError(msg, pos[0], pos[1], filename) + + def process_value(v): + kind, text, value, pos = v + if kind == 'str' and value.startswith('\n'): + value = value[1:] + if kind == 'array': + if value and any(k != value[0][0] for k, t, v, p in value[1:]): + error('array-type-mismatch') + value = [process_value(item) for item in value] + elif kind == 'table': + value = dict([(k, process_value(value[k])) for k in value]) + return translate(kind, text, value) + + for kind, value, pos in ast: + if kind == 'kv': + k, v = value + if k in scope: + error('duplicate_keys. Key "{0}" was used more than once.'.format(k)) + scope[k] = process_value(v) + else: + is_table_array = (kind == 'table_array') + cur = tables + for name in value[:-1]: + if isinstance(cur.get(name), list): + d, cur = cur[name][-1] + else: + d, cur = cur.setdefault(name, (None, {})) + + scope = {} + name = value[-1] + if name not in cur: + if is_table_array: + cur[name] = [(scope, {})] + else: + cur[name] = (scope, {}) + elif isinstance(cur[name], list): + if not is_table_array: + error('table_type_mismatch') + cur[name].append((scope, {})) + else: + if is_table_array: + error('table_type_mismatch') + old_scope, next_table = cur[name] + if old_scope is not None: + error('duplicate_tables') + cur[name] = (scope, next_table) + + def merge_tables(scope, tables): + if scope is None: + scope = {} + for k in tables: + if k in scope: + error('key_table_conflict') + v = tables[k] + if isinstance(v, list): + scope[k] = [merge_tables(sc, tbl) for sc, tbl in v] + else: + scope[k] = merge_tables(v[0], v[1]) + return scope + + return merge_tables(root, tables) + +class _Source: + def __init__(self, s, filename=None): + self.s = s + self._pos = (1, 1) + self._last = None + self._filename = filename + self.backtrack_stack = [] + + def last(self): + return self._last + + def pos(self): + return self._pos + + def fail(self): + return self._expect(None) + + def consume_dot(self): + if self.s: + self._last = self.s[0] + self.s = self[1:] + self._advance(self._last) + return self._last + return None + + def expect_dot(self): + return self._expect(self.consume_dot()) + + def consume_eof(self): + if not self.s: + self._last = '' + return True + return False + + def expect_eof(self): + return self._expect(self.consume_eof()) + + def consume(self, s): + if self.s.startswith(s): + self.s = self.s[len(s):] + self._last = s + self._advance(s) + return True + return False + + def expect(self, s): + return self._expect(self.consume(s)) + + def consume_re(self, re): + m = re.match(self.s) + if m: + self.s = self.s[len(m.group(0)):] + self._last = m + self._advance(m.group(0)) + return m + return None + + def expect_re(self, re): + return self._expect(self.consume_re(re)) + + def __enter__(self): + self.backtrack_stack.append((self.s, self._pos)) + + def __exit__(self, type, value, traceback): + if type is None: + self.backtrack_stack.pop() + else: + self.s, self._pos = self.backtrack_stack.pop() + return type == TomlError + + def commit(self): + self.backtrack_stack[-1] = (self.s, self._pos) + + def _expect(self, r): + if not r: + raise TomlError('msg', self._pos[0], self._pos[1], self._filename) + return r + + def _advance(self, s): + suffix_pos = s.rfind('\n') + if suffix_pos == -1: + self._pos = (self._pos[0], self._pos[1] + len(s)) + else: + self._pos = (self._pos[0] + s.count('\n'), len(s) - suffix_pos) + +_ews_re = re.compile(r'(?:[ \t]|#[^\n]*\n|#[^\n]*\Z|\n)*') +def _p_ews(s): + s.expect_re(_ews_re) + +_ws_re = re.compile(r'[ \t]*') +def _p_ws(s): + s.expect_re(_ws_re) + +_escapes = { 'b': '\b', 'n': '\n', 'r': '\r', 't': '\t', '"': '"', '\'': '\'', + '\\': '\\', '/': '/', 'f': '\f' } + +_basicstr_re = re.compile(r'[^"\\\000-\037]*') +_short_uni_re = re.compile(r'u([0-9a-fA-F]{4})') +_long_uni_re = re.compile(r'U([0-9a-fA-F]{8})') +_escapes_re = re.compile('[bnrt"\'\\\\/f]') +_newline_esc_re = re.compile('\n[ \t\n]*') +def _p_basicstr_content(s, content=_basicstr_re): + res = [] + while True: + res.append(s.expect_re(content).group(0)) + if not s.consume('\\'): + break + if s.consume_re(_newline_esc_re): + pass + elif s.consume_re(_short_uni_re) or s.consume_re(_long_uni_re): + res.append(_chr(int(s.last().group(1), 16))) + else: + s.expect_re(_escapes_re) + res.append(_escapes[s.last().group(0)]) + return ''.join(res) + +_key_re = re.compile(r'[0-9a-zA-Z-_]+') +def _p_key(s): + with s: + s.expect('"') + r = _p_basicstr_content(s, _basicstr_re) + s.expect('"') + return r + if s.consume('\''): + if s.consume('\'\''): + r = s.expect_re(_litstr_ml_re).group(0) + s.expect('\'\'\'') + else: + r = s.expect_re(_litstr_re).group(0) + s.expect('\'') + return r + return s.expect_re(_key_re).group(0) + +_float_re = re.compile(r'[+-]?(?:0|[1-9](?:_?\d)*)(?:\.\d(?:_?\d)*)?(?:[eE][+-]?(?:\d(?:_?\d)*))?') +_datetime_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))') + +_basicstr_ml_re = re.compile(r'(?:(?:|"|"")[^"\\\000-\011\013-\037])*') +_litstr_re = re.compile(r"[^'\000-\037]*") +_litstr_ml_re = re.compile(r"(?:(?:|'|'')(?:[^'\000-\011\013-\037]))*") +def _p_value(s): + pos = s.pos() + + if s.consume('true'): + return 'bool', s.last(), True, pos + if s.consume('false'): + return 'bool', s.last(), False, pos + + if s.consume('"'): + if s.consume('""'): + r = _p_basicstr_content(s, _basicstr_ml_re) + s.expect('"""') + else: + r = _p_basicstr_content(s, _basicstr_re) + s.expect('"') + return 'str', r, r, pos + + if s.consume('\''): + if s.consume('\'\''): + r = s.expect_re(_litstr_ml_re).group(0) + s.expect('\'\'\'') + else: + r = s.expect_re(_litstr_re).group(0) + s.expect('\'') + return 'str', r, r, pos + + if s.consume_re(_datetime_re): + m = s.last() + s0 = m.group(0) + r = map(int, m.groups()[:6]) + if m.group(7): + micro = float(m.group(7)) + else: + micro = 0 + + if m.group(8): + g = int(m.group(8), 10) * 60 + int(m.group(9), 10) + tz = _TimeZone(datetime.timedelta(0, g * 60)) + else: + tz = _TimeZone(datetime.timedelta(0, 0)) + + y, m, d, H, M, S = r + dt = datetime.datetime(y, m, d, H, M, S, int(micro * 1000000), tz) + return 'datetime', s0, dt, pos + + if s.consume_re(_float_re): + m = s.last().group(0) + r = m.replace('_','') + if '.' in m or 'e' in m or 'E' in m: + return 'float', m, float(r), pos + else: + return 'int', m, int(r, 10), pos + + if s.consume('['): + items = [] + with s: + while True: + _p_ews(s) + items.append(_p_value(s)) + s.commit() + _p_ews(s) + s.expect(',') + s.commit() + _p_ews(s) + s.expect(']') + return 'array', None, items, pos + + if s.consume('{'): + _p_ws(s) + items = {} + if not s.consume('}'): + k = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + items[k] = _p_value(s) + _p_ws(s) + while s.consume(','): + _p_ws(s) + k = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + items[k] = _p_value(s) + _p_ws(s) + s.expect('}') + return 'table', None, items, pos + + s.fail() + +def _p_stmt(s): + pos = s.pos() + if s.consume( '['): + is_array = s.consume('[') + _p_ws(s) + keys = [_p_key(s)] + _p_ws(s) + while s.consume('.'): + _p_ws(s) + keys.append(_p_key(s)) + _p_ws(s) + s.expect(']') + if is_array: + s.expect(']') + return 'table_array' if is_array else 'table', keys, pos + + key = _p_key(s) + _p_ws(s) + s.expect('=') + _p_ws(s) + value = _p_value(s) + return 'kv', (key, value), pos + +_stmtsep_re = re.compile(r'(?:[ \t]*(?:#[^\n]*)?\n)+[ \t]*') +def _p_toml(s): + stmts = [] + _p_ews(s) + with s: + stmts.append(_p_stmt(s)) + while True: + s.commit() + s.expect_re(_stmtsep_re) + stmts.append(_p_stmt(s)) + _p_ews(s) + s.expect_eof() + return stmts + +class _TimeZone(datetime.tzinfo): + def __init__(self, offset): + self._offset = offset + + def utcoffset(self, dt): + return self._offset + + def dst(self, dt): + return None + + def tzname(self, dt): + m = self._offset.total_seconds() // 60 + if m < 0: + res = '-' + m = -m + else: + res = '+' + h = m // 60 + m = m - h * 60 + return '{}{:.02}{:.02}'.format(res, h, m) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py new file mode 100755 index 0000000..19a8c6e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/pytoml/writer.py @@ -0,0 +1,127 @@ +from __future__ import unicode_literals +import io, datetime, math, sys + +if sys.version_info[0] == 3: + long = int + unicode = str + + +def dumps(obj, sort_keys=False): + fout = io.StringIO() + dump(obj, fout, sort_keys=sort_keys) + return fout.getvalue() + + +_escapes = {'\n': 'n', '\r': 'r', '\\': '\\', '\t': 't', '\b': 'b', '\f': 'f', '"': '"'} + + +def _escape_string(s): + res = [] + start = 0 + + def flush(): + if start != i: + res.append(s[start:i]) + return i + 1 + + i = 0 + while i < len(s): + c = s[i] + if c in '"\\\n\r\t\b\f': + start = flush() + res.append('\\' + _escapes[c]) + elif ord(c) < 0x20: + start = flush() + res.append('\\u%04x' % ord(c)) + i += 1 + + flush() + return '"' + ''.join(res) + '"' + + +def _escape_id(s): + if any(not c.isalnum() and c not in '-_' for c in s): + return _escape_string(s) + return s + + +def _format_list(v): + return '[{0}]'.format(', '.join(_format_value(obj) for obj in v)) + +# Formula from: +# https://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds +# Once support for py26 is dropped, this can be replaced by td.total_seconds() +def _total_seconds(td): + return ((td.microseconds + + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.0**6) + +def _format_value(v): + if isinstance(v, bool): + return 'true' if v else 'false' + if isinstance(v, int) or isinstance(v, long): + return unicode(v) + if isinstance(v, float): + if math.isnan(v) or math.isinf(v): + raise ValueError("{0} is not a valid TOML value".format(v)) + else: + return repr(v) + elif isinstance(v, unicode) or isinstance(v, bytes): + return _escape_string(v) + elif isinstance(v, datetime.datetime): + offs = v.utcoffset() + offs = _total_seconds(offs) // 60 if offs is not None else 0 + + if offs == 0: + suffix = 'Z' + else: + if offs > 0: + suffix = '+' + else: + suffix = '-' + offs = -offs + suffix = '{0}{1:.02}{2:.02}'.format(suffix, offs // 60, offs % 60) + + if v.microsecond: + return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix + else: + return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix + elif isinstance(v, list): + return _format_list(v) + else: + raise RuntimeError(v) + + +def dump(obj, fout, sort_keys=False): + tables = [((), obj, False)] + + while tables: + name, table, is_array = tables.pop() + if name: + section_name = '.'.join(_escape_id(c) for c in name) + if is_array: + fout.write('[[{0}]]\n'.format(section_name)) + else: + fout.write('[{0}]\n'.format(section_name)) + + table_keys = sorted(table.keys()) if sort_keys else table.keys() + new_tables = [] + has_kv = False + for k in table_keys: + v = table[k] + if isinstance(v, dict): + new_tables.append((name + (k,), v, False)) + elif isinstance(v, list) and v and all(isinstance(o, dict) for o in v): + new_tables.extend((name + (k,), d, True) for d in v) + elif v is None: + # based on mojombo's comment: https://github.com/toml-lang/toml/issues/146#issuecomment-25019344 + fout.write( + '#{} = null # To use: uncomment and replace null with value\n'.format(_escape_id(k))) + has_kv = True + else: + fout.write('{0} = {1}\n'.format(_escape_id(k), _format_value(v))) + has_kv = True + + tables.extend(reversed(new_tables)) + + if (name or has_kv) and tables: + fout.write('\n') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py new file mode 100755 index 0000000..f9565cb --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__init__.py @@ -0,0 +1,123 @@ +# -*- 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 + >>> 'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('http://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key2": "value2", + "key1": "value1" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at <http://python-requests.org>. + +:copyright: (c) 2017 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +from pip._vendor import urllib3 +from pip._vendor import chardet +import warnings +from .exceptions import RequestsDependencyWarning + + +def check_compatibility(urllib3_version, chardet_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.22 + assert major == 1 + assert minor >= 21 + assert minor <= 22 + + # Check chardet for compatibility. + major, minor, patch = chardet_version.split('.')[:3] + major, minor, patch = int(major), int(minor), int(patch) + # chardet >= 3.0.2, < 3.1.0 + assert major == 3 + assert minor < 1 + assert patch >= 2 + + +# Check imported dependencies for compatibility. +try: + check_compatibility(urllib3.__version__, chardet.__version__) +except (AssertionError, ValueError): + warnings.warn("urllib3 ({0}) or chardet ({1}) doesn't match a supported " + "version!".format(urllib3.__version__, chardet.__version__), + RequestsDependencyWarning) + +# Attempt to enable urllib3's SNI support, if possible +from pip._internal.compat import WINDOWS +if not WINDOWS: + try: + from pip._vendor.urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() + except ImportError: + pass + +# urllib3's DependencyWarnings should be silenced. +from pip._vendor.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 +) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py new file mode 100755 index 0000000..d380286 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/__version__.py @@ -0,0 +1,14 @@ +# .-. .-. .-. . . .-. .-. .-. .-. +# |( |- |.| | | |- `-. | `-. +# ' ' `-' `-`.`-' `-' `-' ' `-' + +__title__ = 'requests' +__description__ = 'Python HTTP for Humans.' +__url__ = 'http://python-requests.org' +__version__ = '2.18.4' +__build__ = 0x021804 +__author__ = 'Kenneth Reitz' +__author_email__ = 'me@kennethreitz.org' +__license__ = 'Apache 2.0' +__copyright__ = 'Copyright 2017 Kenneth Reitz' +__cake__ = u'\u2728 \U0001f370 \u2728' diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/_internal_utils.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/_internal_utils.py new file mode 100755 index 0000000..405b025 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py new file mode 100755 index 0000000..c50585c --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/adapters.py @@ -0,0 +1,525 @@ +# -*- 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 pip._vendor.urllib3.poolmanager import PoolManager, proxy_from_url +from pip._vendor.urllib3.response import HTTPResponse +from pip._vendor.urllib3.util import Timeout as TimeoutSauce +from pip._vendor.urllib3.util.retry import Retry +from pip._vendor.urllib3.exceptions import ClosedPoolError +from pip._vendor.urllib3.exceptions import ConnectTimeoutError +from pip._vendor.urllib3.exceptions import HTTPError as _HTTPError +from pip._vendor.urllib3.exceptions import MaxRetryError +from pip._vendor.urllib3.exceptions import NewConnectionError +from pip._vendor.urllib3.exceptions import ProxyError as _ProxyError +from pip._vendor.urllib3.exceptions import ProtocolError +from pip._vendor.urllib3.exceptions import ReadTimeoutError +from pip._vendor.urllib3.exceptions import SSLError as _SSLError +from pip._vendor.urllib3.exceptions import ResponseError + +from .models import Response +from .compat import urlparse, basestring +from .utils import (DEFAULT_CA_BUNDLE_PATH, 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) +from .auth import _basic_auth_str + +try: + from pip._vendor.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 <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) <timeouts>` 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 <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 dict((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 <requests.adapters.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 <requests.adapters.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 <requests.adapters.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 = 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: {0}".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: {0}".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: {0}".format(conn.key_file)) + + def build_response(self, req, resp): + """Builds a :class:`Response <requests.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 <requests.adapters.HTTPAdapter>` + + :param req: The :class:`PreparedRequest <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 <requests.adapters.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_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 <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <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 <requests.adapters.HTTPAdapter>`. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <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 <requests.adapters.HTTPAdapter>`. + + :param proxies: 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 <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) <timeouts>` 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 + """ + + conn = self.get_connection(request.url, proxies) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers(request) + + 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 {0}. 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: + low_conn.putrequest(request.method, + url, + skip_accept_encoding=True) + + 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+ versions, use buffering of HTTP + # responses + r = low_conn.getresponse(buffering=True) + except TypeError: + # For compatibility with Python 2.6 versions and back + 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) + else: + raise + + return self.build_response(request, resp) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py new file mode 100755 index 0000000..f9ffabf --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/api.py @@ -0,0 +1,152 @@ +# -*- 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 <Request>`. + + :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 or list of tuples ``[(key, value)]`` (will be form-encoded), 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 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) <timeouts>` 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 <Response>` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'http://httpbin.org/get') + <Response [200]> + """ + + # 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 or bytes to be sent in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + 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 <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + 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. + :return: :class:`Response <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 (will be form-encoded), 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 <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 (will be form-encoded), 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 <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 (will be form-encoded), 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 <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 <Response>` object + :rtype: requests.Response + """ + + return request('delete', url, **kwargs) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py new file mode 100755 index 0000000..73e4534 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/auth.py @@ -0,0 +1,293 @@ +# -*- 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 ({0!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 ({0!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(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 + + 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/requests/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/certs.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/certs.py new file mode 100755 index 0000000..9742f6e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 pip._vendor.certifi import where + +if __name__ == '__main__': + print(where()) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py new file mode 100755 index 0000000..4cea25e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/compat.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- + +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module handles import compatibility issues between Python 2 and +Python 3. +""" + +from pip._vendor import 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) + +# Note: We've patched out simplejson support in pip because it prevents +# upgrading simplejson on Windows. +# try: +# import simplejson as json +# except (ImportError, SyntaxError): +# # simplejson does not support Python 3.2, it throws a SyntaxError +# # because of u'...' Unicode literals. +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 + + from pip._vendor.urllib3.packages.ordered_dict import OrderedDict + + builtin_str = str + bytes = str + str = unicode + basestring = basestring + numeric_types = (int, long, float) + integer_types = (int, long) + +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 + from collections import OrderedDict + + builtin_str = str + str = str + bytes = bytes + basestring = (str, bytes) + numeric_types = (int, float) + integer_types = (int,) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py new file mode 100755 index 0000000..e69d22e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/cookies.py @@ -0,0 +1,542 @@ +# -*- 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 +import collections + +from ._internal_utils import to_native_string +from .compat import cookielib, urlparse, urlunparse, Morsel + +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, collections.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.update(self) + return new_cj + + +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 = dict( + 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. + """ + 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. + """ + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py new file mode 100755 index 0000000..377c4c2 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/exceptions.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from pip._vendor.urllib3.exceptions import HTTPError as BaseHTTPError + + +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 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 schema (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """See defaults.py for valid schemas.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow 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.""" + pass + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + pass + + +class RequestsDependencyWarning(RequestsWarning): + """An imported dependency doesn't match the expected version range.""" + pass diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py new file mode 100755 index 0000000..28385f8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/help.py @@ -0,0 +1,120 @@ +"""Module containing bug report helper(s).""" +from __future__ import print_function + +import json +import platform +import sys +import ssl + +from pip._vendor import idna +from pip._vendor import urllib3 +from pip._vendor import chardet + +from . import __version__ as requests_version + +try: + from .packages.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__} + 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__', ''), + } + + # OPENSSL_VERSION_NUMBER doesn't exist in the Python 2.6 ssl module. + system_ssl = getattr(ssl, 'OPENSSL_VERSION_NUMBER', None) + 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, + 'pyOpenSSL': pyopenssl_info, + 'urllib3': urllib3_info, + 'chardet': chardet_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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/hooks.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/hooks.py new file mode 100755 index 0000000..14db0c8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/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 dict((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 dict() + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py new file mode 100755 index 0000000..6f5b0fb --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/models.py @@ -0,0 +1,948 @@ +# -*- coding: utf-8 -*- + +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import collections +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/requests/requests/issues/3578. +import encodings.idna + +from pip._vendor.urllib3.fields import RequestField +from pip._vendor.urllib3.filepost import encode_multipart_formdata +from pip._vendor.urllib3.util import parse_url +from pip._vendor.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) +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 ( + cookielib, urlunparse, urlsplit, urlencode, str, bytes, + is_py2, chardet, builtin_str, basestring) +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 + else: + fdata = fp.read() + + 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, collections.Callable): + self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if isinstance(h, collections.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 <Request>` object. + + Used to prepare a :class:`PreparedRequest <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 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: dictionary of URL parameters to append to the URL. + :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', 'http://httpbin.org/get') + >>> req.prepare() + <PreparedRequest [GET]> + """ + + 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 '<Request [%s]>' % (self.method) + + def prepare(self): + """Constructs a :class:`PreparedRequest <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 <PreparedRequest>` object, + containing the exact bytes that will be sent to the server. + + Generated from either a :class:`Request <Request>` object or manually. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'http://httpbin.org/get') + >>> r = req.prepare() + <PreparedRequest [GET]> + + >>> s = requests.Session() + >>> s.send(r) + <Response [200]> + """ + + 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 '<PreparedRequest [%s]>' % (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): + from pip._vendor 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/requests/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 schema 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'*'): + 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' + body = complexjson.dumps(json) + if not isinstance(body, bytes): + body = body.encode('utf-8') + + is_stream = all([ + hasattr(data, '__iter__'), + not isinstance(data, (basestring, list, tuple, collections.Mapping)) + ]) + + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + if is_stream: + 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 <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 <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 <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 <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 dict( + (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 '<Response [%s]>' % (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. + + 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 chardet library.""" + 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=None, 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 = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes() + + 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 + ``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 ValueError: 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 chardet 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 + return complexjson.loads(self.text, **kwargs) + + @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 stored :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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py new file mode 100755 index 0000000..c91d9c7 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/packages.py @@ -0,0 +1,16 @@ +import sys + +# This code exists for backwards compatibility reasons. +# I don't like it either. Just look the other way. :) + +for package in ('urllib3', 'idna', 'chardet'): + vendored_package = "pip._vendor." + package + locals()[package] = __import__(vendored_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 == vendored_package or mod.startswith(vendored_package + '.'): + unprefixed_mod = mod[len("pip._vendor."):] + sys.modules['pip._vendor.requests.packages.' + unprefixed_mod] = sys.modules[mod] + +# Kinda cool, though, right? diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py new file mode 100755 index 0000000..d8eafa8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/sessions.py @@ -0,0 +1,737 @@ +# -*- coding: utf-8 -*- + +""" +requests.session +~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +import platform +import time +from collections import Mapping +from datetime import timedelta + +from .auth import _basic_auth_str +from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse +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 +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 +) + +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 platform.system() == 'Windows': + try: # Python 3.3+ + 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 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) + 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 %s redirects.' % 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 = '%s:%s' % (to_native_string(parsed_rurl.scheme), url) + + # The scheme should be lower case... + parsed = urlparse(url) + 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/requests/requests/issues/1084 + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + # https://github.com/requests/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 + try: + del headers['Cookie'] + except KeyError: + pass + + # 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: + # If we get redirected to a new host, we should strip out any + # authentication headers. + original_parsed = urlparse(response.request.url) + redirect_parsed = urlparse(url) + + if (original_parsed.hostname != redirect_parsed.hostname): + 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) + + return + + 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 + """ + proxies = proxies if proxies is not None else {} + headers = prepared_request.headers + url = prepared_request.url + scheme = urlparse(url).scheme + new_proxies = proxies.copy() + no_proxy = proxies.get('no_proxy') + + bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy) + if self.trust_env and not bypass_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) + + 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 + + # http://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('http://httpbin.org/get') + <Response [200]> + + Or as a context manager:: + + >>> with requests.Session() as s: + >>> s.get('http://httpbin.org/get') + <Response [200]> + """ + + __attrs__ = [ + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', + 'cert', 'prefetch', 'adapters', 'stream', 'trust_env', + 'max_redirects', + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request <Request>` sent from this + #: :class:`Session <Session>`. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request <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 <Request>`. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request <Request>`. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + 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 <requests.cookies.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 <PreparedRequest>` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request <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 <Request>`, prepares it and sends it. + Returns :class:`Response <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, 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) <timeouts>` 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``. + :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, 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, 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, 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) + kwargs.setdefault('proxies', self.proxies) + + # 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) + + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + + # Resolve redirects if allowed. + history = [resp for resp in gen] if allow_redirects else [] + + # 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): + return adapter + + # Nothing matches :-/ + raise InvalidSchema("No connection adapters were found for '%s'" % 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 = dict((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. + + :rtype: Session + """ + + return Session() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py new file mode 100755 index 0000000..85d9bbc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/status_codes.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +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') + +for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith(('\\', '/')): + setattr(codes, title.upper(), code) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py new file mode 100755 index 0000000..ce775ba --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/structures.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +import collections + +from .compat import OrderedDict + + +class CaseInsensitiveDict(collections.MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``collections.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, collections.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 '<lookup \'%s\'>' % (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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py new file mode 100755 index 0000000..fc4f894 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/requests/utils.py @@ -0,0 +1,904 @@ +# -*- coding: utf-8 -*- + +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import cgi +import codecs +import collections +import contextlib +import io +import os +import platform +import re +import socket +import struct +import warnings + +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, OrderedDict, unquote, getproxies, + proxy_bypass, urlunparse, basestring, integer_types, is_py3, + proxy_bypass_environment, getproxies_environment) +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() + + +if platform.system() == 'Windows': + # provide a proxy_bypass version on Windows without DNS lookups + + def proxy_bypass_registry(host): + if is_py3: + import winreg + else: + import _winreg as winreg + try: + internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + proxyEnable = winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0] + 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 + # '<local>' 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 == '<local>': + 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: + 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 useable 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.""" + + try: + from netrc import netrc, NetrcParseError + + netrc_path = None + + for f in NETRC_FILES: + try: + loc = os.path.expanduser('~/{0}'.format(f)) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See http://bugs.python.org/issue20164 & + # https://github.com/requests/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 + + # AppEngine 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 from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + ValueError: need more than 1 value to unpack + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :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') + 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, collections.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'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I) + pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return (charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content)) + + +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 = cgi.parse_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + if 'text' in content_type: + return 'ISO-8859-1' + + +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 + """ + 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') + netloc = urlparse(url).netloc + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the netloc, both with and without the port. + no_proxy = ( + host for host in no_proxy.replace(' ', '').split(',') if host + ) + + ip = netloc.split(':')[0] + if is_ipv4_address(ip): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(ip, proxy_ip): + return True + elif ip == 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: + for host in no_proxy: + if netloc.endswith(host) or netloc.split(':')[0].endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + # If the system proxy settings indicate that this URL should be bypassed, + # don't proxy. + # The proxy_bypass function is incredibly buggy on OS X in early versions + # of Python 2.6, so allow this call to fail. Only catch the specific + # exceptions we've seen, though: this call failing in other ways can reveal + # legitimate problems. + with set_environ('no_proxy', no_proxy_arg): + try: + bypass = proxy_bypass(netloc) + 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 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': ', '.join(('gzip', 'deflate')), + 'Accept': '*/*', + 'Connection': 'keep-alive', + }) + + +def parse_header_links(value): + """Return a dict of parsed link headers proxies. + + i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = ' \'"' + + 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 + """ + scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme) + + # urlparse is a finicky beast, and sometimes decides that there isn't a + # netloc present. Assume that it's being over-cautious, and switch netloc + # and path if urlparse decided there was no netloc. + if not netloc: + netloc, path = path, netloc + + return urlunparse((scheme, netloc, path, params, 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py new file mode 100755 index 0000000..f8d743b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/retrying.py @@ -0,0 +1,267 @@ +## Copyright 2013-2014 Ray Holder +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. + +import random +from pip._vendor import six +import sys +import time +import traceback + + +# sys.maxint / 2, since Python 3.2 doesn't have a sys.maxint... +MAX_WAIT = 1073741823 + + +def retry(*dargs, **dkw): + """ + Decorator function that instantiates the Retrying object + @param *dargs: positional arguments passed to Retrying object + @param **dkw: keyword arguments passed to the Retrying object + """ + # support both @retry and @retry() as valid syntax + if len(dargs) == 1 and callable(dargs[0]): + def wrap_simple(f): + + @six.wraps(f) + def wrapped_f(*args, **kw): + return Retrying().call(f, *args, **kw) + + return wrapped_f + + return wrap_simple(dargs[0]) + + else: + def wrap(f): + + @six.wraps(f) + def wrapped_f(*args, **kw): + return Retrying(*dargs, **dkw).call(f, *args, **kw) + + return wrapped_f + + return wrap + + +class Retrying(object): + + def __init__(self, + stop=None, wait=None, + stop_max_attempt_number=None, + stop_max_delay=None, + wait_fixed=None, + wait_random_min=None, wait_random_max=None, + wait_incrementing_start=None, wait_incrementing_increment=None, + wait_exponential_multiplier=None, wait_exponential_max=None, + retry_on_exception=None, + retry_on_result=None, + wrap_exception=False, + stop_func=None, + wait_func=None, + wait_jitter_max=None): + + self._stop_max_attempt_number = 5 if stop_max_attempt_number is None else stop_max_attempt_number + self._stop_max_delay = 100 if stop_max_delay is None else stop_max_delay + self._wait_fixed = 1000 if wait_fixed is None else wait_fixed + self._wait_random_min = 0 if wait_random_min is None else wait_random_min + self._wait_random_max = 1000 if wait_random_max is None else wait_random_max + self._wait_incrementing_start = 0 if wait_incrementing_start is None else wait_incrementing_start + self._wait_incrementing_increment = 100 if wait_incrementing_increment is None else wait_incrementing_increment + self._wait_exponential_multiplier = 1 if wait_exponential_multiplier is None else wait_exponential_multiplier + self._wait_exponential_max = MAX_WAIT if wait_exponential_max is None else wait_exponential_max + self._wait_jitter_max = 0 if wait_jitter_max is None else wait_jitter_max + + # TODO add chaining of stop behaviors + # stop behavior + stop_funcs = [] + if stop_max_attempt_number is not None: + stop_funcs.append(self.stop_after_attempt) + + if stop_max_delay is not None: + stop_funcs.append(self.stop_after_delay) + + if stop_func is not None: + self.stop = stop_func + + elif stop is None: + self.stop = lambda attempts, delay: any(f(attempts, delay) for f in stop_funcs) + + else: + self.stop = getattr(self, stop) + + # TODO add chaining of wait behaviors + # wait behavior + wait_funcs = [lambda *args, **kwargs: 0] + if wait_fixed is not None: + wait_funcs.append(self.fixed_sleep) + + if wait_random_min is not None or wait_random_max is not None: + wait_funcs.append(self.random_sleep) + + if wait_incrementing_start is not None or wait_incrementing_increment is not None: + wait_funcs.append(self.incrementing_sleep) + + if wait_exponential_multiplier is not None or wait_exponential_max is not None: + wait_funcs.append(self.exponential_sleep) + + if wait_func is not None: + self.wait = wait_func + + elif wait is None: + self.wait = lambda attempts, delay: max(f(attempts, delay) for f in wait_funcs) + + else: + self.wait = getattr(self, wait) + + # retry on exception filter + if retry_on_exception is None: + self._retry_on_exception = self.always_reject + else: + self._retry_on_exception = retry_on_exception + + # TODO simplify retrying by Exception types + # retry on result filter + if retry_on_result is None: + self._retry_on_result = self.never_reject + else: + self._retry_on_result = retry_on_result + + self._wrap_exception = wrap_exception + + def stop_after_attempt(self, previous_attempt_number, delay_since_first_attempt_ms): + """Stop after the previous attempt >= stop_max_attempt_number.""" + return previous_attempt_number >= self._stop_max_attempt_number + + def stop_after_delay(self, previous_attempt_number, delay_since_first_attempt_ms): + """Stop after the time from the first attempt >= stop_max_delay.""" + return delay_since_first_attempt_ms >= self._stop_max_delay + + def no_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Don't sleep at all before retrying.""" + return 0 + + def fixed_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Sleep a fixed amount of time between each retry.""" + return self._wait_fixed + + def random_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """Sleep a random amount of time between wait_random_min and wait_random_max""" + return random.randint(self._wait_random_min, self._wait_random_max) + + def incrementing_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + """ + Sleep an incremental amount of time after each attempt, starting at + wait_incrementing_start and incrementing by wait_incrementing_increment + """ + result = self._wait_incrementing_start + (self._wait_incrementing_increment * (previous_attempt_number - 1)) + if result < 0: + result = 0 + return result + + def exponential_sleep(self, previous_attempt_number, delay_since_first_attempt_ms): + exp = 2 ** previous_attempt_number + result = self._wait_exponential_multiplier * exp + if result > self._wait_exponential_max: + result = self._wait_exponential_max + if result < 0: + result = 0 + return result + + def never_reject(self, result): + return False + + def always_reject(self, result): + return True + + def should_reject(self, attempt): + reject = False + if attempt.has_exception: + reject |= self._retry_on_exception(attempt.value[1]) + else: + reject |= self._retry_on_result(attempt.value) + + return reject + + def call(self, fn, *args, **kwargs): + start_time = int(round(time.time() * 1000)) + attempt_number = 1 + while True: + try: + attempt = Attempt(fn(*args, **kwargs), attempt_number, False) + except: + tb = sys.exc_info() + attempt = Attempt(tb, attempt_number, True) + + if not self.should_reject(attempt): + return attempt.get(self._wrap_exception) + + delay_since_first_attempt_ms = int(round(time.time() * 1000)) - start_time + if self.stop(attempt_number, delay_since_first_attempt_ms): + if not self._wrap_exception and attempt.has_exception: + # get() on an attempt with an exception should cause it to be raised, but raise just in case + raise attempt.get() + else: + raise RetryError(attempt) + else: + sleep = self.wait(attempt_number, delay_since_first_attempt_ms) + if self._wait_jitter_max: + jitter = random.random() * self._wait_jitter_max + sleep = sleep + max(0, jitter) + time.sleep(sleep / 1000.0) + + attempt_number += 1 + + +class Attempt(object): + """ + An Attempt encapsulates a call to a target function that may end as a + normal return value from the function or an Exception depending on what + occurred during the execution. + """ + + def __init__(self, value, attempt_number, has_exception): + self.value = value + self.attempt_number = attempt_number + self.has_exception = has_exception + + def get(self, wrap_exception=False): + """ + Return the return value of this Attempt instance or raise an Exception. + If wrap_exception is true, this Attempt is wrapped inside of a + RetryError before being raised. + """ + if self.has_exception: + if wrap_exception: + raise RetryError(self) + else: + six.reraise(self.value[0], self.value[1], self.value[2]) + else: + return self.value + + def __repr__(self): + if self.has_exception: + return "Attempts: {0}, Error:\n{1}".format(self.attempt_number, "".join(traceback.format_tb(self.value[2]))) + else: + return "Attempts: {0}, Value: {1}".format(self.attempt_number, self.value) + + +class RetryError(Exception): + """ + A RetryError encapsulates the last Attempt instance right before giving up. + """ + + def __init__(self, last_attempt): + self.last_attempt = last_attempt + + def __str__(self): + return "RetryError[{0}]".format(self.last_attempt) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py new file mode 100755 index 0000000..e36380b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/six.py @@ -0,0 +1,891 @@ +# Copyright (c) 2010-2017 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 <benjamin@python.org>" +__version__ = "1.11.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 + + +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 __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 + +_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("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_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 + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +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" +_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) + + +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, 2): + exec_("""def raise_from(value, from_value): + try: + if from_value is None: + raise value + raise value from from_value + finally: + value = None +""") +elif sys.version_info[:2] > (3, 2): + 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): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +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): + return meta(name, 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) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py new file mode 100755 index 0000000..1bffade --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/__init__.py @@ -0,0 +1,97 @@ +""" +urllib3 - Thread-safe connection pooling and re-using. +""" + +from __future__ import absolute_import +import warnings + +from .connectionpool import ( + HTTPConnectionPool, + HTTPSConnectionPool, + connection_from_url +) + +from . import exceptions +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.url import get_host +from .util.timeout import Timeout +from .util.retry import Retry + + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' +__license__ = 'MIT' +__version__ = '1.22' + +__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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py new file mode 100755 index 0000000..ecbf6b0 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/_collections.py @@ -0,0 +1,319 @@ +from __future__ import absolute_import +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 + + +try: # Python 2.7+ + from collections import OrderedDict +except ImportError: + from .packages.ordered_dict import OrderedDict +from .packages.six import iterkeys, itervalues, PY3 + + +__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 not PY3: # 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. + headers = [] + + for line in message.headers: + if line.startswith((' ', '\t')): + key, value = headers[-1] + headers[-1] = (key, value + '\r\n' + line.rstrip()) + continue + + key, value = line.split(':', 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py new file mode 100755 index 0000000..67090e3 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connection.py @@ -0,0 +1,373 @@ +from __future__ import absolute_import +import datetime +import logging +import os +import sys +import socket +from socket import error as SocketError, timeout as SocketTimeout +import warnings +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 + +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 + + +from .exceptions import ( + NewConnectionError, + ConnectTimeoutError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .packages.ssl_match_hostname import match_hostname, CertificateError + +from .util.ssl_ import ( + resolve_cert_reqs, + resolve_ssl_version, + assert_fingerprint, + create_urllib3_context, + ssl_wrap_socket +) + + +from .util import connection + +from ._collections import HTTPHeaderDict + +log = logging.getLogger(__name__) + +port_by_scheme = { + 'http': 80, + 'https': 443, +} + +# When updating RECENT_DATE, move it to +# within two years of the current date, and no +# earlier than 6 months ago. +RECENT_DATE = datetime.date(2016, 1, 1) + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + pass + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on httplib.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. + + .. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x + + - ``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:: + + 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 + + def __init__(self, *args, **kw): + if six.PY3: # Python 3 + kw.pop('strict', None) + + # Pre-set source_address in case we have an older Python like 2.6. + self.source_address = kw.get('source_address') + + if sys.version_info < (2, 7): # Python 2.6 + # _HTTPConnection on Python 2.6 will balk at this keyword arg, but + # not newer versions. We can still use it when creating a + # connection though, so we pop it *after* we have saved it as + # self.source_address. + kw.pop('source_address', None) + + #: 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) + + # Superclass also sets self.source_address in Python 2.7+. + _HTTPConnection.__init__(self, *args, **kw) + + 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.host, self.port), self.timeout, **extra_kw) + + except SocketTimeout as e: + 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 _prepare_conn(self, conn): + self.sock = conn + # the _tunnel_host attribute was added in python 2.6.3 (via + # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do + # not have them. + if getattr(self, '_tunnel_host', None): + # 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 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 = HTTPHeaderDict(headers if headers is not None else {}) + skip_accept_encoding = 'accept-encoding' in headers + skip_host = 'host' in headers + self.putrequest( + method, + url, + skip_accept_encoding=skip_accept_encoding, + skip_host=skip_host + ) + for header, value in headers.items(): + self.putheader(header, value) + if 'transfer-encoding' not in headers: + self.putheader('Transfer-Encoding', 'chunked') + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (six.binary_type,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, six.binary_type): + chunk = chunk.encode('utf8') + len_str = hex(len(chunk))[2:] + self.send(len_str.encode('utf-8')) + self.send(b'\r\n') + self.send(chunk) + self.send(b'\r\n') + + # After the if clause, to always have a closed body + self.send(b'0\r\n\r\n') + + +class HTTPSConnection(HTTPConnection): + default_port = port_by_scheme['https'] + + ssl_version = None + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, **kw): + + HTTPConnection.__init__(self, host, port, strict=strict, + timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.ssl_context = ssl_context + + # 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 connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(None), + cert_reqs=resolve_cert_reqs(None), + ) + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ssl_context=self.ssl_context, + ) + + +class VerifiedHTTPSConnection(HTTPSConnection): + """ + Based on httplib.HTTPSConnection but wraps the socket with + SSL certification. + """ + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ssl_version = None + assert_fingerprint = None + + def set_cert(self, key_file=None, cert_file=None, + cert_reqs=None, ca_certs=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided, we can try to guess. If the user gave + # us a cert database, we assume they want to use it: otherwise, if + # they gave us an SSL Context object we should use whatever is set for + # it. + if cert_reqs is None: + if ca_certs or ca_cert_dir: + cert_reqs = 'CERT_REQUIRED' + elif self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + 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) + + def connect(self): + # Add certificate verification + conn = self._new_conn() + + hostname = self.host + if getattr(self, '_tunnel_host', None): + # _tunnel_host was added in Python 2.6.3 + # (See: http://hg.python.org/cpython/rev/0f57b30a152f) + + self.sock = conn + # 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 + + 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 + if self.ssl_context is None: + 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) + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + server_hostname=hostname, + ssl_context=context) + + 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/shazow/urllib3/issues/497 ' + 'for details.)'.format(hostname)), + SubjectAltNameWarning + ) + _match_hostname(cert, self.assert_hostname or hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED or + self.assert_fingerprint is not None + ) + + +def _match_hostname(cert, asserted_hostname): + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.error( + '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 + + +if ssl: + # Make a copy for testing. + UnverifiedHTTPSConnection = HTTPSConnection + HTTPSConnection = VerifiedHTTPSConnection +else: + HTTPSConnection = DummyConnection diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py new file mode 100755 index 0000000..b099ca8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/connectionpool.py @@ -0,0 +1,905 @@ +from __future__ import absolute_import +import errno +import logging +import sys +import warnings + +from socket import error as SocketError, timeout as SocketTimeout +import socket + + +from .exceptions import ( + ClosedPoolError, + ProtocolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + LocationValueError, + MaxRetryError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, + InsecureRequestWarning, + NewConnectionError, +) +from .packages.ssl_match_hostname import CertificateError +from .packages import six +from .packages.six.moves import queue +from .connection import ( + port_by_scheme, + DummyConnection, + HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, + HTTPException, BaseSSLError, +) +from .request import RequestMethods +from .response import HTTPResponse + +from .util.connection import is_connection_dropped +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host, Url + + +if six.PY2: + # Queue is imported for side effects on MS Windows + import Queue as _unused_module_Queue # noqa: F401 + +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`. + """ + + scheme = None + QueueCls = queue.LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _ipv6_host(host).lower() + 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 = set([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:`httplib.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`httplib.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:`httplib.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.connectionpool.ProxyManager`" + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.connectionpool.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, + **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 {} + + # 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', []) + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTP connection (%d): %s", + self.num_connections, self.host) + + 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 + # httplib._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", + self.host) + + # 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.6 + 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 httplib.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # 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 2.6 and older, Python 3 + try: + httplib_response = conn.getresponse() + except Exception as e: + # Remove the TypeError from the exception chain in Python 3; + # otherwise it looks like a programming error was the cause. + 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. + """ + # 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) + + host = _ipv6_host(host).lower() + + # 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 body: + Data to send in the request body (useful for creating + POST requests, see HTTPConnectionPool.post_url for + more convenience). + + :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` + """ + 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) + + 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] <https://github.com/shazow/urllib3/issues/651> + release_this_conn = release_conn + + # Merge the proxy headers. Only do this in HTTP. We have to copy the + # headers dict so we can safely change it without those changes being + # reflected in anyone else's copy. + if self.scheme == 'http': + 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: + 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 queue.Empty: + # Timed out by queue. + raise EmptyPoolError(self, "No pool connections are available.") + + 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 + if 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, body_pos=body_pos, + **response_kw) + + def drain_and_release_conn(response): + try: + # discard any remaining response body, the connection will be + # released back to the pool once the entire response is read + response.read() + except (TimeoutError, HTTPException, SocketError, ProtocolError, + BaseSSLError, SSLError) as e: + pass + + # 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: + # Drain and release the connection for this response, since + # we're not returning it to be released manually. + drain_and_release_conn(response) + raise + return response + + # drain and return the connection to the pool before recursing + drain_and_release_conn(response) + + 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, 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: + # Drain and release the connection for this response, since + # we're not returning it to be released manually. + drain_and_release_conn(response) + raise + return response + + # drain and return the connection to the pool before recursing + drain_and_release_conn(response) + + 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, + body_pos=body_pos, **response_kw) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + When Python is compiled with the :mod:`ssl` module, then + :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, + instead of :class:`.HTTPSConnection`. + + :class:`.VerifiedHTTPSConnection` 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``, and ``ssl_version`` 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, + 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) + + if ca_certs and cert_reqs is None: + cert_reqs = 'CERT_REQUIRED' + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + 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, + 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): + """ + Establish tunnel connection early, because otherwise httplib + would improperly set Host: header to proxy's IP:port. + """ + # Python 2.7+ + try: + set_tunnel = conn.set_tunnel + except AttributeError: # Platform-specific: Python 2.6 + set_tunnel = conn._set_tunnel + + if sys.version_info <= (2, 6, 4) and not self.proxy_headers: # Python 2.6.4 and older + set_tunnel(self._proxy_host, self.port) + else: + set_tunnel(self._proxy_host, self.port, self.proxy_headers) + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTPS connection (%d): %s", + self.num_connections, self.host) + + 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, **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. ' + 'Adding certificate verification is strongly advised. See: ' + 'https://urllib3.readthedocs.io/en/latest/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 _ipv6_host(host): + """ + Process IPv6 address literals + """ + + # 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 + # + # Also if an IPv6 address literal has a zone identifier, the + # percent sign might be URIencoded, convert it back into ASCII + if host.startswith('[') and host.endswith(']'): + host = host.replace('%25', '%').strip('[]') + return host diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py new file mode 100755 index 0000000..9787b02 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/bindings.py @@ -0,0 +1,593 @@ +""" +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 <will@wbond.net> + + 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.util import find_library +from ctypes import ( + c_void_p, c_int32, c_char_p, c_size_t, c_byte, c_uint32, c_ulong, c_long, + c_bool +) +from ctypes import CDLL, POINTER, CFUNCTYPE + + +security_path = find_library('Security') +if not security_path: + raise ImportError('The library Security could not be found') + + +core_foundation_path = find_library('CoreFoundation') +if not core_foundation_path: + raise ImportError('The library CoreFoundation could not be found') + + +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] + ) + ) + +Security = CDLL(security_path, use_errno=True) +CoreFoundation = CDLL(core_foundation_path, use_errno=True) + +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 + + 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 + + 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. + 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_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2 + 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_DSS_WITH_AES_256_CBC_SHA256 = 0x006A + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038 + 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_DSS_WITH_AES_128_CBC_SHA256 = 0x0040 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032 + 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_CHACHA20_POLY1305_SHA256 = 0x1303 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py new file mode 100755 index 0000000..4e5c0db --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/_securetransport/low_level.py @@ -0,0 +1,343 @@ +""" +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 re +import os +import ssl +import tempfile + +from .bindings import Security, CoreFoundation, CFConst + + +# 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 _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. + """ + 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) + + 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.b64encode(random_bytes[:8]).decode('utf-8') + password = base64.b64encode(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) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py new file mode 100755 index 0000000..fc00d17 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/appengine.py @@ -0,0 +1,296 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + +Example usage:: + + from pip._vendor.urllib3 import PoolManager + from pip._vendor.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 <https://cloud.google.com/appengine/docs/python/\ +urlfetch/#Python_Quotas_and_limits>`_ 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 + <https://cloud.google.com/appengine/docs/python/sockets/\ + #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 +<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import +import logging +import os +import warnings +from ..packages.six.moves.urllib.parse import urljoin + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + TimeoutError, + SSLError +) + +from ..packages.six import BytesIO +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.timeout import Timeout +from ..util.retry import Retry + +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 + <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + + 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 megabtyes. + * 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.") + + if is_prod_appengine_mvms(): + raise AppEnginePlatformError( + "Use normal urllib3.PoolManager instead of AppEngineManager" + "on Managed VMs, as using URLFetch is not necessary 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/latest/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) + + return HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **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 + + +def is_appengine(): + return (is_local_appengine() or + is_prod_appengine() or + is_prod_appengine_mvms()) + + +def is_appengine_sandbox(): + return is_appengine() and not is_prod_appengine_mvms() + + +def is_local_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Development/' in os.environ['SERVER_SOFTWARE']) + + +def is_prod_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and + not is_prod_appengine_mvms()) + + +def is_prod_appengine_mvms(): + return os.environ.get('GAE_VM', False) == 'true' diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py new file mode 100755 index 0000000..888e0ad --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/ntlmpool.py @@ -0,0 +1,112 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +from logging import getLogger +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + + +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 = {} + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py new file mode 100755 index 0000000..f13e2bc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/pyopenssl.py @@ -0,0 +1,455 @@ +""" +SSL with SNI_-support for Python 2. Follow these instructions if you would +like to verify SSL 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: + + 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:: + + 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`_). + +If you want to configure the default list of supported cipher suites, you can +set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +""" +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 + +from socket import timeout, error as SocketError +from io import BytesIO + +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 +from ..packages import six +import sys + +from .. import util + +__all__ = ['inject_into_urllib3', 'extract_from_urllib3'] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_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 + +try: + _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD}) +except AttributeError: + pass + +_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.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.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). + """ + 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. + """ + from pip._vendor import idna + + for prefix in [u'*.', u'.']: + if name.startswith(prefix): + name = name[len(prefix):] + return prefix.encode('ascii') + idna.encode(name) + return idna.encode(name) + + name = idna_encode(name) + if 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, x509.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. + names = [ + ('DNS', _dnsname_to_stdlib(name)) + for name in ext.get_values_for_type(x509.DNSName) + ] + 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 as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b'' + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv(*args, **kwargs) + 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 as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv_into(*args, **kwargs) + + 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: + wr = util.wait_for_write(self.socket, self.socket.gettimeout()) + if not wr: + 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 _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') + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_file(certfile) + if password is not None: + self._ctx.set_passwd_cb(lambda max_length, prompt_twice, userdata: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + 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: + rd = util.wait_for_read(sock, sock.gettimeout()) + if not rd: + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py new file mode 100755 index 0000000..77cf861 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/securetransport.py @@ -0,0 +1,810 @@ +""" +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! +""" +from __future__ import absolute_import + +import contextlib +import ctypes +import errno +import os.path +import shutil +import socket +import ssl +import threading +import weakref + +from .. import util +from ._securetransport.bindings import ( + Security, SecurityConst, CoreFoundation +) +from ._securetransport.low_level import ( + _assert_no_error, _cert_array_from_pem, _temporary_keychain, + _load_client_cert_chain +) + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +try: + memoryview(b'') +except NameError: + raise ImportError("SecureTransport only works on Pythons with memoryview") + +__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 becuase this is how +# SecureTransport wants them. +CIPHER_SUITES = [ + SecurityConst.TLS_AES_256_GCM_SHA384, + SecurityConst.TLS_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_RSA_WITH_AES_128_GCM_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. +_protocol_to_min_max = { + ssl.PROTOCOL_SSLv23: (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 + ) +if hasattr(ssl, "PROTOCOL_TLS"): + _protocol_to_min_max[ssl.PROTOCOL_TLS] = _protocol_to_min_max[ssl.PROTOCOL_SSLv23] + + +def inject_into_urllib3(): + """ + Monkey-patch urllib3 with SecureTransport-backed SSL-support. + """ + 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.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 + buffer = (ctypes.c_char * requested_length).from_address(data_buffer) + buffer_view = memoryview(buffer) + + try: + while read_count < requested_length: + if timeout is None or timeout >= 0: + readables = util.wait_for_read([base_socket], timeout) + if not readables: + raise socket.error(errno.EAGAIN, 'timed out') + + # We need to tell ctypes that we have a buffer that can be + # written to. Upsettingly, we do that like this: + chunk_size = base_socket.recv_into( + buffer_view[read_count:requested_length] + ) + 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: + if error == errno.ECONNRESET: + 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: + writables = util.wait_for_write([base_socket], timeout) + if not writables: + 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: + if error == errno.ECONNRESET: + 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 _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. + """ + # If we disabled cert validation, just say: cool. + if not verify: + return + + # 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 None: + CoreFoundation.CFRelease(cert_array) + + # Ok, now we can look at what the result was. + successes = ( + SecurityConst.kSecTrustResultUnspecified, + SecurityConst.kSecTrustResultProceed + ) + if trust_result.value not in successes: + raise ssl.SSLError( + "certificate verify failed, error code: %d" % + trust_result.value + ) + + def handshake(self, + server_hostname, + verify, + trust_bundle, + min_version, + max_version, + client_cert, + client_key, + client_key_passphrase): + """ + 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() + + # 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 _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 + + @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" + ) + + 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 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 + ) + return wrapped_socket diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py new file mode 100755 index 0000000..6c99a75 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/contrib/socks.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) 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: + +- SOCKS4 +- SOCKS4a +- SOCKS5 +- Usernames and passwords for the SOCKS proxy + +Known Limitations: + +- Currently PySocks does not support contacting remote websites via literal + IPv6 addresses. Any such connection attempt will fail. You must use a domain + name. +- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any + such connection attempt will fail. +""" +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/latest/contrib.html#socks-proxies' + ), + DependencyWarning + ) + raise + +from socket import error as SocketError, 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 as e: + 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 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py new file mode 100755 index 0000000..670a63e --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/exceptions.py @@ -0,0 +1,246 @@ +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." + pass + + +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 + <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. + """ + 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 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 perfoming 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 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 httplib.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 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 InvalidHeader(HTTPError): + "The header provided was somehow invalid." + pass + + +class ProxySchemeUnknown(AssertionError, ValueError): + "ProxyManager does not support the supplied scheme" + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + message = "Not supported proxy scheme %s" % scheme + super(ProxySchemeUnknown, self).__init__(message) + + +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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py new file mode 100755 index 0000000..8e15621 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/fields.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +import email.utils +import mimetypes + +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(name, value): + """ + Helper function to format and quote a single header parameter. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows RFC 2231, as + suggested by 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 a unicode string. + """ + if not any(ch in value for ch in '"\\\r\n'): + result = '%s="%s"' % (name, value) + try: + result.encode('ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + if not six.PY3 and isinstance(value, six.text_type): # Python 2: + value = value.encode('utf-8') + value = email.utils.encode_rfc2231(value, 'utf-8') + value = '%s*=%s' % (name, value) + return value + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. + :param headers: + An optional dict-like object of headers to initially use for the field. + """ + def __init__(self, name, data, filename=None, headers=None): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + + @classmethod + def from_tuples(cls, fieldname, value): + """ + 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) + 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. + + :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 format_header_param(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) typles 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 '; '.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('%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('%s: %s' % (header_name, header_value)) + + lines.append('\r\n') + return '\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 'form-data' + self.headers['Content-Disposition'] += '; '.join([ + '', self._render_parts( + (('name', self._name), ('filename', self._filename)) + ) + ]) + self.headers['Content-Type'] = content_type + self.headers['Content-Location'] = content_location diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py new file mode 100755 index 0000000..e53dedc --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/filepost.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import +import codecs + +from uuid import uuid4 +from io import BytesIO + +from .packages import six +from .packages.six import b +from .fields import RequestField + +writer = codecs.lookup('utf-8')[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + return uuid4().hex + + +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:`mimetools.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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py new file mode 100755 index 0000000..324c551 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from . import ssl_match_hostname + +__all__ = ('ssl_match_hostname', ) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py new file mode 100755 index 0000000..00dee0b --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/backports/makefile.py @@ -0,0 +1,53 @@ +# -*- 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) <= set(["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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py new file mode 100755 index 0000000..62dcb42 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ordered_dict.py @@ -0,0 +1,259 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger, released under the MIT License. +# http://code.activestate.com/recipes/576693/ +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The circular doubly linked list starts and ends with a sentinel element. + # The sentinel element never gets deleted (this simplifies the algorithm). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py new file mode 100755 index 0000000..7bd9225 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 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. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.10.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 + + +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 __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 + +_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("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("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_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_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("email_mime_base", "email.MIMEBase", "email.mime.base"), + 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("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "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"), +] +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 + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +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" +_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) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +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): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +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): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +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(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + 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) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py new file mode 100755 index 0000000..accb927 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py @@ -0,0 +1,19 @@ +import sys + +try: + # Our match_hostname function is the same as 3.5's, so we only want to + # import the match_hostname function if it's at least that good. + if sys.version_info < (3, 5): + raise ImportError("Fallback to vendored code") + + from ssl import CertificateError, match_hostname +except ImportError: + try: + # Backport of the function from a pypi module + from backports.ssl_match_hostname import CertificateError, match_hostname + except ImportError: + # Our vendored copy + from ._implementation import CertificateError, match_hostname + +# Not needed, but documenting what we provide. +__all__ = ('CertificateError', 'match_hostname') diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py new file mode 100755 index 0000000..7272d86 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py @@ -0,0 +1,157 @@ +"""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 +# backports.ssl_match_hostname to continue to be used all the way back to +# python-2.4. +try: + from pip._vendor 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,): + obj = unicode(obj, encoding='ascii', errors='strict') + 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 ValueError: + # Not an IP address (common case) + host_ip = None + except 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: + 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py new file mode 100755 index 0000000..607ae0f --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/poolmanager.py @@ -0,0 +1,440 @@ +from __future__ import absolute_import +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from .connectionpool import port_by_scheme +from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.url import parse_url +from .util.retry import Retry + + +__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') + +# 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_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_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 +) + +#: 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) + + +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 + + 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:`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:`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:`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[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:`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 urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.connectionpool.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) + 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 + + if self.proxy is not None and u.scheme == "http": + 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) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + raise + return response + + kw['retries'] = retries + kw['redirect'] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + 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 contaning 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. + + 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, **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 not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + + connection_pool_kw['_proxy'] = self.proxy + connection_pool_kw['_proxy_headers'] = self.proxy_headers + + 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 u.scheme == "http": + # For proxied HTTPS requests, httplib sets the necessary headers + # on the CONNECT to the proxy. For HTTP, 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py new file mode 100755 index 0000000..9d789d6 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/request.py @@ -0,0 +1,148 @@ +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.connectionpool.HTTPConnectionPool` and + :class:`~urllib3.poolmanager.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 = set(['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 NotImplemented("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() + + 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 + :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :meth:`urllib.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 mimick 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py new file mode 100755 index 0000000..54799ba --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/response.py @@ -0,0 +1,626 @@ +from __future__ import absolute_import +from contextlib import contextmanager +import zlib +import io +import logging +from socket import timeout as SocketTimeout +from socket import error as SocketError + +from ._collections import HTTPHeaderDict +from .exceptions import ( + BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError, + ResponseNotChunked, IncompleteRead, InvalidHeader +) +from .packages.six import string_types as basestring, binary_type, PY3 +from .packages.six.moves import http_client as httplib +from .connection import HTTPException, BaseSSLError +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 = binary_type() + 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 GzipDecoder(object): + + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + return self._obj.decompress(data) + + +def _get_decoder(mode): + if mode == 'gzip': + return GzipDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible to httplib's 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 httplib.HTTPResponse: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, attempts to decode specific content-encoding's based on headers + (like 'gzip' and 'deflate') will be skipped and raw data will be used + instead. + + :param original_response: + When this HTTPResponse wrapper is generated from an httplib.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'] + 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, + retries=None, enforce_content_length=False, request_method=None): + + 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._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + + if body and isinstance(body, (basestring, binary_type)): + 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 + + @property + def data(self): + # For backwords-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 tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``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 and 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 + + elif length is not 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 and content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + try: + if decode_content and self._decoder: + data = self._decoder.decompress(data) + except (IOError, zlib.error) 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 and decode_content: + 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): # Defensive: + # This shouldn't happen but just in case we're missing an edge + # case, let's avoid swallowing SSL errors. + raise + + 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:`httplib.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 + data = None + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) + 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:`httplib.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 PY3: # Python 3 + headers = HTTPHeaderDict(headers.items()) + else: # Python 2 + headers = HTTPHeaderDict.from_httplib(headers) + + # 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 httplib.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() + + @property + def closed(self): + if 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'): + 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 + httplib.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 httplib.IncompleteRead(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 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 httplib.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks.") + + # 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 + + with self._error_catcher(): + 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() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py new file mode 100755 index 0000000..a84b005 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/__init__.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import make_headers +from .response import is_fp_closed +from .ssl_ import ( + SSLContext, + HAS_SNI, + IS_PYOPENSSL, + IS_SECURETRANSPORT, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import ( + current_time, + Timeout, +) + +from .retry import Retry +from .url import ( + get_host, + parse_url, + split_first, + Url, +) +from .wait import ( + wait_for_read, + wait_for_write +) + +__all__ = ( + 'HAS_SNI', + 'IS_PYOPENSSL', + 'IS_SECURETRANSPORT', + 'SSLContext', + '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' +) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py new file mode 100755 index 0000000..31ecd83 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/connection.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import +import socket +from .wait import wait_for_read +from .selectors import HAS_SELECT, SelectorError + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`httplib.HTTPConnection` object. + + Note: For platforms like AppEngine, this will always return ``False`` to + let the platform handle connection recycling transparently for us. + """ + sock = getattr(conn, 'sock', False) + if sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + + if not HAS_SELECT: + return False + + try: + return bool(wait_for_read(sock, timeout=0.0)) + except SelectorError: + return True + + +# 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:`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() + + 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 + + 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/shazow/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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py new file mode 100755 index 0000000..22882b8 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/request.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import +from base64 import b64encode + +from ..packages.six import b, integer_types +from ..exceptions import UnrewindableBodyError + +ACCEPT_ENCODING = 'gzip,deflate' +_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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py new file mode 100755 index 0000000..c2eb49c --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/response.py @@ -0,0 +1,81 @@ +from __future__ import absolute_import +from ..packages.six.moves import http_client as httplib + +from ..exceptions import HeaderParsingError + + +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 headers: Headers to verify. + :type headers: `httplib.HTTPMessage`. + + :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: # Platform-specific: Python 3. + unparsed_data = get_payload() + + 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 conn: + :type conn: :class:`httplib.HTTPResponse` + """ + # 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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py new file mode 100755 index 0000000..2a7e8c1 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/retry.py @@ -0,0 +1,401 @@ +from __future__ import absolute_import +import time +import logging +from collections import namedtuple +from itertools import takewhile +import email +import re + +from ..exceptions import ( + ConnectTimeoutError, + MaxRetryError, + ProtocolError, + ReadTimeoutError, + ResponseError, + InvalidHeader, +) +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"]) + + +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. It's a good idea to set this to some sensibly-high value to + account for unexpected edge cases and avoid infinite retry loops. + + 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 iterable method_whitelist: + 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_METHOD_WHITELIST`. + + Set to a ``False`` value to retry on any verb. + + :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 ``method_whitelist`` + 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.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. + + """ + + DEFAULT_METHOD_WHITELIST = frozenset([ + 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) + + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 + + def __init__(self, total=10, connect=None, read=None, redirect=None, status=None, + method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, + backoff_factor=0, raise_on_redirect=True, raise_on_status=True, + history=None, respect_retry_after_header=True): + + self.total = total + self.connect = connect + self.read = read + self.status = status + + 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.method_whitelist = method_whitelist + 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 + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, read=self.read, redirect=self.redirect, status=self.status, + method_whitelist=self.method_whitelist, + 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, + ) + 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.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(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + retry_date = time.mktime(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 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. + """ + 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 on the method whitelist. + """ + if self.method_whitelist and method.upper() not in self.method_whitelist: + return False + + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """ Is this method/status code retryable? (Based on whitelists 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) + 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 + 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 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 a the given method is in the whitelist + 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, + 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) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py new file mode 100755 index 0000000..9f16c66 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/selectors.py @@ -0,0 +1,581 @@ +# Backport of selectors.py from Python 3.5+ to support Python < 3.4 +# Also has the behavior specified in PEP 475 which is to retry syscalls +# in the case of an EINTR error. This module is required because selectors34 +# does not follow this behavior and instead returns that no dile descriptor +# events have occurred rather than retry the syscall. The decision to drop +# support for select.devpoll is made to maintain 100% test coverage. + +import errno +import math +import select +import socket +import sys +import time +from collections import namedtuple, Mapping + +try: + monotonic = time.monotonic +except (AttributeError, ImportError): # Python 3.3< + monotonic = time.time + +EVENT_READ = (1 << 0) +EVENT_WRITE = (1 << 1) + +HAS_SELECT = True # Variable that shows whether the platform has a selector. +_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. +_DEFAULT_SELECTOR = None + + +class SelectorError(Exception): + def __init__(self, errcode): + super(SelectorError, self).__init__() + self.errno = errcode + + def __repr__(self): + return "<SelectorError errno={0}>".format(self.errno) + + def __str__(self): + return self.__repr__() + + +def _fileobj_to_fd(fileobj): + """ Return a file descriptor from a file object. If + given an integer will simply return that integer back. """ + if isinstance(fileobj, int): + fd = fileobj + else: + try: + fd = int(fileobj.fileno()) + except (AttributeError, TypeError, ValueError): + raise ValueError("Invalid file object: {0!r}".format(fileobj)) + if fd < 0: + raise ValueError("Invalid file descriptor: {0}".format(fd)) + return fd + + +# Determine which function to use to wrap system calls because Python 3.5+ +# already handles the case when system calls are interrupted. +if sys.version_info >= (3, 5): + def _syscall_wrapper(func, _, *args, **kwargs): + """ This is the short-circuit version of the below logic + because in Python 3.5+ all system calls automatically restart + and recalculate their timeouts. """ + try: + return func(*args, **kwargs) + except (OSError, IOError, select.error) as e: + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + raise SelectorError(errcode) +else: + def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): + """ Wrapper function for syscalls that could fail due to EINTR. + All functions should be retried if there is time left in the timeout + in accordance with PEP 475. """ + timeout = kwargs.get("timeout", None) + if timeout is None: + expires = None + recalc_timeout = False + else: + timeout = float(timeout) + if timeout < 0.0: # Timeout less than 0 treated as no timeout. + expires = None + else: + expires = monotonic() + timeout + + args = list(args) + if recalc_timeout and "timeout" not in kwargs: + raise ValueError( + "Timeout must be in args or kwargs to be recalculated") + + result = _SYSCALL_SENTINEL + while result is _SYSCALL_SENTINEL: + try: + result = func(*args, **kwargs) + # OSError is thrown by select.select + # IOError is thrown by select.epoll.poll + # select.error is thrown by select.poll.poll + # Aren't we thankful for Python 3.x rework for exceptions? + except (OSError, IOError, select.error) as e: + # select.error wasn't a subclass of OSError in the past. + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + elif hasattr(e, "args"): + errcode = e.args[0] + + # Also test for the Windows equivalent of EINTR. + is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and + errcode == errno.WSAEINTR)) + + if is_interrupt: + if expires is not None: + current_time = monotonic() + if current_time > expires: + raise OSError(errno=errno.ETIMEDOUT) + if recalc_timeout: + if "timeout" in kwargs: + kwargs["timeout"] = expires - current_time + continue + if errcode: + raise SelectorError(errcode) + else: + raise + return result + + +SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) + + +class _SelectorMapping(Mapping): + """ Mapping of file objects to selector keys """ + + def __init__(self, selector): + self._selector = selector + + def __len__(self): + return len(self._selector._fd_to_key) + + def __getitem__(self, fileobj): + try: + fd = self._selector._fileobj_lookup(fileobj) + return self._selector._fd_to_key[fd] + except KeyError: + raise KeyError("{0!r} is not registered.".format(fileobj)) + + def __iter__(self): + return iter(self._selector._fd_to_key) + + +class BaseSelector(object): + """ Abstract Selector class + + A selector supports registering file objects to be monitored + for specific I/O events. + + A file object is a file descriptor or any object with a + `fileno()` method. An arbitrary object can be attached to the + file object which can be used for example to store context info, + a callback, etc. + + A selector can use various implementations (select(), poll(), epoll(), + and kqueue()) depending on the platform. The 'DefaultSelector' class uses + the most efficient implementation for the current platform. + """ + def __init__(self): + # Maps file descriptors to keys. + self._fd_to_key = {} + + # Read-only mapping returned by get_map() + self._map = _SelectorMapping(self) + + def _fileobj_lookup(self, fileobj): + """ Return a file descriptor from a file object. + This wraps _fileobj_to_fd() to do an exhaustive + search in case the object is invalid but we still + have it in our map. Used by unregister() so we can + unregister an object that was previously registered + even if it is closed. It is also used by _SelectorMapping + """ + try: + return _fileobj_to_fd(fileobj) + except ValueError: + + # Search through all our mapped keys. + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + return key.fd + + # Raise ValueError after all. + raise + + def register(self, fileobj, events, data=None): + """ Register a file object for a set of events to monitor. """ + if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): + raise ValueError("Invalid events: {0!r}".format(events)) + + key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) + + if key.fd in self._fd_to_key: + raise KeyError("{0!r} (FD {1}) is already registered" + .format(fileobj, key.fd)) + + self._fd_to_key[key.fd] = key + return key + + def unregister(self, fileobj): + """ Unregister a file object from being monitored. """ + try: + key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + # Getting the fileno of a closed socket on Windows errors with EBADF. + except socket.error as e: # Platform-specific: Windows. + if e.errno != errno.EBADF: + raise + else: + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + self._fd_to_key.pop(key.fd) + break + else: + raise KeyError("{0!r} is not registered".format(fileobj)) + return key + + def modify(self, fileobj, events, data=None): + """ Change a registered file object monitored events and data. """ + # NOTE: Some subclasses optimize this operation even further. + try: + key = self._fd_to_key[self._fileobj_lookup(fileobj)] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + if events != key.events: + self.unregister(fileobj) + key = self.register(fileobj, events, data) + + elif data != key.data: + # Use a shortcut to update the data. + key = key._replace(data=data) + self._fd_to_key[key.fd] = key + + return key + + def select(self, timeout=None): + """ Perform the actual selection until some monitored file objects + are ready or the timeout expires. """ + raise NotImplementedError() + + def close(self): + """ Close the selector. This must be called to ensure that all + underlying resources are freed. """ + self._fd_to_key.clear() + self._map = None + + def get_key(self, fileobj): + """ Return the key associated with a registered file object. """ + mapping = self.get_map() + if mapping is None: + raise RuntimeError("Selector is closed") + try: + return mapping[fileobj] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + def get_map(self): + """ Return a mapping of file objects to selector keys """ + return self._map + + def _key_from_fd(self, fd): + """ Return the key associated to a given file descriptor + Return None if it is not found. """ + try: + return self._fd_to_key[fd] + except KeyError: + return None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + +# Almost all platforms have select.select() +if hasattr(select, "select"): + class SelectSelector(BaseSelector): + """ Select-based selector. """ + def __init__(self): + super(SelectSelector, self).__init__() + self._readers = set() + self._writers = set() + + def register(self, fileobj, events, data=None): + key = super(SelectSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + self._readers.add(key.fd) + if events & EVENT_WRITE: + self._writers.add(key.fd) + return key + + def unregister(self, fileobj): + key = super(SelectSelector, self).unregister(fileobj) + self._readers.discard(key.fd) + self._writers.discard(key.fd) + return key + + def _select(self, r, w, timeout=None): + """ Wrapper for select.select because timeout is a positional arg """ + return select.select(r, w, [], timeout) + + def select(self, timeout=None): + # Selecting on empty lists on Windows errors out. + if not len(self._readers) and not len(self._writers): + return [] + + timeout = None if timeout is None else max(timeout, 0.0) + ready = [] + r, w, _ = _syscall_wrapper(self._select, True, self._readers, + self._writers, timeout) + r = set(r) + w = set(w) + for fd in r | w: + events = 0 + if fd in r: + events |= EVENT_READ + if fd in w: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + +if hasattr(select, "poll"): + class PollSelector(BaseSelector): + """ Poll-based selector """ + def __init__(self): + super(PollSelector, self).__init__() + self._poll = select.poll() + + def register(self, fileobj, events, data=None): + key = super(PollSelector, self).register(fileobj, events, data) + event_mask = 0 + if events & EVENT_READ: + event_mask |= select.POLLIN + if events & EVENT_WRITE: + event_mask |= select.POLLOUT + self._poll.register(key.fd, event_mask) + return key + + def unregister(self, fileobj): + key = super(PollSelector, self).unregister(fileobj) + self._poll.unregister(key.fd) + return key + + def _wrap_poll(self, timeout=None): + """ Wrapper function for select.poll.poll() so that + _syscall_wrapper can work with only seconds. """ + if timeout is not None: + if timeout <= 0: + timeout = 0 + else: + # select.poll.poll() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) + + result = self._poll.poll(timeout) + return result + + def select(self, timeout=None): + ready = [] + fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.POLLIN: + events |= EVENT_WRITE + if event_mask & ~select.POLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + + return ready + + +if hasattr(select, "epoll"): + class EpollSelector(BaseSelector): + """ Epoll-based selector """ + def __init__(self): + super(EpollSelector, self).__init__() + self._epoll = select.epoll() + + def fileno(self): + return self._epoll.fileno() + + def register(self, fileobj, events, data=None): + key = super(EpollSelector, self).register(fileobj, events, data) + events_mask = 0 + if events & EVENT_READ: + events_mask |= select.EPOLLIN + if events & EVENT_WRITE: + events_mask |= select.EPOLLOUT + _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) + return key + + def unregister(self, fileobj): + key = super(EpollSelector, self).unregister(fileobj) + try: + _syscall_wrapper(self._epoll.unregister, False, key.fd) + except SelectorError: + # This can occur when the fd was closed since registry. + pass + return key + + def select(self, timeout=None): + if timeout is not None: + if timeout <= 0: + timeout = 0.0 + else: + # select.epoll.poll() has a resolution of 1 millisecond + # but luckily takes seconds so we don't need a wrapper + # like PollSelector. Just for better rounding. + timeout = math.ceil(timeout * 1e3) * 1e-3 + timeout = float(timeout) + else: + timeout = -1.0 # epoll.poll() must have a float. + + # We always want at least 1 to ensure that select can be called + # with no file descriptors registered. Otherwise will fail. + max_events = max(len(self._fd_to_key), 1) + + ready = [] + fd_events = _syscall_wrapper(self._epoll.poll, True, + timeout=timeout, + maxevents=max_events) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.EPOLLIN: + events |= EVENT_WRITE + if event_mask & ~select.EPOLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + def close(self): + self._epoll.close() + super(EpollSelector, self).close() + + +if hasattr(select, "kqueue"): + class KqueueSelector(BaseSelector): + """ Kqueue / Kevent-based selector """ + def __init__(self): + super(KqueueSelector, self).__init__() + self._kqueue = select.kqueue() + + def fileno(self): + return self._kqueue.fileno() + + def register(self, fileobj, events, data=None): + key = super(KqueueSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + if events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + return key + + def unregister(self, fileobj): + key = super(KqueueSelector, self).unregister(fileobj) + if key.events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + if key.events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + + return key + + def select(self, timeout=None): + if timeout is not None: + timeout = max(timeout, 0) + + max_events = len(self._fd_to_key) * 2 + ready_fds = {} + + kevent_list = _syscall_wrapper(self._kqueue.control, True, + None, max_events, timeout) + + for kevent in kevent_list: + fd = kevent.ident + event_mask = kevent.filter + events = 0 + if event_mask == select.KQ_FILTER_READ: + events |= EVENT_READ + if event_mask == select.KQ_FILTER_WRITE: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + if key.fd not in ready_fds: + ready_fds[key.fd] = (key, events & key.events) + else: + old_events = ready_fds[key.fd][1] + ready_fds[key.fd] = (key, (events | old_events) & key.events) + + return list(ready_fds.values()) + + def close(self): + self._kqueue.close() + super(KqueueSelector, self).close() + + +if not hasattr(select, 'select'): # Platform-specific: AppEngine + HAS_SELECT = False + + +def _can_allocate(struct): + """ Checks that select structs can be allocated by the underlying + operating system, not just advertised by the select module. We don't + check select() because we'll be hopeful that most platforms that + don't have it available will not advertise it. (ie: GAE) """ + try: + # select.poll() objects won't fail until used. + if struct == 'poll': + p = select.poll() + p.poll(0) + + # All others will fail on allocation. + else: + getattr(select, struct)().close() + return True + except (OSError, AttributeError) as e: + return False + + +# Choose the best implementation, roughly: +# kqueue == epoll > poll > select. Devpoll not supported. (See above) +# select() also can't accept a FD > FD_SETSIZE (usually around 1024) +def DefaultSelector(): + """ This function serves as a first call for DefaultSelector to + detect if the select module is being monkey-patched incorrectly + by eventlet, greenlet, and preserve proper behavior. """ + global _DEFAULT_SELECTOR + if _DEFAULT_SELECTOR is None: + if _can_allocate('kqueue'): + _DEFAULT_SELECTOR = KqueueSelector + elif _can_allocate('epoll'): + _DEFAULT_SELECTOR = EpollSelector + elif _can_allocate('poll'): + _DEFAULT_SELECTOR = PollSelector + elif hasattr(select, 'select'): + _DEFAULT_SELECTOR = SelectSelector + else: # Platform-specific: AppEngine + raise ValueError('Platform does not have a selector') + return _DEFAULT_SELECTOR() diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py new file mode 100755 index 0000000..c11dff2 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/ssl_.py @@ -0,0 +1,341 @@ +from __future__ import absolute_import +import errno +import warnings +import hmac + +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning + + +SSLContext = None +HAS_SNI = False +IS_PYOPENSSL = False +IS_SECURETRANSPORT = False + +# 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 l, r in zip(bytearray(a), bytearray(b)): + result |= l ^ r + return result == 0 + + +_const_compare_digest = getattr(hmac, 'compare_digest', + _const_compare_digest_backport) + + +try: # Test for SSL features + import ssl + from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23 + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + + +try: + from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + +# 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 TLS 1.3 cipher suites +# - 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 and DSS for security reasons. +DEFAULT_CIPHERS = ':'.join([ + 'TLS13-AES-256-GCM-SHA384', + 'TLS13-CHACHA20-POLY1305-SHA256', + 'TLS13-AES-128-GCM-SHA256', + 'ECDH+AESGCM', + 'ECDH+CHACHA20', + 'DH+AESGCM', + 'DH+CHACHA20', + 'ECDH+AES256', + 'DH+AES256', + 'ECDH+AES128', + 'DH+AES', + 'RSA+AESGCM', + 'RSA+AES', + '!aNULL', + '!eNULL', + '!MD5', +]) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + import sys + + class SSLContext(object): # Platform-specific: Python 2 & 3.1 + supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or + (3, 2) <= sys.version_info) + + 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): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + if not self.supports_set_ciphers: + raise TypeError( + 'Your version of Python does not support setting ' + 'a custom cipher suite. Please upgrade to Python ' + '2.7, 3.2, or later if you need this functionality.' + ) + 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/latest/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, + } + if self.supports_set_ciphers: # Platform-specific: Python 2.7+ + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + else: # Platform-specific: Python 2.6 + return wrap_socket(socket, **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_NONE`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbrevation. + (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_NONE + + 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_SSLv23 + + 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 pip._vendor.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``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) + + # 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 + + context.options |= options + + if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6 + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + context.verify_mode = cert_reqs + 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 + 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): + """ + 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. This is not + supported on Python 2.6 as the ssl module does not support it. + :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(). + """ + 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: + try: + context.load_verify_locations(ca_certs, ca_cert_dir) + except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2 + raise SSLError(e) + # Py33 raises FileNotFoundError which subclasses OSError + # These are not equivalent unless we check the errno attribute + except OSError as e: # Platform-specific: Python 3.3 and beyond + if e.errno == errno.ENOENT: + raise SSLError(e) + raise + elif getattr(context, 'load_default_certs', None) is not None: + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + if certfile: + context.load_cert_chain(certfile, keyfile) + if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI + return context.wrap_socket(sock, server_hostname=server_hostname) + + warnings.warn( + 'An HTTPS request has been made, but the SNI (Subject 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/latest/advanced-usage.html' + '#ssl-warnings', + SNIMissingWarning + ) + return context.wrap_socket(sock) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py new file mode 100755 index 0000000..9c2e6ef --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/timeout.py @@ -0,0 +1,242 @@ +from __future__ import absolute_import +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT +import time + +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:: + + 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):: + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``:: + + 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: integer, float, or None + + :param connect: + The maximum amount of time 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 + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout for connection attempts. + + :type connect: integer, float, or None + + :param read: + The maximum amount of time 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 + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout. + + :type read: integer, 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 __str__(self): + return '%s(connect=%r, read=%r, total=%r)' % ( + type(self).__name__, self._connect, self._read, self.total) + + @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. + :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/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py new file mode 100755 index 0000000..60f826a --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/url.py @@ -0,0 +1,230 @@ +from __future__ import absolute_import +from collections import namedtuple + +from ..exceptions import LocationParseError + + +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) + + +class Url(namedtuple('Url', url_attrs)): + """ + Datastructure 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: + scheme = scheme.lower() + if host and scheme in NORMALIZABLE_SCHEMES: + host = host.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 = '' + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + '://' + if auth is not None: + url += auth + '@' + if host is not None: + url += host + if port is not None: + url += ':' + str(port) + if path is not None: + url += path + if query is not None: + url += '?' + query + if fragment is not None: + url += '#' + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, '', None + + return s[:min_idx], s[min_idx + 1:], min_delim + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/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', ...) + """ + + # While this code has overlap with stdlib's urlparse, it is much + # simplified for our needs and less annoying. + # Additionally, this implementations does silly things to be optimal + # on CPython. + + if not url: + # Empty + return Url() + + scheme = None + auth = None + host = None + port = None + path = None + fragment = None + query = None + + # Scheme + if '://' in url: + scheme, url = url.split('://', 1) + + # Find the earliest Authority Terminator + # (http://tools.ietf.org/html/rfc3986#section-3.2) + url, path_, delim = split_first(url, ['/', '?', '#']) + + if delim: + # Reassemble the path + path = delim + path_ + + # Auth + if '@' in url: + # Last '@' denotes end of auth part + auth, url = url.rsplit('@', 1) + + # IPv6 + if url and url[0] == '[': + host, url = url.split(']', 1) + host += ']' + + # Port + if ':' in url: + _host, port = url.split(':', 1) + + if not host: + host = _host + + if port: + # If given, ports must be integers. No whitespace, no plus or + # minus prefixes, no non-integer digits such as ^2 (superscript). + if not port.isdigit(): + raise LocationParseError(url) + try: + port = int(port) + except ValueError: + raise LocationParseError(url) + else: + # Blank ports are cool, too. (rfc3986#section-3.2.3) + port = None + + elif not host and url: + host = url + + if not path: + return Url(scheme, auth, host, port, path, query, fragment) + + # Fragment + if '#' in path: + path, fragment = path.split('#', 1) + + # Query + if '?' in path: + path, query = path.split('?', 1) + + return Url(scheme, auth, host, port, path, query, fragment) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or 'http', p.hostname, p.port diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py new file mode 100755 index 0000000..46392f2 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/urllib3/util/wait.py @@ -0,0 +1,40 @@ +from .selectors import ( + HAS_SELECT, + DefaultSelector, + EVENT_READ, + EVENT_WRITE +) + + +def _wait_for_io_events(socks, events, timeout=None): + """ Waits for IO events to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be interacted with immediately. """ + if not HAS_SELECT: + raise ValueError('Platform does not have a selector') + if not isinstance(socks, list): + # Probably just a single socket. + if hasattr(socks, "fileno"): + socks = [socks] + # Otherwise it might be a non-list iterable. + else: + socks = list(socks) + with DefaultSelector() as selector: + for sock in socks: + selector.register(sock, events) + return [key[0].fileobj for key in + selector.select(timeout) if key[1] & events] + + +def wait_for_read(socks, timeout=None): + """ Waits for reading to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be read from immediately. """ + return _wait_for_io_events(socks, EVENT_READ, timeout) + + +def wait_for_write(socks, timeout=None): + """ Waits for writing to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be written to immediately. """ + return _wait_for_io_events(socks, EVENT_WRITE, timeout) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py new file mode 100755 index 0000000..16671ef --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/__init__.py @@ -0,0 +1,342 @@ +# coding: utf-8 +""" + + webencodings + ~~~~~~~~~~~~ + + This is a Python implementation of the `WHATWG Encoding standard + <http://encoding.spec.whatwg.org/>`. See README for details. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +import codecs + +from .labels import LABELS + + +VERSION = '0.5.1' + + +# Some names in Encoding are not valid Python aliases. Remap these. +PYTHON_NAMES = { + 'iso-8859-8-i': 'iso-8859-8', + 'x-mac-cyrillic': 'mac-cyrillic', + 'macintosh': 'mac-roman', + 'windows-874': 'cp874'} + +CACHE = {} + + +def ascii_lower(string): + r"""Transform (only) ASCII letters to lower case: A-Z is mapped to a-z. + + :param string: An Unicode string. + :returns: A new Unicode string. + + This is used for `ASCII case-insensitive + <http://encoding.spec.whatwg.org/#ascii-case-insensitive>`_ + matching of encoding labels. + The same matching is also used, among other things, + for `CSS keywords <http://dev.w3.org/csswg/css-values/#keywords>`_. + + This is different from the :meth:`~py:str.lower` method of Unicode strings + which also affect non-ASCII characters, + sometimes mapping them into the ASCII range: + + >>> keyword = u'Bac\N{KELVIN SIGN}ground' + >>> assert keyword.lower() == u'background' + >>> assert ascii_lower(keyword) != keyword.lower() + >>> assert ascii_lower(keyword) == u'bac\N{KELVIN SIGN}ground' + + """ + # This turns out to be faster than unicode.translate() + return string.encode('utf8').lower().decode('utf8') + + +def lookup(label): + """ + Look for an encoding by its label. + This is the spec’s `get an encoding + <http://encoding.spec.whatwg.org/#concept-encoding-get>`_ algorithm. + Supported labels are listed there. + + :param label: A string. + :returns: + An :class:`Encoding` object, or :obj:`None` for an unknown label. + + """ + # Only strip ASCII whitespace: U+0009, U+000A, U+000C, U+000D, and U+0020. + label = ascii_lower(label.strip('\t\n\f\r ')) + name = LABELS.get(label) + if name is None: + return None + encoding = CACHE.get(name) + if encoding is None: + if name == 'x-user-defined': + from .x_user_defined import codec_info + else: + python_name = PYTHON_NAMES.get(name, name) + # Any python_name value that gets to here should be valid. + codec_info = codecs.lookup(python_name) + encoding = Encoding(name, codec_info) + CACHE[name] = encoding + return encoding + + +def _get_encoding(encoding_or_label): + """ + Accept either an encoding object or label. + + :param encoding: An :class:`Encoding` object or a label string. + :returns: An :class:`Encoding` object. + :raises: :exc:`~exceptions.LookupError` for an unknown label. + + """ + if hasattr(encoding_or_label, 'codec_info'): + return encoding_or_label + + encoding = lookup(encoding_or_label) + if encoding is None: + raise LookupError('Unknown encoding label: %r' % encoding_or_label) + return encoding + + +class Encoding(object): + """Reresents a character encoding such as UTF-8, + that can be used for decoding or encoding. + + .. attribute:: name + + Canonical name of the encoding + + .. attribute:: codec_info + + The actual implementation of the encoding, + a stdlib :class:`~codecs.CodecInfo` object. + See :func:`codecs.register`. + + """ + def __init__(self, name, codec_info): + self.name = name + self.codec_info = codec_info + + def __repr__(self): + return '<Encoding %s>' % self.name + + +#: The UTF-8 encoding. Should be used for new content and formats. +UTF8 = lookup('utf-8') + +_UTF16LE = lookup('utf-16le') +_UTF16BE = lookup('utf-16be') + + +def decode(input, fallback_encoding, errors='replace'): + """ + Decode a single string. + + :param input: A byte string + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :return: + A ``(output, encoding)`` tuple of an Unicode string + and an :obj:`Encoding`. + + """ + # Fail early if `encoding` is an invalid label. + fallback_encoding = _get_encoding(fallback_encoding) + bom_encoding, input = _detect_bom(input) + encoding = bom_encoding or fallback_encoding + return encoding.codec_info.decode(input, errors)[0], encoding + + +def _detect_bom(input): + """Return (bom_encoding, input), with any BOM removed from the input.""" + if input.startswith(b'\xFF\xFE'): + return _UTF16LE, input[2:] + if input.startswith(b'\xFE\xFF'): + return _UTF16BE, input[2:] + if input.startswith(b'\xEF\xBB\xBF'): + return UTF8, input[3:] + return None, input + + +def encode(input, encoding=UTF8, errors='strict'): + """ + Encode a single string. + + :param input: An Unicode string. + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :return: A byte string. + + """ + return _get_encoding(encoding).codec_info.encode(input, errors)[0] + + +def iter_decode(input, fallback_encoding, errors='replace'): + """ + "Pull"-based decoder. + + :param input: + An iterable of byte strings. + + The input is first consumed just enough to determine the encoding + based on the precense of a BOM, + then consumed on demand when the return value is. + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :returns: + An ``(output, encoding)`` tuple. + :obj:`output` is an iterable of Unicode strings, + :obj:`encoding` is the :obj:`Encoding` that is being used. + + """ + + decoder = IncrementalDecoder(fallback_encoding, errors) + generator = _iter_decode_generator(input, decoder) + encoding = next(generator) + return generator, encoding + + +def _iter_decode_generator(input, decoder): + """Return a generator that first yields the :obj:`Encoding`, + then yields output chukns as Unicode strings. + + """ + decode = decoder.decode + input = iter(input) + for chunck in input: + output = decode(chunck) + if output: + assert decoder.encoding is not None + yield decoder.encoding + yield output + break + else: + # Input exhausted without determining the encoding + output = decode(b'', final=True) + assert decoder.encoding is not None + yield decoder.encoding + if output: + yield output + return + + for chunck in input: + output = decode(chunck) + if output: + yield output + output = decode(b'', final=True) + if output: + yield output + + +def iter_encode(input, encoding=UTF8, errors='strict'): + """ + “Pull”-based encoder. + + :param input: An iterable of Unicode strings. + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + :returns: An iterable of byte strings. + + """ + # Fail early if `encoding` is an invalid label. + encode = IncrementalEncoder(encoding, errors).encode + return _iter_encode_generator(input, encode) + + +def _iter_encode_generator(input, encode): + for chunck in input: + output = encode(chunck) + if output: + yield output + output = encode('', final=True) + if output: + yield output + + +class IncrementalDecoder(object): + """ + “Push”-based decoder. + + :param fallback_encoding: + An :class:`Encoding` object or a label string. + The encoding to use if :obj:`input` does note have a BOM. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + + """ + def __init__(self, fallback_encoding, errors='replace'): + # Fail early if `encoding` is an invalid label. + self._fallback_encoding = _get_encoding(fallback_encoding) + self._errors = errors + self._buffer = b'' + self._decoder = None + #: The actual :class:`Encoding` that is being used, + #: or :obj:`None` if that is not determined yet. + #: (Ie. if there is not enough input yet to determine + #: if there is a BOM.) + self.encoding = None # Not known yet. + + def decode(self, input, final=False): + """Decode one chunk of the input. + + :param input: A byte string. + :param final: + Indicate that no more input is available. + Must be :obj:`True` if this is the last call. + :returns: An Unicode string. + + """ + decoder = self._decoder + if decoder is not None: + return decoder(input, final) + + input = self._buffer + input + encoding, input = _detect_bom(input) + if encoding is None: + if len(input) < 3 and not final: # Not enough data yet. + self._buffer = input + return '' + else: # No BOM + encoding = self._fallback_encoding + decoder = encoding.codec_info.incrementaldecoder(self._errors).decode + self._decoder = decoder + self.encoding = encoding + return decoder(input, final) + + +class IncrementalEncoder(object): + """ + “Push”-based encoder. + + :param encoding: An :class:`Encoding` object or a label string. + :param errors: Type of error handling. See :func:`codecs.register`. + :raises: :exc:`~exceptions.LookupError` for an unknown encoding label. + + .. method:: encode(input, final=False) + + :param input: An Unicode string. + :param final: + Indicate that no more input is available. + Must be :obj:`True` if this is the last call. + :returns: A byte string. + + """ + def __init__(self, encoding=UTF8, errors='strict'): + encoding = _get_encoding(encoding) + self.encode = encoding.codec_info.incrementalencoder(errors).encode diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py new file mode 100755 index 0000000..9dae102 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/labels.py @@ -0,0 +1,231 @@ +""" + + webencodings.labels + ~~~~~~~~~~~~~~~~~~~ + + Map encoding labels to their name. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +# XXX Do not edit! +# This file is automatically generated by mklabels.py + +LABELS = { + 'unicode-1-1-utf-8': 'utf-8', + 'utf-8': 'utf-8', + 'utf8': 'utf-8', + '866': 'ibm866', + 'cp866': 'ibm866', + 'csibm866': 'ibm866', + 'ibm866': 'ibm866', + 'csisolatin2': 'iso-8859-2', + 'iso-8859-2': 'iso-8859-2', + 'iso-ir-101': 'iso-8859-2', + 'iso8859-2': 'iso-8859-2', + 'iso88592': 'iso-8859-2', + 'iso_8859-2': 'iso-8859-2', + 'iso_8859-2:1987': 'iso-8859-2', + 'l2': 'iso-8859-2', + 'latin2': 'iso-8859-2', + 'csisolatin3': 'iso-8859-3', + 'iso-8859-3': 'iso-8859-3', + 'iso-ir-109': 'iso-8859-3', + 'iso8859-3': 'iso-8859-3', + 'iso88593': 'iso-8859-3', + 'iso_8859-3': 'iso-8859-3', + 'iso_8859-3:1988': 'iso-8859-3', + 'l3': 'iso-8859-3', + 'latin3': 'iso-8859-3', + 'csisolatin4': 'iso-8859-4', + 'iso-8859-4': 'iso-8859-4', + 'iso-ir-110': 'iso-8859-4', + 'iso8859-4': 'iso-8859-4', + 'iso88594': 'iso-8859-4', + 'iso_8859-4': 'iso-8859-4', + 'iso_8859-4:1988': 'iso-8859-4', + 'l4': 'iso-8859-4', + 'latin4': 'iso-8859-4', + 'csisolatincyrillic': 'iso-8859-5', + 'cyrillic': 'iso-8859-5', + 'iso-8859-5': 'iso-8859-5', + 'iso-ir-144': 'iso-8859-5', + 'iso8859-5': 'iso-8859-5', + 'iso88595': 'iso-8859-5', + 'iso_8859-5': 'iso-8859-5', + 'iso_8859-5:1988': 'iso-8859-5', + 'arabic': 'iso-8859-6', + 'asmo-708': 'iso-8859-6', + 'csiso88596e': 'iso-8859-6', + 'csiso88596i': 'iso-8859-6', + 'csisolatinarabic': 'iso-8859-6', + 'ecma-114': 'iso-8859-6', + 'iso-8859-6': 'iso-8859-6', + 'iso-8859-6-e': 'iso-8859-6', + 'iso-8859-6-i': 'iso-8859-6', + 'iso-ir-127': 'iso-8859-6', + 'iso8859-6': 'iso-8859-6', + 'iso88596': 'iso-8859-6', + 'iso_8859-6': 'iso-8859-6', + 'iso_8859-6:1987': 'iso-8859-6', + 'csisolatingreek': 'iso-8859-7', + 'ecma-118': 'iso-8859-7', + 'elot_928': 'iso-8859-7', + 'greek': 'iso-8859-7', + 'greek8': 'iso-8859-7', + 'iso-8859-7': 'iso-8859-7', + 'iso-ir-126': 'iso-8859-7', + 'iso8859-7': 'iso-8859-7', + 'iso88597': 'iso-8859-7', + 'iso_8859-7': 'iso-8859-7', + 'iso_8859-7:1987': 'iso-8859-7', + 'sun_eu_greek': 'iso-8859-7', + 'csiso88598e': 'iso-8859-8', + 'csisolatinhebrew': 'iso-8859-8', + 'hebrew': 'iso-8859-8', + 'iso-8859-8': 'iso-8859-8', + 'iso-8859-8-e': 'iso-8859-8', + 'iso-ir-138': 'iso-8859-8', + 'iso8859-8': 'iso-8859-8', + 'iso88598': 'iso-8859-8', + 'iso_8859-8': 'iso-8859-8', + 'iso_8859-8:1988': 'iso-8859-8', + 'visual': 'iso-8859-8', + 'csiso88598i': 'iso-8859-8-i', + 'iso-8859-8-i': 'iso-8859-8-i', + 'logical': 'iso-8859-8-i', + 'csisolatin6': 'iso-8859-10', + 'iso-8859-10': 'iso-8859-10', + 'iso-ir-157': 'iso-8859-10', + 'iso8859-10': 'iso-8859-10', + 'iso885910': 'iso-8859-10', + 'l6': 'iso-8859-10', + 'latin6': 'iso-8859-10', + 'iso-8859-13': 'iso-8859-13', + 'iso8859-13': 'iso-8859-13', + 'iso885913': 'iso-8859-13', + 'iso-8859-14': 'iso-8859-14', + 'iso8859-14': 'iso-8859-14', + 'iso885914': 'iso-8859-14', + 'csisolatin9': 'iso-8859-15', + 'iso-8859-15': 'iso-8859-15', + 'iso8859-15': 'iso-8859-15', + 'iso885915': 'iso-8859-15', + 'iso_8859-15': 'iso-8859-15', + 'l9': 'iso-8859-15', + 'iso-8859-16': 'iso-8859-16', + 'cskoi8r': 'koi8-r', + 'koi': 'koi8-r', + 'koi8': 'koi8-r', + 'koi8-r': 'koi8-r', + 'koi8_r': 'koi8-r', + 'koi8-u': 'koi8-u', + 'csmacintosh': 'macintosh', + 'mac': 'macintosh', + 'macintosh': 'macintosh', + 'x-mac-roman': 'macintosh', + 'dos-874': 'windows-874', + 'iso-8859-11': 'windows-874', + 'iso8859-11': 'windows-874', + 'iso885911': 'windows-874', + 'tis-620': 'windows-874', + 'windows-874': 'windows-874', + 'cp1250': 'windows-1250', + 'windows-1250': 'windows-1250', + 'x-cp1250': 'windows-1250', + 'cp1251': 'windows-1251', + 'windows-1251': 'windows-1251', + 'x-cp1251': 'windows-1251', + 'ansi_x3.4-1968': 'windows-1252', + 'ascii': 'windows-1252', + 'cp1252': 'windows-1252', + 'cp819': 'windows-1252', + 'csisolatin1': 'windows-1252', + 'ibm819': 'windows-1252', + 'iso-8859-1': 'windows-1252', + 'iso-ir-100': 'windows-1252', + 'iso8859-1': 'windows-1252', + 'iso88591': 'windows-1252', + 'iso_8859-1': 'windows-1252', + 'iso_8859-1:1987': 'windows-1252', + 'l1': 'windows-1252', + 'latin1': 'windows-1252', + 'us-ascii': 'windows-1252', + 'windows-1252': 'windows-1252', + 'x-cp1252': 'windows-1252', + 'cp1253': 'windows-1253', + 'windows-1253': 'windows-1253', + 'x-cp1253': 'windows-1253', + 'cp1254': 'windows-1254', + 'csisolatin5': 'windows-1254', + 'iso-8859-9': 'windows-1254', + 'iso-ir-148': 'windows-1254', + 'iso8859-9': 'windows-1254', + 'iso88599': 'windows-1254', + 'iso_8859-9': 'windows-1254', + 'iso_8859-9:1989': 'windows-1254', + 'l5': 'windows-1254', + 'latin5': 'windows-1254', + 'windows-1254': 'windows-1254', + 'x-cp1254': 'windows-1254', + 'cp1255': 'windows-1255', + 'windows-1255': 'windows-1255', + 'x-cp1255': 'windows-1255', + 'cp1256': 'windows-1256', + 'windows-1256': 'windows-1256', + 'x-cp1256': 'windows-1256', + 'cp1257': 'windows-1257', + 'windows-1257': 'windows-1257', + 'x-cp1257': 'windows-1257', + 'cp1258': 'windows-1258', + 'windows-1258': 'windows-1258', + 'x-cp1258': 'windows-1258', + 'x-mac-cyrillic': 'x-mac-cyrillic', + 'x-mac-ukrainian': 'x-mac-cyrillic', + 'chinese': 'gbk', + 'csgb2312': 'gbk', + 'csiso58gb231280': 'gbk', + 'gb2312': 'gbk', + 'gb_2312': 'gbk', + 'gb_2312-80': 'gbk', + 'gbk': 'gbk', + 'iso-ir-58': 'gbk', + 'x-gbk': 'gbk', + 'gb18030': 'gb18030', + 'hz-gb-2312': 'hz-gb-2312', + 'big5': 'big5', + 'big5-hkscs': 'big5', + 'cn-big5': 'big5', + 'csbig5': 'big5', + 'x-x-big5': 'big5', + 'cseucpkdfmtjapanese': 'euc-jp', + 'euc-jp': 'euc-jp', + 'x-euc-jp': 'euc-jp', + 'csiso2022jp': 'iso-2022-jp', + 'iso-2022-jp': 'iso-2022-jp', + 'csshiftjis': 'shift_jis', + 'ms_kanji': 'shift_jis', + 'shift-jis': 'shift_jis', + 'shift_jis': 'shift_jis', + 'sjis': 'shift_jis', + 'windows-31j': 'shift_jis', + 'x-sjis': 'shift_jis', + 'cseuckr': 'euc-kr', + 'csksc56011987': 'euc-kr', + 'euc-kr': 'euc-kr', + 'iso-ir-149': 'euc-kr', + 'korean': 'euc-kr', + 'ks_c_5601-1987': 'euc-kr', + 'ks_c_5601-1989': 'euc-kr', + 'ksc5601': 'euc-kr', + 'ksc_5601': 'euc-kr', + 'windows-949': 'euc-kr', + 'csiso2022kr': 'iso-2022-kr', + 'iso-2022-kr': 'iso-2022-kr', + 'utf-16be': 'utf-16be', + 'utf-16': 'utf-16le', + 'utf-16le': 'utf-16le', + 'x-user-defined': 'x-user-defined', +} diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py new file mode 100755 index 0000000..a7f7e76 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/mklabels.py @@ -0,0 +1,59 @@ +""" + + webencodings.mklabels + ~~~~~~~~~~~~~~~~~~~~~ + + Regenarate the webencodings.labels module. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +import json +try: + from urllib import urlopen +except ImportError: + from urllib.request import urlopen + + +def assert_lower(string): + assert string == string.lower() + return string + + +def generate(url): + parts = ['''\ +""" + + webencodings.labels + ~~~~~~~~~~~~~~~~~~~ + + Map encoding labels to their name. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +# XXX Do not edit! +# This file is automatically generated by mklabels.py + +LABELS = { +'''] + labels = [ + (repr(assert_lower(label)).lstrip('u'), + repr(encoding['name']).lstrip('u')) + for category in json.loads(urlopen(url).read().decode('ascii')) + for encoding in category['encodings'] + for label in encoding['labels']] + max_len = max(len(label) for label, name in labels) + parts.extend( + ' %s:%s %s,\n' % (label, ' ' * (max_len - len(label)), name) + for label, name in labels) + parts.append('}') + return ''.join(parts) + + +if __name__ == '__main__': + print(generate('http://encoding.spec.whatwg.org/encodings.json')) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py new file mode 100755 index 0000000..f6cdbf9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/tests.py @@ -0,0 +1,153 @@ +# coding: utf-8 +""" + + webencodings.tests + ~~~~~~~~~~~~~~~~~~ + + A basic test suite for Encoding. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +from . import (lookup, LABELS, decode, encode, iter_decode, iter_encode, + IncrementalDecoder, IncrementalEncoder, UTF8) + + +def assert_raises(exception, function, *args, **kwargs): + try: + function(*args, **kwargs) + except exception: + return + else: # pragma: no cover + raise AssertionError('Did not raise %s.' % exception) + + +def test_labels(): + assert lookup('utf-8').name == 'utf-8' + assert lookup('Utf-8').name == 'utf-8' + assert lookup('UTF-8').name == 'utf-8' + assert lookup('utf8').name == 'utf-8' + assert lookup('utf8').name == 'utf-8' + assert lookup('utf8 ').name == 'utf-8' + assert lookup(' \r\nutf8\t').name == 'utf-8' + assert lookup('u8') is None # Python label. + assert lookup('utf-8 ') is None # Non-ASCII white space. + + assert lookup('US-ASCII').name == 'windows-1252' + assert lookup('iso-8859-1').name == 'windows-1252' + assert lookup('latin1').name == 'windows-1252' + assert lookup('LATIN1').name == 'windows-1252' + assert lookup('latin-1') is None + assert lookup('LATİN1') is None # ASCII-only case insensitivity. + + +def test_all_labels(): + for label in LABELS: + assert decode(b'', label) == ('', lookup(label)) + assert encode('', label) == b'' + for repeat in [0, 1, 12]: + output, _ = iter_decode([b''] * repeat, label) + assert list(output) == [] + assert list(iter_encode([''] * repeat, label)) == [] + decoder = IncrementalDecoder(label) + assert decoder.decode(b'') == '' + assert decoder.decode(b'', final=True) == '' + encoder = IncrementalEncoder(label) + assert encoder.encode('') == b'' + assert encoder.encode('', final=True) == b'' + # All encoding names are valid labels too: + for name in set(LABELS.values()): + assert lookup(name).name == name + + +def test_invalid_label(): + assert_raises(LookupError, decode, b'\xEF\xBB\xBF\xc3\xa9', 'invalid') + assert_raises(LookupError, encode, 'é', 'invalid') + assert_raises(LookupError, iter_decode, [], 'invalid') + assert_raises(LookupError, iter_encode, [], 'invalid') + assert_raises(LookupError, IncrementalDecoder, 'invalid') + assert_raises(LookupError, IncrementalEncoder, 'invalid') + + +def test_decode(): + assert decode(b'\x80', 'latin1') == ('€', lookup('latin1')) + assert decode(b'\x80', lookup('latin1')) == ('€', lookup('latin1')) + assert decode(b'\xc3\xa9', 'utf8') == ('é', lookup('utf8')) + assert decode(b'\xc3\xa9', UTF8) == ('é', lookup('utf8')) + assert decode(b'\xc3\xa9', 'ascii') == ('é', lookup('ascii')) + assert decode(b'\xEF\xBB\xBF\xc3\xa9', 'ascii') == ('é', lookup('utf8')) # UTF-8 with BOM + + assert decode(b'\xFE\xFF\x00\xe9', 'ascii') == ('é', lookup('utf-16be')) # UTF-16-BE with BOM + assert decode(b'\xFF\xFE\xe9\x00', 'ascii') == ('é', lookup('utf-16le')) # UTF-16-LE with BOM + assert decode(b'\xFE\xFF\xe9\x00', 'ascii') == ('\ue900', lookup('utf-16be')) + assert decode(b'\xFF\xFE\x00\xe9', 'ascii') == ('\ue900', lookup('utf-16le')) + + assert decode(b'\x00\xe9', 'UTF-16BE') == ('é', lookup('utf-16be')) + assert decode(b'\xe9\x00', 'UTF-16LE') == ('é', lookup('utf-16le')) + assert decode(b'\xe9\x00', 'UTF-16') == ('é', lookup('utf-16le')) + + assert decode(b'\xe9\x00', 'UTF-16BE') == ('\ue900', lookup('utf-16be')) + assert decode(b'\x00\xe9', 'UTF-16LE') == ('\ue900', lookup('utf-16le')) + assert decode(b'\x00\xe9', 'UTF-16') == ('\ue900', lookup('utf-16le')) + + +def test_encode(): + assert encode('é', 'latin1') == b'\xe9' + assert encode('é', 'utf8') == b'\xc3\xa9' + assert encode('é', 'utf8') == b'\xc3\xa9' + assert encode('é', 'utf-16') == b'\xe9\x00' + assert encode('é', 'utf-16le') == b'\xe9\x00' + assert encode('é', 'utf-16be') == b'\x00\xe9' + + +def test_iter_decode(): + def iter_decode_to_string(input, fallback_encoding): + output, _encoding = iter_decode(input, fallback_encoding) + return ''.join(output) + assert iter_decode_to_string([], 'latin1') == '' + assert iter_decode_to_string([b''], 'latin1') == '' + assert iter_decode_to_string([b'\xe9'], 'latin1') == 'é' + assert iter_decode_to_string([b'hello'], 'latin1') == 'hello' + assert iter_decode_to_string([b'he', b'llo'], 'latin1') == 'hello' + assert iter_decode_to_string([b'hell', b'o'], 'latin1') == 'hello' + assert iter_decode_to_string([b'\xc3\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xEF\xBB\xBF\xc3\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'\xEF\xBB\xBF', b'\xc3', b'\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'\xEF\xBB\xBF', b'a', b'\xc3'], 'latin1') == 'a\uFFFD' + assert iter_decode_to_string([ + b'', b'\xEF', b'', b'', b'\xBB\xBF\xc3', b'\xa9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xEF\xBB\xBF'], 'latin1') == '' + assert iter_decode_to_string([b'\xEF\xBB'], 'latin1') == 'ï»' + assert iter_decode_to_string([b'\xFE\xFF\x00\xe9'], 'latin1') == 'é' + assert iter_decode_to_string([b'\xFF\xFE\xe9\x00'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'', b'\xFF', b'', b'', b'\xFE\xe9', b'\x00'], 'latin1') == 'é' + assert iter_decode_to_string([ + b'', b'h\xe9', b'llo'], 'x-user-defined') == 'h\uF7E9llo' + + +def test_iter_encode(): + assert b''.join(iter_encode([], 'latin1')) == b'' + assert b''.join(iter_encode([''], 'latin1')) == b'' + assert b''.join(iter_encode(['é'], 'latin1')) == b'\xe9' + assert b''.join(iter_encode(['', 'é', '', ''], 'latin1')) == b'\xe9' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16')) == b'\xe9\x00' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16le')) == b'\xe9\x00' + assert b''.join(iter_encode(['', 'é', '', ''], 'utf-16be')) == b'\x00\xe9' + assert b''.join(iter_encode([ + '', 'h\uF7E9', '', 'llo'], 'x-user-defined')) == b'h\xe9llo' + + +def test_x_user_defined(): + encoded = b'2,\x0c\x0b\x1aO\xd9#\xcb\x0f\xc9\xbbt\xcf\xa8\xca' + decoded = '2,\x0c\x0b\x1aO\uf7d9#\uf7cb\x0f\uf7c9\uf7bbt\uf7cf\uf7a8\uf7ca' + encoded = b'aa' + decoded = 'aa' + assert decode(encoded, 'x-user-defined') == (decoded, lookup('x-user-defined')) + assert encode(decoded, 'x-user-defined') == encoded diff --git a/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py new file mode 100755 index 0000000..748e2c9 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/pip-10.0.1-py3.5.egg/pip/_vendor/webencodings/x_user_defined.py @@ -0,0 +1,325 @@ +# coding: utf-8 +""" + + webencodings.x_user_defined + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + An implementation of the x-user-defined encoding. + + :copyright: Copyright 2012 by Simon Sapin + :license: BSD, see LICENSE for details. + +""" + +from __future__ import unicode_literals + +import codecs + + +### Codec APIs + +class Codec(codecs.Codec): + + def encode(self, input, errors='strict'): + return codecs.charmap_encode(input, errors, encoding_table) + + def decode(self, input, errors='strict'): + return codecs.charmap_decode(input, errors, decoding_table) + + +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input, final=False): + return codecs.charmap_encode(input, self.errors, encoding_table)[0] + + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input, final=False): + return codecs.charmap_decode(input, self.errors, decoding_table)[0] + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + + +class StreamReader(Codec, codecs.StreamReader): + pass + + +### encodings module API + +codec_info = codecs.CodecInfo( + name='x-user-defined', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamreader=StreamReader, + streamwriter=StreamWriter, +) + + +### Decoding Table + +# Python 3: +# for c in range(256): print(' %r' % chr(c if c < 128 else c + 0xF700)) +decoding_table = ( + '\x00' + '\x01' + '\x02' + '\x03' + '\x04' + '\x05' + '\x06' + '\x07' + '\x08' + '\t' + '\n' + '\x0b' + '\x0c' + '\r' + '\x0e' + '\x0f' + '\x10' + '\x11' + '\x12' + '\x13' + '\x14' + '\x15' + '\x16' + '\x17' + '\x18' + '\x19' + '\x1a' + '\x1b' + '\x1c' + '\x1d' + '\x1e' + '\x1f' + ' ' + '!' + '"' + '#' + '$' + '%' + '&' + "'" + '(' + ')' + '*' + '+' + ',' + '-' + '.' + '/' + '0' + '1' + '2' + '3' + '4' + '5' + '6' + '7' + '8' + '9' + ':' + ';' + '<' + '=' + '>' + '?' + '@' + 'A' + 'B' + 'C' + 'D' + 'E' + 'F' + 'G' + 'H' + 'I' + 'J' + 'K' + 'L' + 'M' + 'N' + 'O' + 'P' + 'Q' + 'R' + 'S' + 'T' + 'U' + 'V' + 'W' + 'X' + 'Y' + 'Z' + '[' + '\\' + ']' + '^' + '_' + '`' + 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' + 'h' + 'i' + 'j' + 'k' + 'l' + 'm' + 'n' + 'o' + 'p' + 'q' + 'r' + 's' + 't' + 'u' + 'v' + 'w' + 'x' + 'y' + 'z' + '{' + '|' + '}' + '~' + '\x7f' + '\uf780' + '\uf781' + '\uf782' + '\uf783' + '\uf784' + '\uf785' + '\uf786' + '\uf787' + '\uf788' + '\uf789' + '\uf78a' + '\uf78b' + '\uf78c' + '\uf78d' + '\uf78e' + '\uf78f' + '\uf790' + '\uf791' + '\uf792' + '\uf793' + '\uf794' + '\uf795' + '\uf796' + '\uf797' + '\uf798' + '\uf799' + '\uf79a' + '\uf79b' + '\uf79c' + '\uf79d' + '\uf79e' + '\uf79f' + '\uf7a0' + '\uf7a1' + '\uf7a2' + '\uf7a3' + '\uf7a4' + '\uf7a5' + '\uf7a6' + '\uf7a7' + '\uf7a8' + '\uf7a9' + '\uf7aa' + '\uf7ab' + '\uf7ac' + '\uf7ad' + '\uf7ae' + '\uf7af' + '\uf7b0' + '\uf7b1' + '\uf7b2' + '\uf7b3' + '\uf7b4' + '\uf7b5' + '\uf7b6' + '\uf7b7' + '\uf7b8' + '\uf7b9' + '\uf7ba' + '\uf7bb' + '\uf7bc' + '\uf7bd' + '\uf7be' + '\uf7bf' + '\uf7c0' + '\uf7c1' + '\uf7c2' + '\uf7c3' + '\uf7c4' + '\uf7c5' + '\uf7c6' + '\uf7c7' + '\uf7c8' + '\uf7c9' + '\uf7ca' + '\uf7cb' + '\uf7cc' + '\uf7cd' + '\uf7ce' + '\uf7cf' + '\uf7d0' + '\uf7d1' + '\uf7d2' + '\uf7d3' + '\uf7d4' + '\uf7d5' + '\uf7d6' + '\uf7d7' + '\uf7d8' + '\uf7d9' + '\uf7da' + '\uf7db' + '\uf7dc' + '\uf7dd' + '\uf7de' + '\uf7df' + '\uf7e0' + '\uf7e1' + '\uf7e2' + '\uf7e3' + '\uf7e4' + '\uf7e5' + '\uf7e6' + '\uf7e7' + '\uf7e8' + '\uf7e9' + '\uf7ea' + '\uf7eb' + '\uf7ec' + '\uf7ed' + '\uf7ee' + '\uf7ef' + '\uf7f0' + '\uf7f1' + '\uf7f2' + '\uf7f3' + '\uf7f4' + '\uf7f5' + '\uf7f6' + '\uf7f7' + '\uf7f8' + '\uf7f9' + '\uf7fa' + '\uf7fb' + '\uf7fc' + '\uf7fd' + '\uf7fe' + '\uf7ff' +) + +### Encoding table +encoding_table = codecs.charmap_build(decoding_table) diff --git a/meta_updater/venv/lib64/python3.5/site-packages/setuptools-39.1.0-py3.5.egg b/meta_updater/venv/lib64/python3.5/site-packages/setuptools-39.1.0-py3.5.egg new file mode 100755 index 0000000..c93cfda Binary files /dev/null and b/meta_updater/venv/lib64/python3.5/site-packages/setuptools-39.1.0-py3.5.egg differ diff --git a/meta_updater/venv/lib64/python3.5/site-packages/setuptools.pth b/meta_updater/venv/lib64/python3.5/site-packages/setuptools.pth new file mode 100755 index 0000000..9cbfe51 --- /dev/null +++ b/meta_updater/venv/lib64/python3.5/site-packages/setuptools.pth @@ -0,0 +1 @@ +./setuptools-39.1.0-py3.5.egg diff --git a/meta_updater/venv/pyvenv.cfg b/meta_updater/venv/pyvenv.cfg new file mode 100755 index 0000000..20ac621 --- /dev/null +++ b/meta_updater/venv/pyvenv.cfg @@ -0,0 +1,3 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.5.2 diff --git a/pyMDNet/LICENSE b/pyMDNet/LICENSE new file mode 100755 index 0000000..4fa3cd9 --- /dev/null +++ b/pyMDNet/LICENSE @@ -0,0 +1,57 @@ +Copyright Pohang University of Science and Technology. All rights reserved. + +Contact person: +Hyeonseob Nam (namhs09 <at> postech.ac.kr) + +This software is being made available for individual research use only. +Any commercial use or redistribution of this software requires a license from +the Pohang University of Science and Technology. + +You may use this work subject to the following conditions: + +1. This work is provided "as is" by the copyright holder, with +absolutely no warranties of correctness, fitness, intellectual property +ownership, or anything else whatsoever. You use the work +entirely at your own risk. The copyright holder will not be liable for +any legal damages whatsoever connected with the use of this work. + +2. The copyright holder retain all copyright to the work. All copies of +the work and all works derived from it must contain (1) this copyright +notice, and (2) additional notices describing the content, dates and +copyright holder of modifications or additions made to the work, if +any, including distribution and use conditions and intellectual property +claims. Derived works must be clearly distinguished from the original +work, both by name and by the prominent inclusion of explicit +descriptions of overlaps and differences. + +3. The names and trademarks of the copyright holder may not be used in +advertising or publicity related to this work without specific prior +written permission. + +4. In return for the free use of this work, you are requested, but not +legally required, to do the following: + +* If you become aware of factors that may significantly affect other + users of the work, for example major bugs or + deficiencies or possible intellectual property issues, you are + requested to report them to the copyright holder, if possible + including redistributable fixes or workarounds. + +* If you use the work in scientific research or as part of a larger + software system, you are requested to cite the use in any related + publications or technical documentation. The work is based upon: + + Hyeonseob Nam, Bohyung Han. + Learning Multi-Domain Convolutional Neural Networks for Visual Tracking + CVPR, 2016. + + @InProceedings{nam2016mdnet, + author = {Nam, Hyeonseob and Han, Bohyung}, + title = {Learning Multi-Domain Convolutional Neural Networks for Visual Tracking}, + booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2016} + } + +This copyright notice must be retained with all copies of the software, +including any modified or derived versions. diff --git a/pyMDNet/README.md b/pyMDNet/README.md new file mode 100755 index 0000000..0b68bab --- /dev/null +++ b/pyMDNet/README.md @@ -0,0 +1,62 @@ +# py-MDNet + +by [Hyeonseob Nam](https://kr.linkedin.com/in/hyeonseob-nam/) and [Bohyung Han](http://cvlab.postech.ac.kr/~bhhan/) at POSTECH + +**Update (April, 2019)** +- Migration to python 3.6 & pyTorch 1.0 +- Efficiency improvement (~5fps) +- ImagNet-VID pretraining +- Code refactoring + +## Introduction +PyTorch implementation of MDNet, which runs at ~5fps with a single CPU core and a single GPU (GTX 1080 Ti). +#### [[Project]](http://cvlab.postech.ac.kr/research/mdnet/) [[Paper]](https://arxiv.org/abs/1510.07945) [[Matlab code]](https://github.com/HyeonseobNam/MDNet) + +If you're using this code for your research, please cite: + + @InProceedings{nam2016mdnet, + author = {Nam, Hyeonseob and Han, Bohyung}, + title = {Learning Multi-Domain Convolutional Neural Networks for Visual Tracking}, + booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2016} + } + +## Results on OTB +- Raw results of MDNet pretrained on **VOT-OTB** (VOT13,14,15 excluding OTB): [Google drive link](https://drive.google.com/open?id=1ZSCj1UEn4QhoRypgH28hVxSgWbI8q8Hl) +- Raw results of MDNet pretrained on **Imagenet-VID**: [Google drive link](https://drive.google.com/open?id=14lJGcumtBRmtpZhmgY1BsrbEQixfhIpP) + +<img src="./figs/tb100-precision.png" width="400"> <img src="./figs/tb100-success.png" width="400"> +<img src="./figs/tb50-precision.png" width="400"> <img src="./figs/tb50-success.png" width="400"> +<img src="./figs/otb2013-precision.png" width="400"> <img src="./figs/otb2013-success.png" width="400"> + +## Prerequisites +- python 3.6+ +- opencv 3.0+ +- [PyTorch 1.0+](http://pytorch.org/) and its dependencies +- for GPU support: a GPU with ~3G memory + +## Usage + +### Tracking +```bash + python tracking/run_tracker.py -s DragonBaby [-d (display fig)] [-f (save fig)] +``` + - You can provide a sequence configuration in two ways (see tracking/gen_config.py): + - ```python tracking/run_tracker.py -s [seq name]``` + - ```python tracking/run_tracker.py -j [json path]``` + +### Pretraining + - Download [VGG-M](http://www.vlfeat.org/matconvnet/models/imagenet-vgg-m.mat) (matconvnet model) and save as "models/imagenet-vgg-m.mat" + - Pretraining on VOT-OTB + - Download [VOT](http://www.votchallenge.net/) datasets into "datasets/VOT/vot201x" + ``` bash + python pretrain/prepro_vot.py + python pretrain/train_mdnet.py -d vot + ``` + - Pretraining on ImageNet-VID + - Download [ImageNet-VID](http://bvisionweb1.cs.unc.edu/ilsvrc2015/download-videos-3j16.php#vid) dataset into "datasets/ILSVRC" + ``` bash + python pretrain/prepro_imagenet.py + python pretrain/train_mdnet.py -d imagenet + ``` diff --git a/pyMDNet/datasets/OTB/DragonBaby/attrs.txt b/pyMDNet/datasets/OTB/DragonBaby/attrs.txt new file mode 100755 index 0000000..25e6dc5 --- /dev/null +++ b/pyMDNet/datasets/OTB/DragonBaby/attrs.txt @@ -0,0 +1 @@ +SV, OCC, MB, FM, IPR, OPR, OV diff --git a/pyMDNet/datasets/OTB/DragonBaby/cfg.json b/pyMDNet/datasets/OTB/DragonBaby/cfg.json new file mode 100755 index 0000000..67f8d81 --- /dev/null +++ b/pyMDNet/datasets/OTB/DragonBaby/cfg.json @@ -0,0 +1,704 @@ +{ + "name": "DragonBaby", + "path": "./data/DragonBaby/img/", + "startFrame": 1, + "endFrame": 113, + "attributes": [ + "SV", + "OCC", + "MB", + "FM", + "IPR", + "OPR", + "OV" + ], + "nz": 4, + "ext": "jpg", + "imgFormat": "{0:04d}.jpg", + "init_rect": [ + 0, + 0, + 0, + 0 + ], + "gtRect": [ + [ + 160, + 83, + 56, + 65 + ], + [ + 166, + 84, + 55, + 65 + ], + [ + 173, + 78, + 56, + 65 + ], + [ + 175, + 75, + 55, + 65 + ], + [ + 179, + 76, + 56, + 67 + ], + [ + 188, + 67, + 59, + 65 + ], + [ + 183, + 53, + 65, + 73 + ], + [ + 162, + 37, + 65, + 58 + ], + [ + 156, + 39, + 65, + 57 + ], + [ + 152, + 41, + 65, + 71 + ], + [ + 145, + 59, + 65, + 71 + ], + [ + 143, + 67, + 65, + 65 + ], + [ + 143, + 72, + 65, + 65 + ], + [ + 143, + 78, + 62, + 65 + ], + [ + 144, + 88, + 65, + 65 + ], + [ + 149, + 91, + 65, + 65 + ], + [ + 162, + 89, + 65, + 65 + ], + [ + 188, + 89, + 65, + 65 + ], + [ + 192, + 92, + 65, + 65 + ], + [ + 189, + 83, + 65, + 65 + ], + [ + 184, + 84, + 65, + 65 + ], + [ + 177, + 85, + 65, + 65 + ], + [ + 166, + 82, + 65, + 65 + ], + [ + 157, + 82, + 65, + 65 + ], + [ + 135, + 88, + 65, + 65 + ], + [ + 143, + 93, + 65, + 65 + ], + [ + 162, + 83, + 73, + 65 + ], + [ + 190, + 80, + 65, + 65 + ], + [ + 194, + 78, + 65, + 65 + ], + [ + 215, + 95, + 72, + 65 + ], + [ + 212, + 93, + 73, + 75 + ], + [ + 204, + 86, + 73, + 75 + ], + [ + 203, + 75, + 71, + 78 + ], + [ + 216, + 66, + 71, + 84 + ], + [ + 223, + 66, + 72, + 81 + ], + [ + 226, + 70, + 72, + 80 + ], + [ + 221, + 84, + 68, + 72 + ], + [ + 229, + 88, + 64, + 72 + ], + [ + 222, + 92, + 65, + 65 + ], + [ + 219, + 84, + 65, + 65 + ], + [ + 190, + 55, + 65, + 65 + ], + [ + 136, + 40, + 71, + 55 + ], + [ + 110, + 41, + 65, + 56 + ], + [ + 51, + 39, + 65, + 65 + ], + [ + 13, + 41, + 80, + 71 + ], + [ + 20, + 137, + 73, + 65 + ], + [ + 79, + 89, + 71, + 65 + ], + [ + 104, + 51, + 70, + 65 + ], + [ + 131, + 39, + 61, + 59 + ], + [ + 164, + 38, + 56, + 49 + ], + [ + 173, + 38, + 60, + 49 + ], + [ + 181, + 43, + 62, + 52 + ], + [ + 199, + 56, + 65, + 65 + ], + [ + 191, + 71, + 65, + 58 + ], + [ + 198, + 78, + 58, + 62 + ], + [ + 204, + 77, + 54, + 70 + ], + [ + 228, + 63, + 55, + 65 + ], + [ + 240, + 59, + 58, + 65 + ], + [ + 246, + 65, + 60, + 66 + ], + [ + 246, + 71, + 59, + 64 + ], + [ + 231, + 66, + 65, + 65 + ], + [ + 191, + 85, + 65, + 71 + ], + [ + 181, + 102, + 65, + 76 + ], + [ + 173, + 138, + 65, + 76 + ], + [ + 167, + 148, + 65, + 74 + ], + [ + 158, + 117, + 65, + 84 + ], + [ + 154, + 106, + 65, + 76 + ], + [ + 135, + 74, + 65, + 87 + ], + [ + 122, + 54, + 70, + 80 + ], + [ + 121, + 51, + 67, + 88 + ], + [ + 139, + 64, + 68, + 86 + ], + [ + 154, + 74, + 65, + 82 + ], + [ + 153, + 72, + 65, + 89 + ], + [ + 158, + 65, + 65, + 76 + ], + [ + 166, + 49, + 57, + 84 + ], + [ + 182, + 45, + 65, + 65 + ], + [ + 199, + 60, + 58, + 66 + ], + [ + 202, + 73, + 57, + 65 + ], + [ + 201, + 76, + 62, + 65 + ], + [ + 107, + 129, + 108, + 125 + ], + [ + 117, + 164, + 96, + 129 + ], + [ + 109, + 198, + 94, + 118 + ], + [ + 95, + 183, + 88, + 116 + ], + [ + 97, + 143, + 86, + 114 + ], + [ + 100, + 116, + 78, + 119 + ], + [ + 115, + 117, + 81, + 122 + ], + [ + 157, + 124, + 82, + 111 + ], + [ + 168, + 115, + 74, + 114 + ], + [ + 193, + 96, + 82, + 108 + ], + [ + 173, + 58, + 87, + 106 + ], + [ + 154, + 48, + 89, + 94 + ], + [ + 125, + 41, + 83, + 74 + ], + [ + 109, + 39, + 82, + 65 + ], + [ + 111, + 43, + 81, + 65 + ], + [ + 119, + 48, + 72, + 71 + ], + [ + 123, + 60, + 72, + 74 + ], + [ + 128, + 82, + 63, + 68 + ], + [ + 133, + 89, + 59, + 65 + ], + [ + 142, + 76, + 65, + 65 + ], + [ + 157, + 53, + 65, + 73 + ], + [ + 171, + 57, + 59, + 65 + ], + [ + 186, + 57, + 49, + 69 + ], + [ + 180, + 61, + 55, + 65 + ], + [ + 170, + 74, + 59, + 63 + ], + [ + 166, + 76, + 55, + 71 + ], + [ + 159, + 84, + 58, + 64 + ], + [ + 157, + 91, + 57, + 64 + ], + [ + 157, + 89, + 52, + 71 + ], + [ + 159, + 87, + 52, + 71 + ], + [ + 175, + 79, + 54, + 74 + ], + [ + 197, + 80, + 55, + 71 + ], + [ + 234, + 79, + 52, + 67 + ], + [ + 237, + 78, + 62, + 67 + ] + ] +} \ No newline at end of file diff --git a/pyMDNet/datasets/OTB/DragonBaby/cfg.mat b/pyMDNet/datasets/OTB/DragonBaby/cfg.mat new file mode 100755 index 0000000..f1c89f4 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/cfg.mat differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/groundtruth_rect.txt b/pyMDNet/datasets/OTB/DragonBaby/groundtruth_rect.txt new file mode 100755 index 0000000..5f8c977 --- /dev/null +++ b/pyMDNet/datasets/OTB/DragonBaby/groundtruth_rect.txt @@ -0,0 +1,113 @@ +160,83,56,65 +166,84,55,65 +173,78,56,65 +175,75,55,65 +179,76,56,67 +188,67,59,65 +183,53,65,73 +162,37,65,58 +156,39,65,57 +152,41,65,71 +145,59,65,71 +143,67,65,65 +143,72,65,65 +143,78,62,65 +144,88,65,65 +149,91,65,65 +162,89,65,65 +188,89,65,65 +192,92,65,65 +189,83,65,65 +184,84,65,65 +177,85,65,65 +166,82,65,65 +157,82,65,65 +135,88,65,65 +143,93,65,65 +162,83,73,65 +190,80,65,65 +194,78,65,65 +215,95,72,65 +212,93,73,75 +204,86,73,75 +203,75,71,78 +216,66,71,84 +223,66,72,81 +226,70,72,80 +221,84,68,72 +229,88,64,72 +222,92,65,65 +219,84,65,65 +190,55,65,65 +136,40,71,55 +110,41,65,56 +51,39,65,65 +13,41,80,71 +20,137,73,65 +79,89,71,65 +104,51,70,65 +131,39,61,59 +164,38,56,49 +173,38,60,49 +181,43,62,52 +199,56,65,65 +191,71,65,58 +198,78,58,62 +204,77,54,70 +228,63,55,65 +240,59,58,65 +246,65,60,66 +246,71,59,64 +231,66,65,65 +191,85,65,71 +181,102,65,76 +173,138,65,76 +167,148,65,74 +158,117,65,84 +154,106,65,76 +135,74,65,87 +122,54,70,80 +121,51,67,88 +139,64,68,86 +154,74,65,82 +153,72,65,89 +158,65,65,76 +166,49,57,84 +182,45,65,65 +199,60,58,66 +202,73,57,65 +201,76,62,65 +107,129,108,125 +117,164,96,129 +109,198,94,118 +95,183,88,116 +97,143,86,114 +100,116,78,119 +115,117,81,122 +157,124,82,111 +168,115,74,114 +193,96,82,108 +173,58,87,106 +154,48,89,94 +125,41,83,74 +109,39,82,65 +111,43,81,65 +119,48,72,71 +123,60,72,74 +128,82,63,68 +133,89,59,65 +142,76,65,65 +157,53,65,73 +171,57,59,65 +186,57,49,69 +180,61,55,65 +170,74,59,63 +166,76,55,71 +159,84,58,64 +157,91,57,64 +157,89,52,71 +159,87,52,71 +175,79,54,74 +197,80,55,71 +234,79,52,67 +237,78,62,67 diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0001.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0001.jpg new file mode 100755 index 0000000..0af0203 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0001.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0002.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0002.jpg new file mode 100755 index 0000000..b58656a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0002.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0003.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0003.jpg new file mode 100755 index 0000000..ab853ea Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0003.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0004.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0004.jpg new file mode 100755 index 0000000..8d23d5d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0004.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0005.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0005.jpg new file mode 100755 index 0000000..0131b4d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0005.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0006.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0006.jpg new file mode 100755 index 0000000..d55ee12 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0006.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0007.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0007.jpg new file mode 100755 index 0000000..a3a2ae2 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0007.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0008.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0008.jpg new file mode 100755 index 0000000..d471399 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0008.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0009.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0009.jpg new file mode 100755 index 0000000..9c5755b Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0009.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0010.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0010.jpg new file mode 100755 index 0000000..5b8f18e Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0010.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0011.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0011.jpg new file mode 100755 index 0000000..7a0f07c Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0011.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0012.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0012.jpg new file mode 100755 index 0000000..6db2044 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0012.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0013.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0013.jpg new file mode 100755 index 0000000..7ce721a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0013.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0014.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0014.jpg new file mode 100755 index 0000000..bdf46bc Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0014.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0015.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0015.jpg new file mode 100755 index 0000000..be39095 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0015.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0016.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0016.jpg new file mode 100755 index 0000000..769711d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0016.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0017.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0017.jpg new file mode 100755 index 0000000..2e26bbc Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0017.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0018.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0018.jpg new file mode 100755 index 0000000..0ce3fe0 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0018.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0019.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0019.jpg new file mode 100755 index 0000000..ecf73ed Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0019.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0020.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0020.jpg new file mode 100755 index 0000000..86fed2a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0020.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0021.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0021.jpg new file mode 100755 index 0000000..af6c7b5 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0021.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0022.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0022.jpg new file mode 100755 index 0000000..564e8ae Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0022.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0023.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0023.jpg new file mode 100755 index 0000000..af85c37 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0023.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0024.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0024.jpg new file mode 100755 index 0000000..59ae24d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0024.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0025.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0025.jpg new file mode 100755 index 0000000..d8cf0b8 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0025.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0026.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0026.jpg new file mode 100755 index 0000000..f1e5ec1 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0026.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0027.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0027.jpg new file mode 100755 index 0000000..23bd53a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0027.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0028.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0028.jpg new file mode 100755 index 0000000..d504b85 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0028.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0029.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0029.jpg new file mode 100755 index 0000000..f0b7049 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0029.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0030.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0030.jpg new file mode 100755 index 0000000..277f5de Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0030.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0031.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0031.jpg new file mode 100755 index 0000000..018757e Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0031.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0032.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0032.jpg new file mode 100755 index 0000000..e6ee607 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0032.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0033.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0033.jpg new file mode 100755 index 0000000..7e2753a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0033.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0034.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0034.jpg new file mode 100755 index 0000000..1a5ba63 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0034.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0035.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0035.jpg new file mode 100755 index 0000000..574dffe Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0035.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0036.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0036.jpg new file mode 100755 index 0000000..3f3ef9c Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0036.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0037.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0037.jpg new file mode 100755 index 0000000..78d1c36 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0037.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0038.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0038.jpg new file mode 100755 index 0000000..f6a01ce Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0038.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0039.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0039.jpg new file mode 100755 index 0000000..3250fe5 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0039.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0040.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0040.jpg new file mode 100755 index 0000000..01e6e83 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0040.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0041.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0041.jpg new file mode 100755 index 0000000..14b68f3 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0041.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0042.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0042.jpg new file mode 100755 index 0000000..cb67919 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0042.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0043.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0043.jpg new file mode 100755 index 0000000..b9fefe1 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0043.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0044.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0044.jpg new file mode 100755 index 0000000..d7d975f Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0044.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0045.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0045.jpg new file mode 100755 index 0000000..fc9afd2 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0045.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0046.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0046.jpg new file mode 100755 index 0000000..b5ead1f Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0046.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0047.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0047.jpg new file mode 100755 index 0000000..b78e18e Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0047.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0048.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0048.jpg new file mode 100755 index 0000000..2e898d7 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0048.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0049.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0049.jpg new file mode 100755 index 0000000..0856c8d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0049.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0050.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0050.jpg new file mode 100755 index 0000000..fc11107 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0050.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0051.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0051.jpg new file mode 100755 index 0000000..77d13b2 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0051.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0052.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0052.jpg new file mode 100755 index 0000000..2d795a2 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0052.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0053.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0053.jpg new file mode 100755 index 0000000..f808bfe Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0053.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0054.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0054.jpg new file mode 100755 index 0000000..b4d77a5 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0054.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0055.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0055.jpg new file mode 100755 index 0000000..6d53411 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0055.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0056.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0056.jpg new file mode 100755 index 0000000..a57fe69 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0056.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0057.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0057.jpg new file mode 100755 index 0000000..84856c9 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0057.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0058.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0058.jpg new file mode 100755 index 0000000..daa8bea Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0058.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0059.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0059.jpg new file mode 100755 index 0000000..24beb1b Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0059.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0060.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0060.jpg new file mode 100755 index 0000000..529d8af Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0060.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0061.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0061.jpg new file mode 100755 index 0000000..c677534 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0061.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0062.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0062.jpg new file mode 100755 index 0000000..9a54922 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0062.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0063.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0063.jpg new file mode 100755 index 0000000..e2c2f8d Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0063.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0064.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0064.jpg new file mode 100755 index 0000000..f4bbb3c Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0064.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0065.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0065.jpg new file mode 100755 index 0000000..a82699b Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0065.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0066.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0066.jpg new file mode 100755 index 0000000..fb4e316 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0066.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0067.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0067.jpg new file mode 100755 index 0000000..1112917 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0067.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0068.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0068.jpg new file mode 100755 index 0000000..0f33638 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0068.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0069.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0069.jpg new file mode 100755 index 0000000..845c3bb Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0069.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0070.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0070.jpg new file mode 100755 index 0000000..e58a9b0 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0070.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0071.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0071.jpg new file mode 100755 index 0000000..df5d1b3 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0071.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0072.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0072.jpg new file mode 100755 index 0000000..688ff58 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0072.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0073.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0073.jpg new file mode 100755 index 0000000..16b6435 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0073.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0074.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0074.jpg new file mode 100755 index 0000000..3cf53e6 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0074.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0075.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0075.jpg new file mode 100755 index 0000000..4bd7926 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0075.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0076.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0076.jpg new file mode 100755 index 0000000..f9f91be Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0076.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0077.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0077.jpg new file mode 100755 index 0000000..da30d63 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0077.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0078.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0078.jpg new file mode 100755 index 0000000..ffe6d8a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0078.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0079.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0079.jpg new file mode 100755 index 0000000..87d31ad Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0079.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0080.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0080.jpg new file mode 100755 index 0000000..a9808d0 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0080.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0081.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0081.jpg new file mode 100755 index 0000000..ce58d47 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0081.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0082.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0082.jpg new file mode 100755 index 0000000..3b43891 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0082.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0083.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0083.jpg new file mode 100755 index 0000000..f568048 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0083.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0084.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0084.jpg new file mode 100755 index 0000000..c210164 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0084.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0085.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0085.jpg new file mode 100755 index 0000000..fa0eab8 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0085.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0086.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0086.jpg new file mode 100755 index 0000000..4edfe5b Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0086.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0087.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0087.jpg new file mode 100755 index 0000000..5878161 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0087.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0088.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0088.jpg new file mode 100755 index 0000000..4441147 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0088.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0089.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0089.jpg new file mode 100755 index 0000000..7333a1b Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0089.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0090.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0090.jpg new file mode 100755 index 0000000..a24b8f8 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0090.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0091.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0091.jpg new file mode 100755 index 0000000..8f5e0d3 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0091.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0092.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0092.jpg new file mode 100755 index 0000000..70ccb2e Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0092.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0093.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0093.jpg new file mode 100755 index 0000000..c8856e8 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0093.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0094.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0094.jpg new file mode 100755 index 0000000..5d74b4a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0094.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0095.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0095.jpg new file mode 100755 index 0000000..3e54868 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0095.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0096.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0096.jpg new file mode 100755 index 0000000..0d43b2a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0096.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0097.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0097.jpg new file mode 100755 index 0000000..79653ac Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0097.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0098.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0098.jpg new file mode 100755 index 0000000..eef9430 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0098.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0099.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0099.jpg new file mode 100755 index 0000000..280b5d4 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0099.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0100.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0100.jpg new file mode 100755 index 0000000..157f768 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0100.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0101.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0101.jpg new file mode 100755 index 0000000..0b29957 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0101.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0102.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0102.jpg new file mode 100755 index 0000000..0c5af30 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0102.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0103.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0103.jpg new file mode 100755 index 0000000..77170d2 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0103.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0104.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0104.jpg new file mode 100755 index 0000000..bab96bb Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0104.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0105.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0105.jpg new file mode 100755 index 0000000..7232def Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0105.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0106.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0106.jpg new file mode 100755 index 0000000..9371de7 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0106.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0107.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0107.jpg new file mode 100755 index 0000000..434e15e Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0107.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0108.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0108.jpg new file mode 100755 index 0000000..b39f335 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0108.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0109.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0109.jpg new file mode 100755 index 0000000..45e9fb8 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0109.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0110.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0110.jpg new file mode 100755 index 0000000..19734e4 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0110.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0111.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0111.jpg new file mode 100755 index 0000000..4ad6525 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0111.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0112.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0112.jpg new file mode 100755 index 0000000..436ef5a Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0112.jpg differ diff --git a/pyMDNet/datasets/OTB/DragonBaby/img/0113.jpg b/pyMDNet/datasets/OTB/DragonBaby/img/0113.jpg new file mode 100755 index 0000000..9eb2953 Binary files /dev/null and b/pyMDNet/datasets/OTB/DragonBaby/img/0113.jpg differ diff --git a/pyMDNet/datasets/list/vot-otb.txt b/pyMDNet/datasets/list/vot-otb.txt new file mode 100755 index 0000000..768656b --- /dev/null +++ b/pyMDNet/datasets/list/vot-otb.txt @@ -0,0 +1,58 @@ +vot2013/cup +vot2013/iceskater +vot2013/juice +vot2014/ball +vot2014/bicycle +vot2014/drunk +vot2014/fish1 +vot2014/hand1 +vot2014/polarbear +vot2014/sphere +vot2014/sunshade +vot2014/surfing +vot2014/torus +vot2014/tunnel +vot2015/bag +vot2015/ball1 +vot2015/ball2 +vot2015/birds1 +vot2015/birds2 +vot2015/blanket +vot2015/bmx +vot2015/book +vot2015/butterfly +vot2015/crossing +vot2015/dinosaur +vot2015/fernando +vot2015/fish1 +vot2015/fish2 +vot2015/fish3 +vot2015/fish4 +vot2015/glove +vot2015/godfather +vot2015/graduate +vot2015/gymnastics1 +vot2015/gymnastics2 +vot2015/gymnastics3 +vot2015/gymnastics4 +vot2015/hand +vot2015/handball1 +vot2015/handball2 +vot2015/helicopter +vot2015/iceskater1 +vot2015/leaves +vot2015/marching +vot2015/motocross2 +vot2015/nature +vot2015/octopus +vot2015/rabbit +vot2015/racing +vot2015/road +vot2015/sheep +vot2015/singer3 +vot2015/soccer2 +vot2015/soldier +vot2015/sphere +vot2015/traffic +vot2015/tunnel +vot2015/wiper diff --git a/pyMDNet/figs/otb2013-precision.png b/pyMDNet/figs/otb2013-precision.png new file mode 100755 index 0000000..41b9da3 Binary files /dev/null and b/pyMDNet/figs/otb2013-precision.png differ diff --git a/pyMDNet/figs/otb2013-success.png b/pyMDNet/figs/otb2013-success.png new file mode 100755 index 0000000..3210620 Binary files /dev/null and b/pyMDNet/figs/otb2013-success.png differ diff --git a/pyMDNet/figs/tb100-precision.png b/pyMDNet/figs/tb100-precision.png new file mode 100755 index 0000000..b3750a9 Binary files /dev/null and b/pyMDNet/figs/tb100-precision.png differ diff --git a/pyMDNet/figs/tb100-success.png b/pyMDNet/figs/tb100-success.png new file mode 100755 index 0000000..9bec6c7 Binary files /dev/null and b/pyMDNet/figs/tb100-success.png differ diff --git a/pyMDNet/figs/tb50-precision.png b/pyMDNet/figs/tb50-precision.png new file mode 100755 index 0000000..57ca130 Binary files /dev/null and b/pyMDNet/figs/tb50-precision.png differ diff --git a/pyMDNet/figs/tb50-success.png b/pyMDNet/figs/tb50-success.png new file mode 100755 index 0000000..02289b6 Binary files /dev/null and b/pyMDNet/figs/tb50-success.png differ diff --git a/pyMDNet/models/mdnet_imagenet_vid.pth b/pyMDNet/models/mdnet_imagenet_vid.pth new file mode 100755 index 0000000..dac969f Binary files /dev/null and b/pyMDNet/models/mdnet_imagenet_vid.pth differ diff --git a/pyMDNet/modules/__init__.py b/pyMDNet/modules/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pyMDNet/modules/__pycache__/__init__.cpython-37.pyc b/pyMDNet/modules/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..fffbe9e Binary files /dev/null and b/pyMDNet/modules/__pycache__/__init__.cpython-37.pyc differ diff --git a/pyMDNet/modules/__pycache__/model.cpython-37.pyc b/pyMDNet/modules/__pycache__/model.cpython-37.pyc new file mode 100755 index 0000000..45ff081 Binary files /dev/null and b/pyMDNet/modules/__pycache__/model.cpython-37.pyc differ diff --git a/pyMDNet/modules/__pycache__/sample_generator.cpython-37.pyc b/pyMDNet/modules/__pycache__/sample_generator.cpython-37.pyc new file mode 100755 index 0000000..eb43161 Binary files /dev/null and b/pyMDNet/modules/__pycache__/sample_generator.cpython-37.pyc differ diff --git a/pyMDNet/modules/__pycache__/utils.cpython-37.pyc b/pyMDNet/modules/__pycache__/utils.cpython-37.pyc new file mode 100755 index 0000000..a35aeae Binary files /dev/null and b/pyMDNet/modules/__pycache__/utils.cpython-37.pyc differ diff --git a/pyMDNet/modules/model.py b/pyMDNet/modules/model.py new file mode 100755 index 0000000..5151740 --- /dev/null +++ b/pyMDNet/modules/model.py @@ -0,0 +1,172 @@ +import os +import scipy.io +import numpy as np +from collections import OrderedDict + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim + + +def append_params(params, module, prefix): + for child in module.children(): + for k,p in child._parameters.items(): + if p is None: continue + + if isinstance(child, nn.BatchNorm2d): + name = prefix + '_bn_' + k + else: + name = prefix + '_' + k + + if name not in params: + params[name] = p + else: + raise RuntimeError('Duplicated param name: {:s}'.format(name)) + + +def set_optimizer(model, lr_base, lr_mult, train_all=False, momentum=0.9, w_decay=0.0005): + if train_all: + params = model.get_all_params() + else: + params = model.get_learnable_params() + param_list = [] + for k, p in params.items(): + lr = lr_base + for l, m in lr_mult.items(): + if k.startswith(l): + lr = lr_base * m + param_list.append({'params': [p], 'lr':lr}) + optimizer = optim.SGD(param_list, lr = lr, momentum=momentum, weight_decay=w_decay) + return optimizer + + +class MDNet(nn.Module): + def __init__(self, model_path=None, K=1): + super(MDNet, self).__init__() + self.K = K + self.layers = nn.Sequential(OrderedDict([ + ('conv1', nn.Sequential(nn.Conv2d(3, 96, kernel_size=7, stride=2), + nn.ReLU(inplace=True), + nn.LocalResponseNorm(2), + nn.MaxPool2d(kernel_size=3, stride=2))), + ('conv2', nn.Sequential(nn.Conv2d(96, 256, kernel_size=5, stride=2), + nn.ReLU(inplace=True), + nn.LocalResponseNorm(2), + nn.MaxPool2d(kernel_size=3, stride=2))), + ('conv3', nn.Sequential(nn.Conv2d(256, 512, kernel_size=3, stride=1), + nn.ReLU(inplace=True))), + ('fc4', nn.Sequential(nn.Linear(512 * 3 * 3, 512), + nn.ReLU(inplace=True))), + ('fc5', nn.Sequential(nn.Dropout(0.5), + nn.Linear(512, 512), + nn.ReLU(inplace=True)))])) + + self.branches = nn.ModuleList([nn.Sequential(nn.Dropout(0.5), + nn.Linear(512, 2)) for _ in range(K)]) + + for m in self.layers.modules(): + if isinstance(m, nn.Linear): + nn.init.normal_(m.weight, 0, 0.01) + nn.init.constant_(m.bias, 0.1) + for m in self.branches.modules(): + if isinstance(m, nn.Linear): + nn.init.normal_(m.weight, 0, 0.01) + nn.init.constant_(m.bias, 0) + + if model_path is not None: + if os.path.splitext(model_path)[1] == '.pth': + self.load_model(model_path) + elif os.path.splitext(model_path)[1] == '.mat': + self.load_mat_model(model_path) + else: + raise RuntimeError('Unkown model format: {:s}'.format(model_path)) + self.build_param_dict() + + def build_param_dict(self): + self.params = OrderedDict() + for name, module in self.layers.named_children(): + append_params(self.params, module, name) + for k, module in enumerate(self.branches): + append_params(self.params, module, 'fc6_{:d}'.format(k)) + + def set_learnable_params(self, layers): + for k, p in self.params.items(): + if any([k.startswith(l) for l in layers]): + p.requires_grad = True + else: + p.requires_grad = False + + def get_learnable_params(self): + params = OrderedDict() + for k, p in self.params.items(): + if p.requires_grad: + params[k] = p + return params + + def get_all_params(self): + params = OrderedDict() + for k, p in self.params.items(): + params[k] = p + return params + + def forward(self, x, k=0, in_layer='conv1', out_layer='fc6'): + # forward model from in_layer to out_layer + run = False + for name, module in self.layers.named_children(): + if name == in_layer: + run = True + if run: + x = module(x) + if name == 'conv3': + x = x.view(x.size(0), -1) + if name == out_layer: + return x + + x = self.branches[k](x) + if out_layer=='fc6': + return x + elif out_layer=='fc6_softmax': + return F.softmax(x, dim=1) + + def load_model(self, model_path): + states = torch.load(model_path) + shared_layers = states['shared_layers'] + self.layers.load_state_dict(shared_layers) + + def load_mat_model(self, matfile): + mat = scipy.io.loadmat(matfile) + mat_layers = list(mat['layers'])[0] + + # copy conv weights + for i in range(3): + weight, bias = mat_layers[i * 4]['weights'].item()[0] + self.layers[i][0].weight.data = torch.from_numpy(np.transpose(weight, (3, 2, 0, 1))) + self.layers[i][0].bias.data = torch.from_numpy(bias[:, 0]) + + +class BCELoss(nn.Module): + def forward(self, pos_score, neg_score, average=True): + pos_loss = -F.log_softmax(pos_score, dim=1)[:, 1] + neg_loss = -F.log_softmax(neg_score, dim=1)[:, 0] + + loss = pos_loss.sum() + neg_loss.sum() + if average: + loss /= (pos_loss.size(0) + neg_loss.size(0)) + return loss + + +class Accuracy(): + def __call__(self, pos_score, neg_score): + pos_correct = (pos_score[:, 1] > pos_score[:, 0]).sum().float() + neg_correct = (neg_score[:, 1] < neg_score[:, 0]).sum().float() + acc = (pos_correct + neg_correct) / (pos_score.size(0) + neg_score.size(0) + 1e-8) + return acc.item() + + +class Precision(): + def __call__(self, pos_score, neg_score): + scores = torch.cat((pos_score[:, 1], neg_score[:, 1]), 0) + topk = torch.topk(scores, pos_score.size(0))[1] + prec = (topk < pos_score.size(0)).float().sum() / (pos_score.size(0) + 1e-8) + return prec.item() diff --git a/pyMDNet/modules/sample_generator.py b/pyMDNet/modules/sample_generator.py new file mode 100755 index 0000000..74f353f --- /dev/null +++ b/pyMDNet/modules/sample_generator.py @@ -0,0 +1,96 @@ +import numpy as np +from PIL import Image + +from .utils import overlap_ratio + + +class SampleGenerator(): + def __init__(self, type_, img_size, trans=1, scale=1, aspect=None, valid=False): + self.type = type_ + self.img_size = np.array(img_size) # (w, h) + self.trans = trans + self.scale = scale + self.aspect = aspect + self.valid = valid + + def _gen_samples(self, bb, n): + # + # bb: target bbox (min_x,min_y,w,h) + bb = np.array(bb, dtype='float32') + + # (center_x, center_y, w, h) + sample = np.array([bb[0] + bb[2] / 2, bb[1] + bb[3] / 2, bb[2], bb[3]], dtype='float32') + samples = np.tile(sample[None, :], (n ,1)) + + # vary aspect ratio + if self.aspect is not None: + ratio = np.random.rand(n, 2) * 2 - 1 + samples[:, 2:] *= self.aspect ** ratio + + # sample generation + if self.type == 'gaussian': + samples[:, :2] += self.trans * np.mean(bb[2:]) * np.clip(0.5 * np.random.randn(n, 2), -1, 1) + samples[:, 2:] *= self.scale ** np.clip(0.5 * np.random.randn(n, 1), -1, 1) + + elif self.type == 'uniform': + samples[:, :2] += self.trans * np.mean(bb[2:]) * (np.random.rand(n, 2) * 2 - 1) + samples[:, 2:] *= self.scale ** (np.random.rand(n, 1) * 2 - 1) + + elif self.type == 'whole': + m = int(2 * np.sqrt(n)) + xy = np.dstack(np.meshgrid(np.linspace(0, 1, m), np.linspace(0, 1, m))).reshape(-1, 2) + xy = np.random.permutation(xy)[:n] + samples[:, :2] = bb[2:] / 2 + xy * (self.img_size - bb[2:] / 2 - 1) + samples[:, 2:] *= self.scale ** (np.random.rand(n, 1) * 2 - 1) + + # adjust bbox range + samples[:, 2:] = np.clip(samples[:, 2:], 10, self.img_size - 10) + if self.valid: + samples[:, :2] = np.clip(samples[:, :2], samples[:, 2:] / 2, self.img_size - samples[:, 2:] / 2 - 1) + else: + samples[:, :2] = np.clip(samples[:, :2], 0, self.img_size) + + # (min_x, min_y, w, h) + samples[:, :2] -= samples[:, 2:] / 2 + + return samples + + def __call__(self, bbox, n, overlap_range=None, scale_range=None): + + if overlap_range is None and scale_range is None: + return self._gen_samples(bbox, n) + + else: + samples = None + remain = n + factor = 2 + while remain > 0 and factor < 16: + samples_ = self._gen_samples(bbox, remain * factor) + + idx = np.ones(len(samples_), dtype=bool) + if overlap_range is not None: + r = overlap_ratio(samples_, bbox) + idx *= (r >= overlap_range[0]) * (r <= overlap_range[1]) + if scale_range is not None: + s = np.prod(samples_[:, 2:], axis=1) / np.prod(bbox[2:]) + idx *= (s >= scale_range[0]) * (s <= scale_range[1]) + + samples_ = samples_[idx, :] + samples_ = samples_[:min(remain, len(samples_))] + if samples is None: + samples = samples_ + else: + samples = np.concatenate([samples, samples_]) + remain = n - len(samples) + factor = factor * 2 + + return samples + + def set_type(self, type_): + self.type = type_ + + def set_trans(self, trans): + self.trans = trans + + def expand_trans(self, trans_limit): + self.trans = min(self.trans * 1.1, trans_limit) diff --git a/pyMDNet/modules/utils.py b/pyMDNet/modules/utils.py new file mode 100755 index 0000000..4cfb38b --- /dev/null +++ b/pyMDNet/modules/utils.py @@ -0,0 +1,133 @@ +from scipy.misc import imresize +import numpy as np +import cv2 + + +def overlap_ratio(rect1, rect2): + ''' + Compute overlap ratio between two rects + - rect: 1d array of [x,y,w,h] or + 2d array of N x [x,y,w,h] + ''' + + if rect1.ndim == 1: + rect1 = rect1[None, :] + if rect2.ndim == 1: + rect2 = rect2[None, :] + + left = np.maximum(rect1[:, 0], rect2[:, 0]) + right = np.minimum(rect1[:, 0] + rect1[:, 2], rect2[:, 0] + rect2[:, 2]) + top = np.maximum(rect1[:, 1], rect2[:, 1]) + bottom = np.minimum(rect1[:, 1] + rect1[:, 3], rect2[:, 1] + rect2[:, 3]) + + intersect = np.maximum(0, right - left) * np.maximum(0, bottom - top) + union = rect1[:, 2] * rect1[:, 3] + rect2[:, 2] * rect2[:, 3] - intersect + iou = np.clip(intersect / union, 0, 1) + return iou + + +def crop_image2(img, bbox, img_size=107, padding=16, flip=False, rotate_limit=0, blur_limit=0): + x, y, w, h = np.array(bbox, dtype='float32') + + cx, cy = x + w/2, y + h/2 + + if padding > 0: + w += 2 * padding * w/img_size + h += 2 * padding * h/img_size + + # List of transformation matrices + matrices = [] + + # Translation matrix to move patch center to origin + translation_matrix = np.asarray([[1, 0, -cx], + [0, 1, -cy], + [0, 0, 1]], dtype=np.float32) + matrices.append(translation_matrix) + + # Scaling matrix according to image size + scaling_matrix = np.asarray([[img_size / w, 0, 0], + [0, img_size / h, 0], + [0, 0, 1]], dtype=np.float32) + matrices.append(scaling_matrix) + + # Define flip matrix + if flip and np.random.binomial(1, 0.5): + flip_matrix = np.eye(3, dtype=np.float32) + flip_matrix[0, 0] = -1 + matrices.append(flip_matrix) + + # Define rotation matrix + if rotate_limit and np.random.binomial(1, 0.5): + angle = np.random.uniform(-rotate_limit, rotate_limit) + alpha = np.cos(np.deg2rad(angle)) + beta = np.sin(np.deg2rad(angle)) + rotation_matrix = np.asarray([[alpha, -beta, 0], + [beta, alpha, 0], + [0, 0, 1]], dtype=np.float32) + matrices.append(rotation_matrix) + + # Translation matrix to move patch center from origin + revert_t_matrix = np.asarray([[1, 0, img_size / 2], + [0, 1, img_size / 2], + [0, 0, 1]], dtype=np.float32) + matrices.append(revert_t_matrix) + + # Aggregate all transformation matrices + matrix = np.eye(3) + for m_ in matrices: + matrix = np.matmul(m_, matrix) + + # Warp image, padded value is set to 128 + patch = cv2.warpPerspective(img, + matrix, + (img_size, img_size), + borderValue=128) + + if blur_limit and np.random.binomial(1, 0.5): + blur_size = np.random.choice(np.arange(1, blur_limit + 1, 2)) + patch = cv2.GaussianBlur(patch, (blur_size, blur_size), 0) + + return patch + + +def crop_image(img, bbox, img_size=107, padding=16, valid=False): + # This function is deprecated in favor of crop_image2 + + x,y,w,h = np.array(bbox, dtype='float32') + + half_w, half_h = w / 2, h / 2 + center_x, center_y = x + half_w, y + half_h + + if padding > 0: + pad_w = padding * w / img_size + pad_h = padding * h / img_size + half_w += pad_w + half_h += pad_h + + img_h, img_w, _ = img.shape + min_x = int(center_x - half_w + 0.5) + min_y = int(center_y - half_h + 0.5) + max_x = int(center_x + half_w + 0.5) + max_y = int(center_y + half_h + 0.5) + + if valid: + min_x = max(0, min_x) + min_y = max(0, min_y) + max_x = min(img_w, max_x) + max_y = min(img_h, max_y) + + if min_x >=0 and min_y >= 0 and max_x <= img_w and max_y <= img_h: + cropped = img[min_y:max_y, min_x:max_x, :] + + else: + min_x_val = max(0, min_x) + min_y_val = max(0, min_y) + max_x_val = min(img_w, max_x) + max_y_val = min(img_h, max_y) + + cropped = 128 * np.ones((max_y - min_y, max_x - min_x, 3), dtype='uint8') + cropped[min_y_val - min_y:max_y_val - min_y, min_x_val - min_x:max_x_val - min_x, :] \ + = img[min_y_val:max_y_val, min_x_val:max_x_val, :] + + scaled = imresize(cropped, (img_size, img_size)) + return scaled diff --git a/pyMDNet/pretrain/data/vot-otb.pkl b/pyMDNet/pretrain/data/vot-otb.pkl new file mode 100755 index 0000000..f1affdc Binary files /dev/null and b/pyMDNet/pretrain/data/vot-otb.pkl differ diff --git a/pyMDNet/pretrain/data_prov.py b/pyMDNet/pretrain/data_prov.py new file mode 100755 index 0000000..7010d64 --- /dev/null +++ b/pyMDNet/pretrain/data_prov.py @@ -0,0 +1,78 @@ +import numpy as np +from PIL import Image + +import torch +import torch.utils.data as data + +from modules.sample_generator import SampleGenerator +from modules.utils import crop_image2 + + +class RegionDataset(data.Dataset): + def __init__(self, img_list, gt, opts): + self.img_list = np.asarray(img_list) + self.gt = gt + + self.batch_frames = opts['batch_frames'] + self.batch_pos = opts['batch_pos'] + self.batch_neg = opts['batch_neg'] + + self.overlap_pos = opts['overlap_pos'] + self.overlap_neg = opts['overlap_neg'] + + self.crop_size = opts['img_size'] + self.padding = opts['padding'] + + self.flip = opts.get('flip', False) + self.rotate = opts.get('rotate', 0) + self.blur = opts.get('blur', 0) + + self.index = np.random.permutation(len(self.img_list)) + self.pointer = 0 + + image = Image.open(self.img_list[0]).convert('RGB') + self.pos_generator = SampleGenerator('uniform', image.size, + opts['trans_pos'], opts['scale_pos']) + self.neg_generator = SampleGenerator('uniform', image.size, + opts['trans_neg'], opts['scale_neg']) + + def __iter__(self): + return self + + def __next__(self): + next_pointer = min(self.pointer + self.batch_frames, len(self.img_list)) + idx = self.index[self.pointer:next_pointer] + if len(idx) < self.batch_frames: + self.index = np.random.permutation(len(self.img_list)) + next_pointer = self.batch_frames - len(idx) + idx = np.concatenate((idx, self.index[:next_pointer])) + self.pointer = next_pointer + + pos_regions = np.empty((0, 3, self.crop_size, self.crop_size), dtype='float32') + neg_regions = np.empty((0, 3, self.crop_size, self.crop_size), dtype='float32') + for i, (img_path, bbox) in enumerate(zip(self.img_list[idx], self.gt[idx])): + image = Image.open(img_path).convert('RGB') + image = np.asarray(image) + + n_pos = (self.batch_pos - len(pos_regions)) // (self.batch_frames - i) + n_neg = (self.batch_neg - len(neg_regions)) // (self.batch_frames - i) + pos_examples = self.pos_generator(bbox, n_pos, overlap_range=self.overlap_pos) + neg_examples = self.neg_generator(bbox, n_neg, overlap_range=self.overlap_neg) + + pos_regions = np.concatenate((pos_regions, self.extract_regions(image, pos_examples)), axis=0) + neg_regions = np.concatenate((neg_regions, self.extract_regions(image, neg_examples)), axis=0) + + pos_regions = torch.from_numpy(pos_regions) + neg_regions = torch.from_numpy(neg_regions) + return pos_regions, neg_regions + + next = __next__ + + def extract_regions(self, image, samples): + regions = np.zeros((len(samples), self.crop_size, self.crop_size, 3), dtype='uint8') + for i, sample in enumerate(samples): + regions[i] = crop_image2(image, sample, self.crop_size, self.padding, + self.flip, self.rotate, self.blur) + regions = regions.transpose(0, 3, 1, 2) + regions = regions.astype('float32') - 128. + return regions diff --git a/pyMDNet/pretrain/options_imagenet.yaml b/pyMDNet/pretrain/options_imagenet.yaml new file mode 100755 index 0000000..b0f550d --- /dev/null +++ b/pyMDNet/pretrain/options_imagenet.yaml @@ -0,0 +1,38 @@ +use_gpu: true + +# data path +data_path: "pretrain/data/imagenet_vid.pkl" + +# model path +init_model_path: "models/imagenet-vgg-m.mat" +model_path: "models/mdnet_imagenet_vid.pth" + +# input size +img_size: 107 +padding: 16 + +# batch size +batch_frames: 8 +batch_pos: 32 +batch_neg: 96 +batch_accum: 50 + +# training examples sampling +trans_pos: 0.1 +scale_pos: 1.3 +trans_neg: 2 +scale_neg: 1.6 +overlap_pos: [0.7, 1] +overlap_neg: [0, 0.5] + +# augmentation +flip: True +rotate: 30 +blur: 7 + +# training +lr: 0.0001 +grad_clip: 10 +lr_mult: {"fc": 10} +ft_layers: ["conv", "fc"] +n_cycles: 100 diff --git a/pyMDNet/pretrain/options_vot.yaml b/pyMDNet/pretrain/options_vot.yaml new file mode 100755 index 0000000..7375ac5 --- /dev/null +++ b/pyMDNet/pretrain/options_vot.yaml @@ -0,0 +1,32 @@ +use_gpu: true + +# data path +data_path: "pretrain/data/vot-otb.pkl" + +# model path +init_model_path: "models/imagenet-vgg-m.mat" +model_path: "models/mdnet_vot-otb.pth" + +# input size +img_size: 107 +padding: 16 + +# batch size +batch_frames: 8 +batch_pos: 32 +batch_neg: 96 + +# training examples sampling +trans_pos: 0.1 +scale_pos: 1.3 +trans_neg: 2 +scale_neg: 1.6 +overlap_pos: [0.7, 1] +overlap_neg: [0, 0.5] + +# training +lr: 0.0001 +grad_clip: 10 +lr_mult: {"fc": 10} +ft_layers: ["conv", "fc"] +n_cycles: 50 diff --git a/pyMDNet/pretrain/prepro_imagenet.py b/pyMDNet/pretrain/prepro_imagenet.py new file mode 100755 index 0000000..fef249f --- /dev/null +++ b/pyMDNet/pretrain/prepro_imagenet.py @@ -0,0 +1,80 @@ +import os +import numpy as np +import pickle +from collections import OrderedDict + +import xml.etree.ElementTree +import xmltodict + +seq_home = 'datasets/ILSVRC/' +output_path = 'pretrain/data/imagenet_vid.pkl' + +train_list = [p for p in os.listdir(seq_home + 'Data/VID/train')] +seq_list = [] +for num, cur_dir in enumerate(train_list): + seq_list += [os.path.join(cur_dir, p) for p in os.listdir(seq_home + 'Data/VID/train/' + cur_dir)] + +data = {} +completeNum = 0 +for i, seqname in enumerate(seq_list): + print('{}/{}: {}'.format(i, len(seq_list), seqname)) + seq_path = seq_home + 'Data/VID/train/' + seqname + gt_path = seq_home +'Annotations/VID/train/' + seqname + img_list = sorted([p for p in os.listdir(seq_path) if os.path.splitext(p)[1] == '.JPEG']) + + enable_gt = [] + enable_img_list = [] + save_enable = True + gt_list = sorted([os.path.join(gt_path, p) for p in os.listdir(gt_path) if os.path.splitext(p)[1] == '.xml']) + + for gidx in range(0, len(img_list)): + with open(gt_list[gidx]) as fd: + doc = xmltodict.parse(fd.read()) + try: + try: + object_ = doc['annotation']['object'][0] + except: + object_ = doc['annotation']['object'] + except: + ## no object, occlusion and hidden etc. + continue + + if int(object_['trackid']) != 0: + continue + + xmin = float(object_['bndbox']['xmin']) + xmax = float(object_['bndbox']['xmax']) + ymin = float(object_['bndbox']['ymin']) + ymax = float(object_['bndbox']['ymax']) + + ## discard too big object + if (float(doc['annotation']['size']['width']) / 2. < xmax - xmin ) and \ + (float(doc['annotation']['size']['height']) / 2. < ymax - ymin ): + continue + + cur_gt = np.zeros((4)) + cur_gt[0] = xmin + cur_gt[1] = ymin + cur_gt[2] = xmax - xmin + cur_gt[3] = ymax - ymin + + enable_gt.append(cur_gt) + enable_img_list.append(img_list[gidx]) + + if len(enable_img_list) == 0: + save_enable = False + + if save_enable: + assert len(enable_img_list) == len(enable_gt), "Lengths do not match!!" + enable_img_list = [os.path.join(seq_path, p) for p in enable_img_list] + data[seqname] = {'images':enable_img_list, 'gt':np.asarray(enable_gt)} + completeNum += 1 + print('Complete!') + +# Save db +output_dir = os.path.dirname(output_path) +os.makedirs(output_dir, exist_ok=True) +with open(output_path, 'wb') as fp: + pickle.dump(data, fp, -1) + +print('complete {} videos'.format(completeNum)) diff --git a/pyMDNet/pretrain/prepro_vot.py b/pyMDNet/pretrain/prepro_vot.py new file mode 100755 index 0000000..c2803ec --- /dev/null +++ b/pyMDNet/pretrain/prepro_vot.py @@ -0,0 +1,38 @@ +import os +import numpy as np +import pickle +from collections import OrderedDict + +seq_home = 'datasets/VOT' +seqlist_path = 'datasets/list/vot-otb.txt' +output_path = 'pretrain/data/vot-otb.pkl' + +with open(seqlist_path,'r') as fp: + seq_list = fp.read().splitlines() + +# Construct db +data = OrderedDict() +for i, seq in enumerate(seq_list): + img_list = sorted([p for p in os.listdir(os.path.join(seq_home, seq)) if os.path.splitext(p)[1] == '.jpg']) + gt = np.loadtxt(os.path.join(seq_home, seq, 'groundtruth.txt'), delimiter=',') + + if seq == 'vot2014/ball': + img_list = img_list[1:] + + assert len(img_list) == len(gt), "Lengths do not match!!" + + if gt.shape[1] == 8: + x_min = np.min(gt[:, [0, 2, 4, 6]], axis=1)[:, None] + y_min = np.min(gt[:, [1, 3, 5, 7]], axis=1)[:, None] + x_max = np.max(gt[:, [0, 2, 4, 6]], axis=1)[:, None] + y_max = np.max(gt[:, [1, 3, 5, 7]], axis=1)[:, None] + gt = np.concatenate((x_min, y_min, x_max - x_min, y_max - y_min), axis=1) + + img_list = [os.path.join(seq_home, seq, img) for img in img_list] + data[seq] = {'images': img_list, 'gt': gt} + +# Save db +output_dir = os.path.dirname(output_path) +os.makedirs(output_dir, exist_ok=True) +with open(output_path, 'wb') as fp: + pickle.dump(data, fp) diff --git a/pyMDNet/pretrain/train_mdnet.py b/pyMDNet/pretrain/train_mdnet.py new file mode 100755 index 0000000..a6728fc --- /dev/null +++ b/pyMDNet/pretrain/train_mdnet.py @@ -0,0 +1,92 @@ +import os, sys +import pickle +import yaml +import time +import argparse +import numpy as np + +import torch + +sys.path.insert(0,'.') +from data_prov import RegionDataset +from modules.model import MDNet, set_optimizer, BCELoss, Precision + + +def train_mdnet(opts): + + # Init dataset + with open(opts['data_path'], 'rb') as fp: + data = pickle.load(fp) + K = len(data) + dataset = [None] * K + for k, seq in enumerate(data.values()): + dataset[k] = RegionDataset(seq['images'], seq['gt'], opts) + + # Init model + model = MDNet(opts['init_model_path'], K) + if opts['use_gpu']: + model = model.cuda() + model.set_learnable_params(opts['ft_layers']) + + # Init criterion and optimizer + criterion = BCELoss() + evaluator = Precision() + optimizer = set_optimizer(model, opts['lr'], opts['lr_mult']) + + # Main trainig loop + for i in range(opts['n_cycles']): + print('==== Start Cycle {:d}/{:d} ===='.format(i + 1, opts['n_cycles'])) + + if i in opts.get('lr_decay', []): + print('decay learning rate') + for param_group in optimizer.param_groups: + param_group['lr'] *= opts.get('gamma', 0.1) + + # Training + model.train() + prec = np.zeros(K) + k_list = np.random.permutation(K) + for j, k in enumerate(k_list): + tic = time.time() + # training + pos_regions, neg_regions = dataset[k].next() + if opts['use_gpu']: + pos_regions = pos_regions.cuda() + neg_regions = neg_regions.cuda() + pos_score = model(pos_regions, k) + neg_score = model(neg_regions, k) + + loss = criterion(pos_score, neg_score) + + batch_accum = opts.get('batch_accum', 1) + if j % batch_accum == 0: + model.zero_grad() + loss.backward() + if j % batch_accum == batch_accum - 1 or j == len(k_list) - 1: + if 'grad_clip' in opts: + torch.nn.utils.clip_grad_norm_(model.parameters(), opts['grad_clip']) + optimizer.step() + + prec[k] = evaluator(pos_score, neg_score) + + toc = time.time()-tic + print('Cycle {:2d}/{:2d}, Iter {:2d}/{:2d} (Domain {:2d}), Loss {:.3f}, Precision {:.3f}, Time {:.3f}' + .format(i, opts['n_cycles'], j, len(k_list), k, loss.item(), prec[k], toc)) + + print('Mean Precision: {:.3f}'.format(prec.mean())) + print('Save model to {:s}'.format(opts['model_path'])) + if opts['use_gpu']: + model = model.cpu() + states = {'shared_layers': model.layers.state_dict()} + torch.save(states, opts['model_path']) + if opts['use_gpu']: + model = model.cuda() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--dataset', default='imagenet', help='training dataset {vot, imagenet}') + args = parser.parse_args() + + opts = yaml.safe_load(open('pretrain/options_{}.yaml'.format(args.dataset), 'r')) + train_mdnet(opts) diff --git a/pyMDNet/results/DragonBaby/result.json b/pyMDNet/results/DragonBaby/result.json new file mode 100755 index 0000000..ec5e999 --- /dev/null +++ b/pyMDNet/results/DragonBaby/result.json @@ -0,0 +1,684 @@ +{ + "res": [ + [ + 160.0, + 83.0, + 56.0, + 65.0 + ], + [ + 168.0, + 86.0, + 53.0, + 63.0 + ], + [ + 177.0, + 84.0, + 52.0, + 63.0 + ], + [ + 177.0, + 80.0, + 54.0, + 66.0 + ], + [ + 183.0, + 77.0, + 57.0, + 70.0 + ], + [ + 190.0, + 71.0, + 57.0, + 74.0 + ], + [ + 191.0, + 61.0, + 58.0, + 68.0 + ], + [ + 179.0, + 46.0, + 58.0, + 67.0 + ], + [ + 167.0, + 37.0, + 57.0, + 65.0 + ], + [ + 155.0, + 47.0, + 59.0, + 70.0 + ], + [ + 152.0, + 62.0, + 59.0, + 68.0 + ], + [ + 149.0, + 69.0, + 60.0, + 67.0 + ], + [ + 147.0, + 74.0, + 60.0, + 68.0 + ], + [ + 144.0, + 79.0, + 61.0, + 67.0 + ], + [ + 146.0, + 89.0, + 59.0, + 66.0 + ], + [ + 150.0, + 93.0, + 62.0, + 65.0 + ], + [ + 161.0, + 94.0, + 67.0, + 65.0 + ], + [ + 189.0, + 92.0, + 64.0, + 68.0 + ], + [ + 194.0, + 92.0, + 65.0, + 70.0 + ], + [ + 189.0, + 83.0, + 63.0, + 71.0 + ], + [ + 187.0, + 83.0, + 63.0, + 73.0 + ], + [ + 178.0, + 84.0, + 65.0, + 72.0 + ], + [ + 163.0, + 81.0, + 67.0, + 73.0 + ], + [ + 156.0, + 78.0, + 69.0, + 79.0 + ], + [ + 128.0, + 86.0, + 67.0, + 70.0 + ], + [ + 139.0, + 87.0, + 71.0, + 74.0 + ], + [ + 169.0, + 82.0, + 69.0, + 74.0 + ], + [ + 187.0, + 85.0, + 71.0, + 76.0 + ], + [ + 189.0, + 84.0, + 71.0, + 76.0 + ], + [ + 201.0, + 91.0, + 68.0, + 78.0 + ], + [ + 220.0, + 94.0, + 66.0, + 74.0 + ], + [ + 210.0, + 86.0, + 70.0, + 80.0 + ], + [ + 207.0, + 77.0, + 73.0, + 81.0 + ], + [ + 219.0, + 70.0, + 71.0, + 82.0 + ], + [ + 229.0, + 70.0, + 69.0, + 80.0 + ], + [ + 234.0, + 75.0, + 71.0, + 81.0 + ], + [ + 225.0, + 86.0, + 68.0, + 77.0 + ], + [ + 228.0, + 90.0, + 69.0, + 76.0 + ], + [ + 223.0, + 93.0, + 76.0, + 75.0 + ], + [ + 218.0, + 86.0, + 73.0, + 75.0 + ], + [ + 191.0, + 58.0, + 71.0, + 73.0 + ], + [ + 148.0, + 36.0, + 71.0, + 79.0 + ], + [ + 118.0, + 31.0, + 73.0, + 79.0 + ], + [ + 97.0, + 36.0, + 67.0, + 77.0 + ], + [ + 54.0, + 34.0, + 67.0, + 78.0 + ], + [ + 71.0, + 31.0, + 67.0, + 78.0 + ], + [ + 80.0, + 88.0, + 69.0, + 78.0 + ], + [ + 93.0, + 51.0, + 67.0, + 81.0 + ], + [ + 124.0, + 40.0, + 67.0, + 68.0 + ], + [ + 149.0, + 24.0, + 67.0, + 78.0 + ], + [ + 173.0, + 27.0, + 63.0, + 67.0 + ], + [ + 182.0, + 37.0, + 62.0, + 68.0 + ], + [ + 207.0, + 58.0, + 62.0, + 69.0 + ], + [ + 201.0, + 67.0, + 63.0, + 71.0 + ], + [ + 191.0, + 78.0, + 67.0, + 64.0 + ], + [ + 197.0, + 80.0, + 62.0, + 65.0 + ], + [ + 223.0, + 67.0, + 59.0, + 66.0 + ], + [ + 237.0, + 64.0, + 64.0, + 65.0 + ], + [ + 245.0, + 69.0, + 62.0, + 66.0 + ], + [ + 249.0, + 72.0, + 63.0, + 67.0 + ], + [ + 243.0, + 69.0, + 61.0, + 67.0 + ], + [ + 198.0, + 86.0, + 63.0, + 77.0 + ], + [ + 185.0, + 102.0, + 66.0, + 82.0 + ], + [ + 176.0, + 136.0, + 67.0, + 82.0 + ], + [ + 172.0, + 146.0, + 68.0, + 83.0 + ], + [ + 162.0, + 121.0, + 68.0, + 86.0 + ], + [ + 158.0, + 107.0, + 72.0, + 88.0 + ], + [ + 141.0, + 81.0, + 71.0, + 86.0 + ], + [ + 123.0, + 60.0, + 71.0, + 85.0 + ], + [ + 122.0, + 59.0, + 68.0, + 75.0 + ], + [ + 133.0, + 64.0, + 70.0, + 75.0 + ], + [ + 148.0, + 74.0, + 69.0, + 75.0 + ], + [ + 150.0, + 78.0, + 68.0, + 75.0 + ], + [ + 154.0, + 66.0, + 66.0, + 73.0 + ], + [ + 158.0, + 55.0, + 68.0, + 74.0 + ], + [ + 171.0, + 37.0, + 69.0, + 76.0 + ], + [ + 189.0, + 47.0, + 69.0, + 80.0 + ], + [ + 198.0, + 66.0, + 64.0, + 75.0 + ], + [ + 202.0, + 74.0, + 62.0, + 70.0 + ], + [ + 238.0, + 49.0, + 70.0, + 81.0 + ], + [ + 276.0, + 37.0, + 70.0, + 81.0 + ], + [ + 307.0, + 31.0, + 70.0, + 82.0 + ], + [ + 322.0, + 36.0, + 70.0, + 81.0 + ], + [ + 331.0, + 35.0, + 71.0, + 82.0 + ], + [ + 288.0, + 34.0, + 72.0, + 83.0 + ], + [ + 256.0, + 81.0, + 71.0, + 82.0 + ], + [ + 166.0, + 130.0, + 81.0, + 95.0 + ], + [ + 167.0, + 123.0, + 85.0, + 101.0 + ], + [ + 192.0, + 100.0, + 85.0, + 105.0 + ], + [ + 176.0, + 64.0, + 93.0, + 98.0 + ], + [ + 157.0, + 50.0, + 95.0, + 98.0 + ], + [ + 122.0, + 38.0, + 87.0, + 85.0 + ], + [ + 116.0, + 33.0, + 80.0, + 87.0 + ], + [ + 111.0, + 35.0, + 80.0, + 87.0 + ], + [ + 117.0, + 44.0, + 72.0, + 86.0 + ], + [ + 120.0, + 52.0, + 71.0, + 86.0 + ], + [ + 126.0, + 71.0, + 68.0, + 84.0 + ], + [ + 129.0, + 79.0, + 69.0, + 82.0 + ], + [ + 137.0, + 66.0, + 73.0, + 85.0 + ], + [ + 154.0, + 50.0, + 72.0, + 74.0 + ], + [ + 158.0, + 33.0, + 79.0, + 91.0 + ], + [ + 179.0, + 53.0, + 66.0, + 76.0 + ], + [ + 175.0, + 58.0, + 66.0, + 73.0 + ], + [ + 169.0, + 65.0, + 61.0, + 74.0 + ], + [ + 164.0, + 73.0, + 61.0, + 73.0 + ], + [ + 160.0, + 77.0, + 61.0, + 72.0 + ], + [ + 156.0, + 86.0, + 62.0, + 73.0 + ], + [ + 154.0, + 89.0, + 62.0, + 74.0 + ], + [ + 155.0, + 88.0, + 62.0, + 72.0 + ], + [ + 169.0, + 82.0, + 68.0, + 75.0 + ], + [ + 194.0, + 81.0, + 70.0, + 76.0 + ], + [ + 226.0, + 75.0, + 68.0, + 72.0 + ], + [ + 240.0, + 80.0, + 70.0, + 68.0 + ] + ], + "type": "rect", + "fps": 5.590169924970416 +} \ No newline at end of file diff --git a/pyMDNet/tracking/__init__.py b/pyMDNet/tracking/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pyMDNet/tracking/__pycache__/__init__.cpython-37.pyc b/pyMDNet/tracking/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..d17eb60 Binary files /dev/null and b/pyMDNet/tracking/__pycache__/__init__.cpython-37.pyc differ diff --git a/pyMDNet/tracking/__pycache__/bbreg.cpython-37.pyc b/pyMDNet/tracking/__pycache__/bbreg.cpython-37.pyc new file mode 100755 index 0000000..269d84d Binary files /dev/null and b/pyMDNet/tracking/__pycache__/bbreg.cpython-37.pyc differ diff --git a/pyMDNet/tracking/__pycache__/data_prov.cpython-37.pyc b/pyMDNet/tracking/__pycache__/data_prov.cpython-37.pyc new file mode 100755 index 0000000..96108be Binary files /dev/null and b/pyMDNet/tracking/__pycache__/data_prov.cpython-37.pyc differ diff --git a/pyMDNet/tracking/__pycache__/gen_config.cpython-37.pyc b/pyMDNet/tracking/__pycache__/gen_config.cpython-37.pyc new file mode 100755 index 0000000..d6dd48a Binary files /dev/null and b/pyMDNet/tracking/__pycache__/gen_config.cpython-37.pyc differ diff --git a/pyMDNet/tracking/__pycache__/run_tracker.cpython-37.pyc b/pyMDNet/tracking/__pycache__/run_tracker.cpython-37.pyc new file mode 100755 index 0000000..363a9d4 Binary files /dev/null and b/pyMDNet/tracking/__pycache__/run_tracker.cpython-37.pyc differ diff --git a/pyMDNet/tracking/bbreg.py b/pyMDNet/tracking/bbreg.py new file mode 100755 index 0000000..183bef7 --- /dev/null +++ b/pyMDNet/tracking/bbreg.py @@ -0,0 +1,59 @@ +import sys +from sklearn.linear_model import Ridge +import numpy as np + +from pyMDNet.modules.utils import overlap_ratio + + +class BBRegressor(): + def __init__(self, img_size, alpha=1000, overlap=[0.6, 1], scale=[1, 2]): + self.img_size = img_size + self.alpha = alpha + self.overlap_range = overlap + self.scale_range = scale + self.model = Ridge(alpha=self.alpha) + + def train(self, X, bbox, gt): + X = X.cpu().numpy() + bbox = np.copy(bbox) + gt = np.copy(gt) + + if gt.ndim==1: + gt = gt[None,:] + + r = overlap_ratio(bbox, gt) + s = np.prod(bbox[:,2:], axis=1) / np.prod(gt[0,2:]) + idx = (r >= self.overlap_range[0]) * (r <= self.overlap_range[1]) * \ + (s >= self.scale_range[0]) * (s <= self.scale_range[1]) + + X = X[idx] + bbox = bbox[idx] + + Y = self.get_examples(bbox, gt) + self.model.fit(X, Y) + + def predict(self, X, bbox): + X = X.cpu().numpy() + bbox_ = np.copy(bbox) + + Y = self.model.predict(X) + + bbox_[:,:2] = bbox_[:,:2] + bbox_[:,2:]/2 + bbox_[:,:2] = Y[:,:2] * bbox_[:,2:] + bbox_[:,:2] + bbox_[:,2:] = np.exp(Y[:,2:]) * bbox_[:,2:] + bbox_[:,:2] = bbox_[:,:2] - bbox_[:,2:]/2 + + bbox_[:,:2] = np.maximum(bbox_[:,:2], 0) + bbox_[:,2:] = np.minimum(bbox_[:,2:], self.img_size - bbox[:,:2]) + return bbox_ + + def get_examples(self, bbox, gt): + bbox[:,:2] = bbox[:,:2] + bbox[:,2:]/2 + gt[:,:2] = gt[:,:2] + gt[:,2:]/2 + + dst_xy = (gt[:,:2] - bbox[:,:2]) / bbox[:,2:] + dst_wh = np.log(gt[:,2:] / bbox[:,2:]) + + Y = np.concatenate((dst_xy, dst_wh), axis=1) + return Y + diff --git a/pyMDNet/tracking/data_prov.py b/pyMDNet/tracking/data_prov.py new file mode 100755 index 0000000..5d230f1 --- /dev/null +++ b/pyMDNet/tracking/data_prov.py @@ -0,0 +1,48 @@ +import sys +import numpy as np +from PIL import Image +import os +from vot_path import base_path + +import torch +import torch.utils.data as data + +from pyMDNet.modules.utils import crop_image2 +import yaml +opts = yaml.safe_load(open(os.path.join(base_path, 'mlpLT/pyMDNet/tracking/options.yaml'), 'r')) + +class RegionExtractor(): + def __init__(self, image, samples, opts): + self.image = np.asarray(image) + self.samples = samples + + self.crop_size = opts['img_size'] + self.padding = opts['padding'] + self.batch_size = opts['batch_test'] + + self.index = np.arange(len(samples)) + self.pointer = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.pointer == len(self.samples): + self.pointer = 0 + raise StopIteration + else: + next_pointer = min(self.pointer + self.batch_size, len(self.samples)) + index = self.index[self.pointer:next_pointer] + self.pointer = next_pointer + regions = self.extract_regions(index) + regions = torch.from_numpy(regions) + return regions + next = __next__ + + def extract_regions(self, index): + regions = np.zeros((len(index), self.crop_size, self.crop_size, 3), dtype='uint8') + for i, sample in enumerate(self.samples[index]): + regions[i] = crop_image2(self.image, sample, self.crop_size, self.padding) + regions = regions.transpose(0, 3, 1, 2) + regions = regions.astype('float32') - 128. + return regions diff --git a/pyMDNet/tracking/gen_config.py b/pyMDNet/tracking/gen_config.py new file mode 100755 index 0000000..f880448 --- /dev/null +++ b/pyMDNet/tracking/gen_config.py @@ -0,0 +1,49 @@ +import os +import json +import numpy as np + + +def gen_config(args): + + if args.seq != '': + # generate config from a sequence name + + seq_home = 'datasets/OTB' + result_home = 'results' + + seq_name = args.seq + img_dir = os.path.join(seq_home, seq_name, 'img') + gt_path = os.path.join(seq_home, seq_name, 'groundtruth_rect.txt') + + img_list = os.listdir(img_dir) + img_list.sort() + img_list = [os.path.join(img_dir, x) for x in img_list] + + with open(gt_path) as f: + gt = np.loadtxt((x.replace('\t',',') for x in f), delimiter=',') + init_bbox = gt[0] + + result_dir = os.path.join(result_home, seq_name) + if not os.path.exists(result_dir): + os.makedirs(result_dir) + savefig_dir = os.path.join(result_dir, 'figs') + result_path = os.path.join(result_dir, 'result.json') + + elif args.json != '': + # load config from a json file + + param = json.load(open(args.json, 'r')) + seq_name = param['seq_name'] + img_list = param['img_list'] + init_bbox = param['init_bbox'] + savefig_dir = param['savefig_dir'] + result_path = param['result_path'] + gt = None + + if args.savefig: + if not os.path.exists(savefig_dir): + os.makedirs(savefig_dir) + else: + savefig_dir = '' + + return img_list, init_bbox, gt, savefig_dir, args.display, result_path diff --git a/pyMDNet/tracking/options.yaml b/pyMDNet/tracking/options.yaml new file mode 100755 index 0000000..5fc7bad --- /dev/null +++ b/pyMDNet/tracking/options.yaml @@ -0,0 +1,61 @@ +use_gpu: true + +# model path +model_path: "models/mdnet_imagenet_vid.pth" + +# input size +img_size: 107 +padding: 16 + +# batch size +batch_pos: 32 +batch_neg: 96 +batch_neg_cand: 1024 +batch_test: 256 + +# candidates sampling +n_samples: 256 +trans: 0.6 +scale: 1.05 +trans_limit: 1.5 + +# training examples sampling +trans_pos: 0.1 +scale_pos: 1.3 +trans_neg_init: 1 +scale_neg_init: 1.6 +trans_neg: 2 +scale_neg: 1.3 + +# bounding box regression +n_bbreg: 1000 +overlap_bbreg: [0.6, 1] +trans_bbreg: 0.3 +scale_bbreg: 1.6 +aspect_bbreg: 1.1 + +# initial training +lr_init: 0.0005 +maxiter_init: 50 +n_pos_init: 500 +n_neg_init: 5000 +overlap_pos_init: [0.7, 1] +overlap_neg_init: [0, 0.5] + +# online training +lr_update: 0.001 +maxiter_update: 15 +n_pos_update: 50 +n_neg_update: 200 +overlap_pos_update: [0.7, 1] +overlap_neg_update: [0, 0.3] + +# update criteria +long_interval: 10 +n_frames_long: 100 +n_frames_short: 30 + +# training +grad_clip: 10 +lr_mult: {'fc6': 10} +ft_layers: ['fc'] diff --git a/pyMDNet/tracking/run_tracker.py b/pyMDNet/tracking/run_tracker.py new file mode 100755 index 0000000..831d1ae --- /dev/null +++ b/pyMDNet/tracking/run_tracker.py @@ -0,0 +1,331 @@ +import numpy as np +import os +import sys +import time +import argparse +import yaml, json +from PIL import Image + +import matplotlib.pyplot as plt + +import torch +# import torch.utils.data as data +import torch.optim as optim + +sys.path.insert(0, '.') +from pyMDNet.modules.model import MDNet, BCELoss, set_optimizer +from pyMDNet.modules.sample_generator import SampleGenerator +from pyMDNet.modules.utils import overlap_ratio +from data_prov import RegionExtractor +from bbreg import BBRegressor +from gen_config import gen_config + +# opts = yaml.safe_load(open('tracking/options.yaml','r')) + + +def forward_samples(model, image, samples, opts, out_layer='conv3'): + model.eval() + extractor = RegionExtractor(image, samples, opts) + for i, regions in enumerate(extractor): + if opts['use_gpu']: + regions = regions.cuda() + with torch.no_grad(): + feat = model(regions, out_layer=out_layer) + if i==0: + feats = feat.detach().clone() + else: + feats = torch.cat((feats, feat.detach().clone()), 0) + return feats + + +def train(model, criterion, optimizer, pos_feats, neg_feats, maxiter, opts, in_layer='fc4'): + model.train() + + batch_pos = opts['batch_pos'] + batch_neg = opts['batch_neg'] + batch_test = opts['batch_test'] + batch_neg_cand = max(opts['batch_neg_cand'], batch_neg) + + pos_idx = np.random.permutation(pos_feats.size(0)) + neg_idx = np.random.permutation(neg_feats.size(0)) + while(len(pos_idx) < batch_pos * maxiter): + pos_idx = np.concatenate([pos_idx, np.random.permutation(pos_feats.size(0))]) + while(len(neg_idx) < batch_neg_cand * maxiter): + neg_idx = np.concatenate([neg_idx, np.random.permutation(neg_feats.size(0))]) + pos_pointer = 0 + neg_pointer = 0 + + for i in range(maxiter): + + # select pos idx + pos_next = pos_pointer + batch_pos + pos_cur_idx = pos_idx[pos_pointer:pos_next] + pos_cur_idx = pos_feats.new(pos_cur_idx).long() + pos_pointer = pos_next + + # select neg idx + neg_next = neg_pointer + batch_neg_cand + neg_cur_idx = neg_idx[neg_pointer:neg_next] + neg_cur_idx = neg_feats.new(neg_cur_idx).long() + neg_pointer = neg_next + + # create batch + batch_pos_feats = pos_feats[pos_cur_idx] + batch_neg_feats = neg_feats[neg_cur_idx] + + # hard negative mining + if batch_neg_cand > batch_neg: + model.eval() + for start in range(0, batch_neg_cand, batch_test): + end = min(start + batch_test, batch_neg_cand) + with torch.no_grad(): + score = model(batch_neg_feats[start:end], in_layer=in_layer) + if start==0: + neg_cand_score = score.detach()[:, 1].clone() + else: + neg_cand_score = torch.cat((neg_cand_score, score.detach()[:, 1].clone()), 0) + + _, top_idx = neg_cand_score.topk(batch_neg) + batch_neg_feats = batch_neg_feats[top_idx] + model.train() + + # forward + pos_score = model(batch_pos_feats, in_layer=in_layer) + neg_score = model(batch_neg_feats, in_layer=in_layer) + + # optimize + loss = criterion(pos_score, neg_score) + model.zero_grad() + loss.backward() + if 'grad_clip' in opts: + torch.nn.utils.clip_grad_norm_(model.parameters(), opts['grad_clip']) + optimizer.step() + + +def run_mdnet(img_list, init_bbox, gt=None, savefig_dir='', display=False): + + # Init bbox + target_bbox = np.array(init_bbox) + result = np.zeros((len(img_list), 4)) + result_bb = np.zeros((len(img_list), 4)) + result[0] = target_bbox + result_bb[0] = target_bbox + + if gt is not None: + overlap = np.zeros(len(img_list)) + overlap[0] = 1 + + # Init model + model = MDNet(opts['model_path']) + if opts['use_gpu']: + model = model.cuda() + + # Init criterion and optimizer + criterion = BCELoss() + model.set_learnable_params(opts['ft_layers']) + init_optimizer = set_optimizer(model, opts['lr_init'], opts['lr_mult']) + update_optimizer = set_optimizer(model, opts['lr_update'], opts['lr_mult']) + + tic = time.time() + # Load first image + image = Image.open(img_list[0]).convert('RGB') + + # Draw pos/neg samples + pos_examples = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos'])( + target_bbox, opts['n_pos_init'], opts['overlap_pos_init']) + + neg_examples = np.concatenate([ + SampleGenerator('uniform', image.size, opts['trans_neg_init'], opts['scale_neg_init'])( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init']), + SampleGenerator('whole', image.size)( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init'])]) + neg_examples = np.random.permutation(neg_examples) + + # Extract pos/neg features + pos_feats = forward_samples(model, image, pos_examples) + neg_feats = forward_samples(model, image, neg_examples) + + # Initial training + train(model, criterion, init_optimizer, pos_feats, neg_feats, opts['maxiter_init']) + del init_optimizer, neg_feats + torch.cuda.empty_cache() + + # Train bbox regressor + bbreg_examples = SampleGenerator('uniform', image.size, opts['trans_bbreg'], opts['scale_bbreg'], opts['aspect_bbreg'])( + target_bbox, opts['n_bbreg'], opts['overlap_bbreg']) + bbreg_feats = forward_samples(model, image, bbreg_examples) + bbreg = BBRegressor(image.size) + bbreg.train(bbreg_feats, bbreg_examples, target_bbox) + del bbreg_feats + torch.cuda.empty_cache() + + # Init sample generators for update + sample_generator = SampleGenerator('gaussian', image.size, opts['trans'], opts['scale']) + pos_generator = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos']) + neg_generator = SampleGenerator('uniform', image.size, opts['trans_neg'], opts['scale_neg']) + + # Init pos/neg features for update + neg_examples = neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_init']) + neg_feats = forward_samples(model, image, neg_examples) + pos_feats_all = [pos_feats] + neg_feats_all = [neg_feats] + + spf_total = time.time() - tic + + # Display + savefig = savefig_dir != '' + if display or savefig: + dpi = 80.0 + figsize = (image.size[0] / dpi, image.size[1] / dpi) + + fig = plt.figure(frameon=False, figsize=figsize, dpi=dpi) + ax = plt.Axes(fig, [0., 0., 1., 1.]) + ax.set_axis_off() + fig.add_axes(ax) + im = ax.imshow(image, aspect='auto') + + if gt is not None: + gt_rect = plt.Rectangle(tuple(gt[0, :2]), gt[0, 2], gt[0, 3], + linewidth=3, edgecolor="#00ff00", zorder=1, fill=False) + ax.add_patch(gt_rect) + + rect = plt.Rectangle(tuple(result_bb[0, :2]), result_bb[0, 2], result_bb[0, 3], + linewidth=3, edgecolor="#ff0000", zorder=1, fill=False) + ax.add_patch(rect) + + if display: + plt.pause(.01) + plt.draw() + if savefig: + fig.savefig(os.path.join(savefig_dir, '0000.jpg'), dpi=dpi) + + # Main loop + for i in range(1, len(img_list)): + + tic = time.time() + # Load image + image = Image.open(img_list[i]).convert('RGB') + + # Estimate target bbox + samples = sample_generator(target_bbox, opts['n_samples']) + sample_scores = forward_samples(model, image, samples, out_layer='fc6') + + top_scores, top_idx = sample_scores[:, 1].topk(5) + top_idx = top_idx.cpu() + target_score = top_scores.mean() + target_bbox = samples[top_idx] + if top_idx.shape[0] > 1: + target_bbox = target_bbox.mean(axis=0) + success = target_score > 0 + + # Expand search area at failure + if success: + sample_generator.set_trans(opts['trans']) + else: + sample_generator.expand_trans(opts['trans_limit']) + + # Bbox regression + if success: + bbreg_samples = samples[top_idx] + if top_idx.shape[0] == 1: + bbreg_samples = bbreg_samples[None,:] + bbreg_feats = forward_samples(model, image, bbreg_samples) + bbreg_samples = bbreg.predict(bbreg_feats, bbreg_samples) + bbreg_bbox = bbreg_samples.mean(axis=0) + else: + bbreg_bbox = target_bbox + + # Save result + result[i] = target_bbox + result_bb[i] = bbreg_bbox + + # Data collect + if success: + pos_examples = pos_generator(target_bbox, opts['n_pos_update'], opts['overlap_pos_update']) + pos_feats = forward_samples(model, image, pos_examples) + pos_feats_all.append(pos_feats) + if len(pos_feats_all) > opts['n_frames_long']: + del pos_feats_all[0] + + neg_examples = neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_update']) + neg_feats = forward_samples(model, image, neg_examples) + neg_feats_all.append(neg_feats) + if len(neg_feats_all) > opts['n_frames_short']: + del neg_feats_all[0] + + # Short term update + if not success: + nframes = min(opts['n_frames_short'], len(pos_feats_all)) + pos_data = torch.cat(pos_feats_all[-nframes:], 0) + neg_data = torch.cat(neg_feats_all, 0) + train(model, criterion, update_optimizer, pos_data, neg_data, opts['maxiter_update']) + + # Long term update + elif i % opts['long_interval'] == 0: + pos_data = torch.cat(pos_feats_all, 0) + neg_data = torch.cat(neg_feats_all, 0) + train(model, criterion, update_optimizer, pos_data, neg_data, opts['maxiter_update']) + + torch.cuda.empty_cache() + spf = time.time() - tic + spf_total += spf + + # Display + if display or savefig: + im.set_data(image) + + if gt is not None: + gt_rect.set_xy(gt[i, :2]) + gt_rect.set_width(gt[i, 2]) + gt_rect.set_height(gt[i, 3]) + + rect.set_xy(result_bb[i, :2]) + rect.set_width(result_bb[i, 2]) + rect.set_height(result_bb[i, 3]) + + if display: + plt.pause(.01) + plt.draw() + if savefig: + fig.savefig(os.path.join(savefig_dir, '{:04d}.jpg'.format(i)), dpi=dpi) + + if gt is None: + print('Frame {:d}/{:d}, Score {:.3f}, Time {:.3f}' + .format(i, len(img_list), target_score, spf)) + else: + overlap[i] = overlap_ratio(gt[i], result_bb[i])[0] + print('Frame {:d}/{:d}, Overlap {:.3f}, Score {:.3f}, Time {:.3f}' + .format(i, len(img_list), overlap[i], target_score, spf)) + + if gt is not None: + print('meanIOU: {:.3f}'.format(overlap.mean())) + fps = len(img_list) / spf_total + return result, result_bb, fps + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--seq', default='DragonBaby', help='input seq') + parser.add_argument('-j', '--json', default='', help='input json') + parser.add_argument('-f', '--savefig', action='store_true') + parser.add_argument('-d', '--display', action='store_true') + + args = parser.parse_args() + assert args.seq != '' or args.json != '' + + np.random.seed(0) + torch.manual_seed(0) + + # Generate sequence config + img_list, init_bbox, gt, savefig_dir, display, result_path = gen_config(args) + + # Run tracker + result, result_bb, fps = run_mdnet(img_list, init_bbox, gt=gt, savefig_dir=savefig_dir, display=display) + + # Save result + res = {} + res['res'] = result_bb.round().tolist() + res['type'] = 'rect' + res['fps'] = fps + json.dump(res, open(result_path, 'w'), indent=2) diff --git a/pytracking/.figs/LaSOT.png b/pytracking/.figs/LaSOT.png new file mode 100755 index 0000000..7e6079d Binary files /dev/null and b/pytracking/.figs/LaSOT.png differ diff --git a/pytracking/.figs/NFS.png b/pytracking/.figs/NFS.png new file mode 100755 index 0000000..a341052 Binary files /dev/null and b/pytracking/.figs/NFS.png differ diff --git a/pytracking/.figs/OTB-100.png b/pytracking/.figs/OTB-100.png new file mode 100755 index 0000000..61f6674 Binary files /dev/null and b/pytracking/.figs/OTB-100.png differ diff --git a/pytracking/.figs/UAV123.png b/pytracking/.figs/UAV123.png new file mode 100755 index 0000000..83ead6d Binary files /dev/null and b/pytracking/.figs/UAV123.png differ diff --git a/pytracking/.figs/atom_overview.png b/pytracking/.figs/atom_overview.png new file mode 100755 index 0000000..705c740 Binary files /dev/null and b/pytracking/.figs/atom_overview.png differ diff --git a/pytracking/.figs/dimp_overview.png b/pytracking/.figs/dimp_overview.png new file mode 100755 index 0000000..5474b53 Binary files /dev/null and b/pytracking/.figs/dimp_overview.png differ diff --git a/pytracking/.figs/visdom.png b/pytracking/.figs/visdom.png new file mode 100755 index 0000000..1172b28 Binary files /dev/null and b/pytracking/.figs/visdom.png differ diff --git a/pytracking/README.md b/pytracking/README.md new file mode 100755 index 0000000..83e34c8 --- /dev/null +++ b/pytracking/README.md @@ -0,0 +1,163 @@ +# PyTracking + +A general python library for visual tracking algorithms. +## Table of Contents + +* [Running a tracker](#running-a-tracker) +* [Overview](#overview) +* [Trackers](#trackers) + * [DiMP](#DiMP) + * [ATOM](#ATOM) + * [ECO](#ECO) +* [Analysis](#analysis) +* [Libs](#libs) +* [Visdom](#visdom) +* [VOT Integration](#vot-integration) +* [Integrating a new tracker](#integrating-a-new-tracker) + + +## Running a tracker +The installation script will automatically generate a local configuration file "evaluation/local.py". In case the file was not generated, run ```evaluation.environment.create_default_local_file()``` to generate it. Next, set the paths to the datasets you want +to use for evaluations. You can also change the path to the networks folder, and the path to the results folder, if you do not want to use the default paths. If all the dependencies have been correctly installed, you are set to run the trackers. + +The toolkit provides many ways to run a tracker. + +**Run the tracker on webcam feed** +This is done using the run_webcam script. The arguments are the name of the tracker, and the name of the parameter file. You can select the object to track by drawing a bounding box. **Note:** It is possible to select multiple targets to track! +```bash +python run_webcam.py tracker_name parameter_name +``` + +**Run the tracker on some dataset sequence** +This is done using the run_tracker script. +```bash +python run_tracker.py tracker_name parameter_name --dataset_name dataset_name --sequence sequence --debug debug --threads threads +``` + +Here, the dataset_name is the name of the dataset used for evaluation, e.g. ```otb```. See [evaluation.datasets.py](evaluation/datasets.py) for the list of datasets which are supported. The sequence can either be an integer denoting the index of the sequence in the dataset, or the name of the sequence, e.g. ```'Soccer'```. +The ```debug``` parameter can be used to control the level of debug visualizations. ```threads``` parameter can be used to run on multiple threads. + +**Run the tracker on a set of datasets** +This is done using the run_experiment script. To use this, first you need to create an experiment setting file in ```pytracking/experiments```. See [myexperiments.py](experiments/myexperiments.py) for reference. +```bash +python run_experiment.py experiment_module experiment_name --dataset_name dataset_name --sequence sequence --debug debug --threads threads +``` +Here, ```experiment_module``` is the name of the experiment setting file, e.g. ```myexperiments``` , and ``` experiment_name``` is the name of the experiment setting, e.g. ``` atom_nfs_uav``` . + +**Run the tracker on a video file** +This is done using the run_video script. +```bash +python run_video.py experiment_module experiment_name videofile --optional_box optional_box --debug debug +``` +Here, ```videofile``` is the path to the video file. You can either draw the box by hand or provide it directly in the ```optional_box``` argument. + +## Overview +The tookit consists of the following sub-modules. + - [analysis](analysis): Contains scripts to analyse tracking performance, e.g. obtain success plots, compute AUC score. It also contains a [script](analysis/playback_results.py) to playback saved results for debugging. + - [evaluation](evaluation): Contains the necessary scripts for running a tracker on a dataset. It also contains integration of a number of standard tracking and video object segmentation datasets, namely [OTB-100](http://cvlab.hanyang.ac.kr/tracker_benchmark/index.html), [NFS](http://ci2cv.net/nfs/index.html), + [UAV123](https://ivul.kaust.edu.sa/Pages/pub-benchmark-simulator-uav.aspx), [Temple128](http://www.dabi.temple.edu/~hbling/data/TColor-128/TColor-128.html), [TrackingNet](https://tracking-net.org/), [GOT-10k](http://got-10k.aitestunion.com/), [LaSOT](https://cis.temple.edu/lasot/), [VOT](http://www.votchallenge.net), [Temple Color 128](http://www.dabi.temple.edu/~hbling/data/TColor-128/TColor-128.html), [DAVIS](https://davischallenge.org), and [YouTube-VOS](https://youtube-vos.org). + - [experiments](experiments): The experiment setting files must be stored here, + - [features](features): Contains tools for feature extraction, data augmentation and wrapping networks. + - [libs](libs): Includes libraries for optimization, dcf, etc. + - [notebooks](notebooks) Jupyter notebooks to analyze tracker performance. + - [parameter](parameter): Contains the parameter settings for different trackers. + - [tracker](tracker): Contains the implementations of different trackers. + - [util_scripts](util_scripts): Some util scripts for e.g. generating packed results for evaluation on GOT-10k and TrackingNet evaluation servers, downloading pre-computed results. + - [utils](utils): Some util functions. + - [VOT](VOT): VOT Integration. + +## Trackers + The toolkit contains the implementation of the following trackers. + +### DiMP +The official implementation for the DiMP tracker ([paper](https://arxiv.org/abs/1904.07220)) and PrDiMP tracker ([paper](https://arxiv.org/abs/2003.12565)). +The tracker implementation file can be found at [tracker.dimp](tracker/dimp). + +##### Parameter Files +Four parameter settings are provided. These can be used to reproduce the results or as a starting point for your exploration. +* **[dimp18](parameter/dimp/dimp18.py)**: The default parameter setting with ResNet-18 backbone which was used to produce all DiMP-18 results in the paper, except on VOT. +* **[dimp18_vot](parameter/dimp/dimp18_vot.py)**: The parameters settings used to generate the DiMP-18 VOT2018 results in the paper. +* **[dimp50](parameter/dimp/dimp50.py)**: The default parameter setting with ResNet-50 backbone which was used to produce all DiMP-50 results in the paper, except on VOT. +* **[dimp50_vot](parameter/dimp/dimp50_vot.py)**: The parameters settings used to generate the DiMP-50 VOT2018 results in the paper. +* **[prdimp18](parameter/dimp/prdimp18.py)**: The default parameter setting with ResNet-18 backbone which was used to produce all PrDiMP-18 results in the paper, except on VOT. +* **[prdimp50](parameter/dimp/prdimp50.py)**: The default parameter setting with ResNet-50 backbone which was used to produce all PrDiMP-50 results in the paper, except on VOT. +* **[super_dimp](parameter/dimp/super_dimp.py)**: Combines the bounding-box regressor of PrDiMP with the standard DiMP classifier and better training and inference settings. + +The difference between the VOT and the non-VOT settings stems from the fact that the VOT protocol measures robustness in a very different manner compared to other benchmarks. In most benchmarks, it is highly important to be able to robustly *redetect* the target after e.g. an occlusion or brief target loss. On the other hand, in VOT the tracker is reset if the prediction does not overlap with the target on a *single* frame. This is then counted as a tracking failure. The capability of recovering after target loss is meaningless in this setting. The ```dimp18_vot``` and ```dimp50_vot``` settings thus focuses on avoiding target loss in the first place, while sacrificing re-detection ability. + +### ATOM +The official implementation for the ATOM tracker ([paper](https://arxiv.org/abs/1811.07628)). +The tracker implementation file can be found at [tracker.atom](tracker/atom). + +##### Parameter Files +Two parameter settings are provided. These can be used to reproduce the results or as a starting point for your exploration. +* **[default](parameter/atom/default.py)**: The default parameter setting that was used to produce all ATOM results in the paper, except on VOT. +* **[default_vot](parameter/atom/default_vot.py)**: The parameters settings used to generate the VOT2018 results in the paper. +* **[multiscale_no_iounet](parameter/atom/multiscale_no_iounet.py)**: Baseline setting that uses simple multiscale search instead of IoU-Net. Can be run on **CPU**. +* **[atom_prob_ml](parameter/atom/atom_prob_ml.py)**: ATOM with the probabilistic bounding box regression proposed in [this paper](https://arxiv.org/abs/1909.12297). +* **[atom_gmm_sampl](parameter/atom/atom_gmm_sampl.py)**: The baseline ATOM* setting evaluated in [this paper](https://arxiv.org/abs/1909.12297). + +### ECO +An unofficial implementation of the ECO tracker can be found at [tracker.eco](tracker/eco). + +## Analysis +The [analysis](analysis) module contains several scripts to analyze tracking performance on standard datasets. It can be used to obtain Precision and Success plots, compute AUC, OP, and Precision scores. The module includes utilities to perform per sequence analysis of the trackers. Further, it includes a [script](analysis/playback_results.py) to visualize pre-computed tracking results. Check [notebooks/analyze_results.ipynb](notebooks/analyze_results.ipynb) for examples on how to use the analysis module. + +## Libs +The pytracking repository includes some general libraries for implementing and developing different kinds of visual trackers, including deep learning based, optimization based and correlation filter based. The following libs are included: + +* [**Optimization**](libs/optimization.py): Efficient optimizers aimed for online learning, including the Gauss-Newton and Conjugate Gradient based optimizer used in ATOM. +* [**Complex**](libs/complex.py): Complex tensors and operations for PyTorch, which can be used for DCF trackers. +* [**Fourier**](libs/fourier.py): Fourier tools and operations, which can be used for implementing DCF trackers. +* [**DCF**](libs/dcf.py): Some general tools for DCF trackers. + +## Visdom + +All trackers support [Visdom](https://github.com/facebookresearch/visdom) for debug visualizations. To use visdom, start the visdom +server from a seperate command line: + +```bash +visdom +``` + +Run the tracker with the ```debug``` argument > 0. The debug output from the tracker can be +accessed by going to ```http://localhost:8097``` in your browser. Further, you can pause the execution of the tracker, +or step through frames using keyboard inputs. + +![visdom](.figs/visdom.png) + +## VOT Integration +#### Python Toolkit (VOT 2020) +Install the vot-python-toolkit and set up the workspace, as described in https://www.votchallenge.net/howto/tutorial_python.html. An example tracker description file to integrate a tracker in the vot-toolkit is provided at [VOT/trackers.ini](VOT/trackers.ini). + + +#### MATLAB Toolkit (VOT 2014-2019) +An example configuration file to integrate the trackers in the [VOT toolkit](https://github.com/votchallenge/vot-toolkit) is provided at [VOT/tracker_DiMP.m](VOT/tracker_DiMP.m). +Copy the configuration file to your VOT workspace and set the paths in the configuration file. You need to install [TraX](https://github.com/votchallenge/trax) +in order to run the trackers on VOT. This can be done with the following commands. + +```bash +cd VOT_TOOLKIT_PATH/native/trax +mkdir build +cd build +cmake -DBUILD_OPENCV=ON -DBUILD_CLIENT=ON .. +make +``` + +See https://trax.readthedocs.io/en/latest/index.html for more details about TraX. + +## Integrating a new tracker + To implement a new tracker, create a new module in "tracker" folder with name your_tracker_name. This folder must contain the implementation of your tracker. Note that your tracker class must inherit from the base tracker class ```tracker.base.BaseTracker```. + The "\_\_init\_\_.py" inside your tracker folder must contain the following lines, +```python +from .tracker_file import TrackerClass + +def get_tracker_class(): + return TrackerClass +``` +Here, ```TrackerClass``` is the name of your tracker class. See the [file for DiMP](tracker/dimp/__init__.py) as reference. + +Next, you need to create a folder "parameter/your_tracker_name", where the parameter settings for the tracker should be stored. The parameter fil shall contain a ```parameters()``` function that returns a ```TrackerParams``` struct. See the [default parameter file for DiMP](parameter/dimp/dimp50.py) as an example. + + + diff --git a/pytracking/VOT/tracker_DiMP.m b/pytracking/VOT/tracker_DiMP.m new file mode 100755 index 0000000..cf99917 --- /dev/null +++ b/pytracking/VOT/tracker_DiMP.m @@ -0,0 +1,32 @@ +% Set path to the python in the pytracking conda environment +python_path = 'PATH_TO_CONDA_INSTALLATION/envs/pytracking/bin/python'; + +% Set path to pytracking +pytracking_path = 'PATH_TO_VISIONML/pytracking'; + +% Set path to trax installation. Check +% https://trax.readthedocs.io/en/latest/tutorial_compiling.html for +% compilation information +trax_path = 'PATH_TO_VOT_TOOLKIT/native/trax'; + +tracker_name = 'dimp'; % Name of the tracker to evaluate +runfile_name = 'dimp18_vot'; % Name of the parameter file to use +debug = 0; + +%% +tracker_label = [tracker_name, '_', runfile_name]; + +% Generate python command +tracker_command = sprintf(['%s -c "import sys; sys.path.append(''%s'');', ... + 'sys.path.append(''%s/support/python'');', ... + 'import run_vot;', ... + 'run_vot.run_vot(''%s'', ''%s'', debug=%d)"'],... + python_path, pytracking_path, trax_path, ... + tracker_name, runfile_name, debug); + + +tracker_interpreter = python_path; + +tracker_linkpath = {[trax_path, '/build'],... + [trax_path, '/build/support/client'],... + [trax_path, '/build/support/opencv']}; diff --git a/pytracking/VOT/trackers.ini b/pytracking/VOT/trackers.ini new file mode 100755 index 0000000..5b58728 --- /dev/null +++ b/pytracking/VOT/trackers.ini @@ -0,0 +1,12 @@ +[DiMP] # <tracker-name> +label = DiMP +protocol = traxpython + +command = import pytracking.run_vot as run_vot; run_vot.run_vot2020('dimp', 'dimp50') # Set the tracker name and the parameter name + +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +paths = PATH_TO_PYTRACKING + +# Additional environment paths +#env_PATH = <additional-env-paths>;${PATH} + diff --git a/pytracking/VOT/vot.py b/pytracking/VOT/vot.py new file mode 100755 index 0000000..22b4b55 --- /dev/null +++ b/pytracking/VOT/vot.py @@ -0,0 +1,116 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016, 2019 + +""" + +import sys +import copy +import collections + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [str(x) for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, Rectangle) or isinstance(region, Polygon)) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return tuple(image) + + request = self._trax.wait() + + if request.type == 'frame': + image = [str(x) for k, x in request.image.items()] + if len(image) == 1: + image = image[0] + return tuple(image) + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() + diff --git a/pytracking/__init__.py b/pytracking/__init__.py new file mode 100755 index 0000000..e44a36f --- /dev/null +++ b/pytracking/__init__.py @@ -0,0 +1,8 @@ +from pytracking.libs import TensorList, TensorDict +import pytracking.libs.complex as complex +import pytracking.libs.operation as operation +import pytracking.libs.fourier as fourier +import pytracking.libs.dcf as dcf +import pytracking.libs.optimization as optimization +from pytracking.run_tracker import run_tracker +from pytracking.run_webcam import run_webcam diff --git a/pytracking/__pycache__/ARcm_seg.cpython-37.pyc b/pytracking/__pycache__/ARcm_seg.cpython-37.pyc new file mode 100755 index 0000000..f3268db Binary files /dev/null and b/pytracking/__pycache__/ARcm_seg.cpython-37.pyc differ diff --git a/pytracking/__pycache__/__init__.cpython-37.pyc b/pytracking/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..ee04349 Binary files /dev/null and b/pytracking/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/__pycache__/run_tracker.cpython-37.pyc b/pytracking/__pycache__/run_tracker.cpython-37.pyc new file mode 100755 index 0000000..46ddf89 Binary files /dev/null and b/pytracking/__pycache__/run_tracker.cpython-37.pyc differ diff --git a/pytracking/__pycache__/run_webcam.cpython-37.pyc b/pytracking/__pycache__/run_webcam.cpython-37.pyc new file mode 100755 index 0000000..f222d60 Binary files /dev/null and b/pytracking/__pycache__/run_webcam.cpython-37.pyc differ diff --git a/pytracking/__pycache__/vot20_utils.cpython-37.pyc b/pytracking/__pycache__/vot20_utils.cpython-37.pyc new file mode 100755 index 0000000..a26d58f Binary files /dev/null and b/pytracking/__pycache__/vot20_utils.cpython-37.pyc differ diff --git a/pytracking/analysis/__init__.py b/pytracking/analysis/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/analysis/evaluate_vos.py b/pytracking/analysis/evaluate_vos.py new file mode 100755 index 0000000..6b14302 --- /dev/null +++ b/pytracking/analysis/evaluate_vos.py @@ -0,0 +1,199 @@ +import os +import numpy as np +import torch +import pandas as pd +from collections import OrderedDict +from ltr.data.image_loader import imread_indexed +from pytracking.evaluation import get_dataset +from pathlib import Path +from pytracking.analysis.plot_results import generate_formatted_report + +import pytracking.analysis.vos_utils as utils + +# Originally db_eval_sequence() in the davis challenge toolkit: +def evaluate_sequence(seq_name, segmentations, annotations, object_info, measure='J'): + """ + Evaluate video sequence results. + + Arguments: + segmentations (dict of ndarray): segmentation labels. + annotations (dict of ndarray): ground-truth labels. + object_info dict: {object_id: first_frame_index} + + measure evaluation metric (J,F) + """ + + results = dict(raw=OrderedDict()) + + _measures = {'J': utils.davis_jaccard_measure, 'F': utils.davis_f_measure} + _statistics = {'decay': utils.decay, 'mean': utils.mean, 'recall': utils.recall, 'std': utils.std} + + for obj_id, first_frame in object_info.items(): + + r = np.ones((len(annotations))) * np.nan + + for i, (an, sg) in enumerate(zip(annotations, segmentations)): + if list(annotations.keys()).index(first_frame) < i < len(annotations) - 1: + r[i] = _measures[measure](annotations[an] == obj_id, segmentations[sg] == obj_id) + + results['raw'][obj_id] = r + + for stat, stat_fn in _statistics.items(): + results[stat] = [float(stat_fn(r)) for r in results['raw'].values()] + + return results + + +def evaluate_dataset(results_path, dset_name, measure='J', to_file=True, scores=False, sequences=None, quiet=False): + dset = get_dataset(dset_name) + results = OrderedDict() + dset_scores = [] + dset_decay = [] + dset_recall = [] + + if to_file: + f = open(results_path / ("evaluation-%s.txt" % measure), "w") + + def _print(msg): + if not quiet: + print(msg) + if to_file: + print(msg, file=f) + + if sequences is not None: + sequences = [sequences] if not isinstance(sequences, (list, tuple)) else sequences + + target_names = [] + for j, sequence in enumerate(dset): + if (sequences is not None) and (sequence.name not in sequences): + continue + + # Load all frames + frames = sequence.ground_truth_seg + + annotations = OrderedDict() + segmentations = OrderedDict() + + for f in frames: + if f is None: + continue + + file = Path(f) + annotations[file.name] = imread_indexed(file) + if not scores: + segmentations[file.name] = imread_indexed(os.path.join(results_path, sequence.name, file.name)) + else: + raise NotImplementedError + # Find object ids and starting frames + + object_info = dict() + + for f_id, d in sequence.init_data.items(): + for obj_id in d['object_ids']: + object_info[int(obj_id)] = Path(d['mask']).name + + if 0 in object_info: # Remove background + object_info.pop(0) + + # Evaluate + n_seqs = len(dset) + n_objs = len(object_info) + seq_name = sequence.name + + _print("%d/%d: %s: %d object%s" % (j + 1, n_seqs, seq_name, n_objs, "s" if n_objs > 1 else "")) + r = evaluate_sequence(seq_name, segmentations, annotations, object_info, measure=measure) + results[seq_name] = r + + # Print scores, per frame and object, ignoring NaNs + + per_obj_score = [] # Per-object accuracies, averaged over the sequence + per_frame_score = [] # Per-frame accuracies, averaged over the objects + + for obj_id, score in r['raw'].items(): + target_names.append('{}_{}'.format(seq_name, obj_id)) + per_frame_score.append(score) + s = utils.mean(score) # Sequence average for one object + per_obj_score.append(s) + if n_objs > 1: + _print("joint {obj}: acc {score:.3f} ┊{apf}┊".format(obj=obj_id, score=s, apf=utils.text_bargraph(score))) + + # Print mean object score per frame and final score + dset_decay.extend(r['decay']) + dset_recall.extend(r['recall']) + dset_scores.extend(per_obj_score) + + seq_score = utils.mean(per_obj_score) # Final score + seq_mean_score = utils.nanmean(np.array(per_frame_score), axis=0) # Mean object score per frame + + # Print sequence results + _print("final : acc {seq:.3f} ({dset:.3f}) ┊{apf}┊".format( + seq=seq_score, dset=np.mean(dset_scores), apf=utils.text_bargraph(seq_mean_score))) + + _print("%s: %.3f, recall: %.3f, decay: %.3f" % (measure, utils.mean(dset_scores), utils.mean(dset_recall), utils.mean(dset_decay))) + + if to_file: + f.close() + + return target_names, dset_scores, dset_recall, dset_decay + + +def evaluate_vos(trackers, dataset='yt2019_jjval', force=False): + """ evaluate a list of trackers on a vos dataset. + + args: + trackers - list of trackers to evaluate + dataset - name of the dataset + force - Force re-evaluation. If False, the pre-computed results are loaded if available + """ + csv_name_global = f'{dataset}_global_results.csv' + csv_name_per_sequence = f'{dataset}_per-sequence_results.csv' + + table_g_all = [] + table_seq_all = [] + scores = {'J-Mean': [], 'J-Recall': [], 'J-Decay': []} + display_names = [] + for t in trackers: + if t.display_name is not None: + disp_name = t.display_name + elif t.run_id is not None: + disp_name = '{} {}_{:03d}'.format(t.name, t.parameter_name, t.run_id) + else: + disp_name = '{} {}'.format(t.name, t.parameter_name) + + display_names.append(disp_name) + results_path = t.segmentation_dir + + csv_name_global_path = os.path.join(results_path, csv_name_global) + csv_name_per_sequence_path = os.path.join(results_path, csv_name_per_sequence) + if os.path.exists(csv_name_global_path) and os.path.exists(csv_name_per_sequence_path) and not force: + table_g = pd.read_csv(csv_name_global_path) + table_seq = pd.read_csv(csv_name_per_sequence_path) + else: + seq_names, dset_scores, dset_recall, dset_decay = evaluate_dataset(results_path, dataset, measure='J', + to_file=False, scores=False, + sequences=None) + g_measures = ['J-Mean', 'J-Recall', 'J-Decay'] + g_res = np.array([utils.mean(dset_scores), utils.mean(dset_recall), utils.mean(dset_decay)]) + g_res = np.reshape(g_res, [1, len(g_res)]) + + table_g = pd.DataFrame(data=g_res, columns=g_measures) + with open(csv_name_global_path, 'w') as f: + table_g.to_csv(f, index=False, float_format="%.3f") + + seq_measures = ['Sequence', 'J-Mean', 'J-Recall', 'J-Decay'] + + table_seq = pd.DataFrame(data=list(zip(seq_names, dset_scores, dset_recall, dset_decay)), columns=seq_measures) + with open(csv_name_per_sequence_path, 'w') as f: + table_seq.to_csv(f, index=False, float_format="%.3f") + + scores['J-Mean'].append(table_g['J-Mean'].values[0]*100) + scores['J-Recall'].append(table_g['J-Recall'].values[0]*100) + scores['J-Decay'].append(table_g['J-Decay'].values[0]*100) + + table_g_all.append(table_g) + table_seq_all.append(table_seq) + + report = generate_formatted_report(display_names, scores) + print(report) + + return table_g_all, table_seq_all diff --git a/pytracking/analysis/extract_results.py b/pytracking/analysis/extract_results.py new file mode 100755 index 0000000..c54cfbd --- /dev/null +++ b/pytracking/analysis/extract_results.py @@ -0,0 +1,183 @@ +import os +import sys +import importlib +import numpy as np +from pytracking.utils.load_text import load_text +import torch +import pickle +from tqdm import tqdm + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation.environment import env_settings + + +def calc_err_center(pred_bb, anno_bb, normalized=False): + pred_center = pred_bb[:, :2] + 0.5 * (pred_bb[:, 2:] - 1.0) + anno_center = anno_bb[:, :2] + 0.5 * (anno_bb[:, 2:] - 1.0) + + if normalized: + pred_center = pred_center / anno_bb[:, 2:] + anno_center = anno_center / anno_bb[:, 2:] + + err_center = ((pred_center - anno_center)**2).sum(1).sqrt() + return err_center + + +def calc_iou_overlap(pred_bb, anno_bb): + tl = torch.max(pred_bb[:, :2], anno_bb[:, :2]) + br = torch.min(pred_bb[:, :2] + pred_bb[:, 2:] - 1.0, anno_bb[:, :2] + anno_bb[:, 2:] - 1.0) + sz = (br - tl + 1.0).clamp(0) + + # Area + intersection = sz.prod(dim=1) + union = pred_bb[:, 2:].prod(dim=1) + anno_bb[:, 2:].prod(dim=1) - intersection + + return intersection / union + + +def calc_seq_err_robust(pred_bb, anno_bb, dataset, target_visible=None): + pred_bb = pred_bb.clone() + + # Check if invalid values are present + if torch.isnan(pred_bb).any() or (pred_bb[:, 2:] < 0.0).any(): + raise Exception('Error: Invalid results') + + if torch.isnan(anno_bb).any(): + if dataset == 'uav': + pass + else: + raise Exception('Warning: NaNs in annotation') + + if (pred_bb[:, 2:] == 0.0).any(): + for i in range(1, pred_bb.shape[0]): + if (pred_bb[i, 2:] == 0.0).any() and not torch.isnan(anno_bb[i, :]).any(): + pred_bb[i, :] = pred_bb[i-1, :] + + if pred_bb.shape[0] != anno_bb.shape[0]: + if dataset == 'lasot': + if pred_bb.shape[0] > anno_bb.shape[0]: + # For monkey-17, there is a mismatch for some trackers. + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + raise Exception('Mis-match in tracker prediction and GT lengths') + else: + # print('Warning: Mis-match in tracker prediction and GT lengths') + if pred_bb.shape[0] > anno_bb.shape[0]: + pred_bb = pred_bb[:anno_bb.shape[0], :] + else: + pad = torch.zeros((anno_bb.shape[0] - pred_bb.shape[0], 4)).type_as(pred_bb) + pred_bb = torch.cat((pred_bb, pad), dim=0) + + pred_bb[0, :] = anno_bb[0, :] + + if target_visible is not None: + target_visible = target_visible.bool() + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) & target_visible + else: + valid = ((anno_bb[:, 2:] > 0.0).sum(1) == 2) + + err_center = calc_err_center(pred_bb, anno_bb) + err_center_normalized = calc_err_center(pred_bb, anno_bb, normalized=True) + err_overlap = calc_iou_overlap(pred_bb, anno_bb) + + # handle invalid anno cases + if dataset in ['uav']: + err_center[~valid] = -1.0 + else: + err_center[~valid] = float("Inf") + err_center_normalized[~valid] = -1.0 + err_overlap[~valid] = -1.0 + + if dataset == 'lasot': + err_center_normalized[~target_visible] = float("Inf") + err_center[~target_visible] = float("Inf") + + if torch.isnan(err_overlap).any(): + raise Exception('Nans in calculated overlap') + return err_overlap, err_center, err_center_normalized, valid + + +def extract_results(trackers, dataset, report_name, skip_missing_seq=False, plot_bin_gap=0.05, + exclude_invalid_frames=False): + settings = env_settings() + eps = 1e-16 + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + if not os.path.exists(result_plot_path): + os.makedirs(result_plot_path) + + threshold_set_overlap = torch.arange(0.0, 1.0 + plot_bin_gap, plot_bin_gap, dtype=torch.float64) + threshold_set_center = torch.arange(0, 51, dtype=torch.float64) + threshold_set_center_norm = torch.arange(0, 51, dtype=torch.float64) / 100.0 + + avg_overlap_all = torch.zeros((len(dataset), len(trackers)), dtype=torch.float64) + ave_success_rate_plot_overlap = torch.zeros((len(dataset), len(trackers), threshold_set_overlap.numel()), + dtype=torch.float32) + ave_success_rate_plot_center = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + ave_success_rate_plot_center_norm = torch.zeros((len(dataset), len(trackers), threshold_set_center.numel()), + dtype=torch.float32) + + valid_sequence = torch.ones(len(dataset), dtype=torch.uint8) + + for seq_id, seq in enumerate(tqdm(dataset)): + # Load anno + anno_bb = torch.tensor(seq.ground_truth_rect) + target_visible = torch.tensor(seq.target_visible, dtype=torch.uint8) if seq.target_visible is not None else None + for trk_id, trk in enumerate(trackers): + # Load results + base_results_path = '{}/{}'.format(trk.results_dir, seq.name) + results_path = '{}.txt'.format(base_results_path) + + if os.path.isfile(results_path): + pred_bb = torch.tensor(load_text(str(results_path), delimiter=('\t', ','), dtype=np.float64)) + else: + if skip_missing_seq: + valid_sequence[seq_id] = 0 + break + else: + raise Exception('Result not found. {}'.format(results_path)) + + # Calculate measures + err_overlap, err_center, err_center_normalized, valid_frame = calc_seq_err_robust( + pred_bb, anno_bb, seq.dataset, target_visible) + + avg_overlap_all[seq_id, trk_id] = err_overlap[valid_frame].mean() + + if exclude_invalid_frames: + seq_length = valid_frame.long().sum() + else: + seq_length = anno_bb.shape[0] + + if seq_length <= 0: + raise Exception('Seq length zero') + + ave_success_rate_plot_overlap[seq_id, trk_id, :] = (err_overlap.view(-1, 1) > threshold_set_overlap.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center[seq_id, trk_id, :] = (err_center.view(-1, 1) <= threshold_set_center.view(1, -1)).sum(0).float() / seq_length + ave_success_rate_plot_center_norm[seq_id, trk_id, :] = (err_center_normalized.view(-1, 1) <= threshold_set_center_norm.view(1, -1)).sum(0).float() / seq_length + + print('\n\nComputed results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + # Prepare dictionary for saving data + seq_names = [s.name for s in dataset] + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + + eval_data = {'sequences': seq_names, 'trackers': tracker_names, + 'valid_sequence': valid_sequence.tolist(), + 'ave_success_rate_plot_overlap': ave_success_rate_plot_overlap.tolist(), + 'ave_success_rate_plot_center': ave_success_rate_plot_center.tolist(), + 'ave_success_rate_plot_center_norm': ave_success_rate_plot_center_norm.tolist(), + 'avg_overlap_all': avg_overlap_all.tolist(), + 'threshold_set_overlap': threshold_set_overlap.tolist(), + 'threshold_set_center': threshold_set_center.tolist(), + 'threshold_set_center_norm': threshold_set_center_norm.tolist()} + + with open(result_plot_path + '/eval_data.pkl', 'wb') as fh: + pickle.dump(eval_data, fh) + + return eval_data diff --git a/pytracking/analysis/playback_results.py b/pytracking/analysis/playback_results.py new file mode 100755 index 0000000..f611f72 --- /dev/null +++ b/pytracking/analysis/playback_results.py @@ -0,0 +1,176 @@ +import os +import sys +import importlib +import numpy as np +import torch +import time +import matplotlib.patches as patches +import cv2 as cv +import matplotlib.pyplot as plt +from pytracking.analysis.plot_results import get_plot_draw_styles +from pytracking.utils.plotting import draw_figure +from pytracking.evaluation import get_dataset, trackerlist + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + + +class Display: + def __init__(self, sequence_length, plot_draw_styles, sequence_name): + self.active = True + self.frame_number = 0 + self.pause_mode = True + self.step_size = 0 + self.step_direction = 'forward' + self.fig, self.ax = plt.subplots(1) + self.fig.canvas.mpl_connect('key_press_event', self.key_callback_fn) + plt.tight_layout() + + self.sequence_length = sequence_length + self.sequence_name = sequence_name + self.plot_draw_styles = plot_draw_styles + + def key_callback_fn(self, event): + if event.key == ' ': + self.pause_mode = not self.pause_mode + self.step_size = 0 + self.step_direction = 'forward' + elif event.key == 'right': + if self.pause_mode: + self.frame_number += 1 + + if self.frame_number >= self.sequence_length: + self.frame_number = self.sequence_length - 1 + elif self.step_direction == 'stop': + self.step_direction = 'forward' + self.step_size = 0 + elif self.step_direction == 'backward' and self.step_size == 0: + self.step_direction = 'stop' + else: + self.step_size += 1 + elif event.key == 'left': + if self.pause_mode: + self.frame_number -= 1 + + if self.frame_number < 0: + self.frame_number = 0 + elif self.step_direction == 'stop': + self.step_direction = 'backward' + self.step_size = 0 + elif self.step_direction == 'forward' and self.step_size == 0: + self.step_direction = 'stop' + else: + self.step_size -= 1 + elif event.key == 'escape' or event.key == 'q': + self.active = False + + def _get_speed(self): + delta = 0 + if self.step_direction == 'forward': + delta = 2 ** abs(self.step_size) + elif self.step_direction == 'backward': + delta = -1 * 2 ** abs(self.step_size) + + return delta + + def step(self): + delta = self._get_speed() + + self.frame_number += delta + if self.frame_number < 0: + self.frame_number = 0 + elif self.frame_number >= self.sequence_length: + self.frame_number = self.sequence_length - 1 + + def show(self, image, bb_list, trackers, gt=None): + self.ax.cla() + self.ax.imshow(image) + + # Draw rects + rect_handles = [] + for i, bb in enumerate(bb_list): + rect = patches.Rectangle((bb[0], bb[1]), bb[2], bb[3], linewidth=1, + edgecolor=self.plot_draw_styles[i]['color'], facecolor='none') + self.ax.add_patch(rect) + + rect_handles.append(patches.Rectangle((bb[0], bb[1]), bb[2], bb[3], linewidth=1, + edgecolor=self.plot_draw_styles[i]['color'], + facecolor=self.plot_draw_styles[i]['color'], + label=trackers[i])) + + if gt is not None: + rect = patches.Rectangle((gt[0], gt[1]), gt[2], gt[3], linewidth=2, edgecolor='g', + facecolor='none') + self.ax.add_patch(rect) + rect_handles.append(rect) + + self.ax.set_axis_off() + self.ax.axis('equal') + plt.legend(handles=rect_handles, loc=4, borderaxespad=0.) + mode = 'manual' if self.pause_mode else 'auto ' + speed = self._get_speed() + self.fig.suptitle('Sequence: {} Mode: {} Speed: {:d}x'.format(self.sequence_name, mode, speed), + fontsize=14) + draw_figure(self.fig) + + +def read_image(image_file: str): + im = cv.imread(image_file) + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + + +def _get_display_name(tracker): + if tracker.display_name is None: + if tracker.run_id is not None: + return '{}_{}_{:03d}'.format(tracker.name, tracker.parameter_name, tracker.run_id) + else: + return '{}_{}'.format(tracker.name, tracker.parameter_name) + else: + return tracker.display_name + + +def playback_results(trackers, sequence): + """ + Playback saved results of input trackers for a particular sequence. You can navigate the sequence using left/right + arrow keys. You can also change to 'auto' mode by pressing space bar, in which case the sequence will be replayed + at a particular speed. The speed for playback in 'auto' mode can be controlled using the left/right arrow keys. + You can exit the application using escape or q keys. + """ + plot_draw_styles = get_plot_draw_styles() + + tracker_results = [] + # Load results + for trk_id, trk in enumerate(trackers): + # Load results + base_results_path = '{}/{}'.format(trk.results_dir, sequence.name) + results_path = '{}.txt'.format(base_results_path) + + if os.path.isfile(results_path): + try: + pred_bb = torch.tensor(np.loadtxt(str(results_path), dtype=np.float64)) + except: + pred_bb = torch.tensor(np.loadtxt(str(results_path), delimiter=',', dtype=np.float64)) + else: + raise Exception('Result not found. {}'.format(results_path)) + + tracker_results.append(pred_bb) + + # Convert to list of shape seq_length * num_trackers * 4 + tracker_results = torch.stack(tracker_results, dim=1).tolist() + tracker_names = [_get_display_name(t) for t in trackers] + + display = Display(len(tracker_results), plot_draw_styles, sequence.name) + + while display.active: + frame_number = display.frame_number + image = read_image(sequence.frames[frame_number]) + + display.show(image, tracker_results[frame_number], tracker_names) + + time.sleep(0.01) + if display.pause_mode and display.frame_number == frame_number: + time.sleep(0.1) + elif not display.pause_mode: + display.step() + diff --git a/pytracking/analysis/plot_results.py b/pytracking/analysis/plot_results.py new file mode 100755 index 0000000..f75cb3d --- /dev/null +++ b/pytracking/analysis/plot_results.py @@ -0,0 +1,483 @@ +import tikzplotlib +import matplotlib +import matplotlib.pyplot as plt +import os +import torch +import pickle +import json +from pytracking.evaluation.environment import env_settings +from pytracking.analysis.extract_results import extract_results + + +def get_plot_draw_styles(): + plot_draw_style = [{'color': (1.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 0.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 0.0, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.0, 1.0), 'line_style': '-'}, + {'color': (0.0, 1.0, 1.0), 'line_style': '-'}, + {'color': (0.5, 0.5, 0.5), 'line_style': '-'}, + {'color': (136.0 / 255.0, 0.0, 21.0 / 255.0), 'line_style': '-'}, + {'color': (1.0, 127.0 / 255.0, 39.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 162.0 / 255.0, 232.0 / 255.0), 'line_style': '-'}, + {'color': (0.0, 0.5, 0.0), 'line_style': '-'}, + {'color': (1.0, 0.5, 0.2), 'line_style': '-'}, + {'color': (0.1, 0.4, 0.0), 'line_style': '-'}, + {'color': (0.6, 0.3, 0.9), 'line_style': '-'}, + {'color': (0.4, 0.7, 0.1), 'line_style': '-'}, + {'color': (0.2, 0.1, 0.7), 'line_style': '-'}, + {'color': (0.7, 0.6, 0.2), 'line_style': '-'}] + + return plot_draw_style + + +def check_eval_data_is_valid(eval_data, trackers, dataset): + """ Checks if the pre-computed results are valid""" + seq_names = [s.name for s in dataset] + seq_names_saved = eval_data['sequences'] + + tracker_names_f = [(t.name, t.parameter_name, t.run_id) for t in trackers] + tracker_names_f_saved = [(t['name'], t['param'], t['run_id']) for t in eval_data['trackers']] + + return seq_names == seq_names_saved and tracker_names_f == tracker_names_f_saved + + +def merge_multiple_runs(eval_data): + new_tracker_names = [] + ave_success_rate_plot_overlap_merged = [] + ave_success_rate_plot_center_merged = [] + ave_success_rate_plot_center_norm_merged = [] + avg_overlap_all_merged = [] + + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) + + trackers = eval_data['trackers'] + merged = torch.zeros(len(trackers), dtype=torch.uint8) + for i in range(len(trackers)): + if merged[i]: + continue + base_tracker = trackers[i] + new_tracker_names.append(base_tracker) + + match = [t['name'] == base_tracker['name'] and t['param'] == base_tracker['param'] for t in trackers] + match = torch.tensor(match) + + ave_success_rate_plot_overlap_merged.append(ave_success_rate_plot_overlap[:, match, :].mean(1)) + ave_success_rate_plot_center_merged.append(ave_success_rate_plot_center[:, match, :].mean(1)) + ave_success_rate_plot_center_norm_merged.append(ave_success_rate_plot_center_norm[:, match, :].mean(1)) + avg_overlap_all_merged.append(avg_overlap_all[:, match].mean(1)) + + merged[match] = 1 + + ave_success_rate_plot_overlap_merged = torch.stack(ave_success_rate_plot_overlap_merged, dim=1) + ave_success_rate_plot_center_merged = torch.stack(ave_success_rate_plot_center_merged, dim=1) + ave_success_rate_plot_center_norm_merged = torch.stack(ave_success_rate_plot_center_norm_merged, dim=1) + avg_overlap_all_merged = torch.stack(avg_overlap_all_merged, dim=1) + + eval_data['trackers'] = new_tracker_names + eval_data['ave_success_rate_plot_overlap'] = ave_success_rate_plot_overlap_merged.tolist() + eval_data['ave_success_rate_plot_center'] = ave_success_rate_plot_center_merged.tolist() + eval_data['ave_success_rate_plot_center_norm'] = ave_success_rate_plot_center_norm_merged.tolist() + eval_data['avg_overlap_all'] = avg_overlap_all_merged.tolist() + + return eval_data + + +def get_tracker_display_name(tracker): + if tracker['disp_name'] is None: + if tracker['run_id'] is None: + disp_name = '{}_{}'.format(tracker['name'], tracker['param']) + else: + disp_name = '{}_{}_{:03d}'.format(tracker['name'], tracker['param'], + tracker['run_id']) + else: + disp_name = tracker['disp_name'] + + return disp_name + + +def plot_draw_save(y, x, scores, trackers, plot_draw_styles, result_plot_path, plot_opts): + # Plot settings + font_size = plot_opts.get('font_size', 12) + font_size_axis = plot_opts.get('font_size_axis', 13) + line_width = plot_opts.get('line_width', 2) + font_size_legend = plot_opts.get('font_size_legend', 13) + + plot_type = plot_opts['plot_type'] + legend_loc = plot_opts['legend_loc'] + + xlabel = plot_opts['xlabel'] + ylabel = plot_opts['ylabel'] + xlim = plot_opts['xlim'] + ylim = plot_opts['ylim'] + + title = plot_opts['title'] + + matplotlib.rcParams.update({'font.size': font_size}) + matplotlib.rcParams.update({'axes.titlesize': font_size_axis}) + matplotlib.rcParams.update({'axes.titleweight': 'black'}) + matplotlib.rcParams.update({'axes.labelsize': font_size_axis}) + + fig, ax = plt.subplots() + + index_sort = scores.argsort(descending=False) + + plotted_lines = [] + legend_text = [] + + for id, id_sort in enumerate(index_sort): + line = ax.plot(x.tolist(), y[id_sort, :].tolist(), + linewidth=line_width, + color=plot_draw_styles[index_sort.numel() - id - 1]['color'], + linestyle=plot_draw_styles[index_sort.numel() - id - 1]['line_style']) + + plotted_lines.append(line[0]) + + tracker = trackers[id_sort] + disp_name = get_tracker_display_name(tracker) + + legend_text.append('{} [{:.1f}]'.format(disp_name, scores[id_sort])) + + ax.legend(plotted_lines[::-1], legend_text[::-1], loc=legend_loc, fancybox=False, edgecolor='black', + fontsize=font_size_legend, framealpha=1.0) + + ax.set(xlabel=xlabel, + ylabel=ylabel, + xlim=xlim, ylim=ylim, + title=title) + + ax.grid(True, linestyle='-.') + fig.tight_layout() + + tikzplotlib.save('{}/{}_plot.tex'.format(result_plot_path, plot_type)) + fig.savefig('{}/{}_plot.pdf'.format(result_plot_path, plot_type), dpi=300, format='pdf', transparent=True) + plt.draw() + + +def check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation=False, **kwargs): + # Load data + settings = env_settings() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data_path = os.path.join(result_plot_path, 'eval_data.pkl') + + if os.path.isfile(eval_data_path) and not force_evaluation: + with open(eval_data_path, 'rb') as fh: + eval_data = pickle.load(fh) + else: + # print('Pre-computed evaluation data not found. Computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + + if not check_eval_data_is_valid(eval_data, trackers, dataset): + # print('Pre-computed evaluation data invalid. Re-computing results!') + eval_data = extract_results(trackers, dataset, report_name, **kwargs) + else: + # Update display names + tracker_names = [{'name': t.name, 'param': t.parameter_name, 'run_id': t.run_id, 'disp_name': t.display_name} + for t in trackers] + eval_data['trackers'] = tracker_names + + return eval_data + + +def get_auc_curve(ave_success_rate_plot_overlap, valid_sequence): + ave_success_rate_plot_overlap = ave_success_rate_plot_overlap[valid_sequence, :, :] + auc_curve = ave_success_rate_plot_overlap.mean(0) * 100.0 + auc = auc_curve.mean(-1) + + return auc_curve, auc + + +def get_prec_curve(ave_success_rate_plot_center, valid_sequence): + ave_success_rate_plot_center = ave_success_rate_plot_center[valid_sequence, :, :] + prec_curve = ave_success_rate_plot_center.mean(0) * 100.0 + prec_score = prec_curve[:, 20] + + return prec_curve, prec_score + + +def plot_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), force_evaluation=False, **kwargs): + """ + Plot results for the given trackers + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success', + 'prec' (precision), and 'norm_prec' (normalized precision) + """ + # Load data + settings = env_settings() + + plot_draw_styles = get_plot_draw_styles() + + # Load pre-computed results + result_plot_path = os.path.join(settings.result_plot_path, report_name) + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, force_evaluation, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nPlotting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + print('\nGenerating plots for: {}'.format(report_name)) + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 100), 'title': 'Success plot'} + plot_draw_save(auc_curve, threshold_set_overlap, auc, tracker_names, plot_draw_styles, result_plot_path, success_plot_opts) + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + threshold_set_center = torch.tensor(eval_data['threshold_set_center']) + + precision_plot_opts = {'plot_type': 'precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold [pixels]', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 50), 'ylim': (0, 100), 'title': 'Precision plot'} + plot_draw_save(prec_curve, threshold_set_center, prec_score, tracker_names, plot_draw_styles, result_plot_path, + precision_plot_opts) + + # ******************************** Norm Precision Plot ************************************** + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + threshold_set_center_norm = torch.tensor(eval_data['threshold_set_center_norm']) + + norm_precision_plot_opts = {'plot_type': 'norm_precision', 'legend_loc': 'lower right', + 'xlabel': 'Location error threshold', 'ylabel': 'Distance Precision [%]', + 'xlim': (0, 0.5), 'ylim': (0, 100), 'title': 'Normalized Precision plot'} + plot_draw_save(prec_curve, threshold_set_center_norm, prec_score, tracker_names, plot_draw_styles, result_plot_path, + norm_precision_plot_opts) + + plt.show() + + +def generate_formatted_report(row_labels, scores, table_name=''): + name_width = max([len(d) for d in row_labels] + [len(table_name)]) + 5 + min_score_width = 10 + + report_text = '\n{label: <{width}} |'.format(label=table_name, width=name_width) + + score_widths = [max(min_score_width, len(k) + 3) for k in scores.keys()] + + for s, s_w in zip(scores.keys(), score_widths): + report_text = '{prev} {s: <{width}} |'.format(prev=report_text, s=s, width=s_w) + + report_text = '{prev}\n'.format(prev=report_text) + + for trk_id, d_name in enumerate(row_labels): + # display name + report_text = '{prev}{tracker: <{width}} |'.format(prev=report_text, tracker=d_name, + width=name_width) + for (score_type, score_value), s_w in zip(scores.items(), score_widths): + report_text = '{prev} {score: <{width}} |'.format(prev=report_text, + score='{:0.2f}'.format(score_value[trk_id].item()), + width=s_w) + report_text = '{prev}\n'.format(prev=report_text) + + return report_text + + +def print_results(trackers, dataset, report_name, merge_results=False, + plot_types=('success'), **kwargs): + """ Print the results for the given trackers in a formatted table + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + plot_types - List of scores to display. Can contain 'success' (prints AUC, OP50, and OP75 scores), + 'prec' (prints precision score), and 'norm_prec' (prints normalized precision score) + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + + print('\nReporting results over {} / {} sequences'.format(valid_sequence.long().sum().item(), valid_sequence.shape[0])) + + scores = {} + + # ******************************** Success Plot ************************************** + if 'success' in plot_types: + threshold_set_overlap = torch.tensor(eval_data['threshold_set_overlap']) + ave_success_rate_plot_overlap = torch.tensor(eval_data['ave_success_rate_plot_overlap']) + + # Index out valid sequences + auc_curve, auc = get_auc_curve(ave_success_rate_plot_overlap, valid_sequence) + scores['AUC'] = auc + scores['OP50'] = auc_curve[:, threshold_set_overlap == 0.50] + scores['OP75'] = auc_curve[:, threshold_set_overlap == 0.75] + + # ******************************** Precision Plot ************************************** + if 'prec' in plot_types: + ave_success_rate_plot_center = torch.tensor(eval_data['ave_success_rate_plot_center']) + + # Index out valid sequences + prec_curve, prec_score = get_prec_curve(ave_success_rate_plot_center, valid_sequence) + scores['Precision'] = prec_score + + # ******************************** Norm Precision Plot ********************************* + if 'norm_prec' in plot_types: + ave_success_rate_plot_center_norm = torch.tensor(eval_data['ave_success_rate_plot_center_norm']) + + # Index out valid sequences + norm_prec_curve, norm_prec_score = get_prec_curve(ave_success_rate_plot_center_norm, valid_sequence) + scores['Norm Precision'] = norm_prec_score + + # Print + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + report_text = generate_formatted_report(tracker_disp_names, scores, table_name=report_name) + print(report_text) + + +def plot_got_success(trackers, report_name): + """ Plot success plot for GOT-10k dataset using the json reports. + Save the json reports from http://got-10k.aitestunion.com/leaderboard in the directory set to + env_settings.got_reports_path + + The tracker name in the experiment file should be set to the name of the report file for that tracker, + e.g. DiMP50_report_2019_09_02_15_44_25 if the report is name DiMP50_report_2019_09_02_15_44_25.json + + args: + trackers - List of trackers to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + """ + # Load data + settings = env_settings() + plot_draw_styles = get_plot_draw_styles() + + result_plot_path = os.path.join(settings.result_plot_path, report_name) + + auc_curve = torch.zeros((len(trackers), 101)) + scores = torch.zeros(len(trackers)) + + # Load results + tracker_names = [] + for trk_id, trk in enumerate(trackers): + json_path = '{}/{}.json'.format(settings.got_reports_path, trk.name) + + if os.path.isfile(json_path): + with open(json_path, 'r') as f: + eval_data = json.load(f) + else: + raise Exception('Report not found {}'.format(json_path)) + + if len(eval_data.keys()) > 1: + raise Exception + + # First field is the tracker name. Index it out + eval_data = eval_data[list(eval_data.keys())[0]] + if 'succ_curve' in eval_data.keys(): + curve = eval_data['succ_curve'] + ao = eval_data['ao'] + elif 'overall' in eval_data.keys() and 'succ_curve' in eval_data['overall'].keys(): + curve = eval_data['overall']['succ_curve'] + ao = eval_data['overall']['ao'] + else: + raise Exception('Invalid JSON file {}'.format(json_path)) + + auc_curve[trk_id, :] = torch.tensor(curve) * 100.0 + scores[trk_id] = ao * 100.0 + + tracker_names.append({'name': trk.name, 'param': trk.parameter_name, 'run_id': trk.run_id, + 'disp_name': trk.display_name}) + + threshold_set_overlap = torch.arange(0.0, 1.01, 0.01, dtype=torch.float64) + + success_plot_opts = {'plot_type': 'success', 'legend_loc': 'lower left', 'xlabel': 'Overlap threshold', + 'ylabel': 'Overlap Precision [%]', 'xlim': (0, 1.0), 'ylim': (0, 100), 'title': 'Success plot'} + plot_draw_save(auc_curve, threshold_set_overlap, scores, tracker_names, plot_draw_styles, result_plot_path, + success_plot_opts) + plt.show() + + +def print_per_sequence_results(trackers, dataset, report_name, merge_results=False, + filter_criteria=None, **kwargs): + """ Print per-sequence results for the given trackers. Additionally, the sequences to list can be filtered using + the filter criteria. + + args: + trackers - List of trackers to evaluate + dataset - List of sequences to evaluate + report_name - Name of the folder in env_settings.perm_mat_path where the computed results and plots are saved + merge_results - If True, multiple random runs for a non-deterministic trackers are averaged + filter_criteria - Filter sequence results which are reported. Following modes are supported + None: No filtering. Display results for all sequences in dataset + 'ao_min': Only display sequences for which the minimum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences where at least one tracker performs poorly. + 'ao_max': Only display sequences for which the maximum average overlap (AO) score over the + trackers is less than a threshold filter_criteria['threshold']. This mode can + be used to select sequences all tracker performs poorly. + 'delta_ao': Only display sequences for which the performance of different trackers vary by at + least filter_criteria['threshold'] in average overlap (AO) score. This mode can + be used to select sequences where the behaviour of the trackers greatly differ + between each other. + """ + # Load pre-computed results + eval_data = check_and_load_precomputed_results(trackers, dataset, report_name, **kwargs) + + # Merge results from multiple runs + if merge_results: + eval_data = merge_multiple_runs(eval_data) + + tracker_names = eval_data['trackers'] + valid_sequence = torch.tensor(eval_data['valid_sequence'], dtype=torch.bool) + sequence_names = eval_data['sequences'] + avg_overlap_all = torch.tensor(eval_data['avg_overlap_all']) * 100.0 + + # Filter sequences + if filter_criteria is not None: + if filter_criteria['mode'] == 'ao_min': + min_ao = avg_overlap_all.min(dim=1)[0] + valid_sequence = valid_sequence & (min_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'ao_max': + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & (max_ao < filter_criteria['threshold']) + elif filter_criteria['mode'] == 'delta_ao': + min_ao = avg_overlap_all.min(dim=1)[0] + max_ao = avg_overlap_all.max(dim=1)[0] + valid_sequence = valid_sequence & ((max_ao - min_ao) > filter_criteria['threshold']) + else: + raise Exception + + avg_overlap_all = avg_overlap_all[valid_sequence, :] + sequence_names = [s + ' (ID={})'.format(i) for i, (s, v) in enumerate(zip(sequence_names, valid_sequence.tolist())) if v] + + tracker_disp_names = [get_tracker_display_name(trk) for trk in tracker_names] + + scores_per_tracker = {k: avg_overlap_all[:, i] for i, k in enumerate(tracker_disp_names)} + report_text = generate_formatted_report(sequence_names, scores_per_tracker) + + print(report_text) diff --git a/pytracking/analysis/vos_utils.py b/pytracking/analysis/vos_utils.py new file mode 100755 index 0000000..49f46d6 --- /dev/null +++ b/pytracking/analysis/vos_utils.py @@ -0,0 +1,235 @@ +import warnings +import numpy as np +from skimage.morphology import binary_dilation, disk +from math import floor + + +def text_bargraph(values): + + blocks = np.array(('u', ' ', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', 'o')) + nsteps = len(blocks)-2-1 + hstep = 1 / (2*nsteps) + values = np.array(values) + nans = np.isnan(values) + values[nans] = 0 # '░' + indices = ((values + hstep) * nsteps + 1).astype(np.int) + indices[values < 0] = 0 + indices[values > 1] = len(blocks)-1 + graph = blocks[indices] + graph[nans] = '░' + graph = str.join('', graph) + return graph + + +# ---------------------------------------------------------------------------- +# The 2017 DAVIS Challenge on Video Object Segmentation +# ----------------------------------------------------------------------------- +# Copyright (c) 2017 Federico Perazzi +# Licensed under the BSD License [see LICENSE for details] +# Written by Federico Perazzi (federico@disneyresearch.com) +# Adapted from DAVIS 2016 (Federico Perazzi) +# ---------------------------------------------------------------------------- + +# Originally db_eval_iou() in the davis challenge toolkit: +def davis_jaccard_measure(fg_mask, gt_mask): + """ Compute region similarity as the Jaccard Index. + + :param fg_mask: (ndarray): binary segmentation map. + :param gt_mask: (ndarray): binary annotation map. + :return: jaccard (float): region similarity + """ + + gt_mask = gt_mask.astype(np.bool) + fg_mask = fg_mask.astype(np.bool) + + if np.isclose(np.sum(gt_mask), 0) and np.isclose(np.sum(fg_mask), 0): + return 1 + else: + return np.sum((gt_mask & fg_mask)) / \ + np.sum((gt_mask | fg_mask), dtype=np.float32) + + +def davis_jaccard_measure_torch(fg_mask, gt_mask): + """ Compute region similarity as the Jaccard Index. + + :param fg_mask: (ndarray): binary segmentation map. + :param gt_mask: (ndarray): binary annotation map. + :return: jaccard (float): region similarity + """ + + #gt_mask = gt_mask.astype(np.bool) + #fg_mask = fg_mask.astype(np.bool) + + if gt_mask.sum() == 0 and fg_mask.sum() == 0: + return 1 + else: + return (gt_mask & fg_mask).sum() / \ + (gt_mask | fg_mask).sum().float() + +# Originally db_eval_boundary() in the davis challenge toolkit: +def davis_f_measure(foreground_mask, gt_mask, bound_th=0.008): + """ + Compute mean,recall and decay from per-frame evaluation. + Calculates precision/recall for boundaries between foreground_mask and + gt_mask using morphological operators to speed it up. + + Arguments: + foreground_mask (ndarray): binary segmentation image. + gt_mask (ndarray): binary annotated image. + + Returns: + F (float): boundaries F-measure + P (float): boundaries precision + R (float): boundaries recall + """ + assert np.atleast_3d(foreground_mask).shape[2] == 1 + + bound_pix = bound_th if bound_th >= 1 else \ + np.ceil(bound_th * np.linalg.norm(foreground_mask.shape)) + + # Get the pixel boundaries of both masks + fg_boundary = seg2bmap(foreground_mask) + gt_boundary = seg2bmap(gt_mask) + + fg_dil = binary_dilation(fg_boundary, disk(bound_pix)) + gt_dil = binary_dilation(gt_boundary, disk(bound_pix)) + + # Get the intersection + gt_match = gt_boundary * fg_dil + fg_match = fg_boundary * gt_dil + + # Area of the intersection + n_fg = np.sum(fg_boundary) + n_gt = np.sum(gt_boundary) + + # % Compute precision and recall + if n_fg == 0 and n_gt > 0: + precision = 1 + recall = 0 + elif n_fg > 0 and n_gt == 0: + precision = 0 + recall = 1 + elif n_fg == 0 and n_gt == 0: + precision = 1 + recall = 1 + else: + precision = np.sum(fg_match) / float(n_fg) + recall = np.sum(gt_match) / float(n_gt) + + # Compute F measure + if precision + recall == 0: + F = 0 + else: + F = 2 * precision * recall / (precision + recall) + + return F + + +def seg2bmap(seg, width=None, height=None): + """ + From a segmentation, compute a binary boundary map with 1 pixel wide + boundaries. The boundary pixels are offset by 1/2 pixel towards the + origin from the actual segment boundary. + + Arguments: + seg : Segments labeled from 1..k. + width : Width of desired bmap <= seg.shape[1] + height : Height of desired bmap <= seg.shape[0] + + Returns: + bmap (ndarray): Binary boundary map. + + David Martin <dmartin@eecs.berkeley.edu> + January 2003 + """ + + seg = seg.astype(np.bool) + seg[seg > 0] = 1 + + assert np.atleast_3d(seg).shape[2] == 1 + + width = seg.shape[1] if width is None else width + height = seg.shape[0] if height is None else height + + h, w = seg.shape[:2] + + ar1 = float(width) / float(height) + ar2 = float(w) / float(h) + + assert not (width > w | height > h | abs(ar1 - ar2) > 0.01), \ + 'Can''t convert %dx%d seg to %dx%d bmap.' % (w, h, width, height) + + e = np.zeros_like(seg) + s = np.zeros_like(seg) + se = np.zeros_like(seg) + + e[:, :-1] = seg[:, 1:] + s[:-1, :] = seg[1:, :] + se[:-1, :-1] = seg[1:, 1:] + + b = seg ^ e | seg ^ s | seg ^ se + b[-1, :] = seg[-1, :] ^ e[-1, :] + b[:, -1] = seg[:, -1] ^ s[:, -1] + b[-1, -1] = 0 + + if w == width and h == height: + bmap = b + else: + bmap = np.zeros((height, width)) + for x in range(w): + for y in range(h): + if b[y, x]: + j = 1 + floor((y - 1) + height / h) + i = 1 + floor((x - 1) + width / h) + bmap[j, i] = 1 + + return bmap + + +def nanmean(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + return np.nanmean(*args, **kwargs) + + +def mean(X): + """ + Compute average ignoring NaN values. + """ + return np.nanmean(X) + + +def recall(X, threshold=0.5): + """ + Fraction of values of X scoring higher than 'threshold' + """ + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + x = X[~np.isnan(X)] + x = mean(x > threshold) + return x + + +def decay(X, n_bins=4): + """ + Performance loss over time. + """ + X = X[~np.isnan(X)] + ids = np.round(np.linspace(1, len(X), n_bins + 1) + 1e-10) - 1 + ids = ids.astype(np.uint8) + + D_bins = [X[ids[i]:ids[i + 1] + 1] for i in range(0, 4)] + + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + D = np.nanmean(D_bins[0]) - np.nanmean(D_bins[3]) + return D + + +def std(X): + """ + Compute standard deviation. + """ + return np.nanstd(X) + + diff --git a/pytracking/evaluation/__init__.py b/pytracking/evaluation/__init__.py new file mode 100755 index 0000000..5ee6d34 --- /dev/null +++ b/pytracking/evaluation/__init__.py @@ -0,0 +1,3 @@ +from .data import Sequence +from .tracker import Tracker, trackerlist +from .datasets import get_dataset \ No newline at end of file diff --git a/pytracking/evaluation/__pycache__/__init__.cpython-37.pyc b/pytracking/evaluation/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..61d06ba Binary files /dev/null and b/pytracking/evaluation/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/data.cpython-37.pyc b/pytracking/evaluation/__pycache__/data.cpython-37.pyc new file mode 100755 index 0000000..76bbbb4 Binary files /dev/null and b/pytracking/evaluation/__pycache__/data.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/datasets.cpython-37.pyc b/pytracking/evaluation/__pycache__/datasets.cpython-37.pyc new file mode 100755 index 0000000..04c475a Binary files /dev/null and b/pytracking/evaluation/__pycache__/datasets.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/environment.cpython-37.pyc b/pytracking/evaluation/__pycache__/environment.cpython-37.pyc new file mode 100755 index 0000000..bcff3e5 Binary files /dev/null and b/pytracking/evaluation/__pycache__/environment.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/local.cpython-37.pyc b/pytracking/evaluation/__pycache__/local.cpython-37.pyc new file mode 100755 index 0000000..0cc660c Binary files /dev/null and b/pytracking/evaluation/__pycache__/local.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/multi_object_wrapper.cpython-37.pyc b/pytracking/evaluation/__pycache__/multi_object_wrapper.cpython-37.pyc new file mode 100755 index 0000000..b5f126f Binary files /dev/null and b/pytracking/evaluation/__pycache__/multi_object_wrapper.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/running.cpython-37.pyc b/pytracking/evaluation/__pycache__/running.cpython-37.pyc new file mode 100755 index 0000000..6dbf08f Binary files /dev/null and b/pytracking/evaluation/__pycache__/running.cpython-37.pyc differ diff --git a/pytracking/evaluation/__pycache__/tracker.cpython-37.pyc b/pytracking/evaluation/__pycache__/tracker.cpython-37.pyc new file mode 100755 index 0000000..c4cecea Binary files /dev/null and b/pytracking/evaluation/__pycache__/tracker.cpython-37.pyc differ diff --git a/pytracking/evaluation/data.py b/pytracking/evaluation/data.py new file mode 100755 index 0000000..6446efb --- /dev/null +++ b/pytracking/evaluation/data.py @@ -0,0 +1,169 @@ +import numpy as np +from pytracking.evaluation.environment import env_settings +from ltr.data.image_loader import imread_indexed +from collections import OrderedDict + + +class BaseDataset: + """Base class for all datasets.""" + def __init__(self): + self.env_settings = env_settings() + + def __len__(self): + """Overload this function in your dataset. This should return number of sequences in the dataset.""" + raise NotImplementedError + + def get_sequence_list(self): + """Overload this in your dataset. Should return the list of sequences in the dataset.""" + raise NotImplementedError + + +class Sequence: + """Class for the sequence in an evaluation.""" + def __init__(self, name, frames, dataset, ground_truth_rect, ground_truth_seg=None, init_data=None, + object_class=None, target_visible=None, object_ids=None, multiobj_mode=False): + self.name = name + self.frames = frames + self.dataset = dataset + self.ground_truth_rect = ground_truth_rect + self.ground_truth_seg = ground_truth_seg + self.object_class = object_class + self.target_visible = target_visible + self.object_ids = object_ids + self.multiobj_mode = multiobj_mode + self.init_data = self._construct_init_data(init_data) + self._ensure_start_frame() + + def _ensure_start_frame(self): + # Ensure start frame is 0 + start_frame = min(list(self.init_data.keys())) + if start_frame > 0: + self.frames = self.frames[start_frame:] + if self.ground_truth_rect is not None: + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + for obj_id, gt in self.ground_truth_rect.items(): + self.ground_truth_rect[obj_id] = gt[start_frame:,:] + else: + self.ground_truth_rect = self.ground_truth_rect[start_frame:,:] + if self.ground_truth_seg is not None: + self.ground_truth_seg = self.ground_truth_seg[start_frame:] + assert len(self.frames) == len(self.ground_truth_seg) + + if self.target_visible is not None: + self.target_visible = self.target_visible[start_frame:] + self.init_data = {frame-start_frame: val for frame, val in self.init_data.items()} + + def _construct_init_data(self, init_data): + if init_data is not None: + if not self.multiobj_mode: + assert self.object_ids is None or len(self.object_ids) == 1 + for frame, init_val in init_data.items(): + if 'bbox' in init_val and isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = init_val['bbox'][self.object_ids[0]] + # convert to list + for frame, init_val in init_data.items(): + if 'bbox' in init_val: + if isinstance(init_val['bbox'], (dict, OrderedDict)): + init_val['bbox'] = OrderedDict({obj_id: list(init) for obj_id, init in init_val['bbox'].items()}) + else: + init_val['bbox'] = list(init_val['bbox']) + else: + init_data = {0: dict()} # Assume start from frame 0 + + if self.object_ids is not None: + init_data[0]['object_ids'] = self.object_ids + + if self.ground_truth_rect is not None: + if self.multiobj_mode: + assert isinstance(self.ground_truth_rect, (dict, OrderedDict)) + init_data[0]['bbox'] = OrderedDict({obj_id: list(gt[0,:]) for obj_id, gt in self.ground_truth_rect.items()}) + else: + assert self.object_ids is None or len(self.object_ids) == 1 + if isinstance(self.ground_truth_rect, (dict, OrderedDict)): + init_data[0]['bbox'] = list(self.ground_truth_rect[self.object_ids[0]][0, :]) + else: + init_data[0]['bbox'] = list(self.ground_truth_rect[0,:]) + + if self.ground_truth_seg is not None: + init_data[0]['mask'] = self.ground_truth_seg[0] + + return init_data + + def init_info(self): + info = self.frame_info(frame_num=0) + return info + + def frame_info(self, frame_num): + info = self.object_init_data(frame_num=frame_num) + return info + + def init_bbox(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_bbox') + + def init_mask(self, frame_num=0): + return self.object_init_data(frame_num=frame_num).get('init_mask') + + def get_info(self, keys, frame_num=None): + info = dict() + for k in keys: + val = self.get(k, frame_num=frame_num) + if val is not None: + info[k] = val + return info + + def object_init_data(self, frame_num=None) -> dict: + if frame_num is None: + frame_num = 0 + if frame_num not in self.init_data: + return dict() + + init_data = dict() + for key, val in self.init_data[frame_num].items(): + if val is None: + continue + init_data['init_'+key] = val + + if 'init_mask' in init_data and init_data['init_mask'] is not None: + anno = imread_indexed(init_data['init_mask']) + if not self.multiobj_mode and self.object_ids is not None: + assert len(self.object_ids) == 1 + anno = (anno == int(self.object_ids[0])).astype(np.uint8) + init_data['init_mask'] = anno + + if self.object_ids is not None: + init_data['object_ids'] = self.object_ids + init_data['sequence_object_ids'] = self.object_ids + + return init_data + + def target_class(self, frame_num=None): + return self.object_class + + def get(self, name, frame_num=None): + return getattr(self, name)(frame_num) + + def __repr__(self): + return "{self.__class__.__name__} {self.name}, length={len} frames".format(self=self, len=len(self.frames)) + + + +class SequenceList(list): + """List of sequences. Supports the addition operator to concatenate sequence lists.""" + def __getitem__(self, item): + if isinstance(item, str): + for seq in self: + if seq.name == item: + return seq + raise IndexError('Sequence name not in the dataset.') + elif isinstance(item, int): + return super(SequenceList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return SequenceList([super(SequenceList, self).__getitem__(i) for i in item]) + else: + return SequenceList(super(SequenceList, self).__getitem__(item)) + + def __add__(self, other): + return SequenceList(super(SequenceList, self).__add__(other)) + + def copy(self): + return SequenceList(super(SequenceList, self).copy()) \ No newline at end of file diff --git a/pytracking/evaluation/datasets.py b/pytracking/evaluation/datasets.py new file mode 100755 index 0000000..6f39e2e --- /dev/null +++ b/pytracking/evaluation/datasets.py @@ -0,0 +1,61 @@ +from collections import namedtuple +import importlib +from pytracking.evaluation.data import SequenceList + +DatasetInfo = namedtuple('DatasetInfo', ['module', 'class_name', 'kwargs']) + +pt = "pytracking.evaluation.%sdataset" # Useful abbreviations to reduce the clutter + +dataset_dict = dict( + otb=DatasetInfo(module=pt % "otb", class_name="OTBDataset", kwargs=dict()), + nfs=DatasetInfo(module=pt % "nfs", class_name="NFSDataset", kwargs=dict()), + uav=DatasetInfo(module=pt % "uav", class_name="UAVDataset", kwargs=dict()), + tpl=DatasetInfo(module=pt % "tpl", class_name="TPLDataset", kwargs=dict()), + tpl_nootb=DatasetInfo(module=pt % "tpl", class_name="TPLDataset", kwargs=dict(exclude_otb=True)), + vot=DatasetInfo(module=pt % "vot", class_name="VOTDataset", kwargs=dict()), + trackingnet=DatasetInfo(module=pt % "trackingnet", class_name="TrackingNetDataset", kwargs=dict()), + got10k_test=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='test')), + got10k_val=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='val')), + got10k_ltrval=DatasetInfo(module=pt % "got10k", class_name="GOT10KDataset", kwargs=dict(split='ltrval')), + lasot=DatasetInfo(module=pt % "lasot", class_name="LaSOTDataset", kwargs=dict()), + dv2017_val=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", kwargs=dict(version='2017', split='val')), + dv2016_val=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", kwargs=dict(version='2016', split='val')), + dv2017_test_dev=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", + kwargs=dict(version='2017', split='test-dev')), + dv2017_test_chal=DatasetInfo(module="ltr.dataset.davis", class_name="Davis", + kwargs=dict(version='2017', split='test-challenge')), + yt2019_test=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='test')), + yt2019_valid=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='valid')), + yt2019_valid_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='valid', all_frames=True)), + yt2018_valid_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2018', split='valid', all_frames=True)), + yt2018_jjval=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2018', split='jjvalid')), + yt2019_jjval=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='jjvalid', cleanup=['starts'])), + yt2019_jjval_all=DatasetInfo(module="ltr.dataset.youtubevos", class_name="YouTubeVOS", + kwargs=dict(version='2019', split='jjvalid', all_frames=True, cleanup=['starts'])), +) + + +def load_dataset(name: str): + """ Import and load a single dataset.""" + name = name.lower() + dset_info = dataset_dict.get(name) + if dset_info is None: + raise ValueError('Unknown dataset \'%s\'' % name) + + m = importlib.import_module(dset_info.module) + dataset = getattr(m, dset_info.class_name)(**dset_info.kwargs) # Call the constructor + return dataset.get_sequence_list() + + +def get_dataset(*args): + """ Get a single or set of datasets.""" + dset = SequenceList() + for name in args: + dset.extend(load_dataset(name)) + return dset \ No newline at end of file diff --git a/pytracking/evaluation/environment.py b/pytracking/evaluation/environment.py new file mode 100755 index 0000000..171adac --- /dev/null +++ b/pytracking/evaluation/environment.py @@ -0,0 +1,66 @@ +import importlib +import os + + +class EnvSettings: + def __init__(self): + pytracking_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + + self.results_path = '{}/tracking_results/'.format(pytracking_path) + self.segmentation_path = '{}/segmentation_results/'.format(pytracking_path) + self.network_path = '{}/networks/'.format(pytracking_path) + self.result_plot_path = '{}/result_plots/'.format(pytracking_path) + self.otb_path = '' + self.nfs_path = '' + self.uav_path = '' + self.tpl_path = '' + self.vot_path = '' + self.got10k_path = '' + self.lasot_path = '' + self.trackingnet_path = '' + self.davis_dir = '' + self.youtubevos_dir = '' + + self.got_packed_results_path = '' + self.got_reports_path = '' + self.tn_packed_results_path = '' + + +def create_default_local_file(): + comment = {'results_path': 'Where to store tracking results', + 'network_path': 'Where tracking networks are stored.'} + + path = os.path.join(os.path.dirname(__file__), 'local.py') + with open(path, 'w') as f: + settings = EnvSettings() + + f.write('from pytracking.evaluation.environment import EnvSettings\n\n') + f.write('def local_env_settings():\n') + f.write(' settings = EnvSettings()\n\n') + f.write(' # Set your local paths here.\n\n') + + for attr in dir(settings): + comment_str = None + if attr in comment: + comment_str = comment[attr] + attr_val = getattr(settings, attr) + if not attr.startswith('__') and not callable(attr_val): + if comment_str is None: + f.write(' settings.{} = \'{}\'\n'.format(attr, attr_val)) + else: + f.write(' settings.{} = \'{}\' # {}\n'.format(attr, attr_val, comment_str)) + f.write('\n return settings\n\n') + + +def env_settings(): + env_module_name = 'pytracking.evaluation.local' + try: + env_module = importlib.import_module(env_module_name) + return env_module.local_env_settings() + except: + env_file = os.path.join(os.path.dirname(__file__), 'local.py') + + # Create a default file + create_default_local_file() + raise RuntimeError('YOU HAVE NOT SETUP YOUR local.py!!!\n Go to "{}" and set all the paths you need. ' + 'Then try to run again.'.format(env_file)) \ No newline at end of file diff --git a/pytracking/evaluation/got10kdataset.py b/pytracking/evaluation/got10kdataset.py new file mode 100755 index 0000000..43bb3b7 --- /dev/null +++ b/pytracking/evaluation/got10kdataset.py @@ -0,0 +1,56 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text +import os + + +class GOT10KDataset(BaseDataset): + """ GOT-10k dataset. + + Publication: + GOT-10k: A Large High-Diversity Benchmark for Generic Object Tracking in the Wild + Lianghua Huang, Xin Zhao, and Kaiqi Huang + arXiv:1810.11981, 2018 + https://arxiv.org/pdf/1810.11981.pdf + + Download dataset from http://got-10k.aitestunion.com/downloads + """ + def __init__(self, split): + super().__init__() + # Split can be test, val, or ltrval (a validation split consisting of videos from the official train set) + if split == 'test' or split == 'val': + self.base_path = os.path.join(self.env_settings.got10k_path, split) + else: + self.base_path = os.path.join(self.env_settings.got10k_path, 'train') + + self.sequence_list = self._get_sequence_list(split) + self.split = split + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + anno_path = '{}/{}/groundtruth.txt'.format(self.base_path, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + frames_path = '{}/{}'.format(self.base_path, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'got10k', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self, split): + with open('{}/list.txt'.format(self.base_path)) as f: + sequence_list = f.read().splitlines() + + if split == 'ltrval': + with open('{}/got10k_val_split.txt'.format(self.env_settings.dataspec_path)) as f: + seq_ids = f.read().splitlines() + + sequence_list = [sequence_list[int(x)] for x in seq_ids] + return sequence_list diff --git a/pytracking/evaluation/lasotdataset.py b/pytracking/evaluation/lasotdataset.py new file mode 100755 index 0000000..fdefcbf --- /dev/null +++ b/pytracking/evaluation/lasotdataset.py @@ -0,0 +1,342 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class LaSOTDataset(BaseDataset): + """ + LaSOT test set consisting of 280 videos (see Protocol-II in the LaSOT paper) + + Publication: + LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking + Heng Fan, Liting Lin, Fan Yang, Peng Chu, Ge Deng, Sijia Yu, Hexin Bai, Yong Xu, Chunyuan Liao and Haibin Ling + CVPR, 2019 + https://arxiv.org/pdf/1809.07845.pdf + + Download the dataset from https://cis.temple.edu/lasot/download.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.lasot_path + self.sequence_list = self._get_sequence_list() + self.clean_list = self.clean_seq_list() + + def clean_seq_list(self): + clean_lst = [] + for i in range(len(self.sequence_list)): + cls, _ = self.sequence_list[i].split('-') + clean_lst.append(cls) + return clean_lst + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + class_name = sequence_name.split('-')[0] + anno_path = '{}/{}/{}/groundtruth.txt'.format(self.base_path, class_name, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64) + + occlusion_label_path = '{}/{}/{}/full_occlusion.txt'.format(self.base_path, class_name, sequence_name) + + # NOTE: pandas backed seems super super slow for loading occlusion/oov masks + full_occlusion = load_text(str(occlusion_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + out_of_view_label_path = '{}/{}/{}/out_of_view.txt'.format(self.base_path, class_name, sequence_name) + out_of_view = load_text(str(out_of_view_label_path), delimiter=',', dtype=np.float64, backend='numpy') + + target_visible = np.logical_and(full_occlusion == 0, out_of_view == 0) + + frames_path = '{}/{}/{}/img'.format(self.base_path, class_name, sequence_name) + + frames_list = ['{}/{:08d}.jpg'.format(frames_path, frame_number) for frame_number in range(1, ground_truth_rect.shape[0] + 1)] + + target_class = class_name + return Sequence(sequence_name, frames_list, 'lasot', ground_truth_rect.reshape(-1, 4), + object_class=target_class, target_visible=target_visible) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list = ['airplane-1', + 'airplane-9', + 'airplane-13', + 'airplane-15', + 'basketball-1', + 'basketball-6', + 'basketball-7', + 'basketball-11', + 'bear-2', + 'bear-4', + 'bear-6', + 'bear-17', + 'bicycle-2', + 'bicycle-7', + 'bicycle-9', + 'bicycle-18', + 'bird-2', + 'bird-3', + 'bird-15', + 'bird-17', + 'boat-3', + 'boat-4', + 'boat-12', + 'boat-17', + 'book-3', + 'book-10', + 'book-11', + 'book-19', + 'bottle-1', + 'bottle-12', + 'bottle-14', + 'bottle-18', + 'bus-2', + 'bus-5', + 'bus-17', + 'bus-19', + 'car-2', + 'car-6', + 'car-9', + 'car-17', + 'cat-1', + 'cat-3', + 'cat-18', + 'cat-20', + 'cattle-2', + 'cattle-7', + 'cattle-12', + 'cattle-13', + 'spider-14', + 'spider-16', + 'spider-18', + 'spider-20', + 'coin-3', + 'coin-6', + 'coin-7', + 'coin-18', + 'crab-3', + 'crab-6', + 'crab-12', + 'crab-18', + 'surfboard-12', + 'surfboard-4', + 'surfboard-5', + 'surfboard-8', + 'cup-1', + 'cup-4', + 'cup-7', + 'cup-17', + 'deer-4', + 'deer-8', + 'deer-10', + 'deer-14', + 'dog-1', + 'dog-7', + 'dog-15', + 'dog-19', + 'guitar-3', + 'guitar-8', + 'guitar-10', + 'guitar-16', + 'person-1', + 'person-5', + 'person-10', + 'person-12', + 'pig-2', + 'pig-10', + 'pig-13', + 'pig-18', + 'rubicCube-1', + 'rubicCube-6', + 'rubicCube-14', + 'rubicCube-19', + 'swing-10', + 'swing-14', + 'swing-17', + 'swing-20', + 'drone-13', + 'drone-15', + 'drone-2', + 'drone-7', + 'pool-12', + 'pool-15', + 'pool-3', + 'pool-7', + 'rabbit-10', + 'rabbit-13', + 'rabbit-17', + 'rabbit-19', + 'racing-10', + 'racing-15', + 'racing-16', + 'racing-20', + 'robot-1', + 'robot-19', + 'robot-5', + 'robot-8', + 'sepia-13', + 'sepia-16', + 'sepia-6', + 'sepia-8', + 'sheep-3', + 'sheep-5', + 'sheep-7', + 'sheep-9', + 'skateboard-16', + 'skateboard-19', + 'skateboard-3', + 'skateboard-8', + 'tank-14', + 'tank-16', + 'tank-6', + 'tank-9', + 'tiger-12', + 'tiger-18', + 'tiger-4', + 'tiger-6', + 'train-1', + 'train-11', + 'train-20', + 'train-7', + 'truck-16', + 'truck-3', + 'truck-6', + 'truck-7', + 'turtle-16', + 'turtle-5', + 'turtle-8', + 'turtle-9', + 'umbrella-17', + 'umbrella-19', + 'umbrella-2', + 'umbrella-9', + 'yoyo-15', + 'yoyo-17', + 'yoyo-19', + 'yoyo-7', + 'zebra-10', + 'zebra-14', + 'zebra-16', + 'zebra-17', + 'elephant-1', + 'elephant-12', + 'elephant-16', + 'elephant-18', + 'goldfish-3', + 'goldfish-7', + 'goldfish-8', + 'goldfish-10', + 'hat-1', + 'hat-2', + 'hat-5', + 'hat-18', + 'kite-4', + 'kite-6', + 'kite-10', + 'kite-15', + 'motorcycle-1', + 'motorcycle-3', + 'motorcycle-9', + 'motorcycle-18', + 'mouse-1', + 'mouse-8', + 'mouse-9', + 'mouse-17', + 'flag-3', + 'flag-9', + 'flag-5', + 'flag-2', + 'frog-3', + 'frog-4', + 'frog-20', + 'frog-9', + 'gametarget-1', + 'gametarget-2', + 'gametarget-7', + 'gametarget-13', + 'hand-2', + 'hand-3', + 'hand-9', + 'hand-16', + 'helmet-5', + 'helmet-11', + 'helmet-19', + 'helmet-13', + 'licenseplate-6', + 'licenseplate-12', + 'licenseplate-13', + 'licenseplate-15', + 'electricfan-1', + 'electricfan-10', + 'electricfan-18', + 'electricfan-20', + 'chameleon-3', + 'chameleon-6', + 'chameleon-11', + 'chameleon-20', + 'crocodile-3', + 'crocodile-4', + 'crocodile-10', + 'crocodile-14', + 'gecko-1', + 'gecko-5', + 'gecko-16', + 'gecko-19', + 'fox-2', + 'fox-3', + 'fox-5', + 'fox-20', + 'giraffe-2', + 'giraffe-10', + 'giraffe-13', + 'giraffe-15', + 'gorilla-4', + 'gorilla-6', + 'gorilla-9', + 'gorilla-13', + 'hippo-1', + 'hippo-7', + 'hippo-9', + 'hippo-20', + 'horse-1', + 'horse-4', + 'horse-12', + 'horse-15', + 'kangaroo-2', + 'kangaroo-5', + 'kangaroo-11', + 'kangaroo-14', + 'leopard-1', + 'leopard-7', + 'leopard-16', + 'leopard-20', + 'lion-1', + 'lion-5', + 'lion-12', + 'lion-20', + 'lizard-1', + 'lizard-3', + 'lizard-6', + 'lizard-13', + 'microphone-2', + 'microphone-6', + 'microphone-14', + 'microphone-16', + 'monkey-3', + 'monkey-4', + 'monkey-9', + 'monkey-17', + 'shark-2', + 'shark-3', + 'shark-5', + 'shark-6', + 'squirrel-8', + 'squirrel-11', + 'squirrel-13', + 'squirrel-19', + 'volleyball-1', + 'volleyball-13', + 'volleyball-18', + 'volleyball-19'] + return sequence_list diff --git a/pytracking/evaluation/local.py b/pytracking/evaluation/local.py new file mode 100755 index 0000000..c19fcf8 --- /dev/null +++ b/pytracking/evaluation/local.py @@ -0,0 +1,27 @@ +from pytracking.evaluation.environment import EnvSettings + +def local_env_settings(): + settings = EnvSettings() + + # Set your local paths here. + + settings.davis_dir = '' + settings.got10k_path = '' + settings.got_packed_results_path = '' + settings.got_reports_path = '' + settings.lasot_path = '' + settings.network_path = '/media/dkn/Data2/LTMU_research/PrDiMP_MU/pytracking/networks/' # Where tracking networks are stored. + settings.nfs_path = '' + settings.otb_path = '' + settings.result_plot_path = '/media/dkn/Data2/LTMU_research/PrDiMP_MU/pytracking/result_plots/' + settings.results_path = '/media/dkn/Data2/LTMU_research/PrDiMP_MU/pytracking/tracking_results/' # Where to store tracking results + settings.segmentation_path = '/media/dkn/Data2/LTMU_research/PrDiMP_MU/pytracking/segmentation_results/' + settings.tn_packed_results_path = '' + settings.tpl_path = '' + settings.trackingnet_path = '' + settings.uav_path = '' + settings.vot_path = '' + settings.youtubevos_dir = '' + + return settings + diff --git a/pytracking/evaluation/mobifacedataset.py b/pytracking/evaluation/mobifacedataset.py new file mode 100755 index 0000000..486fff6 --- /dev/null +++ b/pytracking/evaluation/mobifacedataset.py @@ -0,0 +1,68 @@ +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +import glob +import numpy as np +import os.path as osp +from collections import OrderedDict +import pandas as pd + + +class MobifaceDataset(BaseDataset): + """ Mobiface dataset. + Publication: + MobiFace: A Novel Dataset for Mobile Face Tracking in the Wild + Yiming Lin, Shiyang Cheng, Jie Shen, Maja Pantic + arXiv:1805.09749, 2018 + https://arxiv.org/pdf/1805.09749v2 + + Download dataset from https://mobiface.github.io/ + """ + def __init__(self, split): + """ + args: + split - Split to use. Can be i) 'train': official training set, ii) 'test': official test set, iii) 'all': whole dataset. + """ + super().__init__() + self.base_path = self.env_settings.mobiface_path + self.sequence_list = self._get_sequence_list(split) + self.split = split + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _get_sequence_list(self, split): + + self.train_meta_fn = osp.join(self.base_path, 'train.meta.csv') + self.test_meta_fn = osp.join(self.base_path, 'test.meta.csv') + self.train_meta = pd.read_csv(self.train_meta_fn,index_col=0).transpose().to_dict() + self.test_meta = pd.read_csv(self.test_meta_fn,index_col=0).transpose().to_dict() + if split == 'train': + self.meta = self.train_meta + elif split == 'test': + self.meta = self.test_meta + else: + self.meta = {**self.train_meta, **self.test_meta} # In Python 3.5 or greater + self.meta = OrderedDict(sorted(self.meta.items(), key=lambda t: t[0])) + self.anno_files = [] + for k,v in self.meta.items(): + if k in self.train_meta.keys(): + self.anno_files.append(osp.abspath(osp.join(self.base_path,'train', k+'.annot.csv'))) + else: + self.anno_files.append(osp.abspath(osp.join(self.base_path,'test', k+'.annot.csv'))) + self.seq_names = sorted(list(self.meta.keys())) + self.seq_dirs = [fn[:-len('.annot.csv')] for fn in self.anno_files] + return self.seq_names + + def _construct_sequence(self, sequence_name): + index = self.seq_names.index(sequence_name) + img_files = sorted(glob.glob(self.seq_dirs[index]+'/*.jpg')) + if len(img_files) == 0: + img_files = sorted(glob.glob(self.seq_dirs[index]+'.png')) + with open(self.anno_files[index], 'r') as f: + anno = np.loadtxt(f, delimiter=',', skiprows=1, dtype=int) + anno = anno[:,1:] + assert anno.shape[1] == 4 + + return Sequence(sequence_name, img_files, anno.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) diff --git a/pytracking/evaluation/multi_object_wrapper.py b/pytracking/evaluation/multi_object_wrapper.py new file mode 100755 index 0000000..885cd9e --- /dev/null +++ b/pytracking/evaluation/multi_object_wrapper.py @@ -0,0 +1,187 @@ +import numpy as np +from collections import OrderedDict +import time +import copy + + +class MultiObjectWrapper: + def __init__(self, base_tracker_class, params, visdom=None, fast_load=False): + self.base_tracker_class = base_tracker_class + self.params = params + self.visdom = visdom + + self.initialized_ids = [] + self.trackers = OrderedDict() + + self.fast_load = fast_load + if self.fast_load: + self.tracker_copy = self.base_tracker_class(self.params) + if hasattr(self.tracker_copy, 'initialize_features'): + self.tracker_copy.initialize_features() + + def create_tracker(self): + tracker = None + if self.fast_load: + try: + tracker = copy.deepcopy(self.tracker_copy) + except: + pass + if tracker is None: + tracker = self.base_tracker_class(self.params) + tracker.visdom = self.visdom + return tracker + + def _split_info(self, info): + info_split = OrderedDict() + init_other = OrderedDict() # Init other contains init info for all other objects + for obj_id in info['init_object_ids']: + info_split[obj_id] = dict() + init_other[obj_id] = dict() + info_split[obj_id]['object_ids'] = [obj_id] + info_split[obj_id]['sequence_object_ids'] = info['sequence_object_ids'] + if 'init_bbox' in info: + info_split[obj_id]['init_bbox'] = info['init_bbox'][obj_id] + init_other[obj_id]['init_bbox'] = info['init_bbox'][obj_id] + if 'init_mask' in info: + info_split[obj_id]['init_mask'] = (info['init_mask'] == int(obj_id)).astype(np.uint8) + init_other[obj_id]['init_mask'] = info_split[obj_id]['init_mask'] + for obj_info in info_split.values(): + obj_info['init_other'] = init_other + return info_split + + def _set_defaults(self, tracker_out: dict, defaults=None): + defaults = {} if defaults is None else defaults + + for key, val in defaults.items(): + if tracker_out.get(key) is None: + tracker_out[key] = val + + return tracker_out + + def default_merge(self, out_all): + out_merged = OrderedDict() + + out_first = list(out_all.values())[0] + out_types = out_first.keys() + + # Merge segmentation mask + if 'segmentation' in out_types and out_first['segmentation'] is not None: + # Stack all masks + # If a tracker outputs soft segmentation mask, use that. Else use the binary segmentation + segmentation_maps = [out.get('segmentation_soft', out['segmentation']) for out in out_all.values()] + segmentation_maps = np.stack(segmentation_maps) + + obj_ids = np.array([0, *map(int, out_all.keys())], dtype=np.uint8) + segm_threshold = getattr(self.params, 'segmentation_threshold', 0.5) + merged_segmentation = obj_ids[np.where(segmentation_maps.max(axis=0) > segm_threshold, + segmentation_maps.argmax(axis=0) + 1, 0)] + + out_merged['segmentation'] = merged_segmentation + + # Merge other fields + for key in out_types: + if key == 'segmentation': + pass + else: + out_merged[key] = {obj_id: out[key] for obj_id, out in out_all.items()} + + return out_merged + + def merge_outputs(self, out_all): + if hasattr(self.base_tracker_class, 'merge_results'): + out_merged = self.base_tracker_class.merge_results(out_all) + else: + out_merged = self.default_merge(out_all) + + return out_merged + + def initialize(self, image, info: dict) -> dict: + self.initialized_ids = [] + self.trackers = OrderedDict() + + if len(info['init_object_ids']) == 0: + return None + + object_ids = info['object_ids'] + + init_info_split = self._split_info(info) + self.trackers = OrderedDict({obj_id: self.create_tracker() for obj_id in object_ids}) + + out_all = OrderedDict() + # Run individual trackers for each object + for obj_id in info['init_object_ids']: + start_time = time.time() + out = self.trackers[obj_id].initialize(image, init_info_split[obj_id]) + if out is None: + out = {} + + init_default = {'target_bbox': init_info_split[obj_id].get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info_split[obj_id].get('init_mask')} + + out = self._set_defaults(out, init_default) + out_all[obj_id] = out + + # Merge results + out_merged = self.merge_outputs(out_all) + + self.initialized_ids = info['init_object_ids'].copy() + return out_merged + + def track(self, image, info: dict = None) -> dict: + if info is None: + info = {} + + prev_output = info.get('previous_output', OrderedDict()) + + if info.get('init_object_ids', False): + init_info_split = self._split_info(info) + for obj_init_info in init_info_split.values(): + obj_init_info['previous_output'] = prev_output + + info['init_other'] = list(init_info_split.values())[0]['init_other'] + + out_all = OrderedDict() + for obj_id in self.initialized_ids: + start_time = time.time() + + out = self.trackers[obj_id].track(image, info) + + default = {'time': time.time() - start_time} + out = self._set_defaults(out, default) + out_all[obj_id] = out + + # Initialize new + if info.get('init_object_ids', False): + for obj_id in info['init_object_ids']: + if not obj_id in self.trackers: + self.trackers[obj_id] = self.create_tracker() + + start_time = time.time() + out = self.trackers[obj_id].initialize(image, init_info_split[obj_id]) + if out is None: + out = {} + + init_default = {'target_bbox': init_info_split[obj_id].get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info_split[obj_id].get('init_mask')} + + out = self._set_defaults(out, init_default) + out_all[obj_id] = out + + self.initialized_ids.extend(info['init_object_ids']) + + # Merge results + out_merged = self.merge_outputs(out_all) + + return out_merged + + def visdom_draw_tracking(self, image, box, segmentation): + if isinstance(box, (OrderedDict, dict)): + box = [v for k, v in box.items()] + else: + box = (box,) + if segmentation is None: + self.visdom.register((image, *box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, *box, segmentation), 'Tracking', 1, 'Tracking') diff --git a/pytracking/evaluation/nfsdataset.py b/pytracking/evaluation/nfsdataset.py new file mode 100755 index 0000000..4733e7a --- /dev/null +++ b/pytracking/evaluation/nfsdataset.py @@ -0,0 +1,153 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class NFSDataset(BaseDataset): + """ NFS dataset. + + Publication: + Need for Speed: A Benchmark for Higher Frame Rate Object Tracking + H. Kiani Galoogahi, A. Fagg, C. Huang, D. Ramanan, and S.Lucey + ICCV, 2017 + http://openaccess.thecvf.com/content_ICCV_2017/papers/Galoogahi_Need_for_Speed_ICCV_2017_paper.pdf + + Download the dataset from http://ci2cv.net/nfs/index.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.nfs_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter='\t', dtype=np.float64) + + return Sequence(sequence_info['name'], frames, 'nfs', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "nfs_Gymnastics", "path": "sequences/Gymnastics", "startFrame": 1, "endFrame": 368, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Gymnastics.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_MachLoop_jet", "path": "sequences/MachLoop_jet", "startFrame": 1, "endFrame": 99, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_MachLoop_jet.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_Skiing_red", "path": "sequences/Skiing_red", "startFrame": 1, "endFrame": 69, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Skiing_red.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_Skydiving", "path": "sequences/Skydiving", "startFrame": 1, "endFrame": 196, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_Skydiving.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_airboard_1", "path": "sequences/airboard_1", "startFrame": 1, "endFrame": 425, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airboard_1.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_airplane_landing", "path": "sequences/airplane_landing", "startFrame": 1, "endFrame": 81, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airplane_landing.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_airtable_3", "path": "sequences/airtable_3", "startFrame": 1, "endFrame": 482, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_airtable_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_1", "path": "sequences/basketball_1", "startFrame": 1, "endFrame": 282, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_1.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_2", "path": "sequences/basketball_2", "startFrame": 1, "endFrame": 102, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_3", "path": "sequences/basketball_3", "startFrame": 1, "endFrame": 421, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_6", "path": "sequences/basketball_6", "startFrame": 1, "endFrame": 224, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_basketball_7", "path": "sequences/basketball_7", "startFrame": 1, "endFrame": 240, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_7.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_basketball_player", "path": "sequences/basketball_player", "startFrame": 1, "endFrame": 369, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_player.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_basketball_player_2", "path": "sequences/basketball_player_2", "startFrame": 1, "endFrame": 437, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_basketball_player_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_beach_flipback_person", "path": "sequences/beach_flipback_person", "startFrame": 1, "endFrame": 61, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_beach_flipback_person.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_bee", "path": "sequences/bee", "startFrame": 1, "endFrame": 45, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bee.txt", "object_class": "insect", 'occlusion': False}, + {"name": "nfs_biker_acrobat", "path": "sequences/biker_acrobat", "startFrame": 1, "endFrame": 128, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_acrobat.txt", "object_class": "bicycle", 'occlusion': False}, + {"name": "nfs_biker_all_1", "path": "sequences/biker_all_1", "startFrame": 1, "endFrame": 113, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_all_1.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_biker_head_2", "path": "sequences/biker_head_2", "startFrame": 1, "endFrame": 132, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_head_2.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_biker_head_3", "path": "sequences/biker_head_3", "startFrame": 1, "endFrame": 254, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_head_3.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_biker_upper_body", "path": "sequences/biker_upper_body", "startFrame": 1, "endFrame": 194, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_upper_body.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_biker_whole_body", "path": "sequences/biker_whole_body", "startFrame": 1, "endFrame": 572, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_biker_whole_body.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_billiard_2", "path": "sequences/billiard_2", "startFrame": 1, "endFrame": 604, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_3", "path": "sequences/billiard_3", "startFrame": 1, "endFrame": 698, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_6", "path": "sequences/billiard_6", "startFrame": 1, "endFrame": 771, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_7", "path": "sequences/billiard_7", "startFrame": 1, "endFrame": 724, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_7.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_billiard_8", "path": "sequences/billiard_8", "startFrame": 1, "endFrame": 778, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_billiard_8.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_bird_2", "path": "sequences/bird_2", "startFrame": 1, "endFrame": 476, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bird_2.txt", "object_class": "bird", 'occlusion': False}, + {"name": "nfs_book", "path": "sequences/book", "startFrame": 1, "endFrame": 288, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_book.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_bottle", "path": "sequences/bottle", "startFrame": 1, "endFrame": 2103, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bottle.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_bowling_1", "path": "sequences/bowling_1", "startFrame": 1, "endFrame": 303, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_1.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_2", "path": "sequences/bowling_2", "startFrame": 1, "endFrame": 710, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_2.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_3", "path": "sequences/bowling_3", "startFrame": 1, "endFrame": 271, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_3.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bowling_6", "path": "sequences/bowling_6", "startFrame": 1, "endFrame": 260, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_6.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_bowling_ball", "path": "sequences/bowling_ball", "startFrame": 1, "endFrame": 275, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bowling_ball.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_bunny", "path": "sequences/bunny", "startFrame": 1, "endFrame": 705, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_bunny.txt", "object_class": "mammal", 'occlusion': False}, + {"name": "nfs_car", "path": "sequences/car", "startFrame": 1, "endFrame": 2020, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car.txt", "object_class": "car", 'occlusion': True}, + {"name": "nfs_car_camaro", "path": "sequences/car_camaro", "startFrame": 1, "endFrame": 36, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_camaro.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_drifting", "path": "sequences/car_drifting", "startFrame": 1, "endFrame": 173, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_drifting.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_jumping", "path": "sequences/car_jumping", "startFrame": 1, "endFrame": 22, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_jumping.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_rc_rolling", "path": "sequences/car_rc_rolling", "startFrame": 1, "endFrame": 62, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_rc_rolling.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_rc_rotating", "path": "sequences/car_rc_rotating", "startFrame": 1, "endFrame": 80, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_rc_rotating.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_side", "path": "sequences/car_side", "startFrame": 1, "endFrame": 108, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_side.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_car_white", "path": "sequences/car_white", "startFrame": 1, "endFrame": 2063, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_car_white.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_cheetah", "path": "sequences/cheetah", "startFrame": 1, "endFrame": 167, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cheetah.txt", "object_class": "mammal", 'occlusion': True}, + {"name": "nfs_cup", "path": "sequences/cup", "startFrame": 1, "endFrame": 1281, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cup.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_cup_2", "path": "sequences/cup_2", "startFrame": 1, "endFrame": 182, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_cup_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_dog", "path": "sequences/dog", "startFrame": 1, "endFrame": 1030, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dog_1", "path": "sequences/dog_1", "startFrame": 1, "endFrame": 168, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_1.txt", "object_class": "dog", 'occlusion': False}, + {"name": "nfs_dog_2", "path": "sequences/dog_2", "startFrame": 1, "endFrame": 594, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_2.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dog_3", "path": "sequences/dog_3", "startFrame": 1, "endFrame": 200, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dog_3.txt", "object_class": "dog", 'occlusion': False}, + {"name": "nfs_dogs", "path": "sequences/dogs", "startFrame": 1, "endFrame": 198, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dogs.txt", "object_class": "dog", 'occlusion': True}, + {"name": "nfs_dollar", "path": "sequences/dollar", "startFrame": 1, "endFrame": 1426, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_dollar.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_drone", "path": "sequences/drone", "startFrame": 1, "endFrame": 70, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_drone.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_ducks_lake", "path": "sequences/ducks_lake", "startFrame": 1, "endFrame": 107, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_ducks_lake.txt", "object_class": "bird", 'occlusion': False}, + {"name": "nfs_exit", "path": "sequences/exit", "startFrame": 1, "endFrame": 359, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_exit.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_first", "path": "sequences/first", "startFrame": 1, "endFrame": 435, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_first.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_flower", "path": "sequences/flower", "startFrame": 1, "endFrame": 448, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_flower.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_footbal_skill", "path": "sequences/footbal_skill", "startFrame": 1, "endFrame": 131, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_footbal_skill.txt", "object_class": "ball", 'occlusion': True}, + {"name": "nfs_helicopter", "path": "sequences/helicopter", "startFrame": 1, "endFrame": 310, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_helicopter.txt", "object_class": "aircraft", 'occlusion': False}, + {"name": "nfs_horse_jumping", "path": "sequences/horse_jumping", "startFrame": 1, "endFrame": 117, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_horse_jumping.txt", "object_class": "horse", 'occlusion': True}, + {"name": "nfs_horse_running", "path": "sequences/horse_running", "startFrame": 1, "endFrame": 139, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_horse_running.txt", "object_class": "horse", 'occlusion': False}, + {"name": "nfs_iceskating_6", "path": "sequences/iceskating_6", "startFrame": 1, "endFrame": 603, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_iceskating_6.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_jellyfish_5", "path": "sequences/jellyfish_5", "startFrame": 1, "endFrame": 746, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_jellyfish_5.txt", "object_class": "invertebrate", 'occlusion': False}, + {"name": "nfs_kid_swing", "path": "sequences/kid_swing", "startFrame": 1, "endFrame": 169, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_kid_swing.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_motorcross", "path": "sequences/motorcross", "startFrame": 1, "endFrame": 39, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_motorcross.txt", "object_class": "vehicle", 'occlusion': True}, + {"name": "nfs_motorcross_kawasaki", "path": "sequences/motorcross_kawasaki", "startFrame": 1, "endFrame": 65, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_motorcross_kawasaki.txt", "object_class": "vehicle", 'occlusion': False}, + {"name": "nfs_parkour", "path": "sequences/parkour", "startFrame": 1, "endFrame": 58, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_parkour.txt", "object_class": "person head", 'occlusion': False}, + {"name": "nfs_person_scooter", "path": "sequences/person_scooter", "startFrame": 1, "endFrame": 413, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_person_scooter.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_pingpong_2", "path": "sequences/pingpong_2", "startFrame": 1, "endFrame": 1277, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_pingpong_7", "path": "sequences/pingpong_7", "startFrame": 1, "endFrame": 1290, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_7.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_pingpong_8", "path": "sequences/pingpong_8", "startFrame": 1, "endFrame": 296, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_pingpong_8.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_purse", "path": "sequences/purse", "startFrame": 1, "endFrame": 968, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_purse.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_rubber", "path": "sequences/rubber", "startFrame": 1, "endFrame": 1328, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_rubber.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_running", "path": "sequences/running", "startFrame": 1, "endFrame": 677, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_running_100_m", "path": "sequences/running_100_m", "startFrame": 1, "endFrame": 313, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_100_m.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_running_100_m_2", "path": "sequences/running_100_m_2", "startFrame": 1, "endFrame": 337, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_100_m_2.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_running_2", "path": "sequences/running_2", "startFrame": 1, "endFrame": 363, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_running_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_shuffleboard_1", "path": "sequences/shuffleboard_1", "startFrame": 1, "endFrame": 42, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_1.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_2", "path": "sequences/shuffleboard_2", "startFrame": 1, "endFrame": 41, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_4", "path": "sequences/shuffleboard_4", "startFrame": 1, "endFrame": 62, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_4.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_5", "path": "sequences/shuffleboard_5", "startFrame": 1, "endFrame": 32, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_5.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffleboard_6", "path": "sequences/shuffleboard_6", "startFrame": 1, "endFrame": 52, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffleboard_6.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_2", "path": "sequences/shuffletable_2", "startFrame": 1, "endFrame": 372, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_2.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_3", "path": "sequences/shuffletable_3", "startFrame": 1, "endFrame": 368, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_3.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_shuffletable_4", "path": "sequences/shuffletable_4", "startFrame": 1, "endFrame": 101, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_shuffletable_4.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_ski_long", "path": "sequences/ski_long", "startFrame": 1, "endFrame": 274, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_ski_long.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_soccer_ball", "path": "sequences/soccer_ball", "startFrame": 1, "endFrame": 163, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_ball_2", "path": "sequences/soccer_ball_2", "startFrame": 1, "endFrame": 1934, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball_2.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_ball_3", "path": "sequences/soccer_ball_3", "startFrame": 1, "endFrame": 1381, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_ball_3.txt", "object_class": "ball", 'occlusion': False}, + {"name": "nfs_soccer_player_2", "path": "sequences/soccer_player_2", "startFrame": 1, "endFrame": 475, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_player_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_soccer_player_3", "path": "sequences/soccer_player_3", "startFrame": 1, "endFrame": 319, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_soccer_player_3.txt", "object_class": "person", 'occlusion': True}, + {"name": "nfs_stop_sign", "path": "sequences/stop_sign", "startFrame": 1, "endFrame": 302, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_stop_sign.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_suv", "path": "sequences/suv", "startFrame": 1, "endFrame": 2584, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_suv.txt", "object_class": "car", 'occlusion': False}, + {"name": "nfs_tiger", "path": "sequences/tiger", "startFrame": 1, "endFrame": 1556, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_tiger.txt", "object_class": "mammal", 'occlusion': False}, + {"name": "nfs_walking", "path": "sequences/walking", "startFrame": 1, "endFrame": 555, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_walking.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_walking_3", "path": "sequences/walking_3", "startFrame": 1, "endFrame": 1427, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_walking_3.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_water_ski_2", "path": "sequences/water_ski_2", "startFrame": 1, "endFrame": 47, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_water_ski_2.txt", "object_class": "person", 'occlusion': False}, + {"name": "nfs_yoyo", "path": "sequences/yoyo", "startFrame": 1, "endFrame": 67, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_yoyo.txt", "object_class": "other", 'occlusion': False}, + {"name": "nfs_zebra_fish", "path": "sequences/zebra_fish", "startFrame": 1, "endFrame": 671, "nz": 5, "ext": "jpg", "anno_path": "anno/nfs_zebra_fish.txt", "object_class": "fish", 'occlusion': False}, + ] + + return sequence_info_list diff --git a/pytracking/evaluation/otbdataset.py b/pytracking/evaluation/otbdataset.py new file mode 100755 index 0000000..2230c57 --- /dev/null +++ b/pytracking/evaluation/otbdataset.py @@ -0,0 +1,254 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class OTBDataset(BaseDataset): + """ OTB-2015 dataset + + Publication: + Object Tracking Benchmark + Wu, Yi, Jongwoo Lim, and Ming-hsuan Yan + TPAMI, 2015 + http://faculty.ucmerced.edu/mhyang/papers/pami15_tracking_benchmark.pdf + + Download the dataset from http://cvlab.hanyang.ac.kr/tracker_benchmark/index.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.otb_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + # NOTE: OTB has some weird annos which panda cannot handle + ground_truth_rect = load_text(str(anno_path), delimiter=(',', None), dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'otb', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "Basketball", "path": "Basketball/img", "startFrame": 1, "endFrame": 725, "nz": 4, "ext": "jpg", "anno_path": "Basketball/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Biker", "path": "Biker/img", "startFrame": 1, "endFrame": 142, "nz": 4, "ext": "jpg", "anno_path": "Biker/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Bird1", "path": "Bird1/img", "startFrame": 1, "endFrame": 408, "nz": 4, "ext": "jpg", "anno_path": "Bird1/groundtruth_rect.txt", + "object_class": "bird"}, + {"name": "Bird2", "path": "Bird2/img", "startFrame": 1, "endFrame": 99, "nz": 4, "ext": "jpg", "anno_path": "Bird2/groundtruth_rect.txt", + "object_class": "bird"}, + {"name": "BlurBody", "path": "BlurBody/img", "startFrame": 1, "endFrame": 334, "nz": 4, "ext": "jpg", "anno_path": "BlurBody/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "BlurCar1", "path": "BlurCar1/img", "startFrame": 247, "endFrame": 988, "nz": 4, "ext": "jpg", "anno_path": "BlurCar1/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar2", "path": "BlurCar2/img", "startFrame": 1, "endFrame": 585, "nz": 4, "ext": "jpg", "anno_path": "BlurCar2/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar3", "path": "BlurCar3/img", "startFrame": 3, "endFrame": 359, "nz": 4, "ext": "jpg", "anno_path": "BlurCar3/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurCar4", "path": "BlurCar4/img", "startFrame": 18, "endFrame": 397, "nz": 4, "ext": "jpg", "anno_path": "BlurCar4/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "BlurFace", "path": "BlurFace/img", "startFrame": 1, "endFrame": 493, "nz": 4, "ext": "jpg", "anno_path": "BlurFace/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "BlurOwl", "path": "BlurOwl/img", "startFrame": 1, "endFrame": 631, "nz": 4, "ext": "jpg", "anno_path": "BlurOwl/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Board", "path": "Board/img", "startFrame": 1, "endFrame": 698, "nz": 5, "ext": "jpg", "anno_path": "Board/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Bolt", "path": "Bolt/img", "startFrame": 1, "endFrame": 350, "nz": 4, "ext": "jpg", "anno_path": "Bolt/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Bolt2", "path": "Bolt2/img", "startFrame": 1, "endFrame": 293, "nz": 4, "ext": "jpg", "anno_path": "Bolt2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Box", "path": "Box/img", "startFrame": 1, "endFrame": 1161, "nz": 4, "ext": "jpg", "anno_path": "Box/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Boy", "path": "Boy/img", "startFrame": 1, "endFrame": 602, "nz": 4, "ext": "jpg", "anno_path": "Boy/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Car1", "path": "Car1/img", "startFrame": 1, "endFrame": 1020, "nz": 4, "ext": "jpg", "anno_path": "Car1/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car2", "path": "Car2/img", "startFrame": 1, "endFrame": 913, "nz": 4, "ext": "jpg", "anno_path": "Car2/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car24", "path": "Car24/img", "startFrame": 1, "endFrame": 3059, "nz": 4, "ext": "jpg", "anno_path": "Car24/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Car4", "path": "Car4/img", "startFrame": 1, "endFrame": 659, "nz": 4, "ext": "jpg", "anno_path": "Car4/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "CarDark", "path": "CarDark/img", "startFrame": 1, "endFrame": 393, "nz": 4, "ext": "jpg", "anno_path": "CarDark/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "CarScale", "path": "CarScale/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", "anno_path": "CarScale/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "ClifBar", "path": "ClifBar/img", "startFrame": 1, "endFrame": 472, "nz": 4, "ext": "jpg", "anno_path": "ClifBar/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Coke", "path": "Coke/img", "startFrame": 1, "endFrame": 291, "nz": 4, "ext": "jpg", "anno_path": "Coke/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Couple", "path": "Couple/img", "startFrame": 1, "endFrame": 140, "nz": 4, "ext": "jpg", "anno_path": "Couple/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Coupon", "path": "Coupon/img", "startFrame": 1, "endFrame": 327, "nz": 4, "ext": "jpg", "anno_path": "Coupon/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Crossing", "path": "Crossing/img", "startFrame": 1, "endFrame": 120, "nz": 4, "ext": "jpg", "anno_path": "Crossing/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Crowds", "path": "Crowds/img", "startFrame": 1, "endFrame": 347, "nz": 4, "ext": "jpg", "anno_path": "Crowds/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dancer", "path": "Dancer/img", "startFrame": 1, "endFrame": 225, "nz": 4, "ext": "jpg", "anno_path": "Dancer/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dancer2", "path": "Dancer2/img", "startFrame": 1, "endFrame": 150, "nz": 4, "ext": "jpg", "anno_path": "Dancer2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "David", "path": "David/img", "startFrame": 300, "endFrame": 770, "nz": 4, "ext": "jpg", "anno_path": "David/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "David2", "path": "David2/img", "startFrame": 1, "endFrame": 537, "nz": 4, "ext": "jpg", "anno_path": "David2/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "David3", "path": "David3/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", "anno_path": "David3/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Deer", "path": "Deer/img", "startFrame": 1, "endFrame": 71, "nz": 4, "ext": "jpg", "anno_path": "Deer/groundtruth_rect.txt", + "object_class": "mammal"}, + {"name": "Diving", "path": "Diving/img", "startFrame": 1, "endFrame": 215, "nz": 4, "ext": "jpg", "anno_path": "Diving/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Dog", "path": "Dog/img", "startFrame": 1, "endFrame": 127, "nz": 4, "ext": "jpg", "anno_path": "Dog/groundtruth_rect.txt", + "object_class": "dog"}, + {"name": "Dog1", "path": "Dog1/img", "startFrame": 1, "endFrame": 1350, "nz": 4, "ext": "jpg", "anno_path": "Dog1/groundtruth_rect.txt", + "object_class": "dog"}, + {"name": "Doll", "path": "Doll/img", "startFrame": 1, "endFrame": 3872, "nz": 4, "ext": "jpg", "anno_path": "Doll/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "DragonBaby", "path": "DragonBaby/img", "startFrame": 1, "endFrame": 113, "nz": 4, "ext": "jpg", "anno_path": "DragonBaby/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Dudek", "path": "Dudek/img", "startFrame": 1, "endFrame": 1145, "nz": 4, "ext": "jpg", "anno_path": "Dudek/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "FaceOcc1", "path": "FaceOcc1/img", "startFrame": 1, "endFrame": 892, "nz": 4, "ext": "jpg", "anno_path": "FaceOcc1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "FaceOcc2", "path": "FaceOcc2/img", "startFrame": 1, "endFrame": 812, "nz": 4, "ext": "jpg", "anno_path": "FaceOcc2/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Fish", "path": "Fish/img", "startFrame": 1, "endFrame": 476, "nz": 4, "ext": "jpg", "anno_path": "Fish/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "FleetFace", "path": "FleetFace/img", "startFrame": 1, "endFrame": 707, "nz": 4, "ext": "jpg", "anno_path": "FleetFace/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Football", "path": "Football/img", "startFrame": 1, "endFrame": 362, "nz": 4, "ext": "jpg", "anno_path": "Football/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Football1", "path": "Football1/img", "startFrame": 1, "endFrame": 74, "nz": 4, "ext": "jpg", "anno_path": "Football1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman1", "path": "Freeman1/img", "startFrame": 1, "endFrame": 326, "nz": 4, "ext": "jpg", "anno_path": "Freeman1/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman3", "path": "Freeman3/img", "startFrame": 1, "endFrame": 460, "nz": 4, "ext": "jpg", "anno_path": "Freeman3/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Freeman4", "path": "Freeman4/img", "startFrame": 1, "endFrame": 283, "nz": 4, "ext": "jpg", "anno_path": "Freeman4/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Girl", "path": "Girl/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", "anno_path": "Girl/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Girl2", "path": "Girl2/img", "startFrame": 1, "endFrame": 1500, "nz": 4, "ext": "jpg", "anno_path": "Girl2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Gym", "path": "Gym/img", "startFrame": 1, "endFrame": 767, "nz": 4, "ext": "jpg", "anno_path": "Gym/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human2", "path": "Human2/img", "startFrame": 1, "endFrame": 1128, "nz": 4, "ext": "jpg", "anno_path": "Human2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human3", "path": "Human3/img", "startFrame": 1, "endFrame": 1698, "nz": 4, "ext": "jpg", "anno_path": "Human3/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human4_2", "path": "Human4/img", "startFrame": 1, "endFrame": 667, "nz": 4, "ext": "jpg", "anno_path": "Human4/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Human5", "path": "Human5/img", "startFrame": 1, "endFrame": 713, "nz": 4, "ext": "jpg", "anno_path": "Human5/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human6", "path": "Human6/img", "startFrame": 1, "endFrame": 792, "nz": 4, "ext": "jpg", "anno_path": "Human6/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human7", "path": "Human7/img", "startFrame": 1, "endFrame": 250, "nz": 4, "ext": "jpg", "anno_path": "Human7/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human8", "path": "Human8/img", "startFrame": 1, "endFrame": 128, "nz": 4, "ext": "jpg", "anno_path": "Human8/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Human9", "path": "Human9/img", "startFrame": 1, "endFrame": 305, "nz": 4, "ext": "jpg", "anno_path": "Human9/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Ironman", "path": "Ironman/img", "startFrame": 1, "endFrame": 166, "nz": 4, "ext": "jpg", "anno_path": "Ironman/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Jogging_1", "path": "Jogging/img", "startFrame": 1, "endFrame": 307, "nz": 4, "ext": "jpg", "anno_path": "Jogging/groundtruth_rect.1.txt", + "object_class": "person"}, + {"name": "Jogging_2", "path": "Jogging/img", "startFrame": 1, "endFrame": 307, "nz": 4, "ext": "jpg", "anno_path": "Jogging/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Jump", "path": "Jump/img", "startFrame": 1, "endFrame": 122, "nz": 4, "ext": "jpg", "anno_path": "Jump/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Jumping", "path": "Jumping/img", "startFrame": 1, "endFrame": 313, "nz": 4, "ext": "jpg", "anno_path": "Jumping/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "KiteSurf", "path": "KiteSurf/img", "startFrame": 1, "endFrame": 84, "nz": 4, "ext": "png", "anno_path": "KiteSurf/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Lemming", "path": "Lemming/img", "startFrame": 1, "endFrame": 1336, "nz": 4, "ext": "jpg", "anno_path": "Lemming/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Liquor", "path": "Liquor/img", "startFrame": 1, "endFrame": 1741, "nz": 4, "ext": "jpg", "anno_path": "Liquor/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Man", "path": "Man/img", "startFrame": 1, "endFrame": 134, "nz": 4, "ext": "jpg", "anno_path": "Man/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Matrix", "path": "Matrix/img", "startFrame": 1, "endFrame": 100, "nz": 4, "ext": "jpg", "anno_path": "Matrix/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Mhyang", "path": "Mhyang/img", "startFrame": 1, "endFrame": 1490, "nz": 4, "ext": "jpg", "anno_path": "Mhyang/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "MotorRolling", "path": "MotorRolling/img", "startFrame": 1, "endFrame": 164, "nz": 4, "ext": "jpg", "anno_path": "MotorRolling/groundtruth_rect.txt", + "object_class": "vehicle"}, + {"name": "MountainBike", "path": "MountainBike/img", "startFrame": 1, "endFrame": 228, "nz": 4, "ext": "jpg", "anno_path": "MountainBike/groundtruth_rect.txt", + "object_class": "bicycle"}, + {"name": "Panda", "path": "Panda/img", "startFrame": 1, "endFrame": 1000, "nz": 4, "ext": "jpg", "anno_path": "Panda/groundtruth_rect.txt", + "object_class": "mammal"}, + {"name": "RedTeam", "path": "RedTeam/img", "startFrame": 1, "endFrame": 1918, "nz": 4, "ext": "jpg", "anno_path": "RedTeam/groundtruth_rect.txt", + "object_class": "vehicle"}, + {"name": "Rubik", "path": "Rubik/img", "startFrame": 1, "endFrame": 1997, "nz": 4, "ext": "jpg", "anno_path": "Rubik/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Shaking", "path": "Shaking/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", "anno_path": "Shaking/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Singer1", "path": "Singer1/img", "startFrame": 1, "endFrame": 351, "nz": 4, "ext": "jpg", "anno_path": "Singer1/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Singer2", "path": "Singer2/img", "startFrame": 1, "endFrame": 366, "nz": 4, "ext": "jpg", "anno_path": "Singer2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skater", "path": "Skater/img", "startFrame": 1, "endFrame": 160, "nz": 4, "ext": "jpg", "anno_path": "Skater/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skater2", "path": "Skater2/img", "startFrame": 1, "endFrame": 435, "nz": 4, "ext": "jpg", "anno_path": "Skater2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skating1", "path": "Skating1/img", "startFrame": 1, "endFrame": 400, "nz": 4, "ext": "jpg", "anno_path": "Skating1/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Skating2_1", "path": "Skating2/img", "startFrame": 1, "endFrame": 473, "nz": 4, "ext": "jpg", "anno_path": "Skating2/groundtruth_rect.1.txt", + "object_class": "person"}, + {"name": "Skating2_2", "path": "Skating2/img", "startFrame": 1, "endFrame": 473, "nz": 4, "ext": "jpg", "anno_path": "Skating2/groundtruth_rect.2.txt", + "object_class": "person"}, + {"name": "Skiing", "path": "Skiing/img", "startFrame": 1, "endFrame": 81, "nz": 4, "ext": "jpg", "anno_path": "Skiing/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Soccer", "path": "Soccer/img", "startFrame": 1, "endFrame": 392, "nz": 4, "ext": "jpg", "anno_path": "Soccer/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Subway", "path": "Subway/img", "startFrame": 1, "endFrame": 175, "nz": 4, "ext": "jpg", "anno_path": "Subway/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Surfer", "path": "Surfer/img", "startFrame": 1, "endFrame": 376, "nz": 4, "ext": "jpg", "anno_path": "Surfer/groundtruth_rect.txt", + "object_class": "person head"}, + {"name": "Suv", "path": "Suv/img", "startFrame": 1, "endFrame": 945, "nz": 4, "ext": "jpg", "anno_path": "Suv/groundtruth_rect.txt", + "object_class": "car"}, + {"name": "Sylvester", "path": "Sylvester/img", "startFrame": 1, "endFrame": 1345, "nz": 4, "ext": "jpg", "anno_path": "Sylvester/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Tiger1", "path": "Tiger1/img", "startFrame": 1, "endFrame": 354, "nz": 4, "ext": "jpg", "anno_path": "Tiger1/groundtruth_rect.txt", "initOmit": 5, + "object_class": "other"}, + {"name": "Tiger2", "path": "Tiger2/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", "anno_path": "Tiger2/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Toy", "path": "Toy/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", "anno_path": "Toy/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Trans", "path": "Trans/img", "startFrame": 1, "endFrame": 124, "nz": 4, "ext": "jpg", "anno_path": "Trans/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Trellis", "path": "Trellis/img", "startFrame": 1, "endFrame": 569, "nz": 4, "ext": "jpg", "anno_path": "Trellis/groundtruth_rect.txt", + "object_class": "face"}, + {"name": "Twinnings", "path": "Twinnings/img", "startFrame": 1, "endFrame": 472, "nz": 4, "ext": "jpg", "anno_path": "Twinnings/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Vase", "path": "Vase/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", "anno_path": "Vase/groundtruth_rect.txt", + "object_class": "other"}, + {"name": "Walking", "path": "Walking/img", "startFrame": 1, "endFrame": 412, "nz": 4, "ext": "jpg", "anno_path": "Walking/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Walking2", "path": "Walking2/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", "anno_path": "Walking2/groundtruth_rect.txt", + "object_class": "person"}, + {"name": "Woman", "path": "Woman/img", "startFrame": 1, "endFrame": 597, "nz": 4, "ext": "jpg", "anno_path": "Woman/groundtruth_rect.txt", + "object_class": "person"} + ] + + return sequence_info_list diff --git a/pytracking/evaluation/running.py b/pytracking/evaluation/running.py new file mode 100755 index 0000000..eef8f15 --- /dev/null +++ b/pytracking/evaluation/running.py @@ -0,0 +1,150 @@ +import numpy as np +import multiprocessing +import os +import sys +from itertools import product +from collections import OrderedDict +from pytracking.evaluation import Sequence, Tracker +from ltr.data.image_loader import imwrite_indexed + + +def _save_tracker_output(seq: Sequence, tracker: Tracker, output: dict): + """Saves the output of the tracker.""" + + if not os.path.exists(tracker.results_dir): + os.makedirs(tracker.results_dir) + + base_results_path = os.path.join(tracker.results_dir, seq.name) + segmentation_path = os.path.join(tracker.segmentation_dir, seq.name) + + frame_names = [os.path.splitext(os.path.basename(f))[0] for f in seq.frames] + + def save_bb(file, data): + tracked_bb = np.array(data).astype(int) + np.savetxt(file, tracked_bb, delimiter='\t', fmt='%d') + + def save_time(file, data): + exec_times = np.array(data).astype(float) + np.savetxt(file, exec_times, delimiter='\t', fmt='%f') + + def _convert_dict(input_dict): + data_dict = {} + for elem in input_dict: + for k, v in elem.items(): + if k in data_dict.keys(): + data_dict[k].append(v) + else: + data_dict[k] = [v, ] + return data_dict + + for key, data in output.items(): + # If data is empty + if not data: + continue + + if key == 'target_bbox': + if isinstance(data[0], (dict, OrderedDict)): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + bbox_file = '{}_{}.txt'.format(base_results_path, obj_id) + save_bb(bbox_file, d) + else: + # Single-object mode + bbox_file = '{}.txt'.format(base_results_path) + save_bb(bbox_file, data) + + elif key == 'time': + if isinstance(data[0], dict): + data_dict = _convert_dict(data) + + for obj_id, d in data_dict.items(): + timings_file = '{}_{}_time.txt'.format(base_results_path, obj_id) + save_time(timings_file, d) + else: + timings_file = '{}_time.txt'.format(base_results_path) + save_time(timings_file, data) + + elif key == 'segmentation': + assert len(frame_names) == len(data) + if not os.path.exists(segmentation_path): + os.makedirs(segmentation_path) + for frame_name, frame_seg in zip(frame_names, data): + imwrite_indexed(os.path.join(segmentation_path, '{}.png'.format(frame_name)), frame_seg) + + +def run_sequence(seq: Sequence, tracker: Tracker, debug=False, visdom_info=None): + """Runs a tracker on a sequence.""" + + def _results_exist(): + if seq.object_ids is None: + bbox_file = '{}/{}.txt'.format(tracker.results_dir, seq.name) + return os.path.isfile(bbox_file) + else: + bbox_files = ['{}/{}_{}.txt'.format(tracker.results_dir, seq.name, obj_id) for obj_id in seq.object_ids] + missing = [not os.path.isfile(f) for f in bbox_files] + return sum(missing) == 0 + + visdom_info = {} if visdom_info is None else visdom_info + + if _results_exist() and not debug: + print('FPS: {}'.format(-1)) + return + + print('Tracker: {} {} {} , Sequence: {}'.format(tracker.name, tracker.parameter_name, tracker.run_id, seq.name)) + + if debug: + output = tracker.run_sequence(seq, debug=debug, visdom_info=visdom_info) + else: + try: + output = tracker.run_sequence(seq, debug=debug, visdom_info=visdom_info) + except Exception as e: + print(e) + return + + sys.stdout.flush() + + if isinstance(output['time'][0], (dict, OrderedDict)): + exec_time = sum([sum(times.values()) for times in output['time']]) + num_frames = len(output['time']) + else: + exec_time = sum(output['time']) + num_frames = len(output['time']) + + print('FPS: {}'.format(num_frames / exec_time)) + + if not debug: + _save_tracker_output(seq, tracker, output) + + +def run_dataset(dataset, trackers, debug=False, threads=0, visdom_info=None): + """Runs a list of trackers on a dataset. + args: + dataset: List of Sequence instances, forming a dataset. + trackers: List of Tracker instances. + debug: Debug level. + threads: Number of threads to use (default 0). + visdom_info: Dict containing information about the server for visdom + """ + multiprocessing.set_start_method('spawn', force=True) + + print('Evaluating {:4d} trackers on {:5d} sequences'.format(len(trackers), len(dataset))) + + multiprocessing.set_start_method('spawn', force=True) + + visdom_info = {} if visdom_info is None else visdom_info + + if threads == 0: + mode = 'sequential' + else: + mode = 'parallel' + + if mode == 'sequential': + for seq in dataset: + for tracker_info in trackers: + run_sequence(seq, tracker_info, debug=debug, visdom_info=visdom_info) + elif mode == 'parallel': + param_list = [(seq, tracker_info, debug, visdom_info) for seq, tracker_info in product(dataset, trackers)] + with multiprocessing.Pool(processes=threads) as pool: + pool.starmap(run_sequence, param_list) + print('Done') diff --git a/pytracking/evaluation/tpldataset.py b/pytracking/evaluation/tpldataset.py new file mode 100755 index 0000000..0d77b2b --- /dev/null +++ b/pytracking/evaluation/tpldataset.py @@ -0,0 +1,328 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class TPLDataset(BaseDataset): + """ + Temple Color 128 dataset + + Publication: + Encoding Color Information for Visual Tracking: Algorithms and Benchmark + P. Liang, E. Blasch, and H. Ling + TIP, 2015 + http://www.dabi.temple.edu/~hbling/publication/TColor-128.pdf + + Download the dataset from http://www.dabi.temple.edu/~hbling/data/TColor-128/TColor-128.html + """ + def __init__(self, exclude_otb=False): + """ + args: + exclude_otb (bool) - If True, sequences overlapping with the OTB dataset are excluded + """ + super().__init__() + self.base_path = self.env_settings.tpl_path + self.sequence_info_list = self._get_sequence_info_list(exclude_otb) + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter=(',', None), dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'tpl', ground_truth_rect[init_omit:,:]) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self, exclude_otb=False): + sequence_info_list = [ + {"name": "tpl_Skating2", "path": "tpl_Skating2/img", "startFrame": 1, "endFrame": 707, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating2/Skating2_gt.txt"}, + {"name": "tpl_Pool_ce3", "path": "tpl_Pool_ce3/img", "startFrame": 1, "endFrame": 124, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce3/Pool_ce3_gt.txt"}, + {"name": "tpl_Microphone_ce1", "path": "tpl_Microphone_ce1/img", "startFrame": 1, "endFrame": 204, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Microphone_ce1/Microphone_ce1_gt.txt"}, + {"name": "tpl_Torus", "path": "tpl_Torus/img", "startFrame": 1, "endFrame": 264, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Torus/Torus_gt.txt"}, + {"name": "tpl_Lemming", "path": "tpl_Lemming/img", "startFrame": 1, "endFrame": 1336, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Lemming/Lemming_gt.txt"}, + {"name": "tpl_Eagle_ce", "path": "tpl_Eagle_ce/img", "startFrame": 1, "endFrame": 112, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Eagle_ce/Eagle_ce_gt.txt"}, + {"name": "tpl_Skating_ce2", "path": "tpl_Skating_ce2/img", "startFrame": 1, "endFrame": 497, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating_ce2/Skating_ce2_gt.txt"}, + {"name": "tpl_Yo_yos_ce3", "path": "tpl_Yo_yos_ce3/img", "startFrame": 1, "endFrame": 201, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce3/Yo-yos_ce3_gt.txt"}, + {"name": "tpl_Board", "path": "tpl_Board/img", "startFrame": 1, "endFrame": 598, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Board/Board_gt.txt"}, + {"name": "tpl_Tennis_ce3", "path": "tpl_Tennis_ce3/img", "startFrame": 1, "endFrame": 204, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce3/Tennis_ce3_gt.txt"}, + {"name": "tpl_SuperMario_ce", "path": "tpl_SuperMario_ce/img", "startFrame": 1, "endFrame": 146, "nz": 4, + "ext": "jpg", "anno_path": "tpl_SuperMario_ce/SuperMario_ce_gt.txt"}, + {"name": "tpl_Yo_yos_ce1", "path": "tpl_Yo_yos_ce1/img", "startFrame": 1, "endFrame": 235, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce1/Yo-yos_ce1_gt.txt"}, + {"name": "tpl_Soccer", "path": "tpl_Soccer/img", "startFrame": 1, "endFrame": 392, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Soccer/Soccer_gt.txt"}, + {"name": "tpl_Fish_ce2", "path": "tpl_Fish_ce2/img", "startFrame": 1, "endFrame": 573, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Fish_ce2/Fish_ce2_gt.txt"}, + {"name": "tpl_Liquor", "path": "tpl_Liquor/img", "startFrame": 1, "endFrame": 1741, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Liquor/Liquor_gt.txt"}, + {"name": "tpl_Plane_ce2", "path": "tpl_Plane_ce2/img", "startFrame": 1, "endFrame": 653, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plane_ce2/Plane_ce2_gt.txt"}, + {"name": "tpl_Couple", "path": "tpl_Couple/img", "startFrame": 1, "endFrame": 140, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Couple/Couple_gt.txt"}, + {"name": "tpl_Logo_ce", "path": "tpl_Logo_ce/img", "startFrame": 1, "endFrame": 610, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Logo_ce/Logo_ce_gt.txt"}, + {"name": "tpl_Hand_ce2", "path": "tpl_Hand_ce2/img", "startFrame": 1, "endFrame": 251, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hand_ce2/Hand_ce2_gt.txt"}, + {"name": "tpl_Kite_ce2", "path": "tpl_Kite_ce2/img", "startFrame": 1, "endFrame": 658, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce2/Kite_ce2_gt.txt"}, + {"name": "tpl_Walking", "path": "tpl_Walking/img", "startFrame": 1, "endFrame": 412, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Walking/Walking_gt.txt"}, + {"name": "tpl_David", "path": "tpl_David/img", "startFrame": 300, "endFrame": 770, "nz": 4, "ext": "jpg", + "anno_path": "tpl_David/David_gt.txt"}, + {"name": "tpl_Boat_ce1", "path": "tpl_Boat_ce1/img", "startFrame": 1, "endFrame": 377, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Boat_ce1/Boat_ce1_gt.txt"}, + {"name": "tpl_Airport_ce", "path": "tpl_Airport_ce/img", "startFrame": 1, "endFrame": 148, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Airport_ce/Airport_ce_gt.txt"}, + {"name": "tpl_Tiger2", "path": "tpl_Tiger2/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Tiger2/Tiger2_gt.txt"}, + {"name": "tpl_Suitcase_ce", "path": "tpl_Suitcase_ce/img", "startFrame": 1, "endFrame": 184, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Suitcase_ce/Suitcase_ce_gt.txt"}, + {"name": "tpl_TennisBall_ce", "path": "tpl_TennisBall_ce/img", "startFrame": 1, "endFrame": 288, "nz": 4, + "ext": "jpg", "anno_path": "tpl_TennisBall_ce/TennisBall_ce_gt.txt"}, + {"name": "tpl_Singer_ce1", "path": "tpl_Singer_ce1/img", "startFrame": 1, "endFrame": 214, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Singer_ce1/Singer_ce1_gt.txt"}, + {"name": "tpl_Pool_ce2", "path": "tpl_Pool_ce2/img", "startFrame": 1, "endFrame": 133, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce2/Pool_ce2_gt.txt"}, + {"name": "tpl_Surf_ce3", "path": "tpl_Surf_ce3/img", "startFrame": 1, "endFrame": 279, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce3/Surf_ce3_gt.txt"}, + {"name": "tpl_Bird", "path": "tpl_Bird/img", "startFrame": 1, "endFrame": 99, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bird/Bird_gt.txt"}, + {"name": "tpl_Crossing", "path": "tpl_Crossing/img", "startFrame": 1, "endFrame": 120, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Crossing/Crossing_gt.txt"}, + {"name": "tpl_Plate_ce1", "path": "tpl_Plate_ce1/img", "startFrame": 1, "endFrame": 142, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plate_ce1/Plate_ce1_gt.txt"}, + {"name": "tpl_Cup", "path": "tpl_Cup/img", "startFrame": 1, "endFrame": 303, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Cup/Cup_gt.txt"}, + {"name": "tpl_Surf_ce2", "path": "tpl_Surf_ce2/img", "startFrame": 1, "endFrame": 391, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce2/Surf_ce2_gt.txt"}, + {"name": "tpl_Busstation_ce2", "path": "tpl_Busstation_ce2/img", "startFrame": 6, "endFrame": 400, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Busstation_ce2/Busstation_ce2_gt.txt"}, + {"name": "tpl_Charger_ce", "path": "tpl_Charger_ce/img", "startFrame": 1, "endFrame": 298, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Charger_ce/Charger_ce_gt.txt"}, + {"name": "tpl_Pool_ce1", "path": "tpl_Pool_ce1/img", "startFrame": 1, "endFrame": 166, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Pool_ce1/Pool_ce1_gt.txt"}, + {"name": "tpl_MountainBike", "path": "tpl_MountainBike/img", "startFrame": 1, "endFrame": 228, "nz": 4, + "ext": "jpg", "anno_path": "tpl_MountainBike/MountainBike_gt.txt"}, + {"name": "tpl_Guitar_ce1", "path": "tpl_Guitar_ce1/img", "startFrame": 1, "endFrame": 268, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Guitar_ce1/Guitar_ce1_gt.txt"}, + {"name": "tpl_Busstation_ce1", "path": "tpl_Busstation_ce1/img", "startFrame": 1, "endFrame": 363, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Busstation_ce1/Busstation_ce1_gt.txt"}, + {"name": "tpl_Diving", "path": "tpl_Diving/img", "startFrame": 1, "endFrame": 231, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Diving/Diving_gt.txt"}, + {"name": "tpl_Skating_ce1", "path": "tpl_Skating_ce1/img", "startFrame": 1, "endFrame": 409, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating_ce1/Skating_ce1_gt.txt"}, + {"name": "tpl_Hurdle_ce2", "path": "tpl_Hurdle_ce2/img", "startFrame": 27, "endFrame": 330, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hurdle_ce2/Hurdle_ce2_gt.txt"}, + {"name": "tpl_Plate_ce2", "path": "tpl_Plate_ce2/img", "startFrame": 1, "endFrame": 181, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Plate_ce2/Plate_ce2_gt.txt"}, + {"name": "tpl_CarDark", "path": "tpl_CarDark/img", "startFrame": 1, "endFrame": 393, "nz": 4, "ext": "jpg", + "anno_path": "tpl_CarDark/CarDark_gt.txt"}, + {"name": "tpl_Singer_ce2", "path": "tpl_Singer_ce2/img", "startFrame": 1, "endFrame": 999, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Singer_ce2/Singer_ce2_gt.txt"}, + {"name": "tpl_Shaking", "path": "tpl_Shaking/img", "startFrame": 1, "endFrame": 365, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Shaking/Shaking_gt.txt"}, + {"name": "tpl_Iceskater", "path": "tpl_Iceskater/img", "startFrame": 1, "endFrame": 500, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Iceskater/Iceskater_gt.txt"}, + {"name": "tpl_Badminton_ce2", "path": "tpl_Badminton_ce2/img", "startFrame": 1, "endFrame": 705, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Badminton_ce2/Badminton_ce2_gt.txt"}, + {"name": "tpl_Spiderman_ce", "path": "tpl_Spiderman_ce/img", "startFrame": 1, "endFrame": 351, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Spiderman_ce/Spiderman_ce_gt.txt"}, + {"name": "tpl_Kite_ce1", "path": "tpl_Kite_ce1/img", "startFrame": 1, "endFrame": 484, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce1/Kite_ce1_gt.txt"}, + {"name": "tpl_Skyjumping_ce", "path": "tpl_Skyjumping_ce/img", "startFrame": 1, "endFrame": 938, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skyjumping_ce/Skyjumping_ce_gt.txt"}, + {"name": "tpl_Ball_ce1", "path": "tpl_Ball_ce1/img", "startFrame": 1, "endFrame": 391, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce1/Ball_ce1_gt.txt"}, + {"name": "tpl_Yo_yos_ce2", "path": "tpl_Yo_yos_ce2/img", "startFrame": 1, "endFrame": 454, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Yo_yos_ce2/Yo-yos_ce2_gt.txt"}, + {"name": "tpl_Ironman", "path": "tpl_Ironman/img", "startFrame": 1, "endFrame": 166, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Ironman/Ironman_gt.txt"}, + {"name": "tpl_FaceOcc1", "path": "tpl_FaceOcc1/img", "startFrame": 1, "endFrame": 892, "nz": 4, + "ext": "jpg", "anno_path": "tpl_FaceOcc1/FaceOcc1_gt.txt"}, + {"name": "tpl_Surf_ce1", "path": "tpl_Surf_ce1/img", "startFrame": 1, "endFrame": 404, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce1/Surf_ce1_gt.txt"}, + {"name": "tpl_Ring_ce", "path": "tpl_Ring_ce/img", "startFrame": 1, "endFrame": 201, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Ring_ce/Ring_ce_gt.txt"}, + {"name": "tpl_Surf_ce4", "path": "tpl_Surf_ce4/img", "startFrame": 1, "endFrame": 135, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Surf_ce4/Surf_ce4_gt.txt"}, + {"name": "tpl_Ball_ce4", "path": "tpl_Ball_ce4/img", "startFrame": 1, "endFrame": 538, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce4/Ball_ce4_gt.txt"}, + {"name": "tpl_Bikeshow_ce", "path": "tpl_Bikeshow_ce/img", "startFrame": 1, "endFrame": 361, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bikeshow_ce/Bikeshow_ce_gt.txt"}, + {"name": "tpl_Kobe_ce", "path": "tpl_Kobe_ce/img", "startFrame": 1, "endFrame": 582, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Kobe_ce/Kobe_ce_gt.txt"}, + {"name": "tpl_Tiger1", "path": "tpl_Tiger1/img", "startFrame": 1, "endFrame": 354, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Tiger1/Tiger1_gt.txt"}, + {"name": "tpl_Skiing", "path": "tpl_Skiing/img", "startFrame": 1, "endFrame": 81, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Skiing/Skiing_gt.txt"}, + {"name": "tpl_Tennis_ce1", "path": "tpl_Tennis_ce1/img", "startFrame": 1, "endFrame": 454, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce1/Tennis_ce1_gt.txt"}, + {"name": "tpl_Carchasing_ce4", "path": "tpl_Carchasing_ce4/img", "startFrame": 1, "endFrame": 442, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce4/Carchasing_ce4_gt.txt"}, + {"name": "tpl_Walking2", "path": "tpl_Walking2/img", "startFrame": 1, "endFrame": 500, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Walking2/Walking2_gt.txt"}, + {"name": "tpl_Sailor_ce", "path": "tpl_Sailor_ce/img", "startFrame": 1, "endFrame": 402, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Sailor_ce/Sailor_ce_gt.txt"}, + {"name": "tpl_Railwaystation_ce", "path": "tpl_Railwaystation_ce/img", "startFrame": 1, "endFrame": 413, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Railwaystation_ce/Railwaystation_ce_gt.txt"}, + {"name": "tpl_Bee_ce", "path": "tpl_Bee_ce/img", "startFrame": 1, "endFrame": 90, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bee_ce/Bee_ce_gt.txt"}, + {"name": "tpl_Girl", "path": "tpl_Girl/img", "startFrame": 1, "endFrame": 500, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Girl/Girl_gt.txt"}, + {"name": "tpl_Subway", "path": "tpl_Subway/img", "startFrame": 1, "endFrame": 175, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Subway/Subway_gt.txt"}, + {"name": "tpl_David3", "path": "tpl_David3/img", "startFrame": 1, "endFrame": 252, "nz": 4, "ext": "jpg", + "anno_path": "tpl_David3/David3_gt.txt"}, + {"name": "tpl_Electricalbike_ce", "path": "tpl_Electricalbike_ce/img", "startFrame": 1, "endFrame": 818, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Electricalbike_ce/Electricalbike_ce_gt.txt"}, + {"name": "tpl_Michaeljackson_ce", "path": "tpl_Michaeljackson_ce/img", "startFrame": 1, "endFrame": 393, + "nz": 4, "ext": "jpg", "anno_path": "tpl_Michaeljackson_ce/Michaeljackson_ce_gt.txt"}, + {"name": "tpl_Woman", "path": "tpl_Woman/img", "startFrame": 1, "endFrame": 597, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Woman/Woman_gt.txt"}, + {"name": "tpl_TableTennis_ce", "path": "tpl_TableTennis_ce/img", "startFrame": 1, "endFrame": 198, "nz": 4, + "ext": "jpg", "anno_path": "tpl_TableTennis_ce/TableTennis_ce_gt.txt"}, + {"name": "tpl_Motorbike_ce", "path": "tpl_Motorbike_ce/img", "startFrame": 1, "endFrame": 563, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Motorbike_ce/Motorbike_ce_gt.txt"}, + {"name": "tpl_Baby_ce", "path": "tpl_Baby_ce/img", "startFrame": 1, "endFrame": 296, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Baby_ce/Baby_ce_gt.txt"}, + {"name": "tpl_Gym", "path": "tpl_Gym/img", "startFrame": 1, "endFrame": 766, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Gym/Gym_gt.txt"}, + {"name": "tpl_Matrix", "path": "tpl_Matrix/img", "startFrame": 1, "endFrame": 100, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Matrix/Matrix_gt.txt"}, + {"name": "tpl_Kite_ce3", "path": "tpl_Kite_ce3/img", "startFrame": 1, "endFrame": 528, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Kite_ce3/Kite_ce3_gt.txt"}, + {"name": "tpl_Fish_ce1", "path": "tpl_Fish_ce1/img", "startFrame": 1, "endFrame": 401, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Fish_ce1/Fish_ce1_gt.txt"}, + {"name": "tpl_Hand_ce1", "path": "tpl_Hand_ce1/img", "startFrame": 1, "endFrame": 401, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hand_ce1/Hand_ce1_gt.txt"}, + {"name": "tpl_Doll", "path": "tpl_Doll/img", "startFrame": 1, "endFrame": 3872, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Doll/Doll_gt.txt"}, + {"name": "tpl_Carchasing_ce3", "path": "tpl_Carchasing_ce3/img", "startFrame": 1, "endFrame": 572, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce3/Carchasing_ce3_gt.txt"}, + {"name": "tpl_Thunder_ce", "path": "tpl_Thunder_ce/img", "startFrame": 1, "endFrame": 375, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Thunder_ce/Thunder_ce_gt.txt"}, + {"name": "tpl_Singer2", "path": "tpl_Singer2/img", "startFrame": 1, "endFrame": 366, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Singer2/Singer2_gt.txt"}, + {"name": "tpl_Basketball", "path": "tpl_Basketball/img", "startFrame": 1, "endFrame": 725, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball/Basketball_gt.txt"}, + {"name": "tpl_Hand", "path": "tpl_Hand/img", "startFrame": 1, "endFrame": 244, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Hand/Hand_gt.txt"}, + {"name": "tpl_Cup_ce", "path": "tpl_Cup_ce/img", "startFrame": 1, "endFrame": 338, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Cup_ce/Cup_ce_gt.txt"}, + {"name": "tpl_MotorRolling", "path": "tpl_MotorRolling/img", "startFrame": 1, "endFrame": 164, "nz": 4, + "ext": "jpg", "anno_path": "tpl_MotorRolling/MotorRolling_gt.txt"}, + {"name": "tpl_Boat_ce2", "path": "tpl_Boat_ce2/img", "startFrame": 1, "endFrame": 412, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Boat_ce2/Boat_ce2_gt.txt"}, + {"name": "tpl_CarScale", "path": "tpl_CarScale/img", "startFrame": 1, "endFrame": 252, "nz": 4, + "ext": "jpg", "anno_path": "tpl_CarScale/CarScale_gt.txt"}, + {"name": "tpl_Sunshade", "path": "tpl_Sunshade/img", "startFrame": 1, "endFrame": 172, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Sunshade/Sunshade_gt.txt"}, + {"name": "tpl_Football1", "path": "tpl_Football1/img", "startFrame": 1, "endFrame": 74, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Football1/Football1_gt.txt"}, + {"name": "tpl_Singer1", "path": "tpl_Singer1/img", "startFrame": 1, "endFrame": 351, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Singer1/Singer1_gt.txt"}, + {"name": "tpl_Hurdle_ce1", "path": "tpl_Hurdle_ce1/img", "startFrame": 1, "endFrame": 300, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Hurdle_ce1/Hurdle_ce1_gt.txt"}, + {"name": "tpl_Basketball_ce3", "path": "tpl_Basketball_ce3/img", "startFrame": 1, "endFrame": 441, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce3/Basketball_ce3_gt.txt"}, + {"name": "tpl_Toyplane_ce", "path": "tpl_Toyplane_ce/img", "startFrame": 1, "endFrame": 405, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Toyplane_ce/Toyplane_ce_gt.txt"}, + {"name": "tpl_Skating1", "path": "tpl_Skating1/img", "startFrame": 1, "endFrame": 400, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skating1/Skating1_gt.txt"}, + {"name": "tpl_Juice", "path": "tpl_Juice/img", "startFrame": 1, "endFrame": 404, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Juice/Juice_gt.txt"}, + {"name": "tpl_Biker", "path": "tpl_Biker/img", "startFrame": 1, "endFrame": 180, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Biker/Biker_gt.txt"}, + {"name": "tpl_Boy", "path": "tpl_Boy/img", "startFrame": 1, "endFrame": 602, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Boy/Boy_gt.txt"}, + {"name": "tpl_Jogging1", "path": "tpl_Jogging1/img", "startFrame": 1, "endFrame": 307, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Jogging1/Jogging1_gt.txt"}, + {"name": "tpl_Deer", "path": "tpl_Deer/img", "startFrame": 1, "endFrame": 71, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Deer/Deer_gt.txt"}, + {"name": "tpl_Panda", "path": "tpl_Panda/img", "startFrame": 1, "endFrame": 241, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Panda/Panda_gt.txt"}, + {"name": "tpl_Coke", "path": "tpl_Coke/img", "startFrame": 1, "endFrame": 291, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Coke/Coke_gt.txt"}, + {"name": "tpl_Carchasing_ce1", "path": "tpl_Carchasing_ce1/img", "startFrame": 1, "endFrame": 501, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Carchasing_ce1/Carchasing_ce1_gt.txt"}, + {"name": "tpl_Badminton_ce1", "path": "tpl_Badminton_ce1/img", "startFrame": 1, "endFrame": 579, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Badminton_ce1/Badminton_ce1_gt.txt"}, + {"name": "tpl_Trellis", "path": "tpl_Trellis/img", "startFrame": 1, "endFrame": 569, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Trellis/Trellis_gt.txt"}, + {"name": "tpl_Face_ce2", "path": "tpl_Face_ce2/img", "startFrame": 1, "endFrame": 148, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Face_ce2/Face_ce2_gt.txt"}, + {"name": "tpl_Ball_ce2", "path": "tpl_Ball_ce2/img", "startFrame": 1, "endFrame": 603, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce2/Ball_ce2_gt.txt"}, + {"name": "tpl_Skiing_ce", "path": "tpl_Skiing_ce/img", "startFrame": 1, "endFrame": 511, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Skiing_ce/Skiing_ce_gt.txt"}, + {"name": "tpl_Jogging2", "path": "tpl_Jogging2/img", "startFrame": 1, "endFrame": 307, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Jogging2/Jogging2_gt.txt"}, + {"name": "tpl_Bike_ce1", "path": "tpl_Bike_ce1/img", "startFrame": 1, "endFrame": 801, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bike_ce1/Bike_ce1_gt.txt"}, + {"name": "tpl_Bike_ce2", "path": "tpl_Bike_ce2/img", "startFrame": 1, "endFrame": 812, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Bike_ce2/Bike_ce2_gt.txt"}, + {"name": "tpl_Ball_ce3", "path": "tpl_Ball_ce3/img", "startFrame": 1, "endFrame": 273, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Ball_ce3/Ball_ce3_gt.txt"}, + {"name": "tpl_Girlmov", "path": "tpl_Girlmov/img", "startFrame": 1, "endFrame": 1500, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Girlmov/Girlmov_gt.txt"}, + {"name": "tpl_Bolt", "path": "tpl_Bolt/img", "startFrame": 1, "endFrame": 350, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bolt/Bolt_gt.txt"}, + {"name": "tpl_Basketball_ce2", "path": "tpl_Basketball_ce2/img", "startFrame": 1, "endFrame": 455, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce2/Basketball_ce2_gt.txt"}, + {"name": "tpl_Bicycle", "path": "tpl_Bicycle/img", "startFrame": 1, "endFrame": 271, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Bicycle/Bicycle_gt.txt"}, + {"name": "tpl_Face_ce", "path": "tpl_Face_ce/img", "startFrame": 1, "endFrame": 620, "nz": 4, "ext": "jpg", + "anno_path": "tpl_Face_ce/Face_ce_gt.txt"}, + {"name": "tpl_Basketball_ce1", "path": "tpl_Basketball_ce1/img", "startFrame": 1, "endFrame": 496, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Basketball_ce1/Basketball_ce1_gt.txt"}, + {"name": "tpl_Messi_ce", "path": "tpl_Messi_ce/img", "startFrame": 1, "endFrame": 272, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Messi_ce/Messi_ce_gt.txt"}, + {"name": "tpl_Tennis_ce2", "path": "tpl_Tennis_ce2/img", "startFrame": 1, "endFrame": 305, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Tennis_ce2/Tennis_ce2_gt.txt"}, + {"name": "tpl_Microphone_ce2", "path": "tpl_Microphone_ce2/img", "startFrame": 1, "endFrame": 103, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Microphone_ce2/Microphone_ce2_gt.txt"}, + {"name": "tpl_Guitar_ce2", "path": "tpl_Guitar_ce2/img", "startFrame": 1, "endFrame": 313, "nz": 4, + "ext": "jpg", "anno_path": "tpl_Guitar_ce2/Guitar_ce2_gt.txt"} + + ] + + otb_sequences = ['tpl_Skating2', 'tpl_Lemming', 'tpl_Board', 'tpl_Soccer', 'tpl_Liquor', 'tpl_Couple', 'tpl_Walking', 'tpl_David', 'tpl_Tiger2', 'tpl_Bird', 'tpl_Crossing', 'tpl_MountainBike', + 'tpl_Diving', 'tpl_CarDark', 'tpl_Shaking', 'tpl_Ironman', 'tpl_FaceOcc1', 'tpl_Tiger1', 'tpl_Skiing', 'tpl_Walking2', 'tpl_Girl', 'tpl_Girlmov', 'tpl_Subway', 'tpl_David3', 'tpl_Woman', + 'tpl_Gym', 'tpl_Matrix', 'tpl_Doll', 'tpl_Singer2', 'tpl_Basketball', 'tpl_MotorRolling', 'tpl_CarScale', 'tpl_Football1', 'tpl_Singer1', 'tpl_Skating1', 'tpl_Biker', + 'tpl_Boy', 'tpl_Jogging1', 'tpl_Deer', 'tpl_Panda', 'tpl_Coke', 'tpl_Trellis', 'tpl_Jogging2', 'tpl_Bolt', ] + if exclude_otb: + sequence_info_list_nootb = [] + for seq in sequence_info_list: + if seq['name'] not in otb_sequences: + sequence_info_list_nootb.append(seq) + + sequence_info_list = sequence_info_list_nootb + + return sequence_info_list diff --git a/pytracking/evaluation/tracker.py b/pytracking/evaluation/tracker.py new file mode 100755 index 0000000..4bc4ad0 --- /dev/null +++ b/pytracking/evaluation/tracker.py @@ -0,0 +1,710 @@ +import importlib +import os +import numpy as np +from collections import OrderedDict +from pytracking.evaluation.environment import env_settings +import time +import cv2 as cv +from pytracking.utils.visdom import Visdom +import matplotlib.pyplot as plt +import matplotlib.patches as patches +from pytracking.utils.plotting import draw_figure, overlay_mask +from pytracking.utils.convert_vot_anno_to_rect import convert_vot_anno_to_rect +from ltr.data.bounding_box_utils import masks_to_bboxes +from pytracking.evaluation.multi_object_wrapper import MultiObjectWrapper +from pathlib import Path +import torch + + +_tracker_disp_colors = {1: (0, 255, 0), 2: (0, 0, 255), 3: (255, 0, 0), + 4: (255, 255, 255), 5: (0, 0, 0), 6: (0, 255, 128), + 7: (123, 123, 123), 8: (255, 128, 0), 9: (128, 0, 255)} + + +def trackerlist(name: str, parameter_name: str, run_ids = None, display_name: str = None): + """Generate list of trackers. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_ids: A single or list of run_ids. + display_name: Name to be displayed in the result plots. + """ + if run_ids is None or isinstance(run_ids, int): + run_ids = [run_ids] + return [Tracker(name, parameter_name, run_id, display_name) for run_id in run_ids] + + +class Tracker: + """Wraps the tracker for evaluation and running purposes. + args: + name: Name of tracking method. + parameter_name: Name of parameter file. + run_id: The run id. + display_name: Name to be displayed in the result plots. + """ + + def __init__(self, name: str, parameter_name: str, run_id: int = None, display_name: str = None): + assert run_id is None or isinstance(run_id, int) + + self.name = name + self.parameter_name = parameter_name + self.run_id = run_id + self.display_name = display_name + + env = env_settings() + if self.run_id is None: + self.results_dir = '{}/{}/{}'.format(env.results_path, self.name, self.parameter_name) + self.segmentation_dir = '{}/{}/{}'.format(env.segmentation_path, self.name, self.parameter_name) + else: + self.results_dir = '{}/{}/{}_{:03d}'.format(env.results_path, self.name, self.parameter_name, self.run_id) + self.segmentation_dir = '{}/{}/{}_{:03d}'.format(env.segmentation_path, self.name, self.parameter_name, self.run_id) + + tracker_module_abspath = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'tracker', self.name)) + if os.path.isdir(tracker_module_abspath): + tracker_module = importlib.import_module('pytracking.tracker.{}'.format(self.name)) + self.tracker_class = tracker_module.get_tracker_class() + else: + self.tracker_class = None + + self.visdom = None + + + def _init_visdom(self, visdom_info, debug): + visdom_info = {} if visdom_info is None else visdom_info + self.pause_mode = False + self.step = False + if debug > 0 and visdom_info.get('use_visdom', True): + try: + self.visdom = Visdom(debug, {'handler': self._visdom_ui_handler, 'win_id': 'Tracking'}, + visdom_info=visdom_info) + + # Show help + help_text = 'You can pause/unpause the tracker by pressing ''space'' with the ''Tracking'' window ' \ + 'selected. During paused mode, you can track for one frame by pressing the right arrow key.' \ + 'To enable/disable plotting of a data block, tick/untick the corresponding entry in ' \ + 'block list.' + self.visdom.register(help_text, 'text', 1, 'Help') + except: + time.sleep(0.5) + print('!!! WARNING: Visdom could not start, so using matplotlib visualization instead !!!\n' + '!!! Start Visdom in a separate terminal window by typing \'visdom\' !!!') + + def _visdom_ui_handler(self, data): + if data['event_type'] == 'KeyPress': + if data['key'] == ' ': + self.pause_mode = not self.pause_mode + + elif data['key'] == 'ArrowRight' and self.pause_mode: + self.step = True + + + def create_tracker(self, params): + tracker = self.tracker_class(params) + tracker.visdom = self.visdom + return tracker + + def run_sequence(self, seq, visualization=None, debug=None, visdom_info=None, multiobj_mode=None): + """Run tracker on sequence. + args: + seq: Sequence to run the tracker on. + visualization: Set visualization flag (None means default value specified in the parameters). + debug: Set debug level (None means default value specified in the parameters). + visdom_info: Visdom info. + multiobj_mode: Which mode to use for multiple objects. + """ + params = self.get_parameters() + visualization_ = visualization + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + if visualization is None: + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + if visualization_ and self.visdom is None: + self.init_visualization() + + # Get init information + init_info = seq.init_info() + is_single_object = not seq.multiobj_mode + + if multiobj_mode is None: + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default' or is_single_object: + tracker = self.create_tracker(params) + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + output = self._track_sequence(tracker, seq, init_info) + return output + + def _track_sequence(self, tracker, seq, init_info): + # Define outputs + # Each field in output is a list containing tracker prediction for each frame. + + # In case of single object tracking mode: + # target_bbox[i] is the predicted bounding box for frame i + # time[i] is the processing time for frame i + # segmentation[i] is the segmentation mask for frame i (numpy array) + + # In case of multi object tracking mode: + # target_bbox[i] is an OrderedDict, where target_bbox[i][obj_id] is the predicted box for target obj_id in + # frame i + # time[i] is either the processing time for frame i, or an OrderedDict containing processing times for each + # object in frame i + # segmentation[i] is the multi-label segmentation mask for frame i (numpy array) + + output = {'target_bbox': [], + 'time': [], + 'segmentation': []} + + def _store_outputs(tracker_out: dict, defaults=None): + defaults = {} if defaults is None else defaults + for key in output.keys(): + val = tracker_out.get(key, defaults.get(key, None)) + if key in tracker_out or val is not None: + output[key].append(val) + + # Initialize + image = self._read_image(seq.frames[0]) + + if tracker.params.visualization and self.visdom is None: + self.visualize(image, init_info.get('init_bbox')) + + start_time = time.time() + out = tracker.initialize(image, init_info) + if out is None: + out = {} + + prev_output = OrderedDict(out) + + init_default = {'target_bbox': init_info.get('init_bbox'), + 'time': time.time() - start_time, + 'segmentation': init_info.get('init_mask')} + + _store_outputs(out, init_default) + + for frame_num, frame_path in enumerate(seq.frames[1:], start=1): + while True: + if not self.pause_mode: + break + elif self.step: + self.step = False + break + else: + time.sleep(0.1) + + image = self._read_image(frame_path) + + start_time = time.time() + + info = seq.frame_info(frame_num) + info['previous_output'] = prev_output + + out = tracker.track(image, info) + prev_output = OrderedDict(out) + _store_outputs(out, {'time': time.time() - start_time}) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + for key in ['target_bbox', 'segmentation']: + if key in output and len(output[key]) <= 1: + output.pop(key) + + return output + + def run_video(self, videofilepath, optional_box=None, debug=None, visdom_info=None, save_results=False): + """Run the tracker with the vieofile. + args: + debug: Debug level. + """ + + params = self.get_parameters() + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = self.name + params.param_name = self.parameter_name + self._init_visdom(visdom_info, debug_) + + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default': + tracker = self.create_tracker(params) + if hasattr(tracker, 'initialize_features'): + tracker.initialize_features() + + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom, fast_load=True) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + assert os.path.isfile(videofilepath), "Invalid param {}".format(videofilepath) + ", videofilepath must be a valid videofile" + + output_boxes = [] + + cap = cv.VideoCapture(videofilepath) + display_name = 'Display: ' + tracker.params.tracker_name + cv.namedWindow(display_name, cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO) + cv.resizeWindow(display_name, 960, 720) + success, frame = cap.read() + cv.imshow(display_name, frame) + + def _build_init_info(box): + return {'init_bbox': OrderedDict({1: box}), 'init_object_ids': [1, ], 'object_ids': [1, ], + 'sequence_object_ids': [1, ]} + + if success is not True: + print("Read frame from {} failed.".format(videofilepath)) + exit(-1) + if optional_box is not None: + assert isinstance(optional_box, (list, tuple)) + assert len(optional_box) == 4, "valid box's foramt is [x,y,w,h]" + tracker.initialize(frame, _build_init_info(optional_box)) + output_boxes.append(optional_box) + else: + while True: + # cv.waitKey() + frame_disp = frame.copy() + + cv.putText(frame_disp, 'Select target ROI and press ENTER', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, + 1.5, (0, 0, 0), 1) + + x, y, w, h = cv.selectROI(display_name, frame_disp, fromCenter=False) + init_state = [x, y, w, h] + tracker.initialize(frame, _build_init_info(init_state)) + output_boxes.append(init_state) + break + + while True: + ret, frame = cap.read() + + if frame is None: + break + + frame_disp = frame.copy() + + # Draw box + out = tracker.track(frame) + state = [int(s) for s in out['target_bbox'][1]] + output_boxes.append(state) + + cv.rectangle(frame_disp, (state[0], state[1]), (state[2] + state[0], state[3] + state[1]), + (0, 255, 0), 5) + + font_color = (0, 0, 0) + cv.putText(frame_disp, 'Tracking!', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press r to reset', (20, 55), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press q to quit', (20, 80), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + + # Display the resulting frame + cv.imshow(display_name, frame_disp) + key = cv.waitKey(1) + if key == ord('q'): + break + elif key == ord('r'): + ret, frame = cap.read() + frame_disp = frame.copy() + + cv.putText(frame_disp, 'Select target ROI and press ENTER', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1.5, + (0, 0, 0), 1) + + cv.imshow(display_name, frame_disp) + x, y, w, h = cv.selectROI(display_name, frame_disp, fromCenter=False) + init_state = [x, y, w, h] + tracker.initialize(frame, _build_init_info(init_state)) + output_boxes.append(init_state) + + # When everything done, release the capture + cap.release() + cv.destroyAllWindows() + + if save_results: + if not os.path.exists(self.results_dir): + os.makedirs(self.results_dir) + video_name = Path(videofilepath).stem + base_results_path = os.path.join(self.results_dir, 'video_{}'.format(video_name)) + + tracked_bb = np.array(output_boxes).astype(int) + bbox_file = '{}.txt'.format(base_results_path) + np.savetxt(bbox_file, tracked_bb, delimiter='\t', fmt='%d') + + def run_webcam(self, debug=None, visdom_info=None): + """Run the tracker with the webcam. + args: + debug: Debug level. + """ + + params = self.get_parameters() + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = self.name + params.param_name = self.parameter_name + + self._init_visdom(visdom_info, debug_) + + multiobj_mode = getattr(params, 'multiobj_mode', getattr(self.tracker_class, 'multiobj_mode', 'default')) + + if multiobj_mode == 'default': + tracker = self.create_tracker(params) + elif multiobj_mode == 'parallel': + tracker = MultiObjectWrapper(self.tracker_class, params, self.visdom, fast_load=True) + else: + raise ValueError('Unknown multi object mode {}'.format(multiobj_mode)) + + class UIControl: + def __init__(self): + self.mode = 'init' # init, select, track + self.target_tl = (-1, -1) + self.target_br = (-1, -1) + self.new_init = False + + def mouse_callback(self, event, x, y, flags, param): + if event == cv.EVENT_LBUTTONDOWN and self.mode == 'init': + self.target_tl = (x, y) + self.target_br = (x, y) + self.mode = 'select' + elif event == cv.EVENT_MOUSEMOVE and self.mode == 'select': + self.target_br = (x, y) + elif event == cv.EVENT_LBUTTONDOWN and self.mode == 'select': + self.target_br = (x, y) + self.mode = 'init' + self.new_init = True + + def get_tl(self): + return self.target_tl if self.target_tl[0] < self.target_br[0] else self.target_br + + def get_br(self): + return self.target_br if self.target_tl[0] < self.target_br[0] else self.target_tl + + def get_bb(self): + tl = self.get_tl() + br = self.get_br() + + bb = [min(tl[0], br[0]), min(tl[1], br[1]), abs(br[0] - tl[0]), abs(br[1] - tl[1])] + return bb + + ui_control = UIControl() + cap = cv.VideoCapture(0) + display_name = 'Display: ' + self.name + cv.namedWindow(display_name, cv.WINDOW_NORMAL | cv.WINDOW_KEEPRATIO) + cv.resizeWindow(display_name, 960, 720) + cv.setMouseCallback(display_name, ui_control.mouse_callback) + + next_object_id = 1 + sequence_object_ids = [] + prev_output = OrderedDict() + while True: + # Capture frame-by-frame + ret, frame = cap.read() + frame_disp = frame.copy() + + info = OrderedDict() + info['previous_output'] = prev_output + + if ui_control.new_init: + ui_control.new_init = False + init_state = ui_control.get_bb() + + info['init_object_ids'] = [next_object_id, ] + info['init_bbox'] = OrderedDict({next_object_id: init_state}) + sequence_object_ids.append(next_object_id) + + next_object_id += 1 + + # Draw box + if ui_control.mode == 'select': + cv.rectangle(frame_disp, ui_control.get_tl(), ui_control.get_br(), (255, 0, 0), 2) + + if len(sequence_object_ids) > 0: + info['sequence_object_ids'] = sequence_object_ids + out = tracker.track(frame, info) + prev_output = OrderedDict(out) + + if 'segmentation' in out: + frame_disp = overlay_mask(frame_disp, out['segmentation']) + + if 'target_bbox' in out: + for obj_id, state in out['target_bbox'].items(): + state = [int(s) for s in state] + cv.rectangle(frame_disp, (state[0], state[1]), (state[2] + state[0], state[3] + state[1]), + _tracker_disp_colors[obj_id], 5) + + # Put text + font_color = (0, 0, 0) + cv.putText(frame_disp, 'Select target', (20, 30), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, font_color, 1) + cv.putText(frame_disp, 'Press r to reset', (20, 55), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + cv.putText(frame_disp, 'Press q to quit', (20, 85), cv.FONT_HERSHEY_COMPLEX_SMALL, 1, + font_color, 1) + + # Display the resulting frame + cv.imshow(display_name, frame_disp) + key = cv.waitKey(1) + if key == ord('q'): + break + elif key == ord('r'): + next_object_id = 1 + sequence_object_ids = [] + prev_output = OrderedDict() + + info = OrderedDict() + + info['object_ids'] = [] + info['init_object_ids'] = [] + info['init_bbox'] = OrderedDict() + tracker.initialize(frame, info) + ui_control.mode = 'init' + + # When everything done, release the capture + cap.release() + cv.destroyAllWindows() + + def run_vot2020(self, debug=None, visdom_info=None): + params = self.get_parameters() + params.tracker_name = self.name + params.param_name = self.parameter_name + params.run_id = self.run_id + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + + tracker = self.create_tracker(params) + tracker.initialize_features() + + output_segmentation = tracker.predicts_segmentation_mask() + + import pytracking.evaluation.vot2020 as vot + + def _convert_anno_to_list(vot_anno): + vot_anno = [vot_anno[0], vot_anno[1], vot_anno[2], vot_anno[3]] + return vot_anno + + def _convert_image_path(image_path): + return image_path + + """Run tracker on VOT.""" + + if output_segmentation: + handle = vot.VOT("mask") + else: + handle = vot.VOT("rectangle") + + vot_anno = handle.region() + + image_path = handle.frame() + if not image_path: + return + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + + if output_segmentation: + vot_anno_mask = vot.make_full_size(vot_anno, (image.shape[1], image.shape[0])) + bbox = masks_to_bboxes(torch.from_numpy(vot_anno_mask), fmt='t').squeeze().tolist() + else: + bbox = _convert_anno_to_list(vot_anno) + vot_anno_mask = None + + out = tracker.initialize(image, {'init_mask': vot_anno_mask, 'init_bbox': bbox}) + + if out is None: + out = {} + prev_output = OrderedDict(out) + + # Track + while True: + image_path = handle.frame() + if not image_path: + break + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + + info = OrderedDict() + info['previous_output'] = prev_output + + out = tracker.track(image, info) + prev_output = OrderedDict(out) + + if output_segmentation: + pred = out['segmentation'].astype(np.uint8) + else: + state = out['target_bbox'] + pred = vot.Rectangle(*state) + handle.report(pred, 1.0) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + + def run_vot(self, debug=None, visdom_info=None): + params = self.get_parameters() + params.tracker_name = self.name + params.param_name = self.parameter_name + params.run_id = self.run_id + + debug_ = debug + if debug is None: + debug_ = getattr(params, 'debug', 0) + + if debug is None: + visualization_ = getattr(params, 'visualization', False) + else: + visualization_ = True if debug else False + + params.visualization = visualization_ + params.debug = debug_ + + self._init_visdom(visdom_info, debug_) + + tracker = self.create_tracker(params) + tracker.initialize_features() + + import pytracking.evaluation.vot as vot + + def _convert_anno_to_list(vot_anno): + vot_anno = [vot_anno[0][0][0], vot_anno[0][0][1], vot_anno[0][1][0], vot_anno[0][1][1], + vot_anno[0][2][0], vot_anno[0][2][1], vot_anno[0][3][0], vot_anno[0][3][1]] + return vot_anno + + def _convert_image_path(image_path): + image_path_new = image_path[20:- 2] + return "".join(image_path_new) + + """Run tracker on VOT.""" + + handle = vot.VOT("polygon") + + vot_anno_polygon = handle.region() + vot_anno_polygon = _convert_anno_to_list(vot_anno_polygon) + + init_state = convert_vot_anno_to_rect(vot_anno_polygon, tracker.params.vot_anno_conversion_type) + + image_path = handle.frame() + if not image_path: + return + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + tracker.initialize(image, {'init_bbox': init_state}) + + # Track + while True: + image_path = handle.frame() + if not image_path: + break + image_path = _convert_image_path(image_path) + + image = self._read_image(image_path) + out = tracker.track(image) + state = out['target_bbox'] + + handle.report(vot.Rectangle(state[0], state[1], state[2], state[3])) + + segmentation = out['segmentation'] if 'segmentation' in out else None + if self.visdom is not None: + tracker.visdom_draw_tracking(image, out['target_bbox'], segmentation) + elif tracker.params.visualization: + self.visualize(image, out['target_bbox'], segmentation) + + def get_parameters(self): + """Get parameters.""" + param_module = importlib.import_module('pytracking.parameter.{}.{}'.format(self.name, self.parameter_name)) + params = param_module.parameters() + return params + + + def init_visualization(self): + self.pause_mode = False + self.fig, self.ax = plt.subplots(1) + self.fig.canvas.mpl_connect('key_press_event', self.press) + plt.tight_layout() + + + def visualize(self, image, state, segmentation=None): + self.ax.cla() + self.ax.imshow(image) + if segmentation is not None: + self.ax.imshow(segmentation, alpha=0.5) + + if isinstance(state, (OrderedDict, dict)): + boxes = [v for k, v in state.items()] + else: + boxes = (state,) + + for i, box in enumerate(boxes, start=1): + col = _tracker_disp_colors[i] + col = [float(c) / 255.0 for c in col] + rect = patches.Rectangle((box[0], box[1]), box[2], box[3], linewidth=1, edgecolor=col, facecolor='none') + self.ax.add_patch(rect) + + if getattr(self, 'gt_state', None) is not None: + gt_state = self.gt_state + rect = patches.Rectangle((gt_state[0], gt_state[1]), gt_state[2], gt_state[3], linewidth=1, edgecolor='g', facecolor='none') + self.ax.add_patch(rect) + self.ax.set_axis_off() + self.ax.axis('equal') + draw_figure(self.fig) + + if self.pause_mode: + keypress = False + while not keypress: + keypress = plt.waitforbuttonpress() + + def reset_tracker(self): + pass + + def press(self, event): + if event.key == 'p': + self.pause_mode = not self.pause_mode + print("Switching pause mode!") + elif event.key == 'r': + self.reset_tracker() + print("Resetting target pos to gt!") + + def _read_image(self, image_file: str): + im = cv.imread(image_file) + return cv.cvtColor(im, cv.COLOR_BGR2RGB) + + + diff --git a/pytracking/evaluation/trackingnetdataset.py b/pytracking/evaluation/trackingnetdataset.py new file mode 100755 index 0000000..09e5f0f --- /dev/null +++ b/pytracking/evaluation/trackingnetdataset.py @@ -0,0 +1,58 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +import os +from pytracking.utils.load_text import load_text + + +class TrackingNetDataset(BaseDataset): + """ TrackingNet test set. + + Publication: + TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild. + Matthias Mueller,Adel Bibi, Silvio Giancola, Salman Al-Subaihi and Bernard Ghanem + ECCV, 2018 + https://ivul.kaust.edu.sa/Documents/Publications/2018/TrackingNet%20A%20Large%20Scale%20Dataset%20and%20Benchmark%20for%20Object%20Tracking%20in%20the%20Wild.pdf + + Download the dataset using the toolkit https://github.com/SilvioGiancola/TrackingNet-devkit. + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.trackingnet_path + + sets = 'TEST' + if not isinstance(sets, (list, tuple)): + if sets == 'TEST': + sets = ['TEST'] + elif sets == 'TRAIN': + sets = ['TRAIN_{}'.format(i) for i in range(5)] + + self.sequence_list = self._list_sequences(self.base_path, sets) + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(set, seq_name) for set, seq_name in self.sequence_list]) + + def _construct_sequence(self, set, sequence_name): + anno_path = '{}/{}/anno/{}.txt'.format(self.base_path, set, sequence_name) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64, backend='numpy') + + frames_path = '{}/{}/frames/{}'.format(self.base_path, set, sequence_name) + frame_list = [frame for frame in os.listdir(frames_path) if frame.endswith(".jpg")] + frame_list.sort(key=lambda f: int(f[:-4])) + frames_list = [os.path.join(frames_path, frame) for frame in frame_list] + + return Sequence(sequence_name, frames_list, 'trackingnet', ground_truth_rect.reshape(-1, 4)) + + def __len__(self): + return len(self.sequence_list) + + def _list_sequences(self, root, set_ids): + sequence_list = [] + + for s in set_ids: + anno_dir = os.path.join(root, s, "anno") + sequences_cur_set = [(s, os.path.splitext(f)[0]) for f in os.listdir(anno_dir) if f.endswith('.txt')] + + sequence_list += sequences_cur_set + + return sequence_list diff --git a/pytracking/evaluation/uavdataset.py b/pytracking/evaluation/uavdataset.py new file mode 100755 index 0000000..1c6d099 --- /dev/null +++ b/pytracking/evaluation/uavdataset.py @@ -0,0 +1,299 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList +from pytracking.utils.load_text import load_text + + +class UAVDataset(BaseDataset): + """ UAV123 dataset. + + Publication: + A Benchmark and Simulator for UAV Tracking. + Matthias Mueller, Neil Smith and Bernard Ghanem + ECCV, 2016 + https://ivul.kaust.edu.sa/Documents/Publications/2016/A%20Benchmark%20and%20Simulator%20for%20UAV%20Tracking.pdf + + Download the dataset from https://ivul.kaust.edu.sa/Pages/pub-benchmark-simulator-uav.aspx + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.uav_path + self.sequence_info_list = self._get_sequence_info_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_info_list]) + + def _construct_sequence(self, sequence_info): + sequence_path = sequence_info['path'] + nz = sequence_info['nz'] + ext = sequence_info['ext'] + start_frame = sequence_info['startFrame'] + end_frame = sequence_info['endFrame'] + + init_omit = 0 + if 'initOmit' in sequence_info: + init_omit = sequence_info['initOmit'] + + frames = ['{base_path}/{sequence_path}/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) for frame_num in range(start_frame+init_omit, end_frame+1)] + + anno_path = '{}/{}'.format(self.base_path, sequence_info['anno_path']) + + ground_truth_rect = load_text(str(anno_path), delimiter=',', dtype=np.float64, backend='numpy') + + return Sequence(sequence_info['name'], frames, 'uav', ground_truth_rect[init_omit:,:], + object_class=sequence_info['object_class']) + + def __len__(self): + return len(self.sequence_info_list) + + def _get_sequence_info_list(self): + sequence_info_list = [ + {"name": "uav_bike1", "path": "data_seq/UAV123/bike1", "startFrame": 1, "endFrame": 3085, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike1.txt", "object_class": "vehicle"}, + {"name": "uav_bike2", "path": "data_seq/UAV123/bike2", "startFrame": 1, "endFrame": 553, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike2.txt", "object_class": "vehicle"}, + {"name": "uav_bike3", "path": "data_seq/UAV123/bike3", "startFrame": 1, "endFrame": 433, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bike3.txt", "object_class": "vehicle"}, + {"name": "uav_bird1_1", "path": "data_seq/UAV123/bird1", "startFrame": 1, "endFrame": 253, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_1.txt", "object_class": "bird"}, + {"name": "uav_bird1_2", "path": "data_seq/UAV123/bird1", "startFrame": 775, "endFrame": 1477, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_2.txt", "object_class": "bird"}, + {"name": "uav_bird1_3", "path": "data_seq/UAV123/bird1", "startFrame": 1573, "endFrame": 2437, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/bird1_3.txt", "object_class": "bird"}, + {"name": "uav_boat1", "path": "data_seq/UAV123/boat1", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat1.txt", "object_class": "vessel"}, + {"name": "uav_boat2", "path": "data_seq/UAV123/boat2", "startFrame": 1, "endFrame": 799, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat2.txt", "object_class": "vessel"}, + {"name": "uav_boat3", "path": "data_seq/UAV123/boat3", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat3.txt", "object_class": "vessel"}, + {"name": "uav_boat4", "path": "data_seq/UAV123/boat4", "startFrame": 1, "endFrame": 553, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat4.txt", "object_class": "vessel"}, + {"name": "uav_boat5", "path": "data_seq/UAV123/boat5", "startFrame": 1, "endFrame": 505, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat5.txt", "object_class": "vessel"}, + {"name": "uav_boat6", "path": "data_seq/UAV123/boat6", "startFrame": 1, "endFrame": 805, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat6.txt", "object_class": "vessel"}, + {"name": "uav_boat7", "path": "data_seq/UAV123/boat7", "startFrame": 1, "endFrame": 535, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat7.txt", "object_class": "vessel"}, + {"name": "uav_boat8", "path": "data_seq/UAV123/boat8", "startFrame": 1, "endFrame": 685, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat8.txt", "object_class": "vessel"}, + {"name": "uav_boat9", "path": "data_seq/UAV123/boat9", "startFrame": 1, "endFrame": 1399, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/boat9.txt", "object_class": "vessel"}, + {"name": "uav_building1", "path": "data_seq/UAV123/building1", "startFrame": 1, "endFrame": 469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building1.txt", "object_class": "other"}, + {"name": "uav_building2", "path": "data_seq/UAV123/building2", "startFrame": 1, "endFrame": 577, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building2.txt", "object_class": "other"}, + {"name": "uav_building3", "path": "data_seq/UAV123/building3", "startFrame": 1, "endFrame": 829, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building3.txt", "object_class": "other"}, + {"name": "uav_building4", "path": "data_seq/UAV123/building4", "startFrame": 1, "endFrame": 787, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building4.txt", "object_class": "other"}, + {"name": "uav_building5", "path": "data_seq/UAV123/building5", "startFrame": 1, "endFrame": 481, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/building5.txt", "object_class": "other"}, + {"name": "uav_car1_1", "path": "data_seq/UAV123/car1", "startFrame": 1, "endFrame": 751, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_1.txt", "object_class": "car"}, + {"name": "uav_car1_2", "path": "data_seq/UAV123/car1", "startFrame": 751, "endFrame": 1627, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_2.txt", "object_class": "car"}, + {"name": "uav_car1_3", "path": "data_seq/UAV123/car1", "startFrame": 1627, "endFrame": 2629, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_3.txt", "object_class": "car"}, + {"name": "uav_car10", "path": "data_seq/UAV123/car10", "startFrame": 1, "endFrame": 1405, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car10.txt", "object_class": "car"}, + {"name": "uav_car11", "path": "data_seq/UAV123/car11", "startFrame": 1, "endFrame": 337, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car11.txt", "object_class": "car"}, + {"name": "uav_car12", "path": "data_seq/UAV123/car12", "startFrame": 1, "endFrame": 499, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car12.txt", "object_class": "car"}, + {"name": "uav_car13", "path": "data_seq/UAV123/car13", "startFrame": 1, "endFrame": 415, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car13.txt", "object_class": "car"}, + {"name": "uav_car14", "path": "data_seq/UAV123/car14", "startFrame": 1, "endFrame": 1327, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car14.txt", "object_class": "car"}, + {"name": "uav_car15", "path": "data_seq/UAV123/car15", "startFrame": 1, "endFrame": 469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car15.txt", "object_class": "car"}, + {"name": "uav_car16_1", "path": "data_seq/UAV123/car16", "startFrame": 1, "endFrame": 415, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car16_1.txt", "object_class": "car"}, + {"name": "uav_car16_2", "path": "data_seq/UAV123/car16", "startFrame": 415, "endFrame": 1993, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car16_2.txt", "object_class": "car"}, + {"name": "uav_car17", "path": "data_seq/UAV123/car17", "startFrame": 1, "endFrame": 1057, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car17.txt", "object_class": "car"}, + {"name": "uav_car18", "path": "data_seq/UAV123/car18", "startFrame": 1, "endFrame": 1207, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car18.txt", "object_class": "car"}, + {"name": "uav_car1_s", "path": "data_seq/UAV123/car1_s", "startFrame": 1, "endFrame": 1475, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car1_s.txt", "object_class": "car"}, + {"name": "uav_car2", "path": "data_seq/UAV123/car2", "startFrame": 1, "endFrame": 1321, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car2.txt", "object_class": "car"}, + {"name": "uav_car2_s", "path": "data_seq/UAV123/car2_s", "startFrame": 1, "endFrame": 320, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car2_s.txt", "object_class": "car"}, + {"name": "uav_car3", "path": "data_seq/UAV123/car3", "startFrame": 1, "endFrame": 1717, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car3.txt", "object_class": "car"}, + {"name": "uav_car3_s", "path": "data_seq/UAV123/car3_s", "startFrame": 1, "endFrame": 1300, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car3_s.txt", "object_class": "car"}, + {"name": "uav_car4", "path": "data_seq/UAV123/car4", "startFrame": 1, "endFrame": 1345, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car4.txt", "object_class": "car"}, + {"name": "uav_car4_s", "path": "data_seq/UAV123/car4_s", "startFrame": 1, "endFrame": 830, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car4_s.txt", "object_class": "car"}, + {"name": "uav_car5", "path": "data_seq/UAV123/car5", "startFrame": 1, "endFrame": 745, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car5.txt", "object_class": "car"}, + {"name": "uav_car6_1", "path": "data_seq/UAV123/car6", "startFrame": 1, "endFrame": 487, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_1.txt", "object_class": "car"}, + {"name": "uav_car6_2", "path": "data_seq/UAV123/car6", "startFrame": 487, "endFrame": 1807, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_2.txt", "object_class": "car"}, + {"name": "uav_car6_3", "path": "data_seq/UAV123/car6", "startFrame": 1807, "endFrame": 2953, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_3.txt", "object_class": "car"}, + {"name": "uav_car6_4", "path": "data_seq/UAV123/car6", "startFrame": 2953, "endFrame": 3925, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_4.txt", "object_class": "car"}, + {"name": "uav_car6_5", "path": "data_seq/UAV123/car6", "startFrame": 3925, "endFrame": 4861, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car6_5.txt", "object_class": "car"}, + {"name": "uav_car7", "path": "data_seq/UAV123/car7", "startFrame": 1, "endFrame": 1033, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car7.txt", "object_class": "car"}, + {"name": "uav_car8_1", "path": "data_seq/UAV123/car8", "startFrame": 1, "endFrame": 1357, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car8_1.txt", "object_class": "car"}, + {"name": "uav_car8_2", "path": "data_seq/UAV123/car8", "startFrame": 1357, "endFrame": 2575, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car8_2.txt", "object_class": "car"}, + {"name": "uav_car9", "path": "data_seq/UAV123/car9", "startFrame": 1, "endFrame": 1879, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/car9.txt", "object_class": "car"}, + {"name": "uav_group1_1", "path": "data_seq/UAV123/group1", "startFrame": 1, "endFrame": 1333, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_1.txt", "object_class": "person"}, + {"name": "uav_group1_2", "path": "data_seq/UAV123/group1", "startFrame": 1333, "endFrame": 2515, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_2.txt", "object_class": "person"}, + {"name": "uav_group1_3", "path": "data_seq/UAV123/group1", "startFrame": 2515, "endFrame": 3925, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_3.txt", "object_class": "person"}, + {"name": "uav_group1_4", "path": "data_seq/UAV123/group1", "startFrame": 3925, "endFrame": 4873, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group1_4.txt", "object_class": "person"}, + {"name": "uav_group2_1", "path": "data_seq/UAV123/group2", "startFrame": 1, "endFrame": 907, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_1.txt", "object_class": "person"}, + {"name": "uav_group2_2", "path": "data_seq/UAV123/group2", "startFrame": 907, "endFrame": 1771, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_2.txt", "object_class": "person"}, + {"name": "uav_group2_3", "path": "data_seq/UAV123/group2", "startFrame": 1771, "endFrame": 2683, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group2_3.txt", "object_class": "person"}, + {"name": "uav_group3_1", "path": "data_seq/UAV123/group3", "startFrame": 1, "endFrame": 1567, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_1.txt", "object_class": "person"}, + {"name": "uav_group3_2", "path": "data_seq/UAV123/group3", "startFrame": 1567, "endFrame": 2827, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_2.txt", "object_class": "person"}, + {"name": "uav_group3_3", "path": "data_seq/UAV123/group3", "startFrame": 2827, "endFrame": 4369, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_3.txt", "object_class": "person"}, + {"name": "uav_group3_4", "path": "data_seq/UAV123/group3", "startFrame": 4369, "endFrame": 5527, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/group3_4.txt", "object_class": "person"}, + {"name": "uav_person1", "path": "data_seq/UAV123/person1", "startFrame": 1, "endFrame": 799, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person1.txt", "object_class": "person"}, + {"name": "uav_person10", "path": "data_seq/UAV123/person10", "startFrame": 1, "endFrame": 1021, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person10.txt", "object_class": "person"}, + {"name": "uav_person11", "path": "data_seq/UAV123/person11", "startFrame": 1, "endFrame": 721, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person11.txt", "object_class": "person"}, + {"name": "uav_person12_1", "path": "data_seq/UAV123/person12", "startFrame": 1, "endFrame": 601, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person12_1.txt", "object_class": "person"}, + {"name": "uav_person12_2", "path": "data_seq/UAV123/person12", "startFrame": 601, "endFrame": 1621, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person12_2.txt", "object_class": "person"}, + {"name": "uav_person13", "path": "data_seq/UAV123/person13", "startFrame": 1, "endFrame": 883, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person13.txt", "object_class": "person"}, + {"name": "uav_person14_1", "path": "data_seq/UAV123/person14", "startFrame": 1, "endFrame": 847, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person14_1.txt", "object_class": "person"}, + {"name": "uav_person14_2", "path": "data_seq/UAV123/person14", "startFrame": 847, "endFrame": 1813, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person14_2.txt", "object_class": "person"}, + {"name": "uav_person14_3", "path": "data_seq/UAV123/person14", "startFrame": 1813, "endFrame": 2923, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person14_3.txt", "object_class": "person"}, + {"name": "uav_person15", "path": "data_seq/UAV123/person15", "startFrame": 1, "endFrame": 1339, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person15.txt", "object_class": "person"}, + {"name": "uav_person16", "path": "data_seq/UAV123/person16", "startFrame": 1, "endFrame": 1147, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person16.txt", "object_class": "person"}, + {"name": "uav_person17_1", "path": "data_seq/UAV123/person17", "startFrame": 1, "endFrame": 1501, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person17_1.txt", "object_class": "person"}, + {"name": "uav_person17_2", "path": "data_seq/UAV123/person17", "startFrame": 1501, "endFrame": 2347, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person17_2.txt", "object_class": "person"}, + {"name": "uav_person18", "path": "data_seq/UAV123/person18", "startFrame": 1, "endFrame": 1393, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person18.txt", "object_class": "person"}, + {"name": "uav_person19_1", "path": "data_seq/UAV123/person19", "startFrame": 1, "endFrame": 1243, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person19_1.txt", "object_class": "person"}, + {"name": "uav_person19_2", "path": "data_seq/UAV123/person19", "startFrame": 1243, "endFrame": 2791, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person19_2.txt", "object_class": "person"}, + {"name": "uav_person19_3", "path": "data_seq/UAV123/person19", "startFrame": 2791, "endFrame": 4357, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/person19_3.txt", "object_class": "person"}, + {"name": "uav_person1_s", "path": "data_seq/UAV123/person1_s", "startFrame": 1, "endFrame": 1600, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person1_s.txt", "object_class": "person"}, + {"name": "uav_person2_1", "path": "data_seq/UAV123/person2", "startFrame": 1, "endFrame": 1189, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_1.txt", "object_class": "person"}, + {"name": "uav_person2_2", "path": "data_seq/UAV123/person2", "startFrame": 1189, "endFrame": 2623, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_2.txt", "object_class": "person"}, + {"name": "uav_person20", "path": "data_seq/UAV123/person20", "startFrame": 1, "endFrame": 1783, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person20.txt", "object_class": "person"}, + {"name": "uav_person21", "path": "data_seq/UAV123/person21", "startFrame": 1, "endFrame": 487, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person21.txt", "object_class": "person"}, + {"name": "uav_person22", "path": "data_seq/UAV123/person22", "startFrame": 1, "endFrame": 199, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person22.txt", "object_class": "person"}, + {"name": "uav_person23", "path": "data_seq/UAV123/person23", "startFrame": 1, "endFrame": 397, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person23.txt", "object_class": "person"}, + {"name": "uav_person2_s", "path": "data_seq/UAV123/person2_s", "startFrame": 1, "endFrame": 250, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person2_s.txt", "object_class": "person"}, + {"name": "uav_person3", "path": "data_seq/UAV123/person3", "startFrame": 1, "endFrame": 643, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person3.txt", "object_class": "person"}, + {"name": "uav_person3_s", "path": "data_seq/UAV123/person3_s", "startFrame": 1, "endFrame": 505, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person3_s.txt", "object_class": "person"}, + {"name": "uav_person4_1", "path": "data_seq/UAV123/person4", "startFrame": 1, "endFrame": 1501, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person4_1.txt", "object_class": "person"}, + {"name": "uav_person4_2", "path": "data_seq/UAV123/person4", "startFrame": 1501, "endFrame": 2743, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person4_2.txt", "object_class": "person"}, + {"name": "uav_person5_1", "path": "data_seq/UAV123/person5", "startFrame": 1, "endFrame": 877, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person5_1.txt", "object_class": "person"}, + {"name": "uav_person5_2", "path": "data_seq/UAV123/person5", "startFrame": 877, "endFrame": 2101, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person5_2.txt", "object_class": "person"}, + {"name": "uav_person6", "path": "data_seq/UAV123/person6", "startFrame": 1, "endFrame": 901, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person6.txt", "object_class": "person"}, + {"name": "uav_person7_1", "path": "data_seq/UAV123/person7", "startFrame": 1, "endFrame": 1249, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person7_1.txt", "object_class": "person"}, + {"name": "uav_person7_2", "path": "data_seq/UAV123/person7", "startFrame": 1249, "endFrame": 2065, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person7_2.txt", "object_class": "person"}, + {"name": "uav_person8_1", "path": "data_seq/UAV123/person8", "startFrame": 1, "endFrame": 1075, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person8_1.txt", "object_class": "person"}, + {"name": "uav_person8_2", "path": "data_seq/UAV123/person8", "startFrame": 1075, "endFrame": 1525, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person8_2.txt", "object_class": "person"}, + {"name": "uav_person9", "path": "data_seq/UAV123/person9", "startFrame": 1, "endFrame": 661, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/person9.txt", "object_class": "person"}, + {"name": "uav_truck1", "path": "data_seq/UAV123/truck1", "startFrame": 1, "endFrame": 463, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck1.txt", "object_class": "truck"}, + {"name": "uav_truck2", "path": "data_seq/UAV123/truck2", "startFrame": 1, "endFrame": 385, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck2.txt", "object_class": "truck"}, + {"name": "uav_truck3", "path": "data_seq/UAV123/truck3", "startFrame": 1, "endFrame": 535, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck3.txt", "object_class": "truck"}, + {"name": "uav_truck4_1", "path": "data_seq/UAV123/truck4", "startFrame": 1, "endFrame": 577, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck4_1.txt", "object_class": "truck"}, + {"name": "uav_truck4_2", "path": "data_seq/UAV123/truck4", "startFrame": 577, "endFrame": 1261, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/truck4_2.txt", "object_class": "truck"}, + {"name": "uav_uav1_1", "path": "data_seq/UAV123/uav1", "startFrame": 1, "endFrame": 1555, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_1.txt", "object_class": "aircraft"}, + {"name": "uav_uav1_2", "path": "data_seq/UAV123/uav1", "startFrame": 1555, "endFrame": 2377, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_2.txt", "object_class": "aircraft"}, + {"name": "uav_uav1_3", "path": "data_seq/UAV123/uav1", "startFrame": 2473, "endFrame": 3469, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav1_3.txt", "object_class": "aircraft"}, + {"name": "uav_uav2", "path": "data_seq/UAV123/uav2", "startFrame": 1, "endFrame": 133, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav2.txt", "object_class": "aircraft"}, + {"name": "uav_uav3", "path": "data_seq/UAV123/uav3", "startFrame": 1, "endFrame": 265, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav3.txt", "object_class": "aircraft"}, + {"name": "uav_uav4", "path": "data_seq/UAV123/uav4", "startFrame": 1, "endFrame": 157, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav4.txt", "object_class": "aircraft"}, + {"name": "uav_uav5", "path": "data_seq/UAV123/uav5", "startFrame": 1, "endFrame": 139, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav5.txt", "object_class": "aircraft"}, + {"name": "uav_uav6", "path": "data_seq/UAV123/uav6", "startFrame": 1, "endFrame": 109, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav6.txt", "object_class": "aircraft"}, + {"name": "uav_uav7", "path": "data_seq/UAV123/uav7", "startFrame": 1, "endFrame": 373, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav7.txt", "object_class": "aircraft"}, + {"name": "uav_uav8", "path": "data_seq/UAV123/uav8", "startFrame": 1, "endFrame": 301, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/uav8.txt", "object_class": "aircraft"}, + {"name": "uav_wakeboard1", "path": "data_seq/UAV123/wakeboard1", "startFrame": 1, "endFrame": 421, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard1.txt", "object_class": "person"}, + {"name": "uav_wakeboard10", "path": "data_seq/UAV123/wakeboard10", "startFrame": 1, "endFrame": 469, + "nz": 6, "ext": "jpg", "anno_path": "anno/UAV123/wakeboard10.txt", "object_class": "person"}, + {"name": "uav_wakeboard2", "path": "data_seq/UAV123/wakeboard2", "startFrame": 1, "endFrame": 733, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard2.txt", "object_class": "person"}, + {"name": "uav_wakeboard3", "path": "data_seq/UAV123/wakeboard3", "startFrame": 1, "endFrame": 823, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard3.txt", "object_class": "person"}, + {"name": "uav_wakeboard4", "path": "data_seq/UAV123/wakeboard4", "startFrame": 1, "endFrame": 697, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard4.txt", "object_class": "person"}, + {"name": "uav_wakeboard5", "path": "data_seq/UAV123/wakeboard5", "startFrame": 1, "endFrame": 1675, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard5.txt", "object_class": "person"}, + {"name": "uav_wakeboard6", "path": "data_seq/UAV123/wakeboard6", "startFrame": 1, "endFrame": 1165, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard6.txt", "object_class": "person"}, + {"name": "uav_wakeboard7", "path": "data_seq/UAV123/wakeboard7", "startFrame": 1, "endFrame": 199, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard7.txt", "object_class": "person"}, + {"name": "uav_wakeboard8", "path": "data_seq/UAV123/wakeboard8", "startFrame": 1, "endFrame": 1543, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard8.txt", "object_class": "person"}, + {"name": "uav_wakeboard9", "path": "data_seq/UAV123/wakeboard9", "startFrame": 1, "endFrame": 355, "nz": 6, + "ext": "jpg", "anno_path": "anno/UAV123/wakeboard9.txt", "object_class": "person"} + ] + + return sequence_info_list diff --git a/pytracking/evaluation/vot.py b/pytracking/evaluation/vot.py new file mode 100755 index 0000000..6d2aad1 --- /dev/null +++ b/pytracking/evaluation/vot.py @@ -0,0 +1,174 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016 + +""" + +import sys +import copy +import collections + +try: + import trax + import trax.server + TRAX = True +except ImportError: + TRAX = False + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +def parse_region(string): + tokens = map(float, string.split(',')) + if len(tokens) == 4: + return Rectangle(tokens[0], tokens[1], tokens[2], tokens[3]) + elif len(tokens) % 2 == 0 and len(tokens) > 4: + return Polygon([Point(tokens[i],tokens[i+1]) for i in xrange(0,len(tokens),2)]) + return None + +def encode_region(region): + if isinstance(region, Polygon): + return ','.join(['{},{}'.format(p.x,p.y) for p in region.points]) + elif isinstance(region, Rectangle): + return '{},{},{},{}'.format(region.x, region.y, region.width, region.height) + else: + return "" + +def convert_region(region, to): + + if to == 'rectangle': + + if isinstance(region, Rectangle): + return copy.copy(region) + elif isinstance(region, Polygon): + top = sys.float_info.max + bottom = sys.float_info.min + left = sys.float_info.max + right = sys.float_info.min + + for point in region.points: + top = min(top, point.y) + bottom = max(bottom, point.y) + left = min(left, point.x) + right = max(right, point.x) + + return Rectangle(left, top, right - left, bottom - top) + + else: + return None + if to == 'polygon': + + if isinstance(region, Rectangle): + points = [] + points.append((region.x, region.y)) + points.append((region.x + region.width, region.y)) + points.append((region.x + region.width, region.y + region.height)) + points.append((region.x, region.y + region.height)) + return Polygon(points) + + elif isinstance(region, Polygon): + return copy.copy(region) + else: + return None + + return None + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in ['rectangle', 'polygon']) + if TRAX: + options = trax.server.ServerOptions(region_format, trax.image.PATH) + self._trax = trax.server.Server(options) + + request = self._trax.wait() + assert(request.type == 'initialize') + if request.region.type == 'polygon': + self._region = Polygon([Point(x[0], x[1]) for x in request.region.points]) + else: + self._region = Rectangle(request.region.x, request.region.y, request.region.width, request.region.height) + self._image = str(request.image) + self._trax.status(request.region) + else: + self._files = [x.strip('\n') for x in open('images.txt', 'r').readlines()] + self._frame = 0 + self._region = convert_region(parse_region(open('region.txt', 'r').readline()), region_format) + self._result = [] + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = 0): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, Rectangle) or isinstance(region, Polygon)) + if TRAX: + if isinstance(region, Polygon): + tregion = trax.region.Polygon([(x.x, x.y) for x in region.points]) + else: + tregion = trax.region.Rectangle(region.x, region.y, region.width, region.height) + self._trax.status(tregion, {"confidence" : confidence}) + else: + self._result.append(region) + self._frame += 1 + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if TRAX: + if hasattr(self, "_image"): + image = str(self._image) + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + return str(request.image) + else: + return None + + else: + if self._frame >= len(self._files): + return None + return self._files[self._frame] + + def quit(self): + if TRAX: + self._trax.quit() + elif hasattr(self, '_result'): + with open('output.txt', 'w') as f: + for r in self._result: + f.write(encode_region(r)) + f.write('\n') + + def __del__(self): + self.quit() + diff --git a/pytracking/evaluation/vot2020.py b/pytracking/evaluation/vot2020.py new file mode 100755 index 0000000..8310900 --- /dev/null +++ b/pytracking/evaluation/vot2020.py @@ -0,0 +1,143 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016 + +""" + +import sys +import copy +import collections +import numpy as np + +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + + +def make_full_size(x, output_sz): + ''' + zero-pad input x (right and down) to match output_sz + x: numpy array e.g., binary mask + output_sz: size of the output [width, height] + ''' + if x.shape[0] == output_sz[1] and x.shape[1] == output_sz[0]: + return x + pad_x = output_sz[0] - x.shape[1] + if pad_x < 0: + x = x[:, :x.shape[1] + pad_x] + # padding has to be set to zero, otherwise pad function fails + pad_x = 0 + pad_y = output_sz[1] - x.shape[0] + if pad_y < 0: + x = x[:x.shape[0] + pad_y, :] + # padding has to be set to zero, otherwise pad function fails + pad_y = 0 + return np.pad(x, ((0, pad_y), (0, pad_x)), 'constant', constant_values=0) + + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON, trax.Region.MASK]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels, customMetadata=dict(vot="python")) + + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + if isinstance(request.region, trax.Mask): + self._region = request.region.array(True) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [x.path() for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, (Rectangle, Polygon, np.ndarray))) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + if isinstance(region, np.ndarray): + tregion = trax.Mask.create(region) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + image = [x.path() for k, x in request.image.items()] + if len(image) == 1: + return image[0] + return image + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() diff --git a/pytracking/evaluation/votdataset.py b/pytracking/evaluation/votdataset.py new file mode 100755 index 0000000..f11bc6a --- /dev/null +++ b/pytracking/evaluation/votdataset.py @@ -0,0 +1,122 @@ +import numpy as np +from pytracking.evaluation.data import Sequence, BaseDataset, SequenceList + + +class VOTDataset(BaseDataset): + """ + VOT2018 dataset + + Publication: + The sixth Visual Object Tracking VOT2018 challenge results. + Matej Kristan, Ales Leonardis, Jiri Matas, Michael Felsberg, Roman Pfugfelder, Luka Cehovin Zajc, Tomas Vojir, + Goutam Bhat, Alan Lukezic et al. + ECCV, 2018 + https://prints.vicos.si/publications/365 + + Download the dataset from http://www.votchallenge.net/vot2018/dataset.html + """ + def __init__(self): + super().__init__() + self.base_path = self.env_settings.vot_path + self.sequence_list = self._get_sequence_list() + + def get_sequence_list(self): + return SequenceList([self._construct_sequence(s) for s in self.sequence_list]) + + def _construct_sequence(self, sequence_name): + sequence_path = sequence_name + nz = 8 + ext = 'jpg' + start_frame = 1 + + anno_path = '{}/{}/groundtruth.txt'.format(self.base_path, sequence_name) + try: + ground_truth_rect = np.loadtxt(str(anno_path), dtype=np.float64) + except: + ground_truth_rect = np.loadtxt(str(anno_path), delimiter=',', dtype=np.float64) + + end_frame = ground_truth_rect.shape[0] + + frames = ['{base_path}/{sequence_path}/color/{frame:0{nz}}.{ext}'.format(base_path=self.base_path, + sequence_path=sequence_path, frame=frame_num, nz=nz, ext=ext) + for frame_num in range(start_frame, end_frame+1)] + + # Convert gt + if ground_truth_rect.shape[1] > 4: + gt_x_all = ground_truth_rect[:, [0, 2, 4, 6]] + gt_y_all = ground_truth_rect[:, [1, 3, 5, 7]] + + x1 = np.amin(gt_x_all, 1).reshape(-1,1) + y1 = np.amin(gt_y_all, 1).reshape(-1,1) + x2 = np.amax(gt_x_all, 1).reshape(-1,1) + y2 = np.amax(gt_y_all, 1).reshape(-1,1) + + ground_truth_rect = np.concatenate((x1, y1, x2-x1, y2-y1), 1) + return Sequence(sequence_name, frames, 'vot', ground_truth_rect) + + def __len__(self): + return len(self.sequence_list) + + def _get_sequence_list(self): + sequence_list= ['ants1', + 'ants3', + 'bag', + 'ball1', + 'ball2', + 'basketball', + 'birds1', + 'blanket', + 'bmx', + 'bolt1', + 'bolt2', + 'book', + 'butterfly', + 'car1', + 'conduction1', + 'crabs1', + 'crossing', + 'dinosaur', + 'drone_across', + 'drone_flip', + 'drone1', + 'fernando', + 'fish1', + 'fish2', + 'fish3', + 'flamingo1', + 'frisbee', + 'girl', + 'glove', + 'godfather', + 'graduate', + 'gymnastics1', + 'gymnastics2', + 'gymnastics3', + 'hand', + 'handball1', + 'handball2', + 'helicopter', + 'iceskater1', + 'iceskater2', + 'leaves', + 'matrix', + 'motocross1', + 'motocross2', + 'nature', + 'pedestrian1', + 'rabbit', + 'racing', + 'road', + 'shaking', + 'sheep', + 'singer2', + 'singer3', + 'soccer1', + 'soccer2', + 'soldier', + 'tiger', + 'traffic', + 'wiper', + 'zebrafish1'] + + return sequence_list diff --git a/pytracking/experiments/__init__.py b/pytracking/experiments/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/experiments/myexperiments.py b/pytracking/experiments/myexperiments.py new file mode 100755 index 0000000..afe2a02 --- /dev/null +++ b/pytracking/experiments/myexperiments.py @@ -0,0 +1,19 @@ +from pytracking.evaluation import Tracker, get_dataset, trackerlist + + +def atom_nfs_uav(): + # Run three runs of ATOM on NFS and UAV datasets + trackers = trackerlist('atom', 'default', range(3)) + + dataset = get_dataset('nfs', 'uav') + return trackers, dataset + + +def uav_test(): + # Run DiMP18, ATOM and ECO on the UAV dataset + trackers = trackerlist('dimp', 'dimp18', range(1)) + \ + trackerlist('atom', 'default', range(1)) + \ + trackerlist('eco', 'default', range(1)) + + dataset = get_dataset('uav') + return trackers, dataset diff --git a/pytracking/features/__init__.py b/pytracking/features/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/features/__pycache__/__init__.cpython-37.pyc b/pytracking/features/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..226727c Binary files /dev/null and b/pytracking/features/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/features/__pycache__/augmentation.cpython-37.pyc b/pytracking/features/__pycache__/augmentation.cpython-37.pyc new file mode 100755 index 0000000..7d78129 Binary files /dev/null and b/pytracking/features/__pycache__/augmentation.cpython-37.pyc differ diff --git a/pytracking/features/__pycache__/net_wrappers.cpython-37.pyc b/pytracking/features/__pycache__/net_wrappers.cpython-37.pyc new file mode 100755 index 0000000..f2790d1 Binary files /dev/null and b/pytracking/features/__pycache__/net_wrappers.cpython-37.pyc differ diff --git a/pytracking/features/__pycache__/preprocessing.cpython-37.pyc b/pytracking/features/__pycache__/preprocessing.cpython-37.pyc new file mode 100755 index 0000000..d7ffd33 Binary files /dev/null and b/pytracking/features/__pycache__/preprocessing.cpython-37.pyc differ diff --git a/pytracking/features/augmentation.py b/pytracking/features/augmentation.py new file mode 100755 index 0000000..95dc4f3 --- /dev/null +++ b/pytracking/features/augmentation.py @@ -0,0 +1,232 @@ +import numpy as np +import math +import torch +import torch.nn.functional as F +import cv2 as cv +import random +from pytracking.features.preprocessing import numpy_to_torch, torch_to_numpy + + +class Transform: + """Base data augmentation transform class.""" + + def __init__(self, output_sz = None, shift = None): + self.output_sz = output_sz + self.shift = (0,0) if shift is None else shift + + def __call__(self, image, is_mask=False): + raise NotImplementedError + + def crop_to_output(self, image): + if isinstance(image, torch.Tensor): + imsz = image.shape[2:] + if self.output_sz is None: + pad_h = 0 + pad_w = 0 + else: + pad_h = (self.output_sz[0] - imsz[0]) / 2 + pad_w = (self.output_sz[1] - imsz[1]) / 2 + + pad_left = math.floor(pad_w) + self.shift[1] + pad_right = math.ceil(pad_w) - self.shift[1] + pad_top = math.floor(pad_h) + self.shift[0] + pad_bottom = math.ceil(pad_h) - self.shift[0] + + return F.pad(image, (pad_left, pad_right, pad_top, pad_bottom), 'replicate') + else: + raise NotImplementedError + +class Identity(Transform): + """Identity transformation.""" + def __call__(self, image, is_mask=False): + return self.crop_to_output(image) + +class FlipHorizontal(Transform): + """Flip along horizontal axis.""" + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image.flip((3,))) + else: + return np.fliplr(image) + +class FlipVertical(Transform): + """Flip along vertical axis.""" + def __call__(self, image: torch.Tensor, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image.flip((2,))) + else: + return np.flipud(image) + +class Translation(Transform): + """Translate.""" + def __init__(self, translation, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.shift = (self.shift[0] + translation[0], self.shift[1] + translation[1]) + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(image) + else: + raise NotImplementedError + +class Scale(Transform): + """Scale.""" + def __init__(self, scale_factor, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.scale_factor = scale_factor + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + # Calculate new size. Ensure that it is even so that crop/pad becomes easier + h_orig, w_orig = image.shape[2:] + + if h_orig != w_orig: + raise NotImplementedError + + h_new = round(h_orig /self.scale_factor) + h_new += (h_new - h_orig) % 2 + w_new = round(w_orig /self.scale_factor) + w_new += (w_new - w_orig) % 2 + + image_resized = F.interpolate(image, [h_new, w_new], mode='bilinear') + + return self.crop_to_output(image_resized) + else: + raise NotImplementedError + + +class Affine(Transform): + """Affine transformation.""" + def __init__(self, transform_matrix, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.transform_matrix = transform_matrix + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(numpy_to_torch(self(torch_to_numpy(image)))) + else: + return cv.warpAffine(image, self.transform_matrix, image.shape[1::-1], borderMode=cv.BORDER_REPLICATE) + + +class Rotate(Transform): + """Rotate with given angle.""" + def __init__(self, angle, output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.angle = math.pi * angle/180 + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + return self.crop_to_output(numpy_to_torch(self(torch_to_numpy(image)))) + else: + c = (np.expand_dims(np.array(image.shape[:2]),1)-1)/2 + R = np.array([[math.cos(self.angle), math.sin(self.angle)], + [-math.sin(self.angle), math.cos(self.angle)]]) + H =np.concatenate([R, c - R @ c], 1) + return cv.warpAffine(image, H, image.shape[1::-1], borderMode=cv.BORDER_REPLICATE) + + +class Blur(Transform): + """Blur with given sigma (can be axis dependent).""" + def __init__(self, sigma, output_sz = None, shift = None): + super().__init__(output_sz, shift) + if isinstance(sigma, (float, int)): + sigma = (sigma, sigma) + self.sigma = sigma + self.filter_size = [math.ceil(2*s) for s in self.sigma] + x_coord = [torch.arange(-sz, sz+1, dtype=torch.float32) for sz in self.filter_size] + self.filter = [torch.exp(-(x**2)/(2*s**2)) for x, s in zip(x_coord, self.sigma)] + self.filter[0] = self.filter[0].view(1,1,-1,1) / self.filter[0].sum() + self.filter[1] = self.filter[1].view(1,1,1,-1) / self.filter[1].sum() + + def __call__(self, image, is_mask=False): + if isinstance(image, torch.Tensor): + sz = image.shape[2:] + im1 = F.conv2d(image.view(-1,1,sz[0],sz[1]), self.filter[0], padding=(self.filter_size[0],0)) + return self.crop_to_output(F.conv2d(im1, self.filter[1], padding=(0,self.filter_size[1])).view(1,-1,sz[0],sz[1])) + else: + raise NotImplementedError + + +class RandomAffine(Transform): + """Affine transformation.""" + def __init__(self, p_flip=0.0, max_rotation=0.0, max_shear=0.0, max_scale=0.0, max_ar_factor=0.0, + border_mode='constant', output_sz = None, shift = None): + super().__init__(output_sz, shift) + self.p_flip = p_flip + self.max_rotation = max_rotation + self.max_shear = max_shear + self.max_scale = max_scale + self.max_ar_factor = max_ar_factor + + self.pad_amount = 0 + if border_mode == 'constant': + self.border_flag = cv.BORDER_CONSTANT + elif border_mode == 'replicate': + self.border_flag == cv.BORDER_REPLICATE + else: + raise Exception + + self.roll_values = self.roll() + + def roll(self): + do_flip = random.random() < self.p_flip + theta = random.uniform(-self.max_rotation, self.max_rotation) + + shear_x = random.uniform(-self.max_shear, self.max_shear) + shear_y = random.uniform(-self.max_shear, self.max_shear) + + ar_factor = np.exp(random.uniform(-self.max_ar_factor, self.max_ar_factor)) + scale_factor = np.exp(random.uniform(-self.max_scale, self.max_scale)) + + return do_flip, theta, (shear_x, shear_y), (scale_factor, scale_factor * ar_factor) + + def _construct_t_mat(self, image_shape, do_flip, theta, shear_values, scale_factors): + im_h, im_w = image_shape + t_mat = np.identity(3) + + if do_flip: + if do_flip: + t_mat[0, 0] = -1.0 + t_mat[0, 2] = im_w + + t_rot = cv.getRotationMatrix2D((im_w * 0.5, im_h * 0.5), theta, 1.0) + t_rot = np.concatenate((t_rot, np.array([0.0, 0.0, 1.0]).reshape(1, 3))) + + t_shear = np.array([[1.0, shear_values[0], -shear_values[0] * 0.5 * im_w], + [shear_values[1], 1.0, -shear_values[1] * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_scale = np.array([[scale_factors[0], 0.0, (1.0 - scale_factors[0]) * 0.5 * im_w], + [0.0, scale_factors[1], (1.0 - scale_factors[1]) * 0.5 * im_h], + [0.0, 0.0, 1.0]]) + + t_mat = t_scale @ t_rot @ t_shear @ t_mat + + t_mat[0, 2] += self.pad_amount + t_mat[1, 2] += self.pad_amount + + t_mat = t_mat[:2, :] + + return t_mat + + def __call__(self, image, is_mask=False): + input_tensor = torch.is_tensor(image) + if input_tensor: + image = torch_to_numpy(image) + + do_flip, theta, shear_values, scale_factors = self.roll_values + t_mat = self._construct_t_mat(image.shape[:2], do_flip, theta, shear_values, scale_factors) + output_sz = (image.shape[1] + 2*self.pad_amount, image.shape[0] + 2*self.pad_amount) + + if not is_mask: + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_LINEAR, + borderMode=self.border_flag) + else: + image_t = cv.warpAffine(image, t_mat, output_sz, flags=cv.INTER_NEAREST, + borderMode=self.border_flag) + image_t = image_t.reshape(image.shape) + + if input_tensor: + image_t = numpy_to_torch(image_t) + + return self.crop_to_output(image_t) diff --git a/pytracking/features/color.py b/pytracking/features/color.py new file mode 100755 index 0000000..c24cbac --- /dev/null +++ b/pytracking/features/color.py @@ -0,0 +1,26 @@ +import torch +from pytracking.features.featurebase import FeatureBase + + +class RGB(FeatureBase): + """RGB feature normalized to [-0.5, 0.5].""" + def dim(self): + return 3 + + def stride(self): + return self.pool_stride + + def extract(self, im: torch.Tensor): + return im/255 - 0.5 + + +class Grayscale(FeatureBase): + """Grayscale feature normalized to [-0.5, 0.5].""" + def dim(self): + return 1 + + def stride(self): + return self.pool_stride + + def extract(self, im: torch.Tensor): + return torch.mean(im/255 - 0.5, 1, keepdim=True) diff --git a/pytracking/features/deep.py b/pytracking/features/deep.py new file mode 100755 index 0000000..ab5f530 --- /dev/null +++ b/pytracking/features/deep.py @@ -0,0 +1,220 @@ +from pytracking.features.featurebase import FeatureBase, MultiFeatureBase +import torch +import torchvision +from pytracking import TensorList +from pytracking.evaluation.environment import env_settings +import os +from pytracking.utils.loading import load_network +from ltr.models.backbone.resnet18_vggm import resnet18_vggmconv1 +from ltr.models.backbone.mobilenetv3 import mobilenet3 + +normalize = torchvision.transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + + +class ResNet18m1(MultiFeatureBase): + """ResNet18 feature together with the VGG-m conv1 layer. + args: + output_layers: List of layers to output. + net_path: Relative or absolute net path (default should be fine). + use_gpu: Use GPU or CPU. + """ + + def __init__(self, output_layers, net_path=None, use_gpu=True, *args, **kwargs): + super(ResNet18m1, self).__init__(*args, **kwargs) + + for l in output_layers: + if l not in ['vggconv1', 'conv1', 'layer1', 'layer2', 'layer3', 'layer4', 'fc']: + raise ValueError('Unknown layer') + + self.output_layers = list(output_layers) + self.use_gpu = use_gpu + self.net_path = 'resnet18_vggmconv1/resnet18_vggmconv1.pth' if net_path is None else net_path + + def initialize(self): + + if isinstance(self.pool_stride, int) and self.pool_stride == 1: + self.pool_stride = [1] * len(self.output_layers) + + self.layer_stride = {'vggconv1': 2, 'conv1': 2, 'layer1': 4, 'layer2': 8, 'layer3': 16, 'layer4': 32, + 'fc': None} + self.layer_dim = {'vggconv1': 96, 'conv1': 64, 'layer1': 64, 'layer2': 128, 'layer3': 256, 'layer4': 512, + 'fc': None} + + self.mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1) + self.std = torch.Tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1) + + if os.path.isabs(self.net_path): + net_path_full = [self.net_path] + else: + root_paths = env_settings().network_path + if isinstance(root_paths, str): + root_paths = [root_paths] + net_path_full = [os.path.join(root, self.net_path) for root in root_paths] + + self.net = None + for net_path in net_path_full: + try: + self.net = resnet18_vggmconv1(self.output_layers, path=net_path) + break + except: + pass + if self.net is None: + raise Exception('Did not find network file {}'.format(self.net_path)) + + if self.use_gpu: + self.net.cuda() + self.net.eval() + + def dim(self): + return TensorList([self.layer_dim[l] for l in self.output_layers]) + + def stride(self): + return TensorList([s * self.layer_stride[l] for l, s in zip(self.output_layers, self.pool_stride)]) + + def extract(self, im: torch.Tensor): + im = im / 255 + im -= self.mean + im /= self.std + + if self.use_gpu: + im = im.cuda() + + with torch.no_grad(): + return TensorList(self.net(im).values()) + +class Mobilenet(MultiFeatureBase): + """ResNet18 feature together with the VGG-m conv1 layer. + args: + output_layers: List of layers to output. + net_path: Relative or absolute net path (default should be fine). + use_gpu: Use GPU or CPU. + """ + + def __init__(self, output_layers, net_path=None, use_gpu=True, *args, **kwargs): + super(ResNet18m1, self).__init__(*args, **kwargs) + + for l in output_layers: + if l not in ['init_conv','layer1', 'layer2', 'layer3', 'layer4', 'layer5','layer6','layer_out']: + raise ValueError('Unknown layer') + + self.output_layers = list(output_layers) + self.use_gpu = use_gpu + self.net_path = 'mobilev3_test.t7' if net_path is None else net_path + + def initialize(self): + + if isinstance(self.pool_stride, int) and self.pool_stride == 1: + self.pool_stride = [1] * len(self.output_layers) + + self.layer_stride = {'init_conv': 2, 'layer1': 2, 'layer2': 4, 'layer3': 8, 'layer4': 16, 'layer5': 16,'layer6': 32, 'layer_out': 32} + self.layer_dim = {'init_conv': 16, 'layer1': 16, 'layer2': 24, 'layer3': 40, 'layer4': 80, 'layer5': 112,'layer6': 160, 'layer_out': 960} + + + self.mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1) + self.std = torch.Tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1) + + if os.path.isabs(self.net_path): + net_path_full = [self.net_path] + else: + root_paths = env_settings().network_path + if isinstance(root_paths, str): + root_paths = [root_paths] + net_path_full = [os.path.join(root, self.net_path) for root in root_paths] + + self.net = None + for net_path in net_path_full: + try: + self.net = mobilenet3(self.output_layers, path=net_path_full) + break + except: + pass + if self.net is None: + raise Exception('Did not find network file {}'.format(self.net_path)) + + if self.use_gpu: + self.net.cuda() + self.net.eval() + + def dim(self): + return TensorList([self.layer_dim[l] for l in self.output_layers]) + + def stride(self): + return TensorList([s * self.layer_stride[l] for l, s in zip(self.output_layers, self.pool_stride)]) + + def extract(self, im: torch.Tensor): + im = im / 255 + im -= self.mean + im /= self.std + + if self.use_gpu: + im = im.cuda() + + with torch.no_grad(): + return TensorList(self.net(im).values()) + +class ATOMResNet18(MultiFeatureBase): + """ResNet18 feature with the ATOM IoUNet. + args: + output_layers: List of layers to output. + net_path: Relative or absolute net path (default should be fine). + use_gpu: Use GPU or CPU. + """ + + def __init__(self, output_layers=('layer3',), net_path='atom_iou', use_gpu=True, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.output_layers = list(output_layers) + self.use_gpu = use_gpu + self.net_path = net_path + + def initialize(self): + self.net = load_network(self.net_path) + + if self.use_gpu: + self.net.cuda() + self.net.eval() + + self.iou_predictor = self.net.bb_regressor + + self.layer_stride = {'conv1': 2, 'layer1': 4, 'layer2': 8, 'layer3': 16, 'layer4': 32, 'classification': 16, + 'fc': None} + self.layer_dim = {'conv1': 64, 'layer1': 64, 'layer2': 128, 'layer3': 256, 'layer4': 512, 'classification': 256, + 'fc': None} + + self.iounet_feature_layers = self.net.bb_regressor_layer + + if isinstance(self.pool_stride, int) and self.pool_stride == 1: + self.pool_stride = [1] * len(self.output_layers) + + self.feature_layers = sorted(list(set(self.output_layers + self.iounet_feature_layers))) + + self.mean = torch.Tensor([0.485, 0.456, 0.406]).view(1, -1, 1, 1) + self.std = torch.Tensor([0.229, 0.224, 0.225]).view(1, -1, 1, 1) + + def dim(self): + return TensorList([self.layer_dim[l] for l in self.output_layers]) + + def stride(self): + return TensorList([s * self.layer_stride[l] for l, s in zip(self.output_layers, self.pool_stride)]) + + def extract(self, im: torch.Tensor): + im = im / 255 + im -= self.mean + im /= self.std + + if self.use_gpu: + im = im.cuda() + + with torch.no_grad(): + output_features = self.net.extract_features(im, self.feature_layers) + + # Store the raw resnet features which are input to iounet + self.iounet_backbone_features = TensorList( + [output_features[layer].clone() for layer in self.iounet_feature_layers]) + + # Store the processed features from iounet, just before pooling + with torch.no_grad(): + self.iounet_features = TensorList(self.iou_predictor.get_iou_feat(self.iounet_backbone_features)) + + return TensorList([output_features[layer] for layer in self.output_layers]) diff --git a/pytracking/features/extractor.py b/pytracking/features/extractor.py new file mode 100755 index 0000000..032b1a4 --- /dev/null +++ b/pytracking/features/extractor.py @@ -0,0 +1,143 @@ +import torch +from pytracking.features.preprocessing import sample_patch +from pytracking import TensorList + +class ExtractorBase: + """Base feature extractor class. + args: + features: List of features. + """ + def __init__(self, features): + self.features = features + + def initialize(self): + for f in self.features: + f.initialize() + + +class SingleResolutionExtractor(ExtractorBase): + """Single resolution feature extractor. + args: + features: List of features. + """ + def __init__(self, features): + super().__init__(features) + + self.feature_stride = self.features[0].stride() + if isinstance(self.feature_stride, (list, TensorList)): + self.feature_stride = self.feature_stride[0] + + def stride(self): + return self.feature_stride + + def size(self, input_sz): + return input_sz // self.stride() + + def extract(self, im, pos, scales, image_sz): + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + im_patches = torch.cat([sample_patch(im, pos, s*image_sz, image_sz) for s in scales]) + + # Compute features + feature_map = torch.cat(TensorList([f.get_feature(im_patches) for f in self.features]).unroll(), dim=1) + + return feature_map + + +class MultiResolutionExtractor(ExtractorBase): + """Multi-resolution feature extractor. + args: + features: List of features. + """ + def __init__(self, features, patch_mode='replicate', max_scale_change=None): + super().__init__(features) + self.patch_mode = patch_mode + self.max_scale_change = max_scale_change + self.is_color = None + + def stride(self): + return torch.Tensor(TensorList([f.stride() for f in self.features if self._return_feature(f)]).unroll().list()) + + def size(self, input_sz): + return TensorList([f.size(input_sz) for f in self.features if self._return_feature(f)]).unroll() + + def dim(self): + return TensorList([f.dim() for f in self.features if self._return_feature(f)]).unroll() + + def get_fparams(self, name: str = None): + if name is None: + return [f.fparams for f in self.features if self._return_feature(f)] + return TensorList([getattr(f.fparams, name) for f in self.features if self._return_feature(f)]).unroll() + + def get_attribute(self, name: str, ignore_missing: bool = False): + if ignore_missing: + return TensorList([getattr(f, name) for f in self.features if self._return_feature(f) and hasattr(f, name)]) + else: + return TensorList([getattr(f, name, None) for f in self.features if self._return_feature(f)]) + + def get_unique_attribute(self, name: str): + feat = None + for f in self.features: + if self._return_feature(f) and hasattr(f, name): + if feat is not None: + raise RuntimeError('The attribute was not unique.') + feat = f + if feat is None: + raise RuntimeError('The attribute did not exist') + return getattr(feat, name) + + def _return_feature(self, f): + return self.is_color is None or self.is_color and f.use_for_color or not self.is_color and f.use_for_gray + + def set_is_color(self, is_color: bool): + self.is_color = is_color + + def extract(self, im, pos, scales, image_sz, return_patches=False): + """Extract features. + args: + im: Image. + pos: Center position for extraction. + scales: Image scales to extract features from. + image_sz: Size to resize the image samples to before extraction. + """ + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + patch_iter, coord_iter = zip(*(sample_patch(im, pos, s*image_sz, image_sz, mode=self.patch_mode, + max_scale_change=self.max_scale_change) for s in scales)) + im_patches = torch.cat(list(patch_iter)) + patch_coords = torch.cat(list(coord_iter)) + + # im_patches = torch.cat([sample_patch(im, pos, s*image_sz, image_sz) for s in scales]) + + # Compute features + feature_map = TensorList([f.get_feature(im_patches) for f in self.features]).unroll() + + if return_patches: + return feature_map, patch_coords, im_patches + else: + return feature_map, patch_coords + + def extract_transformed(self, im, pos, scale, image_sz, transforms): + """Extract features from a set of transformed image samples. + args: + im: Image. + pos: Center position for extraction. + scale: Image scale to extract features from. + image_sz: Size to resize the image samples to before extraction. + transforms: A set of image transforms to apply. + """ + + # Get image patche + im_patch, _ = sample_patch(im, pos, scale*image_sz, image_sz) + + # Apply transforms + im_patches = torch.cat([T(im_patch) for T in transforms]) + + # Compute features + feature_map = TensorList([f.get_feature(im_patches) for f in self.features]).unroll() + + return feature_map diff --git a/pytracking/features/featurebase.py b/pytracking/features/featurebase.py new file mode 100755 index 0000000..cdd5130 --- /dev/null +++ b/pytracking/features/featurebase.py @@ -0,0 +1,110 @@ +import torch +import torch.nn.functional as F +from pytracking import TensorList + + +class FeatureBase: + """Base feature class. + args: + fparams: Feature specific parameters. + pool_stride: Amount of average pooling to apply do downsample the feature map. + output_size: Alternatively, specify the output size of the feature map. Adaptive average pooling will be applied. + normalize_power: The power exponent for the normalization. None means no normalization (default). + use_for_color: Use this feature for color images. + use_for_gray: Use this feature for grayscale images. + """ + def __init__(self, fparams = None, pool_stride = None, output_size = None, normalize_power = None, use_for_color = True, use_for_gray = True): + self.fparams = fparams + self.pool_stride = 1 if pool_stride is None else pool_stride + self.output_size = output_size + self.normalize_power = normalize_power + self.use_for_color = use_for_color + self.use_for_gray = use_for_gray + + def initialize(self): + pass + + def dim(self): + raise NotImplementedError + + def stride(self): + raise NotImplementedError + + def size(self, im_sz): + if self.output_size is None: + return im_sz // self.stride() + if isinstance(im_sz, torch.Tensor): + return torch.Tensor([self.output_size[0], self.output_size[1]]) + return self.output_size + + def extract(self, im): + """Performs feature extraction.""" + raise NotImplementedError + + def get_feature(self, im: torch.Tensor): + """Get the feature. Generally, call this function. + args: + im: image patch as a torch.Tensor. + """ + + # Return empty tensor if it should not be used + is_color = im.shape[1] == 3 + if is_color and not self.use_for_color or not is_color and not self.use_for_gray: + return torch.Tensor([]) + + # Extract feature + feat = self.extract(im) + + # Pool/downsample + if self.output_size is not None: + feat = F.adaptive_avg_pool2d(feat, self.output_size) + elif self.pool_stride != 1: + feat = F.avg_pool2d(feat, self.pool_stride, self.pool_stride) + + # Normalize + if self.normalize_power is not None: + feat /= (torch.sum(feat.abs().view(feat.shape[0],1,1,-1)**self.normalize_power, dim=3, keepdim=True) / + (feat.shape[1]*feat.shape[2]*feat.shape[3]) + 1e-10)**(1/self.normalize_power) + + return feat + + +class MultiFeatureBase(FeatureBase): + """Base class for features potentially having multiple feature blocks as output (like CNNs). + See FeatureBase for more info. + """ + def size(self, im_sz): + if self.output_size is None: + return TensorList([im_sz // s for s in self.stride()]) + if isinstance(im_sz, torch.Tensor): + return TensorList([im_sz // s if sz is None else torch.Tensor([sz[0], sz[1]]) for sz, s in zip(self.output_size, self.stride())]) + + def get_feature(self, im: torch.Tensor): + """Get the feature. Generally, call this function. + args: + im: image patch as a torch.Tensor. + """ + + # Return empty tensor if it should not be used + is_color = im.shape[1] == 3 + if is_color and not self.use_for_color or not is_color and not self.use_for_gray: + return torch.Tensor([]) + + feat_list = self.extract(im) + + output_sz = [None]*len(feat_list) if self.output_size is None else self.output_size + + # Pool/downsample + for i, (sz, s) in enumerate(zip(output_sz, self.pool_stride)): + if sz is not None: + feat_list[i] = F.adaptive_avg_pool2d(feat_list[i], sz) + elif s != 1: + feat_list[i] = F.avg_pool2d(feat_list[i], s, s) + + # Normalize + if self.normalize_power is not None: + for feat in feat_list: + feat /= (torch.sum(feat.abs().view(feat.shape[0],1,1,-1)**self.normalize_power, dim=3, keepdim=True) / + (feat.shape[1]*feat.shape[2]*feat.shape[3]) + 1e-10)**(1/self.normalize_power) + + return feat_list \ No newline at end of file diff --git a/pytracking/features/net_wrappers.py b/pytracking/features/net_wrappers.py new file mode 100755 index 0000000..e1614d9 --- /dev/null +++ b/pytracking/features/net_wrappers.py @@ -0,0 +1,75 @@ +import torch +from pytracking.utils.loading import load_network + + +class NetWrapper: + """Used for wrapping networks in pytracking. + Network modules and functions can be accessed directly as if they were members of this class.""" + _rec_iter=0 + def __init__(self, net_path, use_gpu=True, initialize=False, **kwargs): + self.net_path = net_path + self.use_gpu = use_gpu + self.net = None + self.net_kwargs = kwargs + if initialize: + self.initialize() + + def __getattr__(self, name): + if self._rec_iter > 0: + self._rec_iter = 0 + return None + self._rec_iter += 1 + try: + ret_val = getattr(self.net, name) + except Exception as e: + self._rec_iter = 0 + raise e + self._rec_iter = 0 + return ret_val + + def load_network(self): + self.net = load_network(self.net_path, **self.net_kwargs) + if self.use_gpu: + self.cuda() + self.eval() + + def initialize(self): + self.load_network() + + +class NetWithBackbone(NetWrapper): + """Wraps a network with a common backbone. + Assumes the network have a 'extract_backbone_features(image)' function.""" + + def __init__(self, net_path, use_gpu=True, initialize=False, image_format='rgb', + mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), **kwargs): + super().__init__(net_path, use_gpu, initialize, **kwargs) + + self.image_format = image_format + self._mean = torch.Tensor(mean).view(1, -1, 1, 1) + self._std = torch.Tensor(std).view(1, -1, 1, 1) + + def initialize(self, image_format='rgb', mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)): + super().initialize() + + def preprocess_image(self, im: torch.Tensor): + """Normalize the image with the mean and standard deviation used by the network.""" + + if self.image_format in ['rgb', 'bgr']: + im = im/255 + + if self.image_format in ['bgr', 'bgr255']: + im = im[:, [2, 1, 0], :, :] + im -= self._mean + im /= self._std + + if self.use_gpu: + im = im.cuda() + + return im + + def extract_backbone(self, im: torch.Tensor): + """Extract backbone features from the network. + Expects a float tensor image with pixel range [0, 255].""" + im = self.preprocess_image(im) + return self.net.extract_backbone_features(im) diff --git a/pytracking/features/preprocessing.py b/pytracking/features/preprocessing.py new file mode 100755 index 0000000..f9a54c4 --- /dev/null +++ b/pytracking/features/preprocessing.py @@ -0,0 +1,145 @@ +import torch +import torch.nn.functional as F +import numpy as np + + +def numpy_to_torch(a: np.ndarray): + return torch.from_numpy(a).float().permute(2, 0, 1).unsqueeze(0) + + +def torch_to_numpy(a: torch.Tensor): + return a.squeeze(0).permute(1,2,0).numpy() + + +def sample_patch_transformed(im, pos, scale, image_sz, transforms, is_mask=False): + """Extract transformed image samples. + args: + im: Image. + pos: Center position for extraction. + scale: Image scale to extract features from. + image_sz: Size to resize the image samples to before extraction. + transforms: A set of image transforms to apply. + """ + + # Get image patche + im_patch, _ = sample_patch(im, pos, scale*image_sz, image_sz, is_mask=is_mask) + + # Apply transforms + im_patches = torch.cat([T(im_patch, is_mask=is_mask) for T in transforms]) + + return im_patches + + +def sample_patch_multiscale(im, pos, scales, image_sz, mode: str='replicate', max_scale_change=None): + """Extract image patches at multiple scales. + args: + im: Image. + pos: Center position for extraction. + scales: Image scales to extract image patches from. + image_sz: Size to resize the image samples to + mode: how to treat image borders: 'replicate' (default), 'inside' or 'inside_major' + max_scale_change: maximum allowed scale change when using 'inside' and 'inside_major' mode + """ + if isinstance(scales, (int, float)): + scales = [scales] + + # Get image patches + patch_iter, coord_iter = zip(*(sample_patch(im, pos, s*image_sz, image_sz, mode=mode, + max_scale_change=max_scale_change) for s in scales)) + im_patches = torch.cat(list(patch_iter)) + patch_coords = torch.cat(list(coord_iter)) + + return im_patches, patch_coords + + +def sample_patch(im: torch.Tensor, pos: torch.Tensor, sample_sz: torch.Tensor, output_sz: torch.Tensor = None, + mode: str = 'replicate', max_scale_change=None, is_mask=False): + """Sample an image patch. + + args: + im: Image + pos: center position of crop + sample_sz: size to crop + output_sz: size to resize to + mode: how to treat image borders: 'replicate' (default), 'inside' or 'inside_major' + max_scale_change: maximum allowed scale change when using 'inside' and 'inside_major' mode + """ + + # if mode not in ['replicate', 'inside']: + # raise ValueError('Unknown border mode \'{}\'.'.format(mode)) + + # copy and convert + posl = pos.long().clone() + + pad_mode = mode + + # Get new sample size if forced inside the image + if mode == 'inside' or mode == 'inside_major': + pad_mode = 'replicate' + im_sz = torch.Tensor([im.shape[2], im.shape[3]]) + shrink_factor = (sample_sz.float() / im_sz) + if mode == 'inside': + shrink_factor = shrink_factor.max() + elif mode == 'inside_major': + shrink_factor = shrink_factor.min() + shrink_factor.clamp_(min=1, max=max_scale_change) + sample_sz = (sample_sz.float() / shrink_factor).long() + + # Compute pre-downsampling factor + if output_sz is not None: + resize_factor = torch.min(sample_sz.float() / output_sz.float()).item() + df = int(max(int(resize_factor - 0.1), 1)) + else: + df = int(1) + + sz = sample_sz.float() / df # new size + + # Do downsampling + if df > 1: + os = posl % df # offset + posl = (posl - os) / df # new position + im2 = im[..., os[0].item()::df, os[1].item()::df] # downsample + else: + im2 = im + + # compute size to crop + szl = torch.max(sz.round(), torch.Tensor([2])).long() + + # Extract top and bottom coordinates + tl = posl - (szl - 1)/2 + br = posl + szl/2 + 1 + + # Shift the crop to inside + if mode == 'inside' or mode == 'inside_major': + im2_sz = torch.LongTensor([im2.shape[2], im2.shape[3]]) + shift = (-tl).clamp(0) - (br - im2_sz).clamp(0) + tl += shift + br += shift + + outside = ((-tl).clamp(0) + (br - im2_sz).clamp(0)) // 2 + shift = (-tl - outside) * (outside > 0).long() + tl += shift + br += shift + + # Get image patch + # im_patch = im2[...,tl[0].item():br[0].item(),tl[1].item():br[1].item()] + + # Get image patch + if not is_mask: + im_patch = F.pad(im2, (-tl[1].item(), br[1].item() - im2.shape[3], -tl[0].item(), br[0].item() - im2.shape[2]), pad_mode) + else: + im_patch = F.pad(im2, (-tl[1].item(), br[1].item() - im2.shape[3], -tl[0].item(), br[0].item() - im2.shape[2])) + + # Get image coordinates + patch_coord = df * torch.cat((tl, br)).view(1,4) + + if output_sz is None or (im_patch.shape[-2] == output_sz[0] and im_patch.shape[-1] == output_sz[1]): + return im_patch.clone(), patch_coord + + # Resample + if not is_mask: + im_patch = F.interpolate(im_patch, output_sz.long().tolist(), mode='bilinear') + else: + im_patch = F.interpolate(im_patch, output_sz.long().tolist(), mode='nearest') + + return im_patch, patch_coord diff --git a/pytracking/features/util.py b/pytracking/features/util.py new file mode 100755 index 0000000..6f546b6 --- /dev/null +++ b/pytracking/features/util.py @@ -0,0 +1,27 @@ +import torch +from pytracking.features.featurebase import FeatureBase + + +class Concatenate(FeatureBase): + """A feature that concatenates other features. + args: + features: List of features to concatenate. + """ + def __init__(self, features, pool_stride = None, normalize_power = None, use_for_color = True, use_for_gray = True): + super(Concatenate, self).__init__(pool_stride, normalize_power, use_for_color, use_for_gray) + self.features = features + + self.input_stride = self.features[0].stride() + + for feat in self.features: + if self.input_stride != feat.stride(): + raise ValueError('Strides for the features must be the same for a bultiresolution feature.') + + def dim(self): + return sum([f.dim() for f in self.features]) + + def stride(self): + return self.pool_stride * self.input_stride + + def extract(self, im: torch.Tensor): + return torch.cat([f.get_feature(im) for f in self.features], 1) \ No newline at end of file diff --git a/pytracking/libs/__init__.py b/pytracking/libs/__init__.py new file mode 100755 index 0000000..0b47e6b --- /dev/null +++ b/pytracking/libs/__init__.py @@ -0,0 +1,2 @@ +from .tensorlist import TensorList +from .tensordict import TensorDict \ No newline at end of file diff --git a/pytracking/libs/__pycache__/__init__.cpython-37.pyc b/pytracking/libs/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..45eacd6 Binary files /dev/null and b/pytracking/libs/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/complex.cpython-37.pyc b/pytracking/libs/__pycache__/complex.cpython-37.pyc new file mode 100755 index 0000000..a75efc0 Binary files /dev/null and b/pytracking/libs/__pycache__/complex.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/dcf.cpython-37.pyc b/pytracking/libs/__pycache__/dcf.cpython-37.pyc new file mode 100755 index 0000000..17e173b Binary files /dev/null and b/pytracking/libs/__pycache__/dcf.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/fourier.cpython-37.pyc b/pytracking/libs/__pycache__/fourier.cpython-37.pyc new file mode 100755 index 0000000..66e2ce1 Binary files /dev/null and b/pytracking/libs/__pycache__/fourier.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/operation.cpython-37.pyc b/pytracking/libs/__pycache__/operation.cpython-37.pyc new file mode 100755 index 0000000..96fbb1a Binary files /dev/null and b/pytracking/libs/__pycache__/operation.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/optimization.cpython-37.pyc b/pytracking/libs/__pycache__/optimization.cpython-37.pyc new file mode 100755 index 0000000..f097d8a Binary files /dev/null and b/pytracking/libs/__pycache__/optimization.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/tensordict.cpython-37.pyc b/pytracking/libs/__pycache__/tensordict.cpython-37.pyc new file mode 100755 index 0000000..c22df7f Binary files /dev/null and b/pytracking/libs/__pycache__/tensordict.cpython-37.pyc differ diff --git a/pytracking/libs/__pycache__/tensorlist.cpython-37.pyc b/pytracking/libs/__pycache__/tensorlist.cpython-37.pyc new file mode 100755 index 0000000..cf379c0 Binary files /dev/null and b/pytracking/libs/__pycache__/tensorlist.cpython-37.pyc differ diff --git a/pytracking/libs/complex.py b/pytracking/libs/complex.py new file mode 100755 index 0000000..917e342 --- /dev/null +++ b/pytracking/libs/complex.py @@ -0,0 +1,211 @@ +import torch +from pytracking.libs.tensorlist import tensor_operation + + +def is_complex(a: torch.Tensor) -> bool: + return a.dim() >= 4 and a.shape[-1] == 2 + + +def is_real(a: torch.Tensor) -> bool: + return not is_complex(a) + + +@tensor_operation +def mult(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of complex tensors.""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + # a is real + return mult_real_cplx(a, b) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return mult_real_cplx(b, a) + + # Both complex + c = mult_real_cplx(a[..., 0], b) + c[..., 0] -= a[..., 1] * b[..., 1] + c[..., 1] += a[..., 1] * b[..., 0] + return c + + +@tensor_operation +def mult_conj(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of complex tensors, with conjugate on b: a*conj(b).""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + # a is real + return mult_real_cplx(a, conj(b)) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return mult_real_cplx(b, a) + + # Both complex + c = mult_real_cplx(b[...,0], a) + c[..., 0] += a[..., 1] * b[..., 1] + c[..., 1] -= a[..., 0] * b[..., 1] + return c + + +@tensor_operation +def mult_real_cplx(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex multiplication of real tensor a with complex tensor b.""" + + if is_real(b): + raise ValueError('Last dimension must have length 2.') + + return a.unsqueeze(-1) * b + + +@tensor_operation +def div(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex division of complex tensors.""" + + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + # b is real + return div_cplx_real(a, b) + + return div_cplx_real(mult_conj(a, b), abs_sqr(b)) + + +@tensor_operation +def div_cplx_real(a: torch.Tensor, b: torch.Tensor): + """Pointwise complex division of complex tensor a with real tensor b.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a / b.unsqueeze(-1) + + +@tensor_operation +def abs_sqr(a: torch.Tensor): + """Squared absolute value.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return torch.sum(a*a, -1) + + +@tensor_operation +def abs(a: torch.Tensor): + """Absolute value.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return torch.sqrt(abs_sqr(a)) + + +@tensor_operation +def conj(a: torch.Tensor): + """Complex conjugate.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + # return a * torch.Tensor([1, -1], device=a.device) + return complex(a[...,0], -a[...,1]) + + +@tensor_operation +def real(a: torch.Tensor): + """Real part.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a[..., 0] + + +@tensor_operation +def imag(a: torch.Tensor): + """Imaginary part.""" + + if is_real(a): + raise ValueError('Last dimension must have length 2.') + + return a[..., 1] + + +@tensor_operation +def complex(a: torch.Tensor, b: torch.Tensor = None): + """Create complex tensor from real and imaginary part.""" + + if b is None: + b = a.new_zeros(a.shape) + elif a is None: + a = b.new_zeros(b.shape) + + return torch.cat((a.unsqueeze(-1), b.unsqueeze(-1)), -1) + + +@tensor_operation +def mtimes(a: torch.Tensor, b: torch.Tensor, conj_a=False, conj_b=False): + """Complex matrix multiplication of complex tensors. + The dimensions (-3, -2) are matrix multiplied. -1 is the complex dimension.""" + + if is_real(a): + if a.dim() >= b.dim(): + raise ValueError('Incorrect dimensions.') + return mtimes_real_complex(a, b, conj_b=conj_b) + if is_real(b): + if b.dim() >= a.dim(): + raise ValueError('Incorrect dimensions.') + return mtimes_complex_real(a, b, conj_a=conj_a) + + if not conj_a and not conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) - torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 0], b[..., 1]) + torch.matmul(a[..., 1], b[..., 0])) + if conj_a and not conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) + torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 0], b[..., 1]) - torch.matmul(a[..., 1], b[..., 0])) + if not conj_a and conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) + torch.matmul(a[..., 1], b[..., 1]), + torch.matmul(a[..., 1], b[..., 0]) - torch.matmul(a[..., 0], b[..., 1])) + if conj_a and conj_b: + return complex(torch.matmul(a[..., 0], b[..., 0]) - torch.matmul(a[..., 1], b[..., 1]), + -torch.matmul(a[..., 0], b[..., 1]) - torch.matmul(a[..., 1], b[..., 0])) + + +@tensor_operation +def mtimes_real_complex(a: torch.Tensor, b: torch.Tensor, conj_b=False): + if is_real(b): + raise ValueError('Incorrect dimensions.') + + if not conj_b: + return complex(torch.matmul(a, b[..., 0]), torch.matmul(a, b[..., 1])) + if conj_b: + return complex(torch.matmul(a, b[..., 0]), -torch.matmul(a, b[..., 1])) + + +@tensor_operation +def mtimes_complex_real(a: torch.Tensor, b: torch.Tensor, conj_a=False): + if is_real(a): + raise ValueError('Incorrect dimensions.') + + if not conj_a: + return complex(torch.matmul(a[..., 0], b), torch.matmul(a[..., 1], b)) + if conj_a: + return complex(torch.matmul(a[..., 0], b), -torch.matmul(a[..., 1], b)) + + +@tensor_operation +def exp_imag(a: torch.Tensor): + """Complex exponential with imaginary input: e^(i*a)""" + + a = a.unsqueeze(-1) + return torch.cat((torch.cos(a), torch.sin(a)), -1) + + + diff --git a/pytracking/libs/dcf.py b/pytracking/libs/dcf.py new file mode 100755 index 0000000..ae5d88c --- /dev/null +++ b/pytracking/libs/dcf.py @@ -0,0 +1,164 @@ +import torch +import math +from pytracking import fourier +from pytracking import complex +import torch.nn.functional as F + + +def hann1d(sz: int, centered = True) -> torch.Tensor: + """1D cosine window.""" + if centered: + return 0.5 * (1 - torch.cos((2 * math.pi / (sz + 1)) * torch.arange(1, sz + 1).float())) + w = 0.5 * (1 + torch.cos((2 * math.pi / (sz + 2)) * torch.arange(0, sz//2 + 1).float())) + return torch.cat([w, w[1:sz-sz//2].flip((0,))]) + + +def hann2d(sz: torch.Tensor, centered = True) -> torch.Tensor: + """2D cosine window.""" + return hann1d(sz[0].item(), centered).reshape(1, 1, -1, 1) * hann1d(sz[1].item(), centered).reshape(1, 1, 1, -1) + + +def hann2d_clipped(sz: torch.Tensor, effective_sz: torch.Tensor, centered = True) -> torch.Tensor: + """1D clipped cosine window.""" + + # Ensure that the difference is even + effective_sz += (effective_sz - sz) % 2 + effective_window = hann1d(effective_sz[0].item(), True).reshape(1, 1, -1, 1) * hann1d(effective_sz[1].item(), True).reshape(1, 1, 1, -1) + + pad = (sz - effective_sz) / 2 + + window = F.pad(effective_window, (pad[1].item(), pad[1].item(), pad[0].item(), pad[0].item()), 'replicate') + + if centered: + return window + else: + mid = (sz / 2).int() + window_shift_lr = torch.cat((window[:, :, :, mid[1]:], window[:, :, :, :mid[1]]), 3) + return torch.cat((window_shift_lr[:, :, mid[0]:, :], window_shift_lr[:, :, :mid[0], :]), 2) + + +def gauss_fourier(sz: int, sigma: float, half: bool = False) -> torch.Tensor: + if half: + k = torch.arange(0, int(sz/2+1)) + else: + k = torch.arange(-int((sz-1)/2), int(sz/2+1)) + return (math.sqrt(2*math.pi) * sigma / sz) * torch.exp(-2 * (math.pi * sigma * k.float() / sz)**2) + + +def gauss_spatial(sz, sigma, center=0, end_pad=0): + k = torch.arange(-(sz-1)/2, (sz+1)/2+end_pad) + return torch.exp(-1.0/(2*sigma**2) * (k - center)**2) + + +def label_function(sz: torch.Tensor, sigma: torch.Tensor): + return gauss_fourier(sz[0].item(), sigma[0].item()).reshape(1, 1, -1, 1) * gauss_fourier(sz[1].item(), sigma[1].item(), True).reshape(1, 1, 1, -1) + +def label_function_spatial(sz: torch.Tensor, sigma: torch.Tensor, center: torch.Tensor = torch.zeros(2), end_pad: torch.Tensor = torch.zeros(2)): + """The origin is in the middle of the image.""" + return gauss_spatial(sz[0].item(), sigma[0].item(), center[0], end_pad[0].item()).reshape(1, 1, -1, 1) * \ + gauss_spatial(sz[1].item(), sigma[1].item(), center[1], end_pad[1].item()).reshape(1, 1, 1, -1) + + +def cubic_spline_fourier(f, a): + """The continuous Fourier transform of a cubic spline kernel.""" + + bf = (6*(1 - torch.cos(2 * math.pi * f)) + 3*a*(1 - torch.cos(4 * math.pi * f)) + - (6 + 8*a)*math.pi*f*torch.sin(2 * math.pi * f) - 2*a*math.pi*f*torch.sin(4 * math.pi * f)) \ + / (4 * math.pi**4 * f**4) + + bf[f == 0] = 1 + + return bf + + +def get_interp_fourier(sz: torch.Tensor, method='ideal', bicubic_param=0.5, centering=True, windowing=False, device='cpu'): + + ky, kx = fourier.get_frequency_coord(sz) + + if method=='ideal': + interp_y = torch.ones(ky.shape) / sz[0] + interp_x = torch.ones(kx.shape) / sz[1] + elif method=='bicubic': + interp_y = cubic_spline_fourier(ky / sz[0], bicubic_param) / sz[0] + interp_x = cubic_spline_fourier(kx / sz[1], bicubic_param) / sz[1] + else: + raise ValueError('Unknown method.') + + if centering: + interp_y = complex.mult(interp_y, complex.exp_imag((-math.pi/sz[0]) * ky)) + interp_x = complex.mult(interp_x, complex.exp_imag((-math.pi/sz[1]) * kx)) + + if windowing: + raise NotImplementedError + + return interp_y.to(device), interp_x.to(device) + + +def interpolate_dft(a: torch.Tensor, interp_fs) -> torch.Tensor: + + if isinstance(interp_fs, torch.Tensor): + return complex.mult(a, interp_fs) + if isinstance(interp_fs, (tuple, list)): + return complex.mult(complex.mult(a, interp_fs[0]), interp_fs[1]) + raise ValueError('"interp_fs" must be tensor or tuple of tensors.') + + +def get_reg_filter(sz: torch.Tensor, target_sz: torch.Tensor, params): + """Computes regularization filter in CCOT and ECO.""" + + if not params.use_reg_window: + return params.reg_window_min * torch.ones(1,1,1,1) + + if getattr(params, 'reg_window_square', False): + target_sz = target_sz.prod().sqrt() * torch.ones(2) + + # Normalization factor + reg_scale = 0.5 * target_sz + + # Construct grid + if getattr(params, 'reg_window_centered', True): + wrg = torch.arange(-int((sz[0]-1)/2), int(sz[0]/2+1), dtype=torch.float32).view(1,1,-1,1) + wcg = torch.arange(-int((sz[1]-1)/2), int(sz[1]/2+1), dtype=torch.float32).view(1,1,1,-1) + else: + wrg = torch.cat([torch.arange(0, int(sz[0]/2+1), dtype=torch.float32), + torch.arange(-int((sz[0] - 1) / 2), 0, dtype=torch.float32)]).view(1,1,-1,1) + wcg = torch.cat([torch.arange(0, int(sz[1]/2+1), dtype=torch.float32), + torch.arange(-int((sz[1] - 1) / 2), 0, dtype=torch.float32)]).view(1,1,1,-1) + + # Construct regularization window + reg_window = (params.reg_window_edge - params.reg_window_min) * \ + (torch.abs(wrg/reg_scale[0])**params.reg_window_power + + torch.abs(wcg/reg_scale[1])**params.reg_window_power) + params.reg_window_min + + # Compute DFT and enforce sparsity + reg_window_dft = torch.rfft(reg_window, 2) / sz.prod() + reg_window_dft_abs = complex.abs(reg_window_dft) + reg_window_dft[reg_window_dft_abs < params.reg_sparsity_threshold * reg_window_dft_abs.max(), :] = 0 + + # Do the inverse transform to correct for the window minimum + reg_window_sparse = torch.irfft(reg_window_dft, 2, signal_sizes=sz.long().tolist()) + reg_window_dft[0,0,0,0,0] += params.reg_window_min - sz.prod() * reg_window_sparse.min() + reg_window_dft = complex.real(fourier.rfftshift2(reg_window_dft)) + + # Remove zeros + max_inds,_ = reg_window_dft.nonzero().max(dim=0) + mid_ind = int((reg_window_dft.shape[2]-1)/2) + top = max_inds[-2].item() + 1 + bottom = 2*mid_ind - max_inds[-2].item() + right = max_inds[-1].item() + 1 + reg_window_dft = reg_window_dft[..., bottom:top, :right] + if reg_window_dft.shape[-1] > 1: + reg_window_dft = torch.cat([reg_window_dft[..., 1:].flip((2, 3)), reg_window_dft], -1) + + return reg_window_dft + + +def max2d(a: torch.Tensor) -> (torch.Tensor, torch.Tensor): + """Computes maximum and argmax in the last two dimensions.""" + + max_val_row, argmax_row = torch.max(a, dim=-2) + max_val, argmax_col = torch.max(max_val_row, dim=-1) + argmax_row = argmax_row.view(argmax_col.numel(),-1)[torch.arange(argmax_col.numel()), argmax_col.view(-1)] + argmax_row = argmax_row.reshape(argmax_col.shape) + argmax = torch.cat((argmax_row.unsqueeze(-1), argmax_col.unsqueeze(-1)), -1) + return max_val, argmax diff --git a/pytracking/libs/fourier.py b/pytracking/libs/fourier.py new file mode 100755 index 0000000..6cbad18 --- /dev/null +++ b/pytracking/libs/fourier.py @@ -0,0 +1,146 @@ +import torch +import torch.nn.functional as F +from pytracking import complex, TensorList +from pytracking.libs.tensorlist import tensor_operation + + +@tensor_operation +def rfftshift2(a: torch.Tensor): + h = a.shape[2] + 2 + return torch.cat((a[:,:,(h-1)//2:,...], a[:,:,:h//2,...]), 2) + + +@tensor_operation +def irfftshift2(a: torch.Tensor): + mid = int((a.shape[2]-1)/2) + return torch.cat((a[:,:,mid:,...], a[:,:,:mid,...]), 2) + + +@tensor_operation +def cfft2(a): + """Do FFT and center the low frequency component. + Always produces odd (full) output sizes.""" + + return rfftshift2(torch.rfft(a, 2)) + + +@tensor_operation +def cifft2(a, signal_sizes=None): + """Do inverse FFT corresponding to cfft2.""" + + return torch.irfft(irfftshift2(a), 2, signal_sizes=signal_sizes) + + +@tensor_operation +def sample_fs(a: torch.Tensor, grid_sz: torch.Tensor = None, rescale = True): + """Samples the Fourier series.""" + + # Size of the fourier series + sz = torch.Tensor([a.shape[2], 2*a.shape[3]-1]).float() + + # Default grid + if grid_sz is None or sz[0] == grid_sz[0] and sz[1] == grid_sz[1]: + if rescale: + return sz.prod().item() * cifft2(a) + return cifft2(a) + + if sz[0] > grid_sz[0] or sz[1] > grid_sz[1]: + raise ValueError("Only grid sizes that are smaller than the Fourier series size are supported.") + + tot_pad = (grid_sz - sz).tolist() + is_even = [s.item() % 2 == 0 for s in sz] + + # Compute paddings + pad_top = int((tot_pad[0]+1)/2) if is_even[0] else int(tot_pad[0]/2) + pad_bottom = int(tot_pad[0] - pad_top) + pad_right = int((tot_pad[1]+1)/2) + + if rescale: + return grid_sz.prod().item() * cifft2(F.pad(a, (0, 0, 0, pad_right, pad_top, pad_bottom)), signal_sizes=grid_sz.long().tolist()) + else: + return cifft2(F.pad(a, (0, 0, 0, pad_right, pad_top, pad_bottom)), signal_sizes=grid_sz.long().tolist()) + + +def get_frequency_coord(sz, add_complex_dim = False, device='cpu'): + """Frequency coordinates.""" + + ky = torch.arange(-int((sz[0]-1)/2), int(sz[0]/2+1), dtype=torch.float32, device=device).view(1,1,-1,1) + kx = torch.arange(0, int(sz[1]/2+1), dtype=torch.float32, device=device).view(1,1,1,-1) + + if add_complex_dim: + ky = ky.unsqueeze(-1) + kx = kx.unsqueeze(-1) + + return ky, kx + + +@tensor_operation +def shift_fs(a: torch.Tensor, shift: torch.Tensor): + """Shift a sample a in the Fourier domain. + Params: + a : The fourier coefficiens of the sample. + shift : The shift to be performed normalized to the range [-pi, pi].""" + + if a.dim() != 5: + raise ValueError('a must be the Fourier coefficients, a 5-dimensional tensor.') + + if shift[0] == 0 and shift[1] == 0: + return a + + ky, kx = get_frequency_coord((a.shape[2], 2*a.shape[3]-1), device=a.device) + + return complex.mult(complex.mult(a, complex.exp_imag(shift[0].item()*ky)), complex.exp_imag(shift[1].item()*kx)) + + +def sum_fs(a: TensorList) -> torch.Tensor: + """Sum a list of Fourier series expansions.""" + + s = None + mid = None + + for e in sorted(a, key=lambda elem: elem.shape[-3], reverse=True): + if s is None: + s = e.clone() + mid = int((s.shape[-3] - 1) / 2) + else: + # Compute coordinates + top = mid - int((e.shape[-3] - 1) / 2) + bottom = mid + int(e.shape[-3] / 2) + 1 + right = e.shape[-2] + + # Add the data + s[..., top:bottom, :right, :] += e + + return s + + +def sum_fs12(a: TensorList) -> torch.Tensor: + """Sum a list of Fourier series expansions.""" + + s = None + mid = None + + for e in sorted(a, key=lambda elem: elem.shape[0], reverse=True): + if s is None: + s = e.clone() + mid = int((s.shape[0] - 1) / 2) + else: + # Compute coordinates + top = mid - int((e.shape[0] - 1) / 2) + bottom = mid + int(e.shape[0] / 2) + 1 + right = e.shape[1] + + # Add the data + s[top:bottom, :right, ...] += e + + return s + + +@tensor_operation +def inner_prod_fs(a: torch.Tensor, b: torch.Tensor): + if complex.is_complex(a) and complex.is_complex(b): + return 2 * (a.reshape(-1) @ b.reshape(-1)) - a[:, :, :, 0, :].reshape(-1) @ b[:, :, :, 0, :].reshape(-1) + elif complex.is_real(a) and complex.is_real(b): + return 2 * (a.reshape(-1) @ b.reshape(-1)) - a[:, :, :, 0].reshape(-1) @ b[:, :, :, 0].reshape(-1) + else: + raise NotImplementedError('Not implemented for mixed real and complex.') \ No newline at end of file diff --git a/pytracking/libs/operation.py b/pytracking/libs/operation.py new file mode 100755 index 0000000..20fa3d8 --- /dev/null +++ b/pytracking/libs/operation.py @@ -0,0 +1,42 @@ +import torch +import torch.nn.functional as F +from pytracking.libs.tensorlist import tensor_operation, TensorList + + +@tensor_operation +def conv2d(input: torch.Tensor, weight: torch.Tensor, bias: torch.Tensor = None, stride=1, padding=0, dilation=1, groups=1, mode=None): + """Standard conv2d. Returns the input if weight=None.""" + + if weight is None: + return input + + ind = None + if mode is not None: + if padding != 0: + raise ValueError('Cannot input both padding and mode.') + if mode == 'same': + padding = (weight.shape[2]//2, weight.shape[3]//2) + if weight.shape[2] % 2 == 0 or weight.shape[3] % 2 == 0: + ind = (slice(-1) if weight.shape[2] % 2 == 0 else slice(None), + slice(-1) if weight.shape[3] % 2 == 0 else slice(None)) + elif mode == 'valid': + padding = (0, 0) + elif mode == 'full': + padding = (weight.shape[2]-1, weight.shape[3]-1) + else: + raise ValueError('Unknown mode for padding.') + + out = F.conv2d(input, weight, bias=bias, stride=stride, padding=padding, dilation=dilation, groups=groups) + if ind is None: + return out + return out[:,:,ind[0],ind[1]] + + +@tensor_operation +def conv1x1(input: torch.Tensor, weight: torch.Tensor): + """Do a convolution with a 1x1 kernel weights. Implemented with matmul, which can be faster than using conv.""" + + if weight is None: + return input + + return torch.conv2d(input, weight) diff --git a/pytracking/libs/optimization.py b/pytracking/libs/optimization.py new file mode 100755 index 0000000..43a09c4 --- /dev/null +++ b/pytracking/libs/optimization.py @@ -0,0 +1,714 @@ +import torch +import torch.autograd +import math +from pytracking.libs import TensorList +from pytracking.utils.plotting import plot_graph +from ltr.models.layers.activation import softmax_reg + + +class L2Problem: + """Base class for representing an L2 optimization problem.""" + + def __call__(self, x: TensorList) -> TensorList: + """Shall compute the residuals of the problem.""" + raise NotImplementedError + + def ip_input(self, a, b): + """Inner product of the input space.""" + return sum(a.view(-1) @ b.view(-1)) + + def ip_output(self, a, b): + """Inner product of the output space.""" + return sum(a.view(-1) @ b.view(-1)) + + def M1(self, x): + """M1 preconditioner.""" + return x + + def M2(self, x): + """M2 preconditioner.""" + return x + +class MinimizationProblem: + """General minimization problem.""" + def __call__(self, x: TensorList) -> TensorList: + """Shall compute the loss.""" + raise NotImplementedError + + def ip_input(self, a, b): + """Inner product of the input space.""" + return sum(a.view(-1) @ b.view(-1)) + + def M1(self, x): + return x + + def M2(self, x): + return x + + +class ConjugateGradientBase: + """Conjugate Gradient optimizer base class. Implements the CG loop.""" + + def __init__(self, fletcher_reeves = True, standard_alpha = True, direction_forget_factor = 0, debug = False): + self.fletcher_reeves = fletcher_reeves + self.standard_alpha = standard_alpha + self.direction_forget_factor = direction_forget_factor + self.debug = debug + + # State + self.p = None + self.rho = torch.ones(1) + self.r_prev = None + + # Right hand side + self.b = None + + def reset_state(self): + self.p = None + self.rho = torch.ones(1) + self.r_prev = None + + + def run_CG(self, num_iter, x=None, eps=0.0): + """Main conjugate gradient method. + + args: + num_iter: Number of iterations. + x: Initial guess. Assumed zero if None. + eps: Stop if the residual norm gets smaller than this. + """ + + # Apply forgetting factor + if self.direction_forget_factor == 0: + self.reset_state() + elif self.p is not None: + self.rho /= self.direction_forget_factor + + if x is None: + r = self.b.clone() + else: + r = self.b - self.A(x) + + # Norms of residuals etc for debugging + resvec = None + if self.debug: + normr = self.residual_norm(r) + resvec = torch.zeros(num_iter+1) + resvec[0] = normr + + # Loop over iterations + for ii in range(num_iter): + # Preconditioners + y = self.M1(r) + z = self.M2(y) + + rho1 = self.rho + self.rho = self.ip(r, z) + + if self.check_zero(self.rho): + if self.debug: + print('Stopped CG since rho = 0') + if resvec is not None: + resvec = resvec[:ii+1] + return x, resvec + + if self.p is None: + self.p = z.clone() + else: + if self.fletcher_reeves: + beta = self.rho / rho1 + else: + rho2 = self.ip(self.r_prev, z) + beta = (self.rho - rho2) / rho1 + + beta = beta.clamp(0) + self.p = z + self.p * beta + + q = self.A(self.p) + pq = self.ip(self.p, q) + + if self.standard_alpha: + alpha = self.rho / pq + else: + alpha = self.ip(self.p, r) / pq + + # Save old r for PR formula + if not self.fletcher_reeves: + self.r_prev = r.clone() + + # Form new iterate + if x is None: + x = self.p * alpha + else: + x += self.p * alpha + + if ii < num_iter - 1 or self.debug: + r -= q * alpha + + if eps > 0.0 or self.debug: + normr = self.residual_norm(r) + + if self.debug: + self.evaluate_CG_iteration(x) + resvec[ii+1] = normr + + if eps > 0 and normr <= eps: + if self.debug: + print('Stopped CG since norm smaller than eps') + break + + if resvec is not None: + resvec = resvec[:ii+2] + + return x, resvec + + + def A(self, x): + # Implements the left hand operation + raise NotImplementedError + + def ip(self, a, b): + # Implements the inner product + return a.view(-1) @ b.view(-1) + + def residual_norm(self, r): + res = self.ip(r, r).sum() + if isinstance(res, (TensorList, list, tuple)): + res = sum(res) + return res.sqrt() + + def check_zero(self, s, eps = 0.0): + ss = s.abs() <= eps + if isinstance(ss, (TensorList, list, tuple)): + ss = sum(ss) + return ss.item() > 0 + + def M1(self, x): + # M1 preconditioner + return x + + def M2(self, x): + # M2 preconditioner + return x + + def evaluate_CG_iteration(self, x): + pass + + + +class ConjugateGradient(ConjugateGradientBase): + """Conjugate Gradient optimizer, performing single linearization of the residuals in the start.""" + + def __init__(self, problem: L2Problem, variable: TensorList, cg_eps = 0.0, fletcher_reeves = True, + standard_alpha = True, direction_forget_factor = 0, debug = False, plotting = False, visdom=None): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or plotting) + + self.problem = problem + self.x = variable + + self.plotting = plotting + self.fig_num = (10,11) + self.visdom = visdom + + self.cg_eps = cg_eps + self.f0 = None + self.g = None + self.dfdxt_g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + self.dfdxt_g = None + + + def run(self, num_cg_iter): + """Run the oprimizer with the provided number of iterations.""" + + if num_cg_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(2) + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Create copy with graph detached + self.g = self.f0.detach() + + if self.debug: + lossvec[0] = self.problem.ip_output(self.g, self.g) + + self.g.requires_grad_(True) + + # Get df/dx^t @ f0 + self.dfdxt_g = TensorList(torch.autograd.grad(self.f0, self.x, self.g, create_graph=True)) + + # Get the right hand side + self.b = - self.dfdxt_g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.f0 = self.problem(self.x) + lossvec[-1] = self.problem.ip_output(self.f0, self.f0) + self.residuals = torch.cat((self.residuals, res)) + self.losses = torch.cat((self.losses, lossvec)) + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.residuals, 'lineplot', 3, 'CG residuals') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + + self.x.detach_() + self.clear_temp() + + + def A(self, x): + dfdx_x = torch.autograd.grad(self.dfdxt_g, self.g, x, retain_graph=True) + return TensorList(torch.autograd.grad(self.f0, self.x, dfdx_x, retain_graph=True)) + + def ip(self, a, b): + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + + +class GaussNewtonCG(ConjugateGradientBase): + """Gauss-Newton with Conjugate Gradient optimizer.""" + + def __init__(self, problem: L2Problem, variable: TensorList, cg_eps = 0.0, fletcher_reeves = True, + standard_alpha = True, direction_forget_factor = 0, debug = False, analyze = False, plotting = False, + visdom=None): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or analyze or plotting) + + self.problem = problem + self.x = variable + + self.analyze_convergence = analyze + self.plotting = plotting + self.fig_num = (10,11,12) + self.visdom = visdom + + self.cg_eps = cg_eps + self.f0 = None + self.g = None + self.dfdxt_g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + self.dfdxt_g = None + + + def run_GN(self, *args, **kwargs): + return self.run(*args, **kwargs) + + + def run(self, num_cg_iter, num_gn_iter=None): + """Run the optimizer. + args: + num_cg_iter: Number of CG iterations per GN iter. If list, then each entry specifies number of CG iterations + and number of GN iterations is given by the length of the list. + num_gn_iter: Number of GN iterations. Shall only be given if num_cg_iter is an integer. + """ + + if isinstance(num_cg_iter, int): + if num_gn_iter is None: + raise ValueError('Must specify number of GN iter if CG iter is constant') + num_cg_iter = [num_cg_iter]*num_gn_iter + + num_gn_iter = len(num_cg_iter) + if num_gn_iter == 0: + return + + if self.analyze_convergence: + self.evaluate_CG_iteration(0) + + # Outer loop for running the GN iterations. + for cg_iter in num_cg_iter: + self.run_GN_iter(cg_iter) + + if self.debug: + if not self.analyze_convergence: + self.f0 = self.problem(self.x) + loss = self.problem.ip_output(self.f0, self.f0) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.residuals, 'lineplot', 3, 'CG residuals') + + if self.analyze_convergence: + self.visdom.register(self.gradient_mags, 'lineplot', 4, 'Gradient magnitude') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + if self.analyze_convergence: + plot_graph(self.gradient_mags, self.fig_num[2], 'Gradient magnitude') + + + self.x.detach_() + self.clear_temp() + + return self.losses, self.residuals + + + def run_GN_iter(self, num_cg_iter): + """Runs a single GN iteration.""" + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Create copy with graph detached + self.g = self.f0.detach() + + if self.debug and not self.analyze_convergence: + loss = self.problem.ip_output(self.g, self.g) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + self.g.requires_grad_(True) + + # Get df/dx^t @ f0 + self.dfdxt_g = TensorList(torch.autograd.grad(self.f0, self.x, self.g, create_graph=True)) + + # Get the right hand side + self.b = - self.dfdxt_g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + + + def A(self, x): + dfdx_x = torch.autograd.grad(self.dfdxt_g, self.g, x, retain_graph=True) + return TensorList(torch.autograd.grad(self.f0, self.x, dfdx_x, retain_graph=True)) + + def ip(self, a, b): + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + def evaluate_CG_iteration(self, delta_x): + if self.analyze_convergence: + x = (self.x + delta_x).detach() + x.requires_grad_(True) + + # compute loss and gradient + f = self.problem(x) + loss = self.problem.ip_output(f, f) + grad = TensorList(torch.autograd.grad(loss, x)) + + # store in the vectors + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + self.gradient_mags = torch.cat((self.gradient_mags, sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().detach().view(-1))) + + +class GradientDescentL2: + """Gradient descent with momentum for L2 problems.""" + + def __init__(self, problem: L2Problem, variable: TensorList, step_length: float, momentum: float = 0.0, debug = False, plotting = False, visdom=None): + + self.problem = problem + self.x = variable + + self.step_legnth = step_length + self.momentum = momentum + + self.debug = debug or plotting + self.plotting = plotting + self.fig_num = (10,11) + self.visdom = visdom + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + self.residuals = None + + self.clear_temp() + + + def clear_temp(self): + self.f0 = None + self.dir = None + + + def run(self, num_iter, dummy = None): + + if num_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(num_iter+1) + grad_mags = torch.zeros(num_iter+1) + + for i in range(num_iter): + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + # Compute loss + loss = self.problem.ip_output(self.f0, self.f0) + + # Compute grad + grad = TensorList(torch.autograd.grad(loss, self.x)) + + # Update direction + if self.dir is None: + self.dir = grad + else: + self.dir = grad + self.momentum * self.dir + + self.x.detach_() + self.x -= self.step_legnth * self.dir + + if self.debug: + lossvec[i] = loss.item() + grad_mags[i] = sum(grad.view(-1) @ grad.view(-1)).sqrt().item() + + if self.debug: + self.x.requires_grad_(True) + self.f0 = self.problem(self.x) + loss = self.problem.ip_output(self.f0, self.f0) + grad = TensorList(torch.autograd.grad(loss, self.x)) + lossvec[-1] = self.problem.ip_output(self.f0, self.f0).item() + grad_mags[-1] = sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().item() + self.losses = torch.cat((self.losses, lossvec)) + self.gradient_mags = torch.cat((self.gradient_mags, grad_mags)) + + if self.visdom is not None: + self.visdom.register(self.losses, 'lineplot', 3, 'Loss') + self.visdom.register(self.gradient_mags, 'lineplot', 4, 'Gradient magnitude') + elif self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.gradient_mags, self.fig_num[1], title='Gradient magnitude') + + self.x.detach_() + self.clear_temp() + + + +class NewtonCG(ConjugateGradientBase): + """Newton with Conjugate Gradient. Handels general minimization problems.""" + + def __init__(self, problem: MinimizationProblem, variable: TensorList, init_hessian_reg = 0.0, hessian_reg_factor = 1.0, + cg_eps = 0.0, fletcher_reeves = True, standard_alpha = True, direction_forget_factor = 0, + debug = False, analyze = False, plotting = False, fig_num=(10, 11, 12)): + super().__init__(fletcher_reeves, standard_alpha, direction_forget_factor, debug or analyze or plotting) + + self.problem = problem + self.x = variable + + self.analyze_convergence = analyze + self.plotting = plotting + self.fig_num = fig_num + + self.hessian_reg = init_hessian_reg + self.hessian_reg_factor = hessian_reg_factor + self.cg_eps = cg_eps + self.f0 = None + self.g = None + + self.residuals = torch.zeros(0) + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + + def clear_temp(self): + self.f0 = None + self.g = None + + + def run(self, num_cg_iter, num_newton_iter=None): + + if isinstance(num_cg_iter, int): + if num_cg_iter == 0: + return + if num_newton_iter is None: + num_newton_iter = 1 + num_cg_iter = [num_cg_iter] * num_newton_iter + + num_newton_iter = len(num_cg_iter) + if num_newton_iter == 0: + return + + if self.analyze_convergence: + self.evaluate_CG_iteration(0) + + for cg_iter in num_cg_iter: + self.run_newton_iter(cg_iter) + self.hessian_reg *= self.hessian_reg_factor + + if self.debug: + if not self.analyze_convergence: + loss = self.problem(self.x) + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + + if self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.residuals, self.fig_num[1], title='CG residuals') + if self.analyze_convergence: + plot_graph(self.gradient_mags, self.fig_num[2], 'Gradient magnitude') + + self.x.detach_() + self.clear_temp() + + return self.losses, self.residuals + + + def run_newton_iter(self, num_cg_iter): + + self.x.requires_grad_(True) + + # Evaluate function at current estimate + self.f0 = self.problem(self.x) + + if self.debug and not self.analyze_convergence: + self.losses = torch.cat((self.losses, self.f0.detach().cpu().view(-1))) + + # Gradient of loss + self.g = TensorList(torch.autograd.grad(self.f0, self.x, create_graph=True)) + + # Get the right hand side + self.b = - self.g.detach() + + # Run CG + delta_x, res = self.run_CG(num_cg_iter, eps=self.cg_eps) + + self.x.detach_() + self.x += delta_x + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + + + def A(self, x): + return TensorList(torch.autograd.grad(self.g, self.x, x, retain_graph=True)) + self.hessian_reg * x + + def ip(self, a, b): + # Implements the inner product + return self.problem.ip_input(a, b) + + def M1(self, x): + return self.problem.M1(x) + + def M2(self, x): + return self.problem.M2(x) + + def evaluate_CG_iteration(self, delta_x): + if self.analyze_convergence: + x = (self.x + delta_x).detach() + x.requires_grad_(True) + + # compute loss and gradient + loss = self.problem(x) + grad = TensorList(torch.autograd.grad(loss, x)) + + # store in the vectors + self.losses = torch.cat((self.losses, loss.detach().cpu().view(-1))) + self.gradient_mags = torch.cat((self.gradient_mags, sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().detach().view(-1))) + + +class GradientDescent: + """Gradient descent for general minimization problems.""" + + def __init__(self, problem: MinimizationProblem, variable: TensorList, step_length: float, momentum: float = 0.0, + debug = False, plotting = False, fig_num=(10,11)): + + self.problem = problem + self.x = variable + + self.step_legnth = step_length + self.momentum = momentum + + self.debug = debug or plotting + self.plotting = plotting + self.fig_num = fig_num + + self.losses = torch.zeros(0) + self.gradient_mags = torch.zeros(0) + self.residuals = None + + self.clear_temp() + + + def clear_temp(self): + self.dir = None + + + def run(self, num_iter, dummy = None): + + if num_iter == 0: + return + + lossvec = None + if self.debug: + lossvec = torch.zeros(num_iter+1) + grad_mags = torch.zeros(num_iter+1) + + for i in range(num_iter): + self.x.requires_grad_(True) + + # Evaluate function at current estimate + loss = self.problem(self.x) + + # Compute grad + grad = TensorList(torch.autograd.grad(loss, self.x)) + + # Update direction + if self.dir is None: + self.dir = grad + else: + self.dir = grad + self.momentum * self.dir + + self.x.detach_() + self.x -= self.step_legnth * self.dir + + if self.debug: + lossvec[i] = loss.item() + grad_mags[i] = sum(grad.view(-1) @ grad.view(-1)).sqrt().item() + + if self.debug: + self.x.requires_grad_(True) + loss = self.problem(self.x) + grad = TensorList(torch.autograd.grad(loss, self.x)) + lossvec[-1] = loss.item() + grad_mags[-1] = sum(grad.view(-1) @ grad.view(-1)).cpu().sqrt().item() + self.losses = torch.cat((self.losses, lossvec)) + self.gradient_mags = torch.cat((self.gradient_mags, grad_mags)) + if self.plotting: + plot_graph(self.losses, self.fig_num[0], title='Loss') + plot_graph(self.gradient_mags, self.fig_num[1], title='Gradient magnitude') + + self.x.detach_() + self.clear_temp() \ No newline at end of file diff --git a/pytracking/libs/tensordict.py b/pytracking/libs/tensordict.py new file mode 100755 index 0000000..9b2fe7f --- /dev/null +++ b/pytracking/libs/tensordict.py @@ -0,0 +1,36 @@ +from collections import OrderedDict +import torch +import copy + + +class TensorDict(OrderedDict): + """Container mainly used for dicts of torch tensors. Extends OrderedDict with pytorch functionality.""" + + def concat(self, other): + """Concatenates two dicts without copying internal data.""" + return TensorDict(self, **other) + + def copy(self): + return TensorDict(super(TensorDict, self).copy()) + + def __deepcopy__(self, memodict={}): + return TensorDict(copy.deepcopy(list(self), memodict)) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorDict\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorDict({n: getattr(e, name)(*args, **kwargs) if hasattr(e, name) else e for n, e in self.items()}) + return apply_attr + + def attribute(self, attr: str, *args): + return TensorDict({n: getattr(e, attr, *args) for n, e in self.items()}) + + def apply(self, fn, *args, **kwargs): + return TensorDict({n: fn(e, *args, **kwargs) for n, e in self.items()}) + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorDict, list)) + diff --git a/pytracking/libs/tensorlist.py b/pytracking/libs/tensorlist.py new file mode 100755 index 0000000..0e9227e --- /dev/null +++ b/pytracking/libs/tensorlist.py @@ -0,0 +1,212 @@ +import functools +import torch +import copy + + +class TensorList(list): + """Container mainly used for lists of torch tensors. Extends lists with pytorch functionality.""" + + def __init__(self, list_of_tensors = None): + if list_of_tensors is None: + list_of_tensors = list() + super(TensorList, self).__init__(list_of_tensors) + + def __deepcopy__(self, memodict={}): + return TensorList(copy.deepcopy(list(self), memodict)) + + def __getitem__(self, item): + if isinstance(item, int): + return super(TensorList, self).__getitem__(item) + elif isinstance(item, (tuple, list)): + return TensorList([super(TensorList, self).__getitem__(i) for i in item]) + else: + return TensorList(super(TensorList, self).__getitem__(item)) + + def __add__(self, other): + if TensorList._iterable(other): + return TensorList([e1 + e2 for e1, e2 in zip(self, other)]) + return TensorList([e + other for e in self]) + + def __radd__(self, other): + if TensorList._iterable(other): + return TensorList([e2 + e1 for e1, e2 in zip(self, other)]) + return TensorList([other + e for e in self]) + + def __iadd__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] += e2 + else: + for i in range(len(self)): + self[i] += other + return self + + def __sub__(self, other): + if TensorList._iterable(other): + return TensorList([e1 - e2 for e1, e2 in zip(self, other)]) + return TensorList([e - other for e in self]) + + def __rsub__(self, other): + if TensorList._iterable(other): + return TensorList([e2 - e1 for e1, e2 in zip(self, other)]) + return TensorList([other - e for e in self]) + + def __isub__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] -= e2 + else: + for i in range(len(self)): + self[i] -= other + return self + + def __mul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 * e2 for e1, e2 in zip(self, other)]) + return TensorList([e * other for e in self]) + + def __rmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 * e1 for e1, e2 in zip(self, other)]) + return TensorList([other * e for e in self]) + + def __imul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] *= e2 + else: + for i in range(len(self)): + self[i] *= other + return self + + def __truediv__(self, other): + if TensorList._iterable(other): + return TensorList([e1 / e2 for e1, e2 in zip(self, other)]) + return TensorList([e / other for e in self]) + + def __rtruediv__(self, other): + if TensorList._iterable(other): + return TensorList([e2 / e1 for e1, e2 in zip(self, other)]) + return TensorList([other / e for e in self]) + + def __itruediv__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] /= e2 + else: + for i in range(len(self)): + self[i] /= other + return self + + def __matmul__(self, other): + if TensorList._iterable(other): + return TensorList([e1 @ e2 for e1, e2 in zip(self, other)]) + return TensorList([e @ other for e in self]) + + def __rmatmul__(self, other): + if TensorList._iterable(other): + return TensorList([e2 @ e1 for e1, e2 in zip(self, other)]) + return TensorList([other @ e for e in self]) + + def __imatmul__(self, other): + if TensorList._iterable(other): + for i, e2 in enumerate(other): + self[i] @= e2 + else: + for i in range(len(self)): + self[i] @= other + return self + + def __mod__(self, other): + if TensorList._iterable(other): + return TensorList([e1 % e2 for e1, e2 in zip(self, other)]) + return TensorList([e % other for e in self]) + + def __rmod__(self, other): + if TensorList._iterable(other): + return TensorList([e2 % e1 for e1, e2 in zip(self, other)]) + return TensorList([other % e for e in self]) + + def __pos__(self): + return TensorList([+e for e in self]) + + def __neg__(self): + return TensorList([-e for e in self]) + + def __le__(self, other): + if TensorList._iterable(other): + return TensorList([e1 <= e2 for e1, e2 in zip(self, other)]) + return TensorList([e <= other for e in self]) + + def __ge__(self, other): + if TensorList._iterable(other): + return TensorList([e1 >= e2 for e1, e2 in zip(self, other)]) + return TensorList([e >= other for e in self]) + + def concat(self, other): + return TensorList(super(TensorList, self).__add__(other)) + + def copy(self): + return TensorList(super(TensorList, self).copy()) + + def unroll(self): + if not any(isinstance(t, TensorList) for t in self): + return self + + new_list = TensorList() + for t in self: + if isinstance(t, TensorList): + new_list.extend(t.unroll()) + else: + new_list.append(t) + return new_list + + def list(self): + return list(self) + + def attribute(self, attr: str, *args): + return TensorList([getattr(e, attr, *args) for e in self]) + + def apply(self, fn): + return TensorList([fn(e) for e in self]) + + def __getattr__(self, name): + if not hasattr(torch.Tensor, name): + raise AttributeError('\'TensorList\' object has not attribute \'{}\''.format(name)) + + def apply_attr(*args, **kwargs): + return TensorList([getattr(e, name)(*args, **kwargs) for e in self]) + + return apply_attr + + @staticmethod + def _iterable(a): + return isinstance(a, (TensorList, list)) + + + +def tensor_operation(op): + def islist(a): + return isinstance(a, TensorList) + + @functools.wraps(op) + def oplist(*args, **kwargs): + if len(args) == 0: + raise ValueError('Must be at least one argument without keyword (i.e. operand).') + + if len(args) == 1: + if islist(args[0]): + return TensorList([op(a, **kwargs) for a in args[0]]) + else: + # Multiple operands, assume max two + if islist(args[0]) and islist(args[1]): + return TensorList([op(a, b, *args[2:], **kwargs) for a, b in zip(*args[:2])]) + if islist(args[0]): + return TensorList([op(a, *args[1:], **kwargs) for a in args[0]]) + if islist(args[1]): + return TensorList([op(args[0], b, *args[2:], **kwargs) for b in args[1]]) + + # None of the operands are lists + return op(*args, **kwargs) + + return oplist diff --git a/pytracking/notebooks/analyze_results.ipynb b/pytracking/notebooks/analyze_results.ipynb new file mode 100755 index 0000000..46a8eea --- /dev/null +++ b/pytracking/notebooks/analyze_results.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating Results on Datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "%matplotlib inline\n", + "import os\n", + "import sys\n", + "import matplotlib.pyplot as plt\n", + "plt.rcParams['figure.figsize'] = [14, 8]\n", + "\n", + "sys.path.append('../..')\n", + "from pytracking.analysis.plot_results import plot_results, print_results, print_per_sequence_results\n", + "from pytracking.evaluation import Tracker, get_dataset, trackerlist" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plots for OTB, NFS and UAV" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "trackers = []\n", + "trackers.extend(trackerlist('atom', 'default', range(0,5), 'ATOM'))\n", + "trackers.extend(trackerlist('dimp', 'dimp18', range(0,5), 'DiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'dimp50', range(0,5), 'DiMP50'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp18', range(0,5), 'PrDiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp50', range(0,5), 'PrDiMP50'))\n", + "\n", + "dataset = get_dataset('otb')\n", + "plot_results(trackers, dataset, 'OTB', merge_results=True, plot_types=('success', 'prec'), \n", + " skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05, exclude_invalid_frames=False)\n", + "\n", + "dataset = get_dataset('nfs')\n", + "plot_results(trackers, dataset, 'NFS', merge_results=True, plot_types=('success', 'prec'), \n", + " skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05, exclude_invalid_frames=False)\n", + "\n", + "dataset = get_dataset('uav')\n", + "plot_results(trackers, dataset, 'UAV', merge_results=True, plot_types=('success', 'prec'), \n", + " skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05, exclude_invalid_frames=False)\n", + "\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "plot_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, plot_types=('success', 'prec'), \n", + " skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05, exclude_invalid_frames=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plots for LaSOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "trackers = []\n", + "trackers.extend(trackerlist('atom', 'default', range(0,5), 'ATOM'))\n", + "trackers.extend(trackerlist('dimp', 'dimp18', range(0,5), 'DiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'dimp50', range(0,5), 'DiMP50'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp18', range(0,5), 'PrDiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp50', range(0,5), 'PrDiMP50'))\n", + "\n", + "dataset = get_dataset('lasot')\n", + "plot_results(trackers, dataset, 'LaSOT', merge_results=True, plot_types=('success'), \n", + " skip_missing_seq=False, force_evaluation=True, plot_bin_gap=0.05)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tables for OTB, NFS, UAV and LaSOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "trackers = []\n", + "trackers.extend(trackerlist('atom', 'default', range(0,5), 'ATOM'))\n", + "trackers.extend(trackerlist('dimp', 'dimp18', range(0,5), 'DiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'dimp50', range(0,5), 'DiMP50'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp18', range(0,5), 'PrDiMP18'))\n", + "trackers.extend(trackerlist('dimp', 'prdimp50', range(0,5), 'PrDiMP50'))\n", + "\n", + "dataset = get_dataset('otb')\n", + "print_results(trackers, dataset, 'OTB', merge_results=True, plot_types=('success', 'prec', 'norm_prec'))\n", + "\n", + "dataset = get_dataset('nfs')\n", + "print_results(trackers, dataset, 'NFS', merge_results=True, plot_types=('success', 'prec', 'norm_prec'))\n", + "\n", + "dataset = get_dataset('uav')\n", + "print_results(trackers, dataset, 'UAV', merge_results=True, plot_types=('success', 'prec', 'norm_prec'))\n", + "\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "print_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, plot_types=('success', 'prec', 'norm_prec'))\n", + "\n", + "dataset = get_dataset('lasot')\n", + "print_results(trackers, dataset, 'LaSOT', merge_results=True, plot_types=('success', 'prec', 'norm_prec'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Filtered per-sequence results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print per sequence results for sequences where all trackers fail, i.e. all trackers have average overlap in percentage of less than 10.0\n", + "filter_criteria = {'mode': 'ao_max', 'threshold': 10.0}\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "print_per_sequence_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, filter_criteria=filter_criteria, force_evaluation=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print per sequence results for sequences where at least one tracker fails, i.e. a tracker has average overlap in percentage of less than 10.0\n", + "filter_criteria = {'mode': 'ao_min', 'threshold': 10.0}\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "print_per_sequence_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, filter_criteria=filter_criteria, force_evaluation=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print per sequence results for sequences where the trackers have differing behavior.\n", + "# i.e. average overlap in percentage for different trackers on a sequence differ by at least 40.0\n", + "filter_criteria = {'mode': 'delta_ao', 'threshold': 40.0}\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "print_per_sequence_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, filter_criteria=filter_criteria, force_evaluation=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print per sequence results for all sequences\n", + "filter_criteria = None\n", + "dataset = get_dataset('otb', 'nfs', 'uav')\n", + "print_per_sequence_results(trackers, dataset, 'OTB+NFS+UAV', merge_results=True, filter_criteria=filter_criteria, force_evaluation=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/pytracking/parameter/__init__.py b/pytracking/parameter/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/parameter/__pycache__/__init__.cpython-37.pyc b/pytracking/parameter/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..47974db Binary files /dev/null and b/pytracking/parameter/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/parameter/atom/__init__.py b/pytracking/parameter/atom/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/parameter/atom/atom_gmm_sampl.py b/pytracking/parameter/atom/atom_gmm_sampl.py new file mode 100755 index 0000000..5230e26 --- /dev/null +++ b/pytracking/parameter/atom/atom_gmm_sampl.py @@ -0,0 +1,105 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = (1e-2, 5e-2) # 1 # Gradient step length in the bounding box refinement 5e-3 2e-2 + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_gmm_sampl', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/pytracking/parameter/atom/atom_prob_ml.py b/pytracking/parameter/atom/atom_prob_ml.py new file mode 100755 index 0000000..185c827 --- /dev/null +++ b/pytracking/parameter/atom/atom_prob_ml.py @@ -0,0 +1,105 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = (2e-4, 10e-4) # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_prob_ml', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/pytracking/parameter/atom/default.py b/pytracking/parameter/atom/default.py new file mode 100755 index 0000000..16f9eea --- /dev/null +++ b/pytracking/parameter/atom/default.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = True # Use IoU net or not + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/pytracking/parameter/atom/default_vot.py b/pytracking/parameter/atom/default_vot.py new file mode 100755 index 0000000..9d34e5d --- /dev/null +++ b/pytracking/parameter/atom/default_vot.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (14 * 16) ** 2 # Maximum image sample size + params.min_image_sample_size = (14 * 16) ** 2 # Minimum image sample size + params.search_area_scale = 4 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.0075 # Learning rate + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4, 4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = True # Perform windowing of output scores + + # Detection parameters + params.scale_factors = torch.ones(1) # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1 / 3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = -1 # Absolute score threshold to detect target missing + params.distractor_threshold = 100 # Relative threshold to find distractors + params.hard_negative_threshold = 0.3 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.7 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, + normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + params.vot_anno_conversion_type = 'preserve_area' + return params \ No newline at end of file diff --git a/pytracking/parameter/atom/multiscale_no_iounet.py b/pytracking/parameter/atom/multiscale_no_iounet.py new file mode 100755 index 0000000..f89fa74 --- /dev/null +++ b/pytracking/parameter/atom/multiscale_no_iounet.py @@ -0,0 +1,104 @@ +from pytracking.utils import TrackerParams, FeatureParams, Choice +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + # These are usually set from outside + params.debug = 0 # Debug level + params.visualization = False # Do visualization + + # Use GPU or not (IoUNet requires this to be True) + params.use_gpu = True + + # Feature specific parameters + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = (18*16)**2 # Maximum image sample size + params.min_image_sample_size = (18*16)**2 # Minimum image sample size + params.search_area_scale = 5 # Scale relative to target size + params.feature_size_odd = False # Good to use False for even-sized kernels and vice versa + + # Optimization parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 60 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 6 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = None # Forgetting rate of the last conjugate direction + + # Learning parameters for each feature type + deep_params.learning_rate = 0.01 # Learning rate + deep_params.init_samples_minimum_weight = 0.25 # Minimum weight of initial samples in memory + deep_params.output_sigma_factor = 1/4 # Standard deviation of Gaussian label relative to target size + + # Training parameters + params.sample_memory_size = 250 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Online model parameters + deep_params.kernel_size = (4,4) # Kernel size of filter + deep_params.compressed_dim = 64 # Dimension output of projection matrix + deep_params.filter_reg = 1e-1 # Filter regularization factor + deep_params.projection_reg = 1e-4 # Projection regularization factor + + # Windowing + params.feature_window = False # Perform windowing of features + params.window_output = False # Perform windowing of output scores + + # Detection parameters + params.scale_factors = 1.02**torch.arange(-2, 3).float() # What scales to use for localization (only one scale if IoUNet is used) + params.score_upsample_factor = 1 # How much Fourier upsampling to use + + # Init data augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 # How much to expand sample when doing augmentation + params.random_shift_factor = 1/3 # How much random shift to do on each augmented sample + deep_params.use_augmentation = True # Whether to use augmentation for this feature + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + params.proj_init_method = 'randn' # Method for initializing the projection matrix + params.filter_init_method = 'randn' # Method for initializing the spatial filter + params.projection_activation = 'none' # Activation function after projection ('none', 'relu', 'elu' or 'mlu') + params.response_activation = ('mlu', 0.05) # Activation function on the output scores ('none', 'relu', 'elu' or 'mlu') + + # Advanced localization parameters + params.advanced_localization = True # Use this or not + params.target_not_found_threshold = 0.25 # Absolute score threshold to detect target missing + params.distractor_threshold = 0.8 # Relative threshold to find distractors + params.hard_negative_threshold = 0.5 # Relative threshold to find hard negative samples + params.target_neighborhood_scale = 2.2 # Target neighborhood to remove + params.dispalcement_scale = 0.8 # Dispacement to consider for distractors + params.hard_negative_learning_rate = 0.02 # Learning rate if hard negative detected + params.hard_negative_CG_iter = 5 # Number of optimization iterations to use if hard negative detected + params.update_scale_when_uncertain = True # Update scale or not if distractor is close + + # IoUNet parameters + params.use_iou_net = False # Use IoU net or not + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 5 # Number of iterations for refining the boxes + params.box_refinement_step_length = 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + # Setup the feature extractor (which includes the IoUNet) + deep_fparams = FeatureParams(feature_params=[deep_params]) + deep_feat = deep.ATOMResNet18(net_path='atom_default.pth', output_layers=['layer3'], fparams=deep_fparams, normalize_power=2) + params.features = MultiResolutionExtractor([deep_feat]) + + return params diff --git a/pytracking/parameter/dimp/__init__.py b/pytracking/parameter/dimp/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/parameter/dimp/__pycache__/__init__.cpython-37.pyc b/pytracking/parameter/dimp/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..1ffed84 Binary files /dev/null and b/pytracking/parameter/dimp/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/parameter/dimp/__pycache__/super_dimp.cpython-37.pyc b/pytracking/parameter/dimp/__pycache__/super_dimp.cpython-37.pyc new file mode 100755 index 0000000..9ea39f3 Binary files /dev/null and b/pytracking/parameter/dimp/__pycache__/super_dimp.cpython-37.pyc differ diff --git a/pytracking/parameter/dimp/dimp18.py b/pytracking/parameter/dimp/dimp18.py new file mode 100755 index 0000000..84a4636 --- /dev/null +++ b/pytracking/parameter/dimp/dimp18.py @@ -0,0 +1,68 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp18.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/dimp18_vot.py b/pytracking/parameter/dimp/dimp18_vot.py new file mode 100755 index 0000000..bd83125 --- /dev/null +++ b/pytracking/parameter/dimp/dimp18_vot.py @@ -0,0 +1,72 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 14 * 16 + params.search_area_scale = 4 + params.feature_size_odd = False + + # Learning parameters + params.sample_memory_size = 250 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 25 + params.net_opt_update_iter = 3 + params.net_opt_hn_iter = 3 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45, -45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3, 1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6, -0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp18.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/dimp50.py b/pytracking/parameter/dimp/dimp50.py new file mode 100755 index 0000000..201f2db --- /dev/null +++ b/pytracking/parameter/dimp/dimp50.py @@ -0,0 +1,68 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/dimp50_vot.py b/pytracking/parameter/dimp/dimp50_vot.py new file mode 100755 index 0000000..a9c03cb --- /dev/null +++ b/pytracking/parameter/dimp/dimp50_vot.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 14 * 16 + params.search_area_scale = 4 + + # Learning parameters + params.sample_memory_size = 250 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 25 + params.net_opt_update_iter = 3 + params.net_opt_hn_iter = 3 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45, -45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3, 1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6, -0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/dimp50_vot19.py b/pytracking/parameter/dimp/dimp50_vot19.py new file mode 100755 index 0000000..45167b6 --- /dev/null +++ b/pytracking/parameter/dimp/dimp50_vot19.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 16 * 16 + params.search_area_scale = 4.5 + + # Learning parameters + params.sample_memory_size = 100 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 15 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 2 + + # Detection parameters + params.window_output = True + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [-5, 10, -30, 60], + 'blur': [(2, 0.2), (1, 3)], + 'relativeshift': [(0.6, 0.6), (-0.6, -0.6)], + 'dropout': (3, 0.2)} + + params.augmentation_expansion_factor = 1.4 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.0 + params.distractor_threshold = 100 + params.hard_negative_threshold = 0.45 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.7 + + params.perform_hn_without_windowing = True + + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 3 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.net = NetWithBackbone(net_path='dimp50.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/prdimp18.py b/pytracking/parameter/dimp/prdimp18.py new file mode 100755 index 0000000..93ab213 --- /dev/null +++ b/pytracking/parameter/dimp/prdimp18.py @@ -0,0 +1,69 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.score_preprocess = 'softmax' + params.target_not_found_threshold = 0.04 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path='prdimp18.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/prdimp50.py b/pytracking/parameter/dimp/prdimp50.py new file mode 100755 index 0000000..4e716d7 --- /dev/null +++ b/pytracking/parameter/dimp/prdimp50.py @@ -0,0 +1,71 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 22*16 + params.search_area_scale = 6 + params.border_mode = 'inside_major' + params.patch_max_scale_change = 1.5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.score_preprocess = 'softmax' + params.target_not_found_threshold = 0.04 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path='prdimp50.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/dimp/super_dimp.py b/pytracking/parameter/dimp/super_dimp.py new file mode 100755 index 0000000..6a82686 --- /dev/null +++ b/pytracking/parameter/dimp/super_dimp.py @@ -0,0 +1,71 @@ +import vot_path +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 22*16 + params.search_area_scale = 6 + params.border_mode = 'inside_major' + params.patch_max_scale_change = 1.5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + params.net_opt_hn_iter = 1 + + # Detection parameters + params.window_output = False + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Advanced localization parameters + params.advanced_localization = True + params.target_not_found_threshold = 0.25 + params.distractor_threshold = 0.8 + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale = 2.2 + params.dispalcement_scale = 0.8 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.box_refinement_space = 'relative' + params.iounet_augmentation = False # Use the augmented samples to compute the modulation vector + params.iounet_k = 3 # Top-k average to estimate final box + params.num_init_random_boxes = 9 # Num extra random boxes in addition to the classifier prediction + params.box_jitter_pos = 0.1 # How much to jitter the translation for random boxes + params.box_jitter_sz = 0.5 # How much to jitter the scale for random boxes + params.maximal_aspect_ratio = 6 # Limit on the aspect ratio + params.box_refinement_iter = 10 # Number of iterations for refining the boxes + params.box_refinement_step_length = 2.5e-3 # 1 # Gradient step length in the bounding box refinement + params.box_refinement_step_decay = 1 # Multiplicative step length decay (1 means no decay) + + params.net = NetWithBackbone(net_path=vot_path.base_path + 'mlpLT/ckpt/super_dimp.pth.tar', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + + return params diff --git a/pytracking/parameter/eco/__init__.py b/pytracking/parameter/eco/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/parameter/eco/default.py b/pytracking/parameter/eco/default.py new file mode 100755 index 0000000..fddbf51 --- /dev/null +++ b/pytracking/parameter/eco/default.py @@ -0,0 +1,97 @@ +from pytracking.utils import TrackerParams, FeatureParams +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + # Feature specific parameters + shallow_params = TrackerParams() + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = 250**2 # Maximum image sample size + params.min_image_sample_size = 200**2 # Minimum image sample size + params.search_area_scale = 4.5 # Scale relative to target size + + # Conjugate Gradient parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 100 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 10 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = 75 # Forgetting rate of the last conjugate direction + params.precond_data_param = 0.3 # Weight of the data term in the preconditioner + params.precond_reg_param = 0.15 # Weight of the regularization term in the preconditioner + params.precond_proj_param = 35 # Weight of the projection matrix part in the preconditioner + + # Learning parameters + shallow_params.learning_rate = 0.025 + deep_params.learning_rate = 0.0075 + shallow_params.output_sigma_factor = 1/16 + deep_params.output_sigma_factor = 1/4 + + # Training parameters + params.sample_memory_size = 200 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Detection parameters + params.scale_factors = 1.02**torch.arange(-2, 3).float() # What scales to use for localization + params.score_upsample_factor = 1 # How much Fourier upsampling to use + params.score_fusion_strategy = 'weightedsum' # Fusion strategy + shallow_params.translation_weight = 0.4 # Weight of this feature + deep_params.translation_weight = 1 - shallow_params.translation_weight + + # Init augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'shift': [(6, 6), (-6, 6), (6, -6), (-6,-6)], + 'dropout': (7, 0.2)} + + # Whether to use augmentation for this feature + deep_params.use_augmentation = True + shallow_params.use_augmentation = True + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + # params.proj_init_method = 'pca' # Method for initializing the projection matrix + params.projection_reg = 5e-8 # Regularization paremeter of the projection matrix + shallow_params.compressed_dim = 16 # Dimension output of projection matrix for shallow features + deep_params.compressed_dim = 64 # Dimension output of projection matrix for deep features + + # Interpolation parameters + params.interpolation_method = 'bicubic' # The kind of interpolation kernel + params.interpolation_bicubic_a = -0.75 # The parameter for the bicubic interpolation kernel + params.interpolation_centering = True # Center the kernel at the feature sample + params.interpolation_windowing = False # Do additional windowing on the Fourier coefficients of the kernel + + # Regularization parameters + shallow_params.use_reg_window = True # Use spatial regularization or not + shallow_params.reg_window_min = 1e-4 # The minimum value of the regularization window + shallow_params.reg_window_edge = 10e-3 # The impact of the spatial regularization + shallow_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + shallow_params.reg_sparsity_threshold = 0.05 # A relative threshold of which DFT coefficients that should be set to zero + + deep_params.use_reg_window = True # Use spatial regularization or not + deep_params.reg_window_min = 10e-4 # The minimum value of the regularization window + deep_params.reg_window_edge = 50e-3 # The impact of the spatial regularization + deep_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + deep_params.reg_sparsity_threshold = 0.1 # A relative threshold of which DFT coefficients that should be set to zero + + + fparams = FeatureParams(feature_params=[shallow_params, deep_params]) + features = deep.ResNet18m1(output_layers=['vggconv1', 'layer3'], use_gpu=params.use_gpu, fparams=fparams, + pool_stride=[2, 1], normalize_power=2) + + params.features = MultiResolutionExtractor([features]) + + return params \ No newline at end of file diff --git a/pytracking/parameter/eco/mobile3.py b/pytracking/parameter/eco/mobile3.py new file mode 100755 index 0000000..b78236f --- /dev/null +++ b/pytracking/parameter/eco/mobile3.py @@ -0,0 +1,97 @@ +from pytracking.utils import TrackerParams, FeatureParams +from pytracking.features.extractor import MultiResolutionExtractor +from pytracking.features import deep +import torch + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = False + + # Feature specific parameters + shallow_params = TrackerParams() + deep_params = TrackerParams() + + # Patch sampling parameters + params.max_image_sample_size = 250**2 # Maximum image sample size + params.min_image_sample_size = 200**2 # Minimum image sample size + params.search_area_scale = 4.5 # Scale relative to target size + + # Conjugate Gradient parameters + params.CG_iter = 5 # The number of Conjugate Gradient iterations in each update after the first frame + params.init_CG_iter = 100 # The total number of Conjugate Gradient iterations used in the first frame + params.init_GN_iter = 10 # The number of Gauss-Newton iterations used in the first frame (only if the projection matrix is updated) + params.post_init_CG_iter = 0 # CG iterations to run after GN + params.fletcher_reeves = False # Use the Fletcher-Reeves (true) or Polak-Ribiere (false) formula in the Conjugate Gradient + params.standard_alpha = True # Use the standard formula for computing the step length in Conjugate Gradient + params.CG_forgetting_rate = 75 # Forgetting rate of the last conjugate direction + params.precond_data_param = 0.3 # Weight of the data term in the preconditioner + params.precond_reg_param = 0.15 # Weight of the regularization term in the preconditioner + params.precond_proj_param = 35 # Weight of the projection matrix part in the preconditioner + + # Learning parameters + shallow_params.learning_rate = 0.025 + deep_params.learning_rate = 0.0075 + shallow_params.output_sigma_factor = 1/16 + deep_params.output_sigma_factor = 1/4 + + # Training parameters + params.sample_memory_size = 200 # Memory size + params.train_skipping = 10 # How often to run training (every n-th frame) + + # Detection parameters + params.scale_factors = 1.02**torch.arange(-2, 3).float() # What scales to use for localization + params.score_upsample_factor = 1 # How much Fourier upsampling to use + params.score_fusion_strategy = 'weightedsum' # Fusion strategy + shallow_params.translation_weight = 0.4 # Weight of this feature + deep_params.translation_weight = 1 - shallow_params.translation_weight + + # Init augmentation parameters + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45,-45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3,1), (1, 3), (2, 2)], + 'shift': [(6, 6), (-6, 6), (6, -6), (-6,-6)]} + # 'dropout': (7, 0.2)} + + # Whether to use augmentation for this feature + deep_params.use_augmentation = True + shallow_params.use_augmentation = True + + # Factorized convolution parameters + # params.use_projection_matrix = True # Use projection matrix, i.e. use the factorized convolution formulation + params.update_projection_matrix = True # Whether the projection matrix should be optimized or not + # params.proj_init_method = 'pca' # Method for initializing the projection matrix + params.projection_reg = 5e-8 # Regularization paremeter of the projection matrix + shallow_params.compressed_dim = 16 # Dimension output of projection matrix for shallow features + deep_params.compressed_dim = 64 # Dimension output of projection matrix for deep features + + # Interpolation parameters + params.interpolation_method = 'bicubic' # The kind of interpolation kernel + params.interpolation_bicubic_a = -0.75 # The parameter for the bicubic interpolation kernel + params.interpolation_centering = True # Center the kernel at the feature sample + params.interpolation_windowing = False # Do additional windowing on the Fourier coefficients of the kernel + + # Regularization parameters + shallow_params.use_reg_window = True # Use spatial regularization or not + shallow_params.reg_window_min = 1e-4 # The minimum value of the regularization window + shallow_params.reg_window_edge = 10e-3 # The impact of the spatial regularization + shallow_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + shallow_params.reg_sparsity_threshold = 0.05 # A relative threshold of which DFT coefficients that should be set to zero + + deep_params.use_reg_window = True # Use spatial regularization or not + deep_params.reg_window_min = 10e-4 # The minimum value of the regularization window + deep_params.reg_window_edge = 50e-3 # The impact of the spatial regularization + deep_params.reg_window_power = 2 # The degree of the polynomial to use (e.g. 2 is a quadratic window) + deep_params.reg_sparsity_threshold = 0.1 # A relative threshold of which DFT coefficients that should be set to zero + + + fparams = FeatureParams(feature_params=[shallow_params, deep_params]) + features = deep.Mobilenet(output_layers=['init_conv','layer5'], use_gpu=params.use_gpu, fparams=fparams, + pool_stride=[1, 1], normalize_power=2) + + params.features = MultiResolutionExtractor([features]) + + return params \ No newline at end of file diff --git a/pytracking/parameter/kys/__init__.py b/pytracking/parameter/kys/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/parameter/kys/__pycache__/__init__.cpython-37.pyc b/pytracking/parameter/kys/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..c745b58 Binary files /dev/null and b/pytracking/parameter/kys/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/parameter/kys/__pycache__/default.cpython-37.pyc b/pytracking/parameter/kys/__pycache__/default.cpython-37.pyc new file mode 100755 index 0000000..795e111 Binary files /dev/null and b/pytracking/parameter/kys/__pycache__/default.cpython-37.pyc differ diff --git a/pytracking/parameter/kys/__pycache__/default_vot.cpython-37.pyc b/pytracking/parameter/kys/__pycache__/default_vot.cpython-37.pyc new file mode 100755 index 0000000..33a3f15 Binary files /dev/null and b/pytracking/parameter/kys/__pycache__/default_vot.cpython-37.pyc differ diff --git a/pytracking/parameter/kys/default.py b/pytracking/parameter/kys/default.py new file mode 100755 index 0000000..689aa70 --- /dev/null +++ b/pytracking/parameter/kys/default.py @@ -0,0 +1,74 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 18*16 + params.search_area_scale = 5 + + # Learning parameters + params.sample_memory_size = 50 + params.learning_rate = 0.01 + params.init_samples_minimum_weight = 0.25 + params.train_skipping = 20 + params.output_sigma_factor = 1/4 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 10 + params.net_opt_update_iter = 2 + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [10, -10, 45, -45], + 'blur': [(3,1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6,-0.6)], + 'dropout': (2, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1/3 + + # Localization parameters + params.window_output = True + params.use_clipped_window = True + params.effective_search_area = 10.0 + params.apply_window_to_dimp_score = True + + params.dimp_threshold = 0.05 + params.target_not_found_threshold_fused = 0.05 + + params.reset_state_during_occlusion = False + params.prev_feat_remove_subpixel_shift = True + params.move_feat_to_center = True + + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.use_iou_net = True + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.remove_offset_in_fused_score = True + params.score_downsample_factor = 1 + + params.net = NetWithBackbone(net_path='/media/TBData2/projects/vot-EPIC-Kitchens/src/demotrackers/pytracking3/pytracking/pytracking/networks/kys.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + return params diff --git a/pytracking/parameter/kys/default_vot.py b/pytracking/parameter/kys/default_vot.py new file mode 100755 index 0000000..a18a8e6 --- /dev/null +++ b/pytracking/parameter/kys/default_vot.py @@ -0,0 +1,81 @@ +from pytracking.utils import TrackerParams +from pytracking.features.net_wrappers import NetWithBackbone + + +def parameters(): + params = TrackerParams() + + params.debug = 0 + params.visualization = False + + params.use_gpu = True + + params.image_sample_size = 14*16 + params.search_area_scale = 4 + + # Learning parameters + params.sample_memory_size = 250 + params.learning_rate = 0.0075 + params.init_samples_minimum_weight = 0.0 + params.train_skipping = 10 + + # Net optimization params + params.update_classifier = True + params.net_opt_iter = 25 + params.net_opt_update_iter = 3 + params.net_opt_hn_iter = 3 + + params.output_sigma_factor = 1/4 + + # Init augmentation parameters + params.use_augmentation = True + params.augmentation = {'fliplr': True, + 'rotate': [5, -5, 10, -10, 20, -20, 30, -30, 45, -45, -60, 60], + 'blur': [(2, 0.2), (0.2, 2), (3, 1), (1, 3), (2, 2)], + 'relativeshift': [(0.6, 0.6), (-0.6, 0.6), (0.6, -0.6), (-0.6, -0.6)], + 'dropout': (7, 0.2)} + + params.augmentation_expansion_factor = 2 + params.random_shift_factor = 1 / 3 + + # localization parameters + params.window_output = True + params.use_clipped_window = True + params.effective_search_area = 4.0 + params.apply_window_to_dimp_score = True + + params.target_not_found_threshold_fused = 0.05 + params.dimp_threshold = 0.05 + + params.reset_state_during_occlusion = True + + params.prev_feat_remove_subpixel_shift = True + params.move_feat_to_center = True + + params.perform_hn_mining_dimp = True + params.hard_negative_threshold = 0.5 + params.target_neighborhood_scale_safe = 2.2 + params.hard_negative_learning_rate = 0.02 + params.update_scale_when_uncertain = True + + # IoUnet parameters + params.use_iou_net = True + params.iounet_augmentation = False + params.iounet_use_log_scale = True + params.iounet_k = 3 + params.num_init_random_boxes = 9 + params.box_jitter_pos = 0.1 + params.box_jitter_sz = 0.5 + params.maximal_aspect_ratio = 6 + params.box_refinement_iter = 5 + params.box_refinement_step_length = 1 + params.box_refinement_step_decay = 1 + + params.remove_offset_in_fused_score = True + params.score_downsample_factor = 1 + + params.net = NetWithBackbone(net_path='kys.pth', + use_gpu=params.use_gpu) + + params.vot_anno_conversion_type = 'preserve_area' + return params diff --git a/pytracking/run_experiment.py b/pytracking/run_experiment.py new file mode 100755 index 0000000..2fa0ded --- /dev/null +++ b/pytracking/run_experiment.py @@ -0,0 +1,41 @@ +import os +import sys +import argparse +import importlib + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation.running import run_dataset + + +def run_experiment(experiment_module: str, experiment_name: str, debug=0, threads=0): + """Run experiment. + args: + experiment_module: Name of experiment module in the experiments/ folder. + experiment_name: Name of the experiment function. + debug: Debug level. + threads: Number of threads. + """ + expr_module = importlib.import_module('pytracking.experiments.{}'.format(experiment_module)) + expr_func = getattr(expr_module, experiment_name) + trackers, dataset = expr_func() + print('Running: {} {}'.format(experiment_module, experiment_name)) + run_dataset(dataset, trackers, debug, threads) + + +def main(): + parser = argparse.ArgumentParser(description='Run tracker.') + parser.add_argument('experiment_module', type=str, help='Name of experiment module in the experiments/ folder.') + parser.add_argument('experiment_name', type=str, help='Name of the experiment function.') + parser.add_argument('--debug', type=int, default=0, help='Debug level.') + parser.add_argument('--threads', type=int, default=0, help='Number of threads.') + + args = parser.parse_args() + + run_experiment(args.experiment_module, args.experiment_name, args.debug, args.threads) + + +if __name__ == '__main__': + main() diff --git a/pytracking/run_tracker.py b/pytracking/run_tracker.py new file mode 100755 index 0000000..466f329 --- /dev/null +++ b/pytracking/run_tracker.py @@ -0,0 +1,65 @@ +import os +import sys +import argparse + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation import get_dataset +from pytracking.evaluation.running import run_dataset +from pytracking.evaluation import Tracker + + +def run_tracker(tracker_name, tracker_param, run_id=None, dataset_name='otb', sequence=None, debug=0, threads=0, + visdom_info=None): + """Run tracker on sequence or dataset. + args: + tracker_name: Name of tracking method. + tracker_param: Name of parameter file. + run_id: The run id. + dataset_name: Name of dataset (otb, nfs, uav, tpl, vot, tn, gott, gotv, lasot). + sequence: Sequence number or name. + debug: Debug level. + threads: Number of threads. + visdom_info: Dict optionally containing 'use_visdom', 'server' and 'port' for Visdom visualization. + """ + + visdom_info = {} if visdom_info is None else visdom_info + + dataset = get_dataset(dataset_name) + + if sequence is not None: + dataset = [dataset[sequence]] + + trackers = [Tracker(tracker_name, tracker_param, run_id)] + + run_dataset(dataset, trackers, debug, threads, visdom_info=visdom_info) + + +def main(): + parser = argparse.ArgumentParser(description='Run tracker on sequence or dataset.') + parser.add_argument('tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('tracker_param', type=str, help='Name of parameter file.') + parser.add_argument('--runid', type=int, default=None, help='The run id.') + parser.add_argument('--dataset_name', type=str, default='otb', help='Name of dataset (otb, nfs, uav, tpl, vot, tn, gott, gotv, lasot).') + parser.add_argument('--sequence', type=str, default=None, help='Sequence number or name.') + parser.add_argument('--debug', type=int, default=0, help='Debug level.') + parser.add_argument('--threads', type=int, default=0, help='Number of threads.') + parser.add_argument('--use_visdom', type=bool, default=True, help='Flag to enable visdom.') + parser.add_argument('--visdom_server', type=str, default='127.0.0.1', help='Server for visdom.') + parser.add_argument('--visdom_port', type=int, default=8097, help='Port for visdom.') + + args = parser.parse_args() + + try: + seq_name = int(args.sequence) + except: + seq_name = args.sequence + + run_tracker(args.tracker_name, args.tracker_param, args.runid, args.dataset_name, seq_name, args.debug, + args.threads, {'use_visdom': args.use_visdom, 'server': args.visdom_server, 'port': args.visdom_port}) + + +if __name__ == '__main__': + main() diff --git a/pytracking/run_video.py b/pytracking/run_video.py new file mode 100755 index 0000000..8954fa5 --- /dev/null +++ b/pytracking/run_video.py @@ -0,0 +1,38 @@ +import os +import sys +import argparse + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation import Tracker + + +def run_video(tracker_name, tracker_param, videofile, optional_box=None, debug=None, save_results=False): + """Run the tracker on your webcam. + args: + tracker_name: Name of tracking method. + tracker_param: Name of parameter file. + debug: Debug level. + """ + tracker = Tracker(tracker_name, tracker_param) + tracker.run_video(videofilepath=videofile, optional_box=optional_box, debug=debug, save_results=save_results) + +def main(): + parser = argparse.ArgumentParser(description='Run the tracker on your webcam.') + parser.add_argument('tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('tracker_param', type=str, help='Name of parameter file.') + parser.add_argument('videofile', type=str, help='path to a video file.') + parser.add_argument('--optional_box', type=float, default=None, nargs="+", help='optional_box with format x y w h.') + parser.add_argument('--debug', type=int, default=0, help='Debug level.') + parser.add_argument('--save_results', dest='save_results', action='store_true', help='Save bounding boxes') + parser.set_defaults(save_results=False) + + args = parser.parse_args() + + run_video(args.tracker_name, args.tracker_param,args.videofile, args.optional_box, args.debug, args.save_results) + + +if __name__ == '__main__': + main() diff --git a/pytracking/run_vot.py b/pytracking/run_vot.py new file mode 100755 index 0000000..442d41d --- /dev/null +++ b/pytracking/run_vot.py @@ -0,0 +1,34 @@ +import os +import sys +import argparse + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation import Tracker + + +def run_vot2020(tracker_name, tracker_param, run_id=None, debug=0, visdom_info=None): + tracker = Tracker(tracker_name, tracker_param, run_id) + tracker.run_vot2020(debug, visdom_info) + + +def run_vot(tracker_name, tracker_param, run_id=None): + tracker = Tracker(tracker_name, tracker_param, run_id) + tracker.run_vot() + + +def main(): + parser = argparse.ArgumentParser(description='Run VOT.') + parser.add_argument('tracker_name', type=str) + parser.add_argument('tracker_param', type=str) + parser.add_argument('--run_id', type=int, default=None) + + args = parser.parse_args() + + run_vot(args.tracker_name, args.tracker_param, args.run_id) + + +if __name__ == '__main__': + main() diff --git a/pytracking/run_webcam.py b/pytracking/run_webcam.py new file mode 100755 index 0000000..5beb2d4 --- /dev/null +++ b/pytracking/run_webcam.py @@ -0,0 +1,41 @@ +import os +import sys +import argparse + +env_path = os.path.join(os.path.dirname(__file__), '..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation import Tracker + + +def run_webcam(tracker_name, tracker_param, debug=None, visdom_info=None): + """Run the tracker on your webcam. + args: + tracker_name: Name of tracking method. + tracker_param: Name of parameter file. + debug: Debug level. + visdom_info: Dict optionally containing 'use_visdom', 'server' and 'port' for Visdom visualization. + """ + visdom_info = {} if visdom_info is None else visdom_info + tracker = Tracker(tracker_name, tracker_param) + tracker.run_webcam(debug, visdom_info) + + +def main(): + parser = argparse.ArgumentParser(description='Run the tracker on your webcam.') + parser.add_argument('tracker_name', type=str, help='Name of tracking method.') + parser.add_argument('tracker_param', type=str, help='Name of parameter file.') + parser.add_argument('--debug', type=int, default=0, help='Debug level.') + parser.add_argument('--use_visdom', type=bool, default=True, help='Flag to enable visdom') + parser.add_argument('--visdom_server', type=str, default='127.0.0.1', help='Server for visdom') + parser.add_argument('--visdom_port', type=int, default=8097, help='Port for visdom') + + args = parser.parse_args() + + visdom_info = {'use_visdom': args.use_visdom, 'server': args.visdom_server, 'port': args.visdom_port} + run_webcam(args.tracker_name, args.tracker_param, args.debug, visdom_info) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/pytracking/tracker/__init__.py b/pytracking/tracker/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/tracker/__pycache__/__init__.cpython-37.pyc b/pytracking/tracker/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..d2f47d7 Binary files /dev/null and b/pytracking/tracker/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/tracker/atom/__init__.py b/pytracking/tracker/atom/__init__.py new file mode 100755 index 0000000..f0778c0 --- /dev/null +++ b/pytracking/tracker/atom/__init__.py @@ -0,0 +1,4 @@ +from .atom import ATOM + +def get_tracker_class(): + return ATOM \ No newline at end of file diff --git a/pytracking/tracker/atom/atom.py b/pytracking/tracker/atom/atom.py new file mode 100755 index 0000000..ac18b0a --- /dev/null +++ b/pytracking/tracker/atom/atom.py @@ -0,0 +1,836 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import torch.nn +import math +import time +from pytracking import dcf, fourier, TensorList, operation +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor +from pytracking.libs.optimization import GaussNewtonCG, ConjugateGradient, GradientDescentL2 +from .optim import ConvProblem, FactorizedConvProblem +from pytracking.features import augmentation +import ltr.data.bounding_box_utils as bbutils + + +class ATOM(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.features.initialize() + self.features_initialized = True + + + def initialize(self, image, info: dict) -> dict: + state = info['init_bbox'] + + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize features + self.initialize_features() + + # Check if image is color + self.params.features.set_is_color(image.shape[2] == 3) + + # Get feature specific params + self.fparams = self.params.features.get_fparams('feature_params') + + tic = time.time() + + # Get position and size + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Set search area + self.target_scale = 1.0 + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + if search_area > self.params.max_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.max_image_sample_size) + elif search_area < self.params.min_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.min_image_sample_size) + + # Check if IoUNet is used + self.use_iou_net = self.params.get('use_iou_net', True) + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Use odd square search area and set sizes + feat_max_stride = max(self.params.features.stride()) + if self.params.get('search_area_shape', 'square') == 'square': + self.img_sample_sz = torch.round(torch.sqrt(torch.prod(self.base_target_sz * self.params.search_area_scale))) * torch.ones(2) + elif self.params.search_area_shape == 'initrect': + self.img_sample_sz = torch.round(self.base_target_sz * self.params.search_area_scale) + else: + raise ValueError('Unknown search area shape') + if self.params.feature_size_odd: + self.img_sample_sz += feat_max_stride - self.img_sample_sz % (2 * feat_max_stride) + else: + self.img_sample_sz += feat_max_stride - (self.img_sample_sz + feat_max_stride) % (2 * feat_max_stride) + + # Set sizes + self.img_support_sz = self.img_sample_sz + self.feature_sz = self.params.features.size(self.img_sample_sz) + self.output_sz = self.params.score_upsample_factor * self.img_support_sz # Interpolated size of the output + self.kernel_size = self.fparams.attribute('kernel_size') + + self.iou_img_sample_sz = self.img_sample_sz + + # Optimization options + self.params.precond_learning_rate = self.fparams.attribute('learning_rate') + if self.params.CG_forgetting_rate is None or max(self.params.precond_learning_rate) >= 1: + self.params.direction_forget_factor = 0 + else: + self.params.direction_forget_factor = (1 - max(self.params.precond_learning_rate))**self.params.CG_forgetting_rate + + self.output_window = None + if self.params.get('window_output', False): + if self.params.get('use_clipped_window', False): + self.output_window = dcf.hann2d_clipped(self.output_sz.long(), self.output_sz.long()*self.params.effective_search_area / self.params.search_area_scale, centered=False).to(self.params.device) + else: + self.output_window = dcf.hann2d(self.output_sz.long(), centered=False).to(self.params.device) + + # Initialize some learning things + self.init_learning() + + # Convert image + im = numpy_to_torch(image) + self.im = im # For debugging only + + # Setup scale bounds + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + x = self.generate_init_samples(im) + + # Initialize iounet + if self.use_iou_net: + self.init_iou_net() + + # Initialize projection matrix + self.init_projection_matrix(x) + + # Transform to get the training sample + train_x = self.preprocess_sample(x) + + # Generate label function + init_y = self.init_label_function(train_x) + + # Init memory + self.init_memory(train_x) + + # Init optimizer and do initial optimization + self.init_optimization(train_x, init_y) + + self.pos_iounet = self.pos.clone() + + out = {'time': time.time() - tic} + return out + + + def init_optimization(self, train_x, init_y): + # Initialize filter + filter_init_method = self.params.get('filter_init_method', 'zeros') + self.filter = TensorList( + [x.new_zeros(1, cdim, sz[0], sz[1]) for x, cdim, sz in zip(train_x, self.compressed_dim, self.kernel_size)]) + if filter_init_method == 'zeros': + pass + elif filter_init_method == 'randn': + for f in self.filter: + f.normal_(0, 1/f.numel()) + else: + raise ValueError('Unknown "filter_init_method"') + + # Get parameters + self.params.update_projection_matrix = self.params.get('update_projection_matrix', True) and self.params.use_projection_matrix + optimizer = self.params.get('optimizer', 'GaussNewtonCG') + + # Setup factorized joint optimization + if self.params.update_projection_matrix: + self.joint_problem = FactorizedConvProblem(self.init_training_samples, init_y, self.filter_reg, + self.fparams.attribute('projection_reg'), self.params, self.init_sample_weights, + self.projection_activation, self.response_activation) + + # Variable containing both filter and projection matrix + joint_var = self.filter.concat(self.projection_matrix) + + # Initialize optimizer + analyze_convergence = self.params.get('analyze_convergence', False) + if optimizer == 'GaussNewtonCG': + self.joint_optimizer = GaussNewtonCG(self.joint_problem, joint_var, debug=(self.params.debug >= 1), + plotting=(self.params.debug >= 3), analyze=analyze_convergence, + visdom=self.visdom) + elif optimizer == 'GradientDescentL2': + self.joint_optimizer = GradientDescentL2(self.joint_problem, joint_var, self.params.optimizer_step_length, self.params.optimizer_momentum, plotting=(self.params.debug >= 3), debug=(self.params.debug >= 1), + visdom=self.visdom) + + # Do joint optimization + if isinstance(self.params.init_CG_iter, (list, tuple)): + self.joint_optimizer.run(self.params.init_CG_iter) + else: + self.joint_optimizer.run(self.params.init_CG_iter // self.params.init_GN_iter, self.params.init_GN_iter) + + if analyze_convergence: + opt_name = 'CG' if self.params.get('CG_optimizer', True) else 'GD' + for val_name, values in zip(['loss', 'gradient'], [self.joint_optimizer.losses, self.joint_optimizer.gradient_mags]): + val_str = ' '.join(['{:.8e}'.format(v.item()) for v in values]) + file_name = '{}_{}.txt'.format(opt_name, val_name) + with open(file_name, 'a') as f: + f.write(val_str + '\n') + raise RuntimeError('Exiting') + + # Re-project samples with the new projection matrix + compressed_samples = self.project_sample(self.init_training_samples, self.projection_matrix) + for train_samp, init_samp in zip(self.training_samples, compressed_samples): + train_samp[:init_samp.shape[0],...] = init_samp + + self.hinge_mask = None + + # Initialize optimizer + self.conv_problem = ConvProblem(self.training_samples, self.y, self.filter_reg, self.sample_weights, self.response_activation) + + if optimizer == 'GaussNewtonCG': + self.filter_optimizer = ConjugateGradient(self.conv_problem, self.filter, fletcher_reeves=self.params.fletcher_reeves, + direction_forget_factor=self.params.direction_forget_factor, debug=(self.params.debug>=1), + plotting=(self.params.debug>=3), visdom=self.visdom) + elif optimizer == 'GradientDescentL2': + self.filter_optimizer = GradientDescentL2(self.conv_problem, self.filter, self.params.optimizer_step_length, + self.params.optimizer_momentum, debug=(self.params.debug >= 1), + plotting=(self.params.debug>=3), visdom=self.visdom) + + # Transfer losses from previous optimization + if self.params.update_projection_matrix: + self.filter_optimizer.residuals = self.joint_optimizer.residuals + self.filter_optimizer.losses = self.joint_optimizer.losses + + if not self.params.update_projection_matrix: + self.filter_optimizer.run(self.params.init_CG_iter) + + # Post optimization + self.filter_optimizer.run(self.params.post_init_CG_iter) + + # Free memory + del self.init_training_samples + if self.params.use_projection_matrix: + del self.joint_problem, self.joint_optimizer + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + self.im = im # For debugging only + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.pos.round() + sample_scales = self.target_scale * self.params.scale_factors + test_x = self.extract_processed_sample(im, self.pos, sample_scales, self.img_sample_sz) + + # Compute scores + scores_raw = self.apply_filter(test_x) + translation_vec, scale_ind, s, flag = self.localize_target(scores_raw) + + # Update position and scale + if flag != 'not_found': + if self.use_iou_net: + update_scale_flag = self.params.get('update_scale_when_uncertain', True) or flag != 'uncertain' + if self.params.get('use_classifier', True): + self.update_state(sample_pos + translation_vec) + self.refine_target_box(sample_pos, sample_scales[scale_ind], scale_ind, update_scale_flag) + elif self.params.get('use_classifier', True): + self.update_state(sample_pos + translation_vec, sample_scales[scale_ind]) + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + self.debug_info['max_score'] = max_score + self.debug_info['flag'] = flag + + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map') + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # ------- UPDATE ------- # + + # Check flags and set learning rate if hard negative + update_flag = flag not in ['not_found', 'uncertain'] + hard_negative = (flag == 'hard_negative') + learning_rate = self.params.hard_negative_learning_rate if hard_negative else None + + if update_flag: + # Get train sample + train_x = TensorList([x[scale_ind:scale_ind+1, ...] for x in test_x]) + + # Create label for sample + train_y = self.get_label_function(sample_pos, sample_scales[scale_ind]) + + # Update memory + self.update_memory(train_x, train_y, learning_rate) + + # Train filter + if hard_negative: + self.filter_optimizer.run(self.params.hard_negative_CG_iter) + elif (self.frame_num-1) % self.params.train_skipping == 0: + self.filter_optimizer.run(self.params.CG_iter) + + # Set the pos of the tracker to iounet pos + if self.use_iou_net and flag != 'not_found': + self.pos = self.pos_iounet.clone() + + # Return new state + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + out = {'target_bbox': new_state.tolist()} + return out + + + def apply_filter(self, sample_x: TensorList): + return operation.conv2d(sample_x, self.filter, mode='same') + + def localize_target(self, scores_raw): + # Weighted sum (if multiple features) with interpolation in fourier domain + weight = self.fparams.attribute('translation_weight', 1.0) + scores_raw = weight * scores_raw + sf_weighted = fourier.cfft2(scores_raw) / (scores_raw.size(2) * scores_raw.size(3)) + for i, (sz, ksz) in enumerate(zip(self.feature_sz, self.kernel_size)): + sf_weighted[i] = fourier.shift_fs(sf_weighted[i], math.pi * (1 - torch.Tensor([ksz[0]%2, ksz[1]%2]) / sz)) + + scores_fs = fourier.sum_fs(sf_weighted) + scores = fourier.sample_fs(scores_fs, self.output_sz) + + if self.output_window is not None and not self.params.get('perform_hn_without_windowing', False): + scores *= self.output_window + + if self.params.get('advanced_localization', False): + return self.localize_advanced(scores) + + # Get maximum + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp.float().cpu() + + # Convert to displacements in the base scale + disp = (max_disp + self.output_sz / 2) % self.output_sz - self.output_sz / 2 + + # Compute translation vector and scale change factor + translation_vec = disp[scale_ind, ...].view(-1) * (self.img_support_sz / self.output_sz) * self.target_scale + translation_vec *= self.params.scale_factors[scale_ind] + + # Shift the score output for visualization purposes + if self.params.debug >= 2: + sz = scores.shape[-2:] + scores = torch.cat([scores[...,sz[0]//2:,:], scores[...,:sz[0]//2,:]], -2) + scores = torch.cat([scores[...,:,sz[1]//2:], scores[...,:,:sz[1]//2]], -1) + + return translation_vec, scale_ind, scores, None + + def localize_advanced(self, scores): + """Dows the advanced localization with hard negative detection and target not found.""" + + sz = scores.shape[-2:] + + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores_orig = scores.clone() + + scores_orig = torch.cat([scores_orig[..., (sz[0] + 1) // 2:, :], scores_orig[..., :(sz[0] + 1) // 2, :]], -2) + scores_orig = torch.cat([scores_orig[..., :, (sz[1] + 1) // 2:], scores_orig[..., :, :(sz[1] + 1) // 2]], -1) + + scores *= self.output_window + + # Shift scores back + scores = torch.cat([scores[...,(sz[0]+1)//2:,:], scores[...,:(sz[0]+1)//2,:]], -2) + scores = torch.cat([scores[...,:,(sz[1]+1)//2:], scores[...,:,:(sz[1]+1)//2]], -1) + + # Find maximum + max_score1, max_disp1 = dcf.max2d(scores) + _, scale_ind = torch.max(max_score1, dim=0) + max_score1 = max_score1[scale_ind] + max_disp1 = max_disp1[scale_ind,...].float().cpu().view(-1) + target_disp1 = max_disp1 - self.output_sz // 2 + translation_vec1 = target_disp1 * (self.img_support_sz / self.output_sz) * self.target_scale + + if max_score1.item() < self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores, 'not_found' + + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores = scores_orig + + # Mask out target neighborhood + target_neigh_sz = self.params.target_neighborhood_scale * self.target_sz / self.target_scale + tneigh_top = max(round(max_disp1[0].item() - target_neigh_sz[0].item() / 2), 0) + tneigh_bottom = min(round(max_disp1[0].item() + target_neigh_sz[0].item() / 2 + 1), sz[0]) + tneigh_left = max(round(max_disp1[1].item() - target_neigh_sz[1].item() / 2), 0) + tneigh_right = min(round(max_disp1[1].item() + target_neigh_sz[1].item() / 2 + 1), sz[1]) + scores_masked = scores[scale_ind:scale_ind+1,...].clone() + scores_masked[...,tneigh_top:tneigh_bottom,tneigh_left:tneigh_right] = 0 + + # Find new maximum + max_score2, max_disp2 = dcf.max2d(scores_masked) + max_disp2 = max_disp2.float().cpu().view(-1) + target_disp2 = max_disp2 - self.output_sz // 2 + translation_vec2 = target_disp2 * (self.img_support_sz / self.output_sz) * self.target_scale + + # Handle the different cases + if max_score2 > self.params.distractor_threshold * max_score1: + disp_norm1 = torch.sqrt(torch.sum(target_disp1**2)) + disp_norm2 = torch.sqrt(torch.sum(target_disp2**2)) + disp_threshold = self.params.dispalcement_scale * math.sqrt(sz[0] * sz[1]) / 2 + + if disp_norm2 > disp_threshold and disp_norm1 < disp_threshold: + return translation_vec1, scale_ind, scores, 'hard_negative' + if disp_norm2 < disp_threshold and disp_norm1 > disp_threshold: + return translation_vec2, scale_ind, scores, 'hard_negative' + if disp_norm2 > disp_threshold and disp_norm1 > disp_threshold: + return translation_vec1, scale_ind, scores, 'uncertain' + + # If also the distractor is close, return with highest score + return translation_vec1, scale_ind, scores, 'uncertain' + + if max_score2 > self.params.hard_negative_threshold * max_score1 and max_score2 > self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores, 'hard_negative' + + return translation_vec1, scale_ind, scores, None + + + def extract_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + return self.params.features.extract(im, pos, scales, sz)[0] + + def get_iou_features(self): + return self.params.features.get_unique_attribute('iounet_features') + + def get_iou_backbone_features(self): + return self.params.features.get_unique_attribute('iounet_backbone_features') + + def extract_processed_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor) -> (TensorList, TensorList): + x = self.extract_sample(im, pos, scales, sz) + return self.preprocess_sample(self.project_sample(x)) + + def preprocess_sample(self, x: TensorList) -> (TensorList, TensorList): + if self.params.get('_feature_window', False): + x = x * self.feature_window + return x + + def project_sample(self, x: TensorList, proj_matrix = None): + # Apply projection matrix + if proj_matrix is None: + proj_matrix = self.projection_matrix + return operation.conv2d(x, proj_matrix).apply(self.projection_activation) + + def init_learning(self): + # Get window function + self.feature_window = TensorList([dcf.hann2d(sz).to(self.params.device) for sz in self.feature_sz]) + + # Filter regularization + self.filter_reg = self.fparams.attribute('filter_reg') + + # Activation function after the projection matrix (phi_1 in the paper) + projection_activation = self.params.get('projection_activation', 'none') + if isinstance(projection_activation, tuple): + projection_activation, act_param = projection_activation + + if projection_activation == 'none': + self.projection_activation = lambda x: x + elif projection_activation == 'relu': + self.projection_activation = torch.nn.ReLU(inplace=True) + elif projection_activation == 'elu': + self.projection_activation = torch.nn.ELU(inplace=True) + elif projection_activation == 'mlu': + self.projection_activation = lambda x: F.elu(F.leaky_relu(x, 1 / act_param), act_param) + else: + raise ValueError('Unknown activation') + + # Activation function after the output scores (phi_2 in the paper) + response_activation = self.params.get('response_activation', 'none') + if isinstance(response_activation, tuple): + response_activation, act_param = response_activation + + if response_activation == 'none': + self.response_activation = lambda x: x + elif response_activation == 'relu': + self.response_activation = torch.nn.ReLU(inplace=True) + elif response_activation == 'elu': + self.response_activation = torch.nn.ELU(inplace=True) + elif response_activation == 'mlu': + self.response_activation = lambda x: F.elu(F.leaky_relu(x, 1 / act_param), act_param) + else: + raise ValueError('Unknown activation') + + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + """Generate augmented initial samples.""" + + # Compute augmentation size + aug_expansion_factor = self.params.get('augmentation_expansion_factor', None) + aug_expansion_sz = self.img_sample_sz.clone() + aug_output_sz = None + if aug_expansion_factor is not None and aug_expansion_factor != 1: + aug_expansion_sz = (self.img_sample_sz * aug_expansion_factor).long() + aug_expansion_sz += (aug_expansion_sz - self.img_sample_sz.long()) % 2 + aug_expansion_sz = aug_expansion_sz.float() + aug_output_sz = self.img_sample_sz.long().tolist() + + # Random shift operator + get_rand_shift = lambda: None + random_shift_factor = self.params.get('random_shift_factor', 0) + if random_shift_factor > 0: + get_rand_shift = lambda: ((torch.rand(2) - 0.5) * self.img_sample_sz * random_shift_factor).long().tolist() + + # Create transofmations + self.transforms = [augmentation.Identity(aug_output_sz)] + if 'shift' in self.params.augmentation: + self.transforms.extend([augmentation.Translation(shift, aug_output_sz) for shift in self.params.augmentation['shift']]) + if 'relativeshift' in self.params.augmentation: + get_absolute = lambda shift: (torch.Tensor(shift) * self.img_sample_sz/2).long().tolist() + self.transforms.extend([augmentation.Translation(get_absolute(shift), aug_output_sz) for shift in self.params.augmentation['relativeshift']]) + if 'fliplr' in self.params.augmentation and self.params.augmentation['fliplr']: + self.transforms.append(augmentation.FlipHorizontal(aug_output_sz, get_rand_shift())) + if 'blur' in self.params.augmentation: + self.transforms.extend([augmentation.Blur(sigma, aug_output_sz, get_rand_shift()) for sigma in self.params.augmentation['blur']]) + if 'scale' in self.params.augmentation: + self.transforms.extend([augmentation.Scale(scale_factor, aug_output_sz, get_rand_shift()) for scale_factor in self.params.augmentation['scale']]) + if 'rotate' in self.params.augmentation: + self.transforms.extend([augmentation.Rotate(angle, aug_output_sz, get_rand_shift()) for angle in self.params.augmentation['rotate']]) + + # Generate initial samples + init_samples = self.params.features.extract_transformed(im, self.pos, self.target_scale, aug_expansion_sz, self.transforms) + + # Remove augmented samples for those that shall not have + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if not use_aug: + init_samples[i] = init_samples[i][0:1, ...] + + # Add dropout samples + if 'dropout' in self.params.augmentation: + num, prob = self.params.augmentation['dropout'] + self.transforms.extend(self.transforms[:1]*num) + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if use_aug: + init_samples[i] = torch.cat([init_samples[i], F.dropout2d(init_samples[i][0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + return init_samples + + + def init_projection_matrix(self, x): + # Set if using projection matrix + self.params.use_projection_matrix = self.params.get('use_projection_matrix', True) + + if self.params.use_projection_matrix: + self.compressed_dim = self.fparams.attribute('compressed_dim', None) + + proj_init_method = self.params.get('proj_init_method', 'pca') + if proj_init_method == 'pca': + x_mat = TensorList([e.permute(1, 0, 2, 3).reshape(e.shape[1], -1).clone() for e in x]) + x_mat -= x_mat.mean(dim=1, keepdim=True) + cov_x = x_mat @ x_mat.t() + self.projection_matrix = TensorList( + [None if cdim is None else torch.svd(C)[0][:, :cdim].t().unsqueeze(-1).unsqueeze(-1).clone() for C, cdim in + zip(cov_x, self.compressed_dim)]) + elif proj_init_method == 'randn': + self.projection_matrix = TensorList( + [None if cdim is None else ex.new_zeros(cdim,ex.shape[1],1,1).normal_(0,1/math.sqrt(ex.shape[1])) for ex, cdim in + zip(x, self.compressed_dim)]) + else: + self.compressed_dim = x.size(1) + self.projection_matrix = TensorList([None]*len(x)) + + def init_label_function(self, train_x): + # Allocate label function + self.y = TensorList([x.new_zeros(self.params.sample_memory_size, 1, x.shape[2], x.shape[3]) for x in train_x]) + + # Output sigma factor + output_sigma_factor = self.fparams.attribute('output_sigma_factor') + self.sigma = (self.feature_sz / self.img_support_sz * self.base_target_sz).prod().sqrt() * output_sigma_factor * torch.ones(2) + + # Center pos in normalized coords + target_center_norm = (self.pos - self.pos.round()) / (self.target_scale * self.img_support_sz) + + # Generate label functions + for y, sig, sz, ksz, x in zip(self.y, self.sigma, self.feature_sz, self.kernel_size, train_x): + center_pos = sz * target_center_norm + 0.5 * torch.Tensor([(ksz[0] + 1) % 2, (ksz[1] + 1) % 2]) + for i, T in enumerate(self.transforms[:x.shape[0]]): + sample_center = center_pos + torch.Tensor(T.shift) / self.img_support_sz * sz + y[i, 0, ...] = dcf.label_function_spatial(sz, sig, sample_center) + + # Return only the ones to use for initial training + return TensorList([y[:x.shape[0], ...] for y, x in zip(self.y, train_x)]) + + + def init_memory(self, train_x): + # Initialize first-frame training samples + self.num_init_samples = train_x.size(0) + self.init_sample_weights = TensorList([x.new_ones(1) / x.shape[0] for x in train_x]) + self.init_training_samples = train_x + + # Sample counters and weights + self.num_stored_samples = self.num_init_samples.copy() + self.previous_replace_ind = [None] * len(self.num_stored_samples) + self.sample_weights = TensorList([x.new_zeros(self.params.sample_memory_size) for x in train_x]) + for sw, init_sw, num in zip(self.sample_weights, self.init_sample_weights, self.num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [x.new_zeros(self.params.sample_memory_size, cdim, x.shape[2], x.shape[3]) for x, cdim in + zip(train_x, self.compressed_dim)]) + + def update_memory(self, sample_x: TensorList, sample_y: TensorList, learning_rate = None): + replace_ind = self.update_sample_weights(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.num_init_samples, self.fparams, learning_rate) + self.previous_replace_ind = replace_ind + for train_samp, x, ind in zip(self.training_samples, sample_x, replace_ind): + train_samp[ind:ind+1,...] = x + for y_memory, y, ind in zip(self.y, sample_y, replace_ind): + y_memory[ind:ind+1,...] = y + if self.hinge_mask is not None: + for m, y, ind in zip(self.hinge_mask, sample_y, replace_ind): + m[ind:ind+1,...] = (y >= self.params.hinge_threshold).float() + self.num_stored_samples += 1 + + + def update_sample_weights(self, sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, fparams, learning_rate = None): + # Update weights and get index to replace in memory + replace_ind = [] + for sw, prev_ind, num_samp, num_init, fpar in zip(sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, fparams): + lr = learning_rate + if lr is None: + lr = fpar.learning_rate + + init_samp_weight = getattr(fpar, 'init_samples_minimum_weight', None) + if init_samp_weight == 0: + init_samp_weight = None + s_ind = 0 if init_samp_weight is None else num_init + + if num_samp == 0 or lr == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + _, r_ind = torch.min(sw[s_ind:], 0) + r_ind = r_ind.item() + s_ind + + # Update weights + if prev_ind is None: + sw /= 1 - lr + sw[r_ind] = lr + else: + sw[r_ind] = sw[prev_ind] / (1 - lr) + + sw /= sw.sum() + if init_samp_weight is not None and sw[:num_init].sum() < init_samp_weight: + sw /= init_samp_weight + sw[num_init:].sum() + sw[:num_init] = init_samp_weight / num_init + + replace_ind.append(r_ind) + + return replace_ind + + def get_label_function(self, sample_pos, sample_scale): + # Generate label function + train_y = TensorList() + target_center_norm = (self.pos - sample_pos) / (sample_scale * self.img_support_sz) + for sig, sz, ksz in zip(self.sigma, self.feature_sz, self.kernel_size): + center = sz * target_center_norm + 0.5 * torch.Tensor([(ksz[0] + 1) % 2, (ksz[1] + 1) % 2]) + train_y.append(dcf.label_function_spatial(sz, sig, center)) + return train_y + + def update_state(self, new_pos, new_scale = None): + # Update scale + if new_scale is not None: + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = 0.2 + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + def get_iounet_box(self, pos, sz, sample_pos, sample_scale): + """All inputs in original image coordinates""" + box_center = (pos - sample_pos) / sample_scale + (self.iou_img_sample_sz - 1) / 2 + box_sz = sz / sample_scale + target_ul = box_center - (box_sz - 1) / 2 + return torch.cat([target_ul.flip((0,)), box_sz.flip((0,))]) + + def init_iou_net(self): + # Setup IoU net + self.iou_predictor = self.params.features.get_unique_attribute('iou_predictor') + for p in self.iou_predictor.parameters(): + p.requires_grad = False + + # Get target boxes for the different augmentations + self.iou_target_box = self.get_iounet_box(self.pos, self.target_sz, self.pos.round(), self.target_scale) + target_boxes = TensorList() + if self.params.iounet_augmentation: + for T in self.transforms: + if not isinstance(T, (augmentation.Identity, augmentation.Translation, augmentation.FlipHorizontal, augmentation.FlipVertical, augmentation.Blur)): + break + target_boxes.append(self.iou_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + else: + target_boxes.append(self.iou_target_box.clone()) + target_boxes = torch.cat(target_boxes.view(1,4), 0).to(self.params.device) + + # Get iou features + iou_backbone_features = self.get_iou_backbone_features() + + # Remove other augmentations such as rotation + iou_backbone_features = TensorList([x[:target_boxes.shape[0],...] for x in iou_backbone_features]) + + # Extract target feat + with torch.no_grad(): + target_feat = self.iou_predictor.get_modulation(iou_backbone_features, target_boxes) + self.target_feat = TensorList([x.detach().mean(0) for x in target_feat]) + + if self.params.get('iounet_not_use_reference', False): + self.target_feat = TensorList([torch.full_like(tf, tf.norm() / tf.numel()) for tf in self.target_feat]) + + + def refine_target_box(self, sample_pos, sample_scale, scale_ind, update_scale = True): + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features() + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + init_boxes = init_box.view(1,4).clone() + if self.params.num_init_random_boxes > 0: + # Get random initial boxes + square_box_sz = init_box[2:].prod().sqrt() + rand_factor = square_box_sz * torch.cat([self.params.box_jitter_pos * torch.ones(2), self.params.box_jitter_sz * torch.ones(2)]) + minimal_edge_size = init_box[2:].min()/3 + rand_bb = (torch.rand(self.params.num_init_random_boxes, 4) - 0.5) * rand_factor + new_sz = (init_box[2:] + rand_bb[:,2:]).clamp(minimal_edge_size) + new_center = (init_box[:2] + init_box[2:]/2) + rand_bb[:,:2] + init_boxes = torch.cat([new_center - new_sz/2, new_sz], 1) + init_boxes = torch.cat([init_box.view(1,4), init_boxes]) + + # Refine boxes by maximizing iou + output_boxes, output_iou = self.optimize_boxes(iou_features, init_boxes) + + # Remove weird boxes with extreme aspect ratios + output_boxes[:, 2:].clamp_(1) + aspect_ratio = output_boxes[:,2] / output_boxes[:,3] + keep_ind = (aspect_ratio < self.params.maximal_aspect_ratio) * (aspect_ratio > 1/self.params.maximal_aspect_ratio) + output_boxes = output_boxes[keep_ind,:] + output_iou = output_iou[keep_ind] + + # If no box found + if output_boxes.shape[0] == 0: + return + + # Take average of top k boxes + k = self.params.get('iounet_k', 5) + topk = min(k, output_boxes.shape[0]) + _, inds = torch.topk(output_iou, topk) + predicted_box = output_boxes[inds, :].mean(0) + predicted_iou = output_iou.view(-1, 1)[inds, :].mean(0) + + # Update position + new_pos = predicted_box[:2] + predicted_box[2:]/2 - (self.iou_img_sample_sz - 1) / 2 + new_pos = new_pos.flip((0,)) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + def optimize_boxes(self, iou_features, init_boxes): + # Optimize iounet boxes + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + init_step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + init_step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]]).to( + self.params.device).view(1, 1, 4) + box_refinement_space = self.params.get('box_refinement_space', 'default') + + step_length = init_step_length * output_boxes.new_ones(1, output_boxes.shape[1], 1) + outputs_prev = -99999999 * output_boxes.new_ones(1, output_boxes.shape[1]) + step = torch.zeros_like(output_boxes) + + if box_refinement_space == 'default': + # Optimization using bounding box space used in original IoUNet + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init = output_boxes.clone().detach() + bb_init.requires_grad = True + + outputs = self.iou_predictor.predict_iou(self.target_feat, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient=torch.ones_like(outputs)) + + # Update mask and step length + update_mask = (outputs.detach() > outputs_prev) | (self.params.box_refinement_step_decay >= 1) + update_mask_float = update_mask.view(1, -1, 1).float() + step_length[~update_mask, :] *= self.params.box_refinement_step_decay + outputs_prev = outputs.detach().clone() + + # Update proposal + step = update_mask_float * step_length * bb_init.grad * bb_init[:, :, 2:].repeat(1, 1, 2) - ( + 1.0 - update_mask_float) * step + output_boxes = bb_init + step + output_boxes.detach_() + + elif box_refinement_space == 'relative': + # Optimization using relative bounding box space + sz_norm = output_boxes[:, :1, 2:].clone() + output_boxes_rel = bbutils.rect_to_rel(output_boxes, sz_norm) + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init_rel = output_boxes_rel.clone().detach() + bb_init_rel.requires_grad = True + + bb_init = bbutils.rel_to_rect(bb_init_rel, sz_norm) + outputs = self.iou_predictor.predict_iou(self.target_feat, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient=torch.ones_like(outputs)) + + # Update mask and step length + update_mask = (outputs.detach() > outputs_prev) | (self.params.box_refinement_step_decay >= 1) + update_mask_float = update_mask.view(1, -1, 1).float() + step_length[~update_mask, :] *= self.params.box_refinement_step_decay + outputs_prev = outputs.detach().clone() + + # Update proposal + step = update_mask_float * step_length * bb_init_rel.grad - (1.0 - update_mask_float) * step + output_boxes_rel = bb_init_rel + step + output_boxes_rel.detach_() + + # for s in outputs.view(-1): + # print('{:.2f} '.format(s.item()), end='') + # print('') + # print('') + + output_boxes = bbutils.rel_to_rect(output_boxes_rel, sz_norm) + + else: + raise ValueError('Unknown box_refinement_space {}'.format(box_refinement_space)) + + return output_boxes.view(-1, 4).cpu(), outputs.detach().view(-1).cpu() diff --git a/pytracking/tracker/atom/optim.py b/pytracking/tracker/atom/optim.py new file mode 100755 index 0000000..2f4b989 --- /dev/null +++ b/pytracking/tracker/atom/optim.py @@ -0,0 +1,99 @@ +import torch +from pytracking import optimization, TensorList, operation +import math + + +class FactorizedConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, y:TensorList, filter_reg: torch.Tensor, projection_reg, params, sample_weights: TensorList, + projection_activation, response_activation): + self.training_samples = training_samples + self.y = y + self.filter_reg = filter_reg + self.sample_weights = sample_weights + self.params = params + self.projection_reg = projection_reg + self.projection_activation = projection_activation + self.response_activation = response_activation + + self.diag_M = self.filter_reg.concat(projection_reg) + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters, projection_matrices] + :return: [data_terms, filter_regularizations, proj_mat_regularizations] + """ + filter = x[:len(x)//2] # w2 in paper + P = x[len(x)//2:] # w1 in paper + + # Do first convolution + compressed_samples = operation.conv1x1(self.training_samples, P).apply(self.projection_activation) + + # Do second convolution + residuals = operation.conv2d(compressed_samples, filter, mode='same').apply(self.response_activation) + + # Compute data residuals + residuals = residuals - self.y + + residuals = self.sample_weights.sqrt().view(-1, 1, 1, 1) * residuals + + # Add regularization for projection matrix + residuals.extend(self.filter_reg.apply(math.sqrt) * filter) + + # Add regularization for projection matrix + residuals.extend(self.projection_reg.apply(math.sqrt) * P) + + return residuals + + + def ip_input(self, a: TensorList, b: TensorList): + num = len(a) // 2 # Number of filters + a_filter = a[:num] + b_filter = b[:num] + a_P = a[num:] + b_P = b[num:] + + # Filter inner product + # ip_out = a_filter.reshape(-1) @ b_filter.reshape(-1) + ip_out = operation.conv2d(a_filter, b_filter).view(-1) + + # Add projection matrix part + # ip_out += a_P.reshape(-1) @ b_P.reshape(-1) + ip_out += operation.conv2d(a_P.view(1,-1,1,1), b_P.view(1,-1,1,1)).view(-1) + + # Have independent inner products for each filter + return ip_out.concat(ip_out.clone()) + + def M1(self, x: TensorList): + return x / self.diag_M + + +class ConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, y:TensorList, filter_reg: torch.Tensor, sample_weights: TensorList, response_activation): + self.training_samples = training_samples + self.y = y + self.filter_reg = filter_reg + self.sample_weights = sample_weights + self.response_activation = response_activation + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters] + :return: [data_terms, filter_regularizations] + """ + # Do convolution and compute residuals + residuals = operation.conv2d(self.training_samples, x, mode='same').apply(self.response_activation) + residuals = residuals - self.y + + residuals = self.sample_weights.sqrt().view(-1, 1, 1, 1) * residuals + + # Add regularization for projection matrix + residuals.extend(self.filter_reg.apply(math.sqrt) * x) + + return residuals + + def ip_input(self, a: TensorList, b: TensorList): + # return a.reshape(-1) @ b.reshape(-1) + # return (a * b).sum() + return operation.conv2d(a, b).view(-1) diff --git a/pytracking/tracker/base/__init__.py b/pytracking/tracker/base/__init__.py new file mode 100755 index 0000000..945e713 --- /dev/null +++ b/pytracking/tracker/base/__init__.py @@ -0,0 +1 @@ +from .basetracker import BaseTracker \ No newline at end of file diff --git a/pytracking/tracker/base/__pycache__/__init__.cpython-37.pyc b/pytracking/tracker/base/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..2c90166 Binary files /dev/null and b/pytracking/tracker/base/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/tracker/base/__pycache__/basetracker.cpython-37.pyc b/pytracking/tracker/base/__pycache__/basetracker.cpython-37.pyc new file mode 100755 index 0000000..65c6338 Binary files /dev/null and b/pytracking/tracker/base/__pycache__/basetracker.cpython-37.pyc differ diff --git a/pytracking/tracker/base/basetracker.py b/pytracking/tracker/base/basetracker.py new file mode 100755 index 0000000..458c4a3 --- /dev/null +++ b/pytracking/tracker/base/basetracker.py @@ -0,0 +1,33 @@ +from _collections import OrderedDict + +class BaseTracker: + """Base class for all trackers.""" + + def __init__(self, params): + self.params = params + self.visdom = None + + + def predicts_segmentation_mask(self): + return False + + + def initialize(self, image, info: dict) -> dict: + """Overload this function in your tracker. This should initialize the model.""" + raise NotImplementedError + + + def track(self, image, info: dict = None) -> dict: + """Overload this function in your tracker. This should track in the frame and update the model.""" + raise NotImplementedError + + + def visdom_draw_tracking(self, image, box, segmentation=None): + if isinstance(box, OrderedDict): + box = [v for k, v in box.items()] + else: + box = (box,) + if segmentation is None: + self.visdom.register((image, *box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, *box, segmentation), 'Tracking', 1, 'Tracking') \ No newline at end of file diff --git a/pytracking/tracker/dimp/__init__.py b/pytracking/tracker/dimp/__init__.py new file mode 100755 index 0000000..d605970 --- /dev/null +++ b/pytracking/tracker/dimp/__init__.py @@ -0,0 +1,4 @@ +from .dimp import DiMP + +def get_tracker_class(): + return DiMP \ No newline at end of file diff --git a/pytracking/tracker/dimp/__pycache__/__init__.cpython-37.pyc b/pytracking/tracker/dimp/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..eda90a0 Binary files /dev/null and b/pytracking/tracker/dimp/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/tracker/dimp/__pycache__/dimp.cpython-37.pyc b/pytracking/tracker/dimp/__pycache__/dimp.cpython-37.pyc new file mode 100755 index 0000000..585de9a Binary files /dev/null and b/pytracking/tracker/dimp/__pycache__/dimp.cpython-37.pyc differ diff --git a/pytracking/tracker/dimp/dimp.py b/pytracking/tracker/dimp/dimp.py new file mode 100755 index 0000000..ff6512f --- /dev/null +++ b/pytracking/tracker/dimp/dimp.py @@ -0,0 +1,937 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import math +import time +from pytracking import dcf, TensorList +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor, plot_graph +from pytracking.features.preprocessing import sample_patch_multiscale, sample_patch_transformed +from pytracking.features import augmentation +import ltr.data.bounding_box_utils as bbutils +from ltr.models.target_classifier.initializer import FilterInitializerZero +from ltr.models.layers import activation + + +class DiMP(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.net.initialize() + self.features_initialized = True + + def initialize(self, image, info: dict) -> dict: + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize network + self.initialize_features() + + # The DiMP network + self.net = self.params.net + + # Time initialization + tic = time.time() + + # Convert image + im = numpy_to_torch(image) + + # Get target position and size + state = info['init_bbox'] + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Get object id + self.object_id = info.get('object_ids', [None])[0] + self.id_str = '' if self.object_id is None else ' {}'.format(self.object_id) + + # Set sizes + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + sz = self.params.image_sample_size + sz = torch.Tensor([sz, sz] if isinstance(sz, int) else sz) + if self.params.get('use_image_aspect_ratio', False): + sz = self.image_sz * sz.prod().sqrt() / self.image_sz.prod().sqrt() + stride = self.params.get('feature_stride', 32) + sz = torch.round(sz / stride) * stride + self.img_sample_sz = sz + self.img_support_sz = self.img_sample_sz + + # Set search area + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + self.target_scale = math.sqrt(search_area) / self.img_sample_sz.prod().sqrt() + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Setup scale factors + if not self.params.has('scale_factors'): + self.params.scale_factors = torch.ones(1) + elif isinstance(self.params.scale_factors, (list, tuple)): + self.params.scale_factors = torch.Tensor(self.params.scale_factors) + + # Setup scale bounds + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + init_backbone_feat = self.generate_init_samples(im) + + # Initialize classifier + self.init_classifier(init_backbone_feat) + + # Initialize IoUNet + if self.params.get('use_iou_net', True): + self.init_iou_net(init_backbone_feat) + + out = {'time': time.time() - tic} + return out + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + + # ------- LOCALIZATION ------- # + + # Extract backbone features + backbone_feat, sample_coords, im_patches = self.extract_backbone_features(im, self.get_centered_sample_pos(), + self.target_scale * self.params.scale_factors, + self.img_sample_sz) + # Extract classification features + test_x = self.get_classification_features(backbone_feat) + + # Location of sample + sample_pos, sample_scales = self.get_sample_location(sample_coords) + + # Compute classification scores + scores_raw = self.classify_target(test_x) + + # Localize the target + translation_vec, scale_ind, s, flag = self.localize_target(scores_raw, sample_pos, sample_scales) + new_pos = sample_pos[scale_ind,:] + translation_vec + + # Update position and scale + if flag != 'not_found': + if self.params.get('use_iou_net', True): + update_scale_flag = self.params.get('update_scale_when_uncertain', True) or flag != 'uncertain' + if self.params.get('use_classifier', True): + self.update_state(new_pos) + self.refine_target_box(backbone_feat, sample_pos[scale_ind,:], sample_scales[scale_ind], scale_ind, update_scale_flag) + elif self.params.get('use_classifier', True): + self.update_state(new_pos, sample_scales[scale_ind]) + + + # ------- UPDATE ------- # + + update_flag = flag not in ['not_found', 'uncertain'] + hard_negative = (flag == 'hard_negative') + learning_rate = self.params.get('hard_negative_learning_rate', None) if hard_negative else None + + if update_flag and self.params.get('update_classifier', False): + # Get train sample + train_x = test_x[scale_ind:scale_ind+1, ...] + + # Create target_box and label for spatial sample + target_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos[scale_ind,:], sample_scales[scale_ind]) + + # Update the classifier model + self.update_classifier(train_x, target_box, learning_rate, s[scale_ind,...]) + + # Set the pos of the tracker to iounet pos + if self.params.get('use_iou_net', True) and flag != 'not_found' and hasattr(self, 'pos_iounet'): + self.pos = self.pos_iounet.clone() + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + + # Visualize and set debug info + self.search_area_box = torch.cat((sample_coords[scale_ind,[1,0]], sample_coords[scale_ind,[3,2]] - sample_coords[scale_ind,[1,0]] - 1)) + self.debug_info['flag' + self.id_str] = flag + self.debug_info['max_score' + self.id_str] = max_score + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map' + self.id_str) + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # Compute output bounding box + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + if self.params.get('output_not_found_box', False) and flag == 'not_found': + output_state = [-1, -1, -1, -1] + else: + output_state = new_state.tolist() + + out = {'target_bbox': output_state} + return output_state, score_map.data.cpu().numpy() + + def track_updater(self, image) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + + # ------- LOCALIZATION ------- # + + # Extract backbone features + backbone_feat, sample_coords, im_patches = self.extract_backbone_features(im, self.get_centered_sample_pos(), + self.target_scale * self.params.scale_factors, + self.img_sample_sz) + # Extract classification features + test_x = self.get_classification_features(backbone_feat) + + # Location of sample + sample_pos, sample_scales = self.get_sample_location(sample_coords) + + # Compute classification scores + scores_raw = self.classify_target(test_x) + + # Localize the target + translation_vec, scale_ind, s, flag = self.localize_target(scores_raw, sample_pos, sample_scales) + new_pos = sample_pos[scale_ind, :] + translation_vec + + # Update position and scale + if flag != 'not_found': + if self.params.get('use_iou_net', True): + update_scale_flag = self.params.get('update_scale_when_uncertain', True) or flag != 'uncertain' + if self.params.get('use_classifier', True): + self.update_state(new_pos) + self.refine_target_box(backbone_feat, sample_pos[scale_ind, :], sample_scales[scale_ind], scale_ind, + update_scale_flag) + elif self.params.get('use_classifier', True): + self.update_state(new_pos, sample_scales[scale_ind]) + + + # ------- UPDATE ------- # + + # Set the pos of the tracker to iounet pos + if self.params.get('use_iou_net', True) and flag != 'not_found' and hasattr(self, 'pos_iounet'): + self.pos = self.pos_iounet.clone() + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + + # Visualize and set debug info + self.search_area_box = torch.cat((sample_coords[scale_ind, [1, 0]], + sample_coords[scale_ind, [3, 2]] - sample_coords[ + scale_ind, [1, 0]] - 1)) + self.debug_info['flag' + self.id_str] = flag + self.debug_info['max_score' + self.id_str] = max_score + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map' + self.id_str) + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # Compute output bounding box + new_state = torch.cat((self.pos[[1, 0]] - (self.target_sz[[1, 0]] - 1) / 2, self.target_sz[[1, 0]])) + + if self.params.get('output_not_found_box', False) and flag == 'not_found': + output_state = [-1, -1, -1, -1] + else: + output_state = new_state.tolist() + + out = {'target_bbox': output_state} + return new_state.tolist(), score_map.cpu().data.numpy(), test_x, scale_ind, sample_pos, sample_scales, flag, s + + + def get_sample_location(self, sample_coord): + """Get the location of the extracted sample.""" + sample_coord = sample_coord.float() + sample_pos = 0.5*(sample_coord[:,:2] + sample_coord[:,2:] - 1) + sample_scales = ((sample_coord[:,2:] - sample_coord[:,:2]) / self.img_sample_sz).prod(dim=1).sqrt() + return sample_pos, sample_scales + + def get_centered_sample_pos(self): + """Get the center position for the new sample. Make sure the target is correctly centered.""" + return self.pos + ((self.feature_sz + self.kernel_size) % 2) * self.target_scale * \ + self.img_support_sz / (2*self.feature_sz) + + def classify_target(self, sample_x: TensorList): + """Classify target by applying the DiMP filter.""" + with torch.no_grad(): + scores = self.net.classifier.classify(self.target_filter, sample_x) + return scores + + def localize_target(self, scores, sample_pos, sample_scales): + """Run the target localization.""" + + scores = scores.squeeze(1) + + preprocess_method = self.params.get('score_preprocess', 'none') + if preprocess_method == 'none': + pass + elif preprocess_method == 'exp': + scores = scores.exp() + elif preprocess_method == 'softmax': + reg_val = getattr(self.net.classifier.filter_optimizer, 'softmax_reg', None) + scores_view = scores.view(scores.shape[0], -1) + scores_softmax = activation.softmax_reg(scores_view, dim=-1, reg=reg_val) + scores = scores_softmax.view(scores.shape) + else: + raise Exception('Unknown score_preprocess in params.') + + score_filter_ksz = self.params.get('score_filter_ksz', 1) + if score_filter_ksz > 1: + assert score_filter_ksz % 2 == 1 + kernel = scores.new_ones(1,1,score_filter_ksz,score_filter_ksz) + scores = F.conv2d(scores.view(-1,1,*scores.shape[-2:]), kernel, padding=score_filter_ksz//2).view(scores.shape) + + if self.params.get('advanced_localization', False): + return self.localize_advanced(scores, sample_pos, sample_scales) + + # Get maximum + score_sz = torch.Tensor(list(scores.shape[-2:])) + score_center = (score_sz - 1)/2 + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp[scale_ind,...].float().cpu().view(-1) + target_disp = max_disp - score_center + + # Compute translation vector and scale change factor + output_sz = score_sz - (self.kernel_size + 1) % 2 + translation_vec = target_disp * (self.img_support_sz / output_sz) * sample_scales[scale_ind] + + return translation_vec, scale_ind, scores, None + + + def localize_advanced(self, scores, sample_pos, sample_scales): + """Run the target advanced localization (as in ATOM).""" + + sz = scores.shape[-2:] + score_sz = torch.Tensor(list(sz)) + output_sz = score_sz - (self.kernel_size + 1) % 2 + score_center = (score_sz - 1)/2 + + scores_hn = scores + if self.output_window is not None and self.params.get('perform_hn_without_windowing', False): + scores_hn = scores.clone() + scores *= self.output_window + + max_score1, max_disp1 = dcf.max2d(scores) + _, scale_ind = torch.max(max_score1, dim=0) + sample_scale = sample_scales[scale_ind] + max_score1 = max_score1[scale_ind] + max_disp1 = max_disp1[scale_ind,...].float().cpu().view(-1) + target_disp1 = max_disp1 - score_center + translation_vec1 = target_disp1 * (self.img_support_sz / output_sz) * sample_scale + + if max_score1.item() < self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores_hn, 'not_found' + if max_score1.item() < self.params.get('uncertain_threshold', -float('inf')): + return translation_vec1, scale_ind, scores_hn, 'uncertain' + if max_score1.item() < self.params.get('hard_sample_threshold', -float('inf')): + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + + # Mask out target neighborhood + target_neigh_sz = self.params.target_neighborhood_scale * (self.target_sz / sample_scale) * (output_sz / self.img_support_sz) + + tneigh_top = max(round(max_disp1[0].item() - target_neigh_sz[0].item() / 2), 0) + tneigh_bottom = min(round(max_disp1[0].item() + target_neigh_sz[0].item() / 2 + 1), sz[0]) + tneigh_left = max(round(max_disp1[1].item() - target_neigh_sz[1].item() / 2), 0) + tneigh_right = min(round(max_disp1[1].item() + target_neigh_sz[1].item() / 2 + 1), sz[1]) + scores_masked = scores_hn[scale_ind:scale_ind + 1, ...].clone() + scores_masked[...,tneigh_top:tneigh_bottom,tneigh_left:tneigh_right] = 0 + + # Find new maximum + max_score2, max_disp2 = dcf.max2d(scores_masked) + max_disp2 = max_disp2.float().cpu().view(-1) + target_disp2 = max_disp2 - score_center + translation_vec2 = target_disp2 * (self.img_support_sz / output_sz) * sample_scale + + prev_target_vec = (self.pos - sample_pos[scale_ind,:]) / ((self.img_support_sz / output_sz) * sample_scale) + + # Handle the different cases + if max_score2 > self.params.distractor_threshold * max_score1: + disp_norm1 = torch.sqrt(torch.sum((target_disp1-prev_target_vec)**2)) + disp_norm2 = torch.sqrt(torch.sum((target_disp2-prev_target_vec)**2)) + disp_threshold = self.params.dispalcement_scale * math.sqrt(sz[0] * sz[1]) / 2 + + if disp_norm2 > disp_threshold and disp_norm1 < disp_threshold: + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + if disp_norm2 < disp_threshold and disp_norm1 > disp_threshold: + return translation_vec2, scale_ind, scores_hn, 'hard_negative' + if disp_norm2 > disp_threshold and disp_norm1 > disp_threshold: + return translation_vec1, scale_ind, scores_hn, 'uncertain' + + # If also the distractor is close, return with highest score + return translation_vec1, scale_ind, scores_hn, 'uncertain' + + if max_score2 > self.params.hard_negative_threshold * max_score1 and max_score2 > self.params.target_not_found_threshold: + return translation_vec1, scale_ind, scores_hn, 'hard_negative' + + return translation_vec1, scale_ind, scores_hn, 'normal' + + def extract_backbone_features(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + im_patches, patch_coords = sample_patch_multiscale(im, pos, scales, sz, + mode=self.params.get('border_mode', 'replicate'), + max_scale_change=self.params.get('patch_max_scale_change', None)) + with torch.no_grad(): + backbone_feat = self.net.extract_backbone(im_patches) + return backbone_feat, patch_coords, im_patches + + def get_classification_features(self, backbone_feat): + with torch.no_grad(): + return self.net.extract_classification_feat(backbone_feat) + + def get_iou_backbone_features(self, backbone_feat): + return self.net.get_backbone_bbreg_feat(backbone_feat) + + def get_iou_features(self, backbone_feat): + with torch.no_grad(): + return self.net.bb_regressor.get_iou_feat(self.get_iou_backbone_features(backbone_feat)) + + def get_iou_modulation(self, iou_backbone_feat, target_boxes): + with torch.no_grad(): + return self.net.bb_regressor.get_modulation(iou_backbone_feat, target_boxes) + + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + """Perform data augmentation to generate initial training samples.""" + + mode = self.params.get('border_mode', 'replicate') + if mode == 'inside': + # Get new sample size if forced inside the image + im_sz = torch.Tensor([im.shape[2], im.shape[3]]) + sample_sz = self.target_scale * self.img_sample_sz + shrink_factor = (sample_sz.float() / im_sz) + if mode == 'inside': + shrink_factor = shrink_factor.max() + elif mode == 'inside_major': + shrink_factor = shrink_factor.min() + shrink_factor.clamp_(min=1, max=self.params.get('patch_max_scale_change', None)) + sample_sz = (sample_sz.float() / shrink_factor) + self.init_sample_scale = (sample_sz / self.img_sample_sz).prod().sqrt() + tl = self.pos - (sample_sz - 1) / 2 + br = self.pos + sample_sz / 2 + 1 + global_shift = - ((-tl).clamp(0) - (br - im_sz).clamp(0)) / self.init_sample_scale + else: + self.init_sample_scale = self.target_scale + global_shift = torch.zeros(2) + + self.init_sample_pos = self.pos.round() + + # Compute augmentation size + aug_expansion_factor = self.params.get('augmentation_expansion_factor', None) + aug_expansion_sz = self.img_sample_sz.clone() + aug_output_sz = None + if aug_expansion_factor is not None and aug_expansion_factor != 1: + aug_expansion_sz = (self.img_sample_sz * aug_expansion_factor).long() + aug_expansion_sz += (aug_expansion_sz - self.img_sample_sz.long()) % 2 + aug_expansion_sz = aug_expansion_sz.float() + aug_output_sz = self.img_sample_sz.long().tolist() + + # Random shift for each sample + get_rand_shift = lambda: None + random_shift_factor = self.params.get('random_shift_factor', 0) + if random_shift_factor > 0: + get_rand_shift = lambda: ((torch.rand(2) - 0.5) * self.img_sample_sz * random_shift_factor + global_shift).long().tolist() + + # Always put identity transformation first, since it is the unaugmented sample that is always used + self.transforms = [augmentation.Identity(aug_output_sz, global_shift.long().tolist())] + + augs = self.params.augmentation if self.params.get('use_augmentation', True) else {} + + # Add all augmentations + if 'shift' in augs: + self.transforms.extend([augmentation.Translation(shift, aug_output_sz, global_shift.long().tolist()) for shift in augs['shift']]) + if 'relativeshift' in augs: + get_absolute = lambda shift: (torch.Tensor(shift) * self.img_sample_sz/2).long().tolist() + self.transforms.extend([augmentation.Translation(get_absolute(shift), aug_output_sz, global_shift.long().tolist()) for shift in augs['relativeshift']]) + if 'fliplr' in augs and augs['fliplr']: + self.transforms.append(augmentation.FlipHorizontal(aug_output_sz, get_rand_shift())) + if 'blur' in augs: + self.transforms.extend([augmentation.Blur(sigma, aug_output_sz, get_rand_shift()) for sigma in augs['blur']]) + if 'scale' in augs: + self.transforms.extend([augmentation.Scale(scale_factor, aug_output_sz, get_rand_shift()) for scale_factor in augs['scale']]) + if 'rotate' in augs: + self.transforms.extend([augmentation.Rotate(angle, aug_output_sz, get_rand_shift()) for angle in augs['rotate']]) + + # Extract augmented image patches + im_patches = sample_patch_transformed(im, self.init_sample_pos, self.init_sample_scale, aug_expansion_sz, self.transforms) + + # Extract initial backbone features + with torch.no_grad(): + init_backbone_feat = self.net.extract_backbone(im_patches) + + return init_backbone_feat + + def init_target_boxes(self): + """Get the target bounding boxes for the initial augmented samples.""" + self.classifier_target_box = self.get_iounet_box(self.pos, self.target_sz, self.init_sample_pos, self.init_sample_scale) + init_target_boxes = TensorList() + for T in self.transforms: + init_target_boxes.append(self.classifier_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + init_target_boxes = torch.cat(init_target_boxes.view(1, 4), 0).to(self.params.device) + self.target_boxes = init_target_boxes.new_zeros(self.params.sample_memory_size, 4) + self.target_boxes[:init_target_boxes.shape[0],:] = init_target_boxes + return init_target_boxes + + def init_memory(self, train_x: TensorList): + # Initialize first-frame spatial training samples + self.num_init_samples = train_x.size(0) + init_sample_weights = TensorList([x.new_ones(1) / x.shape[0] for x in train_x]) + + # Sample counters and weights for spatial + self.num_stored_samples = self.num_init_samples.copy() + self.previous_replace_ind = [None] * len(self.num_stored_samples) + self.sample_weights = TensorList([x.new_zeros(self.params.sample_memory_size) for x in train_x]) + for sw, init_sw, num in zip(self.sample_weights, init_sample_weights, self.num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [x.new_zeros(self.params.sample_memory_size, x.shape[1], x.shape[2], x.shape[3]) for x in train_x]) + + for ts, x in zip(self.training_samples, train_x): + ts[:x.shape[0],...] = x + + + def update_memory(self, sample_x: TensorList, target_box, learning_rate = None): + # Update weights and get replace ind + replace_ind = self.update_sample_weights(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.num_init_samples, learning_rate) + self.previous_replace_ind = replace_ind + + # Update sample and label memory + for train_samp, x, ind in zip(self.training_samples, sample_x, replace_ind): + train_samp[ind:ind+1,...] = x + + # Update bb memory + self.target_boxes[replace_ind[0],:] = target_box + + self.num_stored_samples += 1 + + + def update_sample_weights(self, sample_weights, previous_replace_ind, num_stored_samples, num_init_samples, learning_rate = None): + # Update weights and get index to replace + replace_ind = [] + for sw, prev_ind, num_samp, num_init in zip(sample_weights, previous_replace_ind, num_stored_samples, num_init_samples): + lr = learning_rate + if lr is None: + lr = self.params.learning_rate + + init_samp_weight = self.params.get('init_samples_minimum_weight', None) + if init_samp_weight == 0: + init_samp_weight = None + s_ind = 0 if init_samp_weight is None else num_init + + if num_samp == 0 or lr == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + if num_samp < sw.shape[0]: + r_ind = num_samp + else: + _, r_ind = torch.min(sw[s_ind:], 0) + r_ind = r_ind.item() + s_ind + + # Update weights + if prev_ind is None: + sw /= 1 - lr + sw[r_ind] = lr + else: + sw[r_ind] = sw[prev_ind] / (1 - lr) + + sw /= sw.sum() + if init_samp_weight is not None and sw[:num_init].sum() < init_samp_weight: + sw /= init_samp_weight + sw[num_init:].sum() + sw[:num_init] = init_samp_weight / num_init + + replace_ind.append(r_ind) + + return replace_ind + + def update_state(self, new_pos, new_scale = None): + # Update scale + if new_scale is not None: + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = self.params.get('target_inside_ratio', 0.2) + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + + def get_iounet_box(self, pos, sz, sample_pos, sample_scale): + """All inputs in original image coordinates. + Generates a box in the cropped image sample reference frame, in the format used by the IoUNet.""" + box_center = (pos - sample_pos) / sample_scale + (self.img_sample_sz - 1) / 2 + box_sz = sz / sample_scale + target_ul = box_center - (box_sz - 1) / 2 + return torch.cat([target_ul.flip((0,)), box_sz.flip((0,))]) + + + def init_iou_net(self, backbone_feat): + # Setup IoU net and objective + for p in self.net.bb_regressor.parameters(): + p.requires_grad = False + + # Get target boxes for the different augmentations + self.classifier_target_box = self.get_iounet_box(self.pos, self.target_sz, self.init_sample_pos, self.init_sample_scale) + target_boxes = TensorList() + if self.params.iounet_augmentation: + for T in self.transforms: + if not isinstance(T, (augmentation.Identity, augmentation.Translation, augmentation.FlipHorizontal, augmentation.FlipVertical, augmentation.Blur)): + break + target_boxes.append(self.classifier_target_box + torch.Tensor([T.shift[1], T.shift[0], 0, 0])) + else: + target_boxes.append(self.classifier_target_box + torch.Tensor([self.transforms[0].shift[1], self.transforms[0].shift[0], 0, 0])) + target_boxes = torch.cat(target_boxes.view(1,4), 0).to(self.params.device) + + # Get iou features + iou_backbone_feat = self.get_iou_backbone_features(backbone_feat) + + # Remove other augmentations such as rotation + iou_backbone_feat = TensorList([x[:target_boxes.shape[0],...] for x in iou_backbone_feat]) + + # Get modulation vector + self.iou_modulation = self.get_iou_modulation(iou_backbone_feat, target_boxes) + if torch.is_tensor(self.iou_modulation[0]): + self.iou_modulation = TensorList([x.detach().mean(0) for x in self.iou_modulation]) + + + def init_classifier(self, init_backbone_feat): + # Get classification features + x = self.get_classification_features(init_backbone_feat) + + # Overwrite some parameters in the classifier. (These are not generally changed) + self._overwrite_classifier_params(feature_dim=x.shape[-3]) + + # Add the dropout augmentation here, since it requires extraction of the classification features + if 'dropout' in self.params.augmentation and self.params.get('use_augmentation', True): + num, prob = self.params.augmentation['dropout'] + self.transforms.extend(self.transforms[:1]*num) + x = torch.cat([x, F.dropout2d(x[0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + # Set feature size and other related sizes + self.feature_sz = torch.Tensor(list(x.shape[-2:])) + ksz = self.net.classifier.filter_size + self.kernel_size = torch.Tensor([ksz, ksz] if isinstance(ksz, (int, float)) else ksz) + self.output_sz = self.feature_sz + (self.kernel_size + 1)%2 + + # Construct output window + self.output_window = None + if self.params.get('window_output', False): + if self.params.get('use_clipped_window', False): + self.output_window = dcf.hann2d_clipped(self.output_sz.long(), (self.output_sz*self.params.effective_search_area / self.params.search_area_scale).long(), centered=True).to(self.params.device) + else: + self.output_window = dcf.hann2d(self.output_sz.long(), centered=True).to(self.params.device) + self.output_window = self.output_window.squeeze(0) + + # Get target boxes for the different augmentations + target_boxes = self.init_target_boxes() + + # Set number of iterations + plot_loss = self.params.debug > 0 + num_iter = self.params.get('net_opt_iter', None) + + # Get target filter by running the discriminative model prediction module + with torch.no_grad(): + self.target_filter, _, losses = self.net.classifier.get_filter(x, target_boxes, num_iter=num_iter, + compute_losses=plot_loss) + + # Init memory + if self.params.get('update_classifier', True): + self.init_memory(TensorList([x])) + + if plot_loss: + if isinstance(losses, dict): + losses = losses['train'] + self.losses = torch.cat(losses) + if self.visdom is not None: + self.visdom.register((self.losses, torch.arange(self.losses.numel())), 'lineplot', 3, 'Training Loss' + self.id_str) + elif self.params.debug >= 3: + plot_graph(self.losses, 10, title='Training Loss' + self.id_str) + + def _overwrite_classifier_params(self, feature_dim): + # Overwrite some parameters in the classifier. (These are not generally changed) + pred_module = getattr(self.net.classifier.filter_optimizer, 'score_predictor', self.net.classifier.filter_optimizer) + if self.params.get('label_threshold', None) is not None: + self.net.classifier.filter_optimizer.label_threshold = self.params.label_threshold + if self.params.get('label_shrink', None) is not None: + self.net.classifier.filter_optimizer.label_shrink = self.params.label_shrink + if self.params.get('softmax_reg', None) is not None: + self.net.classifier.filter_optimizer.softmax_reg = self.params.softmax_reg + if self.params.get('filter_reg', None) is not None: + pred_module.filter_reg[0] = self.params.filter_reg + pred_module.min_filter_reg = self.params.filter_reg + if self.params.get('filter_init_zero', False): + self.net.classifier.filter_initializer = FilterInitializerZero(self.net.classifier.filter_size, feature_dim) + + + def update_classifier(self, train_x, target_box, learning_rate=None, scores=None): + # Set flags and learning rate + hard_negative_flag = learning_rate is not None + if learning_rate is None: + learning_rate = self.params.learning_rate + + # Update the tracker memory + if hard_negative_flag or self.frame_num % self.params.get('train_sample_interval', 1) == 0: + self.update_memory(TensorList([train_x]), target_box, learning_rate) + + # Decide the number of iterations to run + num_iter = 0 + low_score_th = self.params.get('low_score_opt_threshold', None) + if hard_negative_flag: + num_iter = self.params.get('net_opt_hn_iter', None) + elif low_score_th is not None and low_score_th > scores.max().item(): + num_iter = self.params.get('net_opt_low_iter', None) + elif (self.frame_num - 1) % self.params.train_skipping == 0: + num_iter = self.params.get('net_opt_update_iter', None) + + plot_loss = self.params.debug > 0 + + if num_iter > 0: + # Get inputs for the DiMP filter optimizer module + samples = self.training_samples[0][:self.num_stored_samples[0],...] + target_boxes = self.target_boxes[:self.num_stored_samples[0],:].clone() + sample_weights = self.sample_weights[0][:self.num_stored_samples[0]] + + # Run the filter optimizer module + with torch.no_grad(): + self.target_filter, _, losses = self.net.classifier.filter_optimizer(self.target_filter, + num_iter=num_iter, feat=samples, + bb=target_boxes, + sample_weight=sample_weights, + compute_losses=plot_loss) + + if plot_loss: + if isinstance(losses, dict): + losses = losses['train'] + self.losses = torch.cat((self.losses, torch.cat(losses))) + if self.visdom is not None: + self.visdom.register((self.losses, torch.arange(self.losses.numel())), 'lineplot', 3, 'Training Loss' + self.id_str) + elif self.params.debug >= 3: + plot_graph(self.losses, 10, title='Training Loss' + self.id_str) + + def refine_target_box(self, backbone_feat, sample_pos, sample_scale, scale_ind, update_scale = True): + """Run the ATOM IoUNet to refine the target bounding box.""" + + if hasattr(self.net.bb_regressor, 'predict_bb'): + return self.direct_box_regression(backbone_feat, sample_pos, sample_scale, scale_ind, update_scale) + + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features(backbone_feat) + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + # Generate random initial boxes + init_boxes = init_box.view(1,4).clone() + if self.params.num_init_random_boxes > 0: + square_box_sz = init_box[2:].prod().sqrt() + rand_factor = square_box_sz * torch.cat([self.params.box_jitter_pos * torch.ones(2), self.params.box_jitter_sz * torch.ones(2)]) + + minimal_edge_size = init_box[2:].min()/3 + rand_bb = (torch.rand(self.params.num_init_random_boxes, 4) - 0.5) * rand_factor + new_sz = (init_box[2:] + rand_bb[:,2:]).clamp(minimal_edge_size) + new_center = (init_box[:2] + init_box[2:]/2) + rand_bb[:,:2] + init_boxes = torch.cat([new_center - new_sz/2, new_sz], 1) + init_boxes = torch.cat([init_box.view(1,4), init_boxes]) + + # Optimize the boxes + output_boxes, output_iou = self.optimize_boxes(iou_features, init_boxes) + + # Remove weird boxes + output_boxes[:, 2:].clamp_(1) + aspect_ratio = output_boxes[:,2] / output_boxes[:,3] + keep_ind = (aspect_ratio < self.params.maximal_aspect_ratio) * (aspect_ratio > 1/self.params.maximal_aspect_ratio) + output_boxes = output_boxes[keep_ind,:] + output_iou = output_iou[keep_ind] + + # If no box found + if output_boxes.shape[0] == 0: + return + + # Predict box + k = self.params.get('iounet_k', 5) + topk = min(k, output_boxes.shape[0]) + _, inds = torch.topk(output_iou, topk) + predicted_box = output_boxes[inds, :].mean(0) + predicted_iou = output_iou.view(-1, 1)[inds, :].mean(0) + + # Get new position and size + new_pos = predicted_box[:2] + predicted_box[2:] / 2 + new_pos = (new_pos.flip((0,)) - (self.img_sample_sz - 1) / 2) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + # self.visualize_iou_pred(iou_features, predicted_box) + + + def optimize_boxes(self, iou_features, init_boxes): + box_refinement_space = self.params.get('box_refinement_space', 'default') + if box_refinement_space == 'default': + return self.optimize_boxes_default(iou_features, init_boxes) + if box_refinement_space == 'relative': + return self.optimize_boxes_relative(iou_features, init_boxes) + raise ValueError('Unknown box_refinement_space {}'.format(box_refinement_space)) + + + def optimize_boxes_default(self, iou_features, init_boxes): + """Optimize iounet boxes with the default parametrization""" + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]], device=self.params.device).view(1,1,4) + + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init = output_boxes.clone().detach() + bb_init.requires_grad = True + + outputs = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient = torch.ones_like(outputs)) + + # Update proposal + output_boxes = bb_init + step_length * bb_init.grad * bb_init[:, :, 2:].repeat(1, 1, 2) + output_boxes.detach_() + + step_length *= self.params.box_refinement_step_decay + + return output_boxes.view(-1,4).cpu(), outputs.detach().view(-1).cpu() + + + def optimize_boxes_relative(self, iou_features, init_boxes): + """Optimize iounet boxes with the relative parametrization ised in PrDiMP""" + output_boxes = init_boxes.view(1, -1, 4).to(self.params.device) + step_length = self.params.box_refinement_step_length + if isinstance(step_length, (tuple, list)): + step_length = torch.Tensor([step_length[0], step_length[0], step_length[1], step_length[1]]).to(self.params.device).view(1,1,4) + + sz_norm = output_boxes[:,:1,2:].clone() + output_boxes_rel = bbutils.rect_to_rel(output_boxes, sz_norm) + for i_ in range(self.params.box_refinement_iter): + # forward pass + bb_init_rel = output_boxes_rel.clone().detach() + bb_init_rel.requires_grad = True + + bb_init = bbutils.rel_to_rect(bb_init_rel, sz_norm) + outputs = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, bb_init) + + if isinstance(outputs, (list, tuple)): + outputs = outputs[0] + + outputs.backward(gradient = torch.ones_like(outputs)) + + # Update proposal + output_boxes_rel = bb_init_rel + step_length * bb_init_rel.grad + output_boxes_rel.detach_() + + step_length *= self.params.box_refinement_step_decay + + # for s in outputs.view(-1): + # print('{:.2f} '.format(s.item()), end='') + # print('') + # print('') + + output_boxes = bbutils.rel_to_rect(output_boxes_rel, sz_norm) + + return output_boxes.view(-1,4).cpu(), outputs.detach().view(-1).cpu() + + def direct_box_regression(self, backbone_feat, sample_pos, sample_scale, scale_ind, update_scale = True): + """Implementation of direct bounding box regression.""" + + # Initial box for refinement + init_box = self.get_iounet_box(self.pos, self.target_sz, sample_pos, sample_scale) + + # Extract features from the relevant scale + iou_features = self.get_iou_features(backbone_feat) + iou_features = TensorList([x[scale_ind:scale_ind+1,...] for x in iou_features]) + + # Generate random initial boxes + init_boxes = init_box.view(1, 1, 4).clone().to(self.params.device) + + # Optimize the boxes + output_boxes = self.net.bb_regressor.predict_bb(self.iou_modulation, iou_features, init_boxes).view(-1,4).cpu() + + # Remove weird boxes + output_boxes[:, 2:].clamp_(1) + + predicted_box = output_boxes[0, :] + + # Get new position and size + new_pos = predicted_box[:2] + predicted_box[2:] / 2 + new_pos = (new_pos.flip((0,)) - (self.img_sample_sz - 1) / 2) * sample_scale + sample_pos + new_target_sz = predicted_box[2:].flip((0,)) * sample_scale + new_scale_bbr = torch.sqrt(new_target_sz.prod() / self.base_target_sz.prod()) + new_scale = new_scale_bbr + + self.pos_iounet = new_pos.clone() + + if self.params.get('use_iounet_pos_for_learning', True): + self.pos = new_pos.clone() + + self.target_sz = new_target_sz + + if update_scale: + self.target_scale = new_scale + + + def visualize_iou_pred(self, iou_features, center_box): + center_box = center_box.view(1,1,4) + sz_norm = center_box[...,2:].clone() + center_box_rel = bbutils.rect_to_rel(center_box, sz_norm) + + pos_dist = 1.0 + sz_dist = math.log(3.0) + pos_step = 0.01 + sz_step = 0.01 + + pos_scale = torch.arange(-pos_dist, pos_dist+pos_step, step=pos_step) + sz_scale = torch.arange(-sz_dist, sz_dist+sz_step, step=sz_step) + + bbx = torch.zeros(1, pos_scale.numel(), 4) + bbx[0,:,0] = pos_scale.clone() + bby = torch.zeros(pos_scale.numel(), 1, 4) + bby[:,0,1] = pos_scale.clone() + bbw = torch.zeros(1, sz_scale.numel(), 4) + bbw[0,:,2] = sz_scale.clone() + bbh = torch.zeros(sz_scale.numel(), 1, 4) + bbh[:,0,3] = sz_scale.clone() + + pos_boxes = bbutils.rel_to_rect((center_box_rel + bbx) + bby, sz_norm).view(1,-1,4).to(self.params.device) + sz_boxes = bbutils.rel_to_rect((center_box_rel + bbw) + bbh, sz_norm).view(1,-1,4).to(self.params.device) + + pos_scores = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, pos_boxes).exp() + sz_scores = self.net.bb_regressor.predict_iou(self.iou_modulation, iou_features, sz_boxes).exp() + + show_tensor(pos_scores.view(pos_scale.numel(),-1), title='Position scores', fig_num=21) + show_tensor(sz_scores.view(sz_scale.numel(),-1), title='Size scores', fig_num=22) + + + def visdom_draw_tracking(self, image, box, segmentation=None): + if hasattr(self, 'search_area_box'): + self.visdom.register((image, box, self.search_area_box), 'Tracking', 1, 'Tracking') + else: + self.visdom.register((image, box), 'Tracking', 1, 'Tracking') \ No newline at end of file diff --git a/pytracking/tracker/eco/__init__.py b/pytracking/tracker/eco/__init__.py new file mode 100755 index 0000000..26cf654 --- /dev/null +++ b/pytracking/tracker/eco/__init__.py @@ -0,0 +1,4 @@ +from .eco import ECO + +def get_tracker_class(): + return ECO \ No newline at end of file diff --git a/pytracking/tracker/eco/eco.py b/pytracking/tracker/eco/eco.py new file mode 100755 index 0000000..25e90e6 --- /dev/null +++ b/pytracking/tracker/eco/eco.py @@ -0,0 +1,385 @@ +from pytracking.tracker.base import BaseTracker +import torch +import torch.nn.functional as F +import math +from pytracking import complex, dcf, fourier, TensorList +from pytracking.libs.tensorlist import tensor_operation +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_tensor +from pytracking.libs.optimization import GaussNewtonCG +from .optim import FilterOptim, FactorizedConvProblem +from pytracking.features import augmentation + + + +class ECO(BaseTracker): + + multiobj_mode = 'parallel' + + def initialize_features(self): + if not getattr(self, 'features_initialized', False): + self.params.features.initialize() + self.features_initialized = True + + + def initialize(self, image, info: dict) -> dict: + state = info['init_bbox'] + + # Initialize some stuff + self.frame_num = 1 + if not self.params.has('device'): + self.params.device = 'cuda' if self.params.use_gpu else 'cpu' + + # Initialize features + self.initialize_features() + + # Chack if image is color + self.params.features.set_is_color(image.shape[2] == 3) + + # Get feature specific params + self.fparams = self.params.features.get_fparams('feature_params') + + # Get position and size + self.pos = torch.Tensor([state[1] + (state[3] - 1)/2, state[0] + (state[2] - 1)/2]) + self.target_sz = torch.Tensor([state[3], state[2]]) + + # Set search area + self.target_scale = 1.0 + search_area = torch.prod(self.target_sz * self.params.search_area_scale).item() + if search_area > self.params.max_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.max_image_sample_size) + elif search_area < self.params.min_image_sample_size: + self.target_scale = math.sqrt(search_area / self.params.min_image_sample_size) + + # Target size in base scale + self.base_target_sz = self.target_sz / self.target_scale + + # Use odd square search area and set sizes + feat_max_stride = max(self.params.features.stride()) + self.img_sample_sz = torch.round(torch.sqrt(torch.prod(self.base_target_sz * self.params.search_area_scale))) * torch.ones(2) + self.img_sample_sz += feat_max_stride - self.img_sample_sz % (2 * feat_max_stride) + + # Set other sizes (corresponds to ECO code) + self.img_support_sz = self.img_sample_sz + self.feature_sz = self.params.features.size(self.img_sample_sz) + self.filter_sz = self.feature_sz + (self.feature_sz + 1) % 2 + self.output_sz = self.params.score_upsample_factor * self.img_support_sz # Interpolated size of the output + self.compressed_dim = self.fparams.attribute('compressed_dim') + + # Number of filters + self.num_filters = len(self.filter_sz) + + # Get window function + self.window = TensorList([dcf.hann2d(sz).to(self.params.device) for sz in self.feature_sz]) + + # Get interpolation function + self.interp_fs = TensorList([dcf.get_interp_fourier(sz, self.params.interpolation_method, + self.params.interpolation_bicubic_a, self.params.interpolation_centering, + self.params.interpolation_windowing, self.params.device) for sz in self.filter_sz]) + + # Get regularization filter + self.reg_filter = TensorList([dcf.get_reg_filter(self.img_support_sz, self.base_target_sz, fparams).to(self.params.device) + for fparams in self.fparams]) + self.reg_energy = self.reg_filter.view(-1) @ self.reg_filter.view(-1) + + # Get label function + output_sigma_factor = self.fparams.attribute('output_sigma_factor') + sigma = (self.filter_sz / self.img_support_sz) * torch.sqrt(self.base_target_sz.prod()) * output_sigma_factor + self.yf = TensorList([dcf.label_function(sz, sig).to(self.params.device) for sz, sig in zip(self.filter_sz, sigma)]) + + # Optimization options + self.params.precond_learning_rate = self.fparams.attribute('learning_rate') + if self.params.CG_forgetting_rate is None or max(self.params.precond_learning_rate) >= 1: + self.params.direction_forget_factor = 0 + else: + self.params.direction_forget_factor = (1 - max(self.params.precond_learning_rate))**self.params.CG_forgetting_rate + + + # Convert image + im = numpy_to_torch(image) + + # Setup bounds + self.image_sz = torch.Tensor([im.shape[2], im.shape[3]]) + self.min_scale_factor = torch.max(10 / self.base_target_sz) + self.max_scale_factor = torch.min(self.image_sz / self.base_target_sz) + + # Extract and transform sample + x = self.generate_init_samples(im) + + # Initialize projection matrix + x_mat = TensorList([e.permute(1,0,2,3).reshape(e.shape[1], -1).clone() for e in x]) + x_mat -= x_mat.mean(dim=1, keepdim=True) + cov_x = x_mat @ x_mat.t() + self.projection_matrix = TensorList([torch.svd(C)[0][:,:cdim].clone() for C, cdim in zip(cov_x, self.compressed_dim)]) + + # Transform to get the training sample + train_xf = self.preprocess_sample(x) + + # Shift the samples back + if 'shift' in self.params.augmentation: + for xf in train_xf: + if xf.shape[0] == 1: + continue + for i, shift in enumerate(self.params.augmentation['shift']): + shift_samp = 2 * math.pi * torch.Tensor(shift) / self.img_support_sz + xf[1+i:2+i,...] = fourier.shift_fs(xf[1+i:2+i,...], shift=shift_samp) + + # Shift sample + shift_samp = 2*math.pi * (self.pos - self.pos.round()) / (self.target_scale * self.img_support_sz) + train_xf = fourier.shift_fs(train_xf, shift=shift_samp) + + # Initialize first-frame training samples + num_init_samples = train_xf.size(0) + self.init_sample_weights = TensorList([xf.new_ones(1) / xf.shape[0] for xf in train_xf]) + self.init_training_samples = train_xf.permute(2, 3, 0, 1, 4) + + + # Sample counters and weights + self.num_stored_samples = num_init_samples + self.previous_replace_ind = [None]*len(self.num_stored_samples) + self.sample_weights = TensorList([xf.new_zeros(self.params.sample_memory_size) for xf in train_xf]) + for sw, init_sw, num in zip(self.sample_weights, self.init_sample_weights, num_init_samples): + sw[:num] = init_sw + + # Initialize memory + self.training_samples = TensorList( + [xf.new_zeros(xf.shape[2], xf.shape[3], self.params.sample_memory_size, cdim, 2) for xf, cdim in zip(train_xf, self.compressed_dim)]) + + # Initialize filter + self.filter = TensorList( + [xf.new_zeros(1, cdim, xf.shape[2], xf.shape[3], 2) for xf, cdim in zip(train_xf, self.compressed_dim)]) + + # Do joint optimization + self.joint_problem = FactorizedConvProblem(self.init_training_samples, self.yf, self.reg_filter, self.projection_matrix, self.params, self.init_sample_weights) + joint_var = self.filter.concat(self.projection_matrix) + self.joint_optimizer = GaussNewtonCG(self.joint_problem, joint_var, debug=(self.params.debug>=1), visdom=self.visdom) + + if self.params.update_projection_matrix: + self.joint_optimizer.run(self.params.init_CG_iter // self.params.init_GN_iter, self.params.init_GN_iter) + + # Re-project samples with the new projection matrix + compressed_samples = complex.mtimes(self.init_training_samples, self.projection_matrix) + for train_samp, init_samp in zip(self.training_samples, compressed_samples): + train_samp[:,:,:init_samp.shape[2],:,:] = init_samp + + # Initialize optimizer + self.filter_optimizer = FilterOptim(self.params, self.reg_energy) + self.filter_optimizer.register(self.filter, self.training_samples, self.yf, self.sample_weights, self.reg_filter) + self.filter_optimizer.sample_energy = self.joint_problem.sample_energy + self.filter_optimizer.residuals = self.joint_optimizer.residuals.clone() + + if not self.params.update_projection_matrix: + self.filter_optimizer.run(self.params.init_CG_iter) + + # Post optimization + self.filter_optimizer.run(self.params.post_init_CG_iter) + + self.symmetrize_filter() + + + + def track(self, image, info: dict = None) -> dict: + self.debug_info = {} + + self.frame_num += 1 + self.debug_info['frame_num'] = self.frame_num + + # Convert image + im = numpy_to_torch(image) + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.pos.round() + sample_scales = self.target_scale * self.params.scale_factors + test_xf = self.extract_fourier_sample(im, self.pos, sample_scales, self.img_sample_sz) + + # Compute scores + sf = self.apply_filter(test_xf) + translation_vec, scale_ind, s = self.localize_target(sf) + scale_change_factor = self.params.scale_factors[scale_ind] + + # Update position and scale + self.update_state(sample_pos + translation_vec, self.target_scale * scale_change_factor) + + score_map = s[scale_ind, ...] + max_score = torch.max(score_map).item() + self.debug_info['max_score'] = max_score + + if self.visdom is not None: + self.visdom.register(score_map, 'heatmap', 2, 'Score Map') + self.visdom.register(self.debug_info, 'info_dict', 1, 'Status') + elif self.params.debug >= 2: + show_tensor(score_map, 5, title='Max score = {:.2f}'.format(max_score)) + + # if self.params.debug >= 3: + # for i, hf in enumerate(self.filter): + # show_tensor(fourier.sample_fs(hf).abs().mean(1), 6+i) + + + # ------- UPDATE ------- # + + # Get train sample + train_xf = TensorList([xf[scale_ind:scale_ind+1, ...] for xf in test_xf]) + + # Shift the sample + shift_samp = 2*math.pi * (self.pos - sample_pos) / (sample_scales[scale_ind] * self.img_support_sz) + train_xf = fourier.shift_fs(train_xf, shift=shift_samp) + + # Update memory + self.update_memory(train_xf) + + # Train filter + if self.frame_num % self.params.train_skipping == 1: + self.filter_optimizer.run(self.params.CG_iter, train_xf) + self.symmetrize_filter() + + # Return new state + new_state = torch.cat((self.pos[[1,0]] - (self.target_sz[[1,0]]-1)/2, self.target_sz[[1,0]])) + + out = {'target_bbox': new_state.tolist()} + return out + + + def apply_filter(self, sample_xf: TensorList) -> torch.Tensor: + return complex.mult(self.filter, sample_xf).sum(1, keepdim=True) + + def localize_target(self, sf: TensorList): + if self.params.score_fusion_strategy == 'sum': + scores = fourier.sample_fs(fourier.sum_fs(sf), self.output_sz) + elif self.params.score_fusion_strategy == 'weightedsum': + weight = self.fparams.attribute('translation_weight') + scores = fourier.sample_fs(fourier.sum_fs(weight * sf), self.output_sz) + elif self.params.score_fusion_strategy == 'transcale': + alpha = self.fparams.attribute('scale_weight') + beta = self.fparams.attribute('translation_weight') + sample_sz = torch.round(self.output_sz.view(1,-1) * self.params.scale_factors.view(-1,1)) + scores = 0 + for sfe, a, b in zip(sf, alpha, beta): + sfe = fourier.shift_fs(sfe, math.pi*torch.ones(2)) + scores_scales = [] + for sind, sz in enumerate(sample_sz): + pd = (self.output_sz-sz)/2 + scores_scales.append(F.pad(fourier.sample_fs(sfe[sind:sind+1,...], sz), + (math.floor(pd[1].item()), math.ceil(pd[1].item()), + math.floor(pd[0].item()), math.ceil(pd[0].item())))) + scores_cat = torch.cat(scores_scales) + scores = scores + (b - a) * scores_cat.mean(dim=0, keepdim=True) + a * scores_cat + else: + raise ValueError('Unknown score fusion strategy.') + + # Get maximum + max_score, max_disp = dcf.max2d(scores) + _, scale_ind = torch.max(max_score, dim=0) + max_disp = max_disp.float().cpu() + + # Convert to displacements in the base scale + if self.params.score_fusion_strategy in ['sum', 'weightedsum']: + disp = (max_disp + self.output_sz / 2) % self.output_sz - self.output_sz / 2 + elif self.params.score_fusion_strategy == 'transcale': + disp = max_disp - self.output_sz / 2 + + # Compute translation vector and scale change factor + translation_vec = disp[scale_ind, ...].view(-1) * (self.img_support_sz / self.output_sz) * self.target_scale + if self.params.score_fusion_strategy in ['sum', 'weightedsum']: + translation_vec *= self.params.scale_factors[scale_ind] + + return translation_vec, scale_ind, scores + + + def extract_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor): + return self.params.features.extract(im, pos, scales, sz)[0] + + def extract_fourier_sample(self, im: torch.Tensor, pos: torch.Tensor, scales, sz: torch.Tensor) -> TensorList: + x = self.extract_sample(im, pos, scales, sz) + return self.preprocess_sample(self.project_sample(x)) + + def preprocess_sample(self, x: TensorList) -> TensorList: + x *= self.window + sample_xf = fourier.cfft2(x) + return TensorList([dcf.interpolate_dft(xf, bf) for xf, bf in zip(sample_xf, self.interp_fs)]) + + def project_sample(self, x: TensorList): + @tensor_operation + def _project_sample(x: torch.Tensor, P: torch.Tensor): + if P is None: + return x + return torch.matmul(x.permute(2, 3, 0, 1), P).permute(2, 3, 0, 1) + + return _project_sample(x, self.projection_matrix) + + def generate_init_samples(self, im: torch.Tensor) -> TensorList: + # Do data augmentation + transforms = [augmentation.Identity()] + if 'shift' in self.params.augmentation: + transforms.extend([augmentation.Translation(shift) for shift in self.params.augmentation['shift']]) + if 'fliplr' in self.params.augmentation and self.params.augmentation['fliplr']: + transforms.append(augmentation.FlipHorizontal()) + if 'rotate' in self.params.augmentation: + transforms.extend([augmentation.Rotate(angle) for angle in self.params.augmentation['rotate']]) + if 'blur' in self.params.augmentation: + transforms.extend([augmentation.Blur(sigma) for sigma in self.params.augmentation['blur']]) + + init_samples = self.params.features.extract_transformed(im, self.pos, self.target_scale, self.img_sample_sz, transforms) + + # Remove augmented samples for those that shall not have + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if not use_aug: + init_samples[i] = init_samples[i][0:1, ...] + + if 'dropout' in self.params.augmentation: + num, prob = self.params.augmentation['dropout'] + for i, use_aug in enumerate(self.fparams.attribute('use_augmentation')): + if use_aug: + init_samples[i] = torch.cat([init_samples[i], F.dropout2d(init_samples[i][0:1,...].expand(num,-1,-1,-1), p=prob, training=True)]) + + return init_samples + + + def update_memory(self, sample_xf: TensorList): + # Update weights and get index to replace + replace_ind = self.update_sample_weights() + for train_samp, xf, ind in zip(self.training_samples, sample_xf, replace_ind): + train_samp[:,:,ind:ind+1,:,:] = xf.permute(2, 3, 0, 1, 4) + + + def update_sample_weights(self): + replace_ind = [] + for sw, prev_ind, num_samp, fparams in zip(self.sample_weights, self.previous_replace_ind, self.num_stored_samples, self.fparams): + if num_samp == 0 or fparams.learning_rate == 1: + sw[:] = 0 + sw[0] = 1 + r_ind = 0 + else: + # Get index to replace + _, r_ind = torch.min(sw, 0) + r_ind = r_ind.item() + + # Update weights + if prev_ind is None: + sw /= 1 - fparams.learning_rate + sw[r_ind] = fparams.learning_rate + else: + sw[r_ind] = sw[prev_ind] / (1 - fparams.learning_rate) + + sw /= sw.sum() + replace_ind.append(r_ind) + + self.previous_replace_ind = replace_ind.copy() + self.num_stored_samples += 1 + return replace_ind + + def update_state(self, new_pos, new_scale): + # Update scale + self.target_scale = new_scale.clamp(self.min_scale_factor, self.max_scale_factor) + self.target_sz = self.base_target_sz * self.target_scale + + # Update pos + inside_ratio = 0.2 + inside_offset = (inside_ratio - 0.5) * self.target_sz + self.pos = torch.max(torch.min(new_pos, self.image_sz - inside_offset), inside_offset) + + def symmetrize_filter(self): + for hf in self.filter: + hf[:,:,:,0,:] /= 2 + hf[:,:,:,0,:] += complex.conj(hf[:,:,:,0,:].flip((2,))) \ No newline at end of file diff --git a/pytracking/tracker/eco/optim.py b/pytracking/tracker/eco/optim.py new file mode 100755 index 0000000..32d9c64 --- /dev/null +++ b/pytracking/tracker/eco/optim.py @@ -0,0 +1,208 @@ +import torch +import torch.nn.functional as F +from pytracking import complex, optimization, fourier, TensorList +from pytracking.utils.plotting import plot_graph +import math + + +class FactorizedConvProblem(optimization.L2Problem): + def __init__(self, training_samples: TensorList, yf:TensorList, reg_filter: torch.Tensor, init_proj_mat: TensorList, params, sample_weights: torch.Tensor = None): + self.training_samples = training_samples + self.yf = complex.complex(yf).permute(2, 3, 0, 1, 4) + self.reg_filter = reg_filter + self.sample_weights_sqrt = None if sample_weights is None else sample_weights.sqrt() + self.params = params + + # Sample energy for preconditioner + compressed_samples = complex.mtimes(self.training_samples, init_proj_mat) + self.sample_energy = complex.abs_sqr(compressed_samples).mean(dim=2, keepdim=True).permute(2, 3, 0, 1) + self.reg_energy = self.reg_filter.view(-1) @ self.reg_filter.view(-1) + + # Projection energy for preconditioner + self.proj_energy = 2 * fourier.inner_prod_fs(yf, yf) / self.training_samples.size(3) + + # Filter part of preconditioner + self.diag_M = (1 - self.params.precond_reg_param) * (self.params.precond_data_param * self.sample_energy + + (1 - self.params.precond_data_param) * self.sample_energy.mean(1, keepdim=True)) + \ + self.params.precond_reg_param * self.reg_energy + self.diag_M.unsqueeze_(-1) + + # Projection matrix part of preconditioner + self.diag_M.extend(self.params.precond_proj_param * (self.proj_energy + self.params.projection_reg)) + + + def __call__(self, x: TensorList): + """ + Compute residuals + :param x: [filters, projection_matrices] + :return: [data_terms, filter_regularizations, proj_mat_regularizations] + """ + hf = x[:len(x)//2] + P = x[len(x)//2:] + + compressed_samples = complex.mtimes(self.training_samples, P) + residuals = complex.mtimes(compressed_samples, hf.permute(2, 3, 1, 0, 4)) # (h, w, num_samp, num_filt, 2) + residuals = residuals - self.yf + + if self.sample_weights_sqrt is not None: + residuals = complex.mult(self.sample_weights_sqrt.view(1, 1, -1, 1), residuals) + + + # Add spatial regularization + for hfe, reg_filter in zip(hf, self.reg_filter): + reg_pad1 = min(reg_filter.shape[-2] - 1, hfe.shape[-3] - 1) + reg_pad2 = min(reg_filter.shape[-1] - 1, hfe.shape[-2] - 1) + + # Add part needed for convolution + if reg_pad2 > 0: + hfe_left_padd = complex.conj(hfe[...,1:reg_pad2+1,:].clone().detach().flip((2,3))) + hfe_conv = torch.cat([hfe_left_padd, hfe], -2) + else: + hfe_conv = hfe.clone() + + # Shift data to batch dimension + hfe_conv = hfe_conv.permute(0,1,4,2,3).reshape(-1, 1, hfe_conv.shape[-3], hfe_conv.shape[-2]) + + # Do first convolution + hfe_conv = F.conv2d(hfe_conv, reg_filter, padding=(reg_pad1, reg_pad2)) + + residuals.append(hfe_conv) + + # Add regularization for projection matrix + residuals.extend(math.sqrt(self.params.projection_reg) * P) + + return residuals + + + def ip_input(self, a: TensorList, b: TensorList): + num = len(a) // 2 # Number of filters + a_filter = a[:num] + b_filter = b[:num] + a_P = a[num:] + b_P = b[num:] + + # Filter inner product + ip_out = fourier.inner_prod_fs(a_filter, b_filter) + + # Add projection matrix part + ip_out += a_P.reshape(-1) @ b_P.reshape(-1) + + # Have independent inner products for each filter + return ip_out.concat(ip_out.clone()) + + + def ip_output(self, a: TensorList, b: TensorList): + num = len(a) // 3 # Number of filters + a_data = a[:num].permute(2,3,0,1,4) + b_data = b[:num].permute(2,3,0,1,4) + a_filt_reg = a[num:2*num] + b_filt_reg = b[num:2*num] + a_P_reg = a[2*num:] + b_P_reg = b[2*num:] + + ip_data = sum(fourier.inner_prod_fs(a_data, b_data)) + ip_filt_reg = ip_data.new_zeros(1) + + for ar, br, res_data, reg_filter in zip(a_filt_reg, b_filt_reg, a_data, self.reg_filter): + reg_pad2 = min(reg_filter.shape[-1] - 1, res_data.shape[-2] - 1) + arp = ar.reshape(1, -1, 2, ar.shape[2], ar.shape[3]).permute(0, 1, 3, 4, 2) + brp = br.reshape(1, -1, 2, br.shape[2], br.shape[3]).permute(0, 1, 3, 4, 2) + ip_filt_reg += fourier.inner_prod_fs(arp[:,:,:,2*reg_pad2:,:], brp[:,:,:,2*reg_pad2:,:]) + + ip_P_reg = sum(a_P_reg.view(-1) @ b_P_reg.view(-1)) + + return ip_data + ip_filt_reg + ip_P_reg + + + def M1(self, x: TensorList): + return x / self.diag_M + + +class FilterOptim(optimization.ConjugateGradientBase): + def __init__(self, params, reg_energy): + super(FilterOptim, self).__init__(params.fletcher_reeves, params.standard_alpha, params.direction_forget_factor, (params.debug >= 3)) + + # Parameters + self.params = params + + self.reg_energy = reg_energy + self.sample_energy = None + + self.residuals = torch.zeros(0) + + + def register(self, filter, training_samples, yf, sample_weights, reg_filter): + self.filter = filter + self.training_samples = training_samples # (h, w, num_samples, num_channels, 2) + self.yf = yf + self.sample_weights = sample_weights + self.reg_filter = reg_filter + + + def run(self, num_iter, new_xf: TensorList = None): + if num_iter == 0: + return + + if new_xf is not None: + new_sample_energy = complex.abs_sqr(new_xf) + if self.sample_energy is None: + self.sample_energy = new_sample_energy + else: + self.sample_energy = (1 - self.params.precond_learning_rate) * self.sample_energy + self.params.precond_learning_rate * new_sample_energy + + # Compute right hand side + self.b = complex.mtimes(self.sample_weights.view(1,1,1,-1), self.training_samples).permute(2,3,0,1,4) + self.b = complex.mult_conj(self.yf, self.b) + + self.diag_M = (1 - self.params.precond_reg_param) * (self.params.precond_data_param * self.sample_energy + + (1 - self.params.precond_data_param) * self.sample_energy.mean(1, keepdim=True)) + self.params.precond_reg_param * self.reg_energy + + _, res = self.run_CG(num_iter, self.filter) + + if self.debug: + self.residuals = torch.cat((self.residuals, res)) + plot_graph(self.residuals, 9) + + + + def A(self, hf: TensorList): + # Classify + sh = complex.mtimes(self.training_samples, hf.permute(2,3,1,0,4)) # (h, w, num_samp, num_filt, 2) + sh = complex.mult(self.sample_weights.view(1,1,-1,1), sh) + + # Multiply with transpose + hf_out = complex.mtimes(sh.permute(0,1,3,2,4), self.training_samples, conj_b=True).permute(2,3,0,1,4) + + # Add regularization + for hfe, hfe_out, reg_filter in zip(hf, hf_out, self.reg_filter): + reg_pad1 = min(reg_filter.shape[-2] - 1, hfe.shape[-3] - 1) + reg_pad2 = min(reg_filter.shape[-1] - 1, 2*hfe.shape[-2]- 2) + + # Add part needed for convolution + if reg_pad2 > 0: + hfe_conv = torch.cat([complex.conj(hfe[...,1:reg_pad2+1,:].flip((2,3))), hfe], -2) + else: + hfe_conv = hfe.clone() + + # Shift data to batch dimension + hfe_conv = hfe_conv.permute(0,1,4,2,3).reshape(-1, 1, hfe_conv.shape[-3], hfe_conv.shape[-2]) + + # Do first convolution + hfe_conv = F.conv2d(hfe_conv, reg_filter, padding=(reg_pad1, reg_pad2)) + + # Do second convolution + remove_size = min(reg_pad2, hfe.shape[-2]-1) + hfe_conv = F.conv2d(hfe_conv[...,remove_size:], reg_filter) + + # Reshape back and add + hfe_out += hfe_conv.reshape(hfe.shape[0], hfe.shape[1], 2, hfe.shape[2], hfe.shape[3]).permute(0,1,3,4,2) + + return hf_out + + + def ip(self, a: torch.Tensor, b: torch.Tensor): + return fourier.inner_prod_fs(a, b) + + + def M1(self, hf): + return complex.div(hf, self.diag_M) diff --git a/pytracking/util_scripts/__init__.py b/pytracking/util_scripts/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/pytracking/util_scripts/download_results.py b/pytracking/util_scripts/download_results.py new file mode 100755 index 0000000..d251873 --- /dev/null +++ b/pytracking/util_scripts/download_results.py @@ -0,0 +1,217 @@ +import os +import sys +import gdown +import re +import shutil +import argparse +import tempfile + +env_path = os.path.join(os.path.dirname(__file__), '../..') +if env_path not in sys.path: + sys.path.append(env_path) + +from pytracking.evaluation.environment import env_settings + +pytracking_results_link_dict = { + "dimp": { + "prdimp50_003.zip": "1p13j3iwcOCubBi3ms0hLwqnP6-x0J8Mc", + "prdimp50_002.zip": "1PPKgrAepbuyM2kjfzYAozQKTL6AjcQOz", + "prdimp50_001.zip": "17NFBObEDeK6mW4Mk2vN5Ekk1SGbFvxRS", + "prdimp50_000.zip": "1r3Efq7AumML2yGQ_KV4zmf4ATKVE1bo6", + "prdimp18_004.zip": "1DF4ZJQAa4CwvN_OiT4te33AV0kpsO7JM", + "prdimp18_003.zip": "1RgwJAN4TxnzgVgsfvrHIg1OUXD1EBZkO", + "prdimp18_002.zip": "17lMllYhygCqgE81DoHX4BZar3xc3auzM", + "prdimp18_001.zip": "1Yg7DmGYOnn2k0MYtSjjKlGyzO1Uimj4G", + "prdimp18_000.zip": "1DuZJSBJ-23WJBQTOWSAaoPYSbGAJJN2Z", + "prdimp50_004.zip": "1f9bx9-dtx3B5_IvIJhjjJyp-cnXciqLO", + "dimp50_004.zip": "1Lj3p8mYCoIqxzdQXZkWFTw-MA8c6eeLa", + "dimp50_000.zip": "1LCgf5sg453Z4bY37A_W5mbXeG68U1fET", + "dimp18_000.zip": "17M7dJZ1oKrIY4-O5lL_mlQPEubUn034g", + "dimp18_001.zip": "1AsiliVgISyDTouYOQYVOXA0srj3YskhJ", + "dimp50_got_001.zip": "1EE5FcPXqMBkv_0ghfzytCMmbKxWxy04p", + "dimp18_002.zip": "1I0GrBaPnySOyPWSvItHhXH8182tFCi_Y", + "dimp50_got_002.zip": "1ALXzVkn58GZ1E0I22vrbXkEXwy5u0xOc", + "dimp18_got_000.zip": "1BxowlgGEonnuaVXwiDwiYr7VV7BRWLvr", + "dimp50_001.zip": "1XfPvwAcymW88J1rq7RlhyKmqsawJDK-K", + "dimp18_got_002.zip": "1awqXQnFRr5NwjLfI-Ngtt3zT7XmQIwzs", + "dimp18_got_001.zip": "1rr2J6NuuYJ5E4wDUw-PrxaNKjIsfgAyk", + "dimp50_got_000.zip": "1ruP8XJOu0woq-bvKdHJ9_Y9RceHDrDjm", + "dimp18_004.zip": "1EztF6bpROFwZ1PSJWgMB7bQ4G_Z08YIg", + "dimp18_003.zip": "1iuiFLv04WE7GfBjm8UkZXFq4gheG2Ru8", + "dimp50_003.zip": "1rLsgeQXyKpD6ryl9BjlIVdO3vd27ekwy", + "dimp50_002.zip": "1wj2jUwlpHgsP1hAcuxXAVriUPuEspsu4", + }, + "atom": { + "default_004.zip": "1BapnQh_8iRM44DXj862eOZV4q8zQLdmT", + "default_003.zip": "1YpfOBLBEUQQiX0fWMPA5pnW3dm0NG3E5", + "default_got_000.zip": "1uJnC0PPQhavwRbAL7VQ2Zow8YdLVzeCb", + "default_got_001.zip": "1YzJm0H31veDW-lMxwy8MYNpMULgsYHKf", + "default_000.zip": "1x6fKGZk3V839mX99Gl_pw7JUaiMaTxc5", + "default_002.zip": "1QIlQFv3p6MBTwsYdIMYmzUDBDQGxGsUC", + "default_001.zip": "1-K2--GNCURDKEgUuiEF18K4DcCLvDEVt", + "default_got_002.zip": "1qGtArxdAy0uWSd-HqFT5zmXpR6TCm4Vc", + }, +} + +external_results_link_dict = { + "UPDT": { + "default_009.zip": "11zrgjiRL-gyRFsx5ZzycBpHb3a9rknA4", + "default_008.zip": "1397XtEgFY68Ska6qo-cnGnwU4Dj6F-yE", + "default_007.zip": "1fi4w32daXwfhbmLKao7esRw9JPXpKnwE", + "default_006.zip": "14XxeykT-o1Ovj9KJocertk5zt6UaYB57", + "default_005.zip": "1k5Mm4WNKUlWPTdsHyjxpJwFsUD8zmNo4", + "default_004.zip": "1E3HcRScBf7_wyzS_4jH6fBbRUw9HJ3Tb", + "default_003.zip": "1FdYCYp1KxGb2cwwvGG8tGk1-odY6a7T-", + "default_002.zip": "19V3JaO7bNnhxIYD_OFdvUDGua9Oq3b7H", + "default_001.zip": "18ie7rpLMxVRm-P4JmiS_VLBaibW6YQMz", + "default_000.zip": "1i4mBqcNWxx9b0t-0hH_k65c-XkkGnZfi", + }, + "SiamRPN++": { + "default.zip": "1a_hBzAeTojEy_zueDxjwh2egv-EIfHnv", + }, + "MDNet": { + "default.zip": "18J0-5QrYbyGlnXXLNeF8g3mzgayxmEM1", + }, + "ECO": { + "default_hc.zip": "1M5fpL_b9KHjaHe-eMnfFYhNuTzdvzngb", + "default_deep.zip": "1548ZhXdplOBFFxRG-kSNctSQsoOWHMrp", + }, + "DaSiamRPN": { + "default.zip": "1ckxL3nt4es6SfpAEUzVLhRrPYVsGK3Oi", + }, + "CCOT": { + "default.zip": "1yt_KpURIHQthwls5w3mcPsi9ia7fNih9", + }, +} + + +def _download_file(file_id, path): + link = 'https://drive.google.com/uc?id=' + file_id + gdown.download(link, path, quiet=True) + + +def download_results(download_path, trackers='pytracking'): + """ + Script to automatically download tracker results for PyTracking. + + args: + download_path - Directory where the zipped results are downloaded + trackers - Tracker results which are to be downloaded. + If set to 'pytracking', results for all pytracking based trackers will be downloaded. + If set to 'external', results for available external trackers will be downloaded. + If set to 'all', all available results are downloaded. + If set to a name of a tracker (e.g. atom), all results for that tracker are downloaded. + Otherwise, it can be set to a dict, where the keys are the names of the trackers for which results are + downloaded. The value can be set to either 'all', in which case all available results for the + tracker are downloaded. Else the value should be a list of parameter file names. + """ + print('Using download path ''{}'''.format(download_path)) + + os.makedirs(download_path, exist_ok=True) + + if isinstance(trackers, str): + if trackers == 'all': + all_trackers = list(pytracking_results_link_dict.keys()) + list(external_results_link_dict.keys()) + trackers = {k: 'all' for k in all_trackers} + elif trackers == 'pytracking': + trackers = {k: 'all' for k in pytracking_results_link_dict.keys()} + elif trackers == 'external': + trackers = {k: 'all' for k in external_results_link_dict.keys()} + elif trackers in pytracking_results_link_dict or trackers in external_results_link_dict: + trackers = {trackers: 'all'} + else: + raise Exception('tracker_list must be set to ''all'', a tracker name, or be a dict') + elif isinstance(trackers, dict): + pass + else: + raise Exception('tracker_list must be set to ''all'', or be a dict') + + common_link_dict = pytracking_results_link_dict + for k, v in external_results_link_dict.items(): + common_link_dict[k] = v + + for trk, runfiles in trackers.items(): + trk_path = os.path.join(download_path, trk) + if not os.path.exists(trk_path): + os.makedirs(trk_path) + + if runfiles == 'all': + for params, fileid in common_link_dict[trk].items(): + print('Downloading: {}/{}'.format(trk, params)) + _download_file(fileid, os.path.join(trk_path, params)) + elif isinstance(runfiles, (list, tuple)): + for p in runfiles: + for params, fileid in common_link_dict[trk].items(): + if re.match(r'{}(|_(\d\d\d)).zip'.format(p), params) is not None: + print('Downloading: {}/{}'.format(trk, params)) + _download_file(fileid, os.path.join(trk_path, params)) + + else: + raise Exception('tracker_list values must either be set to ''all'', or be a list of param names') + + + +def unpack_tracking_results(download_path, output_path=None): + """ + Unpacks zipped benchmark results. The directory 'download_path' should have the following structure + - root + - tracker1 + - param1.zip + - param2.zip + . + . + - tracker2 + - param1.zip + - param2.zip + . + . + + args: + download_path - Path to the directory where the zipped results are stored + output_path - Path to the directory where the results will be unpacked. Set to env_settings().results_path + by default + """ + + if output_path is None: + output_path = env_settings().results_path + + if not os.path.exists(output_path): + os.makedirs(output_path) + + trackers = os.listdir(download_path) + + for t in trackers: + runfiles = os.listdir(os.path.join(download_path, t)) + + for r in runfiles: + save_path = os.path.join(output_path, t) + if not os.path.exists(save_path): + os.makedirs(save_path) + shutil.unpack_archive(os.path.join(download_path, t, r), os.path.join(save_path, r[:-4]), 'zip') + + +def main(): + parser = argparse.ArgumentParser(description='Download and unpack zipped results') + parser.add_argument('--tracker', type=str, default='pytracking', + help='Name of tracker results to download, or "pytracking" (downloads results for PyTracking' + ' based trackers, or "external" (downloads results for external trackers) or "all"') + parser.add_argument('--output_path', type=str, default=None, + help='Path to the directory where the results will be unpacked.') + parser.add_argument('--temp_download_path', type=str, default=None, + help='Temporary path used for downloading the Zip files.') + parser.add_argument('--download', type=bool, default=True, + help='Whether to download results or unpack existing downloaded files.') + args = parser.parse_args() + + download_path = args.temp_download_path + if download_path is None: + download_path = '{}/pytracking_results/'.format(tempfile.gettempdir()) + + if args.download: + download_results(download_path, args.tracker) + + unpack_tracking_results(download_path, args.output_path) + + +if __name__ == '__main__': + main() diff --git a/pytracking/util_scripts/pack_got10k_results.py b/pytracking/util_scripts/pack_got10k_results.py new file mode 100755 index 0000000..f1c036b --- /dev/null +++ b/pytracking/util_scripts/pack_got10k_results.py @@ -0,0 +1,42 @@ +import numpy as np +import os +import shutil +from pytracking.evaluation.environment import env_settings + + +def pack_got10k_results(tracker_name, param_name, output_name): + """ Packs got10k results into a zip folder which can be directly uploaded to the evaluation server. The packed + file is saved in the folder env_settings().got_packed_results_path + + args: + tracker_name - name of the tracker + param_name - name of the parameter file + output_name - name of the packed zip file + """ + output_path = os.path.join(env_settings().got_packed_results_path, output_name) + + if not os.path.exists(output_path): + os.makedirs(output_path) + + results_path = env_settings().results_path + for i in range(1,181): + seq_name = 'GOT-10k_Test_{:06d}'.format(i) + + seq_output_path = '{}/{}'.format(output_path, seq_name) + if not os.path.exists(seq_output_path): + os.makedirs(seq_output_path) + + for run_id in range(3): + res = np.loadtxt('{}/{}/{}_{:03d}/{}.txt'.format(results_path, tracker_name, param_name, run_id, seq_name), dtype=np.float64) + times = np.loadtxt( + '{}/{}/{}_{:03d}/{}_time.txt'.format(results_path, tracker_name, param_name, run_id, seq_name), + dtype=np.float64) + + np.savetxt('{}/{}_{:03d}.txt'.format(seq_output_path, seq_name, run_id+1), res, delimiter=',', fmt='%f') + np.savetxt('{}/{}_time.txt'.format(seq_output_path, seq_name), times, fmt='%f') + + # Generate ZIP file + shutil.make_archive(output_path, 'zip', output_path) + + # Remove raw text files + shutil.rmtree(output_path) diff --git a/pytracking/util_scripts/pack_trackingnet_results.py b/pytracking/util_scripts/pack_trackingnet_results.py new file mode 100755 index 0000000..40fb76a --- /dev/null +++ b/pytracking/util_scripts/pack_trackingnet_results.py @@ -0,0 +1,50 @@ +import numpy as np +import os +import shutil +from pytracking.evaluation.environment import env_settings +from pytracking.evaluation.datasets import get_dataset + + +def pack_trackingnet_results(tracker_name, param_name, run_id=None, output_name=None): + """ Packs trackingnet results into a zip folder which can be directly uploaded to the evaluation server. The packed + file is saved in the folder env_settings().tn_packed_results_path + + args: + tracker_name - name of the tracker + param_name - name of the parameter file + run_id - run id for the tracker + output_name - name of the packed zip file + """ + + if output_name is None: + if run_id is None: + output_name = '{}_{}'.format(tracker_name, param_name) + else: + output_name = '{}_{}_{:03d}'.format(tracker_name, param_name, run_id) + + output_path = os.path.join(env_settings().tn_packed_results_path, output_name) + + if not os.path.exists(output_path): + os.makedirs(output_path) + + results_path = env_settings().results_path + + tn_dataset = get_dataset('trackingnet') + + for seq in tn_dataset: + seq_name = seq.name + + if run_id is None: + seq_results_path = '{}/{}/{}/{}.txt'.format(results_path, tracker_name, param_name, seq_name) + else: + seq_results_path = '{}/{}/{}_{:03d}/{}.txt'.format(results_path, tracker_name, param_name, run_id, seq_name) + + results = np.loadtxt(seq_results_path, dtype=np.float64) + + np.savetxt('{}/{}.txt'.format(output_path, seq_name), results, delimiter=',', fmt='%.2f') + + # Generate ZIP file + shutil.make_archive(output_path, 'zip', output_path) + + # Remove raw text files + shutil.rmtree(output_path) diff --git a/pytracking/utils/__init__.py b/pytracking/utils/__init__.py new file mode 100755 index 0000000..8d83e11 --- /dev/null +++ b/pytracking/utils/__init__.py @@ -0,0 +1 @@ +from .params import TrackerParams, FeatureParams, Choice \ No newline at end of file diff --git a/pytracking/utils/__pycache__/__init__.cpython-37.pyc b/pytracking/utils/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..1ef03ca Binary files /dev/null and b/pytracking/utils/__pycache__/__init__.cpython-37.pyc differ diff --git a/pytracking/utils/__pycache__/convert_vot_anno_to_rect.cpython-37.pyc b/pytracking/utils/__pycache__/convert_vot_anno_to_rect.cpython-37.pyc new file mode 100755 index 0000000..46c4123 Binary files /dev/null and b/pytracking/utils/__pycache__/convert_vot_anno_to_rect.cpython-37.pyc differ diff --git a/pytracking/utils/__pycache__/loading.cpython-37.pyc b/pytracking/utils/__pycache__/loading.cpython-37.pyc new file mode 100755 index 0000000..31e1cd8 Binary files /dev/null and b/pytracking/utils/__pycache__/loading.cpython-37.pyc differ diff --git a/pytracking/utils/__pycache__/params.cpython-37.pyc b/pytracking/utils/__pycache__/params.cpython-37.pyc new file mode 100755 index 0000000..35ab4bb Binary files /dev/null and b/pytracking/utils/__pycache__/params.cpython-37.pyc differ diff --git a/pytracking/utils/__pycache__/plotting.cpython-37.pyc b/pytracking/utils/__pycache__/plotting.cpython-37.pyc new file mode 100755 index 0000000..d33c17e Binary files /dev/null and b/pytracking/utils/__pycache__/plotting.cpython-37.pyc differ diff --git a/pytracking/utils/__pycache__/visdom.cpython-37.pyc b/pytracking/utils/__pycache__/visdom.cpython-37.pyc new file mode 100755 index 0000000..7a0d395 Binary files /dev/null and b/pytracking/utils/__pycache__/visdom.cpython-37.pyc differ diff --git a/pytracking/utils/convert_vot_anno_to_rect.py b/pytracking/utils/convert_vot_anno_to_rect.py new file mode 100755 index 0000000..e0d1c64 --- /dev/null +++ b/pytracking/utils/convert_vot_anno_to_rect.py @@ -0,0 +1,37 @@ +import numpy as np + + +def convert_vot_anno_to_rect(vot_anno, type): + if len(vot_anno) == 4: + return vot_anno + + if type == 'union': + x1 = min(vot_anno[0::2]) + x2 = max(vot_anno[0::2]) + y1 = min(vot_anno[1::2]) + y2 = max(vot_anno[1::2]) + return [x1, y1, x2 - x1, y2 - y1] + elif type == 'preserve_area': + if len(vot_anno) != 8: + raise ValueError + + vot_anno = np.array(vot_anno) + cx = np.mean(vot_anno[0::2]) + cy = np.mean(vot_anno[1::2]) + + x1 = min(vot_anno[0::2]) + x2 = max(vot_anno[0::2]) + y1 = min(vot_anno[1::2]) + y2 = max(vot_anno[1::2]) + + A1 = np.linalg.norm(vot_anno[0:2] - vot_anno[2: 4]) * np.linalg.norm(vot_anno[2: 4] - vot_anno[4:6]) + A2 = (x2 - x1) * (y2 - y1) + s = np.sqrt(A1 / A2) + w = s * (x2 - x1) + 1 + h = s * (y2 - y1) + 1 + + x = cx - 0.5*w + y = cy - 0.5*h + return [x, y, w, h] + else: + raise ValueError diff --git a/pytracking/utils/load_text.py b/pytracking/utils/load_text.py new file mode 100755 index 0000000..919536c --- /dev/null +++ b/pytracking/utils/load_text.py @@ -0,0 +1,41 @@ +import numpy as np +import pandas as pd + + +def load_text_numpy(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = np.loadtxt(path, delimiter=d, dtype=dtype) + return ground_truth_rect + except: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = np.loadtxt(path, delimiter=delimiter, dtype=dtype) + return ground_truth_rect + + +def load_text_pandas(path, delimiter, dtype): + if isinstance(delimiter, (tuple, list)): + for d in delimiter: + try: + ground_truth_rect = pd.read_csv(path, delimiter=d, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + except Exception as e: + pass + + raise Exception('Could not read file {}'.format(path)) + else: + ground_truth_rect = pd.read_csv(path, delimiter=delimiter, header=None, dtype=dtype, na_filter=False, + low_memory=False).values + return ground_truth_rect + + +def load_text(path, delimiter=' ', dtype=np.float32, backend='numpy'): + if backend == 'numpy': + return load_text_numpy(path, delimiter, dtype) + elif backend == 'pandas': + return load_text_pandas(path, delimiter, dtype) diff --git a/pytracking/utils/loading.py b/pytracking/utils/loading.py new file mode 100755 index 0000000..55846a7 --- /dev/null +++ b/pytracking/utils/loading.py @@ -0,0 +1,33 @@ +import os +import ltr.admin.loading as ltr_loading +from pytracking.evaluation.environment import env_settings + + +def load_network(net_path, **kwargs): + """Load network for tracking. + args: + net_path - Path to network. If it is not an absolute path, it is relative to the network_path in the local.py. + See ltr.admin.loading.load_network for further details. + **kwargs - Additional key-word arguments that are sent to ltr.admin.loading.load_network. + """ + kwargs['backbone_pretrained'] = False + if os.path.isabs(net_path): + path_full = net_path + net, _ = ltr_loading.load_network(path_full, **kwargs) + elif isinstance(env_settings().network_path, (list, tuple)): + net = None + for p in env_settings().network_path: + path_full = os.path.join(p, net_path) + try: + net, _ = ltr_loading.load_network(path_full, **kwargs) + break + except Exception as e: + # print(e) + pass + + assert net is not None, 'Failed to load network' + else: + path_full = os.path.join(env_settings().network_path, net_path) + net, _ = ltr_loading.load_network(path_full, **kwargs) + + return net diff --git a/pytracking/utils/params.py b/pytracking/utils/params.py new file mode 100755 index 0000000..b3cdb04 --- /dev/null +++ b/pytracking/utils/params.py @@ -0,0 +1,43 @@ +from pytracking import TensorList +import random + + +class TrackerParams: + """Class for tracker parameters.""" + def set_default_values(self, default_vals: dict): + for name, val in default_vals.items(): + if not hasattr(self, name): + setattr(self, name, val) + + def get(self, name: str, *default): + """Get a parameter value with the given name. If it does not exists, it return the default value given as a + second argument or returns an error if no default value is given.""" + if len(default) > 1: + raise ValueError('Can only give one default value.') + + if not default: + return getattr(self, name) + + return getattr(self, name, default[0]) + + def has(self, name: str): + """Check if there exist a parameter with the given name.""" + return hasattr(self, name) + + +class FeatureParams: + """Class for feature specific parameters""" + def __init__(self, *args, **kwargs): + if len(args) > 0: + raise ValueError + + for name, val in kwargs.items(): + if isinstance(val, list): + setattr(self, name, TensorList(val)) + else: + setattr(self, name, val) + + +def Choice(*args): + """Can be used to sample random parameter values.""" + return random.choice(args) diff --git a/pytracking/utils/plotting.py b/pytracking/utils/plotting.py new file mode 100755 index 0000000..47869fe --- /dev/null +++ b/pytracking/utils/plotting.py @@ -0,0 +1,155 @@ +import matplotlib.pyplot as plt +import numpy as np +import torch +import cv2 + + +def draw_figure(fig): + fig.canvas.draw() + fig.canvas.flush_events() + plt.pause(0.001) + + +def show_tensor(a: torch.Tensor, fig_num = None, title = None, range=(None, None), ax=None): + """Display a 2D tensor. + args: + fig_num: Figure number. + title: Title of figure. + """ + a_np = a.squeeze().cpu().clone().detach().numpy() + if a_np.ndim == 3: + a_np = np.transpose(a_np, (1, 2, 0)) + + if ax is None: + fig = plt.figure(fig_num) + plt.tight_layout() + plt.cla() + plt.imshow(a_np, vmin=range[0], vmax=range[1]) + plt.axis('off') + plt.axis('equal') + if title is not None: + plt.title(title) + draw_figure(fig) + else: + ax.cla() + ax.imshow(a_np, vmin=range[0], vmax=range[1]) + ax.set_axis_off() + ax.axis('equal') + if title is not None: + ax.set_title(title) + draw_figure(plt.gcf()) + + +def plot_graph(a: torch.Tensor, fig_num = None, title = None): + """Plot graph. Data is a 1D tensor. + args: + fig_num: Figure number. + title: Title of figure. + """ + a_np = a.squeeze().cpu().clone().detach().numpy() + if a_np.ndim > 1: + raise ValueError + fig = plt.figure(fig_num) + # plt.tight_layout() + plt.cla() + plt.plot(a_np) + if title is not None: + plt.title(title) + draw_figure(fig) + + +def show_image_with_boxes(im, boxes, iou_pred=None, disp_ids=None): + im_np = im.clone().cpu().squeeze().numpy() + im_np = np.ascontiguousarray(im_np.transpose(1, 2, 0).astype(np.uint8)) + + boxes = boxes.view(-1, 4).cpu().numpy().round().astype(int) + + # Draw proposals + for i_ in range(boxes.shape[0]): + if disp_ids is None or disp_ids[i_]: + bb = boxes[i_, :] + disp_color = (i_*38 % 256, (255 - i_*97) % 256, (123 + i_*66) % 256) + cv2.rectangle(im_np, (bb[0], bb[1]), (bb[0] + bb[2], bb[1] + bb[3]), + disp_color, 1) + + if iou_pred is not None: + text_pos = (bb[0], bb[1] - 5) + cv2.putText(im_np, 'ID={} IOU = {:3.2f}'.format(i_, iou_pred[i_]), text_pos, + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1, bottomLeftOrigin=False) + + im_tensor = torch.from_numpy(im_np.transpose(2, 0, 1)).float() + + return im_tensor + + + +def _pascal_color_map(N=256, normalized=False): + """ + Python implementation of the color map function for the PASCAL VOC data set. + Official Matlab version can be found in the PASCAL VOC devkit + http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html#devkit + """ + + def bitget(byteval, idx): + return (byteval & (1 << idx)) != 0 + + dtype = 'float32' if normalized else 'uint8' + cmap = np.zeros((N, 3), dtype=dtype) + for i in range(N): + r = g = b = 0 + c = i + for j in range(8): + r = r | (bitget(c, 0) << 7 - j) + g = g | (bitget(c, 1) << 7 - j) + b = b | (bitget(c, 2) << 7 - j) + c = c >> 3 + + cmap[i] = np.array([r, g, b]) + + cmap = cmap / 255 if normalized else cmap + return cmap + + +def overlay_mask(im, ann, alpha=0.5, colors=None, contour_thickness=None): + """ Overlay mask over image. + Source: https://github.com/albertomontesg/davis-interactive/blob/master/davisinteractive/utils/visualization.py + This function allows you to overlay a mask over an image with some + transparency. + # Arguments + im: Numpy Array. Array with the image. The shape must be (H, W, 3) and + the pixels must be represented as `np.uint8` data type. + ann: Numpy Array. Array with the mask. The shape must be (H, W) and the + values must be intergers + alpha: Float. Proportion of alpha to apply at the overlaid mask. + colors: Numpy Array. Optional custom colormap. It must have shape (N, 3) + being N the maximum number of colors to represent. + contour_thickness: Integer. Thickness of each object index contour draw + over the overlay. This function requires to have installed the + package `opencv-python`. + # Returns + Numpy Array: Image of the overlay with shape (H, W, 3) and data type + `np.uint8`. + """ + im, ann = np.asarray(im, dtype=np.uint8), np.asarray(ann, dtype=np.int) + if im.shape[:-1] != ann.shape: + raise ValueError('First two dimensions of `im` and `ann` must match') + if im.shape[-1] != 3: + raise ValueError('im must have three channels at the 3 dimension') + + colors = colors or _pascal_color_map() + colors = np.asarray(colors, dtype=np.uint8) + + mask = colors[ann] + fg = im * alpha + (1 - alpha) * mask + + img = im.copy() + img[ann > 0] = fg[ann > 0] + + if contour_thickness: # pragma: no cover + import cv2 + for obj_id in np.unique(ann[ann > 0]): + contours = cv2.findContours((ann == obj_id).astype( + np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[-2:] + cv2.drawContours(img, contours[0], -1, colors[obj_id].tolist(), + contour_thickness) + return img diff --git a/pytracking/utils/visdom.py b/pytracking/utils/visdom.py new file mode 100755 index 0000000..72ae3b9 --- /dev/null +++ b/pytracking/utils/visdom.py @@ -0,0 +1,428 @@ +import visdom +import visdom.server +from pytracking.features.preprocessing import numpy_to_torch +from pytracking.utils.plotting import show_image_with_boxes, overlay_mask +import cv2 +import torch +import copy +import numpy as np +from collections import OrderedDict + + +class VisBase: + def __init__(self, visdom, show_data, title): + self.visdom = visdom + self.show_data = show_data + self.title = title + self.raw_data = None + + def update(self, data, **kwargs): + self.save_data(data, **kwargs) + + if self.show_data: + self.draw_data() + + def save_data(self, data, **kwargs): + raise NotImplementedError + + def draw_data(self): + raise NotImplementedError + + def toggle_display(self, new_mode=None): + if new_mode is not None: + self.show_data = new_mode + else: + self.show_data = not self.show_data + + if self.show_data: + self.draw_data() + else: + self.visdom.close(self.title) + + +class VisImage(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + data = data.float() + self.raw_data = data + + def draw_data(self): + self.visdom.image(self.raw_data.clone(), opts={'title': self.title}, win=self.title) + + +class VisHeatmap(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + data = data.squeeze().flip(0) + self.raw_data = data + + def draw_data(self): + self.visdom.heatmap(self.raw_data.clone(), opts={'title': self.title}, win=self.title) + + +class VisFeaturemap(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.block_list = None + + def block_list_callback_handler(self, data): + self.block_list[data['propertyId']]['value'] = data['value'] + self.visdom.properties(self.block_list, opts={'title': 'Featuremap UI'}, win='featuremap_ui') + self.draw_data() + + def save_data(self, data): + data = data.view(-1, *data.shape[-2:]) + data = data.flip(1) + if self.block_list is None: + self.block_list = [] + self.draw_feat = [] + for i in range(data.shape[0]): + self.block_list.append({'type': 'checkbox', 'name': 'Channel {:04d}'.format(i), 'value': False}) + + self.visdom.properties(self.block_list, opts={'title': 'Featuremap UI'}, win='featuremap_ui') + self.visdom.register_event_handler(self.block_list_callback_handler, 'featuremap_ui') + + self.raw_data = data + + def draw_data(self): + if self.block_list is not None and self.show_data: + for i, d in enumerate(self.block_list): + if d['value']: + fig_title = '{} ch: {:04d}'.format(self.title, i) + self.visdom.heatmap(self.raw_data[i, :, :].clone(), + opts={'title': fig_title}, win=fig_title) + + +class VisCostVolume(VisBase): + def __init__(self, visdom, show_data, title, flip=False): + super().__init__(visdom, show_data, title) + self.show_slice = False + self.slice_pos = None + self.flip = flip + + def show_cost_volume(self): + data = self.raw_data.clone() + + # data_perm = data.permute(2, 0, 3, 1).contiguous() + data_perm = data.permute(0, 2, 1, 3).contiguous() + if self.flip: + data_perm = data_perm.permute(2, 3, 0, 1).contiguous() + + data_perm = data_perm.view(data_perm.shape[0] * data_perm.shape[1], -1) + self.visdom.heatmap(data_perm.flip(0), opts={'title': self.title}, win=self.title) + + def set_zoom_pos(self, slice_pos): + self.slice_pos = slice_pos + + def toggle_show_slice(self, new_mode=None): + if new_mode is not None: + self.show_slice = new_mode + else: + self.show_slice = not self.show_slice + + def show_cost_volume_slice(self): + slice_pos = self.slice_pos + + # slice_pos: [row, col] + cost_volume_data = self.raw_data.clone() + + if self.flip: + cost_volume_slice = cost_volume_data[:, :, slice_pos[0], slice_pos[1]] + else: + cost_volume_slice = cost_volume_data[slice_pos[0], slice_pos[1], :, :] + self.visdom.heatmap(cost_volume_slice.flip(0), opts={'title': self.title}, win=self.title) + + def save_data(self, data): + data = data.view(data.shape[-2], data.shape[-1], data.shape[-2], data.shape[-1]) + self.raw_data = data + + def draw_data(self): + if self.show_slice: + self.show_cost_volume_slice() + else: + self.show_cost_volume() + + +class VisCostVolumeUI(VisBase): + def cv_ui_handler(self, data): + zoom_toggled = False + if data['event_type'] == 'KeyPress': + if data['key'] == 'ArrowRight': + self.zoom_pos[1] = min(self.zoom_pos[1] + 1, self.feat_shape[1]-1) + elif data['key'] == 'ArrowLeft': + self.zoom_pos[1] = max(self.zoom_pos[1] - 1, 0) + elif data['key'] == 'ArrowUp': + self.zoom_pos[0] = max(self.zoom_pos[0] - 1, 0) + elif data['key'] == 'ArrowDown': + self.zoom_pos[0] = min(self.zoom_pos[0] + 1, self.feat_shape[0]-1) + elif data['key'] == 'Enter': + self.zoom_mode = not self.zoom_mode + zoom_toggled = True + + # Update image + self.show_image() + + # Update cost volumes + for block_title, block in self.registered_blocks.items(): + if isinstance(block, VisCostVolume): + block.set_zoom_pos(self.zoom_pos) + block.toggle_show_slice(self.zoom_mode) + + if (self.zoom_mode or zoom_toggled) and block.show_data: + block.draw_data() + + def __init__(self, visdom, show_data, title, feat_shape, registered_blocks): + super().__init__(visdom, show_data, title) + self.feat_shape = feat_shape + self.zoom_mode = False + self.zoom_pos = [int((feat_shape[0] - 1) / 2), int((feat_shape[1] - 1) / 2)] + self.registered_blocks = registered_blocks + + self.visdom.register_event_handler(self.cv_ui_handler, title) + + def draw_grid(self, data): + stride_r = int(data.shape[1] / self.feat_shape[0]) + stride_c = int(data.shape[2] / self.feat_shape[1]) + + # Draw grid + data[:, list(range(0, data.shape[1], stride_r)), :] = 0 + data[:, :, list(range(0, data.shape[2], stride_c))] = 0 + + data[0, list(range(0, data.shape[1], stride_r)), :] = 255 + data[0, :, list(range(0, data.shape[2], stride_c))] = 255 + + return data + + def shade_cell(self, data): + stride_r = int(data.shape[1] / self.feat_shape[0]) + stride_c = int(data.shape[2] / self.feat_shape[1]) + + r1 = self.zoom_pos[0]*stride_r + r2 = min((self.zoom_pos[0] + 1)*stride_r, data.shape[1]) + + c1 = self.zoom_pos[1] * stride_c + c2 = min((self.zoom_pos[1] + 1) * stride_c, data.shape[2]) + + factor = 0.8 if self.zoom_mode else 0.5 + data[:, r1:r2, c1:c2] = data[:, r1:r2, c1:c2] * (1 - factor) + torch.tensor([255.0, 0.0, 0.0]).view(3, 1, 1).to(data.device) * factor + return data + + def show_image(self, data=None): + if data is None: + data = self.raw_data.clone() + + data = self.draw_grid(data) + data = self.shade_cell(data) + self.visdom.image(data, opts={'title': self.title}, win=self.title) + + def save_data(self, data): + # Ignore feat shape + data = data[0] + data = data.float() + self.raw_data = data + + def draw_data(self): + self.show_image(self.raw_data.clone()) + + +class VisInfoDict(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.raw_data = OrderedDict() + + def generate_display_text(self, data): + display_text = '' + for key, value in data.items(): + key = key.replace('_', ' ') + if value is None: + display_text += '<b>{}</b>: {}<br>'.format(key, 'None') + elif isinstance(value, (str, int)): + display_text += '<b>{}</b>: {}<br>'.format(key, value) + else: + display_text += '<b>{}</b>: {:.2f}<br>'.format(key, value) + + return display_text + + def save_data(self, data): + for key, val in data.items(): + self.raw_data[key] = val + + def draw_data(self): + data = copy.deepcopy(self.raw_data) + display_text = self.generate_display_text(data) + self.visdom.text(display_text, opts={'title': self.title}, win=self.title) + + +class VisText(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + self.raw_data = data + + def draw_data(self): + data = copy.deepcopy(self.raw_data) + self.visdom.text(data, opts={'title': self.title}, win=self.title) + + +class VisLinePlot(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + self.raw_data = data + + def draw_data(self): + if isinstance(self.raw_data, (list, tuple)): + data_y = self.raw_data[0].clone() + data_x = self.raw_data[1].clone() + else: + data_y = self.raw_data.clone() + data_x = torch.arange(data_y.shape[0]) + + self.visdom.line(data_y, data_x, opts={'title': self.title}, win=self.title) + + +class VisTracking(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + + def save_data(self, data): + image = data[0] + boxes_masks = data[1:] + + boxes, masks = [], [] + for bm in boxes_masks: + if bm is None: + continue + if isinstance(bm, list): + boxes.append(torch.Tensor(bm)); continue + if len(bm.shape) > 1: + # Binarize segmentation if a float tensor is provided + if bm.dtype != np.uint8: + bm = (bm > 0.5).astype(np.uint8) + masks.append(bm); continue + boxes.append(bm.float()) + + self.raw_data = [image, boxes, masks] + + def draw_data(self): + disp_image = self.raw_data[0].copy() + + resize_factor = 1 + if max(disp_image.shape) > 480: + resize_factor = 480.0 / float(max(disp_image.shape)) + disp_image = cv2.resize(disp_image, None, fx=resize_factor, fy=resize_factor) + for i, mask in enumerate(self.raw_data[2]): + self.raw_data[2][i] = cv2.resize(mask, None, fx=resize_factor, fy=resize_factor) + + boxes = [resize_factor * b.clone() for b in self.raw_data[1]] + + for i, disp_rect in enumerate(boxes): + color = ((255*((i%3)>0)), 255*((i+1)%2), (255*(i%5))//4) + cv2.rectangle(disp_image, + (int(disp_rect[0]), int(disp_rect[1])), + (int(disp_rect[0] + disp_rect[2]), int(disp_rect[1] + disp_rect[3])), color, 2) + for i, mask in enumerate(self.raw_data[2], 1): + disp_image = overlay_mask(disp_image, mask * i) + disp_image = numpy_to_torch(disp_image).squeeze(0) + disp_image = disp_image.float() + self.visdom.image(disp_image, opts={'title': self.title}, win=self.title) + + +class VisBBReg(VisBase): + def __init__(self, visdom, show_data, title): + super().__init__(visdom, show_data, title) + self.block_list = [] + + def block_list_callback_handler(self, data): + self.block_list[data['propertyId']]['value'] = data['value'] + self.visdom.properties(self.block_list, opts={'title': 'BBReg Vis'}, win='bbreg_vis') + self.draw_data() + + def save_data(self, data): + self.image = data[0].float() + self.init_boxes = data[1] + self.final_boxes = data[2] + self.final_ious = data[3] + + def draw_data(self): + if len(self.block_list) == 0: + self.block_list.append({'type': 'checkbox', 'name': 'ID 0', 'value': True}) + self.block_list.append({'type': 'checkbox', 'name': 'ID 1', 'value': True}) + self.visdom.properties(self.block_list, opts={'title': 'BBReg Vis'}, win='bbreg_vis') + self.visdom.register_event_handler(self.block_list_callback_handler, 'bbreg_vis') + + disp_image = self.image + + ids = [x['value'] for x in self.block_list] + init_box_image = show_image_with_boxes(disp_image.clone(), self.init_boxes.clone(), disp_ids=ids) + final_box_image = show_image_with_boxes(disp_image.clone(), self.final_boxes.clone(), self.final_ious.clone(), disp_ids=ids) + + self.visdom.image(init_box_image, opts={'title': 'Init Boxes'}, win='Init Boxes') + self.visdom.image(final_box_image, opts={'title': 'Final Boxes'}, win='Final Boxes') + + +class Visdom: + def __init__(self, debug=0, ui_info=None, visdom_info=None): + self.debug = debug + self.visdom = visdom.Visdom(server=visdom_info.get('server', '127.0.0.1'), port=visdom_info.get('port', 8097)) + self.registered_blocks = {} + self.blocks_list = [] + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + self.visdom.register_event_handler(self.block_list_callback_handler, 'block_list') + + if ui_info is not None: + self.visdom.register_event_handler(ui_info['handler'], ui_info['win_id']) + + def block_list_callback_handler(self, data): + field_name = self.blocks_list[data['propertyId']]['name'] + + self.registered_blocks[field_name].toggle_display(data['value']) + + self.blocks_list[data['propertyId']]['value'] = data['value'] + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + + def register(self, data, mode, debug_level=0, title='Data', **kwargs): + if title not in self.registered_blocks.keys(): + show_data = self.debug >= debug_level + + if title != 'Tracking': + self.blocks_list.append({'type': 'checkbox', 'name': title, 'value': show_data}) + + self.visdom.properties(self.blocks_list, opts={'title': 'Block List'}, win='block_list') + + if mode == 'image': + self.registered_blocks[title] = VisImage(self.visdom, show_data, title) + elif mode == 'heatmap': + self.registered_blocks[title] = VisHeatmap(self.visdom, show_data, title) + elif mode == 'cost_volume': + self.registered_blocks[title] = VisCostVolume(self.visdom, show_data, title) + elif mode == 'cost_volume_flip': + self.registered_blocks[title] = VisCostVolume(self.visdom, show_data, title, flip=True) + elif mode == 'cost_volume_ui': + self.registered_blocks[title] = VisCostVolumeUI(self.visdom, show_data, title, data[1], + self.registered_blocks) + elif mode == 'info_dict': + self.registered_blocks[title] = VisInfoDict(self.visdom, show_data, title) + elif mode == 'text': + self.registered_blocks[title] = VisText(self.visdom, show_data, title) + elif mode == 'lineplot': + self.registered_blocks[title] = VisLinePlot(self.visdom, show_data, title) + elif mode == 'Tracking': + self.registered_blocks[title] = VisTracking(self.visdom, show_data, title) + elif mode == 'bbreg': + self.registered_blocks[title] = VisBBReg(self.visdom, show_data, title) + elif mode == 'featmap': + self.registered_blocks[title] = VisFeaturemap(self.visdom, show_data, title) + else: + raise ValueError('Visdom Error: Unknown data mode {}'.format(mode)) + # Update + self.registered_blocks[title].update(data, **kwargs) + diff --git a/requirements.txt b/requirements.txt new file mode 100755 index 0000000..06531a6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,89 @@ +-f https://download.pytorch.org/whl/torch_stable.html +absl-py==0.8.1 +addict==2.2.1 +albumentations==0.4.5 +astor==0.8.0 +attrs==19.3.0 +cachetools==4.1.0 +certifi==2019.11.28 +cffi==1.13.2 +chardet==3.0.4 +colorama==0.4.3 +cycler==0.10.0 +Cython==0.29.14 +decorator==4.4.2 +gast==0.2.2 +google-auth==1.11.0 +google-auth-oauthlib==0.4.1 +google-pasta==0.1.8 +grpcio==1.28.1 +h5py==2.10.0 +idna==2.8 +imagecorruptions==1.0.0 +imageio==2.8.0 +imgaug==0.2.6 +importlib-metadata==1.6.0 +joblib==0.14.1 +jpeg4py==0.1.4 +jsonpatch==1.25 +jsonpointer==2.0 +jsonschema==3.2.0 +Keras-Applications==1.0.8 +Keras-Preprocessing==1.1.0 +kiwisolver==1.1.0 +llvmlite==0.32.0 +Markdown==3.1.1 +matplotlib==3.1.3 +mkl +mmcv==0.2.14 +networkx==2.4 +numba==0.49.0 +numpy==1.18.1 +oauthlib==3.1.0 +olefile==0.46 +opencv-python==4.2.0.32 +opt-einsum==3.1.0 +ordered-set==4.0.1 +pandas==1.0.0 +Pillow==7.0.0 +protobuf==3.11.2 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycocotools==2.0.2 +pycparser==2.19 +PyLaTeX==1.3.1 +pyparsing==2.4.6 +pyrsistent==0.16.0 +python-dateutil==2.8.1 +pytz==2019.3 +PyWavelets==1.1.1 +PyYAML==5.3.1 +pyzmq==18.1.1 +requests==2.22.0 +requests-oauthlib==1.3.0 +rsa==4.0 +scikit-image==0.16.2 +scikit-learn==0.22.2.post1 +scipy==1.2.1 +Shapely==1.7.0 +six==1.14.0 +sklearn==0.0 +tb-nightly==2.2.0a20200205 +tensorboard==1.15.0 +tensorflow-gpu==1.15.0 +tensorflow-estimator==1.15.1 +termcolor==1.1.0 +terminaltables==3.1.0 +torch==1.4.0 +torchfile==0.1.0 +torchvision==0.5.0 +tornado==6.0.3 +tqdm==4.37.0 +urllib3==1.25.9 +visdom==0.1.8.9 +vot-trax==3.0.2 +webencodings==0.5.1 +websocket-client==0.57.0 +Werkzeug==0.16.1 +wrapt==1.11.2 +zipp==3.1.0 diff --git a/tracker_vot.py b/tracker_vot.py new file mode 100755 index 0000000..2ac9738 --- /dev/null +++ b/tracker_vot.py @@ -0,0 +1,521 @@ + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from vot_path import base_path +import cv2 +import os +import torch +import numpy as np +import math +import tensorflow as tf +import sys +import time +import copy +sys.path.append(os.path.join(base_path, 'CoCoLoT/meta_updater')) +sys.path.append(os.path.join(base_path, 'CoCoLoT/utils/metric_net')) +from tcNet import tclstm +from tcopt import tcopts +from metric_model import ft_net +from torch.autograd import Variable +from me_sample_generator import * +import vot +os.environ["CUDA_VISIBLE_DEVICES"] = "0" + +# Dimp +import argparse +from pytracking.libs.tensorlist import TensorList +from pytracking.utils.plotting import show_tensor +from pytracking.features.preprocessing import numpy_to_torch +env_path = os.path.join(os.path.dirname(__file__)) +if env_path not in sys.path: + sys.path.append(env_path) +from pytracking.evaluation import Tracker as pyTracker + +from PIL import Image, ImageDraw, ImageFont +Image.MAX_IMAGE_PIXELS = 1000000000 +from tracking_utils import compute_iou, show_res, process_regions + + +sys.path.append(os.path.join(base_path, 'CoCoLoT/pyMDNet/modules')) +sys.path.append(os.path.join(base_path, 'CoCoLoT/pyMDNet/tracking')) +# pymdnet +from pyMDNet.modules.model import * +sys.path.insert(0, './pyMDNet') +from pyMDNet.modules.model import MDNet, BCELoss, set_optimizer +from pyMDNet.modules.sample_generator import SampleGenerator +from pyMDNet.modules.utils import overlap_ratio +from pyMDNet.tracking.data_prov import RegionExtractor +from pyMDNet.tracking.run_tracker import * +from bbreg import BBRegressor +from gen_config import gen_config +opts = yaml.safe_load(open(os.path.join(base_path, 'CoCoLoT/pyMDNet/tracking/options.yaml'), 'r')) + +from Stark.lib.test.vot20.stark_vot20lt import * + +import random + +SEED = 150 +torch.manual_seed(SEED) +np.random.seed(SEED) +torch.cuda.manual_seed_all(SEED) + +#tf.compat.v1.reset_default_graph() + +class p_config(object): + Verification = "rtmdnet" + name = 'Dimp_MU' + model_dir = 'dimp_mu_votlt' + checkpoint = 220000 + start_frame = 200 + R_candidates = 20 + save_results = False + use_mask = True + save_training_data = False + visualization = True + + +class CoCoLoT_Tracker(object): + + def __init__(self, image, region, p=None, groundtruth=None): + self.p = p + self.i = 0 + self.t_id = 0 + if groundtruth is not None: + self.groundtruth = groundtruth + + tfconfig = tf.compat.v1.ConfigProto() + tfconfig.gpu_options.per_process_gpu_memory_fraction = 0.3 + self.sess = tf.compat.v1.Session(config=tfconfig) + init_gt1 = [region.x, region.y, region.width, region.height] + init_gt = [init_gt1[1], init_gt1[0], init_gt1[1]+init_gt1[3], init_gt1[0]+init_gt1[2]] # ymin xmin ymax xmax + + self.last_gt = init_gt # when initialized assumes ground-truth values + self.init_pymdnet(image, init_gt1) + self.local_init(image, init_gt1) + + + + self.tc_init(self.p.model_dir) + self.metric_init(image, np.array(init_gt1)) + self.dis_record = [] + self.state_record = [] + self.rv_record = [] + self.all_map = [] + self.count = 0 + local_state1, self.score_map, update, self.score_max, dis, flag = self.local_track(image) + self.local_Tracker.pos = torch.FloatTensor( + [(self.last_gt[0] + self.last_gt[2] - 1) / 2, (self.last_gt[1] + self.last_gt[3] - 1) / 2]) + self.local_Tracker.target_sz = torch.FloatTensor( + [(self.last_gt[2] - self.last_gt[0]), (self.last_gt[3] - self.last_gt[1])]) # height, width + + init_stark = [int(init_gt1[0]), int(init_gt1[1]), int(init_gt1[2]), int(init_gt1[3])] + self.stark_init(image, init_stark) + + self.boxes = [init_gt1] + self.boxes_stark = [init_gt1] + self.boxes_dimp = [init_gt1] + self.confidences = [1.0] + self.md_scores_dimp = [1.0] + self.md_scores_stark = [1.0] + self.md_scores_sum = [5] + + self.last_good = copy.copy(self.last_gt) + self.last_good_idx = 0 + + self.img_shape = image.shape + + + def get_first_state(self): + return self.score_map, self.score_max + + def stark_init(self, image, init_box): + self.stark_tracker = stark_vot20_lt(tracker_name='stark_st', para_name='baseline') + self.stark_tracker.initialize(image, init_box) + + def init_pymdnet(self, image, init_bbox): + target_bbox = np.array(init_bbox) + self.last_result = target_bbox + self.pymodel = MDNet(os.path.join(base_path, 'CoCoLoT/pyMDNet/models/mdnet_imagenet_vid.pth')) + if opts['use_gpu']: + self.pymodel = self.pymodel.cuda() + self.pymodel.set_learnable_params(opts['ft_layers']) + + # Init criterion and optimizer + self.criterion = BCELoss() + init_optimizer = set_optimizer(self.pymodel, opts['lr_init'], opts['lr_mult']) + self.update_optimizer = set_optimizer(self.pymodel, opts['lr_update'], opts['lr_mult']) + + tic = time.time() + + # Draw pos/neg samples + pos_examples = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos'])( + target_bbox, opts['n_pos_init'], opts['overlap_pos_init']) + + neg_examples = np.concatenate([ + SampleGenerator('uniform', image.size, opts['trans_neg_init'], opts['scale_neg_init'])( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init']), + SampleGenerator('whole', image.size)( + target_bbox, int(opts['n_neg_init'] * 0.5), opts['overlap_neg_init'])]) + neg_examples = np.random.permutation(neg_examples) + + # Extract pos/neg features + pos_feats = forward_samples(self.pymodel, image, pos_examples, opts) + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.feat_dim = pos_feats.size(-1) + + # Initial training + train(self.pymodel, self.criterion, init_optimizer, pos_feats, neg_feats, opts['maxiter_init'], opts=opts) + del init_optimizer, neg_feats + torch.cuda.empty_cache() + + # Train bbox regressor + bbreg_examples = SampleGenerator('uniform', image.size, opts['trans_bbreg'], opts['scale_bbreg'], + opts['aspect_bbreg'])( + target_bbox, opts['n_bbreg'], opts['overlap_bbreg']) + bbreg_feats = forward_samples(self.pymodel, image, bbreg_examples, opts) + self.bbreg = BBRegressor(image.size) + self.bbreg.train(bbreg_feats, bbreg_examples, target_bbox) + del bbreg_feats + torch.cuda.empty_cache() + # Init sample generators + self.sample_generator = SampleGenerator('gaussian', image.size, opts['trans'], opts['scale']) + self.pos_generator = SampleGenerator('gaussian', image.size, opts['trans_pos'], opts['scale_pos']) + self.neg_generator = SampleGenerator('uniform', image.size, opts['trans_neg'], opts['scale_neg']) + + # Init pos/neg features for update + neg_examples = self.neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_init']) + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.pos_feats_all = [pos_feats] + self.neg_feats_all = [neg_feats] + + spf_total = time.time() - tic + + def pymdnet_eval(self, image, samples): + sample_scores = forward_samples(self.pymodel, image, samples, out_layer='fc6', opts=opts) + return sample_scores[:, 1][:].cpu().numpy() + + def collect_samples_pymdnet(self, image): + self.t_id += 1 + target_bbox = np.array([self.last_gt[1], self.last_gt[0], self.last_gt[3]-self.last_gt[1], self.last_gt[2]-self.last_gt[0]]) + pos_examples = self.pos_generator(target_bbox, opts['n_pos_update'], opts['overlap_pos_update']) + if len(pos_examples) > 0: + pos_feats = forward_samples(self.pymodel, image, pos_examples, opts) + self.pos_feats_all.append(pos_feats) + if len(self.pos_feats_all) > opts['n_frames_long']: + del self.pos_feats_all[0] + + neg_examples = self.neg_generator(target_bbox, opts['n_neg_update'], opts['overlap_neg_update']) + if len(neg_examples) > 0: + neg_feats = forward_samples(self.pymodel, image, neg_examples, opts) + self.neg_feats_all.append(neg_feats) + if len(self.neg_feats_all) > opts['n_frames_short']: + del self.neg_feats_all[0] + + def pymdnet_short_term_update(self): + # Short term update + nframes = min(opts['n_frames_short'], len(self.pos_feats_all)) + pos_data = torch.cat(self.pos_feats_all[-nframes:], 0) + neg_data = torch.cat(self.neg_feats_all, 0) + train(self.pymodel, self.criterion, self.update_optimizer, pos_data, neg_data, opts['maxiter_update'], + opts=opts) + + def pymdnet_long_term_update(self): + if self.t_id % opts['long_interval'] == 0: + # Long term update + pos_data = torch.cat(self.pos_feats_all, 0) + neg_data = torch.cat(self.neg_feats_all, 0) + train(self.pymodel, self.criterion, self.update_optimizer, pos_data, neg_data, opts['maxiter_update'], + opts=opts) + + def metric_init(self, im, init_box): + self.metric_model = ft_net(class_num=1120) + path = os.path.join(base_path, 'CoCoLoT/utils/metric_net/metric_model/metric_model.pt') + self.metric_model.eval() + self.metric_model = self.metric_model.cuda() + self.metric_model.load_state_dict(torch.load(path)) + tmp = np.random.rand(1, 3, 107, 107) + tmp = (Variable(torch.Tensor(tmp))).type(torch.FloatTensor).cuda() + # get target feature + self.metric_model(tmp) + init_box = init_box.reshape((1, 4)) + anchor_region = me_extract_regions(im, init_box) + anchor_region = process_regions(anchor_region) + anchor_region = torch.Tensor(anchor_region) + anchor_region = (Variable(anchor_region)).type(torch.FloatTensor).cuda() + self.anchor_feature, _ = self.metric_model(anchor_region) + + def metric_eval(self, im, boxes, anchor_feature): + box_regions = me_extract_regions(np.array(im), boxes) + box_regions = process_regions(box_regions) + box_regions = torch.Tensor(box_regions) + box_regions = (Variable(box_regions)).type(torch.FloatTensor).cuda() + box_features, class_result = self.metric_model(box_regions) + + class_result = torch.softmax(class_result, dim=1) + ap_dist = torch.norm(anchor_feature - box_features, 2, dim=1).view(-1) + return ap_dist + + def tc_init(self, model_dir): + self.tc_model = tclstm() + self.X_input = tf.placeholder("float", [None, tcopts['time_steps'], tcopts['lstm_num_input']]) + self.maps = tf.placeholder("float", [None, 19, 19, 1]) + self.map_logits = self.tc_model.map_net(self.maps) + self.Inputs = tf.concat((self.X_input, self.map_logits), axis=2) + self.logits, _ = self.tc_model.net(self.Inputs) + + variables_to_restore = [var for var in tf.global_variables() if + (var.name.startswith('tclstm') or var.name.startswith('mapnet'))] + saver = tf.train.Saver(var_list=variables_to_restore) + if self.p.checkpoint is None: + checkpoint = tf.train.latest_checkpoint(os.path.join(base_path, 'CoCoLoT/meta_updater', model_dir)) + else: + checkpoint = os.path.join(base_path, 'CoCoLoT/meta_updater/' + self.p.model_dir + '/lstm_model.ckpt-' + str(self.p.checkpoint)) + saver.restore(self.sess, checkpoint) + + def local_init(self, image, init_bbox): + local_tracker = pyTracker('dimp', 'super_dimp') + params = local_tracker.get_parameters() + + debug_ = getattr(params, 'debug', 0) + params.debug = debug_ + + params.tracker_name = local_tracker.name + params.param_name = local_tracker.parameter_name + + self.local_Tracker = local_tracker.tracker_class(params) + init_box = dict() + init_box['init_bbox'] = init_bbox + self.local_Tracker.initialize(image, init_box) + + def local_track(self, image): + state, score_map, test_x, scale_ind, sample_pos, sample_scales, flag, s = self.local_Tracker.track_updater(image) + score_map = cv2.resize(score_map, (19, 19)) + update_flag = flag not in ['not_found', 'uncertain'] + update = update_flag + max_score = max(score_map.flatten()) + self.all_map.append(score_map) + local_state = np.array(state).reshape((1, 4)) + ap_dis = self.metric_eval(image, local_state, self.anchor_feature) + self.dis_record.append(ap_dis.data.cpu().numpy()[0]) + h = image.shape[0] + w = image.shape[1] + self.state_record.append([local_state[0][0] / w, local_state[0][1] / h, + (local_state[0][0] + local_state[0][2]) / w, + (local_state[0][1] + local_state[0][3]) / h]) + self.rv_record.append(max_score) + #if len(self.state_record) >= tcopts['time_steps']: + if len(self.state_record) >= self.p.start_frame: + dis = np.array(self.dis_record[-tcopts["time_steps"]:]).reshape((tcopts["time_steps"], 1)) + rv = np.array(self.rv_record[-tcopts["time_steps"]:]).reshape((tcopts["time_steps"], 1)) + state_tc = np.array(self.state_record[-tcopts["time_steps"]:]) + map_input = np.array(self.all_map[-tcopts["time_steps"]:]) + map_input = np.reshape(map_input, [tcopts['time_steps'], 1, 19, 19]) + map_input = map_input.transpose((0, 2, 3, 1)) + X_input = np.concatenate((state_tc, rv, dis), axis=1) + logits = self.sess.run(self.logits, + feed_dict={self.X_input: np.expand_dims(X_input, axis=0), + self.maps: map_input}) + update = logits[0][0] < logits[0][1] + + hard_negative = (flag == 'hard_negative') + learning_rate = getattr(self.local_Tracker.params, 'hard_negative_learning_rate', None) if hard_negative else None + + if update: + # Get train sample + train_x = test_x[scale_ind:scale_ind+1, ...] + + # Create target_box and label for spatial sample + target_box = self.local_Tracker.get_iounet_box(self.local_Tracker.pos, self.local_Tracker.target_sz, + sample_pos[scale_ind, :], sample_scales[scale_ind]) + + # Update the classifier model + self.local_Tracker.update_classifier(train_x, target_box, learning_rate, s[scale_ind,...]) + self.last_gt = [state[1], state[0], state[1]+state[3], state[0]+state[2]] + return state, score_map, update, max_score, ap_dis.data.cpu().numpy()[0], flag + + def locate(self, image): + + # Convert image + im = numpy_to_torch(image) + self.local_Tracker.im = im # For debugging only + + # ------- LOCALIZATION ------- # + + # Get sample + sample_pos = self.local_Tracker.pos.round() + sample_scales = self.local_Tracker.target_scale * self.local_Tracker.params.scale_factors + test_x = self.local_Tracker.extract_processed_sample(im, self.local_Tracker.pos, sample_scales, self.local_Tracker.img_sample_sz) + + # Compute scores + scores_raw = self.local_Tracker.apply_filter(test_x) + translation_vec, scale_ind, s, flag = self.local_Tracker.localize_target(scores_raw) + return translation_vec, scale_ind, s, flag, sample_pos, sample_scales, test_x + + def local_update(self, sample_pos, translation_vec, scale_ind, sample_scales, s, test_x, update_flag=None): + + # Check flags and set learning rate if hard negative + if update_flag is None: + update_flag = self.flag not in ['not_found', 'uncertain'] + hard_negative = (self.flag == 'hard_negative') + learning_rate = self.local_Tracker.params.hard_negative_learning_rate if hard_negative else None + + if update_flag: + # Get train sample + train_x = TensorList([x[scale_ind:scale_ind + 1, ...] for x in test_x]) + + # Create label for sample + train_y = self.local_Tracker.get_label_function(sample_pos, sample_scales[scale_ind]) + + # Update memory + self.local_Tracker.update_memory(train_x, train_y, learning_rate) + + # Train filter + if hard_negative: + self.local_Tracker.filter_optimizer.run(self.local_Tracker.params.hard_negative_CG_iter) + elif (self.local_Tracker.frame_num - 1) % self.local_Tracker.params.train_skipping == 0: + self.local_Tracker.filter_optimizer.run(self.local_Tracker.params.CG_iter) + + def local_track_stark(self, image): + update_ouput = [0, 0] + cur_ori_img = Image.fromarray(image).convert('RGB') + cur_image = np.asarray(cur_ori_img) + + target_bbox, local_score = self.stark_tracker.track(image) + + return target_bbox, local_score + + def dist_penalty(self, bbox): + dist_max = math.sqrt(sum(np.array([self.img_shape[0], self.img_shape[1]]) ** 2)) + #for i in range(len(list_search_pos)): + # dist1[i] = math.sqrt(sum((list_search_pos[i] - list_search_pos[0]) ** 2)) + last_good = [self.last_good[1], self.last_good[0], self.last_good[3] - self.last_good[1], self.last_good[2] - self.last_good[0]] + dist = math.sqrt(sum((np.array(bbox[:2]) - np.array(last_good[:2])) ** 2)) + #weight_penalty = 1.0 - self.params.get('redetection_score_penalty_alpha', 0.5) * (dist / dist_max) * math.exp(- self.params.get('redetection_score_penalty_beta', 0.5) * (self.cnt_empty - 1)) + #weight_penalty = 1.0 - 0.75 * (dist / dist_max) * math.exp(- 0.25 * (self.i - self.last_good_idx - 1)) + weight_penalty = 1.0 - 1.0 * (dist / dist_max) * math.exp(- 1.0 * (self.i - self.last_good_idx - 1)) + + return weight_penalty + + def tracking(self, image): + self.i += 1 + + local_state, self.score_map, update, local_score, dis, flag = self.local_track(image) + local_score = np.clip(local_score, 0, 1) + + stark_state, stark_score = self.local_track_stark(image) + + if self.md_scores_sum[-1] > 4: + max_dim = np.argmax([self.boxes[-1][2], self.boxes[-1][3]]) + max_dim_idx = 2 + max_dim + min_dim_idx = 2 + (1 - max_dim) + base_ar = self.boxes[-1][max_dim_idx] / self.boxes[-1][min_dim_idx] + ar = stark_state[max_dim_idx] / stark_state[min_dim_idx] + if base_ar > ar: + if (np.abs(ar - base_ar) > (0.4 * base_ar)): + stark_score = 0.0 + else: + if (np.abs(ar - base_ar) > (1.35 * base_ar)): + stark_score = 0.0 + + md_score_dimp = self.pymdnet_eval(image, np.array(local_state).reshape([-1, 4]))[0] + md_score_dimp = np.clip((local_score + np.arctan(0.2 * md_score_dimp) / math.pi + 0.5) / 2, 0, 1) + #dist_penalty_dimp = self.dist_penalty(local_state) + #md_score_dimp *= dist_penalty_dimp + md_score_stark = self.pymdnet_eval(image, np.array(stark_state).reshape([-1, 4]))[0] + md_score_stark = np.clip((stark_score + np.arctan(0.2 * md_score_stark) / math.pi + 0.5) / 2, 0, 1) + #dist_penalty_stark = self.dist_penalty(stark_state) + #md_score_stark *= dist_penalty_stark + + self.md_scores_dimp.append(md_score_dimp) + self.md_scores_stark.append(md_score_stark) + + if len(self.md_scores_dimp) > 5: + md_scores = [(np.array(self.md_scores_stark)[-5:] > 0.5).sum(), (np.array(self.md_scores_dimp)[-5:] > 0.5).sum()] + else: + md_scores = [md_score_stark, md_score_dimp] + md_scores_1 = [md_score_stark, md_score_dimp] + all_scores = [self.md_scores_stark, self.md_scores_dimp] + bboxes = [copy.copy(stark_state), copy.copy(local_state)] + md_score = max(md_scores) + md_idx = np.argmax(md_scores) + + + if md_score > 3: + + if md_idx == 0: + self.local_Tracker.pos = torch.FloatTensor([(stark_state[1] + stark_state[3] + stark_state[1] - 1) / 2, (stark_state[0] + stark_state[2] + stark_state[0] - 1) / 2]) + self.local_Tracker.target_sz = torch.FloatTensor([stark_state[3], stark_state[2]]) + + self.last_gt = np.array([stark_state[1], stark_state[0], stark_state[1] + stark_state[3], stark_state[0] + stark_state[2]]) + + confidence_score = md_score_stark + + else: + self.stark_tracker.tracker.state = [int(local_state[0]), int(local_state[1]), int(local_state[2]), int(local_state[3])] + + self.last_gt = np.array([local_state[1], local_state[0], local_state[1] + local_state[3], local_state[0] + local_state[2]]) + + confidence_score = md_score_dimp + + self.stark_tracker.tracker.params.search_factor = 2.5 + self.last_good = copy.copy(self.last_gt) + self.last_good_idx = copy.copy(self.i) + + else: + new_box = bboxes[md_idx] + + self.last_gt = np.array([new_box[1], new_box[0], new_box[1] + new_box[3], new_box[0] + new_box[2]]) + + confidence_score = (md_score_stark + md_score_dimp) / 2 + + self.stark_tracker.tracker.params.search_factor = 5.0 + + + if update or (md_scores[0] == 5 and md_scores[1] == 5): + self.collect_samples_pymdnet(image) + + self.pymdnet_long_term_update() + + width = self.last_gt[3] - self.last_gt[1] + height = self.last_gt[2] - self.last_gt[0] + + self.boxes.append(np.array([float(self.last_gt[1]), float(self.last_gt[0]), float(width), float(height)])) + self.boxes_stark.append(np.array(stark_state)) + self.boxes_dimp.append(np.array(local_state)) + self.confidences.append(int(self.score_max > 0)) + + self.md_scores_sum.append(md_score) + + return vot.Rectangle(float(self.last_gt[1]), float(self.last_gt[0]), float(width), + float(height)), confidence_score + + + +handle = vot.VOT("rectangle") # rectangle(x, y, w, h) + +selection = handle.region() +imagefile = handle.frame() +p = p_config() +# if not imagefile: +# sys.exit(0) +image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) +tracker = CoCoLoT_Tracker(image, selection, p=p) # initialize tracker + +while True: + + imagefile = handle.frame() + + if not imagefile: + break + + image = cv2.cvtColor(cv2.imread(imagefile), cv2.COLOR_BGR2RGB) + + region, confidence = tracker.tracking(image) + + handle.report(region, confidence) + + #if idx == n_frames: + # tracker.sess.close() diff --git a/trackers.ini b/trackers.ini new file mode 100755 index 0000000..906afa3 --- /dev/null +++ b/trackers.ini @@ -0,0 +1,13 @@ +[CoCoLoT] # <tracker-name> +label = CoCoLoT +protocol = traxpython + +command = tracker_vot + +# Specify a path to trax python wrapper if it is not visible (separate by ; if using multiple paths) +# Substitute [full-path-to-CoCoLoT] with full path to submission +paths = [full-path-to-CoCoLoT]/CoCoLoT/ + +# Additional environment paths +# Substitute [full-path-to-CoCoLoT] with full path to submission +env_PATH = [full-path-to-CoCoLoT]/CoCoLoT/;${PATH} diff --git a/tracking_utils.py b/tracking_utils.py new file mode 100755 index 0000000..b80966d --- /dev/null +++ b/tracking_utils.py @@ -0,0 +1,80 @@ +import cv2 +import numpy as np + + +def show_res(im, box, win_name,update=None,tracker_score=None,frame_id=None,mask=None,v_score=None, groundtruth=None, can_bboxes=None): + cv2.namedWindow(win_name,cv2.WINDOW_NORMAL) + cv2.rectangle(im, (box[1], box[0]), + (box[3], box[2]), [0, 255, 255], 2) + + if mask is not None: + im[:, :, 1] = (mask > 0) * 128 + (mask == 0) * im[:, :, 1] + if can_bboxes is not None: + can_bboxes = np.array(can_bboxes, dtype=np.int32) + for i in range(len(can_bboxes)): + cv2.rectangle(im, (can_bboxes[i, 0], can_bboxes[i, 1]), + (can_bboxes[i, 0] + can_bboxes[i, 2], can_bboxes[i, 1] + can_bboxes[i, 3]), [255, 0, 0], 2) + if groundtruth is not None and not groundtruth[frame_id][0] == np.nan: + groundtruth = groundtruth.astype("int16") + cv2.rectangle(im, (groundtruth[frame_id][0], groundtruth[frame_id][1]), + (groundtruth[frame_id][0] + groundtruth[frame_id][2], + groundtruth[frame_id][1] + groundtruth[frame_id][3]), [0, 0, 255], 2) + if update is not None: + cv2.putText(im, 'update score:'+str(update), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 255), 1) + if v_score is not None: + cv2.putText(im, str(v_score), (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1) + if tracker_score is not None: + cv2.putText(im, 'tracker score:'+str(tracker_score), (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1) + if frame_id is not None: + cv2.putText(im, 'frame:'+str(frame_id), (20, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 1) + cv2.imshow(win_name, im) + cv2.waitKey(1) + + +def compute_iou(boxA, boxB): + # determine the (x, y)-coordinates of the intersection rectangle + xA = max(boxA[0], boxB[0]) + yA = max(boxA[1], boxB[1]) + xB = min(boxA[0] + boxA[2], boxB[0] + boxB[2]) + yB = min(boxA[1] + boxA[3], boxB[1] + boxB[3]) + + if xA < xB and yA < yB: + # compute the area of intersection rectangle + interArea = (xB - xA) * (yB - yA) + # compute the area of both the prediction and ground-truth + # rectangles + boxAArea = boxA[2] * boxA[3] + boxBArea = boxB[2] * boxB[3] + # compute the intersection over union by taking the intersection + # area and dividing it by the sum of prediction + ground-truth + # areas - the intersection area + iou = interArea / float(boxAArea + boxBArea - interArea) + else: + iou = 0 + + assert iou >= 0 + assert iou <= 1.01 + + return iou + + +def process_regions(regions): + # regions = np.squeeze(regions, axis=0) + regions = regions / 255.0 + regions[:, :, :, 0] = (regions[:, :, :, 0] - 0.485) / 0.229 + regions[:, :, :, 1] = (regions[:, :, :, 1] - 0.456) / 0.224 + regions[:, :, :, 2] = (regions[:, :, :, 2] - 0.406) / 0.225 + regions = np.transpose(regions, (0, 3, 1, 2)) + # regions = np.expand_dims(regions, axis=0) + # regions = np.tile(regions, (2,1,1,1)) + + return regions + + +class Region: + def __init__(self, x, y, width, height): + self.x = x + self.y = y + self.width = width + self.height = height + diff --git a/utils/.DS_Store b/utils/.DS_Store new file mode 100644 index 0000000..d73471c Binary files /dev/null and b/utils/.DS_Store differ diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/utils/metric_net/.DS_Store b/utils/metric_net/.DS_Store new file mode 100644 index 0000000..d33ebf1 Binary files /dev/null and b/utils/metric_net/.DS_Store differ diff --git a/utils/metric_net/.idea/metric_net.iml b/utils/metric_net/.idea/metric_net.iml new file mode 100755 index 0000000..e98082a --- /dev/null +++ b/utils/metric_net/.idea/metric_net.iml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> + <component name="TestRunnerService"> + <option name="projectConfiguration" value="py.test" /> + <option name="PROJECT_TEST_RUNNER" value="py.test" /> + </component> +</module> \ No newline at end of file diff --git a/utils/metric_net/.idea/misc.xml b/utils/metric_net/.idea/misc.xml new file mode 100755 index 0000000..e3ccca8 --- /dev/null +++ b/utils/metric_net/.idea/misc.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="JavaScriptSettings"> + <option name="languageLevel" value="ES6" /> + </component> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (pytracking)" project-jdk-type="Python SDK" /> +</project> \ No newline at end of file diff --git a/utils/metric_net/.idea/modules.xml b/utils/metric_net/.idea/modules.xml new file mode 100755 index 0000000..3b3b068 --- /dev/null +++ b/utils/metric_net/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/metric_net.iml" filepath="$PROJECT_DIR$/.idea/metric_net.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/utils/metric_net/.idea/workspace.xml b/utils/metric_net/.idea/workspace.xml new file mode 100755 index 0000000..7c510fd --- /dev/null +++ b/utils/metric_net/.idea/workspace.xml @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ChangeListManager"> + <list default="true" id="4ee139eb-79ab-437b-ad0a-20a3e41898be" name="Default" comment="" /> + <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> + <option name="TRACKING_ENABLED" value="true" /> + <option name="SHOW_DIALOG" value="false" /> + <option name="HIGHLIGHT_CONFLICTS" value="true" /> + <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> + <option name="LAST_RESOLUTION" value="IGNORE" /> + </component> + <component name="FileEditorManager"> + <leaf> + <file leaf-file-name="demo.py" pinned="false" current-in-tab="true"> + <entry file="file://$PROJECT_DIR$/demo.py"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="601"> + <caret line="47" column="31" lean-forward="true" selection-start-line="47" selection-start-column="31" selection-end-line="47" selection-end-column="31" /> + <folding> + <element signature="e#0#18#0" expanded="true" /> + </folding> + </state> + </provider> + </entry> + </file> + </leaf> + </component> + <component name="IdeDocumentHistory"> + <option name="CHANGED_PATHS"> + <list> + <option value="$PROJECT_DIR$/demo.py" /> + </list> + </option> + </component> + <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" /> + <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" /> + <component name="JsGulpfileManager"> + <detection-done>true</detection-done> + <sorting>DEFINITION_ORDER</sorting> + </component> + <component name="NodePackageJsonFileManager"> + <packageJsonPaths /> + </component> + <component name="ProjectFrameBounds" extendedState="6"> + <option name="x" value="2019" /> + <option name="y" value="37" /> + <option name="width" value="1855" /> + <option name="height" value="1056" /> + </component> + <component name="ProjectView"> + <navigator proportions="" version="1"> + <foldersAlwaysOnTop value="true" /> + </navigator> + <panes> + <pane id="Scope" /> + <pane id="ProjectPane"> + <subPane> + <expand> + <path> + <item name="metric_net" type="b2602c69:ProjectViewProjectNode" /> + <item name="metric_net" type="462c0819:PsiDirectoryNode" /> + </path> + </expand> + <select /> + </subPane> + </pane> + </panes> + </component> + <component name="PropertiesComponent"> + <property name="WebServerToolWindowFactoryState" value="false" /> + <property name="last_opened_file_path" value="$PROJECT_DIR$" /> + <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" /> + <property name="nodejs_npm_path_reset_for_default_project" value="true" /> + <property name="settings.editor.selected.configurable" value="editor.preferences.import" /> + </component> + <component name="RunDashboard"> + <option name="ruleStates"> + <list> + <RuleState> + <option name="name" value="ConfigurationTypeDashboardGroupingRule" /> + </RuleState> + <RuleState> + <option name="name" value="StatusDashboardGroupingRule" /> + </RuleState> + </list> + </option> + </component> + <component name="SvnConfiguration"> + <configuration /> + </component> + <component name="TaskManager"> + <task active="true" id="Default" summary="Default task"> + <changelist id="4ee139eb-79ab-437b-ad0a-20a3e41898be" name="Default" comment="" /> + <created>1557406667009</created> + <option name="number" value="Default" /> + <option name="presentableId" value="Default" /> + <updated>1557406667009</updated> + </task> + <servers /> + </component> + <component name="ToolWindowManager"> + <frame x="1985" y="24" width="1855" height="1056" extended-state="6" /> + <editor active="true" /> + <layout> + <window_info anchor="bottom" id="TODO" order="6" sideWeight="0.503037" side_tool="true" weight="0.31138977" /> + <window_info anchor="bottom" x="1985" y="385" width="1855" height="299" id="Event Log" order="8" sideWeight="0.503037" side_tool="true" weight="0.31138977" /> + <window_info anchor="bottom" id="Database Changes" order="10" show_stripe_button="false" /> + <window_info anchor="bottom" id="Run" order="2" sideWeight="0.49917173" weight="0.08898305" /> + <window_info anchor="bottom" id="Version Control" order="9" show_stripe_button="false" /> + <window_info anchor="bottom" auto_hide="true" x="1985" y="370" width="1855" height="323" id="Python Console" internal_type="SLIDING" order="12" sideWeight="0.496963" type="SLIDING" weight="0.31138977" /> + <window_info anchor="bottom" id="Terminal" order="11" sideWeight="0.49917173" weight="0.3291536" /> + <window_info active="true" content_ui="combo" id="Project" order="0" sideWeight="0.49848023" visible="true" weight="0.2578686" /> + <window_info anchor="bottom" id="Docker" order="7" show_stripe_button="false" /> + <window_info anchor="right" id="Database" order="3" weight="0.32938007" /> + <window_info anchor="right" id="SciView" order="4" weight="0.32938007" /> + <window_info id="Structure" order="1" sideWeight="0.50151974" side_tool="true" weight="0.25842077" /> + <window_info anchor="bottom" x="2006" y="346" width="1813" height="378" id="Debug" order="3" sideWeight="0.4997239" weight="0.33262712" /> + <window_info id="Favorites" order="2" sideWeight="0.50151974" side_tool="true" weight="0.25842077" /> + <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" /> + <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> + <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" /> + <window_info anchor="right" id="Ant Build" order="1" weight="0.25" /> + <window_info anchor="bottom" id="Message" order="0" /> + <window_info anchor="right" x="0" y="0" width="414" height="892" id="Documentation" order="5" side_tool="true" weight="0.32965213" /> + <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> + <window_info anchor="bottom" id="Find" order="1" /> + </layout> + </component> + <component name="TypeScriptGeneratedFilesManager"> + <option name="version" value="1" /> + </component> + <component name="VcsContentAnnotationSettings"> + <option name="myLimit" value="2678400000" /> + </component> + <component name="editorHistoryManager"> + <entry file="file://$PROJECT_DIR$/sample_generator.py"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="1548"> + <caret line="86" column="21" selection-start-line="86" selection-start-column="21" selection-end-line="86" selection-end-column="21" /> + <folding> + <element signature="e#0#18#0" expanded="true" /> + </folding> + </state> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/demo.py"> + <provider selected="true" editor-type-id="text-editor"> + <state relative-caret-position="601"> + <caret line="47" column="31" lean-forward="true" selection-start-line="47" selection-start-column="31" selection-end-line="47" selection-end-column="31" /> + <folding> + <element signature="e#0#18#0" expanded="true" /> + </folding> + </state> + </provider> + </entry> + </component> +</project> \ No newline at end of file diff --git a/utils/metric_net/__pycache__/me_sample_generator.cpython-37.pyc b/utils/metric_net/__pycache__/me_sample_generator.cpython-37.pyc new file mode 100755 index 0000000..2841af2 Binary files /dev/null and b/utils/metric_net/__pycache__/me_sample_generator.cpython-37.pyc differ diff --git a/utils/metric_net/__pycache__/metric_model.cpython-37.pyc b/utils/metric_net/__pycache__/metric_model.cpython-37.pyc new file mode 100755 index 0000000..6aa7472 Binary files /dev/null and b/utils/metric_net/__pycache__/metric_model.cpython-37.pyc differ diff --git a/utils/metric_net/data_loader.py b/utils/metric_net/data_loader.py new file mode 100755 index 0000000..b0c4142 --- /dev/null +++ b/utils/metric_net/data_loader.py @@ -0,0 +1,349 @@ +import numpy as np +import cv2 +import os +import torch +import torch.nn as nn +from sample_generator import * +from PIL import Image +import torch.utils.data as torch_dataset +from model import ft_net +import torch.optim as optim +from torch.optim import lr_scheduler +import time +from torch.autograd import Variable +from torchvision import transforms +from tensorboardX import SummaryWriter +os.environ["CUDA_VISIBLE_DEVICES"] = "0" + +class TripletLoss(nn.Module): + ''' + Compute normal triplet loss or soft margin triplet loss given triplets + ''' + def __init__(self, margin = None): + super(TripletLoss, self).__init__() + self.margin = margin + if self.margin is None: # use soft-margin + self.Loss = nn.SoftMarginLoss() + else: + self.Loss = nn.TripletMarginLoss(margin = margin, p = 2) + self.class_loss = nn.CrossEntropyLoss() + def forward(self, anchor, pos, neg, hard_neg): + if self.margin is None: + num_samples = anchor.shape[0] + y = torch.ones((num_samples, 1)).view(-1) + if anchor.is_cuda: y = y.cuda() + ap_dist = torch.norm(anchor - pos, 2, dim = 1).view(-1) + an_dist = torch.norm(anchor - neg, 2, dim = 1).view(-1) + ahn_dist = torch.norm(anchor - hard_neg, 2, dim = 1).view(-1) + loss = self.Loss(an_dist - ap_dist, y) / 2.0 + self.Loss(ahn_dist - ap_dist, y) / 2.0 + + else: + loss = self.Loss(anchor, pos, neg) + + return loss + +class MixedLoss(nn.Module): + ''' + Compute normal triplet loss or soft margin triplet loss given triplets + ''' + def __init__(self, margin = None): + super(MixedLoss, self).__init__() + self.margin = margin + if self.margin is None: # use soft-margin + self.Loss = nn.SoftMarginLoss() + else: + self.Loss = nn.TripletMarginLoss(margin = margin, p = 2) + self.class_loss = nn.CrossEntropyLoss() + def forward(self, anchor, pos, neg, hard_neg, an_class, p_class, neg_class, hard_neg_class, class_ids, hard_class_ids): + if self.margin is None: + num_samples = anchor.shape[0] + y = torch.ones((num_samples, 1)).view(-1) + if anchor.is_cuda: y = y.cuda() + ap_dist = torch.norm(anchor - pos, 2, dim = 1).view(-1) + an_dist = torch.norm(anchor - neg, 2, dim = 1).view(-1) + ahn_dist = torch.norm(anchor - hard_neg, 2, dim = 1).view(-1) + matching_loss = self.Loss(an_dist - ap_dist, y) / 2.0 + self.Loss(ahn_dist - ap_dist, y) / 2.0 + + class_loss1 = self.class_loss(an_class, class_ids) + class_loss2 = self.class_loss(p_class, class_ids) + class_loss3 = self.class_loss(hard_neg_class, hard_class_ids) + #class_loss = (class_loss1+class_loss2 + class_loss3)/3.0 + + neg_class = torch.softmax(neg_class, dim=1) + neg_class_loss = torch.sum(-1.0/1400 * torch.log(neg_class),dim=1) + neg_class_loss = torch.mean(neg_class_loss, dim=0) + + class_loss = (class_loss1+ class_loss2 + class_loss3 + neg_class_loss) / 4.0 + + loss = matching_loss + class_loss + + else: + loss = self.Loss(anchor, pos, neg) + + return loss, matching_loss, class_loss + +class ValidationDataset(torch_dataset.Dataset): + def __init__(self, src_path): + #src_path = '/home/xiaobai/Documents/LaSOT/LaSOTBenchmark/' + self.data_dict = dict() + seq_list = os.listdir(src_path) + seq_list.sort() + seq_lists = [] + #class_id = 0 + for seq_id, seq_name in enumerate(seq_list): + self.data_dict[seq_name] = dict() + self.data_dict[seq_name]['pos'] = os.listdir(src_path + seq_name + '/pos/') + self.data_dict[seq_name]['neg'] = os.listdir(src_path + seq_name + '/neg/') + self.data_dict[seq_name]['pos_num'] = len(self.data_dict[seq_name]['pos']) + self.data_dict[seq_name]['neg_num'] = len(self.data_dict[seq_name]['neg']) + #class_id += 1 + # print 'Loading sequences: ', seq_id, '/', 50 + + self.src_path = src_path + self.keys = self.data_dict.keys() + self.seq_num = len(self.data_dict.keys()) + transform_train_list = [ + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) + ] + self.data_transforms = transforms.Compose(transform_train_list) + + def process_regions(self, regions): + #regions = np.squeeze(regions, axis=0) + regions = regions / 255.0 + regions[:,:,0] = (regions[:,:,0] - 0.485) / 0.229 + regions[:,:,1] = (regions[:,:,1] - 0.456) / 0.224 + regions[:,:,2] = (regions[:,:,2] - 0.406) / 0.225 + regions = np.transpose(regions, (2,0,1)) + return regions + + def __getitem__(self, index): + #seq_id = np.random.randint(low=0, high = self.seq_num-1, size=[1])[0] + seq_name = self.keys[index] + + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + anchor_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + anchor_regions = self.process_regions(anchor_regions) + + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + pos_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + pos_regions = self.process_regions(pos_regions) + + if self.data_dict[seq_name]['neg_num'] > 0: + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['neg_num'],size=[1,])[0] + neg_regions = np.array(Image.open(self.src_path + seq_name + '/neg/' + self.data_dict[seq_name]['neg'][index1])) + neg_regions = self.process_regions(neg_regions) + else: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + while index2 == index: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + seq_name = self.keys[index2] + index1 = np.random.randint(low=0, high=self.data_dict[seq_name]['pos_num'], size=[1, ])[0] + neg_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + neg_regions = self.process_regions(neg_regions) + + index2 = np.random.randint(low=0,high=self.seq_num, size = [1])[0] + while index2 == index: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + seq_name = self.keys[index2] + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + hard_neg_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + hard_neg_regions = self.process_regions(hard_neg_regions) + + return anchor_regions, pos_regions, neg_regions, hard_neg_regions + + def __len__(self): + # You should change 0 to the total size of your dataset. + return self.seq_num + +class CustomDataset(torch_dataset.Dataset): + def __init__(self, src_path): + #src_path = '/home/xiaobai/Documents/LaSOT/LaSOTBenchmark/' + self.data_dict = dict() + folder_list = os.listdir(src_path) + folder_list.sort() + seq_lists = [] + class_id = 0 + for folder_id, folder in enumerate(folder_list): + #seq_list = sorted([src_path + folder + '/' + seq for seq in seq_list]) + seq_list = os.listdir(src_path + folder) + seq_list = sorted([folder + '/' + seq for seq in seq_list]) + for seq_id, seq_name in enumerate(seq_list): + self.data_dict[seq_name] = dict() + self.data_dict[seq_name]['pos'] = os.listdir(src_path + seq_name + '/pos/') + self.data_dict[seq_name]['neg'] = os.listdir(src_path + seq_name + '/neg/') + self.data_dict[seq_name]['pos_num'] = len(self.data_dict[seq_name]['pos']) + self.data_dict[seq_name]['neg_num'] = len(self.data_dict[seq_name]['neg']) + self.data_dict[seq_name]['class_id'] = class_id + class_id += 1 + # print 'Loading sequences: ', class_id, '/', 1400 + + self.src_path = src_path + self.keys = self.data_dict.keys() + self.seq_num = len(self.data_dict.keys()) + transform_train_list = [ + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) + ] + self.data_transforms = transforms.Compose(transform_train_list) + + def process_regions(self, regions): + #regions = np.squeeze(regions, axis=0) + regions = regions / 255.0 + regions[:,:,0] = (regions[:,:,0] - 0.485) / 0.229 + regions[:,:,1] = (regions[:,:,1] - 0.456) / 0.224 + regions[:,:,2] = (regions[:,:,2] - 0.406) / 0.225 + regions = np.transpose(regions, (2,0,1)) + return regions + + def __getitem__(self, index): + #seq_id = np.random.randint(low=0, high = self.seq_num-1, size=[1])[0] + seq_name = self.keys[index] + + class_id = self.data_dict[seq_name]['class_id'] + class_id = np.array([class_id,]) + + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + anchor_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + anchor_regions = self.process_regions(anchor_regions) + + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + pos_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + pos_regions = self.process_regions(pos_regions) + + if self.data_dict[seq_name]['neg_num'] > 0: + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['neg_num'],size=[1,])[0] + neg_regions = np.array(Image.open(self.src_path + seq_name + '/neg/' + self.data_dict[seq_name]['neg'][index1])) + neg_regions = self.process_regions(neg_regions) + else: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + while index2 == index: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + seq_name = self.keys[index2] + index1 = np.random.randint(low=0, high=self.data_dict[seq_name]['pos_num'], size=[1, ])[0] + neg_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + neg_regions = self.process_regions(neg_regions) + + index2 = np.random.randint(low=0,high=self.seq_num, size = [1])[0] + while index2 == index: + index2 = np.random.randint(low=0, high=self.seq_num, size=[1])[0] + + seq_name = self.keys[index2] + index1 = np.random.randint(low=0,high=self.data_dict[seq_name]['pos_num'],size=[1,])[0] + hard_neg_regions = np.array(Image.open(self.src_path + seq_name + '/pos/' + self.data_dict[seq_name]['pos'][index1])) + hard_neg_regions = self.process_regions(hard_neg_regions) + + hard_class_id = self.data_dict[seq_name]['class_id'] + hard_class_id = np.array([hard_class_id,]) + + return anchor_regions, pos_regions, neg_regions, hard_neg_regions, class_id, hard_class_id + + def __len__(self): + # You should change 0 to the total size of your dataset. + return self.seq_num + +LR_Rate = 1e-3 +model = ft_net(class_num=1400) +ignored_params = list(map(id, model.classifier.parameters())) +base_params = filter(lambda p: id(p) not in ignored_params, model.parameters()) +optimizer_ft = optim.SGD([ + {'params': base_params, 'lr': 0.1 * LR_Rate}, + {'params': model.classifier.parameters(), 'lr': LR_Rate} +], weight_decay=5e-4, momentum=0.9, nesterov=True) +exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=40, gamma=0.1) +#criterion = nn.CrossEntropyLoss() +criterion = MixedLoss() +validation_criterion = TripletLoss() +model = model.cuda() + +model.load_state_dict(torch.load('metric_model/metric_model_19448.pt')) + +writer_path = './summary' +if not os.path.exists(writer_path): + os.mkdir(writer_path) +writer = SummaryWriter(writer_path) + +BatchSize = 16 +M = 2 +im_per_seq = 4 +data_path = '/home/xiaobai/Documents/LaSOT_crops/' +validation_data_path = '/home/xiaobai/Documents/lt2019_crops/' +dataset = CustomDataset(data_path) +validation_dataset = ValidationDataset(validation_data_path) +train_loader = torch_dataset.DataLoader(dataset=dataset, batch_size = BatchSize, shuffle=True) +validation_loader = torch_dataset.DataLoader(dataset=validation_dataset, batch_size = BatchSize, shuffle=True) +save_path = './metric_model' +if not os.path.exists(save_path): + os.mkdir(save_path) +#time2 = time.time() + +#15K iteration lr->1e-3 19448 lr->1e-4 +iter = 20144 +for epoch in range(1000): + # if iter > 15000*M: + # LR_Rate = 1e-3 + # optimizer_ft = optim.SGD([ + # {'params': base_params, 'lr': 0.1 * LR_Rate}, + # {'params': model.classifier.parameters(), 'lr': LR_Rate} + # ], weight_decay=5e-4, momentum=0.9, nesterov=True) + # if iter > 19400*M: + # LR_Rate = 1e-4 + # optimizer_ft = optim.SGD([ + # {'params': base_params, 'lr': 0.1 * LR_Rate}, + # {'params': model.classifier.parameters(), 'lr': LR_Rate} + # ], weight_decay=5e-4, momentum=0.9, nesterov=True) + + + validation_loss = 0 + validation_iter = 0 + for anchor_regions, pos_regions, neg_regions, hard_neg_regions in validation_loader: + # time1 = time.time() + # print "read data time: ", time1 - time2 + pos_regions = (Variable(pos_regions)).type(torch.FloatTensor).cuda() + anchor_regions = (Variable(anchor_regions)).type(torch.FloatTensor).cuda() + neg_regions = (Variable(neg_regions)).type(torch.FloatTensor).cuda() + hard_neg_regions = (Variable(hard_neg_regions)).type(torch.FloatTensor).cuda() + + optimizer_ft.zero_grad() + anchor_metric, anchor_class = model(anchor_regions) + pos_metric, pos_class = model(pos_regions) + neg_metric, neg_class = model(neg_regions) + hard_neg_metric, hard_neg_class = model(hard_neg_regions) + loss = validation_criterion(anchor_metric, pos_metric, neg_metric, hard_neg_metric) + validation_loss = (validation_loss * validation_iter + loss.item()) / (validation_iter + 1) + validation_iter += 1 + + writer.add_scalar('validation_loss', validation_loss, epoch) + + # print "epoch: ", epoch, ", iteration: ", iter, ", validation loss: ", validation_loss + + for anchor_regions, pos_regions, neg_regions, hard_neg_regions, class_ids, hard_class_ids in train_loader: + #time1 = time.time() + #print "read data time: ", time1 - time2 + pos_regions = (Variable(pos_regions)).type(torch.FloatTensor).cuda() + anchor_regions = (Variable(anchor_regions)).type(torch.FloatTensor).cuda() + neg_regions = (Variable(neg_regions)).type(torch.FloatTensor).cuda() + hard_neg_regions = (Variable(hard_neg_regions)).type(torch.FloatTensor).cuda() + class_ids = Variable(class_ids.cuda()) + hard_class_ids = Variable(hard_class_ids.cuda()) + + optimizer_ft.zero_grad() + anchor_metric,anchor_class = model(anchor_regions) + pos_metric,pos_class = model(pos_regions) + neg_metric,neg_class = model(neg_regions) + hard_neg_metric, hard_neg_class = model(hard_neg_regions) + class_ids = torch.squeeze(class_ids, 1) + hard_class_ids = torch.squeeze(hard_class_ids, 1) + loss, matching_loss, class_loss = criterion(anchor_metric, pos_metric, neg_metric, hard_neg_metric, anchor_class, pos_class, neg_class, hard_neg_class, class_ids, hard_class_ids) + loss.backward() + writer.add_scalar('loss', loss.cpu(), iter) + writer.add_scalar('matching loss', matching_loss.cpu(), iter) + writer.add_scalar('classification loss', class_loss.cpu(), iter) + + iter += 1 + optimizer_ft.step() + # print "epoch: ", epoch, ", iteration: ", iter, ", loss: ", loss.item(), ", matching loss: ", matching_loss.item(), ", classification loss: ", class_loss.item() + #time2 = time.time() + #print "train time:", time2 - time1 + if np.mod(epoch, 20) == 0: + torch.save(model.state_dict(), save_path+ '/' + save_path+'_'+str(iter)+'.pt') + +writer.close() \ No newline at end of file diff --git a/utils/metric_net/me_sample_generator.py b/utils/metric_net/me_sample_generator.py new file mode 100755 index 0000000..cc457d8 --- /dev/null +++ b/utils/metric_net/me_sample_generator.py @@ -0,0 +1,185 @@ +import numpy as np +from PIL import Image +from scipy.misc import imresize + + +def overlap_ratio(rect1, rect2): + ''' + Compute overlap ratio between two rects + - rect: 1d array of [x,y,w,h] or + 2d array of N x [x,y,w,h] + ''' + if rect1.ndim == 1: + rect1 = rect1[None, :] + if rect2.ndim == 1: + rect2 = rect2[None, :] + + left = np.maximum(rect1[:, 0], rect2[:, 0]) + right = np.minimum(rect1[:, 0] + rect1[:, 2], rect2[:, 0] + rect2[:, 2]) + top = np.maximum(rect1[:, 1], rect2[:, 1]) + bottom = np.minimum(rect1[:, 1] + rect1[:, 3], rect2[:, 1] + rect2[:, 3]) + + intersect = np.maximum(0, right - left) * np.maximum(0, bottom - top) + union = rect1[:, 2] * rect1[:, 3] + rect2[:, 2] * rect2[:, 3] - intersect + iou = np.clip(intersect / union, 0, 1) + return iou + + +def crop_image(img, bbox, img_size=107, padding=16, valid=False): + x, y, w, h = np.array(bbox, dtype='float32') + + half_w, half_h = w / 2, h / 2 + center_x, center_y = x + half_w, y + half_h + + if padding > 0: + pad_w = padding * w / img_size + pad_h = padding * h / img_size + half_w += pad_w + half_h += pad_h + + img_h, img_w, _ = img.shape + + min_x = int(center_x - half_w + 0.5) + min_y = int(center_y - half_h + 0.5) + max_x = int(center_x + half_w + 0.5) + max_y = int(center_y + half_h + 0.5) + + if valid: + min_x = max(0, min_x) + min_y = max(0, min_y) + max_x = min(img_w, max_x) + max_y = min(img_h, max_y) + + if min_x >= 0 and min_y >= 0 and max_x <= img_w and max_y <= img_h: + cropped = img[min_y:max_y, min_x:max_x, :] + + else: + min_x_val = max(0, min_x) + min_y_val = max(0, min_y) + max_x_val = min(img_w, max_x) + max_y_val = min(img_h, max_y) + + if min_x_val == max_x_val: + if min_x_val <= 0: + min_x_val = 0 + max_x_val = min_x_val + 3 + if max_x_val >= img_w - 1: + max_x_val = img_w - 1 + min_x_val = img_w - 4 + if min_y_val == max_y_val: + if min_y_val <= 0: + min_y_val = 0 + max_y_val = 3 + if max_y_val >= img_h - 1: + max_y_val = img_h - 1 + min_y_val = img_h - 4 + + cropped = 128 * np.ones((max_y - min_y, max_x - min_x, 3), dtype='uint8') + cropped[min_y_val - min_y:max_y_val - min_y, min_x_val - min_x:max_x_val - min_x, :] \ + = img[min_y_val:max_y_val, min_x_val:max_x_val, :] + try: + scaled = imresize(cropped, (img_size, img_size)) + except ValueError: + print("a") + return scaled + + +def me_extract_regions(image, samples, crop_size=107, padding=16, shuffle=False): + regions = np.zeros((samples.shape[0], crop_size, crop_size, 3), dtype='uint8') + for t in range(samples.shape[0]): + regions[t] = crop_image(image, samples[t], crop_size, padding) + + regions = regions #- 128. + return regions + + +def gen_samples(generator, bbox, n, overlap_range=None, scale_range=None): + + if overlap_range is None and scale_range is None: + return generator(bbox, n) + + else: + samples = None + remain = n + factor = 2 + while remain > 0 and factor < 16: + samples_ = generator(bbox, remain*factor) + + idx = np.ones(len(samples_), dtype=bool) + if overlap_range is not None: + r = overlap_ratio(samples_, bbox) + idx *= (r >= overlap_range[0]) * (r <= overlap_range[1]) + if scale_range is not None: + s = np.prod(samples_[:,2:], axis=1) / np.prod(bbox[2:]) + idx *= (s >= scale_range[0]) * (s <= scale_range[1]) + + samples_ = samples_[idx,:] + samples_ = samples_[:min(remain, len(samples_))] + if samples is None: + samples = samples_ + else: + samples = np.concatenate([samples, samples_]) + remain = n - len(samples) + factor = factor*2 + + return samples + + +class SampleGenerator(): + def __init__(self, type, img_size, trans_f=1, scale_f=1, aspect_f=None, valid=False): + self.type = type + self.img_size = np.array(img_size) # (w, h) + self.trans_f = trans_f + self.scale_f = scale_f + self.aspect_f = aspect_f + self.valid = valid + + def __call__(self, bb, n): + # + # bb: target bbox (min_x,min_y,w,h) + bb = np.array(bb, dtype='float32') + + # (center_x, center_y, w, h) + sample = np.array([bb[0]+bb[2]/2, bb[1]+bb[3]/2, bb[2], bb[3]], dtype='float32') + samples = np.tile(sample[None,:],(n,1)) + + # vary aspect ratio + if self.aspect_f is not None: + ratio = np.random.rand(n,1)*2-1 + samples[:,2:] *= self.aspect_f ** np.concatenate([ratio, -ratio],axis=1) + + # sample generation + if self.type=='gaussian': + samples[:,:2] += self.trans_f * np.mean(bb[2:]) * np.clip(0.5*np.random.randn(n,2),-1,1) + samples[:,2:] *= self.scale_f ** np.clip(0.5*np.random.randn(n,1),-1,1) + + elif self.type=='uniform': + samples[:,:2] += self.trans_f * np.mean(bb[2:]) * (np.random.rand(n,2)*2-1) + samples[:,2:] *= self.scale_f ** (np.random.rand(n,1)*2-1) + + elif self.type=='whole': + m = int(2*np.sqrt(n)) + xy = np.dstack(np.meshgrid(np.linspace(0,1,m),np.linspace(0,1,m))).reshape(-1,2) + xy = np.random.permutation(xy)[:n] + samples[:,:2] = bb[2:]/2 + xy * (self.img_size-bb[2:]/2-1) + #samples[:,:2] = bb[2:]/2 + np.random.rand(n,2) * (self.img_size-bb[2:]/2-1) + samples[:,2:] *= self.scale_f ** (np.random.rand(n,1)*2-1) + + # adjust bbox range + samples[:,2:] = np.clip(samples[:,2:], 10, self.img_size-10) + if self.valid: + samples[:,:2] = np.clip(samples[:,:2], samples[:,2:]/2, self.img_size-samples[:,2:]/2-1) + else: + samples[:,:2] = np.clip(samples[:,:2], 0, self.img_size) + + # (min_x, min_y, w, h) + samples[:,:2] -= samples[:,2:]/2 + + return samples + + def set_trans_f(self, trans_f): + self.trans_f = trans_f + + def get_trans_f(self): + return self.trans_f + diff --git a/utils/metric_net/me_sample_generator.pyc b/utils/metric_net/me_sample_generator.pyc new file mode 100755 index 0000000..26eb239 Binary files /dev/null and b/utils/metric_net/me_sample_generator.pyc differ diff --git a/utils/metric_net/metric_model.py b/utils/metric_net/metric_model.py new file mode 100755 index 0000000..d294192 --- /dev/null +++ b/utils/metric_net/metric_model.py @@ -0,0 +1,110 @@ +import torch +import torch.nn as nn +from torch.nn import init +from torchvision import models +from torch.autograd import Variable + +def weights_init_kaiming(m): + classname = m.__class__.__name__ + # print(classname) + if classname.find('Conv') != -1: + init.kaiming_normal_(m.weight.data, a=0, mode='fan_in') # For old pytorch, you may use kaiming_normal. + elif classname.find('Linear') != -1: + init.kaiming_normal_(m.weight.data, a=0, mode='fan_out') + init.constant_(m.bias.data, 0.0) + elif classname.find('BatchNorm1d') != -1: + init.normal_(m.weight.data, 1.0, 0.02) + init.constant_(m.bias.data, 0.0) + +def weights_init_classifier(m): + classname = m.__class__.__name__ + if classname.find('Linear') != -1: + init.normal_(m.weight.data, std=0.001) + init.constant_(m.bias.data, 0.0) + +# Defines the new fc layer and classification layer +# |--Linear--|--bn--|--relu--|--Linear--| +class ClassBlock(nn.Module): + def __init__(self, input_dim, class_num, droprate=0.0, relu=True, bnorm=True, num_bottleneck=512, linear=True, return_f = False): + super(ClassBlock, self).__init__() + self.return_f = return_f + add_block = [] + if linear: + add_block += [nn.Linear(input_dim, num_bottleneck)] + else: + num_bottleneck = input_dim + if bnorm: + add_block += [nn.BatchNorm1d(num_bottleneck)] + if relu: + add_block += [nn.LeakyReLU(0.1)] + if droprate>0: + add_block += [nn.Dropout(p=droprate)] + add_block = nn.Sequential(*add_block) + add_block.apply(weights_init_kaiming) + + classifier = [] + classifier += [nn.Linear(num_bottleneck, class_num)] + classifier = nn.Sequential(*classifier) + classifier.apply(weights_init_classifier) + + self.add_block = add_block + self.classifier = classifier + def forward(self, x): + x = self.add_block(x) + if self.return_f: + f = x + x = self.classifier(x) + return x,f + else: + x = self.classifier(x) + return x + +class DistanceBlock(nn.Module): + def __init__(self, input_dim): + super(DistanceBlock, self).__init__() + add_block = [] + add_block += [nn.Linear(input_dim, 1024)] + add_block += [nn.BatchNorm1d(1024)] + add_block += [nn.LeakyReLU(0.1)] + add_block = nn.Sequential(*add_block) + add_block.apply(weights_init_kaiming) + + distance = [] + distance += [nn.Linear(1024, 1024)] + distance = nn.Sequential(*distance) + distance.apply(weights_init_classifier) + + self.add_block = add_block + self.distance = distance + def forward(self, x): + x = self.add_block(x) + x = self.distance(x) + return x + +class ft_net(nn.Module): + + def __init__(self, class_num, droprate=0.5, stride=2): + super(ft_net, self).__init__() + model_ft = models.resnet50(pretrained=True) + # avg pooling to global pooling + if stride == 1: + model_ft.layer4[0].downsample[0].stride = (1,1) + model_ft.layer4[0].conv2.stride = (1,1) + model_ft.avgpool = nn.AdaptiveAvgPool2d((1,1)) + self.model = model_ft + self.classifier = ClassBlock(2048, class_num) + self.distance = DistanceBlock(2048) + def forward(self, x): + x = self.model.conv1(x) + x = self.model.bn1(x) + x = self.model.relu(x) + x = self.model.maxpool(x) + x = self.model.layer1(x) + x = self.model.layer2(x) + x = self.model.layer3(x) + x = self.model.layer4(x) + x = self.model.avgpool(x) + x = x.view(x.size(0), x.size(1)) + d = self.distance(x) + x = self.classifier(x) + return d, x \ No newline at end of file diff --git a/utils/metric_net/metric_model.pyc b/utils/metric_net/metric_model.pyc new file mode 100755 index 0000000..5c0aaa4 Binary files /dev/null and b/utils/metric_net/metric_model.pyc differ diff --git a/utils/metric_net/metric_model/.DS_Store b/utils/metric_net/metric_model/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/utils/metric_net/metric_model/.DS_Store differ diff --git a/utils/metric_net/metric_model/readme.txt b/utils/metric_net/metric_model/readme.txt new file mode 100755 index 0000000..de72595 --- /dev/null +++ b/utils/metric_net/metric_model/readme.txt @@ -0,0 +1,4 @@ +Put metric model here. + + + diff --git a/utils/metric_net/readme.txt b/utils/metric_net/readme.txt new file mode 100755 index 0000000..6df455e --- /dev/null +++ b/utils/metric_net/readme.txt @@ -0,0 +1,11 @@ +1. run prepare_data.py to prepare training data +2. run construct_validation_data.py to construct validation data +3. run data_loader.py to train the model +4. run test_accuracy.py to find the best threshold + + + +'Best F:', 0.9267233400826453, 'Best threshold: ', 8.082808730602265 + + + diff --git a/utils/metric_net/region_to_bbox.py b/utils/metric_net/region_to_bbox.py new file mode 100755 index 0000000..0b6f49b --- /dev/null +++ b/utils/metric_net/region_to_bbox.py @@ -0,0 +1,47 @@ +import numpy as np + +def region_to_bbox(region, center=True): + + n = len(region) + assert n==4 or n==8, ('GT region format is invalid, should have 4 or 8 entries.') + + if n==4: + return _rect(region, center) + else: + return _poly(region, center) + +# we assume the grountruth bounding boxes are saved with 0-indexing +def _rect(region, center): + + if center: + x = region[0] + y = region[1] + w = region[2] + h = region[3] + cx = x+w/2 + cy = y+h/2 + return cx, cy, w, h + else: + #region[0] -= 1 + #region[1] -= 1 + return region + + +def _poly(region, center): + cx = np.mean(region[::2]) + cy = np.mean(region[1::2]) + x1 = np.min(region[::2]) + x2 = np.max(region[::2]) + y1 = np.min(region[1::2]) + y2 = np.max(region[1::2]) + A1 = np.linalg.norm(region[0:2] - region[2:4]) * np.linalg.norm(region[2:4] - region[4:6]) + A2 = (x2 - x1) * (y2 - y1) + s = np.sqrt(A1/A2) + w = s * (x2 - x1) + 1 + h = s * (y2 - y1) + 1 + + if center: + return cx, cy, w, h + else: + return cx-w/2, cy-h/2, w, h + diff --git a/utils/neuron/__init__.py b/utils/neuron/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/utils/neuron/config/__init__.py b/utils/neuron/config/__init__.py new file mode 100755 index 0000000..00d8d50 --- /dev/null +++ b/utils/neuron/config/__init__.py @@ -0,0 +1,3 @@ +from .config import * +from .registry import * +from . import _init_registry diff --git a/utils/neuron/config/_init_registry.py b/utils/neuron/config/_init_registry.py new file mode 100755 index 0000000..ef1beac --- /dev/null +++ b/utils/neuron/config/_init_registry.py @@ -0,0 +1,4 @@ +# register all modules in neuron +from neuron.data import * +from neuron.models import * +from neuron.optim import * diff --git a/utils/neuron/config/config.py b/utils/neuron/config/config.py new file mode 100755 index 0000000..2d07e5e --- /dev/null +++ b/utils/neuron/config/config.py @@ -0,0 +1,127 @@ +import os.path as osp +import sys +import json +import yaml +import copy +from addict import Dict +from importlib import import_module +from functools import wraps + + +__all__ = ['Config'] + + +def check_frozen(func): + @wraps(func) + def decorated(self, *args, **kwargs): + if self.is_frozen: + raise AttributeError( + 'Attempt to modify frozen Config object.') + else: + return func(self, *args, **kwargs) + return decorated + + +class Config(Dict): + + def __init__(self, *args, **kwargs): + self.__dict__['__frozen__'] = False + super(Config, self).__init__(*args, **kwargs) + + @classmethod + def load(cls, filename, **kwargs): + if not osp.exists(filename): + raise FileNotFoundError( + 'No such file or directory: {}'.format(filename)) + name, ext = osp.splitext(filename) + assert ext in ['.py', '.json', '.yaml', '.yml'] + if ext == '.py': + if '.' in name: + raise ValueError( + 'Dots are not allowed in config file path.') + # load config module + cfg_dir = osp.dirname(filename) + sys.path.insert(0, cfg_dir) + module = import_module(name) + sys.path.pop(0) + # parse config dictionary + cfg_dict = {k: v for k, v in module.__dict__.items() + if not k.startswith('__')} + elif ext == '.json': + with open(filename, 'r') as f: + cfg_dict = json.load(f, **kwargs) + elif ext in ['.yaml', '.yml']: + with open(filename, 'r') as f: + kwargs.setdefault('Loader', yaml.SafeLoader) + cfg_dict = yaml.load(f, **kwargs) + return Config(cfg_dict) + + def dump(self, filename, **kwargs): + name, ext = osp.splitext(filename) + assert ext in ['.py', '.json', '.yaml', '.yml'] + if ext == '.py': + raise NotImplementedError( + 'Saving to .py files is not supported.') + elif ext == '.json': + kwargs.setdefault('indent', 4) + with open(filename, 'w') as f: + json.dump(self.to_dict(), f, **kwargs) + elif ext in ['.yaml', '.yml']: + with open(filename, 'w') as f: + yaml.safe_dump(self.to_dict(), f, **kwargs) + + def merge_from(self, cfg): + merged_cfg = self.deepcopy() + merged_cfg.update(cfg) + return merged_cfg + + def merge_to(self, cfg): + merged_cfg = cfg.deepcopy() + merged_cfg.update(self) + return merged_cfg + + @check_frozen + def __setattr__(self, name, value): + super(Config, self).__setattr__(name, value) + + @check_frozen + def __setitem__(self, name, value): + super(Config, self).__setitem__(name, value) + + @check_frozen + def __setstate__(self, state): + super(Config, self).__setstate__(state) + + @check_frozen + def setdefault(self, key, default=None): + super(Config, self).setdefault(key, default) + + @check_frozen + def __delattr__(self, name): + super(Config, self).__delattr__(name) + + @check_frozen + def update(self, *args, **kwargs): + super(Config, self).update(*args, **kwargs) + + def deepcopy(self): + cfg = copy.deepcopy(self) + if cfg.is_frozen: + cfg.defrost() + return cfg + + def freeze(self): + self.__dict__['__frozen__'] = True + for v in self.values(): + if isinstance(v, Config): + v.freeze() + + def defrost(self): + self.__dict__['__frozen__'] = False + for v in self.values(): + if isinstance(v, Config): + v.defrost() + + @property + def is_frozen(self): + return self.__dict__.get('__frozen__', False) diff --git a/utils/neuron/config/registry.py b/utils/neuron/config/registry.py new file mode 100755 index 0000000..2fcf906 --- /dev/null +++ b/utils/neuron/config/registry.py @@ -0,0 +1,127 @@ +import inspect +import six +import torch.nn as nn +import torch.optim as optim +import torch.utils.data as data +import addict + +import neuron.ops as ops + + +__all__ = ['Registry', 'registry'] + + +class Registry(object): + + def __init__(self): + self._module_dict = {} + self._init_python_modules() + self._init_pytorch_modules() + + def _init_python_modules(self): + # register built-in types + modules = [tuple, list, dict, set] + for m in modules: + self.register_module(m, prefix='python') + + def _init_pytorch_modules(self): + prefix = 'torch' + + # register all nn modules + for k, v in nn.__dict__.items(): + if not isinstance(v, type): + continue + if issubclass(v, nn.Module) and \ + v is not nn.Module: + self.register_module(v, prefix) + + # register all optimizers + for k, v in optim.__dict__.items(): + if not isinstance(v, type): + continue + if issubclass(v, optim.Optimizer) and \ + v is not optim.Optimizer: + self.register_module(v, prefix) + + # register all lr_schedulers + for k, v in optim.lr_scheduler.__dict__.items(): + if not isinstance(v, type): + continue + if issubclass(v, optim.lr_scheduler._LRScheduler) and \ + v is not optim.lr_scheduler._LRScheduler: + self.register_module(v, prefix) + + # register all samplers + for k, v in data.sampler.__dict__.items(): + if not isinstance(v, type): + continue + if issubclass(v, data.sampler.Sampler) and \ + v is not data.sampler.Sampler: + self.register_module(v, prefix) + + # register datasets and dataloader + for k, v in data.dataset.__dict__.items(): + if not isinstance(v, type): + continue + if issubclass(v, data.Dataset) and \ + v is not data.Dataset: + self.register_module(v, prefix) + self.register_module(data.DataLoader, prefix) + + def register_module(self, module, prefix=''): + if not inspect.isclass(module) and \ + not inspect.isfunction(module): + raise TypeError( + 'module must be a class or a function, ' + 'but got {}'.format(module)) + module_name = module.__name__ + if prefix != '': + module_name = '{}.{}'.format(prefix, module_name) + if module_name in self._module_dict: + raise KeyError('{} is already registered'.format( + module_name)) + self._module_dict[module_name] = module + return module + + def get(self, name): + return self._module_dict.get(name, None) + + def build(self, cfg): + assert isinstance(cfg, dict) and 'type' in cfg + cfg = cfg.copy() + module_name = cfg.pop('type') + if 'input_type' in cfg: + ops.sys_print('Warning: "input_type" should be parsed ' + 'before building module') + cfg.pop('input_type') + + # get module + if isinstance(module_name, six.string_types): + module = self.get(module_name) + if module.__name__ == 'dict': + module = addict.Dict + if module is None: + raise KeyError( + '{} is not in the registry'.format(module_name)) + else: + raise TypeError( + 'type must be a string, but got {}'.format(module_name)) + + # build submodules + for k, v in cfg.items(): + if isinstance(v, dict) and 'type' in v: + cfg[k] = self.build(v) + + return module(**cfg) + + @property + def module_dict(self): + return self._module_dict + + def __repr__(self): + repr_str = self.__class__.__name + '(items={})'.format( + list(self._module_dict.keys())) + return repr_str + + +registry = Registry() diff --git a/utils/neuron/data/__init__.py b/utils/neuron/data/__init__.py new file mode 100755 index 0000000..26b52ca --- /dev/null +++ b/utils/neuron/data/__init__.py @@ -0,0 +1,4 @@ +from .datasets import * +from .transforms import * +from .samplers import * +from .evaluators import * diff --git a/utils/neuron/data/collate.py b/utils/neuron/data/collate.py new file mode 100755 index 0000000..e69de29 diff --git a/utils/neuron/data/datasets/__init__.py b/utils/neuron/data/datasets/__init__.py new file mode 100755 index 0000000..52f2d3b --- /dev/null +++ b/utils/neuron/data/datasets/__init__.py @@ -0,0 +1,21 @@ +# base classes +from .dataset import * +from .structure import * +# sequence datasets (SOT + MOT + VID) +from .otb import * +from .vot import * +from .dtb70 import * +from .tcolor128 import * +from .nfs import * +from .uav123 import * +from .oxuva import * +from .got10k import * +from .lasot import * +from .trackingnet import * +from .tlp import * +from .visdrone import * +from .pot import * +from .mot import * +from .imagenet import * +# image datasets +from .coco import * diff --git a/utils/neuron/data/datasets/coco.py b/utils/neuron/data/datasets/coco.py new file mode 100755 index 0000000..5ccbab6 --- /dev/null +++ b/utils/neuron/data/datasets/coco.py @@ -0,0 +1,124 @@ +import os.path as osp +import numpy as np +from pycocotools.coco import COCO + +import neuron.ops as ops +from neuron.config import registry +from .dataset import ImageDataset + + +__all__ = ['COCODetection'] + + +@registry.register_module +class COCODetection(ImageDataset): + r"""`Common Objects in Context (COCO) <http://cocodataset.org/>`_ Dataset. + + Publication: + ``Microsoft COCO: Common Objects in Context``, T. Y. Lin, M. Maire, S. Belongie, et. al., arXiv 2014. + + Args: + root_dir (string): Root directory of dataset where ``Data`` and + ``Annotations`` folders exist. + version (integer, optional): Specify the dataset version. Specify as + one of 2014, 2015 or 2017. Default is 2017. + subset (string, optional): Specify ``train`` or ``val`` subset of + COCO. Default is ``val``. + transforms (object, optional): Augmentations applied to each dataset item. + Default is None. + """ + CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', + 'train', 'truck', 'boat', 'traffic_light', 'fire_hydrant', + 'stop_sign', 'parking_meter', 'bench', 'bird', 'cat', 'dog', + 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', + 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', + 'skis', 'snowboard', 'sports_ball', 'kite', 'baseball_bat', + 'baseball_glove', 'skateboard', 'surfboard', 'tennis_racket', + 'bottle', 'wine_glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', + 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', + 'hot_dog', 'pizza', 'donut', 'cake', 'chair', 'couch', + 'potted_plant', 'bed', 'dining_table', 'toilet', 'tv', 'laptop', + 'mouse', 'remote', 'keyboard', 'cell_phone', 'microwave', + 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', + 'vase', 'scissors', 'teddy_bear', 'hair_drier', 'toothbrush') + + def __init__(self, root_dir=None, version=2017, subset='val', + transforms=None): + if root_dir is None: + root_dir = osp.expanduser('~/data/coco') + super(COCODetection, self).__init__( + name='COCO{}_{}'.format(version, subset), + root_dir=root_dir, + version=version, + subset=subset) + self.transforms = transforms + + def _construct_img_dict(self, root_dir, version, subset): + # image and annotation paths + img_dir = osp.join( + root_dir, + '{}{}'.format(subset, version)) + ann_file = osp.join( + root_dir, + 'annotations/instances_{}{}.json'.format(subset, version)) + coco = COCO(ann_file) + img_infos = coco.dataset['images'] + # filter small images + img_infos = [u for u in img_infos + if min(u['width'], u['height']) >= 32] + img_ids = [u['id'] for u in img_infos] + + # make class IDs contiguous + self._cat2id = { + v: i + 1 for i, v in enumerate(coco.getCatIds())} + self._id2cat = {v: k for k, v in self._cat2id.items()} + + # construct img_dict + img_dict = {} + for i, img_id in enumerate(img_ids): + if i % 1000 == 0 or i + 1 == len(img_ids): + ops.sys_print('Processing image [%d/%d]: %d...' % ( + i + 1, len(img_ids), img_id)) + + # load annotation + ann_id = coco.getAnnIds(imgIds=img_id) + anno = coco.loadAnns(ann_id) + anno = [obj for obj in anno if self._check_obj(obj)] + if len(anno) == 0: + continue + + # read image + img_file = coco.loadImgs(img_id)[0]['file_name'] + img_file = osp.join(img_dir, img_file) + + # read bboxes, labels and mask polygons + bboxes = [obj['bbox'] for obj in anno] + bboxes = np.array(bboxes, dtype=np.float32).reshape(-1, 4) + bboxes[:, 2:] = bboxes[:, :2] + bboxes[:, 2:] - 1 + + labels = [obj['category_id'] for obj in anno] + labels = [self._cat2id[c] for c in labels] + labels = np.array(labels, dtype=np.int64) + + mask_polys = [obj['segmentation'] for obj in anno] + for j, poly in enumerate(mask_polys): + # valid polygons have >= 3 points (6 coordinates) + mask_polys[j] = [np.array(p) for p in poly if len(p) > 6] + + # update img_dict + img_dict[img_id] = { + 'img_file': img_file, + 'target': { + 'bboxes': bboxes, + 'labels': labels, + 'mask_polys': mask_polys, + 'meta': img_infos[i]}} + + return img_dict + + def _check_obj(self, obj): + _, _, w, h = obj['bbox'] + ignore = obj.get('ignore', False) + if obj['iscrowd'] or ignore or w < 1 or h < 1: + return False + return True diff --git a/utils/neuron/data/datasets/dataset.py b/utils/neuron/data/datasets/dataset.py new file mode 100755 index 0000000..e634715 --- /dev/null +++ b/utils/neuron/data/datasets/dataset.py @@ -0,0 +1,185 @@ +import os +import os.path as osp +import pickle +import six +import abc +from torch.utils.data import Dataset + +from neuron import ops + + +__all__ = ['SeqDataset', 'ImageDataset', 'PairDataset', + 'InstanceDataset'] + + +class SeqDataset(Dataset): + CLASSES = ('object', ) + + def __init__(self, name, cache_dir='cache', **kwargs): + self.name = name + self.cache_dir = cache_dir + self.cache_file = osp.join(cache_dir, name + '.pkl') + + # load or construct 'seq_dict' + if not osp.exists(self.cache_dir): + os.makedirs(self.cache_dir) + if osp.exists(self.cache_file): + with open(self.cache_file, 'rb') as f: + seq_dict = pickle.load(f) + else: + seq_dict = self._construct_seq_dict(**kwargs) + with open(self.cache_file, 'wb') as f: + pickle.dump(seq_dict, f) + + # store seq_dict and extract seq_names + self.seq_dict = seq_dict + self.seq_names = list(seq_dict.keys()) + + def __getitem__(self, index): + r""" + Args: + index (integer or string): Index or name of a sequence. + + Returns: + img_files, target (tuple): where ``img_files`` is a list of + file names and ``target`` is dict of annotations. + """ + if isinstance(index, six.string_types): + seq_name = index + else: + seq_name = self.seq_names[index] + seq = self.seq_dict[seq_name] + + # parse img_files and target + img_files, target = seq['img_files'], seq['target'] + if hasattr(self, 'transforms') and self.transforms is not None: + img_files, target = self.transforms(img_files, target) + + return img_files, target + + def __len__(self): + return len(self.seq_dict) + + @abc.abstractmethod + def _construct_seq_dict(self, **kwargs): + raise NotImplementedError + + +class ImageDataset(Dataset): + CLASSES = ('object', ) + + def __init__(self, name, cache_dir='cache', **kwargs): + self.name = name + self.cache_dir = cache_dir + self.cache_file = osp.join(cache_dir, name + '.pkl') + + # load or construct 'img_dict' + if not osp.exists(self.cache_dir): + os.makedirs(self.cache_dir) + if osp.exists(self.cache_file): + with open(self.cache_file, 'rb') as f: + img_dict = pickle.load(f) + else: + img_dict = self._construct_img_dict(**kwargs) + with open(self.cache_file, 'wb') as f: + pickle.dump(img_dict, f) + + # store img_dict and extract img_names + self.img_dict = img_dict + self.img_names = list(img_dict.keys()) + + def __getitem__(self, index): + r""" + Args: + index (integer): Index of an image. + + Returns: + img, target (tuple): where ``target`` is dict of annotations. + """ + img_name = self.img_names[index] + img_info = self.img_dict[img_name] + + # parse image and annotations + img = ops.read_image(img_info['img_file']) + target = img_info['target'] + if hasattr(self, 'transforms') and self.transforms is not None: + img, target = self.transforms(img, target) + + return img, target + + def __len__(self): + return len(self.img_dict) + + @abc.abstractmethod + def _construct_img_dict(self, **kwargs): + raise NotImplementedError + + +class PairDataset(Dataset): + CLASSES = ('object', ) + + def __init__(self, name): + self.name = name + + def __getitem__(self, index): + r""" + Args: + index (integer): Index of an image. + + Returns: + img_z, img_x, target (tuple): where ``target`` + is a dict of annotations. + """ + raise NotImplementedError + + def __len__(self): + raise NotImplementedError + + +class InstanceDataset(Dataset): + + def __init__(self, name, cache_dir='cache', **kwargs): + self.name = name + self.cache_dir = cache_dir + self.cache_file = osp.join(cache_dir, name + '.pkl') + + # load or construct 'ins_dict' + if not osp.exists(self.cache_dir): + os.makedirs(self.cache_dir) + if osp.exists(self.cache_file): + with open(self.cache_file, 'rb') as f: + ins_dict = pickle.load(f) + else: + ins_dict = self._construct_ins_dict(**kwargs) + with open(self.cache_file, 'wb') as f: + pickle.dump(ins_dict, f) + + # store ins_dict and extract ins_names + self.ins_dict = ins_dict + self.ins_names = list(ins_dict.keys()) + + def __getitem__(self, index): + r""" + Args: + index (integer): Index of an image. + + Returns: + img, target (tuple): ``target`` is dict of annotations. + """ + ins_name = self.ins_names[index] + ins_info = self.ins_dict[ins_name] + + # parse image and annotations + img = ops.read_image(ins_info['img_file']) + target = ins_info['target'] + if hasattr(self, 'transforms') and self.transforms is not None: + img, target = self.transforms(img, target) + + return img, target + + def __len__(self): + return len(self.ins_dict) + + @abc.abstractmethod + def _construct_ins_dict(self, **kwargs): + raise NotImplementedError diff --git a/utils/neuron/data/datasets/dtb70.py b/utils/neuron/data/datasets/dtb70.py new file mode 100755 index 0000000..367202a --- /dev/null +++ b/utils/neuron/data/datasets/dtb70.py @@ -0,0 +1,67 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['DTB70'] + + +@registry.register_module +class DTB70(SeqDataset): + """`DTB70 <https://github.com/flyers/drone-tracking>`_ Dataset. + + Publication: + ``Visual object tracking for unmanned aerial vehicles: A benchmark and new motion models``, + Y. Wu, J. Lim and M.-H. Yang, IEEE TPAMI 2015. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + """ + def __init__(self, root_dir=None): + if root_dir is None: + root_dir = osp.expanduser('~/data/DTB70') + self.root_dir = root_dir + + # initialize the dataset + super(DTB70, self).__init__( + name='DTB70', + root_dir=self.root_dir) + + def _construct_seq_dict(self, root_dir): + # image and annotation paths + anno_files = sorted(glob.glob( + osp.join(root_dir, '*/groundtruth_rect.txt'))) + seq_dirs = [osp.dirname(f) for f in anno_files] + seq_names = [osp.basename(d) for d in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], 'img/*.jpg'))) + anno = np.loadtxt(anno_files[s], delimiter=',') + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/got10k.py b/utils/neuron/data/datasets/got10k.py new file mode 100755 index 0000000..dbcc321 --- /dev/null +++ b/utils/neuron/data/datasets/got10k.py @@ -0,0 +1,110 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['GOT10k'] + + +@registry.register_module +class GOT10k(SeqDataset): + r"""`GOT-10K <http://got-10k.aitestunion.com//>`_ Dataset. + + Publication: + ``GOT-10k: A Large High-Diversity Benchmark for Generic Object + Tracking in the Wild``, L. Huang, X. Zhao and K. Huang, arXiv 2018. + + Args: + root_dir (string): Root directory of dataset where ``train``, + ``val`` and ``test`` folders exist. + subset (string, optional): Specify ``train``, ``val`` or ``test`` + subset of GOT-10k. + list_file (string, optional): If provided, only read sequences + specified by the file instead of all sequences in the subset. + """ + def __init__(self, root_dir=None, subset='test', list_file=None): + # dataset name and paths + if root_dir is None: + root_dir = osp.expanduser('~/data/GOT-10k') + assert subset in ['train', 'val', 'test'] + if list_file is None: + list_file = osp.join(root_dir, subset, 'list.txt') + self.root_dir = root_dir + self.subset = subset + self.list_file = list_file + self.name = 'GOT-10k_{}'.format(subset) + + # initialize dataset + super(GOT10k, self).__init__( + self.name, + root_dir=self.root_dir, + subset=self.subset, + list_file=self.list_file) + + def _construct_seq_dict(self, root_dir, subset, list_file): + # image and annotation paths + with open(list_file, 'r') as f: + seq_names = f.read().strip().split('\n') + seq_dirs = [osp.join(root_dir, subset, s) + for s in seq_names] + anno_files = [osp.join(d, 'groundtruth.txt') + for d in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 100 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + anno = np.loadtxt( + anno_files[s], delimiter=',', dtype=np.float32) + if anno.ndim == 1: + assert anno.size == 4 + anno = anno[np.newaxis, :] + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = self._fetch_meta(seq_dirs[s]) + meta.update({ + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len}) + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + def _fetch_meta(self, seq_dir): + # meta information + meta_file = osp.join(seq_dir, 'meta_info.ini') + if osp.exists(meta_file): + with open(meta_file) as f: + meta = f.read().strip().split('\n')[1:] + meta = [line.split(': ') for line in meta] + meta = {line[0]: line[1] for line in meta} + else: + meta = {} + + # attributes + attributes = ['cover', 'absence', 'cut_by_image'] + for att in attributes: + att_file = osp.join(seq_dir, att + '.label') + if osp.exists(att_file): + meta[att] = np.loadtxt(att_file) + + return meta diff --git a/utils/neuron/data/datasets/imagenet.py b/utils/neuron/data/datasets/imagenet.py new file mode 100755 index 0000000..9354fca --- /dev/null +++ b/utils/neuron/data/datasets/imagenet.py @@ -0,0 +1,182 @@ +import os.path as osp +import glob +import numpy as np +import xml.etree.ElementTree as ET + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['ImageNetVID'] + + +@registry.register_module +class ImageNetVID(SeqDataset): + r"""`ImageNet Video Image Detection (VID) <https://image-net.org/challenges/LSVRC/2015/#vid>`_ Dataset. + + Publication: + ``ImageNet Large Scale Visual Recognition Challenge``, O. Russakovsky, + J. deng, H. Su, etc. IJCV, 2015. + + Args: + root_dir (string): Root directory of dataset where ``Data`` and + ``Annotations`` folders exist. + subset (string, optional): Specify ``train``, ``val`` or (``train``, ``val``) + subset(s) of ImageNet-VID. Default is a tuple (``train``, ``val``). + """ + CLASSES = ( + 'airplane', + 'antelope', + 'bear ', + 'bicycle', + 'bird', + 'bus', + 'car', + 'cattle', + 'dog', + 'domestic cat', + 'elephant', + 'fox', + 'giant panda', + 'hamster', + 'horse', + 'lion', + 'lizard', + 'monkey', + 'motorcycle ', + 'rabbit', + 'red panda', + 'sheep', + 'snake', + 'squirrel', + 'tiger', + 'train', + 'turtle', + 'watercraft ', + 'whale', + 'zebra') + WORDNET_IDs = ( + 'n02691156', + 'n02419796', + 'n02131653', + 'n02834778', + 'n01503061', + 'n02924116', + 'n02958343', + 'n02402425', + 'n02084071', + 'n02121808', + 'n02503517', + 'n02118333', + 'n02510455', + 'n02342885', + 'n02374451', + 'n02129165', + 'n01674464', + 'n02484322', + 'n03790512', + 'n02324045', + 'n02509815', + 'n02411705', + 'n01726692', + 'n02355227', + 'n02129604', + 'n04468005', + 'n01662784', + 'n04530566', + 'n02062744', + 'n02391049') + + def __init__(self, root_dir=None, subset=['train', 'val']): + # dataset name and paths + if root_dir is None: + root_dir = osp.expanduser('~/data/ILSVRC') + if isinstance(subset, str): + assert subset in ['train', 'val'] + subset = [subset] + elif isinstance(subset, (list, tuple)): + assert all([s in ['train', 'val'] for s in subset]) + subset = list(subset) + else: + raise ValueError('Unknown subset') + self.root_dir = root_dir + self.subset = subset + self.name = 'ImageNetVID_{}'.format('_'.join(subset)) + + # initialize dataset + super(ImageNetVID, self).__init__( + self.name, + root_dir=self.root_dir, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, subset): + # image and annotation paths + seq_dirs = [] + anno_dirs = [] + if 'train' in subset: + _seq_dirs = sorted(glob.glob(osp.join( + root_dir, 'Data/VID/train/ILSVRC*/ILSVRC*'))) + _anno_dirs = [osp.join( + root_dir, 'Annotations/VID/train', + *s.split('/')[-2:]) for s in _seq_dirs] + seq_dirs += _seq_dirs + anno_dirs += _anno_dirs + if 'val' in subset: + _seq_dirs = sorted(glob.glob(osp.join( + root_dir, 'Data/VID/val/ILSVRC2015_val_*'))) + _anno_dirs = [osp.join( + root_dir, 'Annotations/VID/val', + s.split('/')[-1]) for s in _seq_dirs] + seq_dirs += _seq_dirs + anno_dirs += _anno_dirs + seq_names = [osp.basename(s) for s in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 100 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + + # parse XML annotation files + anno_files = sorted(glob.glob(osp.join( + anno_dirs[s], '*.xml'))) + objects = [ET.ElementTree(file=f).findall('object') + for f in anno_files] + + anno_s = [] + for f, group in enumerate(objects): + for obj in group: + anno_obj = [ + f, # frame_id + int(obj.find('trackid').text), # target_id + int(obj.find('bndbox/xmin').text), # x1 + int(obj.find('bndbox/ymin').text), # y1 + int(obj.find('bndbox/xmax').text), # x2 + int(obj.find('bndbox/ymax').text), # y2 + 1, # score/keep + self.WORDNET_IDs.index(obj.find('name').text), # class_id + int(obj.find('occluded').text)] # occlusion + anno_s.append(anno_obj) + anno_s = np.array(anno_s, dtype=np.float32) + + # meta information + img_files = [osp.join(seq_dirs[s], '%06d.JPEG' % f) + for f in range(len(objects))] + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': len(img_files), + 'target_num': len(set(anno_s[:, 1])), + 'total_instances': len(anno_s)} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno_s, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/lasot.json b/utils/neuron/data/datasets/lasot.json new file mode 100755 index 0000000..29a0e35 --- /dev/null +++ b/utils/neuron/data/datasets/lasot.json @@ -0,0 +1,1406 @@ +{ + "train": [ + "airplane-10", + "airplane-11", + "airplane-12", + "airplane-14", + "airplane-16", + "airplane-17", + "airplane-18", + "airplane-19", + "airplane-2", + "airplane-20", + "airplane-3", + "airplane-4", + "airplane-5", + "airplane-6", + "airplane-7", + "airplane-8", + "basketball-10", + "basketball-12", + "basketball-13", + "basketball-14", + "basketball-15", + "basketball-16", + "basketball-17", + "basketball-18", + "basketball-19", + "basketball-2", + "basketball-20", + "basketball-3", + "basketball-4", + "basketball-5", + "basketball-8", + "basketball-9", + "bear-1", + "bear-10", + "bear-11", + "bear-12", + "bear-13", + "bear-14", + "bear-15", + "bear-16", + "bear-18", + "bear-19", + "bear-20", + "bear-3", + "bear-5", + "bear-7", + "bear-8", + "bear-9", + "bicycle-1", + "bicycle-10", + "bicycle-11", + "bicycle-12", + "bicycle-13", + "bicycle-14", + "bicycle-15", + "bicycle-16", + "bicycle-17", + "bicycle-19", + "bicycle-20", + "bicycle-3", + "bicycle-4", + "bicycle-5", + "bicycle-6", + "bicycle-8", + "bird-1", + "bird-10", + "bird-11", + "bird-12", + "bird-13", + "bird-14", + "bird-16", + "bird-18", + "bird-19", + "bird-20", + "bird-4", + "bird-5", + "bird-6", + "bird-7", + "bird-8", + "bird-9", + "boat-1", + "boat-10", + "boat-11", + "boat-13", + "boat-14", + "boat-15", + "boat-16", + "boat-18", + "boat-19", + "boat-2", + "boat-20", + "boat-5", + "boat-6", + "boat-7", + "boat-8", + "boat-9", + "book-1", + "book-12", + "book-13", + "book-14", + "book-15", + "book-16", + "book-17", + "book-18", + "book-2", + "book-20", + "book-4", + "book-5", + "book-6", + "book-7", + "book-8", + "book-9", + "bottle-10", + "bottle-11", + "bottle-13", + "bottle-15", + "bottle-16", + "bottle-17", + "bottle-19", + "bottle-2", + "bottle-20", + "bottle-3", + "bottle-4", + "bottle-5", + "bottle-6", + "bottle-7", + "bottle-8", + "bottle-9", + "bus-1", + "bus-10", + "bus-11", + "bus-12", + "bus-13", + "bus-14", + "bus-15", + "bus-16", + "bus-18", + "bus-20", + "bus-3", + "bus-4", + "bus-6", + "bus-7", + "bus-8", + "bus-9", + "car-1", + "car-10", + "car-11", + "car-12", + "car-13", + "car-14", + "car-15", + "car-16", + "car-18", + "car-19", + "car-20", + "car-3", + "car-4", + "car-5", + "car-7", + "car-8", + "cat-10", + "cat-11", + "cat-12", + "cat-13", + "cat-14", + "cat-15", + "cat-16", + "cat-17", + "cat-19", + "cat-2", + "cat-4", + "cat-5", + "cat-6", + "cat-7", + "cat-8", + "cat-9", + "cattle-1", + "cattle-10", + "cattle-11", + "cattle-14", + "cattle-15", + "cattle-16", + "cattle-17", + "cattle-18", + "cattle-19", + "cattle-20", + "cattle-3", + "cattle-4", + "cattle-5", + "cattle-6", + "cattle-8", + "cattle-9", + "chameleon-1", + "chameleon-10", + "chameleon-12", + "chameleon-13", + "chameleon-14", + "chameleon-15", + "chameleon-16", + "chameleon-17", + "chameleon-18", + "chameleon-19", + "chameleon-2", + "chameleon-4", + "chameleon-5", + "chameleon-7", + "chameleon-8", + "chameleon-9", + "coin-1", + "coin-10", + "coin-11", + "coin-12", + "coin-13", + "coin-14", + "coin-15", + "coin-16", + "coin-17", + "coin-19", + "coin-2", + "coin-20", + "coin-4", + "coin-5", + "coin-8", + "coin-9", + "crab-1", + "crab-10", + "crab-11", + "crab-13", + "crab-14", + "crab-15", + "crab-16", + "crab-17", + "crab-19", + "crab-2", + "crab-20", + "crab-4", + "crab-5", + "crab-7", + "crab-8", + "crab-9", + "crocodile-1", + "crocodile-11", + "crocodile-12", + "crocodile-13", + "crocodile-15", + "crocodile-16", + "crocodile-17", + "crocodile-18", + "crocodile-19", + "crocodile-2", + "crocodile-20", + "crocodile-5", + "crocodile-6", + "crocodile-7", + "crocodile-8", + "crocodile-9", + "cup-10", + "cup-11", + "cup-12", + "cup-13", + "cup-14", + "cup-15", + "cup-16", + "cup-18", + "cup-19", + "cup-2", + "cup-20", + "cup-3", + "cup-5", + "cup-6", + "cup-8", + "cup-9", + "deer-1", + "deer-11", + "deer-12", + "deer-13", + "deer-15", + "deer-16", + "deer-17", + "deer-18", + "deer-19", + "deer-2", + "deer-20", + "deer-3", + "deer-5", + "deer-6", + "deer-7", + "deer-9", + "dog-10", + "dog-11", + "dog-12", + "dog-13", + "dog-14", + "dog-16", + "dog-17", + "dog-18", + "dog-2", + "dog-20", + "dog-3", + "dog-4", + "dog-5", + "dog-6", + "dog-8", + "dog-9", + "drone-1", + "drone-10", + "drone-11", + "drone-12", + "drone-14", + "drone-16", + "drone-17", + "drone-18", + "drone-19", + "drone-20", + "drone-3", + "drone-4", + "drone-5", + "drone-6", + "drone-8", + "drone-9", + "electricfan-11", + "electricfan-12", + "electricfan-13", + "electricfan-14", + "electricfan-15", + "electricfan-16", + "electricfan-17", + "electricfan-19", + "electricfan-2", + "electricfan-3", + "electricfan-4", + "electricfan-5", + "electricfan-6", + "electricfan-7", + "electricfan-8", + "electricfan-9", + "elephant-10", + "elephant-11", + "elephant-13", + "elephant-14", + "elephant-15", + "elephant-17", + "elephant-19", + "elephant-2", + "elephant-20", + "elephant-3", + "elephant-4", + "elephant-5", + "elephant-6", + "elephant-7", + "elephant-8", + "elephant-9", + "flag-1", + "flag-10", + "flag-11", + "flag-12", + "flag-13", + "flag-14", + "flag-15", + "flag-16", + "flag-17", + "flag-18", + "flag-19", + "flag-20", + "flag-4", + "flag-6", + "flag-7", + "flag-8", + "fox-1", + "fox-10", + "fox-11", + "fox-12", + "fox-13", + "fox-14", + "fox-15", + "fox-16", + "fox-17", + "fox-18", + "fox-19", + "fox-4", + "fox-6", + "fox-7", + "fox-8", + "fox-9", + "frog-1", + "frog-10", + "frog-11", + "frog-12", + "frog-13", + "frog-14", + "frog-15", + "frog-16", + "frog-17", + "frog-18", + "frog-19", + "frog-2", + "frog-5", + "frog-6", + "frog-7", + "frog-8", + "gametarget-10", + "gametarget-11", + "gametarget-12", + "gametarget-14", + "gametarget-15", + "gametarget-16", + "gametarget-17", + "gametarget-18", + "gametarget-19", + "gametarget-20", + "gametarget-3", + "gametarget-4", + "gametarget-5", + "gametarget-6", + "gametarget-8", + "gametarget-9", + "gecko-10", + "gecko-11", + "gecko-12", + "gecko-13", + "gecko-14", + "gecko-15", + "gecko-17", + "gecko-18", + "gecko-2", + "gecko-20", + "gecko-3", + "gecko-4", + "gecko-6", + "gecko-7", + "gecko-8", + "gecko-9", + "giraffe-1", + "giraffe-11", + "giraffe-12", + "giraffe-14", + "giraffe-16", + "giraffe-17", + "giraffe-18", + "giraffe-19", + "giraffe-20", + "giraffe-3", + "giraffe-4", + "giraffe-5", + "giraffe-6", + "giraffe-7", + "giraffe-8", + "giraffe-9", + "goldfish-1", + "goldfish-11", + "goldfish-12", + "goldfish-13", + "goldfish-14", + "goldfish-15", + "goldfish-16", + "goldfish-17", + "goldfish-18", + "goldfish-19", + "goldfish-2", + "goldfish-20", + "goldfish-4", + "goldfish-5", + "goldfish-6", + "goldfish-9", + "gorilla-1", + "gorilla-10", + "gorilla-11", + "gorilla-12", + "gorilla-14", + "gorilla-15", + "gorilla-16", + "gorilla-17", + "gorilla-18", + "gorilla-19", + "gorilla-2", + "gorilla-20", + "gorilla-3", + "gorilla-5", + "gorilla-7", + "gorilla-8", + "guitar-1", + "guitar-11", + "guitar-12", + "guitar-13", + "guitar-14", + "guitar-15", + "guitar-17", + "guitar-18", + "guitar-19", + "guitar-2", + "guitar-20", + "guitar-4", + "guitar-5", + "guitar-6", + "guitar-7", + "guitar-9", + "hand-1", + "hand-10", + "hand-11", + "hand-12", + "hand-13", + "hand-14", + "hand-15", + "hand-17", + "hand-18", + "hand-19", + "hand-20", + "hand-4", + "hand-5", + "hand-6", + "hand-7", + "hand-8", + "hat-10", + "hat-11", + "hat-12", + "hat-13", + "hat-14", + "hat-15", + "hat-16", + "hat-17", + "hat-19", + "hat-20", + "hat-3", + "hat-4", + "hat-6", + "hat-7", + "hat-8", + "hat-9", + "helmet-1", + "helmet-10", + "helmet-12", + "helmet-14", + "helmet-15", + "helmet-16", + "helmet-17", + "helmet-18", + "helmet-2", + "helmet-20", + "helmet-3", + "helmet-4", + "helmet-6", + "helmet-7", + "helmet-8", + "helmet-9", + "hippo-10", + "hippo-11", + "hippo-12", + "hippo-13", + "hippo-14", + "hippo-15", + "hippo-16", + "hippo-17", + "hippo-18", + "hippo-19", + "hippo-2", + "hippo-3", + "hippo-4", + "hippo-5", + "hippo-6", + "hippo-8", + "horse-10", + "horse-11", + "horse-13", + "horse-14", + "horse-16", + "horse-17", + "horse-18", + "horse-19", + "horse-2", + "horse-20", + "horse-3", + "horse-5", + "horse-6", + "horse-7", + "horse-8", + "horse-9", + "kangaroo-1", + "kangaroo-10", + "kangaroo-12", + "kangaroo-13", + "kangaroo-15", + "kangaroo-16", + "kangaroo-17", + "kangaroo-18", + "kangaroo-19", + "kangaroo-20", + "kangaroo-3", + "kangaroo-4", + "kangaroo-6", + "kangaroo-7", + "kangaroo-8", + "kangaroo-9", + "kite-1", + "kite-11", + "kite-12", + "kite-13", + "kite-14", + "kite-16", + "kite-17", + "kite-18", + "kite-19", + "kite-2", + "kite-20", + "kite-3", + "kite-5", + "kite-7", + "kite-8", + "kite-9", + "leopard-10", + "leopard-11", + "leopard-12", + "leopard-13", + "leopard-14", + "leopard-15", + "leopard-17", + "leopard-18", + "leopard-19", + "leopard-2", + "leopard-3", + "leopard-4", + "leopard-5", + "leopard-6", + "leopard-8", + "leopard-9", + "licenseplate-1", + "licenseplate-10", + "licenseplate-11", + "licenseplate-14", + "licenseplate-16", + "licenseplate-17", + "licenseplate-18", + "licenseplate-19", + "licenseplate-2", + "licenseplate-20", + "licenseplate-3", + "licenseplate-4", + "licenseplate-5", + "licenseplate-7", + "licenseplate-8", + "licenseplate-9", + "lion-10", + "lion-11", + "lion-13", + "lion-14", + "lion-15", + "lion-16", + "lion-17", + "lion-18", + "lion-19", + "lion-2", + "lion-3", + "lion-4", + "lion-6", + "lion-7", + "lion-8", + "lion-9", + "lizard-10", + "lizard-11", + "lizard-12", + "lizard-14", + "lizard-15", + "lizard-16", + "lizard-17", + "lizard-18", + "lizard-19", + "lizard-2", + "lizard-20", + "lizard-4", + "lizard-5", + "lizard-7", + "lizard-8", + "lizard-9", + "microphone-1", + "microphone-10", + "microphone-11", + "microphone-12", + "microphone-13", + "microphone-15", + "microphone-17", + "microphone-18", + "microphone-19", + "microphone-20", + "microphone-3", + "microphone-4", + "microphone-5", + "microphone-7", + "microphone-8", + "microphone-9", + "monkey-1", + "monkey-10", + "monkey-11", + "monkey-12", + "monkey-13", + "monkey-14", + "monkey-15", + "monkey-16", + "monkey-18", + "monkey-19", + "monkey-2", + "monkey-20", + "monkey-5", + "monkey-6", + "monkey-7", + "monkey-8", + "motorcycle-10", + "motorcycle-11", + "motorcycle-12", + "motorcycle-13", + "motorcycle-14", + "motorcycle-15", + "motorcycle-16", + "motorcycle-17", + "motorcycle-19", + "motorcycle-2", + "motorcycle-20", + "motorcycle-4", + "motorcycle-5", + "motorcycle-6", + "motorcycle-7", + "motorcycle-8", + "mouse-10", + "mouse-11", + "mouse-12", + "mouse-13", + "mouse-14", + "mouse-15", + "mouse-16", + "mouse-18", + "mouse-19", + "mouse-2", + "mouse-20", + "mouse-3", + "mouse-4", + "mouse-5", + "mouse-6", + "mouse-7", + "person-11", + "person-13", + "person-14", + "person-15", + "person-16", + "person-17", + "person-18", + "person-19", + "person-2", + "person-20", + "person-3", + "person-4", + "person-6", + "person-7", + "person-8", + "person-9", + "pig-1", + "pig-11", + "pig-12", + "pig-14", + "pig-15", + "pig-16", + "pig-17", + "pig-19", + "pig-20", + "pig-3", + "pig-4", + "pig-5", + "pig-6", + "pig-7", + "pig-8", + "pig-9", + "pool-1", + "pool-10", + "pool-11", + "pool-13", + "pool-14", + "pool-16", + "pool-17", + "pool-18", + "pool-19", + "pool-2", + "pool-20", + "pool-4", + "pool-5", + "pool-6", + "pool-8", + "pool-9", + "rabbit-1", + "rabbit-11", + "rabbit-12", + "rabbit-14", + "rabbit-15", + "rabbit-16", + "rabbit-18", + "rabbit-2", + "rabbit-20", + "rabbit-3", + "rabbit-4", + "rabbit-5", + "rabbit-6", + "rabbit-7", + "rabbit-8", + "rabbit-9", + "racing-1", + "racing-11", + "racing-12", + "racing-13", + "racing-14", + "racing-17", + "racing-18", + "racing-19", + "racing-2", + "racing-3", + "racing-4", + "racing-5", + "racing-6", + "racing-7", + "racing-8", + "racing-9", + "robot-10", + "robot-11", + "robot-12", + "robot-13", + "robot-14", + "robot-15", + "robot-16", + "robot-17", + "robot-18", + "robot-2", + "robot-20", + "robot-3", + "robot-4", + "robot-6", + "robot-7", + "robot-9", + "rubicCube-10", + "rubicCube-11", + "rubicCube-12", + "rubicCube-13", + "rubicCube-15", + "rubicCube-16", + "rubicCube-17", + "rubicCube-18", + "rubicCube-2", + "rubicCube-20", + "rubicCube-3", + "rubicCube-4", + "rubicCube-5", + "rubicCube-7", + "rubicCube-8", + "rubicCube-9", + "sepia-1", + "sepia-10", + "sepia-11", + "sepia-12", + "sepia-14", + "sepia-15", + "sepia-17", + "sepia-18", + "sepia-19", + "sepia-2", + "sepia-20", + "sepia-3", + "sepia-4", + "sepia-5", + "sepia-7", + "sepia-9", + "shark-1", + "shark-10", + "shark-11", + "shark-12", + "shark-13", + "shark-14", + "shark-15", + "shark-16", + "shark-17", + "shark-18", + "shark-19", + "shark-20", + "shark-4", + "shark-7", + "shark-8", + "shark-9", + "sheep-1", + "sheep-10", + "sheep-11", + "sheep-12", + "sheep-13", + "sheep-14", + "sheep-15", + "sheep-16", + "sheep-17", + "sheep-18", + "sheep-19", + "sheep-2", + "sheep-20", + "sheep-4", + "sheep-6", + "sheep-8", + "skateboard-1", + "skateboard-10", + "skateboard-11", + "skateboard-12", + "skateboard-13", + "skateboard-14", + "skateboard-15", + "skateboard-17", + "skateboard-18", + "skateboard-2", + "skateboard-20", + "skateboard-4", + "skateboard-5", + "skateboard-6", + "skateboard-7", + "skateboard-9", + "spider-1", + "spider-10", + "spider-11", + "spider-12", + "spider-13", + "spider-15", + "spider-17", + "spider-19", + "spider-2", + "spider-3", + "spider-4", + "spider-5", + "spider-6", + "spider-7", + "spider-8", + "spider-9", + "squirrel-1", + "squirrel-10", + "squirrel-12", + "squirrel-14", + "squirrel-15", + "squirrel-16", + "squirrel-17", + "squirrel-18", + "squirrel-2", + "squirrel-20", + "squirrel-3", + "squirrel-4", + "squirrel-5", + "squirrel-6", + "squirrel-7", + "squirrel-9", + "surfboard-1", + "surfboard-10", + "surfboard-11", + "surfboard-13", + "surfboard-14", + "surfboard-15", + "surfboard-16", + "surfboard-17", + "surfboard-18", + "surfboard-19", + "surfboard-2", + "surfboard-20", + "surfboard-3", + "surfboard-6", + "surfboard-7", + "surfboard-9", + "swing-1", + "swing-11", + "swing-12", + "swing-13", + "swing-15", + "swing-16", + "swing-18", + "swing-19", + "swing-2", + "swing-3", + "swing-4", + "swing-5", + "swing-6", + "swing-7", + "swing-8", + "swing-9", + "tank-1", + "tank-10", + "tank-11", + "tank-12", + "tank-13", + "tank-15", + "tank-17", + "tank-18", + "tank-19", + "tank-2", + "tank-20", + "tank-3", + "tank-4", + "tank-5", + "tank-7", + "tank-8", + "tiger-1", + "tiger-10", + "tiger-11", + "tiger-13", + "tiger-14", + "tiger-15", + "tiger-16", + "tiger-17", + "tiger-19", + "tiger-2", + "tiger-20", + "tiger-3", + "tiger-5", + "tiger-7", + "tiger-8", + "tiger-9", + "train-10", + "train-12", + "train-13", + "train-14", + "train-15", + "train-16", + "train-17", + "train-18", + "train-19", + "train-2", + "train-3", + "train-4", + "train-5", + "train-6", + "train-8", + "train-9", + "truck-1", + "truck-10", + "truck-11", + "truck-12", + "truck-13", + "truck-14", + "truck-15", + "truck-17", + "truck-18", + "truck-19", + "truck-2", + "truck-20", + "truck-4", + "truck-5", + "truck-8", + "truck-9", + "turtle-1", + "turtle-10", + "turtle-11", + "turtle-12", + "turtle-13", + "turtle-14", + "turtle-15", + "turtle-17", + "turtle-18", + "turtle-19", + "turtle-2", + "turtle-20", + "turtle-3", + "turtle-4", + "turtle-6", + "turtle-7", + "umbrella-1", + "umbrella-10", + "umbrella-11", + "umbrella-12", + "umbrella-13", + "umbrella-14", + "umbrella-15", + "umbrella-16", + "umbrella-18", + "umbrella-20", + "umbrella-3", + "umbrella-4", + "umbrella-5", + "umbrella-6", + "umbrella-7", + "umbrella-8", + "volleyball-10", + "volleyball-11", + "volleyball-12", + "volleyball-14", + "volleyball-15", + "volleyball-16", + "volleyball-17", + "volleyball-2", + "volleyball-20", + "volleyball-3", + "volleyball-4", + "volleyball-5", + "volleyball-6", + "volleyball-7", + "volleyball-8", + "volleyball-9", + "yoyo-1", + "yoyo-10", + "yoyo-11", + "yoyo-12", + "yoyo-13", + "yoyo-14", + "yoyo-16", + "yoyo-18", + "yoyo-2", + "yoyo-20", + "yoyo-3", + "yoyo-4", + "yoyo-5", + "yoyo-6", + "yoyo-8", + "yoyo-9", + "zebra-1", + "zebra-11", + "zebra-12", + "zebra-13", + "zebra-15", + "zebra-18", + "zebra-19", + "zebra-2", + "zebra-20", + "zebra-3", + "zebra-4", + "zebra-5", + "zebra-6", + "zebra-7", + "zebra-8", + "zebra-9" + ], + "test": [ + "airplane-1", + "airplane-9", + "airplane-13", + "airplane-15", + "basketball-1", + "basketball-6", + "basketball-7", + "basketball-11", + "bear-2", + "bear-4", + "bear-6", + "bear-17", + "bicycle-2", + "bicycle-7", + "bicycle-9", + "bicycle-18", + "bird-2", + "bird-3", + "bird-15", + "bird-17", + "boat-3", + "boat-4", + "boat-12", + "boat-17", + "book-3", + "book-10", + "book-11", + "book-19", + "bottle-1", + "bottle-12", + "bottle-14", + "bottle-18", + "bus-2", + "bus-5", + "bus-17", + "bus-19", + "car-2", + "car-6", + "car-9", + "car-17", + "cat-1", + "cat-3", + "cat-18", + "cat-20", + "cattle-2", + "cattle-7", + "cattle-12", + "cattle-13", + "spider-14", + "spider-16", + "spider-18", + "spider-20", + "coin-3", + "coin-6", + "coin-7", + "coin-18", + "crab-3", + "crab-6", + "crab-12", + "crab-18", + "surfboard-12", + "surfboard-4", + "surfboard-5", + "surfboard-8", + "cup-1", + "cup-4", + "cup-7", + "cup-17", + "deer-4", + "deer-8", + "deer-10", + "deer-14", + "dog-1", + "dog-7", + "dog-15", + "dog-19", + "guitar-3", + "guitar-8", + "guitar-10", + "guitar-16", + "person-1", + "person-5", + "person-10", + "person-12", + "pig-2", + "pig-10", + "pig-13", + "pig-18", + "rubicCube-1", + "rubicCube-6", + "rubicCube-14", + "rubicCube-19", + "swing-10", + "swing-14", + "swing-17", + "swing-20", + "drone-13", + "drone-15", + "drone-2", + "drone-7", + "pool-12", + "pool-15", + "pool-3", + "pool-7", + "rabbit-10", + "rabbit-13", + "rabbit-17", + "rabbit-19", + "racing-10", + "racing-15", + "racing-16", + "racing-20", + "robot-1", + "robot-19", + "robot-5", + "robot-8", + "sepia-13", + "sepia-16", + "sepia-6", + "sepia-8", + "sheep-3", + "sheep-5", + "sheep-7", + "sheep-9", + "skateboard-16", + "skateboard-19", + "skateboard-3", + "skateboard-8", + "tank-14", + "tank-16", + "tank-6", + "tank-9", + "tiger-12", + "tiger-18", + "tiger-4", + "tiger-6", + "train-1", + "train-11", + "train-20", + "train-7", + "truck-16", + "truck-3", + "truck-6", + "truck-7", + "turtle-16", + "turtle-5", + "turtle-8", + "turtle-9", + "umbrella-17", + "umbrella-19", + "umbrella-2", + "umbrella-9", + "yoyo-15", + "yoyo-17", + "yoyo-19", + "yoyo-7", + "zebra-10", + "zebra-14", + "zebra-16", + "zebra-17", + "elephant-1", + "elephant-12", + "elephant-16", + "elephant-18", + "goldfish-3", + "goldfish-7", + "goldfish-8", + "goldfish-10", + "hat-1", + "hat-2", + "hat-5", + "hat-18", + "kite-4", + "kite-6", + "kite-10", + "kite-15", + "motorcycle-1", + "motorcycle-3", + "motorcycle-9", + "motorcycle-18", + "mouse-1", + "mouse-8", + "mouse-9", + "mouse-17", + "flag-3", + "flag-9", + "flag-5", + "flag-2", + "frog-3", + "frog-4", + "frog-20", + "frog-9", + "gametarget-1", + "gametarget-2", + "gametarget-7", + "gametarget-13", + "hand-2", + "hand-3", + "hand-9", + "hand-16", + "helmet-5", + "helmet-11", + "helmet-19", + "helmet-13", + "licenseplate-6", + "licenseplate-12", + "licenseplate-13", + "licenseplate-15", + "electricfan-1", + "electricfan-10", + "electricfan-18", + "electricfan-20", + "chameleon-3", + "chameleon-6", + "chameleon-11", + "chameleon-20", + "crocodile-3", + "crocodile-4", + "crocodile-10", + "crocodile-14", + "gecko-1", + "gecko-5", + "gecko-16", + "gecko-19", + "fox-2", + "fox-3", + "fox-5", + "fox-20", + "giraffe-2", + "giraffe-10", + "giraffe-13", + "giraffe-15", + "gorilla-4", + "gorilla-6", + "gorilla-9", + "gorilla-13", + "hippo-1", + "hippo-7", + "hippo-9", + "hippo-20", + "horse-1", + "horse-4", + "horse-12", + "horse-15", + "kangaroo-2", + "kangaroo-5", + "kangaroo-11", + "kangaroo-14", + "leopard-1", + "leopard-7", + "leopard-16", + "leopard-20", + "lion-1", + "lion-5", + "lion-12", + "lion-20", + "lizard-1", + "lizard-3", + "lizard-6", + "lizard-13", + "microphone-2", + "microphone-6", + "microphone-14", + "microphone-16", + "monkey-3", + "monkey-4", + "monkey-9", + "monkey-17", + "shark-2", + "shark-3", + "shark-5", + "shark-6", + "squirrel-8", + "squirrel-11", + "squirrel-13", + "squirrel-19", + "volleyball-1", + "volleyball-13", + "volleyball-18", + "volleyball-19" + ] +} \ No newline at end of file diff --git a/utils/neuron/data/datasets/lasot.py b/utils/neuron/data/datasets/lasot.py new file mode 100755 index 0000000..df949f7 --- /dev/null +++ b/utils/neuron/data/datasets/lasot.py @@ -0,0 +1,108 @@ +import os.path as osp +import glob +import json +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset +from local_path import lasot_dir + +__all__ = ['LaSOT'] + + +@registry.register_module +class LaSOT(SeqDataset): + r"""`LaSOT <https://cis.temple.edu/lasot/>`_ Datasets. + + Publication: + ``LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking``, + H. Fan, L. Lin, F. Yang, P. Chu, G. Deng, S. Yu, H. Bai, + Y. Xu, C. Liao, and H. Ling., CVPR 2019. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + subset (string, optional): Specify ``train`` or ``test`` + subset of LaSOT. + """ + def __init__(self, root_dir=None, subset='test'): + # dataset name and paths + assert subset in ['train', 'test'], 'Unknown subset.' + if root_dir is None: + root_dir = osp.expanduser(lasot_dir) + self.root_dir = root_dir + self.subset = subset + self.name = 'LaSOT_{}'.format(subset) + + # initialize dataset + super(LaSOT, self).__init__( + self.name, + root_dir=self.root_dir, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, subset): + # load subset sequence names + split_file = osp.join( + osp.dirname(__file__), 'lasot.json') + with open(split_file, 'r') as f: + splits = json.load(f) + seq_names = splits[subset] + + # image and annotation paths + seq_dirs = [osp.join( + root_dir, n[:n.rfind('-')], n, 'img') + for n in seq_names] + anno_files = [osp.join( + root_dir, n[:n.rfind('-')], n, 'groundtruth.txt') + for n in seq_names] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 100 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + img_files = sorted(glob.glob(osp.join( + seq_dirs[s], '*.jpg'))) + anno = np.loadtxt( + anno_files[s], delimiter=',', dtype=np.float32) + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = self._fetch_meta(seq_dirs[s]) + meta.update({ + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len}) + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + def _fetch_meta(self, seq_dir): + seq_dir = osp.dirname(seq_dir) + meta = {} + + # attributes + for att in ['full_occlusion', 'out_of_view']: + att_file = osp.join(seq_dir, att + '.txt') + if osp.exists(att_file): + meta[att] = np.loadtxt(att_file, delimiter=',') + + # nlp + nlp_file = osp.join(seq_dir, 'nlp.txt') + with open(nlp_file, 'r') as f: + if osp.exists(nlp_file): + meta['nlp'] = f.read().strip() + + return meta diff --git a/utils/neuron/data/datasets/mot.py b/utils/neuron/data/datasets/mot.py new file mode 100755 index 0000000..19c1d3a --- /dev/null +++ b/utils/neuron/data/datasets/mot.py @@ -0,0 +1,169 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +@registry.register_module +class MOT(SeqDataset): + """`MOT <https://motchallenge.net/>`_ Dataset. + + Publication: + ``MOT16: A Benchmark for Multi-Object Tracking``, + Milan, A., Leal-Taixé, L., Reid, I., Roth, S. and Schindler, K., arXiv 2016. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + version (integer, optional): Specify the version of MOT. Specify as + one of 2015, 2016, 2017 and 2019. + subset (string, optional): Specify ``train`` or ``test`` + subset of MOT. + """ + CLASSES = ( + 'Pedestrian', # 0 + 'Person on vehicle', # 1 + 'Car', # 2 + 'Bicycle', # 3 + 'Motorbike', # 4 + 'Non motorized vehicle', # 5 + 'Static person', # 6 + 'Distractor', # 7 + 'Occluder', # 8 + 'Occluder on the ground', # 9 + 'Occluder full', # 10 + 'Reflection', # 11 + 'Crowd') # 12 + + def __init__(self, root_dir=None, version=2016, subset='train'): + assert version in [2015, 2016, 2017, 2019] + assert subset in ['train', 'test'] + if version == 2015: + name = '2DMOT2015' + else: + name = 'MOT{}'.format(version % 100) + if root_dir is None: + root_dir = osp.expanduser('~/data/' + name) + self.root_dir = root_dir + self.version = version + self.subset = subset + self.name = '{}_{}'.format(name, subset) + + # initialize dataset + super(MOT, self).__init__( + self.name, + root_dir=self.root_dir, + version=self.version, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, version, subset): + # image and annotation paths + seq_dirs = sorted(glob.glob( + osp.join(root_dir, subset, '*/img1'))) + parent_dirs = [osp.dirname(d) for d in seq_dirs] + seq_names = [osp.basename(d) for d in parent_dirs] + det_files = [osp.join( + d, 'det/det.txt') for d in parent_dirs] + if subset == 'train': + gt_files = [osp.join( + d, 'gt/gt.txt') for d in parent_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + + det = np.loadtxt( + det_files[s], delimiter=',', dtype=np.float32) + det = self._format_det(det) + target = {'det': det} + + if subset == 'train': + gt = np.loadtxt( + gt_files[s], delimiter=',', dtype=np.float32) + gt = self._format_gt(gt) + target.update({'anno': gt}) + + # meta information + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': len(img_files), + 'target_num': -1 if subset != 'train' else len(set(gt[:, 1])), + 'total_instances': -1 if subset != 'train' else len(gt)} + target.update({'meta': meta}) + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': target} + + return seq_dict + + def _format_gt(self, gt): + r"""Standadize the gt format. + + Input format: + frame_id (1-indexed), target_id (1-indexed), x1, y1, w, h, keep, + class_id (1-indexed), visibility ratio + + Output format: + frame_id (0-indexed), target_id (0-indexed), x1, y1, x2, y2, keep, + class_id (0-indexed), occlusion + """ + anno = [ + gt[:, 0:1] - 1, # frame_id + gt[:, 1:2] - 1, # target_id + gt[:, 2:4], # x1, y1 + gt[:, 2:4] + gt[:, 4:6] - 1, # x2, y2 + gt[:, 6:7], # keep + gt[:, 7:8] - 1, # class_id + 1 - gt[:, 8:9]] # occlusion + anno = np.concatenate(anno, axis=1) + + # filter invalid annotations + mask_class = np.logical_or.reduce(( + anno[:, 7] == 0, + anno[:, 7] == 2, + anno[:, 7] == 3, + anno[:, 7] == 4)) + mask_frame = (anno[:, 0] >= 0) & (anno[:, 0] < 9999) + mask_keep = anno[:, 6] > 0.5 + mask_occ = anno[:, 8] > 0.5 + mask = (mask_class & mask_frame & mask_keep) + anno = anno[mask] + + return anno + + def _format_det(self, det): + r"""Standadize the gt format. + + Input format: + frame_id (1-indexed), target_id (1-indexed), x1, y1, w, h, + conf, x, y, z + + Output format: + frame_id (0-indexed), target_id (0-indexed), x1, y1, x2, y2, keep, + class_id (0-indexed), occlusion + """ + ones = np.ones((len(det), 1), dtype=det.dtype) + anno = [ + det[:, 0:1] - 1, # frame_id + ones, # target_id + det[:, 2:4], # x1, y1 + det[:, 2:4] + det[:, 4:6] - 1, # x2, y2 + ones, # keep + ones * 0, # class_id + ones * 0] # occlusion + anno = np.concatenate(anno, axis=1) + + # filter invalid annotations + mask = (anno[:, 0] >= 0) & (anno[:, 0] < 9999) + anno = anno[mask] + + return anno diff --git a/utils/neuron/data/datasets/nfs.py b/utils/neuron/data/datasets/nfs.py new file mode 100755 index 0000000..130ff1c --- /dev/null +++ b/utils/neuron/data/datasets/nfs.py @@ -0,0 +1,89 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['NfS'] + + +@registry.register_module +class NfS(SeqDataset): + """`NfS <http://ci2cv.net/nfs/index.html>`_ Dataset. + + Publication: + ``Need for Speed: A Benchmark for Higher Frame Rate Object Tracking``, + H. K. Galoogahi, A. Fagg, C. Huang, D. Ramanan and S. Lucey, ICCV 2017. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + fps (integer): Sequence frame rate. Two options ``30`` and ``240`` + are available. Default is 240. + """ + def __init__(self, root_dir=None, fps=30): + assert fps in [30, 240] + if root_dir is None: + root_dir = osp.expanduser('~/data/nfs') + self.root_dir = root_dir + self.fps = fps + + # initialize the dataset + super(NfS, self).__init__( + name='NfS_{}'.format(fps), + root_dir=root_dir, + fps=fps) + + def _construct_seq_dict(self, root_dir, fps): + # image and annotation paths + anno_files = sorted(glob.glob( + osp.join(root_dir, '*/%d/*.txt' % fps))) + seq_names = [ + osp.basename(f)[:-4] for f in anno_files] + seq_dirs = [osp.join( + osp.dirname(f), n) + for f, n in zip(anno_files, seq_names)] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 50 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + anno = np.loadtxt(anno_files[s], dtype=str) + anno = anno[:, 1:5].astype(np.float32) + + # handle inconsistent lengths + if not len(img_files) == len(anno): + if abs(len(anno) / len(img_files) - 8) < 1: + anno = anno[0::8, :] + diff = abs(len(img_files) - len(anno)) + if diff > 0 and diff <= 1: + n = min(len(img_files), len(anno)) + anno = anno[:n] + img_files = img_files[:n] + assert len(img_files) == len(anno) + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/otb.py b/utils/neuron/data/datasets/otb.py new file mode 100755 index 0000000..2d97a1f --- /dev/null +++ b/utils/neuron/data/datasets/otb.py @@ -0,0 +1,191 @@ +import os +import os.path as osp +import glob +import numpy as np +import io +from itertools import chain + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset +from local_path import otb_dir + +__all__ = ['OTB'] + + +@registry.register_module +class OTB(SeqDataset): + r"""`OTB <http://cvlab.hanyang.ac.kr/tracker_benchmark/>`_ Datasets. + + Publication: + ``Object Tracking Benchmark``, Y. Wu, J. Lim and M.-H. Yang, IEEE TPAMI 2015. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + version (integer or string): Specify the benchmark version, specify as one of + ``2013``, ``2015``, ``tb50`` and ``tb100``. + download (boolean, optional): If True, downloads the dataset from the internet + and puts it in root directory. If dataset is downloaded, it is not + downloaded again. + """ + __otb13_seqs = ['Basketball', 'Bolt', 'Boy', 'Car4', 'CarDark', + 'CarScale', 'Coke', 'Couple', 'Crossing', 'David', + 'David2', 'David3', 'Deer', 'Dog1', 'Doll', 'Dudek', + 'FaceOcc1', 'FaceOcc2', 'Fish', 'FleetFace', + 'Football', 'Football1', 'Freeman1', 'Freeman3', + 'Freeman4', 'Girl', 'Ironman', 'Jogging', 'Jumping', + 'Lemming', 'Liquor', 'Matrix', 'Mhyang', 'MotorRolling', + 'MountainBike', 'Shaking', 'Singer1', 'Singer2', + 'Skating1', 'Skiing', 'Soccer', 'Subway', 'Suv', + 'Sylvester', 'Tiger1', 'Tiger2', 'Trellis', 'Walking', + 'Walking2', 'Woman'] + + __tb50_seqs = ['Basketball', 'Biker', 'Bird1', 'BlurBody', 'BlurCar2', + 'BlurFace', 'BlurOwl', 'Bolt', 'Box', 'Car1', 'Car4', + 'CarDark', 'CarScale', 'ClifBar', 'Couple', 'Crowds', + 'David', 'Deer', 'Diving', 'DragonBaby', 'Dudek', + 'Football', 'Freeman4', 'Girl', 'Human3', 'Human4', + 'Human6', 'Human9', 'Ironman', 'Jump', 'Jumping', + 'Liquor', 'Matrix', 'MotorRolling', 'Panda', 'RedTeam', + 'Shaking', 'Singer2', 'Skating1', 'Skating2', 'Skiing', + 'Soccer', 'Surfer', 'Sylvester', 'Tiger2', 'Trellis', + 'Walking', 'Walking2', 'Woman'] + + __tb100_seqs = ['Bird2', 'BlurCar1', 'BlurCar3', 'BlurCar4', 'Board', + 'Bolt2', 'Boy', 'Car2', 'Car24', 'Coke', 'Coupon', + 'Crossing', 'Dancer', 'Dancer2', 'David2', 'David3', + 'Dog', 'Dog1', 'Doll', 'FaceOcc1', 'FaceOcc2', 'Fish', + 'FleetFace', 'Football1', 'Freeman1', 'Freeman3', + 'Girl2', 'Gym', 'Human2', 'Human5', 'Human7', 'Human8', + 'Jogging', 'KiteSurf', 'Lemming', 'Man', 'Mhyang', + 'MountainBike', 'Rubik', 'Singer1', 'Skater', + 'Skater2', 'Subway', 'Suv', 'Tiger1', 'Toy', 'Trans', + 'Twinnings', 'Vase'] + __tb50_seqs + + __otb15_seqs = __tb100_seqs + + __version_dict = { + 2013: __otb13_seqs, + 2015: __otb15_seqs, + 50: __tb50_seqs, + 100: __tb100_seqs} + + def __init__(self, root_dir=None, version=2015, download=False): + assert version in self.__version_dict + if root_dir is None: + root_dir = osp.expanduser(otb_dir) + self.root_dir = root_dir + self.version = version + if download: + self._download(root_dir, version) + + # initialize the dataset + super(OTB, self).__init__( + name='OTB-{}'.format(self.version), + root_dir=self.root_dir, + version=self.version) + + def _construct_seq_dict(self, root_dir, version): + # image and annotation paths + valid_seqs = self.__version_dict[version] + anno_files = sorted(list(chain.from_iterable(glob.glob( + osp.join(root_dir, s, 'groundtruth*.txt')) for s in valid_seqs))) + # remove empty annotation files + # (e.g., groundtruth_rect.1.txt of Human4) + anno_files = self._filter_files(anno_files) + seq_dirs = [osp.dirname(f) for f in anno_files] + seq_names = [osp.basename(d) for d in seq_dirs] + # rename repeated sequence names + # (e.g., Jogging and Skating2) + seq_names = self._rename_seqs(seq_names) + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], 'img/*.jpg'))) + + # special sequences + # (visit http://cvlab.hanyang.ac.kr/tracker_benchmark/index.html for detail) + if seq_name.lower() == 'david': + img_files = img_files[300-1:770] + elif seq_name.lower() == 'football1': + img_files = img_files[:74] + elif seq_name.lower() == 'freeman3': + img_files = img_files[:460] + elif seq_name.lower() == 'freeman4': + img_files = img_files[:283] + elif seq_name.lower() == 'diving': + img_files = img_files[:215] + + # load annotations (to deal with different delimeters) + with open(anno_files[s], 'r') as f: + anno = np.loadtxt(io.StringIO(f.read().replace(',', ' '))) + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + def _filter_files(self, filenames): + filtered_files = [] + for filename in filenames: + with open(filename, 'r') as f: + if f.read().strip() == '': + ops.sys_print('Warning: %s is empty.' % filename) + else: + filtered_files.append(filename) + + return filtered_files + + def _rename_seqs(self, seq_names): + # in case some sequences may have multiple targets + renamed_seqs = [] + for i, seq_name in enumerate(seq_names): + if seq_names.count(seq_name) == 1: + renamed_seqs.append(seq_name) + else: + ind = seq_names[:i + 1].count(seq_name) + renamed_seqs.append('%s.%d' % (seq_name, ind)) + + return renamed_seqs + + def _download(self, root_dir, version): + assert version in self.__version_dict + seq_names = self.__version_dict[version] + + if not osp.isdir(root_dir): + os.makedirs(root_dir) + elif all([osp.isdir(osp.join(root_dir, s)) for s in seq_names]): + ops.sys_print('Files already downloaded.') + return + + url_fmt = 'http://cvlab.hanyang.ac.kr/tracker_benchmark/seq/%s.zip' + for seq_name in seq_names: + seq_dir = osp.join(root_dir, seq_name) + if osp.isdir(seq_dir): + continue + url = url_fmt % seq_name + zip_file = osp.join(root_dir, seq_name + '.zip') + ops.sys_print('Downloading to %s...' % zip_file) + ops.download(url, zip_file) + ops.sys_print('\nExtracting to %s...' % root_dir) + ops.extract(zip_file, root_dir) + + return root_dir diff --git a/utils/neuron/data/datasets/oxuva.py b/utils/neuron/data/datasets/oxuva.py new file mode 100755 index 0000000..9721bb5 --- /dev/null +++ b/utils/neuron/data/datasets/oxuva.py @@ -0,0 +1,97 @@ +import os.path as osp +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['OxUvA'] + + +@registry.register_module +class OxUvA(SeqDataset): + """`OxUvA <https://oxuva.github.io/long-term-tracking-benchmark/>`_ Dataset. + + Publication: + ``Long-term Tracking in the Wild: a Benchmark``, + J. Valmadre, L. Bertinetto, J. F. Henriques, ECCV 2015. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + subset (string, optional): Specify ``dev`` or ``test`` subset of OxUvA. + frame_stride (int, optional): Frame stride for down-sampling frames. + """ + def __init__(self, root_dir=None, subset='dev', frame_stride=30): + assert subset in ['dev', 'test'] + if root_dir is None: + root_dir = osp.expanduser('~/data/OxUvA') + self.root_dir = root_dir + self.subset = subset + self.frame_stride = frame_stride + + # initialize the dataset + super(OxUvA, self).__init__( + name='OxUvA_{}'.format(subset), + root_dir=self.root_dir, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, subset): + # load task information + task_file = osp.join(root_dir, 'tasks/{}.csv'.format(subset)) + task = np.loadtxt(task_file, delimiter=',', dtype=str) + + # load dev annotations + if subset == 'dev': + dev_anno_file = osp.join(root_dir, 'annotations/dev.csv') + dev_anno = np.loadtxt(dev_anno_file, delimiter=',', dtype=str) + + # construct seq_dict + seq_dict = {} + for s, line in enumerate(task): + # parse task information + vid_id, obj_id = line[:2] + init_frame, last_frame = line[2:4].astype(int) + init_anno = line[4:8].astype(np.float32) + + # log information + seq_name = '_'.join([vid_id, obj_id]) + if s % 50 == 0 or s + 1 == len(task): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(task), seq_name)) + + # parse annotations + seq_dir = osp.join(root_dir, 'images', subset, vid_id) + img0 = ops.read_image(seq_dir + '/000000.jpeg') + h, w = img0.shape[:2] + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'target_num': 1} + + # parse and rescale initial annotations + anno = np.expand_dims(init_anno[[0, 2, 1, 3]], axis=0) + anno[:, [0, 2]] *= w + anno[:, [1, 3]] *= h + + # image paths + frames = np.arange( + init_frame, last_frame + 1, self.frame_stride) + img_files = [osp.join(seq_dir, '%06d.jpeg' % f) + for f in frames] + + # update meta information + meta.update({ + 'frame_num': len(img_files), + 'total_instances': len(img_files), + 'frames': frames}) + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/pot.py b/utils/neuron/data/datasets/pot.py new file mode 100755 index 0000000..88c8ff0 --- /dev/null +++ b/utils/neuron/data/datasets/pot.py @@ -0,0 +1,78 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['POT'] + + +@registry.register_module +class POT(SeqDataset): + """`POT <http://www.dabi.temple.edu/~hbling/data/POT-210/planar_benchmark.html>`_ Dataset. + + Publication: + ``Planar Object Tracking in the Wild: A Benchmark``, + P. Liang, Y. Wu, H. Lu, L. Wang, C. Liao, and H. Ling, ICRA 2018. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + """ + def __init__(self, root_dir=None): + if root_dir is None: + root_dir = osp.expanduser('~/data/POT') + self.root_dir = root_dir + + # initialize the dataset + super(POT, self).__init__( + name='POT', + root_dir=root_dir) + + def _construct_seq_dict(self, root_dir): + # image and annotation paths + seq_dirs = sorted(glob.glob( + osp.join(root_dir, '*/*_*/'))) + seq_dirs = [d[:-1] for d in seq_dirs] + seq_names = [osp.basename(d) for d in seq_dirs] + anno_files = [osp.join( + root_dir, 'annotation/annotation/{}_gt_points.txt'.format(n)) + for n in seq_names] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 50 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + anno = np.loadtxt(anno_files[s]) + + n = min(len(img_files), len(anno)) + assert n > 0 + img_files = img_files[:n] + anno = anno[:n] + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/structure.py b/utils/neuron/data/datasets/structure.py new file mode 100755 index 0000000..e93f204 --- /dev/null +++ b/utils/neuron/data/datasets/structure.py @@ -0,0 +1,420 @@ +import numpy as np +from torch.utils.data import Dataset + +from .dataset import PairDataset, InstanceDataset +from neuron.config import registry +from neuron import ops +from collections import OrderedDict + + +__all__ = ['Seq2Pair', 'Image2Pair', 'Seq2Instance', 'Subset', 'Slice', + 'RandomConcat'] + + +@registry.register_module +class Seq2Pair(PairDataset): + + def __init__(self, seqs, transforms=None, + pairs_per_seq=10, max_distance=300): + super(Seq2Pair, self).__init__( + name='{}_pairs'.format(seqs.name)) + self.seqs = seqs + self.transforms = transforms + self.pairs_per_seq = pairs_per_seq + self.max_distance = max_distance + # group sequences by aspect ratios (for sampling) + self.group_flags = self._build_group_flags(seqs, pairs_per_seq) + + def __getitem__(self, index): + if index > len(self): + raise IndexError('Index out of range') + index %= len(self.seqs) + + # get image files and annotations + img_files, target = self.seqs[index] + anno, meta = target['anno'], target['meta'] + # filter noisy annotations + valid_indices = self._filter(anno, meta) + if len(valid_indices) < 2: + return self._random_next() + + # ramdomly sample a pair + rand_z, rand_x = self._sample_pair(anno, valid_indices) + if rand_z < 0 or rand_x < 0: + return self._random_next() + + # annotations pair + if anno.shape[1] in [4, 8]: + # SOT-based pairs + bboxes_z = np.expand_dims(anno[rand_z], axis=0) + bboxes_x = np.expand_dims(anno[rand_x], axis=0) + elif anno.shape[1] == 9: + # MOT/VID-based pairs + # find consistent track_ids + mask_z = (anno[:, 0] == rand_z) + mask_x = (anno[:, 0] == rand_x) + z_ids, x_ids = anno[mask_z, 1], anno[mask_x, 1] + join_ids = sorted(set(z_ids) & set(x_ids)) + + # extract bounding boxes (ignore the class label) + bboxes_z, bboxes_x = [], [] + for track_id in join_ids: + mask_id = (anno[:, 1] == track_id) + mask_id_z = (mask_z & mask_id) + mask_id_x = (mask_x & mask_id) + if mask_id_z.sum() != 1 or mask_id_x.sum() != 1: + ops.sys_print('Warning: found repeated ID for', + self.seqs.seq_names[index]) + return self._random_next() + bboxes_z += [anno[mask_id_z, 2:6]] + bboxes_x += [anno[mask_id_x, 2:6]] + bboxes_z = np.concatenate(bboxes_z, axis=0) + bboxes_x = np.concatenate(bboxes_x, axis=0) + assert len(bboxes_z) == len(bboxes_x) == len(join_ids) + + # image pair + img_z = ops.read_image(img_files[rand_z]) + img_x = ops.read_image(img_files[rand_x]) + + # bound annotations by image boundaries + h, w = img_z.shape[:2] + bboxes_z = ops.bound_bboxes(bboxes_z, [w, h]) + bboxes_x = ops.bound_bboxes(bboxes_x, [w, h]) + + # build target + target = { + 'bboxes_z': bboxes_z, + 'bboxes_x': bboxes_x} + + # apply transforms if applicable + if self.transforms is not None: + return self.transforms(img_z, img_x, target) + else: + return img_z, img_x, target + + def __len__(self): + return len(self.seqs) * self.pairs_per_seq + + def _sample_pair(self, anno, indices): + ndims = anno.shape[1] + n = len(indices) + assert ndims in [4, 8, 9] + assert n > 0 + + if ndims in [4, 8]: + if n == 1: + return indices[0], indices[0] + elif n == 2: + return indices[0], indices[1] + else: + for _ in range(100): + rand_z, rand_x = sorted( + np.random.choice(indices, 2, replace=False)) + if rand_x - rand_z <= self.max_distance: + break + else: + rand_z, rand_x = np.random.choice(indices, 2) + elif ndims == 9: + anno = anno[indices] + track_ids, counts = np.unique(anno[:, 1], return_counts=True) + if np.all(counts < 2): + return -1, -1 + track_id = np.random.choice(track_ids[counts >= 2]) + frames = np.unique(anno[anno[:, 1] == track_id, 0]).astype(np.int64) + rand_z, rand_x = np.random.choice(frames, 2) + + return rand_z, rand_x + + def _filter(self, anno, meta): + ndims = anno.shape[1] + assert ndims in [4, 8, 9] + + if ndims == 8: + return np.arange(len(anno)) + elif ndims == 4: + bboxes = anno.copy() + elif ndims == 9: + bboxes = anno[:, 2:6].copy() + bboxes[:, 2:] = bboxes[:, 2:] - bboxes[:, :2] + 1 + size = np.array([[ + meta['width'], meta['height']]], dtype=np.float32) + areas = bboxes[:, 2] * bboxes[:, 3] + + # conditions + conditions = [ + areas > 20, + np.all(bboxes[:, 2:] >= 10, axis=1), + np.all(bboxes[:, 2:] <= 960, axis=1), + np.all((bboxes[:, 2:] / size) >= 0.01, axis=1), + np.all((bboxes[:, 2:] / size) <= 0.75, axis=1), + bboxes[:, 2] / np.maximum(1, bboxes[:, 3]) >= 0.2, + bboxes[:, 2] / np.maximum(1, bboxes[:, 3]) < 5] + if ndims == 9: + conditions.append(anno[:, 8] <= 0.5) + if 'cover' in meta: + cover = meta['cover'] + conditions.append( + cover > max(1., cover.max() * 0.3)) + + mask = np.logical_and.reduce(conditions) + indices = np.where(mask)[0] + + return indices + + def _random_next(self): + index = np.random.choice(len(self)) + return self.__getitem__(index) + + def _build_group_flags(self, seqs, pairs_per_seq): + flags = np.zeros(len(seqs), dtype=np.uint8) + for i, (_, target) in enumerate(seqs): + meta = target['meta'] + if meta['width'] / meta['height'] > 1: + flags[i] = 1 + flags = np.tile(flags, pairs_per_seq) + assert len(flags) == len(self) + return flags + + +@registry.register_module +class Image2Pair(PairDataset): + + def __init__(self, imgs, transforms=None): + super(Image2Pair, self).__init__( + name='{}_pairs'.format(imgs.name)) + self.imgs = imgs + self.transforms = transforms + # group images by aspect ratios (for sampling) + self.group_flags = self._build_group_flags(imgs) + + def __getitem__(self, index): + img, target = self.imgs[index] + bboxes = target['bboxes'] + if len(bboxes) == 0: + return self._random_next() + + img_z, bboxes_z = img, bboxes + img_x, bboxes_x = img.copy(), bboxes.copy() + + # bound annotations by image boundaries + h, w = img_z.shape[:2] + bboxes_z = ops.bound_bboxes(bboxes_z, [w, h]) + bboxes_x = ops.bound_bboxes(bboxes_x, [w, h]) + + # build target + target = { + 'bboxes_z': bboxes_z, + 'bboxes_x': bboxes_x} + + # apply transforms if applicable + if self.transforms is not None: + return self.transforms(img_z, img_x, target) + else: + return img_z, img_x, target + + def __len__(self): + return len(self.imgs) + + def _random_next(self): + index = np.random.choice(len(self)) + return self.__getitem__(index) + + def _build_group_flags(self, imgs): + flags = np.zeros(len(imgs), dtype=np.uint8) + for i, name in enumerate(imgs.img_names): + meta = imgs.img_dict[name]['target']['meta'] + if meta['width'] / meta['height'] > 1: + flags[i] = 1 + assert len(flags) == len(self) + return flags + + +@registry.register_module +class Seq2Instance(InstanceDataset): + + def __init__(self, seqs, transforms=None, sampling_stride=1): + assert sampling_stride > 0 + super(Seq2Instance, self).__init__( + name='{}_instances'.format(seqs.name), + seqs=seqs, + sampling_stride=sampling_stride) + self.seqs = seqs + self.transforms = transforms + self.sampling_stride = sampling_stride + + # group sequences by aspect ratios (for sampling) + self.group_flags = self._build_group_flags( + self.ins_names, self.ins_dict) + + def _construct_ins_dict(self, seqs, sampling_stride): + # construct ins_dict + ins_dict = OrderedDict() + for s, (img_files, target) in enumerate(seqs): + seq_name = seqs.seq_names[s] + if s % 100 == 0 or (s + 1) == len(seqs): + ops.sys_print('Processing [%d/%d]: %s...' % ( + s + 1, len(seqs), seq_name)) + + # filter out invalid frames + anno, meta = target['anno'], target['meta'] + mask = self._filter(anno, meta) + anno = anno[mask] + + for f, img_file in enumerate(img_files): + if f % sampling_stride != 0: + continue + bbox = target['anno'][f] + ins_id, cam_id = s + 1, 1 + meta_info = { + 'width': meta['width'], + 'height': meta['height']} + + # updat ins_dict + name = '{}-{}_{}'.format(ins_id, cam_id, f + 1) + ins_dict[name] = { + 'img_file': img_file, + 'target': { + 'bbox': bbox, + 'ins_id': ins_id, + 'cam_id': cam_id, + 'frame_id': f + 1, + 'meta': meta_info}} + + return ins_dict + + def _filter(self, anno, meta): + img_size = np.array( + [[meta['width'], meta['height']]], dtype=np.float32) + sizes = anno[:, 2:] - anno[:, :2] + 1 + areas = sizes.prod(axis=1) + + # conditions + conditions = [ + areas > 20, + np.all(sizes >= 10, axis=1), + np.all(sizes <= 960, axis=1), + np.all(sizes / img_size >= 0.01, axis=1), + np.all(sizes / img_size <= 0.75, axis=1), + sizes[:, 0] / np.maximum(1, sizes[:, 1]) >= 0.2, + sizes[:, 0] / np.maximum(1, sizes[:, 1]) < 5] + if 'cover' in meta: + cover = meta['cover'] + conditions.append( + cover > max(1., cover.max() * 0.3)) + + return np.logical_and.reduce(conditions, axis=0) + + def _build_group_flags(self, ins_names, ins_dict): + flags = np.zeros(len(ins_names), dtype=np.uint8) + for i, name in enumerate(ins_names): + ins_info = ins_dict[name] + meta = ins_info['target']['meta'] + if meta['width'] / meta['height'] > 1: + flags[i] = 1 + assert len(flags) == len(self) + return flags + + +@registry.register_module +class Subset(Dataset): + + def __init__(self, dataset, indices): + self.dataset = dataset + self.indices = indices + self.name = '{}_subset'.format(dataset.name) + + def __getitem__(self, index): + return self.dataset[self.indices[index]] + + def __len__(self): + return len(self.indices) + + def __getattr__(self, name): + try: + return object.__getattribute__(self, name) + except AttributeError: + return object.__getattribute__(self.dataset, name) + + +@registry.register_module +class Slice(Dataset): + + def __init__(self, dataset, start=None, stop=None, step=None): + self.dataset = dataset + self.indices = np.arange(start, stop, step) + self.name = '{}_slice_{}_{}_{}'.format( + self.dataset.name, + start or 0, + stop or len(self.dataset), + step or 1) + + def __getitem__(self, index): + return self.dataset[self.indices[index]] + + def __len__(self): + return len(self.indices) + + def __getattr__(self, name): + try: + return object.__getattribute__(self, name) + except AttributeError: + return object.__getattribute__(self.dataset, name) + + +@registry.register_module +class RandomConcat(Dataset): + + def __init__(self, datasets, sampling_prob=None, max_size=None): + names = [u.name for u in datasets] + self.name = 'RandomConcat_' + '_'.join(names) + self.datasets = datasets + if sampling_prob is None: + sampling_prob = np.ones(len(datasets), dtype=np.float32) + sampling_prob /= sampling_prob.sum() + assert len(sampling_prob) == len(datasets) + assert (sum(sampling_prob) - 1) < 1e-6 + self.sampling_prob = np.array(sampling_prob, dtype=np.float32) + self.max_size = max_size + self.group_flags = self._concat_group_flags( + self.datasets, self.sampling_prob) + + def __getitem__(self, index): + d_index = np.random.choice( + len(self.datasets), p=self.sampling_prob) + dataset = self.datasets[d_index] + + # ensure to select the item with correct flag + flag = self.group_flags[index] + indices = np.where(dataset.group_flags == flag)[0] + if len(indices) == 0: + return self._random_next() + index = indices[index % len(indices)] + + return dataset[index] + + def __len__(self): + return len(self.group_flags) + + def _concat_group_flags(self, datasets, sampling_prob): + bin_counts = np.array([np.bincount(d.group_flags, minlength=2) + for d in datasets], dtype=np.float32) + prob = np.sum(bin_counts[:, 1] * \ + sampling_prob / bin_counts.sum(axis=1)) + + # expected dataset length + size = int(sum([len(d) * p for d, p in zip( + datasets, sampling_prob)])) + if self.max_size is not None: + size = max(self.max_size, int(size)) + + # generate flags according to prob + flags = np.zeros(size, dtype=np.uint8) + indices = np.random.choice( + size, int(size * prob), replace=False) + flags[indices] = 1 + + return flags + + def _random_next(self): + index = np.random.choice(len(self)) + return self.__getitem__(index) diff --git a/utils/neuron/data/datasets/tcolor128.py b/utils/neuron/data/datasets/tcolor128.py new file mode 100755 index 0000000..1e1cc4f --- /dev/null +++ b/utils/neuron/data/datasets/tcolor128.py @@ -0,0 +1,96 @@ +import os +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['TColor128'] + + +@registry.register_module +class TColor128(SeqDataset): + """`TColor128 <http://www.dabi.temple.edu/~hbling/data/TColor-128/TColor-128.html>`_ Dataset. + + Publication: + ``Encoding color information for visual tracking: algorithms and benchmark``, + P. Liang, E. Blasch and H. Ling, TIP, 2015. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + """ + def __init__(self, root_dir=None, download=True): + if root_dir is None: + root_dir = osp.expanduser('~/data/Temple-color-128') + self.root_dir = root_dir + if download: + self._download(root_dir) + + # initialize the dataset + super(TColor128, self).__init__( + name='TColor-128', + root_dir=root_dir) + + def _construct_seq_dict(self, root_dir): + # image and annotation paths + anno_files = sorted(glob.glob( + osp.join(root_dir, '*/*_gt.txt'))) + seq_dirs = [osp.dirname(f) for f in anno_files] + seq_names = [osp.basename(d) for d in seq_dirs] + # valid frame range for each sequence + range_files = [glob.glob( + osp.join(d, '*_frames.txt'))[0] + for d in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + # load valid frame range + frames = np.loadtxt( + range_files[s], dtype=int, delimiter=',') + img_files = [osp.join( + seq_dirs[s], 'img/%04d.jpg' % f) + for f in range(frames[0], frames[1] + 1)] + + # load annotations + anno = np.loadtxt(anno_files[s], delimiter=',') + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + def _download(self, root_dir): + if not osp.isdir(root_dir): + os.makedirs(root_dir) + elif len(os.listdir(root_dir)) > 100: + ops.sys_print('Files already downloaded.') + return + + url = 'http://www.dabi.temple.edu/~hbling/data/TColor-128/Temple-color-128.zip' + zip_file = osp.join(root_dir, 'Temple-color-128.zip') + ops.sys_print('Downloading to %s...' % zip_file) + ops.download(url, zip_file) + ops.sys_print('\nExtracting to %s...' % root_dir) + ops.extract(zip_file, root_dir) + + return root_dir diff --git a/utils/neuron/data/datasets/tlp.py b/utils/neuron/data/datasets/tlp.py new file mode 100755 index 0000000..75cfd19 --- /dev/null +++ b/utils/neuron/data/datasets/tlp.py @@ -0,0 +1,72 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset +from local_path import tlp_dir + +__all__ = ['TLP'] + + +@registry.register_module +class TLP(SeqDataset): + """`TLP <https://amoudgl.github.io/tlp/>`_ Dataset. + + Publication: + ``Long-term Visual Object Tracking Benchmark``, + Moudgil Abhinav and Gandhi Vineet, ACCV 2018. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + """ + def __init__(self, root_dir=None): + if root_dir is None: + root_dir = osp.expanduser(tlp_dir) + self.root_dir = root_dir + + # initialize the dataset + super(TLP, self).__init__( + name='TLP', + root_dir=self.root_dir) + + def _construct_seq_dict(self, root_dir): + # image and annotation paths + anno_files = sorted(glob.glob( + osp.join(root_dir, '*/groundtruth_rect.txt'))) + seq_dirs = [osp.dirname(f) for f in anno_files] + seq_names = [osp.basename(d) for d in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], 'img/*.jpg'))) + anno = np.loadtxt(anno_files[s], delimiter=',') + + # parse annotations + frames, bboxes, losts = anno[:, 0], anno[:, 1:5], anno[:, 5] + assert np.all(frames == np.arange(len(frames)) + 1) + bboxes[:, 2:] = bboxes[:, :2] + bboxes[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len, + 'absence': losts} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': bboxes, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/trackingnet.py b/utils/neuron/data/datasets/trackingnet.py new file mode 100755 index 0000000..3959ea9 --- /dev/null +++ b/utils/neuron/data/datasets/trackingnet.py @@ -0,0 +1,88 @@ +import os.path as osp +import glob +import numpy as np + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['TrackingNet'] + + +@registry.register_module +class TrackingNet(SeqDataset): + r"""`TrackingNet <https://tracking-net.org/>`_ Datasets. + + Publication: + ``TrackingNet: A Large-Scale Dataset and Benchmark for Object Tracking in the Wild.``, + M. Muller, A. Bibi, S. Giancola, S. Al-Subaihi and B. Ghanem, ECCV 2018. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + subset (string, optional): Specify ``train`` or ``test`` + subset of TrackingNet. + """ + def __init__(self, root_dir=None, subset='test'): + assert subset in ['train', 'test'], 'Unknown subset.' + if root_dir is None: + root_dir = osp.expanduser('~/data/TrackingNet') + self.root_dir = root_dir + self.subset = subset + if subset == 'test': + subset_dirs = ['TEST'] + elif subset == 'train': + subset_dirs = ['TRAIN_%d' % c for c in range(12)] + + # initialize the dataset + super(TrackingNet, self).__init__( + name='TrackingNet_{}'.format(self.subset), + root_dir=self.root_dir, + subset_dirs=subset_dirs) + + def _construct_seq_dict(self, root_dir, subset_dirs): + # image and annotation paths + anno_files = [glob.glob(osp.join( + root_dir, c, 'anno/*.txt')) for c in subset_dirs] + anno_files = sorted(sum(anno_files, [])) + seq_dirs = [osp.join( + osp.dirname(osp.dirname(f)), + 'frames', osp.basename(f)[:-4]) + for f in anno_files] + seq_names = [osp.basename(d) for d in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 100 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing sequence [%d/%d]: %s...' % ( + s + 1, len(seq_names), seq_name)) + img_files = glob.glob( + osp.join(seq_dirs[s], '*.jpg')) + img_files = sorted( + img_files, + key=lambda f: int(osp.basename(f)[:-4])) + anno = np.loadtxt(anno_files[s], delimiter=',') + if anno.ndim == 1: + anno = np.expand_dims(anno, axis=0) + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/uav123.json b/utils/neuron/data/datasets/uav123.json new file mode 100755 index 0000000..0b1075b --- /dev/null +++ b/utils/neuron/data/datasets/uav123.json @@ -0,0 +1,721 @@ +{ + "UAV123": { + "bike1": { + "start_frame": 1, + "end_frame": 3085, + "folder_name": "bike1" + }, + "bike2": { + "start_frame": 1, + "end_frame": 553, + "folder_name": "bike2" + }, + "bike3": { + "start_frame": 1, + "end_frame": 433, + "folder_name": "bike3" + }, + "bird1_1": { + "start_frame": 1, + "end_frame": 253, + "folder_name": "bird1" + }, + "bird1_2": { + "start_frame": 775, + "end_frame": 1477, + "folder_name": "bird1" + }, + "bird1_3": { + "start_frame": 1573, + "end_frame": 2437, + "folder_name": "bird1" + }, + "boat1": { + "start_frame": 1, + "end_frame": 901, + "folder_name": "boat1" + }, + "boat2": { + "start_frame": 1, + "end_frame": 799, + "folder_name": "boat2" + }, + "boat3": { + "start_frame": 1, + "end_frame": 901, + "folder_name": "boat3" + }, + "boat4": { + "start_frame": 1, + "end_frame": 553, + "folder_name": "boat4" + }, + "boat5": { + "start_frame": 1, + "end_frame": 505, + "folder_name": "boat5" + }, + "boat6": { + "start_frame": 1, + "end_frame": 805, + "folder_name": "boat6" + }, + "boat7": { + "start_frame": 1, + "end_frame": 535, + "folder_name": "boat7" + }, + "boat8": { + "start_frame": 1, + "end_frame": 685, + "folder_name": "boat8" + }, + "boat9": { + "start_frame": 1, + "end_frame": 1399, + "folder_name": "boat9" + }, + "building1": { + "start_frame": 1, + "end_frame": 469, + "folder_name": "building1" + }, + "building2": { + "start_frame": 1, + "end_frame": 577, + "folder_name": "building2" + }, + "building3": { + "start_frame": 1, + "end_frame": 829, + "folder_name": "building3" + }, + "building4": { + "start_frame": 1, + "end_frame": 787, + "folder_name": "building4" + }, + "building5": { + "start_frame": 1, + "end_frame": 481, + "folder_name": "building5" + }, + "car1_1": { + "start_frame": 1, + "end_frame": 751, + "folder_name": "car1" + }, + "car1_2": { + "start_frame": 751, + "end_frame": 1627, + "folder_name": "car1" + }, + "car1_3": { + "start_frame": 1627, + "end_frame": 2629, + "folder_name": "car1" + }, + "car2": { + "start_frame": 1, + "end_frame": 1321, + "folder_name": "car2" + }, + "car3": { + "start_frame": 1, + "end_frame": 1717, + "folder_name": "car3" + }, + "car4": { + "start_frame": 1, + "end_frame": 1345, + "folder_name": "car4" + }, + "car5": { + "start_frame": 1, + "end_frame": 745, + "folder_name": "car5" + }, + "car6_1": { + "start_frame": 1, + "end_frame": 487, + "folder_name": "car6" + }, + "car6_2": { + "start_frame": 487, + "end_frame": 1807, + "folder_name": "car6" + }, + "car6_3": { + "start_frame": 1807, + "end_frame": 2953, + "folder_name": "car6" + }, + "car6_4": { + "start_frame": 2953, + "end_frame": 3925, + "folder_name": "car6" + }, + "car6_5": { + "start_frame": 3925, + "end_frame": 4861, + "folder_name": "car6" + }, + "car7": { + "start_frame": 1, + "end_frame": 1033, + "folder_name": "car7" + }, + "car8_1": { + "start_frame": 1, + "end_frame": 1357, + "folder_name": "car8" + }, + "car8_2": { + "start_frame": 1357, + "end_frame": 2575, + "folder_name": "car8" + }, + "car9": { + "start_frame": 1, + "end_frame": 1879, + "folder_name": "car9" + }, + "car10": { + "start_frame": 1, + "end_frame": 1405, + "folder_name": "car10" + }, + "car11": { + "start_frame": 1, + "end_frame": 337, + "folder_name": "car11" + }, + "car12": { + "start_frame": 1, + "end_frame": 499, + "folder_name": "car12" + }, + "car13": { + "start_frame": 1, + "end_frame": 415, + "folder_name": "car13" + }, + "car14": { + "start_frame": 1, + "end_frame": 1327, + "folder_name": "car14" + }, + "car15": { + "start_frame": 1, + "end_frame": 469, + "folder_name": "car15" + }, + "car16_1": { + "start_frame": 1, + "end_frame": 415, + "folder_name": "car16" + }, + "car16_2": { + "start_frame": 415, + "end_frame": 1993, + "folder_name": "car16" + }, + "car17": { + "start_frame": 1, + "end_frame": 1057, + "folder_name": "car17" + }, + "car18": { + "start_frame": 1, + "end_frame": 1207, + "folder_name": "car18" + }, + "group1_1": { + "start_frame": 1, + "end_frame": 1333, + "folder_name": "group1" + }, + "group1_2": { + "start_frame": 1333, + "end_frame": 2515, + "folder_name": "group1" + }, + "group1_3": { + "start_frame": 2515, + "end_frame": 3925, + "folder_name": "group1" + }, + "group1_4": { + "start_frame": 3925, + "end_frame": 4873, + "folder_name": "group1" + }, + "group2_1": { + "start_frame": 1, + "end_frame": 907, + "folder_name": "group2" + }, + "group2_2": { + "start_frame": 907, + "end_frame": 1771, + "folder_name": "group2" + }, + "group2_3": { + "start_frame": 1771, + "end_frame": 2683, + "folder_name": "group2" + }, + "group3_1": { + "start_frame": 1, + "end_frame": 1567, + "folder_name": "group3" + }, + "group3_2": { + "start_frame": 1567, + "end_frame": 2827, + "folder_name": "group3" + }, + "group3_3": { + "start_frame": 2827, + "end_frame": 4369, + "folder_name": "group3" + }, + "group3_4": { + "start_frame": 4369, + "end_frame": 5527, + "folder_name": "group3" + }, + "person1": { + "start_frame": 1, + "end_frame": 799, + "folder_name": "person1" + }, + "person2_1": { + "start_frame": 1, + "end_frame": 1189, + "folder_name": "person2" + }, + "person2_2": { + "start_frame": 1189, + "end_frame": 2623, + "folder_name": "person2" + }, + "person3": { + "start_frame": 1, + "end_frame": 643, + "folder_name": "person3" + }, + "person4_1": { + "start_frame": 1, + "end_frame": 1501, + "folder_name": "person4" + }, + "person4_2": { + "start_frame": 1501, + "end_frame": 2743, + "folder_name": "person4" + }, + "person5_1": { + "start_frame": 1, + "end_frame": 877, + "folder_name": "person5" + }, + "person5_2": { + "start_frame": 877, + "end_frame": 2101, + "folder_name": "person5" + }, + "person6": { + "start_frame": 1, + "end_frame": 901, + "folder_name": "person6" + }, + "person7_1": { + "start_frame": 1, + "end_frame": 1249, + "folder_name": "person7" + }, + "person7_2": { + "start_frame": 1249, + "end_frame": 2065, + "folder_name": "person7" + }, + "person8_1": { + "start_frame": 1, + "end_frame": 1075, + "folder_name": "person8" + }, + "person8_2": { + "start_frame": 1075, + "end_frame": 1525, + "folder_name": "person8" + }, + "person9": { + "start_frame": 1, + "end_frame": 661, + "folder_name": "person9" + }, + "person10": { + "start_frame": 1, + "end_frame": 1021, + "folder_name": "person10" + }, + "person11": { + "start_frame": 1, + "end_frame": 721, + "folder_name": "person11" + }, + "person12_1": { + "start_frame": 1, + "end_frame": 601, + "folder_name": "person12" + }, + "person12_2": { + "start_frame": 601, + "end_frame": 1621, + "folder_name": "person12" + }, + "person13": { + "start_frame": 1, + "end_frame": 883, + "folder_name": "person13" + }, + "person14_1": { + "start_frame": 1, + "end_frame": 847, + "folder_name": "person14" + }, + "person14_2": { + "start_frame": 847, + "end_frame": 1813, + "folder_name": "person14" + }, + "person14_3": { + "start_frame": 1813, + "end_frame": 2923, + "folder_name": "person14" + }, + "person15": { + "start_frame": 1, + "end_frame": 1339, + "folder_name": "person15" + }, + "person16": { + "start_frame": 1, + "end_frame": 1147, + "folder_name": "person16" + }, + "person17_1": { + "start_frame": 1, + "end_frame": 1501, + "folder_name": "person17" + }, + "person17_2": { + "start_frame": 1501, + "end_frame": 2347, + "folder_name": "person17" + }, + "person18": { + "start_frame": 1, + "end_frame": 1393, + "folder_name": "person18" + }, + "person19_1": { + "start_frame": 1, + "end_frame": 1243, + "folder_name": "person19" + }, + "person19_2": { + "start_frame": 1243, + "end_frame": 2791, + "folder_name": "person19" + }, + "person19_3": { + "start_frame": 2791, + "end_frame": 4357, + "folder_name": "person19" + }, + "person20": { + "start_frame": 1, + "end_frame": 1783, + "folder_name": "person20" + }, + "person21": { + "start_frame": 1, + "end_frame": 487, + "folder_name": "person21" + }, + "person22": { + "start_frame": 1, + "end_frame": 199, + "folder_name": "person22" + }, + "person23": { + "start_frame": 1, + "end_frame": 397, + "folder_name": "person23" + }, + "truck1": { + "start_frame": 1, + "end_frame": 463, + "folder_name": "truck1" + }, + "truck2": { + "start_frame": 1, + "end_frame": 385, + "folder_name": "truck2" + }, + "truck3": { + "start_frame": 1, + "end_frame": 535, + "folder_name": "truck3" + }, + "truck4_1": { + "start_frame": 1, + "end_frame": 577, + "folder_name": "truck4" + }, + "truck4_2": { + "start_frame": 577, + "end_frame": 1261, + "folder_name": "truck4" + }, + "uav1_1": { + "start_frame": 1, + "end_frame": 1555, + "folder_name": "uav1" + }, + "uav1_2": { + "start_frame": 1555, + "end_frame": 2377, + "folder_name": "uav1" + }, + "uav1_3": { + "start_frame": 2473, + "end_frame": 3469, + "folder_name": "uav1" + }, + "uav2": { + "start_frame": 1, + "end_frame": 133, + "folder_name": "uav2" + }, + "uav3": { + "start_frame": 1, + "end_frame": 265, + "folder_name": "uav3" + }, + "uav4": { + "start_frame": 1, + "end_frame": 157, + "folder_name": "uav4" + }, + "uav5": { + "start_frame": 1, + "end_frame": 139, + "folder_name": "uav5" + }, + "uav6": { + "start_frame": 1, + "end_frame": 109, + "folder_name": "uav6" + }, + "uav7": { + "start_frame": 1, + "end_frame": 373, + "folder_name": "uav7" + }, + "uav8": { + "start_frame": 1, + "end_frame": 301, + "folder_name": "uav8" + }, + "wakeboard1": { + "start_frame": 1, + "end_frame": 421, + "folder_name": "wakeboard1" + }, + "wakeboard2": { + "start_frame": 1, + "end_frame": 733, + "folder_name": "wakeboard2" + }, + "wakeboard3": { + "start_frame": 1, + "end_frame": 823, + "folder_name": "wakeboard3" + }, + "wakeboard4": { + "start_frame": 1, + "end_frame": 697, + "folder_name": "wakeboard4" + }, + "wakeboard5": { + "start_frame": 1, + "end_frame": 1675, + "folder_name": "wakeboard5" + }, + "wakeboard6": { + "start_frame": 1, + "end_frame": 1165, + "folder_name": "wakeboard6" + }, + "wakeboard7": { + "start_frame": 1, + "end_frame": 199, + "folder_name": "wakeboard7" + }, + "wakeboard8": { + "start_frame": 1, + "end_frame": 1543, + "folder_name": "wakeboard8" + }, + "wakeboard9": { + "start_frame": 1, + "end_frame": 355, + "folder_name": "wakeboard9" + }, + "wakeboard10": { + "start_frame": 1, + "end_frame": 469, + "folder_name": "wakeboard10" + }, + "car1_s": { + "start_frame": 1, + "end_frame": 1475, + "folder_name": "car1_s" + }, + "car2_s": { + "start_frame": 1, + "end_frame": 320, + "folder_name": "car2_s" + }, + "car3_s": { + "start_frame": 1, + "end_frame": 1300, + "folder_name": "car3_s" + }, + "car4_s": { + "start_frame": 1, + "end_frame": 830, + "folder_name": "car4_s" + }, + "person1_s": { + "start_frame": 1, + "end_frame": 1600, + "folder_name": "person1_s" + }, + "person2_s": { + "start_frame": 1, + "end_frame": 250, + "folder_name": "person2_s" + }, + "person3_s": { + "start_frame": 1, + "end_frame": 505, + "folder_name": "person3_s" + } + }, + "UAV20L": { + "bike1": { + "start_frame": 1, + "end_frame": 3085, + "folder_name": "bike1" + }, + "bird1": { + "start_frame": 1, + "end_frame": 2437, + "folder_name": "bird1" + }, + "car1": { + "start_frame": 1, + "end_frame": 2629, + "folder_name": "car1" + }, + "car3": { + "start_frame": 1, + "end_frame": 1717, + "folder_name": "car3" + }, + "car6": { + "start_frame": 1, + "end_frame": 4861, + "folder_name": "car6" + }, + "car8": { + "start_frame": 1, + "end_frame": 2575, + "folder_name": "car8" + }, + "car9": { + "start_frame": 1, + "end_frame": 1879, + "folder_name": "car9" + }, + "car16": { + "start_frame": 1, + "end_frame": 1993, + "folder_name": "car16" + }, + "group1": { + "start_frame": 1, + "end_frame": 4873, + "folder_name": "group1" + }, + "group2": { + "start_frame": 1, + "end_frame": 2683, + "folder_name": "group2" + }, + "group3": { + "start_frame": 1, + "end_frame": 5527, + "folder_name": "group3" + }, + "person2": { + "start_frame": 1, + "end_frame": 2623, + "folder_name": "person2" + }, + "person4": { + "start_frame": 1, + "end_frame": 2743, + "folder_name": "person4" + }, + "person5": { + "start_frame": 1, + "end_frame": 2101, + "folder_name": "person5" + }, + "person7": { + "start_frame": 1, + "end_frame": 2065, + "folder_name": "person7" + }, + "person14": { + "start_frame": 1, + "end_frame": 2923, + "folder_name": "person14" + }, + "person17": { + "start_frame": 1, + "end_frame": 2347, + "folder_name": "person17" + }, + "person19": { + "start_frame": 1, + "end_frame": 4357, + "folder_name": "person19" + }, + "person20": { + "start_frame": 1, + "end_frame": 1783, + "folder_name": "person20" + }, + "uav1": { + "start_frame": 1, + "end_frame": 3469, + "folder_name": "uav1" + } + } +} \ No newline at end of file diff --git a/utils/neuron/data/datasets/uav123.py b/utils/neuron/data/datasets/uav123.py new file mode 100755 index 0000000..df72e64 --- /dev/null +++ b/utils/neuron/data/datasets/uav123.py @@ -0,0 +1,91 @@ +import os.path as osp +import glob +import numpy as np +import json + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['UAV123'] + + +@registry.register_module +class UAV123(SeqDataset): + """`UAV123 <https://ivul.kaust.edu.sa/Pages/pub-benchmark-simulator-uav.aspx>`_ Dataset. + + Publication: + ``A Benchmark and Simulator for UAV Tracking``, + M. Mueller, N. Smith and B. Ghanem, ECCV 2016. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + version (integer or string): Specify the benchmark version, specify as one of + ``UAV123`` and ``UAV20L``. + """ + def __init__(self, root_dir=None, version='UAV123'): + assert version.upper() in ['UAV20L', 'UAV123'] + if root_dir is None: + root_dir = osp.expanduser('~/data/UAV123') + self.root_dir = root_dir + self.version = version.upper() + + # initialize the dataset + super(UAV123, self).__init__( + name=self.version, + root_dir=self.root_dir, + version=self.version) + + def _construct_seq_dict(self, root_dir, version): + # sequence meta information + meta_file = osp.join( + osp.dirname(__file__), 'uav123.json') + with open(meta_file) as f: + seq_metas = json.load(f) + + # image and annotation paths + anno_files = sorted(glob.glob( + osp.join(root_dir, 'anno/%s/*.txt' % version))) + seq_names = [ + osp.basename(f)[:-4] for f in anno_files] + seq_dirs = [osp.join( + root_dir, 'data_seq/UAV123/%s' % \ + seq_metas[version][n]['folder_name']) + for n in seq_names] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + # valid frame range + start_frame = seq_metas[version][ + seq_names[s]]['start_frame'] + end_frame = seq_metas[version][ + seq_names[s]]['end_frame'] + img_files = [osp.join( + seq_dirs[s], '%06d.jpg' % f) + for f in range(start_frame, end_frame + 1)] + + # load annotations + anno = np.loadtxt(anno_files[s], delimiter=',') + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict diff --git a/utils/neuron/data/datasets/visdrone.py b/utils/neuron/data/datasets/visdrone.py new file mode 100755 index 0000000..cffc39b --- /dev/null +++ b/utils/neuron/data/datasets/visdrone.py @@ -0,0 +1,215 @@ +import os.path as osp +import glob +import numpy as np +from collections import OrderedDict + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['VisDroneSOT', 'VisDroneVID'] + + +@registry.register_module +class VisDroneSOT(SeqDataset): + """`VisDrone <http://www.aiskyeye.com/>`_ Dataset. + + Publication: + ``Vision Meets Drones: A Challenge``, + P. Zhu, L. Wen, X. Bian, H. Ling and Q. Hu, arXiv 2018. + + Args: + root_dir (string): Root directory of dataset where subset + folders exist. + subset (string, optional): Specify ``train``, ``val`` or ``test`` + subset of VisDrone dataset. + """ + def __init__(self, root_dir=None, subset='val'): + assert subset in ['train', 'val', 'test'] + if root_dir is None: + root_dir = osp.expanduser('~/data/VisDrone') + if subset == 'train': + root_dir = osp.join(root_dir, 'VisDrone2018-SOT-train') + elif subset == 'val': + root_dir = osp.join(root_dir, 'VisDrone2018-SOT-val') + elif subset == 'test': + root_dir = osp.join(root_dir, 'VisDrone2019-SOT-test-challenge') + self.root_dir = root_dir + self.subset = subset + + # initialize the dataset + super(VisDroneSOT, self).__init__( + name='VisDroneSOT_{}'.format(subset), + root_dir=self.root_dir, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, subset): + # image and annotation paths + if subset == 'test': + anno_files = sorted(glob.glob( + osp.join(root_dir, 'initialization/*_s.txt'))) + else: + anno_files = sorted(glob.glob( + osp.join(root_dir, 'annotations/*_s.txt'))) + seq_names = [osp.basename(f)[:-4] for f in anno_files] + seq_dirs = [osp.join( + root_dir, 'sequences/{}'.format(n)) for n in seq_names] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], 'img*.jpg'))) + anno = np.loadtxt(anno_files[s], delimiter=',') + if anno.ndim == 1: + assert anno.size == 4 + anno = anno[np.newaxis, :] + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + +@registry.register_module +class VisDroneVID(SeqDataset): + r"""`VisDrone VID <http://www.aiskyeye.com/>`_ Dataset. + + Publication: + ``Vision Meets Drones: A Challenge``, P. Zhu, L. Wen, X. Bian, H. Ling and Q. Hu, arXiv 2018. + + Args: + root_dir (string): Root directory of dataset where ``sequences`` and + ``annotations`` folders exist. + subset (string, optional): Specify ``train``, ``val`` or (``train``, ``val``) + subset(s) of VisDrone VID. Default is a tuple (``train``, ``val``). + """ + CLASSES = ( + 'ignored regions', # 0 + 'pedestrian', # 1 + 'people', # 2 + 'bicycle', # 3 + 'car', # 4 + 'van', # 5 + 'truck', # 6 + 'tricycle', # 7 + 'awning-tricycle', # 8 + 'bus', # 9 + 'motor', # 10 + 'others') # 11 + + def __init__(self, root_dir=None, subset=['train', 'val']): + # dataset name and paths + if root_dir is None: + root_dir = osp.expanduser('~/data/VisDrone') + if isinstance(subset, str): + assert subset in ['train', 'val'] + subset = [subset] + elif isinstance(subset, (list, tuple)): + assert all([s in ['train', 'val'] for s in subset]) + subset = subset + else: + raise Exception('Unknown subset') + self.root_dir = root_dir + self.subset = subset + self.name = 'VisDroneVID_{}'.format('_'.join(subset)) + + # initialize dataset + super(VisDroneVID, self).__init__( + self.name, + root_dir=self.root_dir, + subset=self.subset) + + def _construct_seq_dict(self, root_dir, subset): + # image and annotation paths + seq_dirs = [] + anno_files = [] + if 'train' in subset: + _seq_dirs = sorted(glob.glob(osp.join( + root_dir, 'VisDrone2018-VID-train/sequences/*_v'))) + _anno_files = [osp.join( + root_dir, 'VisDrone2018-VID-train/annotations', + osp.basename(s) + '.txt') for s in _seq_dirs] + seq_dirs += _seq_dirs + anno_files += _anno_files + if 'val' in subset: + _seq_dirs = sorted(glob.glob(osp.join( + root_dir, 'VisDrone2018-VID-val/sequences/*_v'))) + _anno_files = [osp.join( + root_dir, 'VisDrone2018-VID-val/annotations', + osp.basename(s) + '.txt') for s in _seq_dirs] + seq_dirs += _seq_dirs + anno_files += _anno_files + seq_names = [osp.basename(s) for s in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + if s % 10 == 0 or s + 1 == len(seq_names): + ops.sys_print('Processing [%d/%d]: %s' % ( + s + 1, len(seq_names), seq_name)) + + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + anno_s = np.loadtxt( + anno_files[s], delimiter=',', dtype=np.float32) + anno_s = self._format(anno_s) + + # meta information + img0 = ops.read_image(img_files[0]) + meta = { + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': len(img_files), + 'target_num': len(set(anno_s[:, 1])), + 'total_instances': len(anno_s)} + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno_s, + 'meta': meta}} + + return seq_dict + + def _format(self, anno): + r"""Standadize the gt format. + + Input format: + frame_id (1-indexed), target_id, x1, y1, w, h, score/keep, + class_id, truncation, occlusion + + Output format: + frame_id (0-indexed), target_id, x1, y1, x2, y2, keep, + class_id, occlusion + """ + col_indices = [0, 1, 2, 3, 4, 5, 6, 7, 9] + anno = anno[:, col_indices] + + anno[:, 0] -= 1 # convert frame_id to 0-indexed + anno[:, 4:6] = anno[:, 2:4] + anno[:, 4:6] - 1 + anno[:, 8] /= 2. # normalize occlusion to [0, 1] + + # only keep meaningful annotations + # (filter by classes and occlusions) + mask = (anno[:, 7] > 0) & (anno[:, 7] < 11) & (anno[:, 8] < 1) + anno = anno[mask, :] + + return anno diff --git a/utils/neuron/data/datasets/vot.py b/utils/neuron/data/datasets/vot.py new file mode 100755 index 0000000..08ef98c --- /dev/null +++ b/utils/neuron/data/datasets/vot.py @@ -0,0 +1,270 @@ +import os +import os.path as osp +import glob +import numpy as np +import json +import hashlib + +import neuron.ops as ops +from neuron.config import registry +from .dataset import SeqDataset + + +__all__ = ['VOT'] + + +@registry.register_module +class VOT(SeqDataset): + r"""`VOT <http://www.votchallenge.net/>`_ Datasets. + + Publication: + ``The Visual Object Tracking VOT2017 challenge results``, M. Kristan, A. Leonardis + and J. Matas, etc. 2017. + + Args: + root_dir (string): Root directory of dataset where sequence + folders exist. + version (integer, optional): Specify the benchmark version. Specify as + one of 2013~2018. Default is 2017. + anno_type (string, optional): Returned annotation types, chosen as one of + ``rect`` and ``corner``. Default is ``rect``. + download (boolean, optional): If True, downloads the dataset from the internet + and puts it in root directory. If dataset is downloaded, it is not + downloaded again. + list_file (string, optional): If provided, only read sequences + specified by the file. + """ + __valid_versions = [2013, 2014, 2015, 2016, 2017, 2018, 'LT2018', + 2019, 'LT2019', 'RGBD2019', 'RGBT2019'] + + def __init__(self, root_dir=None, version=2019, anno_type='rect', + download=True, list_file=None): + assert version in self.__valid_versions, 'Unsupport VOT version.' + assert anno_type in ['default', 'rect', 'inner_rect'], \ + 'Unknown annotation type.' + if root_dir is None: + root_dir = osp.expanduser('~/data/vot{}'.format(version)) + self.root_dir = root_dir + self.version = version + self.anno_type = anno_type + if download: + self._download(root_dir, version) + if list_file is None: + list_file = osp.join(root_dir, 'list.txt') + + # initialize the dataset + super(VOT, self).__init__( + name='VOT-{}'.format(self.version), + root_dir=self.root_dir, + list_file=list_file) + + def _construct_seq_dict(self, root_dir, list_file): + # image and annotation paths + with open(list_file, 'r') as f: + seq_names = f.read().strip().split('\n') + seq_dirs = [osp.join(root_dir, s) for s in seq_names] + anno_files = [osp.join(s, 'groundtruth.txt') + for s in seq_dirs] + + # construct seq_dict + seq_dict = {} + for s, seq_name in enumerate(seq_names): + img_files = sorted(glob.glob( + osp.join(seq_dirs[s], '*.jpg'))) + anno = np.loadtxt(anno_files[s], delimiter=',') + anno = self._format(anno) + + # meta information + seq_len = len(img_files) + img0 = ops.read_image(img_files[0]) + meta = self._fetch_meta(seq_dirs[s], seq_len) + meta.update({ + 'width': img0.shape[1], + 'height': img0.shape[0], + 'frame_num': seq_len, + 'target_num': 1, + 'total_instances': seq_len}) + + # update seq_dict + seq_dict[seq_name] = { + 'img_files': img_files, + 'target': { + 'anno': anno, + 'meta': meta}} + + return seq_dict + + def _download(self, root_dir, version): + assert version in self.__valid_versions + + if not osp.isdir(root_dir): + os.makedirs(root_dir) + elif osp.isfile(osp.join(root_dir, 'list.txt')): + with open(osp.join(root_dir, 'list.txt')) as f: + seq_names = f.read().strip().split('\n') + if all([osp.isdir(osp.join(root_dir, s)) for s in seq_names]): + ops.sys_print('Files already downloaded.') + return + + url = 'http://data.votchallenge.net/' + if version in range(2013, 2015 + 1): + # main challenge (2013~2015) + homepage = url + 'vot{}/dataset/'.format(version) + elif version in range(2015, 2019 + 1): + # main challenge (2016~2019) + homepage = url + 'vot{}/main/'.format(version) + elif version.startswith('LT'): + # long-term tracking challenge + year = int(version[2:]) + homepage = url + 'vot{}/longterm/'.format(year) + elif version.startswith('RGBD'): + # RGBD tracking challenge + year = int(version[4:]) + homepage = url + 'vot{}/rgbd/'.format(year) + elif version.startswith('RGBT'): + # RGBT tracking challenge + year = int(version[4:]) + url = url + 'vot{}/rgbtir/'.format(year) + homepage = url + 'meta/' + + # download description file + bundle_url = homepage + 'description.json' + bundle_file = osp.join(root_dir, 'description.json') + if not osp.isfile(bundle_file): + ops.sys_print('Downloading description file...') + ops.download(bundle_url, bundle_file) + + # read description file + ops.sys_print('\nParsing description file...') + with open(bundle_file) as f: + bundle = json.load(f) + + # md5 generator + def md5(filename): + hash_md5 = hashlib.md5() + with open(filename, 'rb') as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + + # download all sequences + seq_names = [] + for seq in bundle['sequences']: + seq_name = seq['name'] + seq_names.append(seq_name) + + # download channel (color/depth/ir) files + channels = seq['channels'].keys() + seq_files = [] + for cn in channels: + seq_url = seq['channels'][cn]['url'] + if not seq_url.startswith(('http', 'https')): + seq_url = url + seq_url[seq_url.find('sequence'):] + seq_file = osp.join( + root_dir, + '{}_{}.zip'.format(seq_name, cn)) + if not osp.isfile(seq_file) or \ + md5(seq_file) != seq['channels'][cn]['checksum']: + ops.sys_print('\nDownloading %s...' % seq_name) + ops.download(seq_url, seq_file) + seq_files.append(seq_file) + + # download annotations + anno_url = homepage + '%s.zip' % seq_name + anno_file = osp.join(root_dir, seq_name + '_anno.zip') + if not osp.isfile(anno_file) or \ + md5(anno_file) != seq['annotations']['checksum']: + ops.download(anno_url, anno_file) + + # unzip compressed files + seq_dir = osp.join(root_dir, seq_name) + if not osp.isfile(seq_dir) or len(os.listdir(seq_dir)) < 10: + ops.sys_print('\nExtracting %s...' % seq_name) + os.makedirs(seq_dir) + for seq_file in seq_files: + ops.extract(seq_file, seq_dir) + ops.extract(anno_file, seq_dir) + + # save list.txt + list_file = osp.join(root_dir, 'list.txt') + with open(list_file, 'w') as f: + f.write(str.join('\n', seq_names)) + + return root_dir + + def _format(self, anno): + if anno.shape[1] == 8: + if self.anno_type == 'rect': + anno = self._corner2rect(anno) + elif self.anno_type == 'inner_rect': + anno = self._corner2rect_inner(anno) + + if anno.shape[1] == 4: + anno[:, 2:] = anno[:, :2] + anno[:, 2:] - 1 + + return anno + + def _corner2rect(self, corners, center=False): + x1 = np.min(corners[:, 0::2], axis=1) + x2 = np.max(corners[:, 0::2], axis=1) + y1 = np.min(corners[:, 1::2], axis=1) + y2 = np.max(corners[:, 1::2], axis=1) + + w = x2 - x1 + h = y2 - y1 + + if center: + cx = np.mean(corners[:, 0::2], axis=1) + cy = np.mean(corners[:, 1::2], axis=1) + return np.array([cx, cy, w, h]).T + else: + return np.array([x1, y1, w, h]).T + + def _corner2rect_inner(self, corners, center=False): + cx = np.mean(corners[:, 0::2], axis=1) + cy = np.mean(corners[:, 1::2], axis=1) + + x1 = np.min(corners[:, 0::2], axis=1) + x2 = np.max(corners[:, 0::2], axis=1) + y1 = np.min(corners[:, 1::2], axis=1) + y2 = np.max(corners[:, 1::2], axis=1) + + area1 = np.linalg.norm(corners[:, 0:2] - corners[:, 2:4], axis=1) * \ + np.linalg.norm(corners[:, 2:4] - corners[:, 4:6], axis=1) + area2 = (x2 - x1) * (y2 - y1) + scale = np.sqrt(area1 / area2) + w = scale * (x2 - x1) + 1 + h = scale * (y2 - y1) + 1 + + if center: + return np.array([cx, cy, w, h]).T + else: + return np.array([cx - w / 2, cy - h / 2, w, h]).T + + def _fetch_meta(self, seq_dir, frame_num): + meta = {} + + # attributes + tag_files = glob.glob(osp.join(seq_dir, '*.label')) + \ + glob.glob(osp.join(seq_dir, '*.tag')) + for f in tag_files: + if not osp.exists(f): + continue + tag = osp.basename(f) + tag = tag[:tag.rfind('.')] + meta[tag] = np.loadtxt(f) + + # practical + practical_file = osp.join(seq_dir, 'practical') + if osp.isfile(practical_file + '.value'): + meta['practical'] = np.loadtxt(practical_file + '.value') + if osp.isfile(practical_file + '.txt'): + meta['practical_txt'] = np.loadtxt(practical_file + '.txt') + + # pad zeros if necessary + for tag, val in meta.items(): + if len(val) < frame_num: + meta[tag] = np.pad( + val, (0, frame_num - len(val)), 'constant') + + return meta diff --git a/utils/neuron/data/evaluators/__init__.py b/utils/neuron/data/evaluators/__init__.py new file mode 100755 index 0000000..d0cafb0 --- /dev/null +++ b/utils/neuron/data/evaluators/__init__.py @@ -0,0 +1,5 @@ +from .evaluator import Evaluator +from .otb_eval import * +from .vot_eval import * +from .got10k_eval import * +from .oxuva_eval import * diff --git a/utils/neuron/data/evaluators/evaluator.py b/utils/neuron/data/evaluators/evaluator.py new file mode 100755 index 0000000..7cc1ce0 --- /dev/null +++ b/utils/neuron/data/evaluators/evaluator.py @@ -0,0 +1,17 @@ +import abc + + +class Evaluator(object): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def run(self, model, visualize=False): + raise NotImplementedError + + @abc.abstractmethod + def report(self, model_names): + raise NotImplementedError + + @abc.abstractmethod + def show(self, model_names): + raise NotImplementedError diff --git a/utils/neuron/data/evaluators/got10k_eval.py b/utils/neuron/data/evaluators/got10k_eval.py new file mode 100755 index 0000000..13d2be1 --- /dev/null +++ b/utils/neuron/data/evaluators/got10k_eval.py @@ -0,0 +1,369 @@ +import os +import os.path as osp +import numpy as np +import glob +import ast +import json +import time +import matplotlib.pyplot as plt +import matplotlib + +import neuron.ops as ops +from neuron.config import registry +from neuron.data.datasets import GOT10k +from .evaluator import Evaluator + + +__all__ = ['GOT10kEval', 'EvaluatorGOT10k'] + + +@registry.register_module +class GOT10kEval(Evaluator): + r"""Evaluation pipeline and evaluation toolkit for GOT-10k dataset. + + Args: + root_dir (string): Root directory of GOT-10k dataset where + ``train``, ``val`` and ``test`` folders exist. + subset (string): Specify ``train``, ``val`` or ``test`` + subset of GOT-10k. + list_file (string, optional): If provided, only run evaluation on + sequences specified by this file. + result_dir (string, optional): Directory for storing tracking + results. Default is ``./results``. + report_dir (string, optional): Directory for storing performance + evaluation results. Default is ``./reports``. + """ + def __init__(self, dataset, nbins_iou=101, repetitions=3, + result_dir='results', report_dir='reports'): + self.dataset = dataset + self.nbins_iou = nbins_iou + self.repetitions = repetitions + self.result_dir = osp.join(result_dir, self.dataset.name) + self.report_dir = osp.join(report_dir, self.dataset.name) + + def run(self, tracker, visualize=False): + if self.dataset.subset == 'test': + ops.sys_print( + '\033[93m[WARNING]:\n' \ + 'The groundtruths of GOT-10k\'s test set is withholded.\n' \ + 'You will have to submit your results to\n' \ + '[http://got-10k.aitestunion.com/]' \ + '\nto access the performance.\033[0m') + time.sleep(2) + ops.sys_print('Running tracker %s on GOT-10k...' % tracker.name) + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # run multiple repetitions for each sequence + for r in range(self.repetitions): + # check if the tracker is deterministic + if r > 0 and tracker.is_deterministic: + break + elif r == 3 and self._check_deterministic( + tracker.name, seq_name): + ops.sys_print(' Detected a deterministic tracker, ' + + 'skipping remaining trials.') + break + ops.sys_print(' Repetition: %d' % (r + 1)) + + # skip if results exist + record_file = osp.join( + self.result_dir, tracker.name, seq_name, + '%s_%03d.txt' % (seq_name, r + 1)) + if osp.exists(record_file): + ops.sys_print(' Found results, skipping %s' % seq_name) + continue + + # tracking loop + bboxes, times = tracker.forward_test( + img_files, target['anno'][0], visualize=visualize) + + # record results + self._record(record_file, bboxes, times) + + def report(self, tracker_names, plot_curves=False): + if isinstance(tracker_names, str): + tracker_names = [tracker_names] + assert isinstance(tracker_names, (list, tuple)) + + if self.dataset.subset == 'test': + pwd = os.getcwd() + + # generate compressed submission file for each tracker + for tracker_name in tracker_names: + # compress all tracking results + result_dir = osp.join(self.result_dir, tracker_name) + os.chdir(result_dir) + save_file = '../%s' % tracker_name + ops.compress('.', save_file) + ops.sys_print('Records saved at %s' % (save_file + '.zip')) + + # print submission guides + ops.sys_print('\033[93mLogin and follow instructions on') + ops.sys_print('http://got-10k.aitestunion.com/submit_instructions') + ops.sys_print('to upload and evaluate your tracking results\033[0m') + + # switch back to previous working directory + os.chdir(pwd) + + return None + elif self.dataset.subset == 'val': + # assume tracker_names[0] is your tracker + report_dir = osp.join(self.report_dir, tracker_names[0]) + if not osp.exists(report_dir): + os.makedirs(report_dir) + report_file = osp.join(report_dir, 'performance.json') + + # visible ratios of all sequences + seq_names = self.dataset.seq_names + covers = {s: self.dataset[s][1]['meta']['cover'][1:] + for s in seq_names} + + performance = {} + for name in tracker_names: + ops.sys_print('Evaluating %s' % name) + ious = {} + times = {} + performance.update({name: { + 'overall': {}, + 'seq_wise': {}}}) + + for s, (_, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + anno, meta = target['anno'], target['meta'] + + record_files = glob.glob(osp.join( + self.result_dir, name, seq_name, + '%s_[0-9]*.txt' % seq_name)) + if len(record_files) == 0: + raise Exception('Results for sequence %s not found.' % seq_name) + + # read results of all repetitions + bboxes = [np.loadtxt(f, delimiter=',') for f in record_files] + assert all([b.shape == anno.shape for b in bboxes]) + + # calculate and stack all ious + bound = ast.literal_eval(meta['resolution']) + seq_ious = [ops.rect_iou( + b[1:], anno[1:], bound=bound) for b in bboxes] + # only consider valid frames where targets are visible + seq_ious = [t[covers[seq_name] > 0] for t in seq_ious] + seq_ious = np.concatenate(seq_ious) + ious[seq_name] = seq_ious + + # stack all tracking times + times[seq_name] = [] + time_file = osp.join( + self.result_dir, name, seq_name, + '%s_time.txt' % seq_name) + if osp.exists(time_file): + seq_times = np.loadtxt(time_file, delimiter=',') + seq_times = seq_times[~np.isnan(seq_times)] + seq_times = seq_times[seq_times > 0] + if len(seq_times) > 0: + times[seq_name] = seq_times + + # store sequence-wise performance + ao, sr, speed, _ = self._evaluate(seq_ious, seq_times) + performance[name]['seq_wise'].update({seq_name: { + 'ao': ao, + 'sr': sr, + 'speed_fps': speed, + 'length': len(anno) - 1}}) + + ious = np.concatenate(list(ious.values())) + times = np.concatenate(list(times.values())) + + # store overall performance + ao, sr, speed, succ_curve = self._evaluate(ious, times) + performance[name].update({'overall': { + 'ao': ao, + 'sr': sr, + 'speed_fps': speed, + 'succ_curve': succ_curve.tolist()}}) + + # save performance + with open(report_file, 'w') as f: + json.dump(performance, f, indent=4) + if plot_curves: + # plot success curves + self.plot_curves([report_file], tracker_names) + + return performance + + def show(self, tracker_names, seq_names=None, play_speed=1, + visualize=True, save=False, save_dir='screenshots'): + if seq_names is None: + seq_names = self.dataset.seq_names + elif isinstance(seq_names, str): + seq_names = [seq_names] + assert isinstance(tracker_names, (list, tuple)) + assert isinstance(seq_names, (list, tuple)) + + play_speed = int(round(play_speed)) + assert play_speed > 0 + + for s, seq_name in enumerate(seq_names): + ops.sys_print('[%d/%d] Showing results on %s...' % ( + s + 1, len(seq_names), seq_name)) + + # mkdir if required to save screenshots + if save: + out_dir = osp.join(save_dir, seq_name) + if not osp.exists(out_dir): + os.makedirs(out_dir) + + # load all tracking results + records = {} + for name in tracker_names: + record_file = osp.join( + self.result_dir, name, seq_name, + '%s_001.txt' % seq_name) + records[name] = np.loadtxt(record_file, delimiter=',') + + # loop over the sequence and display results + img_files, target = self.dataset[seq_name] + for f, img_file in enumerate(img_files): + if not f % play_speed == 0: + continue + img = ops.read_image(img_file) + bboxes = [target['anno'][f]] + [ + records[name][f] for name in tracker_names] + img = ops.show_image(img, bboxes, visualize=visualize) + + # save screenshots if required + if save: + out_file = osp.join(out_dir, '%08d.jpg' % (f + 1)) + cv2.imwrite(out_file, img) + + def _record(self, record_file, bboxes, times): + # record bounding boxes + record_dir = osp.dirname(record_file) + if not osp.isdir(record_dir): + os.makedirs(record_dir) + np.savetxt(record_file, bboxes, fmt='%.3f', delimiter=',') + ops.sys_print(' Results recorded at %s' % record_file) + + # record running times + time_file = record_file[:record_file.rfind('_')] + '_time.txt' + times = times[:, np.newaxis] + if osp.exists(time_file): + exist_times = np.loadtxt(time_file, delimiter=',') + if exist_times.ndim == 1: + exist_times = exist_times[:, np.newaxis] + times = np.concatenate((exist_times, times), axis=1) + np.savetxt(time_file, times, fmt='%.8f', delimiter=',') + + def _check_deterministic(self, tracker_name, seq_name): + record_dir = osp.join( + self.result_dir, tracker_name, seq_name) + record_files = sorted(glob.glob(osp.join( + record_dir, '%s_[0-9]*.txt' % seq_name))) + + if len(record_files) < 3: + return False + + records = [] + for record_file in record_files: + with open(record_file, 'r') as f: + records.append(f.read()) + + return len(set(records)) == 1 + + def _evaluate(self, ious, times): + # AO, SR and tracking speed + ao = np.mean(ious) + sr = np.mean(ious > 0.5) + if len(times) > 0: + # times has to be an array of positive values + speed_fps = np.mean(1. / times) + else: + speed_fps = -1 + + # success curve + thr_iou = np.linspace(0, 1, 101) + bin_iou = np.greater(ious[:, None], thr_iou[None, :]) + succ_curve = np.mean(bin_iou, axis=0) + + return ao, sr, speed_fps, succ_curve + + def plot_curves(self, report_files, tracker_names): + assert isinstance(report_files, list), \ + 'Expected "report_files" to be a list, ' \ + 'but got %s instead' % type(report_files) + + # assume tracker_names[0] is your tracker + report_dir = osp.join(self.report_dir, tracker_names[0]) + if not osp.exists(report_dir): + os.makedirs(report_dir) + + performance = {} + for report_file in report_files: + with open(report_file) as f: + performance.update(json.load(f)) + + succ_file = osp.join(report_dir, 'success_plot.pdf') + key = 'overall' + + # sort trackers by AO + tracker_names = list(performance.keys()) + aos = [t[key]['ao'] for t in performance.values()] + inds = np.argsort(aos)[::-1] + tracker_names = [tracker_names[i] for i in inds] + + # markers + markers = ['-', '--', '-.'] + markers = [c + m for m in markers for c in [''] * 10] + + # plot success curves + thr_iou = np.linspace(0, 1, self.nbins_iou) + fig, ax = plt.subplots() + lines = [] + legends = [] + for i, name in enumerate(tracker_names): + line, = ax.plot(thr_iou, + performance[name][key]['succ_curve'], + markers[i % len(markers)]) + lines.append(line) + legends.append('%s: [%.3f]' % ( + name, performance[name][key]['ao'])) + matplotlib.rcParams.update({'font.size': 7.4}) + legend = ax.legend(lines, legends, loc='center left', + bbox_to_anchor=(1, 0.5)) + + matplotlib.rcParams.update({'font.size': 9}) + ax.set(xlabel='Overlap threshold', + ylabel='Success rate', + xlim=(0, 1), ylim=(0, 1), + title='Success plots on GOT-10k') + ax.grid(True) + fig.tight_layout() + + ops.sys_print('Saving success plots to %s' % succ_file) + fig.savefig(succ_file, + bbox_extra_artists=(legend,), + bbox_inches='tight', + dpi=300) + + +@registry.register_module +class EvaluatorGOT10k(GOT10kEval): + r"""Evaluation pipeline and evaluation toolkit for GOT-10k dataset. + + Args: + root_dir (string): Root directory of GOT-10k dataset where + ``train``, ``val`` and ``test`` folders exist. + subset (string): Specify ``train``, ``val`` or ``test`` + subset of GOT-10k. + list_file (string, optional): If provided, only run evaluation on + sequences specified by this file. + """ + def __init__(self, root_dir=None, subset='val', + list_file=None, **kwargs): + assert subset in ['val', 'test'] + dataset = GOT10k(root_dir, subset=subset, list_file=list_file) + super(EvaluatorGOT10k, self).__init__(dataset, **kwargs) diff --git a/utils/neuron/data/evaluators/otb_eval.py b/utils/neuron/data/evaluators/otb_eval.py new file mode 100755 index 0000000..bb8c035 --- /dev/null +++ b/utils/neuron/data/evaluators/otb_eval.py @@ -0,0 +1,463 @@ +import os +import os.path as osp +import numpy as np +import matplotlib.pyplot as plt +import matplotlib +import json +import cv2 + +import neuron.ops as ops +from neuron.config import registry +from neuron.data import datasets +from .evaluator import Evaluator + + +__all__ = ['OTB_Eval', 'EvaluatorOTB', 'EvaluatorDTB70', 'EvaluatorNfS', + 'EvaluatorTColor128', 'EvaluatorUAV123', 'EvaluatorLaSOT', + 'EvaluatorTLP', 'EvaluatorVisDrone'] + + +@registry.register_module +class OTB_Eval(Evaluator): + r"""Evaluation pipeline and evaluation toolkit for OTB-like datasets. + + Args: + dataset (Dataset): An OTB-like dataset. + nbins_iou (integer optional): Number of bins for plotting success curves + and calculating success scores. + nbins_ce (integer optional): Number of bins for plotting precision curves. + result_dir (string, optional): Directory for storing tracking + results. Default is ``./results``. + report_dir (string, optional): Directory for storing performance + evaluation results. Default is ``./reports``. + """ + def __init__(self, dataset, nbins_iou=101, nbins_ce=51, + result_dir='results', report_dir='reports', + visualize=False, plot_curves=False, frame_stride=1): + self.dataset = dataset + self.result_dir = osp.join(result_dir) + self.report_dir = osp.join(report_dir, self.dataset.name) + if frame_stride != 1: + self.result_dir += '_s{}'.format(frame_stride) + self.report_dir += '_s{}'.format(frame_stride) + self.visualize = visualize + # self.plot_curves = plot_curves + self.frame_stride = frame_stride + # as nbins_iou increases, the success score + # converges to the average overlap (AO) + self.nbins_iou = nbins_iou + self.nbins_ce = 51 + + def run(self, tracker, visualize=None): + if visualize is None: + visualize = self.visualize + ops.sys_print('Running tracker %s on %s...' % ( + tracker.name, self.dataset.name)) + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # skip if results exist + record_file = osp.join( + self.result_dir, tracker.name, '%s.txt' % seq_name) + if osp.exists(record_file): + ops.sys_print(' Found results, skipping', seq_name) + continue + + # tracking loop + img_files = img_files[::self.frame_stride] + init_bbox = target['anno'][0] + bboxes, times = tracker.forward_test( + img_files, init_bbox, visualize=visualize) + assert len(bboxes) == len(img_files) + + # record results + self._record(record_file, bboxes, times) + + def report(self, tracker_names, dataset, plot_curves=None): + if isinstance(tracker_names, str): + tracker_names = [tracker_names] + assert isinstance(tracker_names, (list, tuple)) + if plot_curves is None: + plot_curves = self.plot_curves + + # assume that tracker_names[0] is your tracker + report_dir = osp.join(self.report_dir) + if not osp.isdir(report_dir): + os.makedirs(report_dir) + report_file = osp.join(report_dir, 'performance.json') + + performance = {} + for name in tracker_names: + ops.sys_print('Evaluating', name) + seq_num = len(self.dataset) + succ_curve = np.zeros((seq_num, self.nbins_iou)) + prec_curve = np.zeros((seq_num, self.nbins_ce)) + speeds = np.zeros(seq_num) + + performance.update({name: { + 'overall': {}, + 'seq_wise': {}}}) + + for s, (_, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + anno = target['anno'][::self.frame_stride] + + # load results + record_file = osp.join( + self.result_dir, name, dataset, 'eval_results', '%s.txt' % seq_name) + try: + bboxes = np.loadtxt(record_file, delimiter=',') + bboxes = np.array([bboxes[:, 0], bboxes[:, 1], bboxes[:, 0] + bboxes[:, 2], + bboxes[:, 1] + bboxes[:, 3]]).transpose() + except: + bboxes = np.loadtxt(record_file) + bboxes = np.array([bboxes[:, 0], bboxes[:, 1], bboxes[:, 0]+bboxes[:, 2], bboxes[:, 1]+bboxes[:, 3]]).transpose() + bboxes[0] = anno[0] + assert len(bboxes) == len(anno) + + # skip invalid frames + mask = np.all(anno > 0, axis=1) + assert mask.sum() > 0 + bboxes = bboxes[mask] + anno = anno[mask] + + ious, center_errors = self._calc_metrics(bboxes, anno) + succ_curve[s], prec_curve[s] = self._calc_curves(ious, center_errors) + + # calculate average tracking speed + time_file = osp.join( + self.result_dir, name, 'times/%s_time.txt' % seq_name) + if osp.isfile(time_file): + times = np.loadtxt(time_file) + times = times[times > 0] + if len(times) > 0: + speeds[s] = np.mean(1. / times) + + # store sequence-wise performance + performance[name]['seq_wise'].update({seq_name: { + 'success_curve': succ_curve[s].tolist(), + 'precision_curve': prec_curve[s].tolist(), + 'success_score': np.mean(succ_curve[s]), + 'precision_score': prec_curve[s][20], + 'success_rate': succ_curve[s][self.nbins_iou // 2], + 'speed_fps': speeds[s] if speeds[s] > 0 else -1}}) + + succ_curve = np.mean(succ_curve, axis=0) + prec_curve = np.mean(prec_curve, axis=0) + succ_score = np.mean(succ_curve) + prec_score = prec_curve[20] + succ_rate = succ_curve[self.nbins_iou // 2] + if np.count_nonzero(speeds) > 0: + avg_speed = np.sum(speeds) / np.count_nonzero(speeds) + else: + avg_speed = -1 + + # store overall performance + performance[name]['overall'].update({ + 'success_curve': succ_curve.tolist(), + 'precision_curve': prec_curve.tolist(), + 'success_score': succ_score, + 'precision_score': prec_score, + 'success_rate': succ_rate, + 'speed_fps': avg_speed}) + + # report the performance + with open(report_file, 'w') as f: + json.dump(performance, f, indent=4) + + if plot_curves: + # plot precision and success curves + self.plot_curves(tracker_names) + + return performance + + def show(self, tracker_names, seq_names=None, play_speed=1, + visualize=True, save=False, save_dir='screenshots'): + if seq_names is None: + seq_names = self.dataset.seq_names + elif isinstance(seq_names, str): + seq_names = [seq_names] + assert isinstance(tracker_names, (list, tuple)) + assert isinstance(seq_names, (list, tuple)) + + play_speed = int(round(play_speed)) + assert play_speed > 0 + + for s, seq_name in enumerate(seq_names): + ops.sys_print('[%d/%d] Showing results on %s...' % ( + s + 1, len(seq_names), seq_name)) + + # mkdir if required to save screenshots + if save: + out_dir = osp.join(save_dir, seq_name) + if not osp.exists(out_dir): + os.makedirs(out_dir) + + # load all tracking results + records = {} + for name in tracker_names: + record_file = osp.join( + self.result_dir, name, '%s.txt' % seq_name) + records[name] = np.loadtxt(record_file, delimiter=',') + + # loop over the sequence and display results + img_files, target = self.dataset[seq_name][:2] + img_files = img_files[::self.frame_stride] + target['anno'] = target['anno'][self.frame_stride] + for f, img_file in enumerate(img_files): + if not f % play_speed == 0: + continue + img = ops.read_image(img_file) + bboxes = [records[name][f] for name in tracker_names] + if len(target['anno']) > f: + bboxes = [target['anno'][f]] + bboxes + img = ops.show_image(img, bboxes, visualize=visualize) + + # save screenshot if required + if save: + out_file = osp.join(out_dir, '%08d.jpg' % (f + 1)) + cv2.imwrite(out_file, img) + + def _record(self, record_file, bboxes, times): + # record bounding boxes + record_dir = osp.dirname(record_file) + if not osp.isdir(record_dir): + os.makedirs(record_dir) + np.savetxt(record_file, bboxes, fmt='%.3f', delimiter=',') + ops.sys_print(' Results recorded at %s' % record_file) + + # record running times + time_dir = osp.join(record_dir, 'times') + if not osp.isdir(time_dir): + os.makedirs(time_dir) + time_file = osp.join(time_dir, osp.basename( + record_file).replace('.txt', '_time.txt')) + np.savetxt(time_file, times, fmt='%.8f') + + def _calc_metrics(self, bboxes, anno): + # can be modified by children classes + ious = ops.rect_iou(bboxes, anno) + center_errors = ops.center_error(bboxes, anno) + return ious, center_errors + + def _calc_curves(self, ious, center_errors): + ious = np.asarray(ious, float)[:, np.newaxis] + center_errors = np.asarray(center_errors, float)[:, np.newaxis] + + thr_iou = np.linspace(0, 1, self.nbins_iou)[np.newaxis, :] + thr_ce = np.arange(0, self.nbins_ce)[np.newaxis, :] + + bin_iou = np.greater(ious, thr_iou) + bin_ce = np.less_equal(center_errors, thr_ce) + + succ_curve = np.mean(bin_iou, axis=0) + prec_curve = np.mean(bin_ce, axis=0) + + return succ_curve, prec_curve + + def plot_curves(self, tracker_names): + # assume tracker_names[0] is your tracker + report_dir = osp.join(self.report_dir) + assert osp.exists(report_dir), \ + 'No reports found. Run "report" first ' \ + 'before plotting curves.' + report_file = osp.join(report_dir, 'performance.json') + assert osp.exists(report_file), \ + 'No reports found. Run "report" first ' \ + 'before plotting curves.' + + # load pre-computed performance + with open(report_file) as f: + performance = json.load(f) + + succ_file = osp.join(report_dir, 'success_plots.pdf') + prec_file = osp.join(report_dir, 'precision_plots.pdf') + key = 'overall' + + # markers + markers = ['-', '--', '-.'] + markers = [c + m for m in markers for c in [''] * 10] + + # sort trackers by success score + tracker_names = list(performance.keys()) + succ = [t[key]['success_score'] for t in performance.values()] + inds = np.argsort(succ)[::-1] + tracker_names = [tracker_names[i] for i in inds] + + # plot success curves + thr_iou = np.linspace(0, 1, self.nbins_iou) + fig, ax = plt.subplots() + lines = [] + legends = [] + for i, name in enumerate(tracker_names): + line, = ax.plot(thr_iou, + performance[name][key]['success_curve'], + markers[i % len(markers)]) + lines.append(line) + legends.append('%s: [%.3f]' % ( + name, performance[name][key]['success_score'])) + matplotlib.rcParams.update({'font.size': 7.4}) + legend = ax.legend(lines, legends, loc='upper right', + bbox_to_anchor=(1, 1)) + + matplotlib.rcParams.update({'font.size': 9}) + ax.set(xlabel='Overlap threshold', + ylabel='Success rate', + xlim=(0, 1), ylim=(0, 1), + title='Success plots of OPE') + ax.grid(True) + fig.tight_layout() + + ops.sys_print('Saving success plots to', succ_file) + fig.savefig(succ_file, + bbox_extra_artists=(legend,), + bbox_inches='tight', + dpi=300) + + # sort trackers by precision score + tracker_names = list(performance.keys()) + prec = [t[key]['precision_score'] for t in performance.values()] + inds = np.argsort(prec)[::-1] + tracker_names = [tracker_names[i] for i in inds] + + # plot precision curves + thr_ce = np.arange(0, self.nbins_ce) + fig, ax = plt.subplots() + lines = [] + legends = [] + for i, name in enumerate(tracker_names): + line, = ax.plot(thr_ce, + performance[name][key]['precision_curve'], + markers[i % len(markers)]) + lines.append(line) + legends.append('%s: [%.3f]' % ( + name, performance[name][key]['precision_score'])) + matplotlib.rcParams.update({'font.size': 7.4}) + legend = ax.legend(lines, legends, loc='upper left') + + matplotlib.rcParams.update({'font.size': 9}) + ax.set(xlabel='Location error threshold', + ylabel='Precision', + xlim=(0, thr_ce.max()), ylim=(0, 1), + title='Precision plots of OPE') + ax.grid(True) + fig.tight_layout() + + ops.sys_print('Saving precision plots to', prec_file) + fig.savefig(prec_file, bbox_extra_artists=(legend,), dpi=300) + + +@registry.register_module +class EvaluatorOTB(OTB_Eval): + + def __init__(self, root_dir=None, version=2015, **kwargs): + dataset = datasets.OTB(root_dir, version, download=False) + if version == 2013: + nbins_iou = 21 + else: + nbins_iou = 101 + super(EvaluatorOTB, self).__init__(dataset, nbins_iou, **kwargs) + + +@registry.register_module +class EvaluatorDTB70(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for DTB70 dataset. + + Args: + root_dir (string): Root directory of DTB70 dataset. + """ + def __init__(self, root_dir=None, **kwargs): + dataset = datasets.DTB70(root_dir) + super(EvaluatorDTB70, self).__init__(dataset, **kwargs) + + +@registry.register_module +class EvaluatorNfS(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for NfS dataset. + + Args: + root_dir (string): Root directory of NfS dataset. + fps (integer): Choose version among 30 fps and 240 fps. + """ + def __init__(self, root_dir=None, fps=30, **kwargs): + dataset = datasets.NfS(root_dir, fps) + super(EvaluatorNfS, self).__init__(dataset, **kwargs) + + +@registry.register_module +class EvaluatorTColor128(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for TColor128 dataset. + + Args: + root_dir (string): Root directory of TColor128 dataset. + """ + def __init__(self, root_dir=None, **kwargs): + dataset = datasets.TColor128(root_dir) + super(EvaluatorTColor128, self).__init__(dataset, **kwargs) + + +@registry.register_module +class EvaluatorUAV123(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for UAV123 dataset. + + Args: + root_dir (string): Root directory of UAV123 dataset. + version (string): Choose version among UAV123 and UAV20L. + """ + def __init__(self, root_dir=None, version='UAV123', **kwargs): + dataset = datasets.UAV123(root_dir, version) + super(EvaluatorUAV123, self).__init__(dataset, **kwargs) + + def _calc_metrics(self, bboxes, anno): + valid = ~np.any(np.isnan(anno), axis=1) + if len(valid) == 0: + ops.sys_print('Warning: no valid annotations') + return None, None + else: + ious = ops.rect_iou(bboxes[valid, :], anno[valid, :]) + center_errors = ops.center_error( + bboxes[valid, :], anno[valid, :]) + return ious, center_errors + + +@registry.register_module +class EvaluatorLaSOT(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for LaSOT dataset. + + Args: + root_dir (string): Root directory of LaSOT dataset. + """ + def __init__(self, root_dir=None, **kwargs): + dataset = datasets.LaSOT(root_dir, subset='test') + super(EvaluatorLaSOT, self).__init__( + dataset, nbins_iou=21, **kwargs) + + +@registry.register_module +class EvaluatorTLP(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for TLP dataset. + + Args: + root_dir (string): Root directory of TLP dataset. + """ + def __init__(self, root_dir=None, **kwargs): + dataset = datasets.TLP(root_dir) + super(EvaluatorTLP, self).__init__(dataset, **kwargs) + + +@registry.register_module +class EvaluatorVisDrone(OTB_Eval): + r"""Evaluation pipeline and evaluation toolkit for VisDrone dataset. + + Args: + root_dir (string): Root directory of VisDrone dataset. + subset (string, optional): Specify ``train`` or ``val`` + subset of VisDrone. + """ + def __init__(self, root_dir=None, subset='val', **kwargs): + dataset = datasets.VisDroneSOT(root_dir, subset=subset) + super(EvaluatorVisDrone, self).__init__(dataset, **kwargs) diff --git a/utils/neuron/data/evaluators/oxuva_eval.py b/utils/neuron/data/evaluators/oxuva_eval.py new file mode 100755 index 0000000..6151878 --- /dev/null +++ b/utils/neuron/data/evaluators/oxuva_eval.py @@ -0,0 +1,117 @@ +import os +import os.path as osp +import csv +import numpy as np + +import neuron.ops as ops +from .evaluator import Evaluator +from neuron.config import registry +from neuron.data import datasets +from neuron.models.trackers import OxUvA_Tracker + + +__all__ = ['OxUvA_Eval', 'EvaluatorOxUvA'] + + +@registry.register_module +class OxUvA_Eval(Evaluator): + r"""Evaluation pipeline and evaluation toolkit for OxUvA dataset. + + Args: + dataset (Dataset): An OxUvA-like dataset. + """ + def __init__(self, dataset, + result_dir='results', report_dir='reports', + visualize=False, plot_curves=False): + self.dataset = dataset + self.result_dir = osp.join(result_dir, self.dataset.name) + self.report_dir = osp.join(report_dir, self.dataset.name) + self.visualize = visualize + self.plot_curves = plot_curves + + def run(self, tracker, visualize=None): + if visualize is None: + visualize = self.visualize + # sanity check + if not isinstance(tracker, OxUvA_Tracker): + raise ValueError( + 'Only supports trackers that implement OxUvA_Tracker.') + ops.sys_print('Running tracker %s on %s...' % ( + tracker.name, self.dataset.name)) + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # skip if results exist + record_file = osp.join( + self.result_dir, tracker.name, '%s.csv' % seq_name) + if osp.exists(record_file): + ops.sys_print(' Found results, skipping %s' % seq_name) + continue + + # tracking loop + preds, times = tracker.forward_test( + img_files, target['anno'][0, :], visualize=visualize) + assert len(preds) == len(img_files) + + # record results + self._record( + record_file, preds, times, seq_name, target['meta']) + + def report(self, tracker_names, plot_curves=None): + raise NotImplementedError( + 'Evaluation of OxUvA results is not implemented.' + 'Please submit the results to http://oxuva.net/ for evaluation.') + + def _record(self, record_file, preds, times, seq_name, meta): + fields = [ + 'video', 'object', 'frame_num', 'present', 'score', + 'xmin', 'xmax', 'ymin', 'ymax'] + vid_id, obj_id = seq_name.split('_') + img_width, img_height = meta['width'], meta['height'] + + # record predictions + record_dir = osp.dirname(record_file) + if not osp.isdir(record_dir): + os.makedirs(record_dir) + with open(record_file, 'w') as f: + writer = csv.DictWriter(f, fieldnames=fields) + for t, pred in preds.items(): + row = { + 'video': vid_id, + 'object': obj_id, + 'frame_num': t, + 'present': str(pred['present']).lower(), + 'score': pred['score'], + 'xmin': pred['xmin'] / img_width, + 'xmax': pred['xmax'] / img_width, + 'ymin': pred['ymin'] / img_height, + 'ymax': pred['ymax'] / img_height} + writer.writerow(row) + ops.sys_print(' Results recorded at %s' % record_file) + + # record running times + time_dir = osp.join(record_dir, 'times') + if not osp.isdir(time_dir): + os.makedirs(time_dir) + time_file = osp.join(time_dir, osp.basename( + record_file).replace('.csv', '_time.txt')) + np.savetxt(time_file, times, fmt='%.8f') + + +class EvaluatorOxUvA(OxUvA_Eval): + r"""Evaluation pipeline and evaluation toolkit for OxUvA dataset. + + Args: + root_dir (string): Root directory of OxUvA dataset. + subset (string, optional): Specify ``dev`` or ``test`` + subset of OxUvA. + """ + def __init__(self, root_dir=None, subset='dev', + frame_stride=30, **kwargs): + dataset = datasets.OxUvA( + root_dir, subset=subset, frame_stride=frame_stride) + super(EvaluatorOxUvA, self).__init__(dataset, **kwargs) diff --git a/utils/neuron/data/evaluators/vot_eval.py b/utils/neuron/data/evaluators/vot_eval.py new file mode 100755 index 0000000..8c62a2b --- /dev/null +++ b/utils/neuron/data/evaluators/vot_eval.py @@ -0,0 +1,597 @@ +import time +import numpy as np +import os +import glob +import warnings +import json + +import neuron.ops as ops +from neuron.config import registry +from neuron.data.datasets import VOT +from .evaluator import Evaluator + + +__all__ = ['VOT_Eval', 'EvaluatorVOT'] + + +@registry.register_module +class VOT_Eval(Evaluator): + r"""Evaluation pipeline and evaluation toolkit for VOT-like datasets. + + Notes: + - The tracking results of three types of experiments ``supervised`` + ``unsupervised`` and ``realtime`` are compatible with the official + VOT toolkit <https://github.com/votchallenge/vot-toolkit/>`. + - TODO: The evaluation function for VOT tracking results is still + under development. + + Args: + dataset (Dataset): A VOT-like dataset. + experiments (string or list): Specify the type(s) of experiments to run. + Default is a list [``supervised``, ``unsupervised``, ``realtime``]. + tags (list): list of attribute tags to report. + result_dir (string, optional): Directory for storing tracking + results. Default is ``./results``. + report_dir (string, optional): Directory for storing performance + evaluation results. Default is ``./reports``. + """ + def __init__(self, dataset, + experiments=['supervised', 'unsupervised', 'realtime'], + tags=['camera_motion', 'illum_change', 'occlusion', + 'size_change', 'motion_change', 'empty'], + skip_initialize=5, burnin=10, repetitions=15, + sensitive=100, nbins_eao=1500, + result_dir='results', report_dir='reports'): + if isinstance(experiments, str): + experiments = [experiments] + assert all([e in ['supervised', 'unsupervised', 'realtime'] + for e in experiments]) + self.dataset = dataset + self.experiments = experiments + self.tags = tags + self.skip_initialize = skip_initialize + self.burnin = burnin + self.repetitions = repetitions + self.sensitive = sensitive + self.nbins_eao = nbins_eao + self.result_dir = os.path.join(result_dir, dataset.name) + self.report_dir = os.path.join(report_dir, dataset.name) + + def run(self, tracker, visualize=False): + ops.sys_print('Running tracker %s on %s...' % ( + tracker.name, self.dataset.name)) + + # run all specified experiments + if 'supervised' in self.experiments: + self.run_supervised(tracker, visualize) + if 'unsupervised' in self.experiments: + self.run_unsupervised(tracker, visualize) + if 'realtime' in self.experiments: + self.run_realtime(tracker, visualize) + + def run_supervised(self, tracker, visualize=False): + ops.sys_print('Running supervised experiment...') + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # rectangular bounding boxes + anno = target['anno'] + anno_rects = anno.copy() + if anno_rects.shape[1] == 8: + anno_rects = self.dataset._corner2rect(anno_rects) + + # run multiple repetitions for each sequence + for r in range(self.repetitions): + # check if the tracker is deterministic + if r > 0 and tracker.is_deterministic: + break + elif r == 3 and self._check_deterministic('baseline', tracker.name, seq_name): + ops.sys_print( + ' Detected a deterministic tracker, ' + 'skipping remaining trials.') + break + ops.sys_print(' Repetition: %d' % (r + 1)) + + # skip if results exist + record_file = os.path.join( + self.result_dir, tracker.name, 'baseline', seq_name, + '%s_%03d.txt' % (seq_name, r + 1)) + if os.path.exists(record_file): + ops.sys_print(' Found results, skipping %s' % seq_name) + continue + + # state variables + bboxes = [] + times = [] + failure = False + next_start = -1 + + # tracking loop + for f, img_file in enumerate(img_files): + img = ops.read_image(img_file) + if tracker.input_type == 'image': + frame = img + elif tracker.input_type == 'file': + frame = img_file + + start_time = time.time() + if f == 0: + # initial frame + tracker.init(frame, anno_rects[0]) + bboxes.append([1]) + elif failure: + # during failure frames + if f == next_start: + if np.all(anno_rects[f] <= 0): + next_start += 1 + start_time = np.NaN + bboxes.append([0]) + else: + failure = False + tracker.init(frame, anno_rects[f]) + bboxes.append([1]) + else: + start_time = np.NaN + bboxes.append([0]) + else: + # during success frames + bbox = tracker.update(frame) + iou = ops.poly_iou(anno[f], bbox, bound=img.shape[1::-1]) + if iou <= 0.0: + # tracking failure + failure = True + next_start = f + self.skip_initialize + bboxes.append([2]) + else: + # tracking succeed + bboxes.append(bbox) + + # store elapsed time + times.append(time.time() - start_time) + + # visualize if required + if visualize: + if len(bboxes[-1]) == 4: + ops.show_image(img, bboxes[-1]) + else: + ops.show_image(img) + + # record results + self._record(record_file, bboxes, times) + + def run_unsupervised(self, tracker, visualize=False): + ops.sys_print('Running unsupervised experiment...') + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # skip if results exist + record_file = os.path.join( + self.result_dir, tracker.name, 'unsupervised', seq_name, + '%s_001.txt' % seq_name) + if os.path.exists(record_file): + ops.sys_print(' Found results, skipping %s' % seq_name) + continue + + # rectangular bounding boxes + anno_rects = target['anno'].copy() + if anno_rects.shape[1] == 8: + anno_rects = self.dataset._corner2rect(anno_rects) + + # tracking loop + bboxes, times = tracker.forward_test( + img_files, anno_rects[0], visualize=visualize) + assert len(bboxes) == len(img_files) + + # re-formatting + bboxes = list(bboxes) + bboxes[0] = [1] + + # record results + self._record(record_file, bboxes, times) + + def run_realtime(self, tracker, visualize=False): + ops.sys_print('Running real-time experiment...') + + # loop over the complete dataset + for s, (img_files, target) in enumerate(self.dataset): + seq_name = self.dataset.seq_names[s] + ops.sys_print('--Sequence %d/%d: %s' % ( + s + 1, len(self.dataset), seq_name)) + + # skip if results exist + record_file = os.path.join( + self.result_dir, tracker.name, 'realtime', seq_name, + '%s_001.txt' % seq_name) + if os.path.exists(record_file): + ops.sys_print(' Found results, skipping %s' % seq_name) + continue + + # rectangular bounding boxes + anno = target['anno'] + anno_rects = anno.copy() + if anno_rects.shape[1] == 8: + anno_rects = self.dataset._corner2rect(anno_rects) + + # state variables + bboxes = [] + times = [] + next_start = 0 + failure = False + failed_frame = -1 + total_time = 0.0 + grace = 3 - 1 + offset = 0 + + # tracking loop + for f, img_file in enumerate(img_files): + img = ops.read_image(img_file) + if tracker.input_type == 'image': + frame = img + elif tracker.input_type == 'file': + frame = img_file + + start_time = time.time() + if f == next_start: + # during initial frames + tracker.init(frame, anno_rects[f]) + bboxes.append([1]) + + # reset state variables + failure = False + failed_frame = -1 + total_time = 0.0 + grace = 3 - 1 + offset = f + elif not failure: + # during success frames + # calculate current frame + if grace > 0: + total_time += 1000.0 / 25 + grace -= 1 + else: + total_time += max(1000.0 / 25, last_time * 1000.0) + current = offset + int(np.round(np.floor(total_time * 25) / 1000.0)) + + # delayed/tracked bounding box + if f < current: + bbox = bboxes[-1] + elif f == current: + bbox = tracker.update(frame) + + iou = ops.poly_iou(anno[f], bbox, bound=img.shape[1::-1]) + if iou <= 0.0: + # tracking failure + failure = True + failed_frame = f + next_start = current + self.skip_initialize + bboxes.append([2]) + else: + # tracking succeed + bboxes.append(bbox) + else: + # during failure frames + if f < current: + # skipping frame due to slow speed + bboxes.append([0]) + start_time = np.NaN + elif f == current: + # current frame + bbox = tracker.update(frame) + iou = ops.poly_iou(anno[f], bbox, bound=img.shape[1::-1]) + if iou <= 0.0: + # tracking failure + bboxes.append([2]) + bboxes[failed_frame] = [0] + times[failed_frame] = np.NaN + else: + # tracking succeed + bboxes.append(bbox) + elif f < next_start: + # skipping frame due to failure + bboxes.append([0]) + start_time = np.NaN + + # store elapsed time + last_time = time.time() - start_time + times.append(last_time) + + # visualize if required + if visualize: + if len(bboxes[-1]) == 4: + ops.show_image(img, bboxes[-1]) + else: + ops.show_image(img) + + # record results + self._record(record_file, bboxes, times) + + def report(self, tracker_names, plot_curves=False): + if isinstance(tracker_names, str): + tracker_names = [tracker_names] + assert isinstance(tracker_names, (list, tuple)) + + # function for loading results + def read_record(filename): + with open(filename) as f: + record = f.read().strip().split('\n') + record = [[float(t) for t in line.split(',')] + for line in record] + return record + + # assume tracker_names[0] is your tracker + report_dir = os.path.join(self.report_dir, tracker_names[0]) + if not os.path.exists(report_dir): + os.makedirs(report_dir) + report_file = os.path.join(report_dir, 'performance.json') + + performance = {} + for name in tracker_names: + ops.sys_print('Evaluating %s' % name) + ious = {} + ious_full = {} + failures = {} + times = {} + masks = {} # frame masks for attribute tags + + for s, (img_files, target) in enumerate(self.dataset): + anno, meta = target['anno'], target['meta'] + seq_name = self.dataset.seq_names[s] + + # initialize frames scores + frame_num = len(img_files) + ious[seq_name] = np.full( + (self.repetitions, frame_num), np.nan, dtype=float) + ious_full[seq_name] = np.full( + (self.repetitions, frame_num), np.nan, dtype=float) + failures[seq_name] = np.full( + (self.repetitions, frame_num), np.nan, dtype=float) + times[seq_name] = np.full( + (self.repetitions, frame_num), np.nan, dtype=float) + + # read results of all repetitions + record_files = sorted(glob.glob(os.path.join( + self.result_dir, name, 'baseline', seq_name, + '%s_[0-9]*.txt' % seq_name))) + bboxes = [read_record(f) for f in record_files] + assert all([len(b) == len(anno) for b in bboxes]) + + # calculate frame ious with burnin + bound = ops.read_image(img_files[0]).shape[1::-1] + seq_ious = [self._calc_iou(b, anno, bound, burnin=True) + for b in bboxes] + ious[seq_name][:len(seq_ious), :] = seq_ious + + # calculate frame ious without burnin + seq_ious_full = [self._calc_iou(b, anno, bound) + for b in bboxes] + ious_full[seq_name][:len(seq_ious_full), :] = seq_ious_full + + # calculate frame failures + seq_failures = [ + [len(b) == 1 and b[0] == 2 for b in bboxes_per_rep] + for bboxes_per_rep in bboxes] + failures[seq_name][:len(seq_failures), :] = seq_failures + + # collect frame runtimes + time_file = os.path.join( + self.result_dir, name, 'baseline', seq_name, + '%s_time.txt' % seq_name) + if os.path.exists(time_file): + seq_times = np.loadtxt(time_file, delimiter=',').T + times[seq_name][:len(seq_times), :] = seq_times + + # collect attribute masks + tag_num = len(self.tags) + masks[seq_name] = np.zeros((tag_num, frame_num), bool) + for i, tag in enumerate(self.tags): + if tag in meta: + masks[seq_name][i, :] = meta[tag] + # frames with no tags + if 'empty' in self.tags: + tag_frames = np.array([ + v for k, v in meta.items() + if isinstance(v, np.ndarray) and \ + not 'practical' in k], dtype=bool) + ind = self.tags.index('empty') + masks[seq_name][ind, :] = \ + ~np.logical_or.reduce(tag_frames, axis=0) + + # concatenate frames + seq_names = self.dataset.seq_names + masks = np.concatenate( + [masks[s] for s in seq_names], axis=1) + ious = np.concatenate( + [ious[s] for s in seq_names], axis=1) + failures = np.concatenate( + [failures[s] for s in seq_names], axis=1) + + with warnings.catch_warnings(): + # average over repetitions + warnings.simplefilter('ignore', category=RuntimeWarning) + ious = np.nanmean(ious, axis=0) + failures = np.nanmean(failures, axis=0) + + # calculate average overlaps and failures for each tag + tag_ious = np.array( + [np.nanmean(ious[m]) for m in masks]) + tag_failures = np.array( + [np.nansum(failures[m]) for m in masks]) + tag_frames = masks.sum(axis=1) + + # remove nan values + tag_ious[np.isnan(tag_ious)] = 0.0 + tag_weights = tag_frames / tag_frames.sum() + + # calculate weighted accuracy and robustness + accuracy = np.sum(tag_ious * tag_weights) + robustness = np.sum(tag_failures * tag_weights) + + # calculate tracking speed + times = np.concatenate([ + t.reshape(-1) for t in times.values()]) + # remove invalid values + times = times[~np.isnan(times)] + times = times[times > 0] + if len(times) > 0: + speed = np.mean(1. / times) + else: + speed = -1 + + performance.update({name: { + 'accuracy': accuracy, + 'robustness': robustness, + 'speed_fps': speed}}) + + # save performance + with open(report_file, 'w') as f: + json.dump(performance, f, indent=4) + ops.sys_print('Performance saved at %s' % report_file) + + return performance + + def show(self, tracker_names, seq_names=None, play_speed=1, + experiment='supervised', visualize=True, + save=False, save_dir='screenshots'): + if seq_names is None: + seq_names = self.dataset.seq_names + elif isinstance(seq_names, str): + seq_names = [seq_names] + assert isinstance(tracker_names, (list, tuple)) + assert isinstance(seq_names, (list, tuple)) + assert experiment in ['supervised', 'unsupervised', 'realtime'] + + play_speed = int(round(play_speed)) + assert play_speed > 0 + + # "supervised" experiment results are stored in "baseline" folder + if experiment == 'supervised': + experiment = 'baseline' + + # function for loading results + def read_record(filename): + with open(filename) as f: + record = f.read().strip().split('\n') + record = [[float(t) for t in line.split(',')] + for line in record] + for i, r in enumerate(record): + if len(r) == 4: + record[i] = np.array(r) + elif len(r) == 8: + r = np.array(r)[np.newaxis, :] + r = self.dataset._corner2rect(r) + record[i] = r[0] + else: + record[i] = np.zeros(4) + return record + + for s, seq_name in enumerate(seq_names): + ops.sys_print('[%d/%d] Showing results on %s...' % ( + s + 1, len(seq_names), seq_name)) + + # mkdir if required to save screenshots + if save: + out_dir = os.path.join(save_dir, seq_name) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + + # load all tracking results + records = {} + for name in tracker_names: + record_file = os.path.join( + self.result_dir, name, experiment, seq_name, + '%s_001.txt' % seq_name) + records[name] = read_record(record_file) + + # loop over the sequence and display results + img_files, target = self.dataset[seq_name][:2] + anno = target['anno'] + if anno.shape[1] == 8: + anno = self.dataset._corner2rect(anno) + for f, img_file in enumerate(img_files): + if not f % play_speed == 0: + continue + img = ops.read_image(img_file) + bboxes = [anno[f]] + [ + records[name][f] for name in tracker_names] + img = ops.show_image(img, bboxes, visualize=visualize) + + # save screenshot if required + if save: + out_file = os.path.join(out_dir, '%08d.jpg' % (f + 1)) + cv2.imwrite(out_file, img) + + def _record(self, record_file, bboxes, times): + # convert bboxes to string + lines = [] + for bbox in bboxes: + if len(bbox) == 1: + lines.append('%d' % bbox[0]) + else: + lines.append(str.join(',', ['%.4f' % t for t in bbox])) + + # record bounding boxes + record_dir = os.path.dirname(record_file) + if not os.path.isdir(record_dir): + os.makedirs(record_dir) + with open(record_file, 'w') as f: + f.write(str.join('\n', lines)) + ops.sys_print(' Results recorded at %s' % record_file) + + # convert times to string + lines = ['%.4f' % t for t in times] + lines = [t.replace('nan', 'NaN') for t in lines] + + # record running times + time_file = record_file[:record_file.rfind('_')] + '_time.txt' + if os.path.exists(time_file): + with open(time_file) as f: + exist_lines = f.read().strip().split('\n') + lines = [t + ',' + s for t, s in zip(exist_lines, lines)] + with open(time_file, 'w') as f: + f.write(str.join('\n', lines)) + + def _check_deterministic(self, exp, tracker_name, seq_name): + record_dir = os.path.join( + self.result_dir, tracker_name, exp, seq_name) + record_files = sorted(glob.glob(os.path.join( + record_dir, '%s_[0-9]*.txt' % seq_name))) + + if len(record_files) < 3: + return False + + records = [] + for record_file in record_files: + with open(record_file, 'r') as f: + records.append(f.read()) + + return len(set(records)) == 1 + + def _calc_iou(self, bboxes, anno, bound, burnin=False): + # skip initialization frames + if burnin: + bboxes = bboxes.copy() + init_inds = [i for i, bbox in enumerate(bboxes) + if bbox == [1.0]] + for ind in init_inds: + bboxes[ind:ind + self.burnin] = [[0]] * self.burnin + # calculate polygon ious + ious = np.array([ops.poly_iou(np.array(a), b, bound) + if len(a) > 1 else np.NaN + for a, b in zip(bboxes, anno)]) + return ious + + +@registry.register_module +class EvaluatorVOT(VOT_Eval): + + def __init__(self, root_dir=None, version=2018, **kwargs): + dataset = VOT(root_dir, version, anno_type='default') + super(EvaluatorVOT, self).__init__(dataset, **kwargs) diff --git a/utils/neuron/data/parallel.py b/utils/neuron/data/parallel.py new file mode 100755 index 0000000..e69de29 diff --git a/utils/neuron/data/samplers/__init__.py b/utils/neuron/data/samplers/__init__.py new file mode 100755 index 0000000..0acebdd --- /dev/null +++ b/utils/neuron/data/samplers/__init__.py @@ -0,0 +1 @@ +from .samplers import * diff --git a/utils/neuron/data/samplers/samplers.py b/utils/neuron/data/samplers/samplers.py new file mode 100755 index 0000000..05bd3c8 --- /dev/null +++ b/utils/neuron/data/samplers/samplers.py @@ -0,0 +1,68 @@ +import numpy as np +import copy +import random +from collections import defaultdict +from torch.utils.data import Sampler + +from neuron.config import registry + + +__all__ = ['RandomIdentitySampler'] + + +@registry.register_module +class RandomIdentitySampler(Sampler): + + def __init__(self, dataset, num_identities, num_instances): + self.dataset = dataset + self.num_identities = num_identities + self.num_instances = num_instances + self.index_dict = defaultdict(list) + for i, (_, val) in enumerate(dataset.ins_dict.items()): + ins_id = val['target']['ins_id'] + self.index_dict[ins_id].append(i) + self.ins_ids = list(self.index_dict.keys()) + + # estimate length (samples in an epochs) + self.length = 0 + for ins_id in self.ins_ids: + n = len(self.index_dict[ins_id]) + if n < self.num_instances: + n = self.num_instances + self.length += n - n % self.num_instances + + def __iter__(self): + # construct batch indices for each ins_id + batch_index_dict = defaultdict(list) + for ins_id in self.ins_ids: + indices = copy.deepcopy(self.index_dict[ins_id]) + if len(indices) < self.num_instances: + indices = np.random.choice( + indices, size=self.num_instances, replace=True) + random.shuffle(indices) + + batch_indices = [] + for index in indices: + batch_indices.append(index) + if len(batch_indices) == self.num_instances: + batch_index_dict[ins_id].append(batch_indices) + batch_indices = [] + + # construct the final sample indices + rest_ids = copy.deepcopy(self.ins_ids) + final_indices = [] + while len(rest_ids) >= self.num_identities: + selected = random.sample(rest_ids, self.num_identities) + for ins_id in selected: + batch_indices = batch_index_dict[ins_id].pop(0) + final_indices.extend(batch_indices) + if len(batch_index_dict[ins_id]) == 0: + rest_ids.remove(ins_id) + + # update length (samples in an epoch) + self.length = len(final_indices) + + return iter(final_indices) + + def __len__(self): + return self.length diff --git a/utils/neuron/data/transforms/__init__.py b/utils/neuron/data/transforms/__init__.py new file mode 100755 index 0000000..15d36a3 --- /dev/null +++ b/utils/neuron/data/transforms/__init__.py @@ -0,0 +1,2 @@ +from .pair_transforms import * +from .img_transforms import * diff --git a/utils/neuron/data/transforms/img_transforms/__init__.py b/utils/neuron/data/transforms/img_transforms/__init__.py new file mode 100755 index 0000000..158b9c2 --- /dev/null +++ b/utils/neuron/data/transforms/img_transforms/__init__.py @@ -0,0 +1 @@ +from .reid_transforms import * diff --git a/utils/neuron/data/transforms/img_transforms/reid_transforms.py b/utils/neuron/data/transforms/img_transforms/reid_transforms.py new file mode 100755 index 0000000..535cb5c --- /dev/null +++ b/utils/neuron/data/transforms/img_transforms/reid_transforms.py @@ -0,0 +1,188 @@ +import numpy as np +import torch + +import neuron.ops as ops +from neuron.config import registry + + +__all__ = ['ReID_Transforms'] + + +class Compose(object): + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, img, target): + for t in self.transforms: + img, target = t(img, target) + return img, target + + def __getitem__(self, index): + if isinstance(index, int): + return self.transforms[index] + elif isinstance(index, slice): + return Compose(self.transforms[index]) + else: + raise TypeError('Invalid type of index.') + + def __add__(self, other): + if isinstance(other, Compose): + return Compose(self.transforms + other.transforms) + else: + raise TypeError('Invalid type of other.') + + +class CropAndResize(object): + + def __init__(self, + train=True, + context=0.5, + out_size=(128, 128), + random_shift=10): + self.train = train + self.context = context + self.out_size = ops.make_pair(out_size) + self.random_shift = random_shift + + def __call__(self, img, target): + bbox = target['bbox'] + f_out_size = np.array(self.out_size, dtype=np.float32) + + # calculate the cropping size + bbox_size = bbox[2:] - bbox[:2] + 1 + context = self.context * np.sum(bbox_size) + crop_size = np.sqrt(np.prod(bbox_size + context)) + + # calculate the cropping center + bbox_center = (bbox[:2] + bbox[2:]) / 2. + if self.train: + # randomly shift in the cropped image + shift = np.random.uniform( + -self.random_shift, self.random_shift, 2) + shift *= crop_size / f_out_size + else: + shift = np.zeros(2) + crop_center = bbox_center + shift + + # crop and resize + avg_color = np.mean(img, axis=(0, 1)) + crop_img = ops.crop_and_resize( + img, crop_center, crop_size, + out_size=self.out_size, border_value=avg_color) + + # bounding box in the cropped image + scale = f_out_size / crop_size + bbox_center = (f_out_size - 1) / 2. - shift * scale + bbox_size *= scale + crop_bbox = np.concatenate([ + bbox_center - (bbox_size - 1) / 2., + bbox_center + (bbox_size - 1) / 2.]) + target.update({'bbox': crop_bbox.astype(np.float32)}) + + return crop_img, target + + +class RandomHorizontalFlip(object): + + def __init__(self, p=0.5): + self.p = p + + def __call__(self, img, target): + if np.random.rand() < self.p: + img, target['bbox'] = ops.flip_img(img, target['bbox']) + return img, target + + +class Normalize(object): + + def __init__(self, + rgb_mean=[0.485, 0.456, 0.406], + rgb_std=[0.229, 0.224, 0.225]): + self.rgb_mean = rgb_mean + self.rgb_std = rgb_std + + def __call__(self, img, target): + img = ops.normalize_img( + img / 255., self.rgb_mean, self.rgb_std) + return img, target + + +class RandomErasing(object): + + def __init__(self, + p=0.5, + min_area=0.02, + max_area=0.4, + min_aspect_ratio=0.3, + rgb_mean=[0.485, 0.456, 0.406]): + self.p = p + self.min_area = min_area + self.max_area = max_area + self.min_aspect_ratio = min_aspect_ratio + self.rgb_mean = rgb_mean + + def __call__(self, img, target): + if np.random.rand() > self.p: + return img, target + + h, w, c = img.shape + for _ in range(100): + area = np.prod(img.shape[:2]) + + erase_area = area * np.random.uniform( + self.min_area, self.max_area) + erase_aspect_ratio = np.random.uniform( + self.min_aspect_ratio, 1. / self.min_aspect_ratio) + erase_h = int(round(np.sqrt( + erase_area * erase_aspect_ratio))) + erase_w = int(round(np.sqrt( + erase_area / erase_aspect_ratio))) + + if erase_w < w and erase_h < h: + x1 = np.random.randint(0, w - erase_w) + y1 = np.random.randint(0, h - erase_h) + img[y1:y1 + erase_h, x1:x1 + erase_w] = self.rgb_mean + return img, target + + return img, target + + +class ToTensor(object): + + def __call__(self, img, target): + img = torch.from_numpy(img).permute(2, 0, 1).float() + bbox = torch.from_numpy(target['bbox']).float() + label = torch.LongTensor([target['ins_id']])[0] - 1 + target = {'bbox': bbox, 'label': label} + return img, target + + +@registry.register_module +class ReID_Transforms(Compose): + + def __init__(self, + train=True, + context=0.5, + out_size=(128, 128), + random_shift=10, + flip_p=0.5, + rgb_mean=[0.485, 0.456, 0.406], + rgb_std=[0.229, 0.224, 0.225], + erase_p=0.5, + min_area=0.02, + max_area=0.4, + min_aspect_ratio=0.3): + if train: + super(ReID_Transforms, self).__init__(transforms=[ + CropAndResize(train, context, out_size, random_shift), + RandomHorizontalFlip(flip_p), + Normalize(rgb_mean, rgb_std), + RandomErasing(erase_p, min_area, max_area, + min_aspect_ratio, rgb_mean), + ToTensor()]) + else: + super(ReID_Transforms, self).__init__(transforms=[ + CropAndResize(train, context, out_size, random_shift), + Normalize(rgb_mean, rgb_std), + ToTensor()]) diff --git a/utils/neuron/data/transforms/pair_transforms/__init__.py b/utils/neuron/data/transforms/pair_transforms/__init__.py new file mode 100755 index 0000000..b7179a8 --- /dev/null +++ b/utils/neuron/data/transforms/pair_transforms/__init__.py @@ -0,0 +1,2 @@ +from .siamfc_transforms import * +from .mmdet_transforms import * diff --git a/utils/neuron/data/transforms/pair_transforms/mmdet_transforms.py b/utils/neuron/data/transforms/pair_transforms/mmdet_transforms.py new file mode 100755 index 0000000..b69f5a0 --- /dev/null +++ b/utils/neuron/data/transforms/pair_transforms/mmdet_transforms.py @@ -0,0 +1,393 @@ +import numpy as np +import torch +import copy +import cv2 + +import neuron.ops as ops +from neuron.config import registry + + +__all__ = ['BasicPairTransforms', 'ExtraPairTransforms', 'TTFNetTransforms'] + + +class _PairTransform(object): + + def __call__(self, item): + # process query + item['img_z'], item['img_meta_z'], item['gt_bboxes_z'] = \ + self._process_query( + item['img_z'], + item['img_meta_z'], + item['gt_bboxes_z']) + + # process gallary + item['img_x'], item['img_meta_x'], item['gt_bboxes_x'] = \ + self._process_gallary( + item['img_x'], + item['img_meta_x'], + item['gt_bboxes_x']) + + return item + + def _process_query(self, img, meta, bboxes=None): + raise NotImplementedError + + def _process_gallary(self, img, meta, bboxes=None): + raise NotImplementedError + + +class Compose(_PairTransform): + + def __init__(self, transforms): + self.transforms = transforms + + def __call__(self, item): + for t in self.transforms: + item = t(item) + return item + + def __getitem__(self, index): + if isinstance(index, int): + return self.transforms[index] + elif isinstance(index, slice): + return Compose(self.transforms[index]) + else: + raise TypeError('Invalid type of index.') + + def __add__(self, other): + if isinstance(other, Compose): + return Compose(self.transforms + other.transforms) + else: + raise TypeError('Invalid type of other.') + + def _process_query(self, img, meta, bboxes=None): + for t in self.transforms: + img, meta, bboxes = t._process_query(img, meta, bboxes) + return img, meta, bboxes + + def _process_gallary(self, img, meta, bboxes=None): + for t in self.transforms: + img, meta, bboxes = t._process_gallary(img, meta, bboxes) + return img, meta, bboxes + + +class Rescale(_PairTransform): + + def __init__(self, + scale=(1333, 800), + interp=None): + self.scale = scale + self.interp = interp + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + if bboxes is None: + img, scale_factor = ops.rescale_img( + img, self.scale, bboxes=None, interp=self.interp) + else: + img, bboxes, scale_factor = ops.rescale_img( + img, self.scale, bboxes=bboxes, interp=self.interp) + meta.update({ + 'img_shape': img.shape, + 'scale_factor': scale_factor}) + return img, meta, bboxes + + +class Resize(_PairTransform): + + def __init__(self, + scale=(512, 512), + interp=None): + self.scale = scale + self.interp = interp + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + if bboxes is None: + img, scale_factor = ops.resize_img( + img, self.scale, bboxes=None, interp=self.interp) + else: + img, bboxes, scale_factor = ops.resize_img( + img, self.scale, bboxes=bboxes, interp=self.interp) + meta.update({ + 'img_shape': img.shape, + 'scale_factor': scale_factor}) + return img, meta, bboxes + + +class Normalize(_PairTransform): + + def __init__(self, + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375]): + self.mean = mean + self.std = std + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + img = ops.normalize_img(img, self.mean, self.std) + return img, meta, bboxes + + +class RandomFlip(_PairTransform): + + def __init__(self, p=0.5): + self.p = p + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + if np.random.rand() < self.p: + if bboxes is None: + img = ops.flip_img(img) + else: + img, bboxes = ops.flip_img(img, bboxes) + meta.update({'flip': True}) + else: + meta.update({'flip': False}) + return img, meta, bboxes + + +class PadToDivisor(_PairTransform): + + def __init__(self, divisor=32, border_value=0): + self.divisor = divisor + self.border_value = border_value + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + img = ops.pad_to_divisor(img, self.divisor, self.border_value) + meta.update({'pad_shape': img.shape}) + return img, meta, bboxes + + +class BoundBoxes(_PairTransform): + + def __init__(self): + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + if bboxes is not None: + bboxes = ops.bound_bboxes(bboxes, img.shape[1::-1]) + return img, meta, bboxes + + +class ToTensor(_PairTransform): + + def __init__(self): + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes=None): + img = torch.from_numpy(img.transpose(2, 0, 1)).float() + if bboxes is not None: + bboxes = torch.from_numpy(bboxes).float() + return img, meta, bboxes + + +class PhotometricDistort(_PairTransform): + + def __init__(self, swap_channels=True): + self.swap_channels = swap_channels + self._swap_order = None + + def _process_query(self, img, meta, bboxes=None): + img = ops.photometric_distort(img, swap_channels=False) + if self.swap_channels and np.random.randint(2): + order = np.random.permutation(3) + img = img[..., order] + self._swap_order = order + else: + self._swap_order = None + return img, meta, bboxes + + def _process_gallary(self, img, meta, bboxes=None): + img = ops.photometric_distort(img, swap_channels=False) + if self.swap_channels and self._swap_order is not None: + img = img[..., self._swap_order] + return img, meta, bboxes + + +class RandomExpand(_PairTransform): + + def __init__(self, + mean=[123.675, 116.28, 103.53], + min_ratio=1, + max_ratio=4): + self.mean = mean + self.min_ratio = min_ratio + self.max_ratio = max_ratio + self._process_query = self._process + self._process_gallary = self._process + + def _process(self, img, meta, bboxes): + if bboxes is None: + raise ValueError('Unsupport None type of bboxes') + img, bboxes = ops.random_expand( + img, bboxes, self.mean, self.min_ratio, self.max_ratio) + return img, meta, bboxes + + +class RandomCrop(_PairTransform): + + def __init__(self, + min_ious=[0.1, 0.3, 0.5, 0.7, 0.9], + min_scale=0.3): + self.min_ious = min_ious + self.min_scale = min_scale + + def __call__(self, item): + item0 = item + for i in range(10): + item = copy.deepcopy(item0) + item['img_z'], item['gt_bboxes_z'], mask_z = ops.random_crop( + item['img_z'], item['gt_bboxes_z'], + self.min_ious, self.min_scale) + item['img_x'], item['gt_bboxes_x'], mask_x = ops.random_crop( + item['img_x'], item['gt_bboxes_x'], + self.min_ious, self.min_scale) + mask = mask_z & mask_x + if not mask.any(): + continue + item['gt_bboxes_z'] = item['gt_bboxes_z'][mask] + item['gt_bboxes_x'] = item['gt_bboxes_x'][mask] + return item + return item0 + + def _process_query(self, img, meta, bboxes): + raise NotImplementedError( + 'Separately processing query is not supported') + + def _process_gallary(self, img, meta, bboxes): + raise NotImplementedError( + 'Separately processing gallary is not supported') + + +@registry.register_module +class BasicPairTransforms(Compose): + + def __init__(self, + train=True, + scale=(1333, 800), + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + interp=None, + flip_p=0.5, + pad_divisor=32, + border_value=0): + if not train: + flip_p = 0. + interp = cv2.INTER_LINEAR if interp is None else interp + super(BasicPairTransforms, self).__init__(transforms=[ + Rescale(scale, interp), + Normalize(mean, std), + RandomFlip(flip_p), + PadToDivisor(pad_divisor, border_value), + BoundBoxes(), + ToTensor()]) + + def __call__(self, *args): + assert len(args) in [1, 3], 'Invalid number of arguments' + if len(args) == 3: + img_z, img_x, target = args + item = { + 'img_z': img_z, + 'img_x': img_x, + 'img_meta_z': {'ori_shape': img_z.shape}, + 'img_meta_x': {'ori_shape': img_x.shape}, + 'gt_bboxes_z': target['bboxes_z'], + 'gt_bboxes_x': target['bboxes_x']} + return super(BasicPairTransforms, self).__call__(item) + else: + return super(BasicPairTransforms, self).__call__(args[0]) + + +@registry.register_module +class ExtraPairTransforms(Compose): + + def __init__(self, + with_photometric=True, + with_expand=True, + with_crop=True, + with_basic=True, + swap_channels=True, + mean=[123.675, 116.28, 103.53], + min_ratio=1, + max_ratio=4, + min_ious=[0.1, 0.3, 0.5, 0.7, 0.9], + min_scale=0.3, + **kwargs): + transforms = [] + if with_photometric: + transforms += [PhotometricDistort(swap_channels)] + if with_expand: + transforms += [RandomExpand(mean, min_ratio, max_ratio)] + if with_crop: + transforms += [RandomCrop(min_ious, min_scale)] + if with_basic: + transforms += [BasicPairTransforms(**kwargs)] + super(ExtraPairTransforms, self).__init__(transforms) + + def __call__(self, *args): + assert len(args) in [1, 3], 'Invalid number of arguments' + if len(args) == 3: + img_z, img_x, target = args + item = { + 'img_z': img_z, + 'img_x': img_x, + 'img_meta_z': {'ori_shape': img_z.shape}, + 'img_meta_x': {'ori_shape': img_x.shape}, + 'gt_bboxes_z': target['bboxes_z'], + 'gt_bboxes_x': target['bboxes_x']} + return super(ExtraPairTransforms, self).__call__(item) + else: + return super(ExtraPairTransforms, self).__call__(args[0]) + + +@registry.register_module +class TTFNetTransforms(Compose): + + def __init__(self, + train=True, + scale=(512, 512), + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + interp=None, + flip_p=0.5, + pad_divisor=32, + border_value=0, + swap_channels=True): + if train: + transforms = [PhotometricDistort(swap_channels)] + else: + flip_p = 0. + interp = cv2.INTER_LINEAR if interp is None else interp + transforms = [] + transforms += [ + Resize(scale, interp), + Normalize(mean, std), + RandomFlip(flip_p), + PadToDivisor(pad_divisor, border_value), + BoundBoxes(), + ToTensor()] + super(TTFNetTransforms, self).__init__(transforms) + + def __call__(self, *args): + assert len(args) in [1, 3], 'Invalid number of arguments' + if len(args) == 3: + img_z, img_x, target = args + item = { + 'img_z': img_z, + 'img_x': img_x, + 'img_meta_z': {'ori_shape': img_z.shape}, + 'img_meta_x': {'ori_shape': img_x.shape}, + 'gt_bboxes_z': target['bboxes_z'], + 'gt_bboxes_x': target['bboxes_x']} + return super(TTFNetTransforms, self).__call__(item) + else: + return super(TTFNetTransforms, self).__call__(args[0]) diff --git a/utils/neuron/data/transforms/pair_transforms/siamfc_transforms.py b/utils/neuron/data/transforms/pair_transforms/siamfc_transforms.py new file mode 100755 index 0000000..8769a84 --- /dev/null +++ b/utils/neuron/data/transforms/pair_transforms/siamfc_transforms.py @@ -0,0 +1,133 @@ +import numbers +import torch +import torchvision.transforms as T +import numpy as np + +import neuron.ops as ops +from neuron.config import registry + + +__all__ = ['SiamFC_Transforms'] + + +class RandomResize(object): + + def __init__(self, max_scale=1.05): + self.max_scale = max_scale + + def __call__(self, img): + return ops.random_resize(img, self.max_scale) + + +class CenterCrop(object): + + def __init__(self, size): + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + self.size = size + + def __call__(self, img): + return ops.center_crop(img, self.size) + + +class RandomCrop(object): + + def __init__(self, size): + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + self.size = size + + def __call__(self, img): + return ops.simple_random_crop(img, self.size) + + +class ToTensor(object): + + def __call__(self, img): + return torch.from_numpy(img).float().permute(2, 0, 1) + + +@registry.register_module +class SiamFC_Transforms(object): + + def __init__(self, + exemplar_sz=127, + instance_sz=255, + context=0.5, + shift=8, + out_stride=8, + response_sz=15, + r_pos=16, + r_neg=0): + self.exemplar_sz = exemplar_sz + self.instance_sz = instance_sz + self.context = context + self.shift = shift + self.out_stride = out_stride + self.response_sz = response_sz + self.r_pos = r_pos + self.r_neg = r_neg + + # transforms for the query image + self.transforms_z = T.Compose([ + RandomResize(max_scale=1.05), + CenterCrop(size=instance_sz - shift), + RandomCrop(size=instance_sz - 2 * shift), + CenterCrop(size=exemplar_sz), + ToTensor()]) + + # transforms for the search image + self.transforms_x = T.Compose([ + RandomResize(max_scale=1.05), + CenterCrop(instance_sz - shift), + RandomCrop(instance_sz - 2 * shift), + ToTensor()]) + + def __call__(self, img_z, img_x, target): + # crop image pair and perform data augmentation + img_z = ops.crop_square( + img_z, target['bboxes_z'][0], + self.context, self.exemplar_sz, self.instance_sz) + img_x = ops.crop_square( + img_x, target['bboxes_x'][0], + self.context, self.exemplar_sz, self.instance_sz) + img_z = self.transforms_z(img_z) + img_x = self.transforms_x(img_x) + + # build training target + target = self._build_target(self.response_sz) + + return img_z, img_x, target + + def _build_target(self, response_sz): + # skip if same sized labels has already been created + response_sz = ops.make_pair(response_sz) + if hasattr(self, '_labels') and self._labels.size() == response_sz: + return self._labels + + def logistic_labels(x, y, r_pos, r_neg): + dist = np.abs(x) + np.abs(y) # block distance + labels = np.where(dist <= r_pos, + np.ones_like(x), + np.where(dist < r_neg, + np.ones_like(x) * 0.5, + np.zeros_like(x))) + return labels + + # distances along x- and y-axis + h, w = response_sz + x = np.arange(w) - (w - 1) / 2 + y = np.arange(h) - (h - 1) / 2 + x, y = np.meshgrid(x, y) + + # create logistic labels + r_pos = self.r_pos / self.out_stride + r_neg = self.r_neg / self.out_stride + labels = logistic_labels(x, y, r_pos, r_neg) + + # convert to tensors (add the channel dimension) + self._labels = torch.from_numpy(labels).float().unsqueeze(0) + + return self._labels diff --git a/utils/neuron/engine/__init__.py b/utils/neuron/engine/__init__.py new file mode 100755 index 0000000..8bf1764 --- /dev/null +++ b/utils/neuron/engine/__init__.py @@ -0,0 +1,4 @@ +from .logger import * +from .meter import * +from .trainer import * +from .inference import * diff --git a/utils/neuron/engine/inference.py b/utils/neuron/engine/inference.py new file mode 100755 index 0000000..e69de29 diff --git a/utils/neuron/engine/logger.py b/utils/neuron/engine/logger.py new file mode 100755 index 0000000..3b80e78 --- /dev/null +++ b/utils/neuron/engine/logger.py @@ -0,0 +1,59 @@ +import os.path as osp +import logging +import sys +from tensorboardX import SummaryWriter + + +class Logger(object): + LOG_LEVELS = { + 'CRITICAL': logging.CRITICAL, + 'ERROR': logging.ERROR, + 'WARNING': logging.WARNING, + 'INFO': logging.INFO, + 'DEBUG': logging.DEBUG, + 'NOTSET': logging.NOTSET} + + def __init__(self, log_dir, run_name, **kwargs): + # console and file logger + log_level = kwargs.pop('log_level', logging.DEBUG) + if isinstance(log_level, str): + log_level = self.LOG_LEVELS[log_level.upper()] + fmt = logging.Formatter( + '%(asctime)s %(levelname)s: %(message)s') + self._logger = logging.getLogger(run_name) + self._logger.setLevel(log_level) + # console handler + ch = logging.StreamHandler(stream=sys.stdout) + ch.setLevel(log_level) + ch.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + self._logger.addHandler(ch) + # file logger + log_file = osp.join(log_dir, run_name + '.log') + fh = logging.FileHandler(log_file) + fh.setLevel(log_level) + fh.setFormatter(logging.Formatter( + '%(asctime)s %(levelname)s: %(message)s')) + self._logger.addHandler(fh) + + # summary writer + self._writer = SummaryWriter(logdir=log_dir) + + def log(self, msg, level=logging.INFO): + self._logger.log(level, msg) + + def __getattr__(self, name): + try: + return object.__getattribute__(self, name) + except AttributeError: + if name in dir(self._writer): + return object.__getattribute__(self._writer, name) + elif name in dir(self._logger): + object.__getattribute__(self._logger, name) + else: + raise AttributeError( + '\'{}\' has no attribute \'{}\''.format( + self.__class__.__name__, name)) + + def close(self): + self._logger.close() + self._writer.close() diff --git a/utils/neuron/engine/meter.py b/utils/neuron/engine/meter.py new file mode 100755 index 0000000..0315409 --- /dev/null +++ b/utils/neuron/engine/meter.py @@ -0,0 +1,44 @@ +import addict + + +__all__ = ['Meter'] + + +class _AverageMeter(object): + + def __init__(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def update(self, val): + self.val = val + self.sum += val + self.count += 1 + self.avg = self.sum / self.count + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + def __repr__(self): + return '{:.3f}'.format(self.avg) + + +class Meter(addict.Dict): + + def update(self, metrics): + for k, v in metrics.items(): + if k in self.keys(): + self.__getitem__(k).update(v) + else: + meter = _AverageMeter() + meter.update(v) + self.__setitem__(k, meter) + + def reset(self): + for k in self.keys(): + self.__getitem__(k).reset() diff --git a/utils/neuron/engine/trainer.py b/utils/neuron/engine/trainer.py new file mode 100755 index 0000000..b34f157 --- /dev/null +++ b/utils/neuron/engine/trainer.py @@ -0,0 +1,337 @@ +import torch +import os +import os.path as osp +from datetime import datetime + +import neuron.ops as ops +from neuron.config import registry +from .meter import Meter +from .logger import Logger + + +class Trainer(object): + + def __init__(self, cfg): + # experimental information + self.name = '{}_{}'.format( + cfg.experiment, + datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) + self.work_dir = osp.join(cfg.work_dir, self.name) + if not osp.exists(self.work_dir): + os.makedirs(self.work_dir) + self.log_level = cfg.log_level + self.train_echo = cfg.train_echo + self.val_echo = cfg.val_echo + self.max_epochs = cfg.max_epochs + self.start_epoch = cfg.start_epoch + self.save_frequency = cfg.save_frequency + self.val_frequency = cfg.val_frequency + + # GPU usage + cuda = torch.cuda.is_available() + cfg.use_gpu = cfg.use_gpu if cuda else False + self.device = torch.device('cuda:0' if cfg.use_gpu else 'cpu') + # store configurations + self.cfg = cfg.deepcopy() + + # build model, loss and metrics + self.model = registry.build(cfg.model).to(self.device) + self.criterion = registry.build(cfg.loss).to(self.device) + if cfg.metric: + self.metric = registry.build(cfg.metric).to(self.device) + else: + self.metric = None + + # build optimizer + if cfg.param_grouper: + param_grouper = registry.build(cfg.param_grouper) + params = param_grouper(self.model, self.criterion) + else: + params = list(self.model.parameters()) + \ + list(self.criterion.parameters()) + params = [p for p in params if p.requires_grad] + cfg.optimizer.update({'params': params}) + self.optimizer = registry.build(cfg.optimizer) + + # build lr scheduler + if cfg.lr_scheduler: + cfg.lr_scheduler.update({'optimizer': self.optimizer}) + self.lr_scheduler = registry.build(cfg.lr_scheduler) + else: + self.lr_scheduler = None + + # build training, validation and test data + self.train_data = self._build_dataset(cfg.train_data) + self.val_data = self._build_dataset(cfg.val_data) + self.test_data = self._build_dataset(cfg.test_data) + + # build evaluator + if cfg.evaluator: + cfg.evaluator.update({'dataset': self.test_data}) + self.evaluator = registry.build(cfg.evaluator) + else: + self.evaluator = None + + # state variables + self._train_epoch = -1 + self._train_iter = -1 + self._val_epoch = -1 + self._val_iter = -1 + self._train_meters = Meter() + self._val_meters = Meter() + self._logger = Logger( + self.work_dir, self.name, log_level=self.log_level) + + def train(self): + self._hook_started() + for epoch in range(self.start_epoch, self.max_epochs): + self.train_epoch(self.train_data, epoch=epoch) + if ((epoch + 1) % self.val_frequency == 0 or \ + (epoch + 1) == self.max_epochs) and \ + self.val_data is not None: + self.val_epoch(self.val_data, epoch=epoch) + self._hook_completed() + + @torch.enable_grad() + def train_epoch(self, train_data, epoch): + self._set_train(True) + self._hook_epoch_started(epoch=epoch) + for it, batch in enumerate(train_data): + self._hook_iter_started(iter_=it) + loss = self.train_step(batch) + self._hook_iter_completed(metrics=loss) + self._hook_epoch_completed() + + @torch.enable_grad() + def train_step(self, batch): + self._set_train(True) + batch = ops.put_device(batch, self.device) + + # forward pass + output = ops.adaptive_apply(self.model.forward_train, batch) + + # evaluate loss and ensure it to be a dictionary + loss = ops.adaptive_apply(self.criterion, output) + if isinstance(loss, torch.Tensor): + loss = {'loss': loss} + assert isinstance(loss, dict) + + # optimization step + self.optimizer.zero_grad() + loss['loss'].backward() + self.optimizer.step() + + # evaluate metrics + if self.metric is not None: + metrics = ops.adaptive_apply( + self.metric, ops.detach(output)) + loss.update(metrics) + + # convert to CPU arrays or scalars + for k, v in loss.items(): + if not isinstance(v, torch.Tensor): + continue + if v.numel() == 1: + loss[k] = v.item() + else: + loss[k] = v.detach().cpu().numpy() + + return loss + + @torch.no_grad() + def val_epoch(self, val_data, epoch): + self._set_train(False) + self._hook_val_epoch_started(epoch=epoch) + for it, batch in enumerate(val_data): + self._hook_val_iter_started(iter_=it) + loss = self.val_step(batch) + self._hook_val_iter_completed(metrics=loss) + self._hook_val_epoch_completed() + + @torch.no_grad() + def val_step(self, batch): + self._set_train(False) + batch = ops.put_device(batch, self.device) + + # forward pass + output = ops.adaptive_apply(self.model.forward_val, batch) + + # evaluate loss and ensure it to be a dictionary + loss = ops.adaptive_apply(self.criterion, output) + if isinstance(loss, torch.Tensor): + loss = {'loss': loss} + assert isinstance(loss, dict) + + # evaluate metrics + if self.metric is not None: + metrics = ops.adaptive_apply( + self.metric, ops.detach(output)) + loss.update(metrics) + + # convert to CPU arrays or scalars + for k, v in loss.items(): + if not isinstance(v, torch.Tensor): + continue + if v.numel() == 1: + loss[k] = v.item() + else: + loss[k] = v.detach().cpu().numpy() + + return loss + + @torch.no_grad() + def test(self): + self._set_train(False) + if self.evaluator is None: + raise ValueError('The evaluator is not configured') + self.evaluator.run(self.model) + self.evaluator.report(self.model.name) + + def _set_train(self, flag=True): + if flag: + self.model.train() + self.criterion.train() + else: + self.model.eval() + self.criterion.eval() + + def _build_dataset(self, cfg): + if not cfg: + return None + + if 'DataLoader' in cfg.type: + dataset = registry.build(cfg.dataset) + cfg.update({'dataset': dataset}) + if 'sampler' in cfg: + if 'shuffle' in cfg: + cfg.shuffle = False + cfg.sampler.update({'dataset': dataset}) + + return registry.build(cfg) + + def _adaptive_apply(self, func, args): + if isinstance(args, (tuple, list)): + return func(*args) + elif isinstance(args, dict): + return func(**args) + else: + return func(args) + + def _hook_started(self): + self._logger.log( + 'Experiment[{}]: Training started...'.format(self.name)) + self._logger.log('Configurations:\n {}'.format(repr(self.cfg))) + + def _hook_completed(self): + self._logger.log( + 'Experiment[{}]: Training completed!'.format(self.name)) + + def _hook_epoch_started(self, epoch): + # store epoch + self._train_epoch = epoch + # update lr if applicable + if self.lr_scheduler: + self.lr_scheduler.step(epoch=epoch) + # log text + self._logger.log('Epoch[{}/{}]: Training started...'.format( + epoch + 1, self.max_epochs)) + + def _hook_epoch_completed(self): + # log text + self._logger.log('Epoch[{}/{}]: Training completed!'.format( + self._train_epoch + 1, self.max_epochs)) + text = '\t' + for name in self.train_echo: + if not name in self._train_meters: + continue + text += ' {}: {:.3f}'.format( + name, self._train_meters[name].avg) + self._logger.log(text) + # log metrics + for k, v in self._train_meters.items(): + self._logger.add_scalar( + 'epoch_train/' + k, v.avg, + global_step=self._train_epoch) + # save model + if (self._train_epoch + 1) % self.save_frequency == 0 or \ + (self._train_epoch + 1) == self.max_epochs: + model_file = osp.join( + self.work_dir, + 'model_{}.pth'.format(self._train_epoch + 1)) + torch.save(self.model, model_file) + # reset meters + self._train_meters.reset() + + def _hook_iter_started(self, iter_): + # store iter + self._train_iter = iter_ + # update lr if applicable + if getattr(self.lr_scheduler, 'step_iter', None) is not None: + self.lr_scheduler.step_iter(iter_=iter_) + + def _hook_iter_completed(self, metrics): + # log text + text = 'Epoch[{}/{}] Iter[{}/{}]'.format( + self._train_epoch + 1, self.max_epochs, + self._train_iter + 1, len(self.train_data)) + for name in self.train_echo: + if not name in metrics: + continue + text += ' {}: {:.3f}'.format(name, metrics[name]) + self._logger.log(text) + # log metrics + for k, v in metrics.items(): + self._logger.add_scalar('iter_train/' + k, v) + # update meters + self._train_meters.update(metrics) + + def _hook_val_epoch_started(self, epoch): + # store epoch + self._val_epoch = epoch + # log text + self._logger.log( + 'Val Epoch[{}/{}]: Validation started...'.format( + epoch + 1, self.max_epochs)) + + def _hook_val_epoch_completed(self): + # log text + self._logger.log( + 'Val Epoch[{}/{}]: Validation completed!'.format( + self._val_epoch + 1, self.max_epochs)) + text = '\t' + for name in self.val_echo: + if not name in self._val_meters: + continue + text += ' {}: {:.3f}'.format( + name, self._val_meters[name].avg) + self._logger.log(text) + # log metrics + for k, v in self._val_meters.items(): + self._logger.add_scalar( + 'epoch_val/' + k, v.avg, + global_step=self._val_epoch) + # reset meters + self._val_meters.reset() + + def _hook_val_iter_started(self, iter_): + # store iter + self._val_iter = iter_ + + def _hook_val_iter_completed(self, metrics): + # log text + text = 'Val Epoch[{}/{}] Iter[{}/{}]'.format( + self._val_epoch + 1, self.max_epochs, + self._val_iter + 1, len(self.val_data)) + for name in self.val_echo: + if not name in metrics: + continue + text += ' {}: {:.3f}'.format(name, metrics[name]) + self._logger.log(text) + # log metrics + for k, v in metrics.items(): + self._logger.add_scalar('iter_val/' + k, v) + # update meters + self._val_meters.update(metrics) + + def _hook_exception_raised(self): + pass diff --git a/utils/neuron/models/__init__.py b/utils/neuron/models/__init__.py new file mode 100755 index 0000000..e0823cd --- /dev/null +++ b/utils/neuron/models/__init__.py @@ -0,0 +1,9 @@ +# network modules +from .backbones import * +from .heads import * +from .losses import * +from .metrics import * +# computer vision models +from .model import Model +from .trackers import * +from .reid import * diff --git a/utils/neuron/models/backbones/__init__.py b/utils/neuron/models/backbones/__init__.py new file mode 100755 index 0000000..d7ef8a9 --- /dev/null +++ b/utils/neuron/models/backbones/__init__.py @@ -0,0 +1,3 @@ +from .backbone import Backbone +from .alexnet import * +from .resnet import * diff --git a/utils/neuron/models/backbones/alexnet.py b/utils/neuron/models/backbones/alexnet.py new file mode 100755 index 0000000..9093316 --- /dev/null +++ b/utils/neuron/models/backbones/alexnet.py @@ -0,0 +1,195 @@ +import torch.nn as nn +from collections import OrderedDict + +from .backbone import Backbone +from neuron.config import registry + + +__all__ = ['AlexNetV1', 'AlexNetV2', 'AlexNetV3'] + + +class _BatchNorm2d(nn.BatchNorm2d): + + def __init__(self, num_features, *args, **kwargs): + super(_BatchNorm2d, self).__init__( + num_features, *args, eps=1e-6, momentum=0.05, **kwargs) + + +class _AlexNet(Backbone): + + def __init__(self, out_layers='conv5'): + super(_AlexNet, self).__init__() + self._check_out_layers(out_layers) + self.out_layers = out_layers + + def forward(self, x, out_layers=None): + if out_layers is None: + out_layers = self.out_layers + self._check_out_layers(out_layers) + outputs = OrderedDict() + + # conv1 + x = self.conv1(x) + if self._add_and_check('conv1', out_layers, outputs, x): + if isinstance(out_layers, str): + return outputs[out_layers] + else: + return outputs + + # conv2 + x = self.conv2(x) + if self._add_and_check('conv2', out_layers, outputs, x): + if isinstance(out_layers, str): + return outputs[out_layers] + else: + return outputs + + # conv3 + x = self.conv3(x) + if self._add_and_check('conv3', out_layers, outputs, x): + if isinstance(out_layers, str): + return outputs[out_layers] + else: + return outputs + + # conv4 + x = self.conv4(x) + if self._add_and_check('conv4', out_layers, outputs, x): + if isinstance(out_layers, str): + return outputs[out_layers] + else: + return outputs + + # conv5 + x = self.conv5(x) + if self._add_and_check('conv5', out_layers, outputs, x): + if isinstance(out_layers, str): + return outputs[out_layers] + else: + return outputs + + def _check_out_layers(self, out_layers): + valid_layers = ['conv1', 'conv2', 'conv3', 'conv4', 'conv5'] + if isinstance(out_layers, str): + assert out_layers in valid_layers + elif isinstance(out_layers, (list, tuple)): + assert all([l in valid_layers for l in out_layers]) + else: + raise ValueError('Invalid type of "out_layers".') + + def _add_and_check(self, name, out_layers, outputs, x): + if isinstance(out_layers, str): + out_layers = [out_layers] + assert isinstance(out_layers, (list, tuple)) + if name in out_layers: + outputs[name] = x + return len(out_layers) == len(outputs) + + +@registry.register_module +class AlexNetV1(_AlexNet): + _out_stride = 8 + + def __init__(self, out_layers='conv5'): + super(AlexNetV1, self).__init__(out_layers=out_layers) + self.conv1 = nn.Sequential( + nn.Conv2d(3, 96, 11, 2), + _BatchNorm2d(96), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2)) + self.conv2 = nn.Sequential( + nn.Conv2d(96, 256, 5, 1, groups=2), + _BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2)) + self.conv3 = nn.Sequential( + nn.Conv2d(256, 384, 3, 1), + _BatchNorm2d(384), + nn.ReLU(inplace=True)) + self.conv4 = nn.Sequential( + nn.Conv2d(384, 384, 3, 1, groups=2), + _BatchNorm2d(384), + nn.ReLU(inplace=True)) + self.conv5 = nn.Sequential( + nn.Conv2d(384, 256, 3, 1, groups=2)) + + @property + def out_channels(self): + return self.conv5[-1].out_channels + + @property + def out_stride(self): + return self._out_stride + + +@registry.register_module +class AlexNetV2(_AlexNet): + _out_stride = 4 + + def __init__(self, out_layers='conv5'): + super(AlexNetV2, self).__init__(out_layers=out_layers) + self.conv1 = nn.Sequential( + nn.Conv2d(3, 96, 11, 2), + _BatchNorm2d(96), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2)) + self.conv2 = nn.Sequential( + nn.Conv2d(96, 256, 5, 1, groups=2), + _BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 1)) + self.conv3 = nn.Sequential( + nn.Conv2d(256, 384, 3, 1), + _BatchNorm2d(384), + nn.ReLU(inplace=True)) + self.conv4 = nn.Sequential( + nn.Conv2d(384, 384, 3, 1, groups=2), + _BatchNorm2d(384), + nn.ReLU(inplace=True)) + self.conv5 = nn.Sequential( + nn.Conv2d(384, 32, 3, 1, groups=2)) + + @property + def out_channels(self): + return self.conv5[-1].out_channels + + @property + def out_stride(self): + return self._out_stride + + +@registry.register_module +class AlexNetV3(_AlexNet): + _out_stride = 8 + + def __init__(self, out_layers='conv5'): + super(AlexNetV3, self).__init__(out_layers=out_layers) + self.conv1 = nn.Sequential( + nn.Conv2d(3, 192, 11, 2), + _BatchNorm2d(192), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2)) + self.conv2 = nn.Sequential( + nn.Conv2d(192, 512, 5, 1), + _BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.MaxPool2d(3, 2)) + self.conv3 = nn.Sequential( + nn.Conv2d(512, 768, 3, 1), + _BatchNorm2d(768), + nn.ReLU(inplace=True)) + self.conv4 = nn.Sequential( + nn.Conv2d(768, 768, 3, 1), + _BatchNorm2d(768), + nn.ReLU(inplace=True)) + self.conv5 = nn.Sequential( + nn.Conv2d(768, 512, 3, 1), + _BatchNorm2d(512)) + + @property + def out_channels(self): + return self.conv5[-1].num_features + + @property + def out_stride(self): + return self._out_stride diff --git a/utils/neuron/models/backbones/backbone.py b/utils/neuron/models/backbones/backbone.py new file mode 100755 index 0000000..e838a3b --- /dev/null +++ b/utils/neuron/models/backbones/backbone.py @@ -0,0 +1,14 @@ +import torch.nn as nn +import abc + + +class Backbone(nn.Module): + __metaclass__ = abc.ABCMeta + + @abc.abstractproperty + def out_channels(self): + raise NotImplementedError + + @abc.abstractproperty + def out_stride(self): + raise NotImplementedError diff --git a/utils/neuron/models/backbones/resnet.py b/utils/neuron/models/backbones/resnet.py new file mode 100755 index 0000000..5fe2566 --- /dev/null +++ b/utils/neuron/models/backbones/resnet.py @@ -0,0 +1,239 @@ +import math +import torch.nn as nn +import torch.utils.model_zoo as model_zoo + +from .backbone import Backbone +from neuron.config import registry + + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth'} + + +def conv3x3(in_planes, out_planes, stride=1): + "3x3 convolution with padding" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, + stride=stride, padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(Backbone): + + def __init__(self, block, layers, last_stride=2): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, + padding=3, bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], + stride=last_stride) + self._init_weights() + + # store model's output channels and stride + self._out_channels = 512 * block.expansion + self._out_stride = 16 * last_stride + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + return x + + @property + def out_channels(self): + return self._out_channels + + @property + def out_stride(self): + return self._out_stride + + def _init_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + +@registry.register_module +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + model.load_state_dict( + model_zoo.load_url(model_urls['resnet18']), + strict=False) + return model + + +@registry.register_module +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict( + model_zoo.load_url(model_urls['resnet34']), + strict=False) + return model + + +@registry.register_module +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + model.load_state_dict( + model_zoo.load_url(model_urls['resnet50']), + strict=False) + return model + + +@registry.register_module +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + model.load_state_dict( + model_zoo.load_url(model_urls['resnet101']), + strict=False) + return model + + +@registry.register_module +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + model.load_state_dict( + model_zoo.load_url(model_urls['resnet152']), + strict=False) + return model diff --git a/utils/neuron/models/heads/__init__.py b/utils/neuron/models/heads/__init__.py new file mode 100755 index 0000000..5f0bf7e --- /dev/null +++ b/utils/neuron/models/heads/__init__.py @@ -0,0 +1 @@ +from .xcorr import * diff --git a/utils/neuron/models/heads/xcorr.py b/utils/neuron/models/heads/xcorr.py new file mode 100755 index 0000000..3ee6c30 --- /dev/null +++ b/utils/neuron/models/heads/xcorr.py @@ -0,0 +1,40 @@ +import numbers +import torch +import torch.nn as nn +from collections import OrderedDict + +from neuron.config import registry +from neuron import ops + + +__all__ = ['XCorr'] + + +@registry.register_module +class XCorr(nn.Module): + + def __init__(self, scale=0.001, learnable=False): + assert isinstance(scale, (numbers.Number, list)) + if isinstance(scale, numbers.Number): + scale = [scale] + super(XCorr, self).__init__() + + # store logarithm of scale to avoid explosion during training + self.scale = nn.Parameter(torch.Tensor(scale).log()) + if not learnable: + self.scale.requires_grad = False + + def forward(self, z, x): + assert isinstance(z, (torch.Tensor, OrderedDict)) + scale = self.scale.exp() + + if isinstance(z, torch.Tensor): + assert len(scale) == 1 + out = scale * ops.fast_xcorr(z, x) + elif isinstance(z, OrderedDict): + if len(scale) == 1: + scale = scale.expand(len(z)) + assert len(scale) == len(z) + out = sum([scale[i] * ops.fast_xcorr(z[k], x[k]) + for i, k in enumerate(z)]) + return out diff --git a/utils/neuron/models/losses/__init__.py b/utils/neuron/models/losses/__init__.py new file mode 100755 index 0000000..522b8c2 --- /dev/null +++ b/utils/neuron/models/losses/__init__.py @@ -0,0 +1,2 @@ +from .losses import * +from .multi_task_losses import * diff --git a/utils/neuron/models/losses/losses.py b/utils/neuron/models/losses/losses.py new file mode 100755 index 0000000..cef2799 --- /dev/null +++ b/utils/neuron/models/losses/losses.py @@ -0,0 +1,207 @@ +import torch +import torch.nn as nn + +import neuron.ops as ops +from neuron.config import registry + + +__all__ = ['BalancedBCELoss', 'FocalLoss', 'GHMC_Loss', 'OHEM_BCELoss', + 'LabelSmoothLoss', 'SmoothL1Loss', 'IoULoss', 'GHMR_Loss', + 'TripletLoss', 'CenterLoss'] + + +@registry.register_module +class BalancedBCELoss(nn.Module): + + def __init__(self, neg_weight=1.): + super(BalancedBCELoss, self).__init__() + self.neg_weight = neg_weight + + def forward(self, input, target): + return ops.balanced_bce_loss(input, target, self.neg_weight) + + +@registry.register_module +class FocalLoss(nn.Module): + + def __init__(self, alpha=0.25, gamma=2.): + super(FocalLoss, self).__init__() + self.alpha = alpha + self.gamma = gamma + + def forward(self, input, target): + return ops.focal_loss(input, target, self.alpha, self.gamma) + + +@registry.register_module +class GHMC_Loss(nn.Module): + + def __init__(self, bins=30, momentum=0.5): + super(GHMC_Loss, self).__init__() + self.bins = bins + self.momentum = momentum + + def forward(self, input, target): + return ops.ghmc_loss(input, target, self.bins, self.momentum) + + +@registry.register_module +class OHEM_BCELoss(nn.Module): + + def __init__(self, neg_ratio=3.): + super(OHEM_BCELoss, self).__init__() + self.neg_ratio = neg_ratio + + def forward(self, input, target): + return ops.ohem_bce_loss(input, target, self.neg_ratio) + + +@registry.register_module +class LabelSmoothLoss(nn.Module): + + def __init__(self, num_classes, eps=0.1, calc_metrics=False): + super(LabelSmoothLoss, self).__init__() + self.num_classes = num_classes + self.eps = eps + self.calc_metrics = calc_metrics + + def forward(self, input, target): + loss = ops.label_smooth_loss( + input, target, self.num_classes, self.eps) + + if self.calc_metrics and not self.training: + metrics = ops.topk_precision(input, target) + loss = {'loss': loss} + loss.update(metrics) + + return loss + + +@registry.register_module +class SmoothL1Loss(nn.Module): + + def __init__(self, beta=1. / 9): + super(SmoothL1Loss, self).__init__() + self.beta = beta + + def forward(self, input, target): + return ops.smooth_l1_loss(input, target, self.beta) + + +@registry.register_module +class IoULoss(nn.Module): + + def forward(self, input, target, weight=None): + return ops.iou_loss(input, target, weight) + + +@registry.register_module +class GHMR_Loss(nn.Module): + + def __init__(self, mu=0.02, bins=10, momentum=0): + super(GHMR_Loss, self).__init__() + self.mu = mu + self.bins = bins + self.momentum = momentum + + def forward(self, input, target): + return ops.ghmr_loss(input, target) + + +@registry.register_module +class TripletLoss(nn.Module): + + def __init__(self, margin=None, normalize_feats=False, calc_metrics=False): + super(TripletLoss, self).__init__() + self.margin = margin + if margin is not None: + self.ranking_loss = nn.MarginRankingLoss(margin=margin) + else: + self.ranking_loss = nn.SoftMarginLoss() + self.normalize_feats = normalize_feats + self.calc_metrics = calc_metrics + + def forward(self, input, target): + if self.normalize_feats: + input = self._normalize(input, dim=-1) + dist_mat = ops.euclidean(input, input, sqrt=True) + dist_ap, dist_an = self._ohem(dist_mat, target) + y = dist_an.new_ones(dist_an.size()) + + if self.margin is not None: + loss = self.ranking_loss(dist_an, dist_ap, y) + else: + loss = self.ranking_loss(dist_an - dist_ap, y) + + if self.calc_metrics and not self.training: + metrics = ops.r1_map(dist_mat, target) + loss = {'loss': loss} + loss.update(metrics) + + return loss + + def _normalize(self, x, dim=-1): + norm = torch.norm(x, 2, dim=dim, keepdim=True) + x = x / (norm.expand_as(x) + 1e-12) + return x + + def _ohem(self, dist_mat, target, return_indices=False): + n = dist_mat.size(0) + + label_mat = target.expand(n, n) + pos_mask = label_mat.eq(label_mat.t()) + neg_mask = label_mat.ne(label_mat.t()) + + dist_ap, indices_p = torch.max( + dist_mat[pos_mask].contiguous().view(n, -1), + dim=1, keepdim=True) + dist_an, indices_n = torch.min( + dist_mat[neg_mask].contiguous().view(n, -1), + dim=1, keepdim=True) + dist_ap = dist_ap.squeeze(1) + dist_an = dist_an.squeeze(1) + + if return_indices: + indices = target.new_zeros( + target.size()).copy_(torch.arange(n).long()) + indices = indices.unsqueeze(0).expand(n, n) + + indices_p = torch.gather( + indices[pos_mask].contiguous().view(n, -1), + 1, indices_p).squeeze(1) + indices_n = torch.gather( + indices[neg_mask].contiguous().view(n, -1), + 1, indices_n).squeeze(1) + + return dist_ap, dist_an, indices_p, indices_n + else: + return dist_ap, dist_an + + +@registry.register_module +class CenterLoss(nn.Module): + + def __init__(self, num_classes, num_channels): + super(CenterLoss, self).__init__() + self.num_classes = num_classes + self.num_channels = num_channels + self.centers = nn.Parameter( + torch.randn(num_classes, num_channels)) + + def forward(self, input, target): + assert len(input) == len(target) + + self.centers = self.centers.to(input.device) + dist_mat = ops.euclidean(input, self.centers, sqrt=False) + + classes = torch.arange(self.num_classes).long() + classes = classes.to(input.device) + + n = len(input) + target = target.unsqueeze(1).expand(n, self.num_classes) + mask = target.eq(classes.expand(n, self.num_classes)) + + dist_mat = dist_mat * mask.float() + loss = dist_mat.clamp_(min=1e-12, max=1e+12).sum() / n + + return loss diff --git a/utils/neuron/models/losses/multi_task_losses.py b/utils/neuron/models/losses/multi_task_losses.py new file mode 100755 index 0000000..7eca4f3 --- /dev/null +++ b/utils/neuron/models/losses/multi_task_losses.py @@ -0,0 +1,90 @@ +import torch +import torch.nn as nn + +from neuron.config import registry + + +__all__ = ['MultiTaskLoss', 'ReID_Loss'] + + +@registry.register_module +class MultiTaskLoss(nn.Module): + + def __init__(self, **kwargs): + assert len(kwargs) > 0 + super(MultiTaskLoss, self).__init__() + self.losses = {} + for k, v in kwargs.items(): + self.losses[k] = (v.loss, v.weight) + + def forward(self, input, target): + loss = {} + for name, (loss_fn, weight) in self.losses.items(): + loss_i = loss_fn(input, target) + if isinstance(loss_i, torch.Tensor): + loss[name] = loss_i + elif isinstance(loss_i, dict): + loss[name] = loss_i.pop('loss') + for k, v in loss_i.items(): + if k in loss: + raise KeyError( + 'The criterion name {} is ambiguous since' + 'it appears in multiple losses'.format(k)) + else: + loss[k] = v + else: + raise ValueError( + 'Expected the output of loss {} to be a Tensor' + 'or a dict, but got {}'.format( + name, loss_i.__class__.__name__)) + loss['loss'] += loss[name] * weight + return loss + + +@registry.register_module +class ReID_Loss(MultiTaskLoss): + + def __init__(self, **kwargs): + for name in kwargs: + assert 'cls' in name or 'rank' in name + super(ReID_Loss, self).__init__(**kwargs) + + def forward(self, *args): + if len(args) == 2: + feats, labels = args + elif len(args) == 3: + scores, feats, labels = args + else: + raise ValueError( + 'Expected 2 or 3 inputs, but got {}'.format(len(args))) + + loss = {'loss': 0.} + for name, (loss_fn, weight) in self.losses.items(): + if 'cls' in name: + if len(args) == 2: + continue + loss_i = loss_fn(scores, labels) + elif 'rank' in name: + loss_i = loss_fn(feats, labels) + else: + raise KeyError('Unsupport loss {}'.format(name)) + + if isinstance(loss_i, torch.Tensor): + loss[name] = loss_i + elif isinstance(loss_i, dict): + loss[name] = loss_i.pop('loss') + for k, v in loss_i.items(): + if k in loss: + raise KeyError( + 'The criterion name {} is ambiguous since' + 'it appears in multiple losses'.format(k)) + else: + loss[k] = v + else: + raise ValueError( + 'Expected the output of loss {} to be a Tensor' + 'or a dict, but got {}'.format( + name, loss_i.__class__.__name__)) + + loss['loss'] += loss[name] * weight + return loss diff --git a/utils/neuron/models/metrics/__init__.py b/utils/neuron/models/metrics/__init__.py new file mode 100755 index 0000000..bf9d3ac --- /dev/null +++ b/utils/neuron/models/metrics/__init__.py @@ -0,0 +1,2 @@ +from .metrics import * +from .multi_task_metrics import * diff --git a/utils/neuron/models/metrics/metrics.py b/utils/neuron/models/metrics/metrics.py new file mode 100755 index 0000000..17acc33 --- /dev/null +++ b/utils/neuron/models/metrics/metrics.py @@ -0,0 +1,27 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +import neuron.ops as ops +from neuron.config import registry + + +@registry.register_module +class Precision(nn.Module): + + def forward(self, scores, labels): + return ops.topk_precision(scores, labels) + + +@registry.register_module +class R1_mAP(nn.Module): + + def __init__(self, normalize_feats=False): + super(R1_mAP, self).__init__() + self.normalize_feats = normalize_feats + + def forward(self, feats, labels): + if self.normalize_feats: + feats = F.normalize(feats, dim=1, p=2) + dist_mat = ops.euclidean(feats, feats, sqrt=False) + return ops.r1_map(dist_mat, labels) diff --git a/utils/neuron/models/metrics/multi_task_metrics.py b/utils/neuron/models/metrics/multi_task_metrics.py new file mode 100755 index 0000000..82d9c38 --- /dev/null +++ b/utils/neuron/models/metrics/multi_task_metrics.py @@ -0,0 +1,30 @@ +import torch +import torch.nn as nn + +import neuron.ops as ops +from neuron.config import registry + + +@registry.register_module +class ReID_Metric(nn.Module): + + def __init__(self, metric_cls, metric_rank): + super(ReID_Metric, self).__init__() + self.metric_cls = metric_cls + self.metric_rank = metric_rank + + def forward(self, *args): + if len(args) == 2: + scores = None + feats, labels = args + elif len(args) == 3: + scores, feats, labels = args + else: + raise ValueError('Expected to have 2 or 3 inputs,' + 'but got {}'.format(len(args))) + + metrics = self.metric_rank(feats, labels) + if scores is not None: + metrics.update(self.metric_cls(scores, labels)) + + return metrics diff --git a/utils/neuron/models/model.py b/utils/neuron/models/model.py new file mode 100755 index 0000000..d6c34fd --- /dev/null +++ b/utils/neuron/models/model.py @@ -0,0 +1,18 @@ +import torch.nn as nn +import abc + + +class Model(nn.Module): + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def forward_train(self, train_batch): + raise NotImplementedError + + @abc.abstractmethod + def forward_val(self, val_batch): + raise NotImplementedError + + @abc.abstractmethod + def forward_test(self, test_data, visualize=False): + raise NotImplementedError diff --git a/utils/neuron/models/reid/__init__.py b/utils/neuron/models/reid/__init__.py new file mode 100755 index 0000000..f32a949 --- /dev/null +++ b/utils/neuron/models/reid/__init__.py @@ -0,0 +1 @@ +from .reid_baseline import * diff --git a/utils/neuron/models/reid/reid_baseline.py b/utils/neuron/models/reid/reid_baseline.py new file mode 100755 index 0000000..8b5e9b8 --- /dev/null +++ b/utils/neuron/models/reid/reid_baseline.py @@ -0,0 +1,52 @@ +import torch.nn as nn + +import neuron.ops as ops +from neuron.config import registry +from neuron.models.model import Model + + +__all__ = ['ReID_Baseline'] + + +@registry.register_module +class ReID_Baseline(Model): + + def __init__(self, backbone, num_classes): + super(ReID_Baseline, self).__init__() + + # build network + self.backbone = backbone + self.pool = nn.AdaptiveAvgPool2d(1) + self.neck = nn.BatchNorm1d(backbone.out_channels) + self.neck.bias.requires_grad_(False) # no shift + self.classifier = nn.Linear( + backbone.out_channels, num_classes, bias=False) + self.num_classes = num_classes + + # initialize weights + self.neck.apply(ops.kaiming_init) + self.classifier.apply(ops.classifier_init) + + def forward(self, x, training=None): + x = self.pool(self.backbone(x)).view(len(x), -1) + x_neck = self.neck(x) + + if training is None: + training = self.training + if training: + scores = self.classifier(x_neck) + return scores, x + else: + return x_neck + + def forward_train(self, img, target): + scores, feats = self.forward(img, training=True) + return scores, feats, target['label'] + + def forward_val(self, img, target): + feats = self.forward(img, training=False) + return feats, target['label'] + + def forward_test(self, img, target): + feats = self.forward(img, training=False) + return feats, target['label'] diff --git a/utils/neuron/models/trackers/__init__.py b/utils/neuron/models/trackers/__init__.py new file mode 100755 index 0000000..b16f7e4 --- /dev/null +++ b/utils/neuron/models/trackers/__init__.py @@ -0,0 +1,3 @@ +from .tracker import * +from ._dummy import * +from .siamfc import * diff --git a/utils/neuron/models/trackers/_dummy.py b/utils/neuron/models/trackers/_dummy.py new file mode 100755 index 0000000..51f574e --- /dev/null +++ b/utils/neuron/models/trackers/_dummy.py @@ -0,0 +1,33 @@ +from neuron.config import registry +from .tracker import Tracker, OxUvA_Tracker + + +__all__ = ['DummyTracker', 'DummyOxUvA_Tracker'] + + +@registry.register_module +class DummyTracker(Tracker): + + def __init__(self): + super(DummyTracker, self).__init__( + name='Dummy', is_deterministic=True, input_type='file') + + def init(self, img, init_bbox): + self.bbox = init_bbox + + def update(self, img): + return self.bbox + + +@registry.register_module +class DummyOxUvA_Tracker(OxUvA_Tracker): + + def __init__(self): + super(DummyOxUvA_Tracker, self).__init__( + name='Dummy', is_deterministic=True, input_type='file') + + def init(self, img, init_bbox): + self.bbox = init_bbox + + def update(self, img): + return self.bbox, 1.0, True diff --git a/utils/neuron/models/trackers/siamfc.py b/utils/neuron/models/trackers/siamfc.py new file mode 100755 index 0000000..9ecef8d --- /dev/null +++ b/utils/neuron/models/trackers/siamfc.py @@ -0,0 +1,133 @@ +import torch +import numpy as np +import cv2 + +import neuron.ops as ops +from neuron.config import registry +from .tracker import Tracker + + +__all__ = ['TrackerSiamFC'] + + +@registry.register_module +class TrackerSiamFC(Tracker): + + def __init__(self, backbone, head, cfg): + super(TrackerSiamFC, self).__init__( + name=cfg.get('name', 'SiamFC'), + is_deterministic=True) + self.backbone = backbone + self.head = head + self.cfg = cfg + + def forward(self, z, x): + z = self.backbone(z) + x = self.backbone(x) + return self.head(z, x) + + def forward_train(self, img_z, img_x, target): + pred = self.forward(img_z, img_x) + return pred, target + + def forward_val(self, img_z, img_x, target): + pred = self.forward(img_z, img_x) + return pred, target + + @torch.no_grad() + def init(self, img, init_bbox): + self.eval() + + bbox = init_bbox.copy() + self.center = (bbox[:2] + bbox[2:]) / 2. + self.target_sz = bbox[2:] - bbox[:2] + 1 + + # create hanning window + self.upscale_sz = self.cfg.response_up * self.cfg.response_sz + self.hann_window = np.outer( + np.hanning(self.upscale_sz), + np.hanning(self.upscale_sz)) + self.hann_window /= self.hann_window.sum() + + # search scale factors + self.scale_factors = self.cfg.scale_step ** np.linspace( + -(self.cfg.scale_num // 2), + self.cfg.scale_num // 2, self.cfg.scale_num) + + # exemplar and search sizes + context = self.cfg.context * np.sum(self.target_sz) + self.z_sz = np.sqrt(np.prod(self.target_sz + context)) + self.x_sz = self.z_sz * \ + self.cfg.instance_sz / self.cfg.exemplar_sz + + # exemplar image + self.avg_color = np.mean(img, axis=(0, 1)) + z = ops.crop_and_resize( + img, self.center, self.z_sz, + out_size=self.cfg.exemplar_sz, + border_value=self.avg_color) + + # exemplar features + device = next(self.backbone.parameters()).device + z = torch.from_numpy(z).to( + device).permute(2, 0, 1).unsqueeze(0).float() + self.template = self.backbone(z) + + @torch.no_grad() + def update(self, img): + self.eval() + + # search images + x = [ops.crop_and_resize( + img, self.center, self.x_sz * f, + out_size=self.cfg.instance_sz, + border_value=self.avg_color) for f in self.scale_factors] + device = next(self.backbone.parameters()).device + x = torch.from_numpy(np.stack(x, axis=0)).to( + device).permute(0, 3, 1, 2).float() + + # responses + x = self.backbone(x) + responses = self.head(self.template, x) + responses = responses.squeeze(1).cpu().numpy() + + # upsample responses and penalize scale changes + responses = np.stack([cv2.resize( + u, (self.upscale_sz, self.upscale_sz), + interpolation=cv2.INTER_CUBIC) + for u in responses]) + responses[:self.cfg.scale_num // 2] *= self.cfg.scale_penalty + responses[self.cfg.scale_num // 2 + 1:] *= self.cfg.scale_penalty + + # peak scale + scale_id = np.argmax(np.amax(responses, axis=(1, 2))) + + # peak location + response = responses[scale_id] + response -= response.min() + response /= response.sum() + 1e-16 + response = (1 - self.cfg.window_influence) * response + \ + self.cfg.window_influence * self.hann_window + loc = np.unravel_index(response.argmax(), response.shape) + + # locate target center + disp_in_response = np.array(loc) - (self.upscale_sz - 1) / 2 + disp_in_instance = disp_in_response * \ + self.cfg.out_stride / self.cfg.response_up + disp_in_image = disp_in_instance * self.x_sz * \ + self.scale_factors[scale_id] / self.cfg.instance_sz + self.center += disp_in_image + + # update target size + scale = (1 - self.cfg.scale_lr) * 1.0 + \ + self.cfg.scale_lr * self.scale_factors[scale_id] + self.target_sz *= scale + self.z_sz *= scale + self.x_sz *= scale + + # tracking result + bbox = np.concatenate([ + self.center - (self.target_sz - 1) / 2., + self.center + (self.target_sz - 1) / 2.]) + + return bbox diff --git a/utils/neuron/models/trackers/tracker.py b/utils/neuron/models/trackers/tracker.py new file mode 100755 index 0000000..13e7d48 --- /dev/null +++ b/utils/neuron/models/trackers/tracker.py @@ -0,0 +1,102 @@ +import numpy as np +import time + +import neuron.ops as ops +from neuron.models.model import Model + + +__all__ = ['Tracker', 'OxUvA_Tracker'] + + +class Tracker(Model): + + def __init__(self, name, is_deterministic=True, + input_type='image', color_fmt='RGB'): + assert input_type in ['image', 'file'] + assert color_fmt in ['RGB', 'BGR', 'GRAY'] + super(Tracker, self).__init__() + self.name = name + self.is_deterministic = is_deterministic + self.input_type = input_type + self.color_fmt = color_fmt + + def init(self, img, init_bbox): + self.init(img, init_bbox) + + def update(self, img): + bboxes = self.update(img) + return bboxes + + def forward_test(self, img_files, init_bbox, visualize=False): + # state variables + frame_num = len(img_files) + bboxes = np.zeros((frame_num, 4)) + bboxes[0] = init_bbox + times = np.zeros(frame_num) + + for f, img_file in enumerate(img_files): + if self.input_type == 'image': + img = ops.read_image(img_file, self.color_fmt) + elif self.input_type == 'file': + img = img_file + + begin = time.time() + if f == 0: + self.init(img, init_bbox) + else: + bboxes[f, :] = self.update(img) + times[f] = time.time() - begin + + if visualize: + ops.show_image(img, bboxes[f, :]) + + return bboxes, times + + +class OxUvA_Tracker(Tracker): + + def update(self, img): + r'''One needs to return (bbox, score, present) in + function `update`. + ''' + raise NotImplementedError + + def forward_test(self, img_files, init_bbox, visualize=False): + frame_num = len(img_files) + times = np.zeros(frame_num) + preds = [{ + 'present': True, + 'score': 1.0, + 'xmin': init_bbox[0], + 'xmax': init_bbox[2], + 'ymin': init_bbox[1], + 'ymax': init_bbox[3]}] + + for f, img_file in enumerate(img_files): + if self.input_type == 'image': + img = ops.read_image(img_file, self.color_fmt) + elif self.input_type == 'file': + img = img_file + + begin = time.time() + if f == 0: + self.init(img, init_bbox) + else: + bbox, score, present = self.update(img) + preds.append({ + 'present': present, + 'score': score, + 'xmin': bbox[0], + 'xmax': bbox[2], + 'ymin': bbox[1], + 'ymax': bbox[3]}) + times[f] = time.time() - begin + + if visualize: + ops.show_image(img, bboxes[f, :]) + + # update the preds as one-per-second + frame_stride = 30 + preds = {f * frame_stride: pred for f, pred in enumerate(preds)} + + return preds, times diff --git a/utils/neuron/ops/__init__.py b/utils/neuron/ops/__init__.py new file mode 100755 index 0000000..0dc95ae --- /dev/null +++ b/utils/neuron/ops/__init__.py @@ -0,0 +1,6 @@ +from .ops import * +from .image import * +from .io import * +from .transforms import * +from .losses import * +from .metrics import * diff --git a/utils/neuron/ops/image.py b/utils/neuron/ops/image.py new file mode 100755 index 0000000..786d104 --- /dev/null +++ b/utils/neuron/ops/image.py @@ -0,0 +1,90 @@ +import numpy as np +import cv2 +from PIL import Image + + +def read_image(filename, color_fmt='RGB'): + assert color_fmt in Image.MODES + img = Image.open(filename) + if not img.mode == color_fmt: + img = img.convert(color_fmt) + return np.asarray(img) + + +def save_image(filename, img, color_fmt='RGB'): + assert color_fmt in ['RGB', 'BGR'] + if color_fmt == 'BGR' and img.ndim == 3: + img = img[..., ::-1] + img = Image.fromarray(img) + return img.save(filename) + + +def show_image(img, bboxes=None, bbox_fmt='ltrb', colors=None, + thickness=3, fig=1, delay=1, max_size=640, + visualize=True, cvt_code=cv2.COLOR_RGB2BGR): + if cvt_code is not None: + img = cv2.cvtColor(img, cvt_code) + + # resize img if necessary + if max(img.shape[:2]) > max_size: + scale = max_size / max(img.shape[:2]) + out_size = ( + int(img.shape[1] * scale), + int(img.shape[0] * scale)) + img = cv2.resize(img, out_size) + if bboxes is not None: + bboxes = np.array(bboxes, dtype=np.float32) * scale + + if bboxes is not None: + assert bbox_fmt in ['ltwh', 'ltrb'] + bboxes = np.array(bboxes, dtype=np.int32) + if bboxes.ndim == 1: + bboxes = np.expand_dims(bboxes, axis=0) + if bboxes.shape[1] == 4 and bbox_fmt == 'ltwh': + bboxes[:, 2:] = bboxes[:, :2] + bboxes[:, 2:] - 1 + + # clip bounding boxes + h, w = img.shape[:2] + bboxes[:, 0::2] = np.clip(bboxes[:, 0::2], 0, w) + bboxes[:, 1::2] = np.clip(bboxes[:, 1::2], 0, h) + + if colors is None: + colors = [ + (0, 0, 255), + (0, 255, 0), + (255, 0, 0), + (0, 255, 255), + (255, 0, 255), + (255, 255, 0), + (0, 0, 128), + (0, 128, 0), + (128, 0, 0), + (0, 128, 128), + (128, 0, 128), + (128, 128, 0)] + colors = np.array(colors, dtype=np.int32) + if colors.ndim == 1: + colors = np.expand_dims(colors, axis=0) + + for i, bbox in enumerate(bboxes): + color = colors[i % len(colors)] + if len(bbox) == 4: + pt1 = (int(bbox[0]), int(bbox[1])) + pt2 = (int(bbox[2]), int(bbox[3])) + img = cv2.rectangle(img, pt1, pt2, color.tolist(), thickness) + else: + pts = bbox.reshape(-1, 2) + img = cv2.polylines(img, [pts], True, color.tolist(), thickness) + + if visualize: + if isinstance(fig, str): + winname = fig + else: + winname = 'window_{}'.format(fig) + cv2.imshow(winname, img) + cv2.waitKey(delay) + + if cvt_code in [cv2.COLOR_RGB2BGR, cv2.COLOR_BGR2RGB]: + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + + return img diff --git a/utils/neuron/ops/io.py b/utils/neuron/ops/io.py new file mode 100755 index 0000000..8f83abe --- /dev/null +++ b/utils/neuron/ops/io.py @@ -0,0 +1,72 @@ +import time +import sys +import os +import os.path as osp +import zipfile +import shutil +if sys.version_info.major == 2: + from urllib import urlretrieve +else: + from urllib.request import urlretrieve + + +def download(url, filename): + r"""Download a file from the internet. + + Args: + url (string): URL of the internet file. + filename (string): Path to store the downloaded file. + """ + dirname = osp.dirname(filename) + if not osp.exists(dirname): + os.makedirs(dirname) + return urlretrieve(url, filename, _reporthook) + + +def _reporthook(count, block_size, total_size): + global start_time + if count == 0: + start_time = time.time() + return + duration = time.time() - start_time + progress_size = int(count * block_size) + speed = int(progress_size / (1024 * duration)) + percent = int(count * block_size * 100 / total_size) + sys.stdout.write("\r...%d%%, %d MB, %d KB/s, %d seconds passed" % + (percent, progress_size / (1024 * 1024), speed, duration)) + sys.stdout.flush() + + +def extract(filename, extract_dir): + r"""Extract a zip file. + + Args: + filename (string): Path of the zip file. + extract_dir (string): Directory to store the extracted results. + """ + if osp.splitext(filename)[1] == '.zip': + if not osp.isdir(extract_dir): + os.makedirs(extract_dir) + with zipfile.ZipFile(filename) as z: + z.extractall(extract_dir) + else: + raise ValueError( + 'Expected the extention to be .zip, ' + 'but got {} instead'.format(osp.splitext(filename)[1])) + + +def compress(dirname, save_file): + """Compress a folder to a zip file. + + Arguments: + dirname {string} -- Directory of all files to be compressed. + save_file {string} -- Path to store the zip file. + """ + shutil.make_archive(save_file, 'zip', dirname) + + +def sys_print(*args, **kwargs): + args = tuple(str(u) for u in args) + sys.stdout.write(' '.join(args), **kwargs) + sys.stdout.write('\n') + sys.stdout.flush() diff --git a/utils/neuron/ops/losses.py b/utils/neuron/ops/losses.py new file mode 100755 index 0000000..a62c133 --- /dev/null +++ b/utils/neuron/ops/losses.py @@ -0,0 +1,189 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +def _log_sigmoid(x): + r'''Numerical stable log-sigmoid. + ''' + return torch.clamp(x, max=0) - \ + torch.log(1 + torch.exp(-torch.abs(x))) + \ + 0.5 * torch.clamp(x, min=0, max=0) + + +def _log_one_minus_sigmoid(x): + r'''Numerical stable log-one-minus-sigmoid. + ''' + return torch.clamp(-x, max=0) - \ + torch.log(1 + torch.exp(-torch.abs(x))) + \ + 0.5 * torch.clamp(x, min=0, max=0) + + +def balanced_bce_loss(input, target, neg_weight=1.): + target = target.type_as(input) + pos_mask, neg_mask = target.eq(1), target.eq(0) + pos_num = pos_mask.sum().float().clamp(1e-12) + neg_num = neg_mask.sum().float().clamp(1e-12) + weight = target.new_zeros(target.size()) + weight[pos_mask] = 1. / pos_num + weight[neg_mask] = (1. / neg_num) * neg_weight + weight /= weight.mean() + return F.binary_cross_entropy_with_logits( + input, target, weight, reduction='mean') + + +def focal_loss(input, target, alpha=0.25, gamma=2.): + prob = input.sigmoid() + target = target.type_as(input) + + # focal weights + pt = (1 - prob) * target + prob * (1 - target) + weight = pt.pow(gamma) * \ + (alpha * target + (1 - alpha) * (1 - target)) + + # BCE loss with focal weights + loss = F.binary_cross_entropy_with_logits( + input, target, reduction='none') * weight + + return loss.mean() + + +def ghmc_loss(input, target, bins=30, momentum=0.5): + edges = [t / bins for t in range(bins + 1)] + edges[-1] += 1e-6 + mmt = momentum + if mmt > 0: + acc_sum = [0.0 for _ in range(bins)] + + weight = torch.zeros_like(input) + # gradient length + g = torch.abs(input.sigmoid().detach() - target) + + total = input.numel() + n = 0 + for i in range(bins): + inds = (g >= edges[i]) & (g < edges[i + 1]) + num_in_bin = inds.sum().item() + if num_in_bin > 0: + if mmt > 0: + acc_sum[i] = mmt * acc_sum[i] \ + + (1 - mmt) * num_in_bin + weight[inds] = total / acc_sum[i] + else: + weight[inds] = total / num_in_bin + n += 1 + if n > 0: + weight /= weight.mean() + + loss = F.binary_cross_entropy_with_logits( + input, target, weight, reduction='sum') / total + + return loss + + +def ohem_bce_loss(input, target, neg_ratio=3.): + pos_logits = input[target > 0] + pos_labels = target[target > 0] + neg_logits = input[target == 0] + neg_labels = target[target == 0] + + # calculate hard example numbers + pos_num = pos_logits.numel() + neg_num = neg_logits.numel() + if pos_num * neg_ratio < neg_num: + neg_num = max(1, int(pos_num * neg_ratio)) + else: + pos_num = max(1, int(neg_num / neg_ratio)) + + # top-k lowest positive scores + pos_logits, pos_indices = (-pos_logits).topk(pos_num) + pos_logits = -pos_logits + pos_labels = pos_labels[pos_indices] + + # top-k highest negative scores + neg_logits, neg_indices = neg_logits.topk(neg_num) + neg_labels = neg_labels[neg_indices] + + loss = F.binary_cross_entropy_with_logits( + torch.cat([pos_logits, neg_logits]), + torch.cat([pos_labels, neg_labels]), + reduction='mean') + + return loss + + +def smooth_l1_loss(input, target, beta=1. / 9): + o = torch.abs(input - target) + loss = torch.where( + o < beta, + 0.5 * o ** 2 / beta, + o - 0.5 * beta) + return loss.mean() + + +def iou_loss(input, target, weight=None): + # assume the order of [x1, y1, x2, y2] + il, ir, it, ib = input.t() + tl, tr, tt, tb = target.t() + + input_area = (il + ir) * (it + ib) + target_area = (tl + tr) * (tt + tb) + + inter_w = torch.min(il, tl) + torch.min(ir, tr) + inter_h = torch.min(ib, tb) + torch.min(it, tt) + + inter_area = inter_w * inter_h + union_area = input_area + target_area - inter_area + + loss = -torch.log((inter_area + 1.0) / (union_area + 1.0)) + + if weight is not None and weight.sum() > 0: + return (loss * weight).sum() / weight.sum() + else: + return loss.mean() + + +def ghmr_loss(input, target, mu=0.02, bins=10, momentum=0): + edges = [x / bins for x in range(bins + 1)] + edges[-1] = 1e3 + mmt = momentum + if mmt > 0: + acc_sum = [0.0 for _ in range(bins)] + + # ASL1 loss + diff = input - target + loss = torch.sqrt(diff * diff + mu * mu) - mu + + # gradient length + g = torch.abs(diff / torch.sqrt(mu * mu + diff * diff)).detach() + weight = torch.zeros_like(g) + + tot = input.numel() + n = 0 + for i in range(bins): + inds = (g >= edges[i]) & (g < edges[i + 1]) + num_in_bin = inds.sum().item() + if num_in_bin > 0: + n += 1 + if mmt > 0: + acc_sum[i] = mmt * acc_sum[i] \ + + (1 - mmt) * num_in_bin + weight[inds] = tot / acc_sum[i] + else: + weight[inds] = tot / num_in_bin + if n > 0: + weight /= n + + loss = loss * weight + loss = loss.sum() / tot + + return loss + + +def label_smooth_loss(input, target, num_classes, eps=0.1): + log_probs = F.log_softmax(input, dim=1) + target = log_probs.new_zeros(log_probs.size()).scatter_( + 1, target.unsqueeze(1), 1) + target = (1 - eps) * target + eps / num_classes + loss = (-target * log_probs).mean(dim=0).sum() + return loss diff --git a/utils/neuron/ops/metrics.py b/utils/neuron/ops/metrics.py new file mode 100755 index 0000000..1a24293 --- /dev/null +++ b/utils/neuron/ops/metrics.py @@ -0,0 +1,151 @@ +import numpy as np +import torch +from shapely import geometry + + +def center_error(r1, r2): + r1, r2 = np.broadcast_arrays(r1, r2) + c1 = (r1[..., :2] + r1[..., 2:]) / 2. + c2 = (r2[..., :2] + r2[..., 2:]) / 2. + return np.sqrt(np.sum(np.power(c1 - c2, 2), axis=-1)) + + +def rect_iou(r1, r2, bound=None): + r1, r2 = np.broadcast_arrays(r1, r2) + if bound is not None: + w, h = bound + r1[..., 0::2] = r1[..., 0::2].clip(0, w - 1) + r1[..., 1::2] = r1[..., 1::2].clip(0, h - 1) + r2[..., 0::2] = r2[..., 0::2].clip(0, w - 1) + r2[..., 1::2] = r2[..., 1::2].clip(0, h - 1) + + # areas of r1 and r2 + r1[..., 2:] = r1[..., 2:].clip(r1[..., :2] - 1) + r2[..., 2:] = r2[..., 2:].clip(r2[..., :2] - 1) + r1_areas = np.prod(r1[..., 2:] - r1[..., :2] + 1, axis=-1) + r2_areas = np.prod(r2[..., 2:] - r2[..., :2] + 1, axis=-1) + + # areas of intersection and union + lt = np.maximum(r1[..., :2], r2[..., :2]) + rb = np.minimum(r1[..., 2:], r2[..., 2:]).clip(lt - 1) + inter_areas = np.prod(rb - lt + 1, axis=-1) + union_areas = r1_areas + r2_areas - inter_areas + + return inter_areas / union_areas.clip(1e-12) + + +def poly_iou(p1, p2, bound=None): + def to_polygon(u): + if u.shape[-1] == 4: + return [geometry.box(p[0], p[1], p[2] + 1, p[3] + 1) + for p in u] + elif u.shape[-1] == 8: + return [geometry.Polygon([(p[2 * i], p[2 * i + 1]) + for i in range(4)]) for p in u] + else: + raise ValueError('Expected the last dimension to be 4 or 8,' + 'but got {}'.format(u.shape[-1])) + + # ensure p1 and p2 to be 2-dimensional + if p1.ndim == 1: + p1 = p1[np.newaxis, :] + if p2.ndim == 1: + p2 = p2[np.newaxis, :] + assert p1.ndim == 2 + assert p2.ndim == 2 + + # convert to Polygons + p1 = to_polygon(p1) + p2 = to_polygon(p2) + + # bound Polygons + if bound is not None: + bound = geometry.box(0, 0, bound[0], bound[1]) + p1 = [p.intersection(bound) for p in p1] + p2 = [p.intersection(bound) for p in p2] + + # calculate IOUs + ious = [] + for p1_, p2_ in zip(p1, p2): + inter_area = p1_.intersection(p2_).area + union_area = p1_.union(p2_).area + ious.append(inter_area / max(union_area, 1e-12)) + + return np.array(ious) + + +def euclidean(x, y, sqrt=True): + m, n = x.size(0), y.size(0) + x2 = torch.pow(x, 2).sum(1, keepdim=True).expand(m, n) + y2 = torch.pow(y, 2).sum(1, keepdim=True).expand(n, m).t() + dist_mat = x2 + y2 + dist_mat.addmm_(1, -2, x, y.t()).clamp_(min=1e-12) + if sqrt: + dist_mat = dist_mat.sqrt() + return dist_mat + + +def precision_recall(scores, labels, thr=0.6): + pred = scores.gt(thr) + gt = labels.gt(0) + + tp = (pred & gt).sum().float() + fp = (pred & ~gt).sum().float() + fn = (~pred & gt).sum().float() + + precision = tp / (tp + fp).clamp_(1e-12) + recall = tp / (tp + fn).clamp_(1e-12) + f1_score = 2 * precision * recall / ( + precision + recall).clamp_(1e-12) + + metrics = { + 'precision': precision, + 'recall': recall, + 'f1_score': f1_score} + + return metrics + + +def r1_map(dist_mat, labels): + indices = torch.argsort(dist_mat, dim=1) + matches = (labels[indices] == labels.unsqueeze(1)).float() + + n = dist_mat.size(0) + cmc, ap = [], [] + for i in range(n): + ins_id = labels[i] + + matches_i = matches[i][indices[i] != i] + cmc_i = matches_i.cumsum(dim=0).clamp_(None, 1.) + cmc.append(cmc_i) + + num_matches = matches_i.sum() + tmp_cmc = matches_i.cumsum(dim=0) * matches_i + tmp_cmc /= torch.arange( + 1, len(tmp_cmc) + 1, dtype=tmp_cmc.dtype, + device=tmp_cmc.device) + ap_i = tmp_cmc.sum() / num_matches + ap.append(ap_i) + + cmc = torch.stack(cmc, dim=0).mean(dim=0) + mean_ap = torch.stack(ap, dim=0).mean(dim=0) + metrics = { + 'cmc_1': cmc[0], + 'cmc_2': cmc[1], + 'cmc_5': cmc[4], + 'cmc_10': cmc[9], + 'mean_ap': mean_ap} + + return metrics + + +def topk_precision(scores, labels): + pred = torch.argsort(scores, dim=1, descending=True) + matches = (pred == labels.unsqueeze(1)) + topk = [matches[:, :k].any(dim=1).float().mean() + for k in range(1, matches.size(1) + 1)] + output = { + 'top1': topk[0], + 'top5': topk[4], + 'top10': topk[9]} + return output diff --git a/utils/neuron/ops/ops.py b/utils/neuron/ops/ops.py new file mode 100755 index 0000000..22a5991 --- /dev/null +++ b/utils/neuron/ops/ops.py @@ -0,0 +1,115 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.distributed as dist +import os +from multiprocessing.pool import ThreadPool as Pool + + +def fast_xcorr(z, x): + r'''Fast cross-correlation. + ''' + assert z.shape[1] == x.shape[1] + nz = z.size(0) + nx, c, h, w = x.size() + x = x.view(-1, nz * c, h, w) + out = F.conv2d(x, z, groups=nz) + out = out.view(nx, -1, out.size(-2), out.size(-1)) + return out + + +def init_weights(model, gain=1): + for m in model.modules(): + if isinstance(m, nn.Conv2d): + nn.init.xavier_uniform_(m.weight, gain) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.xavier_uniform_(m.weight, gain) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + +def kaiming_init(m): + if isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight, a=0, mode='fan_out') + if m.bias is not None: + nn.init.constant_(m.bias, 0.0) + elif isinstance(m, (nn.Conv1d, nn.Conv2d)): + nn.init.kaiming_normal_(m.weight, a=0, mode='fan_in') + if m.bias is not None: + nn.init.constant_(m.bias, 0.0) + elif isinstance(m, (nn.BatchNorm1d, nn.BatchNorm2d)) and m.affine: + nn.init.constant_(m.weight, 1.0) + nn.init.constant_(m.bias, 0.0) + + +def classifier_init(m): + if isinstance(m, nn.Linear): + nn.init.normal_(m.weight, std=0.001) + if m.bias is not None: + nn.init.constant_(m.bias, 0.0) + + +def get_dist_info(): + if torch.__version__ < '1.0': + initialized = dist._initialized + else: + initialized = dist.is_initialized() + if initialized: + rank = dist.get_rank() + world_size = dist.get_world_size() + else: + rank = 0 + world_size = 1 + return rank, world_size + + +def put_device(data, device, non_blocking=False): + non_blocking = non_blocking if 'cuda' in device.type else False + if isinstance(data, torch.Tensor): + data = data.to(device, non_blocking=non_blocking) + elif isinstance(data, (list, tuple)): + data = data.__class__([ + put_device(item, device, non_blocking=non_blocking) + for item in data]) + elif isinstance(data, dict): + data = {k: put_device(v, device, non_blocking=non_blocking) + for k, v in data.items()} + return data + + +def adaptive_apply(func, args): + if isinstance(args, (tuple, list)): + return func(*args) + elif isinstance(args, dict): + return func(**args) + else: + return func(args) + + +def detach(data): + if isinstance(data, torch.Tensor): + return data.detach() + elif isinstance(data, (list, tuple)): + data = data.__class__([detach(item) for item in data]) + elif isinstance(data, dict): + data = {k: detach(v) for k, v in data.items()} + return data + + +def map(func, args_list, num_workers=32, timeout=1): + if isinstance(args_list, range): + args_list = list(args_list) + assert isinstance(args_list, list) + if not isinstance(args_list[0], tuple): + args_list = [(args, ) for args in args_list] + + with Pool(processes=num_workers) as pool: + results = [pool.apply_async(func, args) for args in args_list] + results = [res.get(timeout=timeout) for res in results] + + return results diff --git a/utils/neuron/ops/transforms.py b/utils/neuron/ops/transforms.py new file mode 100755 index 0000000..6d9470a --- /dev/null +++ b/utils/neuron/ops/transforms.py @@ -0,0 +1,433 @@ +import numbers +import numpy as np +import cv2 +import random + + +def make_pair(p): + if isinstance(p, numbers.Number): + return (p, p) + elif isinstance(p, (list, tuple)) and len(p) == 2: + return p + else: + raise ValueError('Unable to convert {} to a pair'.format(p)) + + +def bound_bboxes(bboxes, bound_size): + w, h = bound_size + bboxes[..., 0::2] = np.clip(bboxes[..., 0::2], 0, w - 1) + bboxes[..., 1::2] = np.clip(bboxes[..., 1::2], 0, h - 1) + if bboxes.shape[1] == 4: + bboxes[..., 2:] = np.clip( + bboxes[..., 2:], bboxes[..., :2], None) + return bboxes + + +def random_interp(): + interps = [ + cv2.INTER_LINEAR, + cv2.INTER_CUBIC, + cv2.INTER_AREA, + cv2.INTER_NEAREST, + cv2.INTER_LANCZOS4] + return np.random.choice(interps) + + +def rescale_img(img, scale, bboxes=None, interp=None): + h, w = img.shape[:2] + if isinstance(scale, (float, int)): + assert scale > 0 + scale_factor = scale + elif isinstance(scale, (list, tuple)): + long_edge = max(scale) + short_edge = min(scale) + scale_factor = min( + long_edge / max(h, w), + short_edge / min(h, w)) + else: + raise TypeError('Invalid type of scale') + + if interp is None: + interp = random_interp() + out_w = int(w * scale_factor + 0.5) + out_h = int(h * scale_factor + 0.5) + out_img = cv2.resize(img, (out_w, out_h), interpolation=interp) + + if bboxes is not None: + out_bboxes = bboxes * scale_factor + return out_img, out_bboxes, scale_factor + else: + return out_img, scale_factor + + +def resize_img(img, scale, bboxes=None, interp=None): + if interp is None: + interp = random_interp() + h, w = img.shape[:2] + out_w, out_h = scale + out_img = cv2.resize(img, (out_w, out_h), interpolation=interp) + scale_factor = (out_w / w, out_h / h) + + if bboxes is not None: + out_bboxes = bboxes.copy() + out_bboxes[..., 0::2] *= scale_factor[0] + out_bboxes[..., 1::2] *= scale_factor[1] + return out_img, out_bboxes, scale_factor + else: + return out_img, scale_factor + + +def normalize_img(img, mean, std): + img = img.astype(np.float32) + img -= mean + img /= std + return img + + +def denormalize_img(img, mean, std): + img *= std + img += mean + return img + + +def stretch_color(img): + img = img.astype(np.float32) + return (img - img.min()) / (img.max() - img.min()) + + +def flip_img(img, bboxes=None): + img = np.flip(img, axis=1) + if bboxes is None: + return img + else: + w = img.shape[1] + out_bboxes = bboxes.copy() + out_bboxes[..., 0::4] = w - bboxes[..., 2::4] - 1 + out_bboxes[..., 2::4] = w - bboxes[..., 0::4] - 1 + return img, out_bboxes + + +def pad_img(img, shape, border_value=0): + if len(shape) < len(img.shape): + shape += (img.shape[-1], ) + assert all([so >= si for so, si in zip(shape, img.shape)]) + out_img = np.empty(shape, dtype=img.dtype) + out_img[...] = border_value + out_img[:img.shape[0], :img.shape[1], ...] = img + return out_img + + +def pad_to_divisor(img, divisor, border_value=0): + out_h = int(np.ceil(img.shape[0] / divisor) * divisor) + out_w = int(np.ceil(img.shape[1] / divisor) * divisor) + return pad_img(img, (out_h, out_w), border_value) + + +def bound_bboxes(bboxes, img_size): + w, h = img_size + bboxes[:, 0::2] = np.clip(bboxes[:, 0::2], 0, w - 1) + bboxes[:, 1::2] = np.clip(bboxes[:, 1::2], 0, h - 1) + if bboxes.shape[1] == 4: + bboxes[:, 2:] = np.clip(bboxes[:, 2:], bboxes[:, :2], None) + return bboxes + + +def jaccard(a, b): + # a: N x 4 -> N x M x 4 + # b: M x 4 -> N x M x 4 + lt = np.maximum(a[:, None, :2], b[None, :, :2]) + rb = np.minimum(a[:, None, 2:], b[None, :, 2:]) + area_i = (rb - lt).clip(min=0.).prod(axis=2) # N x M + + area_a = (a[:, 2:] - a[:, :2]).prod(axis=1) # N + area_b = (b[:, 2:] - b[:, :2]).prod(axis=1) # M + ious = area_i / ( + area_a[:, None] + area_b[None, :] - area_i).clip(min=1e-6) + + return ious + + +def photometric_distort(img, swap_channels=False): + # convert to float + img = img.astype(np.float32) + + # random brightness + if np.random.randint(2): + delta = np.random.uniform(-32, 32) + img += delta + + # order of random constrast + constrast_first = np.random.randint(2) + if constrast_first and np.random.randint(2): + alpha = np.random.uniform(0.5, 1.5) + img *= alpha + + # convert from RGB to HSV + img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV) + + # random Saturation + if np.random.randint(2): + alpha = np.random.uniform(0.5, 1.5) + img[:, :, 1] *= alpha + + # random Hue + if np.random.randint(2): + delta = np.random.uniform(-18, 18) + img[:, :, 0] += delta + img[:, :, 0][img[:, :, 0] > 360.0] -= 360.0 + img[:, :, 0][img[:, :, 0] < 0.0] += 360.0 + + # convert from HSV to RGB + img = cv2.cvtColor(img, cv2.COLOR_HSV2RGB) + + # order of random constrast + if not constrast_first and np.random.randint(2): + alpha = np.random.uniform(0.5, 1.5) + img *= alpha + + # randomly swap channels + if swap_channels and np.random.randint(2): + order = np.random.permutation(3) + img = img[..., order] + + return img + + +def random_expand(img, bboxes, mean, min_ratio, max_ratio): + if np.random.randint(2): + return img, bboxes + + h, w, c = img.shape + ratio = np.random.uniform(min_ratio, max_ratio) + out_h, out_w = int(h * ratio), int(w * ratio) + out_img = np.empty((out_h, out_w, c), dtype=img.dtype) + out_img[...] = mean + + l = int(np.random.uniform(0, out_w - w)) + t = int(np.random.uniform(0, out_h - h)) + out_img[t:t + h, l:l + w, :] = img + out_bboxes = bboxes + np.tile((l, t), 2) + + return out_img, out_bboxes + + +def random_crop(img, bboxes, min_ious, min_scale): + h, w = img.shape[:2] + min_ious = (1, *min_ious, 0) + + while True: + min_iou = np.random.choice(min_ious) + if min_iou == 1: + valid_mask = np.ones(len(bboxes), dtype=bool) + return img, bboxes, valid_mask + + for i in range(50): + new_w = np.random.uniform(min_scale * w, w) + new_h = np.random.uniform(min_scale * h, h) + + # aspect ratio should be between 0.5 and 2.0 + if new_h / new_w < 0.5 or new_h / new_w > 2.0: + continue + + l = np.random.uniform(0, w - new_w) + t = np.random.uniform(0, h - new_h) + bound = np.array([l, t, l + new_w, t + new_h], dtype=int) + + # minimum IOU should be larger than min_iou + ious = jaccard( + bboxes.reshape(-1, 4), + bound.reshape(-1, 4)).reshape(-1) + if ious.min() < min_iou: + continue + + # keep only bboxes with their centers inside the image + centers = (bboxes[:, :2] + bboxes[:, 2:]) / 2. + valid_mask = (bound[0] < centers[:, 0]) * \ + (bound[1] < centers[:, 1]) * \ + (bound[2] > centers[:, 0]) * \ + (bound[3] > centers[:, 1]) + if not valid_mask.any(): + continue + + # crop image and bboxes + img = img[bound[1]:bound[3], bound[0]:bound[2], :] + bboxes = bboxes.copy() + bboxes[:, 2:] = bboxes[:, 2:].clip(max=bound[2:]) + bboxes[:, :2] = bboxes[:, :2].clip(min=bound[:2]) + bboxes -= np.tile(bound[:2], 2) + + return img, bboxes, valid_mask + + +def blend_(alpha, img1, img2): + img1 *= alpha + img2 *= (1 - alpha) + img1 += img2 + + +def brightness_(rng, img, gray, gray_mean, var): + alpha = 1. + rng.uniform(low=-var, high=var) + img *= alpha + + +def constrast_(rng, img, gray, gray_mean, var): + alpha = 1. + rng.uniform(low=-var, high=var) + blend_(alpha, img, gray_mean) + + +def saturation_(rng, img, gray, gray_mean, var): + alpha = 1. + rng.uniform(low=-var, high=var) + blend_(alpha, img, gray[:, :, None]) + + +def lighting_(rng, img, eig_val, eig_vec, std): + alpha = rng.normal(scale=std, size=(3, )) + img += np.dot(eig_vec, eig_val * alpha) + + +def color_jitter(img, rng, eig_val, eig_vec, var=0.4, std=0.1): + augs = [brightness_, constrast_, saturation_] + random.shuffle(augs) + + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + gray_mean = gray.mean() + for f in augs: + f(rng, img, gray, gray_mean, var=var) + lighting_(rng, img, eig_val, eig_vec, std=std) + + return img + + +def _get_direction(point, rad): + sin, cos = np.sin(rad), np.cos(rad) + + out = [0, 0] + out[0] = point[0] * cos - point[1] * sin + out[1] = point[0] * sin + point[1] * cos + + return out + + +def _get_3rd_point(a, b): + direct = a - b + return b + np.array([-direct[1], direct[0]], dtype=np.float32) + + +def get_affine_transform(center, scale, rotation, output_size, + shift=None, inv=False): + if not isinstance(scale, (list, tuple, np.ndarray)): + scale = np.array([scale, scale], dtype=np.float32) + if shift is None: + shift = np.array([0, 0], dtype=np.float32) + + src_w = scale[0] + dst_w = output_size[0] + dst_h = output_size[1] + + rad = np.pi * rotation / 180 + src_dir = _get_direction([0, src_w * -0.5], rad) + dst_dir = np.array([0, dst_w * -0.5], np.float32) + + src = np.zeros((3, 2), dtype=np.float32) + dst = np.zeros((3, 2), dtype=np.float32) + src[0, :] = center + scale * shift + src[1, :] = center + src_dir + scale * shift + dst[0, :] = [dst_w * 0.5, dst_h * 0.5] + dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5], np.float32) + dst_dir + + src[2:, :] = _get_3rd_point(src[0, :], src[1, :]) + dst[2:, :] = _get_3rd_point(dst[0, :], dst[1, :]) + + if not inv: + return cv2.getAffineTransform(src, dst) + else: + return cv2.getAffineTransform(dst, src) + + +def apply_affine_transform(point, trans): + out = np.array([point[0], point[1], 1.], dtype=np.float32).T + out = np.dot(trans, out) + return out[:2] + + +def random_resize(img, max_scale): + interp = random_interp() + scale = np.random.uniform(1. / max_scale, max_scale) + out_size = ( + round(img.shape[1] * scale), + round(img.shape[0] * scale)) + return cv2.resize(img, out_size, interpolation=interp) + + +def center_crop(img, size): + h, w = img.shape[:2] + tw, th = make_pair(size) + i = round((h - th) / 2.) + j = round((w - tw) / 2.) + + npad = max(0, -i, -j) + if npad > 0: + avg_color = np.mean(img, axis=(0, 1)) + img = cv2.copyMakeBorder( + img, npad, npad, npad, npad, + cv2.BORDER_CONSTANT, value=avg_color) + i += npad + j += npad + + return img[i:i + th, j:j + tw] + + +def simple_random_crop(img, size): + h, w = img.shape[:2] + tw, th = make_pair(size) + i = np.random.randint(0, h - th + 1) + j = np.random.randint(0, w - tw + 1) + return img[i:i + th, j:j + tw] + + +def crop_and_resize(img, center, size, out_size, + border_type=cv2.BORDER_CONSTANT, + border_value=(0, 0, 0), + interp=cv2.INTER_LINEAR): + # convert bbox to corners (0-indexed) + size = np.round(size) + corners = np.concatenate(( + np.round(center - (size - 1) / 2), + np.round(center - (size - 1) / 2) + size)) + corners = np.round(corners).astype(int) + + # pad image if necessary + pads = np.concatenate(( + -corners[:2], corners[2:] - img.shape[1::-1])) + npad = max(0, int(pads.max())) + if npad > 0: + img = cv2.copyMakeBorder( + img, npad, npad, npad, npad, + border_type, value=border_value) + + # crop image patch + corners = (corners + npad).astype(int) + patch = img[corners[1]:corners[3], corners[0]:corners[2]] + + # resize to out_size + out_size = make_pair(out_size) + patch = cv2.resize(patch, out_size, interpolation=interp) + + return patch + + +def crop_square(img, bbox, context, src_size, dst_size): + center = (bbox[:2] + bbox[2:]) / 2. + target_sz = bbox[2:] - bbox[:2] + 1 + + context = context * np.sum(target_sz) + size = np.sqrt(np.prod(target_sz + context)) + size *= dst_size / src_size + + avg_color = np.mean(img, axis=(0, 1), dtype=float) + interp = random_interp() + patch = crop_and_resize( + img, center, size, dst_size, + border_value=avg_color, interp=interp) + + return patch diff --git a/utils/neuron/optim/__init__.py b/utils/neuron/optim/__init__.py new file mode 100755 index 0000000..6f724ed --- /dev/null +++ b/utils/neuron/optim/__init__.py @@ -0,0 +1,2 @@ +from .param_grouper import * +from .lr_scheduler import * diff --git a/utils/neuron/optim/lr_scheduler.py b/utils/neuron/optim/lr_scheduler.py new file mode 100755 index 0000000..b43cbd9 --- /dev/null +++ b/utils/neuron/optim/lr_scheduler.py @@ -0,0 +1,43 @@ +from torch.optim.lr_scheduler import _LRScheduler +from bisect import bisect_right + +from neuron.config import registry + + +__all__ = ['WarmupMultiStepLR'] + + +@registry.register_module +class WarmupMultiStepLR(_LRScheduler): + + def __init__(self, + optimizer, + steps, + gamma, + warmup_factor, + warmup_iters, + warmup_method, + last_epoch=-1): + if steps != sorted(steps): + raise ValueError( + 'Steps should be a list of increasing integers,' + ' but got {}'.format(steps)) + assert warmup_method in ['constant', 'linear'] + self.steps = steps + self.gamma = gamma + self.warmup_factor = warmup_factor + self.warmup_iters = warmup_iters + self.warmup_method = warmup_method + super(WarmupMultiStepLR, self).__init__(optimizer, last_epoch) + + def get_lr(self): + warmup_factor = 1 + if self.last_epoch < self.warmup_iters: + if self.warmup_method == 'constant': + warmup_factor = self.warmup_factor + elif self.warmup_method == 'linear': + alpha = self.last_epoch / self.warmup_iters + warmup_factor = self.warmup_factor * (1 - alpha) + alpha + return [base_lr * warmup_factor * self.gamma ** \ + bisect_right(self.steps, self.last_epoch) + for base_lr in self.base_lrs] diff --git a/utils/neuron/optim/param_grouper.py b/utils/neuron/optim/param_grouper.py new file mode 100755 index 0000000..150360b --- /dev/null +++ b/utils/neuron/optim/param_grouper.py @@ -0,0 +1,56 @@ +from neuron.config import registry + + +__all__ = ['ParamGrouper'] + + +@registry.register_module +class ParamGrouper(object): + + def __init__(self, lr, weight_decay, special_lrs={}, + special_wds={}): + self.base_lr = lr + self.base_wd = weight_decay + self.special_lrs = special_lrs + self.special_wds = special_wds + + def __call__(self, *modules): + # collect all parameters and their names + named_params = [] + for m in modules: + named_params += list(m.named_parameters()) + + # build param_groups + param_groups = [] + for name, params in named_params: + if not params.requires_grad: + continue + + # learning rate + lr_keys = [key for key in self.special_lrs if name in key] + if len(lr_keys) == 0: + lr = self.base_lr + elif len(lr_keys) == 1: + lr = self.special_lrs[lr_keys[0]] + else: + raise ValueError( + 'The lr group of parameter {} is ambiguous since it' + 'has multiple matches in special_lrs'.format(name)) + + # weight decay + wd_keys = [key for key in self.special_wds if name in key] + if len(wd_keys) == 0: + wd = self.base_wd + elif len(wd_keys) == 1: + wd = self.special_wds[wd_keys[0]] + else: + raise ValueError( + 'The wd group of parameter {} is ambiguous since it' + 'has multiple matches in special_wds'.format(name)) + + # append to param_groups + param_groups += [{'params': [params], + 'lr': lr, + 'weight_decay': wd}] + + return param_groups diff --git a/utils/testing_set.txt b/utils/testing_set.txt new file mode 100755 index 0000000..4f419ed --- /dev/null +++ b/utils/testing_set.txt @@ -0,0 +1,280 @@ +airplane-1 +airplane-9 +airplane-13 +airplane-15 +basketball-1 +basketball-6 +basketball-7 +basketball-11 +bear-2 +bear-4 +bear-6 +bear-17 +bicycle-2 +bicycle-7 +bicycle-9 +bicycle-18 +bird-2 +bird-3 +bird-15 +bird-17 +boat-3 +boat-4 +boat-12 +boat-17 +book-3 +book-10 +book-11 +book-19 +bottle-1 +bottle-12 +bottle-14 +bottle-18 +bus-2 +bus-5 +bus-17 +bus-19 +car-2 +car-6 +car-9 +car-17 +cat-1 +cat-3 +cat-18 +cat-20 +cattle-2 +cattle-7 +cattle-12 +cattle-13 +spider-14 +spider-16 +spider-18 +spider-20 +coin-3 +coin-6 +coin-7 +coin-18 +crab-3 +crab-6 +crab-12 +crab-18 +surfboard-12 +surfboard-4 +surfboard-5 +surfboard-8 +cup-1 +cup-4 +cup-7 +cup-17 +deer-4 +deer-8 +deer-10 +deer-14 +dog-1 +dog-7 +dog-15 +dog-19 +guitar-3 +guitar-8 +guitar-10 +guitar-16 +person-1 +person-5 +person-10 +person-12 +pig-2 +pig-10 +pig-13 +pig-18 +rubicCube-1 +rubicCube-6 +rubicCube-14 +rubicCube-19 +swing-10 +swing-14 +swing-17 +swing-20 +drone-13 +drone-15 +drone-2 +drone-7 +pool-12 +pool-15 +pool-3 +pool-7 +rabbit-10 +rabbit-13 +rabbit-17 +rabbit-19 +racing-10 +racing-15 +racing-16 +racing-20 +robot-1 +robot-19 +robot-5 +robot-8 +sepia-13 +sepia-16 +sepia-6 +sepia-8 +sheep-3 +sheep-5 +sheep-7 +sheep-9 +skateboard-16 +skateboard-19 +skateboard-3 +skateboard-8 +tank-14 +tank-16 +tank-6 +tank-9 +tiger-12 +tiger-18 +tiger-4 +tiger-6 +train-1 +train-11 +train-20 +train-7 +truck-16 +truck-3 +truck-6 +truck-7 +turtle-16 +turtle-5 +turtle-8 +turtle-9 +umbrella-17 +umbrella-19 +umbrella-2 +umbrella-9 +yoyo-15 +yoyo-17 +yoyo-19 +yoyo-7 +zebra-10 +zebra-14 +zebra-16 +zebra-17 +elephant-1 +elephant-12 +elephant-16 +elephant-18 +goldfish-3 +goldfish-7 +goldfish-8 +goldfish-10 +hat-1 +hat-2 +hat-5 +hat-18 +kite-4 +kite-6 +kite-10 +kite-15 +motorcycle-1 +motorcycle-3 +motorcycle-9 +motorcycle-18 +mouse-1 +mouse-8 +mouse-9 +mouse-17 +flag-3 +flag-9 +flag-5 +flag-2 +frog-3 +frog-4 +frog-20 +frog-9 +gametarget-1 +gametarget-2 +gametarget-7 +gametarget-13 +hand-2 +hand-3 +hand-9 +hand-16 +helmet-5 +helmet-11 +helmet-19 +helmet-13 +licenseplate-6 +licenseplate-12 +licenseplate-13 +licenseplate-15 +electricfan-1 +electricfan-10 +electricfan-18 +electricfan-20 +chameleon-3 +chameleon-6 +chameleon-11 +chameleon-20 +crocodile-3 +crocodile-4 +crocodile-10 +crocodile-14 +gecko-1 +gecko-5 +gecko-16 +gecko-19 +fox-2 +fox-3 +fox-5 +fox-20 +giraffe-2 +giraffe-10 +giraffe-13 +giraffe-15 +gorilla-4 +gorilla-6 +gorilla-9 +gorilla-13 +hippo-1 +hippo-7 +hippo-9 +hippo-20 +horse-1 +horse-4 +horse-12 +horse-15 +kangaroo-2 +kangaroo-5 +kangaroo-11 +kangaroo-14 +leopard-1 +leopard-7 +leopard-16 +leopard-20 +lion-1 +lion-5 +lion-12 +lion-20 +lizard-1 +lizard-3 +lizard-6 +lizard-13 +microphone-2 +microphone-6 +microphone-14 +microphone-16 +monkey-3 +monkey-4 +monkey-9 +monkey-17 +shark-2 +shark-3 +shark-5 +shark-6 +squirrel-8 +squirrel-11 +squirrel-13 +squirrel-19 +volleyball-1 +volleyball-13 +volleyball-18 +volleyball-19 \ No newline at end of file diff --git a/vot.py b/vot.py new file mode 100755 index 0000000..081f165 --- /dev/null +++ b/vot.py @@ -0,0 +1,115 @@ +""" +\file vot.py + +@brief Python utility functions for VOT integration + +@author Luka Cehovin, Alessio Dore + +@date 2016 + +""" + +import sys +import copy +import collections +sys.path.append('/media/dkn/bacd1fd3-567e-47e5-a38d-d2493e106b01/daikenan/Tracking/benchmark/VOT2019/vot2019lt/native/trax/support/python') +try: + import trax +except ImportError: + raise Exception('TraX support not found. Please add trax module to Python path.') + +Rectangle = collections.namedtuple('Rectangle', ['x', 'y', 'width', 'height']) +Point = collections.namedtuple('Point', ['x', 'y']) +Polygon = collections.namedtuple('Polygon', ['points']) + +class VOT(object): + """ Base class for Python VOT integration """ + def __init__(self, region_format, channels=None): + """ Constructor + + Args: + region_format: Region format options + """ + assert(region_format in [trax.Region.RECTANGLE, trax.Region.POLYGON]) + + if channels is None: + channels = ['color'] + elif channels == 'rgbd': + channels = ['color', 'depth'] + elif channels == 'rgbt': + channels = ['color', 'ir'] + elif channels == 'ir': + channels = ['ir'] + else: + raise Exception('Illegal configuration {}.'.format(channels)) + + self._trax = trax.Server([region_format], [trax.Image.PATH], channels) + request = self._trax.wait() + assert(request.type == 'initialize') + if isinstance(request.region, trax.Polygon): + self._region = Polygon([Point(x[0], x[1]) for x in request.region]) + else: + self._region = Rectangle(*request.region.bounds()) + self._image = [x.path() for k, x in request.image.items()] + if len(self._image) == 1: + self._image = self._image[0] + + self._trax.status(request.region) + + def region(self): + """ + Send configuration message to the client and receive the initialization + region and the path of the first image + + Returns: + initialization region + """ + + return self._region + + def report(self, region, confidence = None): + """ + Report the tracking results to the client + + Arguments: + region: region for the frame + """ + assert(isinstance(region, Rectangle) or isinstance(region, Polygon)) + if isinstance(region, Polygon): + tregion = trax.Polygon.create([(x.x, x.y) for x in region.points]) + else: + tregion = trax.Rectangle.create(region.x, region.y, region.width, region.height) + properties = {} + if not confidence is None: + properties['confidence'] = confidence + self._trax.status(tregion, properties) + + def frame(self): + """ + Get a frame (image path) from client + + Returns: + absolute path of the image + """ + if hasattr(self, "_image"): + image = self._image + del self._image + return image + + request = self._trax.wait() + + if request.type == 'frame': + image = [x.path() for k, x in request.image.items()] + if len(image) == 1: + return image[0] + return image + else: + return None + + + def quit(self): + if hasattr(self, '_trax'): + self._trax.quit() + + def __del__(self): + self.quit() diff --git a/vot_path.py b/vot_path.py new file mode 100755 index 0000000..7830f33 --- /dev/null +++ b/vot_path.py @@ -0,0 +1,3 @@ +# code path +# set full path to the location where the CoCoLoT submission folder is stored +base_path = '[full-path-to-CoCoLoT]'